1 /*
2 * Copyright (c) 1998-2003, 2006 Sendmail, 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 #pragma ident "%Z%%M% %I% %E% SMI"
15
16 #include <sendmail.h>
17 #include "map.h"
18
19 #if USERDB
20 SM_RCSID("@(#)$Id: udb.c,v 8.164 2006/12/19 19:49:51 ca Exp $ (with USERDB)")
21 #else /* USERDB */
22 SM_RCSID("@(#)$Id: udb.c,v 8.164 2006/12/19 19:49:51 ca Exp $ (without USERDB)")
23 #endif /* USERDB */
24
25 #if USERDB
26
27 #include <sm/sendmail.h>
28 # if NEWDB
29 # include "sm/bdb.h"
30 # else /* NEWDB */
31 # define DBT struct _data_base_thang_
32 DBT
33 {
34 void *data; /* pointer to data */
35 size_t size; /* length of data */
36 };
37 # endif /* NEWDB */
38
39 /*
40 ** UDB.C -- interface between sendmail and Berkeley User Data Base.
41 **
42 ** This depends on the 4.4BSD db package.
43 */
44
45
46 struct udbent
47 {
48 char *udb_spec; /* string version of spec */
49 int udb_type; /* type of entry */
50 pid_t udb_pid; /* PID of process which opened db */
51 char *udb_default; /* default host for outgoing mail */
52 union
53 {
54 # if NETINET || NETINET6
55 /* type UE_REMOTE -- do remote call for lookup */
56 struct
57 {
58 SOCKADDR _udb_addr; /* address */
59 int _udb_timeout; /* timeout */
60 } udb_remote;
61 # define udb_addr udb_u.udb_remote._udb_addr
62 # define udb_timeout udb_u.udb_remote._udb_timeout
63 # endif /* NETINET || NETINET6 */
64
65 /* type UE_FORWARD -- forward message to remote */
66 struct
67 {
68 char *_udb_fwdhost; /* name of forward host */
69 } udb_forward;
70 # define udb_fwdhost udb_u.udb_forward._udb_fwdhost
71
72 # if NEWDB
73 /* type UE_FETCH -- lookup in local database */
74 struct
75 {
76 char *_udb_dbname; /* pathname of database */
77 DB *_udb_dbp; /* open database ptr */
78 } udb_lookup;
79 # define udb_dbname udb_u.udb_lookup._udb_dbname
80 # define udb_dbp udb_u.udb_lookup._udb_dbp
81 # endif /* NEWDB */
82 } udb_u;
83 };
84
85 # define UDB_EOLIST 0 /* end of list */
86 # define UDB_SKIP 1 /* skip this entry */
87 # define UDB_REMOTE 2 /* look up in remote database */
88 # define UDB_DBFETCH 3 /* look up in local database */
89 # define UDB_FORWARD 4 /* forward to remote host */
90 # define UDB_HESIOD 5 /* look up via hesiod */
91
92 # define MAXUDBENT 10 /* maximum number of UDB entries */
93
94
95 struct udb_option
96 {
97 char *udbo_name;
98 char *udbo_val;
99 };
100
101 # if HESIOD
102 static int hes_udb_get __P((DBT *, DBT *));
103 # endif /* HESIOD */
104 static char *udbmatch __P((char *, char *, SM_RPOOL_T *));
105 static int _udbx_init __P((ENVELOPE *));
106 static int _udb_parsespec __P((char *, struct udb_option [], int));
107
108 /*
109 ** UDBEXPAND -- look up user in database and expand
110 **
111 ** Parameters:
112 ** a -- address to expand.
113 ** sendq -- pointer to head of sendq to put the expansions in.
114 ** aliaslevel -- the current alias nesting depth.
115 ** e -- the current envelope.
116 **
117 ** Returns:
118 ** EX_TEMPFAIL -- if something "odd" happened -- probably due
119 ** to accessing a file on an NFS server that is down.
120 ** EX_OK -- otherwise.
121 **
122 ** Side Effects:
123 ** Modifies sendq.
124 */
125
126 static struct udbent UdbEnts[MAXUDBENT + 1];
127 static bool UdbInitialized = false;
128
129 int
udbexpand(a,sendq,aliaslevel,e)130 udbexpand(a, sendq, aliaslevel, e)
131 register ADDRESS *a;
132 ADDRESS **sendq;
133 int aliaslevel;
134 register ENVELOPE *e;
135 {
136 int i;
137 DBT key;
138 DBT info;
139 bool breakout;
140 register struct udbent *up;
141 int keylen;
142 int naddrs;
143 char *user;
144 char keybuf[MAXUDBKEY];
145
146 memset(&key, '\0', sizeof(key));
147 memset(&info, '\0', sizeof(info));
148
149 if (tTd(28, 1))
150 sm_dprintf("udbexpand(%s)\n", a->q_paddr);
151
152 /* make certain we are supposed to send to this address */
153 if (!QS_IS_SENDABLE(a->q_state))
154 return EX_OK;
155 e->e_to = a->q_paddr;
156
157 /* on first call, locate the database */
158 if (!UdbInitialized)
159 {
160 if (_udbx_init(e) == EX_TEMPFAIL)
161 return EX_TEMPFAIL;
162 }
163
164 /* short circuit the process if no chance of a match */
165 if (UdbSpec == NULL || UdbSpec[0] == '\0')
166 return EX_OK;
167
168 /* extract user to do userdb matching on */
169 user = a->q_user;
170
171 /* short circuit name begins with '\\' since it can't possibly match */
172 /* (might want to treat this as unquoted instead) */
173 if (user[0] == '\\')
174 return EX_OK;
175
176 /* if name begins with a colon, it indicates our metadata */
177 if (user[0] == ':')
178 return EX_OK;
179
180 keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
181
182 /* if name is too long, assume it won't match */
183 if (keylen >= sizeof(keybuf))
184 return EX_OK;
185
186 /* build actual database key */
187
188 breakout = false;
189 for (up = UdbEnts; !breakout; up++)
190 {
191 int usersize;
192 int userleft;
193 char userbuf[MEMCHUNKSIZE];
194 # if HESIOD && HES_GETMAILHOST
195 char pobuf[MAXNAME];
196 # endif /* HESIOD && HES_GETMAILHOST */
197 # if defined(NEWDB) && DB_VERSION_MAJOR > 1
198 DBC *dbc = NULL;
199 # endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */
200
201 user = userbuf;
202 userbuf[0] = '\0';
203 usersize = sizeof(userbuf);
204 userleft = sizeof(userbuf) - 1;
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 /* DB_VERSION_MAJOR < 2 */
368 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
369 &key, &info, 0);
370 # endif /* DB_VERSION_MAJOR < 2 */
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 /* HES_GETMAILHOST */
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 lookup.
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 char *p;
600 register struct udbent *up;
601 int i;
602 int keylen;
603 DBT key, info;
604 char keybuf[MAXUDBKEY];
605
606 if (tTd(28, 1))
607 sm_dprintf("udbmatch(%s, %s)\n", user, field);
608
609 if (!UdbInitialized)
610 {
611 if (_udbx_init(CurEnv) == EX_TEMPFAIL)
612 return NULL;
613 }
614
615 /* short circuit if no spec */
616 if (UdbSpec == NULL || UdbSpec[0] == '\0')
617 return NULL;
618
619 /* short circuit name begins with '\\' since it can't possibly match */
620 if (user[0] == '\\')
621 return NULL;
622
623 /* long names can never match and are a pain to deal with */
624 i = strlen(field);
625 if (i < sizeof("maildrop"))
626 i = sizeof("maildrop");
627 if ((strlen(user) + i) > sizeof(keybuf) - 4)
628 return NULL;
629
630 /* names beginning with colons indicate metadata */
631 if (user[0] == ':')
632 return NULL;
633
634 /* build database key */
635 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
636 keylen = strlen(keybuf);
637
638 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
639 {
640 /*
641 ** Select action based on entry type.
642 */
643
644 switch (up->udb_type)
645 {
646 # if NEWDB
647 case UDB_DBFETCH:
648 memset(&key, '\0', sizeof(key));
649 memset(&info, '\0', sizeof(info));
650 key.data = keybuf;
651 key.size = keylen;
652 # if DB_VERSION_MAJOR < 2
653 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
654 # else /* DB_VERSION_MAJOR < 2 */
655 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
656 &key, &info, 0);
657 # endif /* DB_VERSION_MAJOR < 2 */
658 if (i != 0 || info.size <= 0)
659 {
660 if (tTd(28, 2))
661 sm_dprintf("udbmatch: no match on %s (%d) via db\n",
662 keybuf, keylen);
663 continue;
664 }
665
666 p = sm_rpool_malloc_x(rpool, info.size + 1);
667 memmove(p, info.data, info.size);
668 p[info.size] = '\0';
669 if (tTd(28, 1))
670 sm_dprintf("udbmatch ==> %s\n", p);
671 return p;
672 # endif /* NEWDB */
673
674 # if HESIOD
675 case UDB_HESIOD:
676 key.data = keybuf;
677 key.size = keylen;
678 i = hes_udb_get(&key, &info);
679 if (i != 0 || info.size <= 0)
680 {
681 if (tTd(28, 2))
682 sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
683 keybuf, keylen);
684 continue;
685 }
686
687 p = sm_rpool_malloc_x(rpool, info.size + 1);
688 memmove(p, info.data, info.size);
689 p[info.size] = '\0';
690 if (tTd(28, 1))
691 sm_dprintf("udbmatch ==> %s\n", p);
692 return p;
693 # endif /* HESIOD */
694 }
695 }
696
697 if (strcmp(field, "mailname") != 0)
698 return NULL;
699
700 /*
701 ** Nothing yet. Search again for a default case. But only
702 ** use it if we also have a forward (:maildrop) pointer already
703 ** in the database.
704 */
705
706 /* build database key */
707 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
708 keylen = strlen(keybuf);
709
710 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
711 {
712 switch (up->udb_type)
713 {
714 # if NEWDB
715 case UDB_DBFETCH:
716 /* get the default case for this database */
717 if (up->udb_default == NULL)
718 {
719 memset(&key, '\0', sizeof(key));
720 memset(&info, '\0', sizeof(info));
721 key.data = ":default:mailname";
722 key.size = strlen(key.data);
723 # if DB_VERSION_MAJOR < 2
724 i = (*up->udb_dbp->get)(up->udb_dbp,
725 &key, &info, 0);
726 # else /* DB_VERSION_MAJOR < 2 */
727 i = errno = (*up->udb_dbp->get)(up->udb_dbp,
728 NULL, &key,
729 &info, 0);
730 # endif /* DB_VERSION_MAJOR < 2 */
731 if (i != 0 || info.size <= 0)
732 {
733 /* no default case */
734 up->udb_default = "";
735 continue;
736 }
737
738 /* save the default case */
739 up->udb_default = sm_pmalloc_x(info.size + 1);
740 memmove(up->udb_default, info.data, info.size);
741 up->udb_default[info.size] = '\0';
742 }
743 else if (up->udb_default[0] == '\0')
744 continue;
745
746 /* we have a default case -- verify user:maildrop */
747 memset(&key, '\0', sizeof(key));
748 memset(&info, '\0', sizeof(info));
749 key.data = keybuf;
750 key.size = keylen;
751 # if DB_VERSION_MAJOR < 2
752 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
753 # else /* DB_VERSION_MAJOR < 2 */
754 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
755 &key, &info, 0);
756 # endif /* DB_VERSION_MAJOR < 2 */
757 if (i != 0 || info.size <= 0)
758 {
759 /* nope -- no aliasing for this user */
760 continue;
761 }
762
763 /* they exist -- build the actual address */
764 i = strlen(user) + strlen(up->udb_default) + 2;
765 p = sm_rpool_malloc_x(rpool, i);
766 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
767 if (tTd(28, 1))
768 sm_dprintf("udbmatch ==> %s\n", p);
769 return p;
770 # endif /* NEWDB */
771
772 # if HESIOD
773 case UDB_HESIOD:
774 /* get the default case for this database */
775 if (up->udb_default == NULL)
776 {
777 key.data = ":default:mailname";
778 key.size = strlen(key.data);
779 i = hes_udb_get(&key, &info);
780
781 if (i != 0 || info.size <= 0)
782 {
783 /* no default case */
784 up->udb_default = "";
785 continue;
786 }
787
788 /* save the default case */
789 up->udb_default = sm_pmalloc_x(info.size + 1);
790 memmove(up->udb_default, info.data, info.size);
791 up->udb_default[info.size] = '\0';
792 }
793 else if (up->udb_default[0] == '\0')
794 continue;
795
796 /* we have a default case -- verify user:maildrop */
797 key.data = keybuf;
798 key.size = keylen;
799 i = hes_udb_get(&key, &info);
800 if (i != 0 || info.size <= 0)
801 {
802 /* nope -- no aliasing for this user */
803 continue;
804 }
805
806 /* they exist -- build the actual address */
807 i = strlen(user) + strlen(up->udb_default) + 2;
808 p = sm_rpool_malloc_x(rpool, i);
809 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
810 if (tTd(28, 1))
811 sm_dprintf("udbmatch ==> %s\n", p);
812 return p;
813 break;
814 # endif /* HESIOD */
815 }
816 }
817
818 /* still nothing.... too bad */
819 return NULL;
820 }
821 /*
822 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
823 **
824 ** Parameters:
825 ** map -- the map being queried.
826 ** name -- the name to look up.
827 ** av -- arguments to the map lookup.
828 ** statp -- to get any error status.
829 **
830 ** Returns:
831 ** NULL if name not found in map.
832 ** The rewritten name otherwise.
833 */
834
835 /* ARGSUSED3 */
836 char *
udb_map_lookup(map,name,av,statp)837 udb_map_lookup(map, name, av, statp)
838 MAP *map;
839 char *name;
840 char **av;
841 int *statp;
842 {
843 char *val;
844 char *key;
845 char *SM_NONVOLATILE result = NULL;
846 char keybuf[MAXNAME + 1];
847
848 if (tTd(28, 20) || tTd(38, 20))
849 sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
850
851 if (bitset(MF_NOFOLDCASE, map->map_mflags))
852 {
853 key = name;
854 }
855 else
856 {
857 int keysize = strlen(name);
858
859 if (keysize > sizeof(keybuf) - 1)
860 keysize = sizeof(keybuf) - 1;
861 memmove(keybuf, name, keysize);
862 keybuf[keysize] = '\0';
863 makelower(keybuf);
864 key = keybuf;
865 }
866 val = udbmatch(key, map->map_file, NULL);
867 if (val == NULL)
868 return NULL;
869 SM_TRY
870 if (bitset(MF_MATCHONLY, map->map_mflags))
871 result = map_rewrite(map, name, strlen(name), NULL);
872 else
873 result = map_rewrite(map, val, strlen(val), av);
874 SM_FINALLY
875 sm_free(val);
876 SM_END_TRY
877 return result;
878 }
879 /*
880 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
881 **
882 ** Parameters:
883 ** e -- the current envelope.
884 **
885 ** Returns:
886 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
887 ** database due to a host being down or some similar
888 ** (recoverable) situation.
889 ** EX_OK -- otherwise.
890 **
891 ** Side Effects:
892 ** Fills in the UdbEnts structure from UdbSpec.
893 */
894
895 # define MAXUDBOPTS 27
896
897 static int
_udbx_init(e)898 _udbx_init(e)
899 ENVELOPE *e;
900 {
901 int ents = 0;
902 register char *p;
903 register struct udbent *up;
904
905 if (UdbInitialized)
906 return EX_OK;
907
908 # ifdef UDB_DEFAULT_SPEC
909 if (UdbSpec == NULL)
910 UdbSpec = UDB_DEFAULT_SPEC;
911 # endif /* UDB_DEFAULT_SPEC */
912
913 p = UdbSpec;
914 up = UdbEnts;
915 while (p != NULL)
916 {
917 char *spec;
918 int l;
919 struct udb_option opts[MAXUDBOPTS + 1];
920
921 while (*p == ' ' || *p == '\t' || *p == ',')
922 p++;
923 if (*p == '\0')
924 break;
925 spec = p;
926 p = strchr(p, ',');
927 if (p != NULL)
928 *p++ = '\0';
929
930 if (ents >= MAXUDBENT)
931 {
932 syserr("Maximum number of UDB entries exceeded");
933 break;
934 }
935
936 /* extract options */
937 (void) _udb_parsespec(spec, opts, MAXUDBOPTS);
938
939 /*
940 ** Decode database specification.
941 **
942 ** In the sendmail tradition, the leading character
943 ** defines the semantics of the rest of the entry.
944 **
945 ** @hostname -- forward email to the indicated host.
946 ** This should be the last in the list,
947 ** since it always matches the input.
948 ** /dbname -- search the named database on the local
949 ** host using the Berkeley db package.
950 ** Hesiod -- search the named database with BIND
951 ** using the MIT Hesiod package.
952 */
953
954 switch (*spec)
955 {
956 case '@': /* forward to remote host */
957 up->udb_type = UDB_FORWARD;
958 up->udb_pid = CurrentPid;
959 up->udb_fwdhost = spec + 1;
960 ents++;
961 up++;
962 break;
963
964 # if HESIOD
965 case 'h': /* use hesiod */
966 case 'H':
967 if (sm_strcasecmp(spec, "hesiod") != 0)
968 goto badspec;
969 up->udb_type = UDB_HESIOD;
970 up->udb_pid = CurrentPid;
971 ents++;
972 up++;
973 break;
974 # endif /* HESIOD */
975
976 # if NEWDB
977 case '/': /* look up remote name */
978 l = strlen(spec);
979 if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
980 {
981 up->udb_dbname = spec;
982 }
983 else
984 {
985 up->udb_dbname = sm_pmalloc_x(l + 4);
986 (void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
987 spec, ".db");
988 }
989 errno = 0;
990 # if DB_VERSION_MAJOR < 2
991 up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
992 0644, DB_BTREE, NULL);
993 # else /* DB_VERSION_MAJOR < 2 */
994 {
995 int flags = DB_RDONLY;
996 # if DB_VERSION_MAJOR > 2
997 int ret;
998 # endif /* DB_VERSION_MAJOR > 2 */
999
1000 SM_DB_FLAG_ADD(flags);
1001 up->udb_dbp = NULL;
1002 # if DB_VERSION_MAJOR > 2
1003 ret = db_create(&up->udb_dbp, NULL, 0);
1004 if (ret != 0)
1005 {
1006 (void) up->udb_dbp->close(up->udb_dbp,
1007 0);
1008 up->udb_dbp = NULL;
1009 }
1010 else
1011 {
1012 ret = up->udb_dbp->open(up->udb_dbp,
1013 DBTXN
1014 up->udb_dbname,
1015 NULL,
1016 DB_BTREE,
1017 flags,
1018 0644);
1019 if (ret != 0)
1020 {
1021 #ifdef DB_OLD_VERSION
1022 if (ret == DB_OLD_VERSION)
1023 ret = EINVAL;
1024 #endif /* DB_OLD_VERSION */
1025 (void) up->udb_dbp->close(up->udb_dbp, 0);
1026 up->udb_dbp = NULL;
1027 }
1028 }
1029 errno = ret;
1030 # else /* DB_VERSION_MAJOR > 2 */
1031 errno = db_open(up->udb_dbname, DB_BTREE,
1032 flags, 0644, NULL,
1033 NULL, &up->udb_dbp);
1034 # endif /* DB_VERSION_MAJOR > 2 */
1035 }
1036 # endif /* DB_VERSION_MAJOR < 2 */
1037 if (up->udb_dbp == NULL)
1038 {
1039 if (tTd(28, 1))
1040 {
1041 int save_errno = errno;
1042
1043 # if DB_VERSION_MAJOR < 2
1044 sm_dprintf("dbopen(%s): %s\n",
1045 # else /* DB_VERSION_MAJOR < 2 */
1046 sm_dprintf("db_open(%s): %s\n",
1047 # endif /* DB_VERSION_MAJOR < 2 */
1048 up->udb_dbname,
1049 sm_errstring(errno));
1050 errno = save_errno;
1051 }
1052 if (errno != ENOENT && errno != EACCES)
1053 {
1054 if (LogLevel > 2)
1055 sm_syslog(LOG_ERR, e->e_id,
1056 # if DB_VERSION_MAJOR < 2
1057 "dbopen(%s): %s",
1058 # else /* DB_VERSION_MAJOR < 2 */
1059 "db_open(%s): %s",
1060 # endif /* DB_VERSION_MAJOR < 2 */
1061 up->udb_dbname,
1062 sm_errstring(errno));
1063 up->udb_type = UDB_EOLIST;
1064 if (up->udb_dbname != spec)
1065 sm_free(up->udb_dbname); /* XXX */
1066 goto tempfail;
1067 }
1068 if (up->udb_dbname != spec)
1069 sm_free(up->udb_dbname); /* XXX */
1070 break;
1071 }
1072 if (tTd(28, 1))
1073 {
1074 # if DB_VERSION_MAJOR < 2
1075 sm_dprintf("_udbx_init: dbopen(%s)\n",
1076 # else /* DB_VERSION_MAJOR < 2 */
1077 sm_dprintf("_udbx_init: db_open(%s)\n",
1078 # endif /* DB_VERSION_MAJOR < 2 */
1079 up->udb_dbname);
1080 }
1081 up->udb_type = UDB_DBFETCH;
1082 up->udb_pid = CurrentPid;
1083 ents++;
1084 up++;
1085 break;
1086 # endif /* NEWDB */
1087
1088 default:
1089 # if HESIOD
1090 badspec:
1091 # endif /* HESIOD */
1092 syserr("Unknown UDB spec %s", spec);
1093 break;
1094 }
1095 }
1096 up->udb_type = UDB_EOLIST;
1097
1098 if (tTd(28, 4))
1099 {
1100 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1101 {
1102 switch (up->udb_type)
1103 {
1104 case UDB_REMOTE:
1105 sm_dprintf("REMOTE: addr %s, timeo %d\n",
1106 anynet_ntoa((SOCKADDR *) &up->udb_addr),
1107 up->udb_timeout);
1108 break;
1109
1110 case UDB_DBFETCH:
1111 # if NEWDB
1112 sm_dprintf("FETCH: file %s\n",
1113 up->udb_dbname);
1114 # else /* NEWDB */
1115 sm_dprintf("FETCH\n");
1116 # endif /* NEWDB */
1117 break;
1118
1119 case UDB_FORWARD:
1120 sm_dprintf("FORWARD: host %s\n",
1121 up->udb_fwdhost);
1122 break;
1123
1124 case UDB_HESIOD:
1125 sm_dprintf("HESIOD\n");
1126 break;
1127
1128 default:
1129 sm_dprintf("UNKNOWN\n");
1130 break;
1131 }
1132 }
1133 }
1134
1135 UdbInitialized = true;
1136 errno = 0;
1137 return EX_OK;
1138
1139 /*
1140 ** On temporary failure, back out anything we've already done
1141 */
1142
1143 tempfail:
1144 # if NEWDB
1145 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1146 {
1147 if (up->udb_type == UDB_DBFETCH)
1148 {
1149 # if DB_VERSION_MAJOR < 2
1150 (*up->udb_dbp->close)(up->udb_dbp);
1151 # else /* DB_VERSION_MAJOR < 2 */
1152 errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1153 # endif /* DB_VERSION_MAJOR < 2 */
1154 if (tTd(28, 1))
1155 sm_dprintf("_udbx_init: db->close(%s)\n",
1156 up->udb_dbname);
1157 }
1158 }
1159 # endif /* NEWDB */
1160 return EX_TEMPFAIL;
1161 }
1162
1163 static int
_udb_parsespec(udbspec,opt,maxopts)1164 _udb_parsespec(udbspec, opt, maxopts)
1165 char *udbspec;
1166 struct udb_option opt[];
1167 int maxopts;
1168 {
1169 register char *spec;
1170 register char *spec_end;
1171 register int optnum;
1172
1173 spec_end = strchr(udbspec, ':');
1174 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1175 {
1176 register char *p;
1177
1178 while (isascii(*spec) && isspace(*spec))
1179 spec++;
1180 spec_end = strchr(spec, ':');
1181 if (spec_end != NULL)
1182 *spec_end++ = '\0';
1183
1184 opt[optnum].udbo_name = spec;
1185 opt[optnum].udbo_val = NULL;
1186 p = strchr(spec, '=');
1187 if (p != NULL)
1188 opt[optnum].udbo_val = ++p;
1189 }
1190 return optnum;
1191 }
1192 /*
1193 ** _UDBX_CLOSE -- close all file based UDB entries.
1194 **
1195 ** Parameters:
1196 ** none
1197 **
1198 ** Returns:
1199 ** none
1200 */
1201 void
_udbx_close()1202 _udbx_close()
1203 {
1204 struct udbent *up;
1205
1206 if (!UdbInitialized)
1207 return;
1208
1209 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1210 {
1211 if (up->udb_pid != CurrentPid)
1212 continue;
1213
1214 # if NEWDB
1215 if (up->udb_type == UDB_DBFETCH)
1216 {
1217 # if DB_VERSION_MAJOR < 2
1218 (*up->udb_dbp->close)(up->udb_dbp);
1219 # else /* DB_VERSION_MAJOR < 2 */
1220 errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1221 # endif /* DB_VERSION_MAJOR < 2 */
1222 }
1223 if (tTd(28, 1))
1224 sm_dprintf("_udbx_init: db->close(%s)\n",
1225 up->udb_dbname);
1226 # endif /* NEWDB */
1227 }
1228 }
1229
1230 # if HESIOD
1231
1232 static int
hes_udb_get(key,info)1233 hes_udb_get(key, info)
1234 DBT *key;
1235 DBT *info;
1236 {
1237 char *name, *type;
1238 char **hp;
1239 char kbuf[MAXUDBKEY + 1];
1240
1241 if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf))
1242 return 0;
1243 name = kbuf;
1244 type = strrchr(name, ':');
1245 if (type == NULL)
1246 return 1;
1247 *type++ = '\0';
1248 if (strchr(name, '@') != NULL)
1249 return 1;
1250
1251 if (tTd(28, 1))
1252 sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
1253
1254 /* make the hesiod query */
1255 # ifdef HESIOD_INIT
1256 if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1257 return -1;
1258 hp = hesiod_resolve(HesiodContext, name, type);
1259 # else /* HESIOD_INIT */
1260 hp = hes_resolve(name, type);
1261 # endif /* HESIOD_INIT */
1262 *--type = ':';
1263 # ifdef HESIOD_INIT
1264 if (hp == NULL)
1265 return 1;
1266 if (*hp == NULL)
1267 {
1268 hesiod_free_list(HesiodContext, hp);
1269 if (errno == ECONNREFUSED || errno == EMSGSIZE)
1270 return -1;
1271 return 1;
1272 }
1273 # else /* HESIOD_INIT */
1274 if (hp == NULL || hp[0] == NULL)
1275 {
1276 /* network problem or timeout */
1277 if (hes_error() == HES_ER_NET)
1278 return -1;
1279
1280 return 1;
1281 }
1282 # endif /* HESIOD_INIT */
1283 else
1284 {
1285 /*
1286 ** If there are multiple matches, just return the
1287 ** first one.
1288 **
1289 ** XXX These should really be returned; for example,
1290 ** XXX it is legal for :maildrop to be multi-valued.
1291 */
1292
1293 info->data = hp[0];
1294 info->size = (size_t) strlen(info->data);
1295 }
1296
1297 if (tTd(28, 80))
1298 sm_dprintf("hes_udb_get => %s\n", *hp);
1299
1300 return 0;
1301 }
1302 # endif /* HESIOD */
1303
1304 #else /* USERDB */
1305
1306 int
1307 udbexpand(a, sendq, aliaslevel, e)
1308 ADDRESS *a;
1309 ADDRESS **sendq;
1310 int aliaslevel;
1311 ENVELOPE *e;
1312 {
1313 return EX_OK;
1314 }
1315
1316 #endif /* USERDB */
1317