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