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