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