don't use %e for syslog errors -- either %m or errstring
[unix-history] / usr / src / usr.sbin / sendmail / src / udb.c
CommitLineData
814c4102
EA
1/*
2 * Copyright (c) 1983 Eric P. Allman
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9#ifndef lint
83b7c7b1 10#ifdef USERDB
3f0792d1 11static char sccsid [] = "@(#)udb.c 6.19 (Berkeley) %G% (with USERDB)";
83b7c7b1 12#else
3f0792d1 13static char sccsid [] = "@(#)udb.c 6.19 (Berkeley) %G% (without USERDB)";
83b7c7b1 14#endif
814c4102
EA
15#endif
16
17#include "sendmail.h"
18
19#ifdef USERDB
20
83b7c7b1 21#include <sys/time.h>
6ab0fb92 22#include <errno.h>
83b7c7b1 23#include <netdb.h>
814c4102
EA
24#include <db.h>
25
26/*
42fa5d67 27** UDB.C -- interface between sendmail and Berkeley User Data Base.
814c4102 28**
7a059839 29** This depends on the 4.4BSD db package.
814c4102
EA
30*/
31
dac6c90e 32
83b7c7b1
EA
33struct udbent
34{
35 char *udb_spec; /* string version of spec */
36 int udb_type; /* type of entry */
f61c3c40 37 char *udb_default; /* default host for outgoing mail */
83b7c7b1
EA
38 union
39 {
40 /* type UE_REMOTE -- do remote call for lookup */
41 struct
42 {
83b7c7b1
EA
43 struct sockaddr_in _udb_addr; /* address */
44 int _udb_timeout; /* timeout */
45 } udb_remote;
83b7c7b1
EA
46#define udb_addr udb_u.udb_remote._udb_addr
47#define udb_timeout udb_u.udb_remote._udb_timeout
48
49 /* type UE_FORWARD -- forward message to remote */
50 struct
51 {
52 char *_udb_fwdhost; /* name of forward host */
53 } udb_forward;
54#define udb_fwdhost udb_u.udb_forward._udb_fwdhost
55
f61c3c40 56 /* type UE_FETCH -- lookup in local database */
83b7c7b1
EA
57 struct
58 {
59 char *_udb_dbname; /* pathname of database */
60 DB *_udb_dbp; /* open database ptr */
61 } udb_lookup;
62#define udb_dbname udb_u.udb_lookup._udb_dbname
63#define udb_dbp udb_u.udb_lookup._udb_dbp
64 } udb_u;
65};
66
67#define UDB_EOLIST 0 /* end of list */
68#define UDB_SKIP 1 /* skip this entry */
69#define UDB_REMOTE 2 /* look up in remote database */
f61c3c40 70#define UDB_DBFETCH 3 /* look up in local database */
83b7c7b1
EA
71#define UDB_FORWARD 4 /* forward to remote host */
72
73#define MAXUDBENT 10 /* maximum number of UDB entries */
74
7a059839
EA
75
76struct option
77{
78 char *name;
79 char *val;
80};
81\f/*
82** UDBEXPAND -- look up user in database and expand
83**
84** Parameters:
85** a -- address to expand.
86** sendq -- pointer to head of sendq to put the expansions in.
87**
88** Returns:
6ab0fb92
EA
89** EX_TEMPFAIL -- if something "odd" happened -- probably due
90** to accessing a file on an NFS server that is down.
91** EX_OK -- otherwise.
7a059839
EA
92**
93** Side Effects:
94** Modifies sendq.
95*/
96
97int UdbPort = 1616;
98int UdbTimeout = 10;
99
d2836270
EA
100struct udbent UdbEnts[MAXUDBENT + 1];
101int UdbSock = -1;
102bool UdbInitialized = FALSE;
83b7c7b1 103
6ab0fb92 104int
a4076aed 105udbexpand(a, sendq, e)
814c4102
EA
106 register ADDRESS *a;
107 ADDRESS **sendq;
a4076aed 108 register ENVELOPE *e;
814c4102
EA
109{
110 int i;
111 register char *p;
814c4102
EA
112 DBT key;
113 DBT info;
83b7c7b1
EA
114 bool breakout;
115 register struct udbent *up;
dac6c90e 116 int keylen;
1c7897ef 117 int naddrs;
f43b04ce
EA
118 char keybuf[MAXKEY];
119 char buf[BUFSIZ];
814c4102
EA
120
121 if (tTd(28, 1))
f7eca811 122 printf("udbexpand(%s)\n", a->q_paddr);
814c4102
EA
123
124 /* make certain we are supposed to send to this address */
8bcce465 125 if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
6ab0fb92 126 return EX_OK;
a4076aed 127 e->e_to = a->q_paddr;
814c4102 128
83b7c7b1 129 /* on first call, locate the database */
f61c3c40 130 if (!UdbInitialized)
814c4102 131 {
6ab0fb92 132 extern int _udbx_init();
dac6c90e 133
6ab0fb92
EA
134 if (_udbx_init() == EX_TEMPFAIL)
135 return EX_TEMPFAIL;
dac6c90e 136 }
83b7c7b1 137
d27b0e11
EA
138 /* short circuit the process if no chance of a match */
139 if (UdbSpec == NULL || UdbSpec[0] == '\0')
6ab0fb92 140 return EX_OK;
d27b0e11 141
dac6c90e
EA
142 /* if name is too long, assume it won't match */
143 if (strlen(a->q_user) > sizeof keybuf - 12)
6ab0fb92 144 return EX_OK;
83b7c7b1 145
dac6c90e
EA
146 /* if name begins with a colon, it indicates our metadata */
147 if (a->q_user[0] == ':')
6ab0fb92 148 return EX_OK;
dac6c90e
EA
149
150 /* build actual database key */
151 (void) strcpy(keybuf, a->q_user);
152 (void) strcat(keybuf, ":maildrop");
153 keylen = strlen(keybuf);
814c4102 154
83b7c7b1 155 breakout = FALSE;
dac6c90e 156 for (up = UdbEnts; !breakout; up++)
814c4102 157 {
83b7c7b1 158 char *user;
814c4102 159
83b7c7b1
EA
160 /*
161 ** Select action based on entry type.
162 **
163 ** On dropping out of this switch, "class" should
164 ** explain the type of the data, and "user" should
165 ** contain the user information.
166 */
814c4102 167
83b7c7b1
EA
168 switch (up->udb_type)
169 {
f61c3c40 170 case UDB_DBFETCH:
dac6c90e
EA
171 key.data = keybuf;
172 key.size = keylen;
173 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
6ab0fb92 174 if (i > 0 || info.size <= 0)
83b7c7b1 175 {
83b7c7b1 176 if (tTd(28, 2))
f7eca811 177 printf("udbexpand: no match on %s\n", keybuf);
83b7c7b1
EA
178 continue;
179 }
814c4102 180
1c7897ef
EA
181 naddrs = 0;
182 a->q_flags &= ~QSELFREF;
256fe397
EA
183 while (i == 0 && key.size == keylen &&
184 bcmp(key.data, keybuf, keylen) == 0)
dac6c90e 185 {
fc14ab33 186 if (bitset(EF_VRFYONLY, e->e_flags))
8bcce465
EA
187 {
188 a->q_flags |= QVERIFIED;
a7dc53bd 189 e->e_nrcpts++;
fc14ab33 190 return EX_OK;
8bcce465 191 }
fc14ab33 192
256fe397 193 breakout = TRUE;
dac6c90e
EA
194 if (info.size < sizeof buf)
195 user = buf;
196 else
197 user = xalloc(info.size + 1);
198 bcopy(info.data, user, info.size);
199 user[info.size] = '\0';
200
b6edea3d 201 message("expanded to %s", user);
aa102c71
EA
202#ifdef LOG
203 if (LogLevel >= 10)
204 syslog(LOG_INFO, "%s: expand %s => %s",
205 e->e_id, e->e_to, user);
206#endif
dac6c90e 207 AliasLevel++;
1c7897ef 208 naddrs += sendtolist(user, a, sendq, e);
dac6c90e
EA
209 AliasLevel--;
210
211 if (user != buf)
212 free(user);
213
214 /* get the next record */
215 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
256fe397 216 }
1c7897ef 217 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
218 {
219 if (tTd(28, 5))
220 {
221 printf("udbexpand: QDONTSEND ");
222 printaddr(a, FALSE);
223 }
224 a->q_flags |= QDONTSEND;
225 }
6ab0fb92
EA
226 if (i < 0)
227 {
49a282c6
EA
228 syserr("udbexpand: db-get %.*s stat %d",
229 key.size, key.data, i);
6ab0fb92
EA
230 return EX_TEMPFAIL;
231 }
83b7c7b1
EA
232 break;
233
234 case UDB_REMOTE:
84a5cc29
EA
235 /* not yet implemented */
236 continue;
83b7c7b1
EA
237
238 case UDB_FORWARD:
fc14ab33
EA
239 if (bitset(EF_VRFYONLY, e->e_flags))
240 return EX_OK;
83b7c7b1
EA
241 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
242 if (i < sizeof buf)
243 user = buf;
244 else
245 user = xalloc(i + 1);
246 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
b6edea3d 247 message("expanded to %s", user);
1c7897ef 248 a->q_flags &= ~QSELFREF;
dac6c90e 249 AliasLevel++;
1c7897ef 250 naddrs = sendtolist(user, a, sendq, e);
dac6c90e 251 AliasLevel--;
1c7897ef 252 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
253 {
254 if (tTd(28, 5))
255 {
256 printf("udbexpand: QDONTSEND ");
257 printaddr(a, FALSE);
258 }
259 a->q_flags |= QDONTSEND;
260 }
dac6c90e
EA
261 if (user != buf)
262 free(user);
263 breakout = TRUE;
83b7c7b1
EA
264 break;
265
266 case UDB_EOLIST:
267 breakout = TRUE;
268 continue;
269
270 default:
271 /* unknown entry type */
272 continue;
273 }
dac6c90e 274 }
6ab0fb92 275 return EX_OK;
dac6c90e 276}
f61c3c40
EA
277\f/*
278** UDBSENDER -- return canonical external name of sender, given local name
279**
280** Parameters:
281** sender -- the name of the sender on the local machine.
282**
283** Returns:
284** The external name for this sender, if derivable from the
285** database.
286** NULL -- if nothing is changed from the database.
287**
288** Side Effects:
289** none.
290*/
291
292char *
293udbsender(sender)
294 char *sender;
295{
296 register char *p;
297 register struct udbent *up;
298 int i;
299 int keylen;
300 DBT key, info;
f43b04ce 301 char keybuf[MAXKEY];
f61c3c40
EA
302
303 if (tTd(28, 1))
304 printf("udbsender(%s)\n", sender);
305
306 if (!UdbInitialized)
307 {
308 if (_udbx_init() == EX_TEMPFAIL)
309 return NULL;
310 }
311
312 /* short circuit if no spec */
313 if (UdbSpec == NULL || UdbSpec[0] == '\0')
314 return NULL;
315
316 /* long names can never match and are a pain to deal with */
317 if (strlen(sender) > sizeof keybuf - 12)
318 return NULL;
319
320 /* names beginning with colons indicate metadata */
321 if (sender[0] == ':')
322 return NULL;
323
324 /* build database key */
325 (void) strcpy(keybuf, sender);
326 (void) strcat(keybuf, ":mailname");
327 keylen = strlen(keybuf);
328
329 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
330 {
331 /*
332 ** Select action based on entry type.
333 */
334
335 switch (up->udb_type)
336 {
337 case UDB_DBFETCH:
338 key.data = keybuf;
339 key.size = keylen;
340 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
341 if (i != 0 || info.size <= 0)
342 {
343 if (tTd(28, 2))
344 printf("udbsender: no match on %s\n",
345 keybuf);
346 continue;
347 }
348
349 p = xalloc(info.size + 1);
350 bcopy(info.data, p, info.size);
351 p[info.size] = '\0';
352 if (tTd(28, 1))
353 printf("udbsender ==> %s\n", p);
354 return p;
355 }
356 }
357
358 /*
359 ** Nothing yet. Search again for a default case. But only
360 ** use it if we also have a forward (:maildrop) pointer already
361 ** in the database.
362 */
363
364 /* build database key */
365 (void) strcpy(keybuf, sender);
366 (void) strcat(keybuf, ":maildrop");
367 keylen = strlen(keybuf);
368
369 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
370 {
371 switch (up->udb_type)
372 {
373 case UDB_DBFETCH:
374 /* get the default case for this database */
375 if (up->udb_default == NULL)
376 {
377 key.data = ":default:mailname";
378 key.size = strlen(key.data);
379 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
380 if (i != 0 || info.size <= 0)
381 {
382 /* no default case */
383 up->udb_default = "";
384 continue;
385 }
386
387 /* save the default case */
388 up->udb_default = xalloc(info.size + 1);
389 bcopy(info.data, up->udb_default, info.size);
390 up->udb_default[info.size] = '\0';
391 }
392 else if (up->udb_default[0] == '\0')
393 continue;
394
395 /* we have a default case -- verify user:maildrop */
396 key.data = keybuf;
397 key.size = keylen;
398 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
399 if (i != 0 || info.size <= 0)
400 {
401 /* nope -- no aliasing for this user */
402 continue;
403 }
404
405 /* they exist -- build the actual address */
406 p = xalloc(strlen(sender) + strlen(up->udb_default) + 2);
407 (void) strcpy(p, sender);
408 (void) strcat(p, "@");
409 (void) strcat(p, up->udb_default);
410 if (tTd(28, 1))
411 printf("udbsender ==> %s\n", p);
412 return p;
413 }
414 }
415
416 /* still nothing.... too bad */
417 return NULL;
418}
419\f/*
420** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
421**
422** Parameters:
423** none.
424**
425** Returns:
426** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
427** database due to a host being down or some similar
428** (recoverable) situation.
429** EX_OK -- otherwise.
430**
431** Side Effects:
432** Fills in the UdbEnts structure from UdbSpec.
433*/
83b7c7b1 434
7a059839
EA
435#define MAXUDBOPTS 27
436
d2836270 437int
dac6c90e
EA
438_udbx_init()
439{
440 register char *p;
441 int i;
442 register struct udbent *up;
f43b04ce 443 char buf[BUFSIZ];
83b7c7b1 444
f61c3c40
EA
445 if (UdbInitialized)
446 return EX_OK;
447
fe993526
EA
448# ifdef UDB_DEFAULT_SPEC
449 if (UdbSpec == NULL)
450 UdbSpec = UDB_DEFAULT_SPEC;
451# endif
452
dac6c90e
EA
453 p = UdbSpec;
454 up = UdbEnts;
b375cb3b 455 while (p != NULL)
dac6c90e
EA
456 {
457 char *spec;
458 auto int rcode;
7a059839 459 int nopts;
dac6c90e
EA
460 int nmx;
461 register struct hostent *h;
462 char *mxhosts[MAXMXHOSTS + 1];
7a059839 463 struct option opts[MAXUDBOPTS + 1];
dac6c90e
EA
464
465 while (*p == ' ' || *p == '\t' || *p == ',')
466 p++;
467 if (*p == '\0')
468 break;
469 spec = p;
f3d8f6d6 470 p = strchr(p, ',');
93f1f3e4 471 if (p != NULL)
dac6c90e 472 *p++ = '\0';
7a059839
EA
473
474 /* extract options */
475 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
476
477 /*
478 ** Decode database specification.
479 **
480 ** In the sendmail tradition, the leading character
481 ** defines the semantics of the rest of the entry.
482 **
483 ** +hostname -- send a datagram to the udb server
484 ** on host "hostname" asking for the
485 ** home mail server for this user.
486 ** *hostname -- similar to +hostname, except that the
487 ** hostname is searched as an MX record;
488 ** resulting hosts are searched as for
489 ** +mxhostname. If no MX host is found,
490 ** this is the same as +hostname.
491 ** @hostname -- forward email to the indicated host.
492 ** This should be the last in the list,
493 ** since it always matches the input.
494 ** /dbname -- search the named database on the local
495 ** host using the Berkeley db package.
496 */
497
dac6c90e 498 switch (*spec)
83b7c7b1 499 {
dac6c90e 500 case '+': /* search remote database */
7a059839
EA
501 case '*': /* search remote database (expand MX) */
502 if (*spec == '*')
dac6c90e 503 {
823cd830 504#ifdef NAMED_BIND
c3577cd6 505 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
823cd830
EA
506#else
507 mxhosts[0] = spec + 1;
508 nmx = 1;
509 rcode = 0;
510#endif
7a059839
EA
511 if (tTd(28, 16))
512 {
513 int i;
514
515 printf("getmxrr(%s): %d", spec + 1, nmx);
516 for (i = 0; i <= nmx; i++)
517 printf(" %s", mxhosts[i]);
518 printf("\n");
519 }
dac6c90e 520 }
7a059839 521 else
dac6c90e 522 {
7a059839
EA
523 nmx = 1;
524 mxhosts[0] = spec + 1;
dac6c90e 525 }
7a059839 526
dac6c90e
EA
527 for (i = 0; i < nmx; i++)
528 {
529 h = gethostbyname(mxhosts[i]);
530 if (h == NULL)
531 continue;
532 up->udb_type = UDB_REMOTE;
533 up->udb_addr.sin_family = h->h_addrtype;
dac6c90e
EA
534 bcopy(h->h_addr_list[0],
535 (char *) &up->udb_addr.sin_addr,
536 h->h_length);
537 up->udb_addr.sin_port = UdbPort;
538 up->udb_timeout = UdbTimeout;
539 up++;
540 }
541
542 /* set up a datagram socket */
543 if (UdbSock < 0)
544 {
545 UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
546 (void) fcntl(UdbSock, F_SETFD, 1);
547 }
548 break;
549
550 case '@': /* forward to remote host */
551 up->udb_type = UDB_FORWARD;
552 up->udb_fwdhost = spec + 1;
553 up++;
554 break;
555
556 case '/': /* look up remote name */
834f8378 557 up->udb_dbname = spec;
6ab0fb92 558 errno = 0;
dac6c90e
EA
559 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
560 if (up->udb_dbp == NULL)
6ab0fb92
EA
561 {
562 if (errno != ENOENT && errno != EACCES)
f61c3c40 563 {
73f6752a
EA
564#ifdef LOG
565 if (LogLevel > 2)
3f0792d1
EA
566 syslog(LOG_ERR, "dbopen(%s): %s",
567 spec, errstring(errno));
73f6752a 568#endif
f61c3c40
EA
569 up->udb_type = UDB_EOLIST;
570 goto tempfail;
571 }
dac6c90e 572 break;
6ab0fb92 573 }
f61c3c40 574 up->udb_type = UDB_DBFETCH;
dac6c90e
EA
575 up++;
576 break;
83b7c7b1 577 }
dac6c90e
EA
578 }
579 up->udb_type = UDB_EOLIST;
83b7c7b1 580
dac6c90e
EA
581 if (tTd(28, 4))
582 {
f61c3c40 583 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
83b7c7b1 584 {
dac6c90e
EA
585 switch (up->udb_type)
586 {
dac6c90e
EA
587 case UDB_REMOTE:
588 printf("REMOTE: addr %s, timeo %d\n",
3341995c 589 anynet_ntoa(&up->udb_addr),
dac6c90e
EA
590 up->udb_timeout);
591 break;
592
f61c3c40
EA
593 case UDB_DBFETCH:
594 printf("FETCH: file %s\n",
256fe397 595 up->udb_dbname);
dac6c90e
EA
596 break;
597
598 case UDB_FORWARD:
599 printf("FORWARD: host %s\n",
600 up->udb_fwdhost);
601 break;
602
603 default:
604 printf("UNKNOWN\n");
605 break;
606 }
83b7c7b1 607 }
814c4102 608 }
f61c3c40
EA
609
610 UdbInitialized = TRUE;
847ac56a 611 errno = 0;
f61c3c40
EA
612 return EX_OK;
613
614 /*
615 ** On temporary failure, back out anything we've already done
616 */
617
618 tempfail:
619 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
620 {
621 if (up->udb_type == UDB_DBFETCH)
622 {
623 (*up->udb_dbp->close)(up->udb_dbp);
624 }
625 }
626 return EX_TEMPFAIL;
83b7c7b1 627}
814c4102 628
7a059839
EA
629int
630_udb_parsespec(udbspec, opt, maxopts)
631 char *udbspec;
632 struct option opt[];
633 int maxopts;
634{
635 register char *spec;
636 register char *spec_end;
637 register int optnum;
638
f3d8f6d6 639 spec_end = strchr(udbspec, ':');
7a059839
EA
640 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
641 {
642 register char *p;
643
2bee003d 644 while (isascii(*spec) && isspace(*spec))
7a059839 645 spec++;
f3d8f6d6 646 spec_end = strchr(spec, ':');
7a059839
EA
647 if (spec_end != NULL)
648 *spec_end++ = '\0';
649
650 opt[optnum].name = spec;
651 opt[optnum].val = NULL;
f3d8f6d6 652 p = strchr(spec, '=');
7a059839
EA
653 if (p != NULL)
654 opt[optnum].val = ++p;
655 }
656 return optnum;
657}
658
83b7c7b1
EA
659#else /* not USERDB */
660
6ab0fb92 661int
a4076aed 662udbexpand(a, sendq, e)
83b7c7b1
EA
663 ADDRESS *a;
664 ADDRESS **sendq;
a4076aed 665 ENVELOPE *e;
83b7c7b1 666{
6ab0fb92 667 return EX_OK;
814c4102
EA
668}
669
670#endif /* USERDB */