source: trunk/third/sendmail/sendmail/udb.c @ 19204

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