was munmap'ing the wrong size
[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
f8a31c8e 11static char sccsid [] = "@(#)udb.c 6.13 (Berkeley) %G% (with USERDB)";
83b7c7b1 12#else
f8a31c8e 13static char sccsid [] = "@(#)udb.c 6.13 (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;
fc14ab33 189 return EX_OK;
8bcce465 190 }
fc14ab33 191
256fe397 192 breakout = TRUE;
dac6c90e
EA
193 if (info.size < sizeof buf)
194 user = buf;
195 else
196 user = xalloc(info.size + 1);
197 bcopy(info.data, user, info.size);
198 user[info.size] = '\0';
199
b6edea3d 200 message("expanded to %s", user);
aa102c71
EA
201#ifdef LOG
202 if (LogLevel >= 10)
203 syslog(LOG_INFO, "%s: expand %s => %s",
204 e->e_id, e->e_to, user);
205#endif
dac6c90e 206 AliasLevel++;
1c7897ef 207 naddrs += sendtolist(user, a, sendq, e);
dac6c90e
EA
208 AliasLevel--;
209
210 if (user != buf)
211 free(user);
212
213 /* get the next record */
214 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
256fe397 215 }
1c7897ef 216 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
217 {
218 if (tTd(28, 5))
219 {
220 printf("udbexpand: QDONTSEND ");
221 printaddr(a, FALSE);
222 }
223 a->q_flags |= QDONTSEND;
224 }
6ab0fb92
EA
225 if (i < 0)
226 {
49a282c6
EA
227 syserr("udbexpand: db-get %.*s stat %d",
228 key.size, key.data, i);
6ab0fb92
EA
229 return EX_TEMPFAIL;
230 }
83b7c7b1
EA
231 break;
232
233 case UDB_REMOTE:
84a5cc29
EA
234 /* not yet implemented */
235 continue;
83b7c7b1
EA
236
237 case UDB_FORWARD:
fc14ab33
EA
238 if (bitset(EF_VRFYONLY, e->e_flags))
239 return EX_OK;
83b7c7b1
EA
240 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
241 if (i < sizeof buf)
242 user = buf;
243 else
244 user = xalloc(i + 1);
245 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
b6edea3d 246 message("expanded to %s", user);
1c7897ef 247 a->q_flags &= ~QSELFREF;
dac6c90e 248 AliasLevel++;
1c7897ef 249 naddrs = sendtolist(user, a, sendq, e);
dac6c90e 250 AliasLevel--;
1c7897ef 251 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
252 {
253 if (tTd(28, 5))
254 {
255 printf("udbexpand: QDONTSEND ");
256 printaddr(a, FALSE);
257 }
258 a->q_flags |= QDONTSEND;
259 }
dac6c90e
EA
260 if (user != buf)
261 free(user);
262 breakout = TRUE;
83b7c7b1
EA
263 break;
264
265 case UDB_EOLIST:
266 breakout = TRUE;
267 continue;
268
269 default:
270 /* unknown entry type */
271 continue;
272 }
dac6c90e 273 }
6ab0fb92 274 return EX_OK;
dac6c90e 275}
f61c3c40
EA
276\f/*
277** UDBSENDER -- return canonical external name of sender, given local name
278**
279** Parameters:
280** sender -- the name of the sender on the local machine.
281**
282** Returns:
283** The external name for this sender, if derivable from the
284** database.
285** NULL -- if nothing is changed from the database.
286**
287** Side Effects:
288** none.
289*/
290
291char *
292udbsender(sender)
293 char *sender;
294{
295 register char *p;
296 register struct udbent *up;
297 int i;
298 int keylen;
299 DBT key, info;
f43b04ce 300 char keybuf[MAXKEY];
f61c3c40
EA
301
302 if (tTd(28, 1))
303 printf("udbsender(%s)\n", sender);
304
305 if (!UdbInitialized)
306 {
307 if (_udbx_init() == EX_TEMPFAIL)
308 return NULL;
309 }
310
311 /* short circuit if no spec */
312 if (UdbSpec == NULL || UdbSpec[0] == '\0')
313 return NULL;
314
315 /* long names can never match and are a pain to deal with */
316 if (strlen(sender) > sizeof keybuf - 12)
317 return NULL;
318
319 /* names beginning with colons indicate metadata */
320 if (sender[0] == ':')
321 return NULL;
322
323 /* build database key */
324 (void) strcpy(keybuf, sender);
325 (void) strcat(keybuf, ":mailname");
326 keylen = strlen(keybuf);
327
328 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
329 {
330 /*
331 ** Select action based on entry type.
332 */
333
334 switch (up->udb_type)
335 {
336 case UDB_DBFETCH:
337 key.data = keybuf;
338 key.size = keylen;
339 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
340 if (i != 0 || info.size <= 0)
341 {
342 if (tTd(28, 2))
343 printf("udbsender: no match on %s\n",
344 keybuf);
345 continue;
346 }
347
348 p = xalloc(info.size + 1);
349 bcopy(info.data, p, info.size);
350 p[info.size] = '\0';
351 if (tTd(28, 1))
352 printf("udbsender ==> %s\n", p);
353 return p;
354 }
355 }
356
357 /*
358 ** Nothing yet. Search again for a default case. But only
359 ** use it if we also have a forward (:maildrop) pointer already
360 ** in the database.
361 */
362
363 /* build database key */
364 (void) strcpy(keybuf, sender);
365 (void) strcat(keybuf, ":maildrop");
366 keylen = strlen(keybuf);
367
368 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
369 {
370 switch (up->udb_type)
371 {
372 case UDB_DBFETCH:
373 /* get the default case for this database */
374 if (up->udb_default == NULL)
375 {
376 key.data = ":default:mailname";
377 key.size = strlen(key.data);
378 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
379 if (i != 0 || info.size <= 0)
380 {
381 /* no default case */
382 up->udb_default = "";
383 continue;
384 }
385
386 /* save the default case */
387 up->udb_default = xalloc(info.size + 1);
388 bcopy(info.data, up->udb_default, info.size);
389 up->udb_default[info.size] = '\0';
390 }
391 else if (up->udb_default[0] == '\0')
392 continue;
393
394 /* we have a default case -- verify user:maildrop */
395 key.data = keybuf;
396 key.size = keylen;
397 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
398 if (i != 0 || info.size <= 0)
399 {
400 /* nope -- no aliasing for this user */
401 continue;
402 }
403
404 /* they exist -- build the actual address */
405 p = xalloc(strlen(sender) + strlen(up->udb_default) + 2);
406 (void) strcpy(p, sender);
407 (void) strcat(p, "@");
408 (void) strcat(p, up->udb_default);
409 if (tTd(28, 1))
410 printf("udbsender ==> %s\n", p);
411 return p;
412 }
413 }
414
415 /* still nothing.... too bad */
416 return NULL;
417}
418\f/*
419** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
420**
421** Parameters:
422** none.
423**
424** Returns:
425** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
426** database due to a host being down or some similar
427** (recoverable) situation.
428** EX_OK -- otherwise.
429**
430** Side Effects:
431** Fills in the UdbEnts structure from UdbSpec.
432*/
83b7c7b1 433
7a059839
EA
434#define MAXUDBOPTS 27
435
d2836270 436int
dac6c90e
EA
437_udbx_init()
438{
439 register char *p;
440 int i;
441 register struct udbent *up;
f43b04ce 442 char buf[BUFSIZ];
83b7c7b1 443
f61c3c40
EA
444 if (UdbInitialized)
445 return EX_OK;
446
fe993526
EA
447# ifdef UDB_DEFAULT_SPEC
448 if (UdbSpec == NULL)
449 UdbSpec = UDB_DEFAULT_SPEC;
450# endif
451
dac6c90e
EA
452 p = UdbSpec;
453 up = UdbEnts;
b375cb3b 454 while (p != NULL)
dac6c90e
EA
455 {
456 char *spec;
457 auto int rcode;
7a059839 458 int nopts;
dac6c90e
EA
459 int nmx;
460 register struct hostent *h;
461 char *mxhosts[MAXMXHOSTS + 1];
7a059839 462 struct option opts[MAXUDBOPTS + 1];
dac6c90e
EA
463
464 while (*p == ' ' || *p == '\t' || *p == ',')
465 p++;
466 if (*p == '\0')
467 break;
468 spec = p;
f3d8f6d6 469 p = strchr(p, ',');
93f1f3e4 470 if (p != NULL)
dac6c90e 471 *p++ = '\0';
7a059839
EA
472
473 /* extract options */
474 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
475
476 /*
477 ** Decode database specification.
478 **
479 ** In the sendmail tradition, the leading character
480 ** defines the semantics of the rest of the entry.
481 **
482 ** +hostname -- send a datagram to the udb server
483 ** on host "hostname" asking for the
484 ** home mail server for this user.
485 ** *hostname -- similar to +hostname, except that the
486 ** hostname is searched as an MX record;
487 ** resulting hosts are searched as for
488 ** +mxhostname. If no MX host is found,
489 ** this is the same as +hostname.
490 ** @hostname -- forward email to the indicated host.
491 ** This should be the last in the list,
492 ** since it always matches the input.
493 ** /dbname -- search the named database on the local
494 ** host using the Berkeley db package.
495 */
496
dac6c90e 497 switch (*spec)
83b7c7b1 498 {
dac6c90e 499 case '+': /* search remote database */
7a059839
EA
500 case '*': /* search remote database (expand MX) */
501 if (*spec == '*')
dac6c90e 502 {
823cd830 503#ifdef NAMED_BIND
7a059839 504 nmx = getmxrr(spec + 1, mxhosts, "", &rcode);
823cd830
EA
505#else
506 mxhosts[0] = spec + 1;
507 nmx = 1;
508 rcode = 0;
509#endif
7a059839
EA
510 if (tTd(28, 16))
511 {
512 int i;
513
514 printf("getmxrr(%s): %d", spec + 1, nmx);
515 for (i = 0; i <= nmx; i++)
516 printf(" %s", mxhosts[i]);
517 printf("\n");
518 }
dac6c90e 519 }
7a059839 520 else
dac6c90e 521 {
7a059839
EA
522 nmx = 1;
523 mxhosts[0] = spec + 1;
dac6c90e 524 }
7a059839 525
dac6c90e
EA
526 for (i = 0; i < nmx; i++)
527 {
528 h = gethostbyname(mxhosts[i]);
529 if (h == NULL)
530 continue;
531 up->udb_type = UDB_REMOTE;
532 up->udb_addr.sin_family = h->h_addrtype;
dac6c90e
EA
533 bcopy(h->h_addr_list[0],
534 (char *) &up->udb_addr.sin_addr,
535 h->h_length);
536 up->udb_addr.sin_port = UdbPort;
537 up->udb_timeout = UdbTimeout;
538 up++;
539 }
540
541 /* set up a datagram socket */
542 if (UdbSock < 0)
543 {
544 UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
545 (void) fcntl(UdbSock, F_SETFD, 1);
546 }
547 break;
548
549 case '@': /* forward to remote host */
550 up->udb_type = UDB_FORWARD;
551 up->udb_fwdhost = spec + 1;
552 up++;
553 break;
554
555 case '/': /* look up remote name */
834f8378 556 up->udb_dbname = spec;
6ab0fb92 557 errno = 0;
dac6c90e
EA
558 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
559 if (up->udb_dbp == NULL)
6ab0fb92
EA
560 {
561 if (errno != ENOENT && errno != EACCES)
f61c3c40
EA
562 {
563 up->udb_type = UDB_EOLIST;
564 goto tempfail;
565 }
dac6c90e 566 break;
6ab0fb92 567 }
f61c3c40 568 up->udb_type = UDB_DBFETCH;
dac6c90e
EA
569 up++;
570 break;
83b7c7b1 571 }
dac6c90e
EA
572 }
573 up->udb_type = UDB_EOLIST;
83b7c7b1 574
dac6c90e
EA
575 if (tTd(28, 4))
576 {
f61c3c40 577 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
83b7c7b1 578 {
dac6c90e
EA
579 switch (up->udb_type)
580 {
dac6c90e
EA
581 case UDB_REMOTE:
582 printf("REMOTE: addr %s, timeo %d\n",
583 inet_ntoa(up->udb_addr.sin_addr),
584 up->udb_timeout);
585 break;
586
f61c3c40
EA
587 case UDB_DBFETCH:
588 printf("FETCH: file %s\n",
256fe397 589 up->udb_dbname);
dac6c90e
EA
590 break;
591
592 case UDB_FORWARD:
593 printf("FORWARD: host %s\n",
594 up->udb_fwdhost);
595 break;
596
597 default:
598 printf("UNKNOWN\n");
599 break;
600 }
83b7c7b1 601 }
814c4102 602 }
f61c3c40
EA
603
604 UdbInitialized = TRUE;
847ac56a 605 errno = 0;
f61c3c40
EA
606 return EX_OK;
607
608 /*
609 ** On temporary failure, back out anything we've already done
610 */
611
612 tempfail:
613 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
614 {
615 if (up->udb_type == UDB_DBFETCH)
616 {
617 (*up->udb_dbp->close)(up->udb_dbp);
618 }
619 }
620 return EX_TEMPFAIL;
83b7c7b1 621}
814c4102 622
7a059839
EA
623int
624_udb_parsespec(udbspec, opt, maxopts)
625 char *udbspec;
626 struct option opt[];
627 int maxopts;
628{
629 register char *spec;
630 register char *spec_end;
631 register int optnum;
632
f3d8f6d6 633 spec_end = strchr(udbspec, ':');
7a059839
EA
634 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
635 {
636 register char *p;
637
2bee003d 638 while (isascii(*spec) && isspace(*spec))
7a059839 639 spec++;
f3d8f6d6 640 spec_end = strchr(spec, ':');
7a059839
EA
641 if (spec_end != NULL)
642 *spec_end++ = '\0';
643
644 opt[optnum].name = spec;
645 opt[optnum].val = NULL;
f3d8f6d6 646 p = strchr(spec, '=');
7a059839
EA
647 if (p != NULL)
648 opt[optnum].val = ++p;
649 }
650 return optnum;
651}
652
83b7c7b1
EA
653#else /* not USERDB */
654
6ab0fb92 655int
a4076aed 656udbexpand(a, sendq, e)
83b7c7b1
EA
657 ADDRESS *a;
658 ADDRESS **sendq;
a4076aed 659 ENVELOPE *e;
83b7c7b1 660{
6ab0fb92 661 return EX_OK;
814c4102
EA
662}
663
664#endif /* USERDB */