source: trunk/third/sendmail/src/udb.c @ 12554

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