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