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