1 /*
2 * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #include <sendmail.h>
15 #include "map.h"
16
17 #if USERDB
18 SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)")
19 #else
20 SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)")
21 #endif
22
23 #if USERDB
24
25 #include <sm/sendmail.h>
26 # if NEWDB
27 # include "sm/bdb.h"
28 # else /* NEWDB */
29 # define DBT struct _data_base_thang_
30 DBT
31 {
32 void *data; /* pointer to data */
33 size_t size; /* length of data */
34 };
35 # endif /* NEWDB */
36
37 /*
38 ** UDB.C -- interface between sendmail and Berkeley User Data Base.
39 **
40 ** This depends on the 4.4BSD db package.
41 */
42
43
44 struct udbent
45 {
46 char *udb_spec; /* string version of spec */
47 int udb_type; /* type of entry */
48 pid_t udb_pid; /* PID of process which opened db */
49 char *udb_default; /* default host for outgoing mail */
50 union
51 {
52 # if NETINET || NETINET6
53 /* type UE_REMOTE -- do remote call for lookup */
54 struct
55 {
56 SOCKADDR _udb_addr; /* address */
57 int _udb_timeout; /* timeout */
58 } udb_remote;
59 # define udb_addr udb_u.udb_remote._udb_addr
60 # define udb_timeout udb_u.udb_remote._udb_timeout
61 # endif /* NETINET || NETINET6 */
62
63 /* type UE_FORWARD -- forward message to remote */
64 struct
65 {
66 char *_udb_fwdhost; /* name of forward host */
67 } udb_forward;
68 # define udb_fwdhost udb_u.udb_forward._udb_fwdhost
69
70 # if NEWDB
71 /* type UE_FETCH -- lookup in local database */
72 struct
73 {
74 char *_udb_dbname; /* pathname of database */
75 DB *_udb_dbp; /* open database ptr */
76 } udb_lookup;
77 # define udb_dbname udb_u.udb_lookup._udb_dbname
78 # define udb_dbp udb_u.udb_lookup._udb_dbp
79 # endif /* NEWDB */
80 } udb_u;
81 };
82
83 # define UDB_EOLIST 0 /* end of list */
84 # define UDB_SKIP 1 /* skip this entry */
85 # define UDB_REMOTE 2 /* look up in remote database */
86 # define UDB_DBFETCH 3 /* look up in local database */
87 # define UDB_FORWARD 4 /* forward to remote host */
88 # define UDB_HESIOD 5 /* look up via hesiod */
89
90 # define MAXUDBENT 10 /* maximum number of UDB entries */
91
92
93 struct udb_option
94 {
95 char *udbo_name;
96 char *udbo_val;
97 };
98
99 # if HESIOD
100 static int hes_udb_get __P((DBT *, DBT *));
101 # endif
102 static char *udbmatch __P((char *, char *, SM_RPOOL_T *));
103 static int _udbx_init __P((ENVELOPE *));
104 static int _udb_parsespec __P((char *, struct udb_option [], int));
105
106 /*
107 ** UDBEXPAND -- look up user in database and expand
108 **
109 ** Parameters:
110 ** a -- address to expand.
111 ** sendq -- pointer to head of sendq to put the expansions in.
112 ** aliaslevel -- the current alias nesting depth.
113 ** e -- the current envelope.
114 **
115 ** Returns:
116 ** EX_TEMPFAIL -- if something "odd" happened -- probably due
117 ** to accessing a file on an NFS server that is down.
118 ** EX_OK -- otherwise.
119 **
120 ** Side Effects:
121 ** Modifies sendq.
122 */
123
124 static struct udbent UdbEnts[MAXUDBENT + 1];
125 static bool UdbInitialized = false;
126
127 int
udbexpand(a,sendq,aliaslevel,e)128 udbexpand(a, sendq, aliaslevel, e)
129 register ADDRESS *a;
130 ADDRESS **sendq;
131 int aliaslevel;
132 register ENVELOPE *e;
133 {
134 int i;
135 DBT key;
136 DBT info;
137 bool breakout;
138 register struct udbent *up;
139 int keylen;
140 int naddrs;
141 char *user;
142 char keybuf[MAXUDBKEY];
143
144 memset(&key, '\0', sizeof(key));
145 memset(&info, '\0', sizeof(info));
146
147 if (tTd(28, 1))
148 sm_dprintf("udbexpand(%s)\n", a->q_paddr);
149
150 /* make certain we are supposed to send to this address */
151 if (!QS_IS_SENDABLE(a->q_state))
152 return EX_OK;
153 e->e_to = a->q_paddr;
154
155 /* on first call, locate the database */
156 if (!UdbInitialized)
157 {
158 if (_udbx_init(e) == EX_TEMPFAIL)
159 return EX_TEMPFAIL;
160 }
161
162 /* short circuit the process if no chance of a match */
163 if (UdbSpec == NULL || UdbSpec[0] == '\0')
164 return EX_OK;
165
166 /* extract user to do userdb matching on */
167 user = a->q_user;
168
169 /* short circuit name begins with '\\' since it can't possibly match */
170 /* (might want to treat this as unquoted instead) */
171 if (user[0] == '\\')
172 return EX_OK;
173
174 /* if name begins with a colon, it indicates our metadata */
175 if (user[0] == ':')
176 return EX_OK;
177
178 keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
179
180 /* if name is too long, assume it won't match */
181 if (keylen >= sizeof(keybuf))
182 return EX_OK;
183
184 /* build actual database key */
185
186 breakout = false;
187 for (up = UdbEnts; !breakout; up++)
188 {
189 int usersize;
190 # if NEWDB
191 int userleft;
192 # endif
193 char userbuf[MEMCHUNKSIZE];
194 # if HESIOD && HES_GETMAILHOST
195 char pobuf[MAXNAME];
196 # endif
197 # if defined(NEWDB) && DB_VERSION_MAJOR > 1
198 DBC *dbc = NULL;
199 # endif
200
201 user = userbuf;
202 userbuf[0] = '\0';
203 usersize = sizeof(userbuf);
204 # if NEWDB
205 userleft = sizeof(userbuf) - 1;
206 # endif
207
208 /*
209 ** Select action based on entry type.
210 **
211 ** On dropping out of this switch, "class" should
212 ** explain the type of the data, and "user" should
213 ** contain the user information.
214 */
215
216 switch (up->udb_type)
217 {
218 # if NEWDB
219 case UDB_DBFETCH:
220 key.data = keybuf;
221 key.size = keylen;
222 if (tTd(28, 80))
223 sm_dprintf("udbexpand: trying %s (%d) via db\n",
224 keybuf, keylen);
225 # if DB_VERSION_MAJOR < 2
226 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
227 # else /* DB_VERSION_MAJOR < 2 */
228 i = 0;
229 if (dbc == NULL &&
230 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
231 (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
232 NULL, &dbc, 0)) != 0)
233 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
234 (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
235 NULL, &dbc)) != 0)
236 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
237 i = -1;
238 if (i != 0 || dbc == NULL ||
239 (errno = dbc->c_get(dbc, &key,
240 &info, DB_SET)) != 0)
241 i = 1;
242 # endif /* DB_VERSION_MAJOR < 2 */
243 if (i > 0 || info.size <= 0)
244 {
245 if (tTd(28, 2))
246 sm_dprintf("udbexpand: no match on %s (%d)\n",
247 keybuf, keylen);
248 # if DB_VERSION_MAJOR > 1
249 if (dbc != NULL)
250 {
251 (void) dbc->c_close(dbc);
252 dbc = NULL;
253 }
254 # endif /* DB_VERSION_MAJOR > 1 */
255 break;
256 }
257 if (tTd(28, 80))
258 sm_dprintf("udbexpand: match %.*s: %.*s\n",
259 (int) key.size, (char *) key.data,
260 (int) info.size, (char *) info.data);
261
262 a->q_flags &= ~QSELFREF;
263 while (i == 0 && key.size == keylen &&
264 memcmp(key.data, keybuf, keylen) == 0)
265 {
266 char *p;
267
268 if (bitset(EF_VRFYONLY, e->e_flags))
269 {
270 a->q_state = QS_VERIFIED;
271 # if DB_VERSION_MAJOR > 1
272 if (dbc != NULL)
273 {
274 (void) dbc->c_close(dbc);
275 dbc = NULL;
276 }
277 # endif /* DB_VERSION_MAJOR > 1 */
278 return EX_OK;
279 }
280
281 breakout = true;
282 if (info.size >= userleft - 1)
283 {
284 char *nuser;
285 int size = MEMCHUNKSIZE;
286
287 if (info.size > MEMCHUNKSIZE)
288 size = info.size;
289 nuser = sm_malloc_x(usersize + size);
290
291 memmove(nuser, user, usersize);
292 if (user != userbuf)
293 sm_free(user); /* XXX */
294 user = nuser;
295 usersize += size;
296 userleft += size;
297 }
298 p = &user[strlen(user)];
299 if (p != user)
300 {
301 *p++ = ',';
302 userleft--;
303 }
304 memmove(p, info.data, info.size);
305 p[info.size] = '\0';
306 userleft -= info.size;
307
308 /* get the next record */
309 # if DB_VERSION_MAJOR < 2
310 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
311 # else /* DB_VERSION_MAJOR < 2 */
312 i = 0;
313 if ((errno = dbc->c_get(dbc, &key,
314 &info, DB_NEXT)) != 0)
315 i = 1;
316 # endif /* DB_VERSION_MAJOR < 2 */
317 }
318
319 # if DB_VERSION_MAJOR > 1
320 if (dbc != NULL)
321 {
322 (void) dbc->c_close(dbc);
323 dbc = NULL;
324 }
325 # endif /* DB_VERSION_MAJOR > 1 */
326
327 /* if nothing ever matched, try next database */
328 if (!breakout)
329 break;
330
331 message("expanded to %s", user);
332 if (LogLevel > 10)
333 sm_syslog(LOG_INFO, e->e_id,
334 "expand %.100s => %s",
335 e->e_to,
336 shortenstring(user, MAXSHORTSTR));
337 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
338 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
339 {
340 if (tTd(28, 5))
341 {
342 sm_dprintf("udbexpand: QS_EXPANDED ");
343 printaddr(sm_debug_file(), a, false);
344 }
345 a->q_state = QS_EXPANDED;
346 }
347 if (i < 0)
348 {
349 syserr("udbexpand: db-get %.*s stat %d",
350 (int) key.size, (char *) key.data, i);
351 return EX_TEMPFAIL;
352 }
353
354 /*
355 ** If this address has a -request address, reflect
356 ** it into the envelope.
357 */
358
359 memset(&key, '\0', sizeof(key));
360 memset(&info, '\0', sizeof(info));
361 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
362 ":mailsender");
363 keylen = strlen(keybuf);
364 key.data = keybuf;
365 key.size = keylen;
366
367 # if DB_VERSION_MAJOR < 2
368 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
369 # else
370 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
371 &key, &info, 0);
372 # endif
373 if (i != 0 || info.size <= 0)
374 break;
375 a->q_owner = sm_rpool_malloc_x(e->e_rpool,
376 info.size + 1);
377 memmove(a->q_owner, info.data, info.size);
378 a->q_owner[info.size] = '\0';
379
380 /* announce delivery; NORECEIPT bit set later */
381 if (e->e_xfp != NULL)
382 {
383 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
384 "Message delivered to mailing list %s\n",
385 a->q_paddr);
386 }
387 e->e_flags |= EF_SENDRECEIPT;
388 a->q_flags |= QDELIVERED|QEXPANDED;
389 break;
390 # endif /* NEWDB */
391
392 # if HESIOD
393 case UDB_HESIOD:
394 key.data = keybuf;
395 key.size = keylen;
396 if (tTd(28, 80))
397 sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
398 keybuf, keylen);
399 /* look up the key via hesiod */
400 i = hes_udb_get(&key, &info);
401 if (i < 0)
402 {
403 syserr("udbexpand: hesiod-get %.*s stat %d",
404 (int) key.size, (char *) key.data, i);
405 return EX_TEMPFAIL;
406 }
407 else if (i > 0 || info.size <= 0)
408 {
409 # if HES_GETMAILHOST
410 struct hes_postoffice *hp;
411 # endif
412
413 if (tTd(28, 2))
414 sm_dprintf("udbexpand: no match on %s (%d)\n",
415 (char *) keybuf, (int) keylen);
416 # if HES_GETMAILHOST
417 if (tTd(28, 8))
418 sm_dprintf(" ... trying hes_getmailhost(%s)\n",
419 a->q_user);
420 hp = hes_getmailhost(a->q_user);
421 if (hp == NULL)
422 {
423 if (hes_error() == HES_ER_NET)
424 {
425 syserr("udbexpand: hesiod-getmail %s stat %d",
426 a->q_user, hes_error());
427 return EX_TEMPFAIL;
428 }
429 if (tTd(28, 2))
430 sm_dprintf("hes_getmailhost(%s): %d\n",
431 a->q_user, hes_error());
432 break;
433 }
434 if (strlen(hp->po_name) + strlen(hp->po_host) >
435 sizeof(pobuf) - 2)
436 {
437 if (tTd(28, 2))
438 sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
439 a->q_user,
440 hp->po_name,
441 hp->po_host);
442 break;
443 }
444 info.data = pobuf;
445 (void) sm_snprintf(pobuf, sizeof(pobuf),
446 "%s@%s", hp->po_name, hp->po_host);
447 info.size = strlen(info.data);
448 # else /* HES_GETMAILHOST */
449 break;
450 # endif /* HES_GETMAILHOST */
451 }
452 if (tTd(28, 80))
453 sm_dprintf("udbexpand: match %.*s: %.*s\n",
454 (int) key.size, (char *) key.data,
455 (int) info.size, (char *) info.data);
456 a->q_flags &= ~QSELFREF;
457
458 if (bitset(EF_VRFYONLY, e->e_flags))
459 {
460 a->q_state = QS_VERIFIED;
461 return EX_OK;
462 }
463
464 breakout = true;
465 if (info.size >= usersize)
466 user = sm_malloc_x(info.size + 1);
467 memmove(user, info.data, info.size);
468 user[info.size] = '\0';
469
470 message("hesioded to %s", user);
471 if (LogLevel > 10)
472 sm_syslog(LOG_INFO, e->e_id,
473 "hesiod %.100s => %s",
474 e->e_to,
475 shortenstring(user, MAXSHORTSTR));
476 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
477
478 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
479 {
480 if (tTd(28, 5))
481 {
482 sm_dprintf("udbexpand: QS_EXPANDED ");
483 printaddr(sm_debug_file(), a, false);
484 }
485 a->q_state = QS_EXPANDED;
486 }
487
488 /*
489 ** If this address has a -request address, reflect
490 ** it into the envelope.
491 */
492
493 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
494 ":mailsender");
495 keylen = strlen(keybuf);
496 key.data = keybuf;
497 key.size = keylen;
498 i = hes_udb_get(&key, &info);
499 if (i != 0 || info.size <= 0)
500 break;
501 a->q_owner = sm_rpool_malloc_x(e->e_rpool,
502 info.size + 1);
503 memmove(a->q_owner, info.data, info.size);
504 a->q_owner[info.size] = '\0';
505 break;
506 # endif /* HESIOD */
507
508 case UDB_REMOTE:
509 /* not yet implemented */
510 break;
511
512 case UDB_FORWARD:
513 if (bitset(EF_VRFYONLY, e->e_flags))
514 {
515 a->q_state = QS_VERIFIED;
516 return EX_OK;
517 }
518 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
519 if (i >= usersize)
520 {
521 usersize = i + 1;
522 user = sm_malloc_x(usersize);
523 }
524 (void) sm_strlcpyn(user, usersize, 3,
525 a->q_user, "@", up->udb_fwdhost);
526 message("expanded to %s", user);
527 a->q_flags &= ~QSELFREF;
528 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
529 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
530 {
531 if (tTd(28, 5))
532 {
533 sm_dprintf("udbexpand: QS_EXPANDED ");
534 printaddr(sm_debug_file(), a, false);
535 }
536 a->q_state = QS_EXPANDED;
537 }
538 breakout = true;
539 break;
540
541 case UDB_EOLIST:
542 breakout = true;
543 break;
544
545 default:
546 /* unknown entry type */
547 break;
548 }
549 /* XXX if an exception occurs, there is a storage leak */
550 if (user != userbuf)
551 sm_free(user); /* XXX */
552 }
553 return EX_OK;
554 }
555 /*
556 ** UDBSENDER -- return canonical external name of sender, given local name
557 **
558 ** Parameters:
559 ** sender -- the name of the sender on the local machine.
560 ** rpool -- resource pool from which to allocate result
561 **
562 ** Returns:
563 ** The external name for this sender, if derivable from the
564 ** database. Storage allocated from rpool.
565 ** NULL -- if nothing is changed from the database.
566 **
567 ** Side Effects:
568 ** none.
569 */
570
571 char *
udbsender(sender,rpool)572 udbsender(sender, rpool)
573 char *sender;
574 SM_RPOOL_T *rpool;
575 {
576 return udbmatch(sender, "mailname", rpool);
577 }
578 /*
579 ** UDBMATCH -- match user in field, return result of lookup.
580 **
581 ** Parameters:
582 ** user -- the name of the user.
583 ** field -- the field to lookup.
584 ** rpool -- resource pool from which to allocate result
585 **
586 ** Returns:
587 ** The external name for this sender, if derivable from the
588 ** database. Storage allocated from rpool.
589 ** NULL -- if nothing is changed from the database.
590 **
591 ** Side Effects:
592 ** none.
593 */
594
595 static char *
udbmatch(user,field,rpool)596 udbmatch(user, field, rpool)
597 char *user;
598 char *field;
599 SM_RPOOL_T *rpool;
600 {
601 register char *p;
602 register struct udbent *up;
603 int i;
604 int keylen;
605 DBT key, info;
606 char keybuf[MAXUDBKEY];
607
608 if (tTd(28, 1))
609 sm_dprintf("udbmatch(%s, %s)\n", user, field);
610
611 if (!UdbInitialized)
612 {
613 if (_udbx_init(CurEnv) == EX_TEMPFAIL)
614 return NULL;
615 }
616
617 /* short circuit if no spec */
618 if (UdbSpec == NULL || UdbSpec[0] == '\0')
619 return NULL;
620
621 /* short circuit name begins with '\\' since it can't possibly match */
622 if (user[0] == '\\')
623 return NULL;
624
625 /* long names can never match and are a pain to deal with */
626 i = strlen(field);
627 if (i < sizeof("maildrop"))
628 i = sizeof("maildrop");
629 if ((strlen(user) + i) > sizeof(keybuf) - 4)
630 return NULL;
631
632 /* names beginning with colons indicate metadata */
633 if (user[0] == ':')
634 return NULL;
635
636 /* build database key */
637 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
638 keylen = strlen(keybuf);
639
640 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
641 {
642 /*
643 ** Select action based on entry type.
644 */
645
646 switch (up->udb_type)
647 {
648 # if NEWDB
649 case UDB_DBFETCH:
650 memset(&key, '\0', sizeof(key));
651 memset(&info, '\0', sizeof(info));
652 key.data = keybuf;
653 key.size = keylen;
654 # if DB_VERSION_MAJOR < 2
655 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
656 # else
657 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
658 &key, &info, 0);
659 # endif
660 if (i != 0 || info.size <= 0)
661 {
662 if (tTd(28, 2))
663 sm_dprintf("udbmatch: no match on %s (%d) via db\n",
664 keybuf, keylen);
665 continue;
666 }
667
668 p = sm_rpool_malloc_x(rpool, info.size + 1);
669 memmove(p, info.data, info.size);
670 p[info.size] = '\0';
671 if (tTd(28, 1))
672 sm_dprintf("udbmatch ==> %s\n", p);
673 return p;
674 # endif /* NEWDB */
675
676 # if HESIOD
677 case UDB_HESIOD:
678 key.data = keybuf;
679 key.size = keylen;
680 i = hes_udb_get(&key, &info);
681 if (i != 0 || info.size <= 0)
682 {
683 if (tTd(28, 2))
684 sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
685 keybuf, keylen);
686 continue;
687 }
688
689 p = sm_rpool_malloc_x(rpool, info.size + 1);
690 memmove(p, info.data, info.size);
691 p[info.size] = '\0';
692 if (tTd(28, 1))
693 sm_dprintf("udbmatch ==> %s\n", p);
694 return p;
695 # endif /* HESIOD */
696 }
697 }
698
699 if (strcmp(field, "mailname") != 0)
700 return NULL;
701
702 /*
703 ** Nothing yet. Search again for a default case. But only
704 ** use it if we also have a forward (:maildrop) pointer already
705 ** in the database.
706 */
707
708 /* build database key */
709 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
710 keylen = strlen(keybuf);
711
712 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
713 {
714 switch (up->udb_type)
715 {
716 # if NEWDB
717 case UDB_DBFETCH:
718 /* get the default case for this database */
719 if (up->udb_default == NULL)
720 {
721 memset(&key, '\0', sizeof(key));
722 memset(&info, '\0', sizeof(info));
723 key.data = ":default:mailname";
724 key.size = strlen(key.data);
725 # if DB_VERSION_MAJOR < 2
726 i = (*up->udb_dbp->get)(up->udb_dbp,
727 &key, &info, 0);
728 # else /* DB_VERSION_MAJOR < 2 */
729 i = errno = (*up->udb_dbp->get)(up->udb_dbp,
730 NULL, &key,
731 &info, 0);
732 # endif /* DB_VERSION_MAJOR < 2 */
733 if (i != 0 || info.size <= 0)
734 {
735 /* no default case */
736 up->udb_default = "";
737 continue;
738 }
739
740 /* save the default case */
741 up->udb_default = sm_pmalloc_x(info.size + 1);
742 memmove(up->udb_default, info.data, info.size);
743 up->udb_default[info.size] = '\0';
744 }
745 else if (up->udb_default[0] == '\0')
746 continue;
747
748 /* we have a default case -- verify user:maildrop */
749 memset(&key, '\0', sizeof(key));
750 memset(&info, '\0', sizeof(info));
751 key.data = keybuf;
752 key.size = keylen;
753 # if DB_VERSION_MAJOR < 2
754 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
755 # else
756 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
757 &key, &info, 0);
758 # endif
759 if (i != 0 || info.size <= 0)
760 {
761 /* nope -- no aliasing for this user */
762 continue;
763 }
764
765 /* they exist -- build the actual address */
766 i = strlen(user) + strlen(up->udb_default) + 2;
767 p = sm_rpool_malloc_x(rpool, i);
768 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
769 if (tTd(28, 1))
770 sm_dprintf("udbmatch ==> %s\n", p);
771 return p;
772 # endif /* NEWDB */
773
774 # if HESIOD
775 case UDB_HESIOD:
776 /* get the default case for this database */
777 if (up->udb_default == NULL)
778 {
779 key.data = ":default:mailname";
780 key.size = strlen(key.data);
781 i = hes_udb_get(&key, &info);
782
783 if (i != 0 || info.size <= 0)
784 {
785 /* no default case */
786 up->udb_default = "";
787 continue;
788 }
789
790 /* save the default case */
791 up->udb_default = sm_pmalloc_x(info.size + 1);
792 memmove(up->udb_default, info.data, info.size);
793 up->udb_default[info.size] = '\0';
794 }
795 else if (up->udb_default[0] == '\0')
796 continue;
797
798 /* we have a default case -- verify user:maildrop */
799 key.data = keybuf;
800 key.size = keylen;
801 i = hes_udb_get(&key, &info);
802 if (i != 0 || info.size <= 0)
803 {
804 /* nope -- no aliasing for this user */
805 continue;
806 }
807
808 /* they exist -- build the actual address */
809 i = strlen(user) + strlen(up->udb_default) + 2;
810 p = sm_rpool_malloc_x(rpool, i);
811 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
812 if (tTd(28, 1))
813 sm_dprintf("udbmatch ==> %s\n", p);
814 return p;
815 break;
816 # endif /* HESIOD */
817 }
818 }
819
820 /* still nothing.... too bad */
821 return NULL;
822 }
823 /*
824 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
825 **
826 ** Parameters:
827 ** map -- the map being queried.
828 ** name -- the name to look up.
829 ** av -- arguments to the map lookup.
830 ** statp -- to get any error status.
831 **
832 ** Returns:
833 ** NULL if name not found in map.
834 ** The rewritten name otherwise.
835 */
836
837 /* ARGSUSED3 */
838 char *
udb_map_lookup(map,name,av,statp)839 udb_map_lookup(map, name, av, statp)
840 MAP *map;
841 char *name;
842 char **av;
843 int *statp;
844 {
845 char *val;
846 char *key;
847 char *SM_NONVOLATILE result = NULL;
848 char keybuf[MAXNAME + 1];
849
850 if (tTd(28, 20) || tTd(38, 20))
851 sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
852
853 if (bitset(MF_NOFOLDCASE, map->map_mflags))
854 {
855 key = name;
856 }
857 else
858 {
859 int keysize = strlen(name);
860
861 if (keysize > sizeof(keybuf) - 1)
862 keysize = sizeof(keybuf) - 1;
863 memmove(keybuf, name, keysize);
864 keybuf[keysize] = '\0';
865 makelower(keybuf);
866 key = keybuf;
867 }
868 val = udbmatch(key, map->map_file, NULL);
869 if (val == NULL)
870 return NULL;
871 SM_TRY
872 if (bitset(MF_MATCHONLY, map->map_mflags))
873 result = map_rewrite(map, name, strlen(name), NULL);
874 else
875 result = map_rewrite(map, val, strlen(val), av);
876 SM_FINALLY
877 sm_free(val);
878 SM_END_TRY
879 return result;
880 }
881 /*
882 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
883 **
884 ** Parameters:
885 ** e -- the current envelope.
886 **
887 ** Returns:
888 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
889 ** database due to a host being down or some similar
890 ** (recoverable) situation.
891 ** EX_OK -- otherwise.
892 **
893 ** Side Effects:
894 ** Fills in the UdbEnts structure from UdbSpec.
895 */
896
897 # define MAXUDBOPTS 27
898
899 static int
_udbx_init(e)900 _udbx_init(e)
901 ENVELOPE *e;
902 {
903 int ents = 0;
904 register char *p;
905 register struct udbent *up;
906
907 if (UdbInitialized)
908 return EX_OK;
909
910 # ifdef UDB_DEFAULT_SPEC
911 if (UdbSpec == NULL)
912 UdbSpec = UDB_DEFAULT_SPEC;
913 # endif
914
915 p = UdbSpec;
916 up = UdbEnts;
917 while (p != NULL)
918 {
919 char *spec;
920 # if NEWDB
921 int l;
922 # endif
923 struct udb_option opts[MAXUDBOPTS + 1];
924
925 while (*p == ' ' || *p == '\t' || *p == ',')
926 p++;
927 if (*p == '\0')
928 break;
929 spec = p;
930 p = strchr(p, ',');
931 if (p != NULL)
932 *p++ = '\0';
933
934 if (ents >= MAXUDBENT)
935 {
936 syserr("Maximum number of UDB entries exceeded");
937 break;
938 }
939
940 /* extract options */
941 (void) _udb_parsespec(spec, opts, MAXUDBOPTS);
942
943 /*
944 ** Decode database specification.
945 **
946 ** In the sendmail tradition, the leading character
947 ** defines the semantics of the rest of the entry.
948 **
949 ** @hostname -- forward email to the indicated host.
950 ** This should be the last in the list,
951 ** since it always matches the input.
952 ** /dbname -- search the named database on the local
953 ** host using the Berkeley db package.
954 ** Hesiod -- search the named database with BIND
955 ** using the MIT Hesiod package.
956 */
957
958 switch (*spec)
959 {
960 case '@': /* forward to remote host */
961 up->udb_type = UDB_FORWARD;
962 up->udb_pid = CurrentPid;
963 up->udb_fwdhost = spec + 1;
964 ents++;
965 up++;
966 break;
967
968 # if HESIOD
969 case 'h': /* use hesiod */
970 case 'H':
971 if (sm_strcasecmp(spec, "hesiod") != 0)
972 goto badspec;
973 up->udb_type = UDB_HESIOD;
974 up->udb_pid = CurrentPid;
975 ents++;
976 up++;
977 break;
978 # endif /* HESIOD */
979
980 # if NEWDB
981 case '/': /* look up remote name */
982 l = strlen(spec);
983 if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
984 {
985 up->udb_dbname = spec;
986 }
987 else
988 {
989 up->udb_dbname = sm_pmalloc_x(l + 4);
990 (void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
991 spec, ".db");
992 }
993 errno = 0;
994 # if DB_VERSION_MAJOR < 2
995 up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
996 0644, DB_BTREE, NULL);
997 # else /* DB_VERSION_MAJOR < 2 */
998 {
999 int flags = DB_RDONLY;
1000 # if DB_VERSION_MAJOR > 2
1001 int ret;
1002 # endif /* DB_VERSION_MAJOR > 2 */
1003
1004 SM_DB_FLAG_ADD(flags);
1005 up->udb_dbp = NULL;
1006 # if DB_VERSION_MAJOR > 2
1007 ret = db_create(&up->udb_dbp, NULL, 0);
1008 if (ret != 0)
1009 {
1010 (void) up->udb_dbp->close(up->udb_dbp,
1011 0);
1012 up->udb_dbp = NULL;
1013 }
1014 else
1015 {
1016 ret = up->udb_dbp->open(up->udb_dbp,
1017 DBTXN
1018 up->udb_dbname,
1019 NULL,
1020 DB_BTREE,
1021 flags,
1022 0644);
1023 if (ret != 0)
1024 {
1025 #ifdef DB_OLD_VERSION
1026 if (ret == DB_OLD_VERSION)
1027 ret = EINVAL;
1028 #endif
1029 (void) up->udb_dbp->close(up->udb_dbp, 0);
1030 up->udb_dbp = NULL;
1031 }
1032 }
1033 errno = ret;
1034 # else /* DB_VERSION_MAJOR > 2 */
1035 errno = db_open(up->udb_dbname, DB_BTREE,
1036 flags, 0644, NULL,
1037 NULL, &up->udb_dbp);
1038 # endif /* DB_VERSION_MAJOR > 2 */
1039 }
1040 # endif /* DB_VERSION_MAJOR < 2 */
1041 if (up->udb_dbp == NULL)
1042 {
1043 if (tTd(28, 1))
1044 {
1045 int save_errno = errno;
1046
1047 # if DB_VERSION_MAJOR < 2
1048 sm_dprintf("dbopen(%s): %s\n",
1049 # else /* DB_VERSION_MAJOR < 2 */
1050 sm_dprintf("db_open(%s): %s\n",
1051 # endif /* DB_VERSION_MAJOR < 2 */
1052 up->udb_dbname,
1053 sm_errstring(errno));
1054 errno = save_errno;
1055 }
1056 if (errno != ENOENT && errno != EACCES)
1057 {
1058 if (LogLevel > 2)
1059 sm_syslog(LOG_ERR, e->e_id,
1060 # if DB_VERSION_MAJOR < 2
1061 "dbopen(%s): %s",
1062 # else /* DB_VERSION_MAJOR < 2 */
1063 "db_open(%s): %s",
1064 # endif /* DB_VERSION_MAJOR < 2 */
1065 up->udb_dbname,
1066 sm_errstring(errno));
1067 up->udb_type = UDB_EOLIST;
1068 if (up->udb_dbname != spec)
1069 sm_free(up->udb_dbname); /* XXX */
1070 goto tempfail;
1071 }
1072 if (up->udb_dbname != spec)
1073 sm_free(up->udb_dbname); /* XXX */
1074 break;
1075 }
1076 if (tTd(28, 1))
1077 {
1078 # if DB_VERSION_MAJOR < 2
1079 sm_dprintf("_udbx_init: dbopen(%s)\n",
1080 # else /* DB_VERSION_MAJOR < 2 */
1081 sm_dprintf("_udbx_init: db_open(%s)\n",
1082 # endif /* DB_VERSION_MAJOR < 2 */
1083 up->udb_dbname);
1084 }
1085 up->udb_type = UDB_DBFETCH;
1086 up->udb_pid = CurrentPid;
1087 ents++;
1088 up++;
1089 break;
1090 # endif /* NEWDB */
1091
1092 default:
1093 # if HESIOD
1094 badspec:
1095 # endif
1096 syserr("Unknown UDB spec %s", spec);
1097 break;
1098 }
1099 }
1100 up->udb_type = UDB_EOLIST;
1101
1102 if (tTd(28, 4))
1103 {
1104 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1105 {
1106 switch (up->udb_type)
1107 {
1108 case UDB_REMOTE:
1109 sm_dprintf("REMOTE: addr %s, timeo %d\n",
1110 anynet_ntoa((SOCKADDR *) &up->udb_addr),
1111 up->udb_timeout);
1112 break;
1113
1114 case UDB_DBFETCH:
1115 # if NEWDB
1116 sm_dprintf("FETCH: file %s\n", up->udb_dbname);
1117 # else
1118 sm_dprintf("FETCH\n");
1119 # endif
1120 break;
1121
1122 case UDB_FORWARD:
1123 sm_dprintf("FORWARD: host %s\n",
1124 up->udb_fwdhost);
1125 break;
1126
1127 case UDB_HESIOD:
1128 sm_dprintf("HESIOD\n");
1129 break;
1130
1131 default:
1132 sm_dprintf("UNKNOWN\n");
1133 break;
1134 }
1135 }
1136 }
1137
1138 UdbInitialized = true;
1139 errno = 0;
1140 return EX_OK;
1141
1142 /*
1143 ** On temporary failure, back out anything we've already done
1144 */
1145
1146 # if NEWDB
1147 tempfail:
1148 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1149 {
1150 if (up->udb_type == UDB_DBFETCH)
1151 {
1152 # if DB_VERSION_MAJOR < 2
1153 (*up->udb_dbp->close)(up->udb_dbp);
1154 # else
1155 errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1156 # endif
1157 if (tTd(28, 1))
1158 sm_dprintf("_udbx_init: db->close(%s)\n",
1159 up->udb_dbname);
1160 }
1161 }
1162 # endif /* NEWDB */
1163 return EX_TEMPFAIL;
1164 }
1165
1166 static int
_udb_parsespec(udbspec,opt,maxopts)1167 _udb_parsespec(udbspec, opt, maxopts)
1168 char *udbspec;
1169 struct udb_option opt[];
1170 int maxopts;
1171 {
1172 register char *spec;
1173 register char *spec_end;
1174 register int optnum;
1175
1176 spec_end = strchr(udbspec, ':');
1177 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1178 {
1179 register char *p;
1180
1181 while (SM_ISSPACE(*spec))
1182 spec++;
1183 spec_end = strchr(spec, ':');
1184 if (spec_end != NULL)
1185 *spec_end++ = '\0';
1186
1187 opt[optnum].udbo_name = spec;
1188 opt[optnum].udbo_val = NULL;
1189 p = strchr(spec, '=');
1190 if (p != NULL)
1191 opt[optnum].udbo_val = ++p;
1192 }
1193 return optnum;
1194 }
1195 /*
1196 ** _UDBX_CLOSE -- close all file based UDB entries.
1197 **
1198 ** Parameters:
1199 ** none
1200 **
1201 ** Returns:
1202 ** none
1203 */
1204 void
_udbx_close()1205 _udbx_close()
1206 {
1207 struct udbent *up;
1208
1209 if (!UdbInitialized)
1210 return;
1211
1212 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1213 {
1214 if (up->udb_pid != CurrentPid)
1215 continue;
1216
1217 # if NEWDB
1218 if (up->udb_type == UDB_DBFETCH)
1219 {
1220 # if DB_VERSION_MAJOR < 2
1221 (*up->udb_dbp->close)(up->udb_dbp);
1222 # else
1223 errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1224 # endif
1225 }
1226 if (tTd(28, 1))
1227 sm_dprintf("_udbx_close: db->close(%s)\n",
1228 up->udb_dbname);
1229 # endif /* NEWDB */
1230 }
1231 }
1232
1233 # if HESIOD
1234
1235 static int
hes_udb_get(key,info)1236 hes_udb_get(key, info)
1237 DBT *key;
1238 DBT *info;
1239 {
1240 char *name, *type;
1241 char **hp;
1242 char kbuf[MAXUDBKEY + 1];
1243
1244 if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf))
1245 return 0;
1246 name = kbuf;
1247 type = strrchr(name, ':');
1248 if (type == NULL)
1249 return 1;
1250 *type++ = '\0';
1251 if (strchr(name, '@') != NULL)
1252 return 1;
1253
1254 if (tTd(28, 1))
1255 sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
1256
1257 /* make the hesiod query */
1258 # ifdef HESIOD_INIT
1259 if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1260 return -1;
1261 hp = hesiod_resolve(HesiodContext, name, type);
1262 # else
1263 hp = hes_resolve(name, type);
1264 # endif
1265 *--type = ':';
1266 # ifdef HESIOD_INIT
1267 if (hp == NULL)
1268 return 1;
1269 if (*hp == NULL)
1270 {
1271 hesiod_free_list(HesiodContext, hp);
1272 if (errno == ECONNREFUSED || errno == EMSGSIZE)
1273 return -1;
1274 return 1;
1275 }
1276 # else /* HESIOD_INIT */
1277 if (hp == NULL || hp[0] == NULL)
1278 {
1279 /* network problem or timeout */
1280 if (hes_error() == HES_ER_NET)
1281 return -1;
1282
1283 return 1;
1284 }
1285 # endif /* HESIOD_INIT */
1286 else
1287 {
1288 /*
1289 ** If there are multiple matches, just return the
1290 ** first one.
1291 **
1292 ** XXX These should really be returned; for example,
1293 ** XXX it is legal for :maildrop to be multi-valued.
1294 */
1295
1296 info->data = hp[0];
1297 info->size = (size_t) strlen(info->data);
1298 }
1299
1300 if (tTd(28, 80))
1301 sm_dprintf("hes_udb_get => %s\n", *hp);
1302
1303 return 0;
1304 }
1305 # endif /* HESIOD */
1306
1307 #else /* USERDB */
1308
1309 int
1310 udbexpand(a, sendq, aliaslevel, e)
1311 ADDRESS *a;
1312 ADDRESS **sendq;
1313 int aliaslevel;
1314 ENVELOPE *e;
1315 {
1316 return EX_OK;
1317 }
1318
1319 #endif /* USERDB */
1320