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