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