150581Seric /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
362532Sbostic * Copyright (c) 1988, 1993
462532Sbostic * The Regents of the University of California. All rights reserved.
550581Seric *
650581Seric * %sccs.include.redist.c%
750581Seric */
850581Seric
960567Seric #include "sendmail.h"
1060567Seric
1150581Seric #ifndef lint
1269711Seric #if !USERDB
13*69748Seric static char sccsid [] = "@(#)udb.c 8.23 (Berkeley) 05/28/95 (with USERDB)";
1451360Seric #else
15*69748Seric static char sccsid [] = "@(#)udb.c 8.23 (Berkeley) 05/28/95 (without USERDB)";
1650581Seric #endif
1751360Seric #endif
1850581Seric
1969711Seric #if USERDB
2050581Seric
2151923Seric #include <errno.h>
2250581Seric
2369711Seric #ifdef NEWDB
2469711Seric # include <db.h>
2569711Seric #else
2669711Seric # define DBT struct _data_base_thang_
2769711Seric DBT
2869711Seric {
2969711Seric void *data; /* pointer to data */
3069711Seric size_t size; /* length of data */
3169711Seric };
3269711Seric #endif
3369711Seric
3466759Seric #ifdef HESIOD
3569711Seric # include <hesiod.h>
3666759Seric #endif /* HESIOD */
3766759Seric
3850581Seric /*
3953654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base.
4050581Seric **
4151363Seric ** This depends on the 4.4BSD db package.
4250581Seric */
4350581Seric
4451362Seric
4551360Seric struct udbent
4651360Seric {
4751360Seric char *udb_spec; /* string version of spec */
4851360Seric int udb_type; /* type of entry */
4951951Seric char *udb_default; /* default host for outgoing mail */
5051360Seric union
5151360Seric {
5251360Seric /* type UE_REMOTE -- do remote call for lookup */
5351360Seric struct
5451360Seric {
5551360Seric struct sockaddr_in _udb_addr; /* address */
5651360Seric int _udb_timeout; /* timeout */
5751360Seric } udb_remote;
5851360Seric #define udb_addr udb_u.udb_remote._udb_addr
5951360Seric #define udb_timeout udb_u.udb_remote._udb_timeout
6051360Seric
6151360Seric /* type UE_FORWARD -- forward message to remote */
6251360Seric struct
6351360Seric {
6451360Seric char *_udb_fwdhost; /* name of forward host */
6551360Seric } udb_forward;
6651360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost
6751360Seric
6869711Seric #ifdef NEWDB
6951951Seric /* type UE_FETCH -- lookup in local database */
7051360Seric struct
7151360Seric {
7251360Seric char *_udb_dbname; /* pathname of database */
7351360Seric DB *_udb_dbp; /* open database ptr */
7451360Seric } udb_lookup;
7551360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname
7651360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp
7769711Seric #endif
7851360Seric } udb_u;
7951360Seric };
8051360Seric
8151360Seric #define UDB_EOLIST 0 /* end of list */
8251360Seric #define UDB_SKIP 1 /* skip this entry */
8351360Seric #define UDB_REMOTE 2 /* look up in remote database */
8451951Seric #define UDB_DBFETCH 3 /* look up in local database */
8551360Seric #define UDB_FORWARD 4 /* forward to remote host */
8666759Seric #define UDB_HESIOD 5 /* look up via hesiod */
8751360Seric
8851360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */
8951360Seric
9051363Seric
9151363Seric struct option
9251363Seric {
9351363Seric char *name;
9451363Seric char *val;
9551363Seric };
9651363Seric /*
9751363Seric ** UDBEXPAND -- look up user in database and expand
9851363Seric **
9951363Seric ** Parameters:
10051363Seric ** a -- address to expand.
10151363Seric ** sendq -- pointer to head of sendq to put the expansions in.
10267982Seric ** aliaslevel -- the current alias nesting depth.
10367982Seric ** e -- the current envelope.
10451363Seric **
10551363Seric ** Returns:
10651923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due
10751923Seric ** to accessing a file on an NFS server that is down.
10851923Seric ** EX_OK -- otherwise.
10951363Seric **
11051363Seric ** Side Effects:
11151363Seric ** Modifies sendq.
11251363Seric */
11351363Seric
11451363Seric int UdbPort = 1616;
11551363Seric int UdbTimeout = 10;
11651363Seric
11751953Seric struct udbent UdbEnts[MAXUDBENT + 1];
11851953Seric int UdbSock = -1;
11951953Seric bool UdbInitialized = FALSE;
12051360Seric
12151923Seric int
udbexpand(a,sendq,aliaslevel,e)12267982Seric udbexpand(a, sendq, aliaslevel, e)
12350581Seric register ADDRESS *a;
12450581Seric ADDRESS **sendq;
12567982Seric int aliaslevel;
12655012Seric register ENVELOPE *e;
12750581Seric {
12850581Seric int i;
12950581Seric DBT key;
13050581Seric DBT info;
13151360Seric bool breakout;
13251360Seric register struct udbent *up;
13351362Seric int keylen;
13458082Seric int naddrs;
13557232Seric char keybuf[MAXKEY];
13657232Seric char buf[BUFSIZ];
13750581Seric
13850581Seric if (tTd(28, 1))
13958065Seric printf("udbexpand(%s)\n", a->q_paddr);
14050581Seric
14150581Seric /* make certain we are supposed to send to this address */
14258154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
14351923Seric return EX_OK;
14455012Seric e->e_to = a->q_paddr;
14550581Seric
14651360Seric /* on first call, locate the database */
14751951Seric if (!UdbInitialized)
14850581Seric {
14951923Seric extern int _udbx_init();
15051362Seric
15151923Seric if (_udbx_init() == EX_TEMPFAIL)
15251923Seric return EX_TEMPFAIL;
15351362Seric }
15450581Seric
15551909Seric /* short circuit the process if no chance of a match */
15651909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0')
15751923Seric return EX_OK;
15851909Seric
15966759Seric /* short circuit name begins with '\\' since it can't possibly match */
16066759Seric if (a->q_user[0] == '\\')
16166759Seric return EX_OK;
16266759Seric
16351362Seric /* if name is too long, assume it won't match */
16451362Seric if (strlen(a->q_user) > sizeof keybuf - 12)
16551923Seric return EX_OK;
16651360Seric
16751362Seric /* if name begins with a colon, it indicates our metadata */
16851362Seric if (a->q_user[0] == ':')
16951923Seric return EX_OK;
17051360Seric
17151362Seric /* build actual database key */
17251362Seric (void) strcpy(keybuf, a->q_user);
17351362Seric (void) strcat(keybuf, ":maildrop");
17451362Seric keylen = strlen(keybuf);
17551360Seric
17651360Seric breakout = FALSE;
17751362Seric for (up = UdbEnts; !breakout; up++)
17850581Seric {
17951360Seric char *user;
18050581Seric
18151360Seric /*
18251360Seric ** Select action based on entry type.
18351360Seric **
18451360Seric ** On dropping out of this switch, "class" should
18551360Seric ** explain the type of the data, and "user" should
18651360Seric ** contain the user information.
18751360Seric */
18850581Seric
18951360Seric switch (up->udb_type)
19051360Seric {
19168786Seric #ifdef NEWDB
19251951Seric case UDB_DBFETCH:
19351362Seric key.data = keybuf;
19451362Seric key.size = keylen;
19560990Seric if (tTd(28, 80))
19666759Seric printf("udbexpand: trying %s (%d) via db\n",
19764067Seric keybuf, keylen);
19851362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
19951923Seric if (i > 0 || info.size <= 0)
20051360Seric {
20151360Seric if (tTd(28, 2))
20264067Seric printf("udbexpand: no match on %s (%d)\n",
20364067Seric keybuf, keylen);
20451360Seric continue;
20551360Seric }
20660990Seric if (tTd(28, 80))
20760990Seric printf("udbexpand: match %.*s: %.*s\n",
20860990Seric key.size, key.data, info.size, info.data);
20950581Seric
21058082Seric naddrs = 0;
21158082Seric a->q_flags &= ~QSELFREF;
21251830Seric while (i == 0 && key.size == keylen &&
21351830Seric bcmp(key.data, keybuf, keylen) == 0)
21451362Seric {
21558099Seric if (bitset(EF_VRFYONLY, e->e_flags))
21658154Seric {
21758154Seric a->q_flags |= QVERIFIED;
21858884Seric e->e_nrcpts++;
21958099Seric return EX_OK;
22058154Seric }
22158099Seric
22251830Seric breakout = TRUE;
22351362Seric if (info.size < sizeof buf)
22451362Seric user = buf;
22551362Seric else
22651362Seric user = xalloc(info.size + 1);
22751362Seric bcopy(info.data, user, info.size);
22851362Seric user[info.size] = '\0';
22950581Seric
23058151Seric message("expanded to %s", user);
23157977Seric #ifdef LOG
23257977Seric if (LogLevel >= 10)
23357977Seric syslog(LOG_INFO, "%s: expand %s => %s",
23457977Seric e->e_id, e->e_to, user);
23557977Seric #endif
23667982Seric naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e);
23751362Seric
23851362Seric if (user != buf)
23951362Seric free(user);
24051362Seric
24151362Seric /* get the next record */
24251362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
24351830Seric }
24460990Seric
24560990Seric /* if nothing ever matched, try next database */
24660990Seric if (!breakout)
24760990Seric continue;
24860990Seric
24958082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
25058065Seric {
25158065Seric if (tTd(28, 5))
25258065Seric {
25358065Seric printf("udbexpand: QDONTSEND ");
25458065Seric printaddr(a, FALSE);
25558065Seric }
25658065Seric a->q_flags |= QDONTSEND;
25758065Seric }
25851923Seric if (i < 0)
25951923Seric {
26058010Seric syserr("udbexpand: db-get %.*s stat %d",
26158010Seric key.size, key.data, i);
26251923Seric return EX_TEMPFAIL;
26351923Seric }
26459707Seric
26559707Seric /*
26659707Seric ** If this address has a -request address, reflect
26759707Seric ** it into the envelope.
26859707Seric */
26959707Seric
27059707Seric (void) strcpy(keybuf, a->q_user);
27159707Seric (void) strcat(keybuf, ":mailsender");
27259707Seric keylen = strlen(keybuf);
27359707Seric key.data = keybuf;
27459707Seric key.size = keylen;
27559707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
27659707Seric if (i != 0 || info.size <= 0)
27759707Seric break;
27859707Seric a->q_owner = xalloc(info.size + 1);
27959707Seric bcopy(info.data, a->q_owner, info.size);
28059707Seric a->q_owner[info.size] = '\0';
28166784Seric
28266784Seric /* announce delivery; NORECEIPT bit set later */
28366784Seric if (e->e_xfp != NULL)
28466784Seric {
28566784Seric fprintf(e->e_xfp,
28666784Seric "Message delivered to mailing list %s\n",
28766784Seric a->q_paddr);
28866784Seric }
28968603Seric e->e_flags |= EF_SENDRECEIPT;
29068868Seric a->q_flags |= QDELIVERED|QEXPANDED;
29151360Seric break;
29268786Seric #endif
29351360Seric
29466759Seric #ifdef HESIOD
29566759Seric case UDB_HESIOD:
29666759Seric key.data = keybuf;
29766759Seric key.size = keylen;
29866759Seric if (tTd(28, 80))
29966759Seric printf("udbexpand: trying %s (%d) via hesiod\n",
30066759Seric keybuf, keylen);
30166759Seric /* look up the key via hesiod */
30266759Seric i = hes_udb_get(&key, &info);
30369623Seric if (i < 0)
30466759Seric {
30569623Seric syserr("udbexpand: hesiod-get %.*s stat %d",
30669623Seric key.size, key.data, i);
30769623Seric return EX_TEMPFAIL;
30869623Seric }
30969623Seric else if (i > 0 || info.size <= 0)
31069623Seric {
31166759Seric if (tTd(28, 2))
31266759Seric printf("udbexpand: no match on %s (%d)\n",
31366759Seric keybuf, keylen);
31466759Seric continue;
31566759Seric }
31666759Seric if (tTd(28, 80))
31766759Seric printf("udbexpand: match %.*s: %.*s\n",
31866759Seric key.size, key.data, info.size, info.data);
31966759Seric a->q_flags &= ~QSELFREF;
32066759Seric
32166759Seric if (bitset(EF_VRFYONLY, e->e_flags))
32266759Seric {
32366759Seric a->q_flags |= QVERIFIED;
32466759Seric e->e_nrcpts++;
32566759Seric return EX_OK;
32666759Seric }
32766759Seric
32866759Seric breakout = TRUE;
32966759Seric if (info.size < sizeof buf)
33066759Seric user = buf;
33166759Seric else
33266759Seric user = xalloc(info.size + 1);
33366759Seric bcopy(info.data, user, info.size);
33466759Seric user[info.size] = '\0';
33566759Seric
33666759Seric message("hesioded to %s", user);
33766759Seric #ifdef LOG
33866759Seric if (LogLevel >= 10)
33966759Seric syslog(LOG_INFO, "%s: hesiod %s => %s",
34066759Seric e->e_id, e->e_to, user);
34166759Seric #endif
34267982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
34366759Seric
34466759Seric if (user != buf)
34566759Seric free(user);
34666759Seric
34766759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
34866759Seric {
34966759Seric if (tTd(28, 5))
35066759Seric {
35166759Seric printf("udbexpand: QDONTSEND ");
35266759Seric printaddr(a, FALSE);
35366759Seric }
35466759Seric a->q_flags |= QDONTSEND;
35566759Seric }
35666759Seric
35766759Seric /*
35866759Seric ** If this address has a -request address, reflect
35966759Seric ** it into the envelope.
36066759Seric */
36166759Seric
36266759Seric (void) strcpy(keybuf, a->q_user);
36366759Seric (void) strcat(keybuf, ":mailsender");
36466759Seric keylen = strlen(keybuf);
36566759Seric key.data = keybuf;
36666759Seric key.size = keylen;
36766759Seric i = hes_udb_get(&key, &info);
36866759Seric if (i != 0 || info.size <= 0)
36966759Seric break;
37066759Seric a->q_owner = xalloc(info.size + 1);
37166759Seric bcopy(info.data, a->q_owner, info.size);
37266759Seric a->q_owner[info.size] = '\0';
37366759Seric break;
37466759Seric #endif /* HESIOD */
37566759Seric
37651360Seric case UDB_REMOTE:
37751741Seric /* not yet implemented */
37851741Seric continue;
37951362Seric
38051360Seric case UDB_FORWARD:
38158099Seric if (bitset(EF_VRFYONLY, e->e_flags))
38258099Seric return EX_OK;
38351360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
38451360Seric if (i < sizeof buf)
38551360Seric user = buf;
38651360Seric else
38751360Seric user = xalloc(i + 1);
38851360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
38958151Seric message("expanded to %s", user);
39058082Seric a->q_flags &= ~QSELFREF;
39167982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
39258082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
39358065Seric {
39458065Seric if (tTd(28, 5))
39558065Seric {
39658065Seric printf("udbexpand: QDONTSEND ");
39758065Seric printaddr(a, FALSE);
39858065Seric }
39958065Seric a->q_flags |= QDONTSEND;
40058065Seric }
40151362Seric if (user != buf)
40251362Seric free(user);
40351362Seric breakout = TRUE;
40451360Seric break;
40551360Seric
40651360Seric case UDB_EOLIST:
40751360Seric breakout = TRUE;
40851360Seric continue;
40951360Seric
41051360Seric default:
41151360Seric /* unknown entry type */
41251360Seric continue;
41351360Seric }
41451362Seric }
41551923Seric return EX_OK;
41651362Seric }
41751951Seric /*
41851951Seric ** UDBSENDER -- return canonical external name of sender, given local name
41951951Seric **
42051951Seric ** Parameters:
42151951Seric ** sender -- the name of the sender on the local machine.
42251951Seric **
42351951Seric ** Returns:
42451951Seric ** The external name for this sender, if derivable from the
42551951Seric ** database.
42651951Seric ** NULL -- if nothing is changed from the database.
42751951Seric **
42851951Seric ** Side Effects:
42951951Seric ** none.
43051951Seric */
43151360Seric
43251951Seric char *
udbsender(sender)43351951Seric udbsender(sender)
43451951Seric char *sender;
43551951Seric {
43664350Seric extern char *udbmatch();
43764350Seric
43864350Seric return udbmatch(sender, "mailname");
43964350Seric }
44064350Seric
44164350Seric
44264350Seric char *
udbmatch(user,field)44364350Seric udbmatch(user, field)
44464350Seric char *user;
44564350Seric char *field;
44664350Seric {
44751951Seric register char *p;
44851951Seric register struct udbent *up;
44951951Seric int i;
45051951Seric int keylen;
45151951Seric DBT key, info;
45257232Seric char keybuf[MAXKEY];
45351951Seric
45451951Seric if (tTd(28, 1))
45564350Seric printf("udbmatch(%s, %s)\n", user, field);
45651951Seric
45751951Seric if (!UdbInitialized)
45851951Seric {
45951951Seric if (_udbx_init() == EX_TEMPFAIL)
46051951Seric return NULL;
46151951Seric }
46251951Seric
46351951Seric /* short circuit if no spec */
46451951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0')
46551951Seric return NULL;
46651951Seric
46766759Seric /* short circuit name begins with '\\' since it can't possibly match */
46866759Seric if (user[0] == '\\')
46966759Seric return NULL;
47066759Seric
47151951Seric /* long names can never match and are a pain to deal with */
47264350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4)
47351951Seric return NULL;
47451951Seric
47551951Seric /* names beginning with colons indicate metadata */
47664350Seric if (user[0] == ':')
47751951Seric return NULL;
47851951Seric
47951951Seric /* build database key */
48064350Seric (void) strcpy(keybuf, user);
48164350Seric (void) strcat(keybuf, ":");
48264350Seric (void) strcat(keybuf, field);
48351951Seric keylen = strlen(keybuf);
48451951Seric
48551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
48651951Seric {
48751951Seric /*
48851951Seric ** Select action based on entry type.
48951951Seric */
49051951Seric
49151951Seric switch (up->udb_type)
49251951Seric {
49368786Seric #ifdef NEWDB
49451951Seric case UDB_DBFETCH:
49551951Seric key.data = keybuf;
49651951Seric key.size = keylen;
49751951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
49851951Seric if (i != 0 || info.size <= 0)
49951951Seric {
50051951Seric if (tTd(28, 2))
50166759Seric printf("udbmatch: no match on %s (%d) via db\n",
50264067Seric keybuf, keylen);
50351951Seric continue;
50451951Seric }
50551951Seric
50651951Seric p = xalloc(info.size + 1);
50751951Seric bcopy(info.data, p, info.size);
50851951Seric p[info.size] = '\0';
50951951Seric if (tTd(28, 1))
51064350Seric printf("udbmatch ==> %s\n", p);
51151951Seric return p;
51266759Seric break;
51368786Seric #endif
51466759Seric
51566759Seric #ifdef HESIOD
51666759Seric case UDB_HESIOD:
51766759Seric key.data = keybuf;
51866759Seric key.size = keylen;
51966759Seric i = hes_udb_get(&key, &info);
52066759Seric if (i != 0 || info.size <= 0)
52166759Seric {
52266759Seric if (tTd(28, 2))
52366759Seric printf("udbmatch: no match on %s (%d) via hesiod\n",
52466759Seric keybuf, keylen);
52566759Seric continue;
52666759Seric }
52766759Seric
52866759Seric p = xalloc(info.size + 1);
52966759Seric bcopy(info.data, p, info.size);
53066759Seric p[info.size] = '\0';
53166759Seric if (tTd(28, 1))
53266759Seric printf("udbmatch ==> %s\n", p);
53366759Seric return p;
53466759Seric #endif /* HESIOD */
53551951Seric }
53651951Seric }
53751951Seric
53864350Seric if (strcmp(field, "mailname") != 0)
53964350Seric return NULL;
54064350Seric
54151951Seric /*
54251951Seric ** Nothing yet. Search again for a default case. But only
54351951Seric ** use it if we also have a forward (:maildrop) pointer already
54451951Seric ** in the database.
54551951Seric */
54651951Seric
54751951Seric /* build database key */
54864350Seric (void) strcpy(keybuf, user);
54951951Seric (void) strcat(keybuf, ":maildrop");
55051951Seric keylen = strlen(keybuf);
55151951Seric
55251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
55351951Seric {
55451951Seric switch (up->udb_type)
55551951Seric {
55668786Seric #ifdef NEWDB
55751951Seric case UDB_DBFETCH:
55851951Seric /* get the default case for this database */
55951951Seric if (up->udb_default == NULL)
56051951Seric {
56151951Seric key.data = ":default:mailname";
56251951Seric key.size = strlen(key.data);
56351951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
56451951Seric if (i != 0 || info.size <= 0)
56551951Seric {
56651951Seric /* no default case */
56751951Seric up->udb_default = "";
56851951Seric continue;
56951951Seric }
57051951Seric
57151951Seric /* save the default case */
57251951Seric up->udb_default = xalloc(info.size + 1);
57351951Seric bcopy(info.data, up->udb_default, info.size);
57451951Seric up->udb_default[info.size] = '\0';
57551951Seric }
57651951Seric else if (up->udb_default[0] == '\0')
57751951Seric continue;
57851951Seric
57951951Seric /* we have a default case -- verify user:maildrop */
58051951Seric key.data = keybuf;
58151951Seric key.size = keylen;
58251951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
58351951Seric if (i != 0 || info.size <= 0)
58451951Seric {
58551951Seric /* nope -- no aliasing for this user */
58651951Seric continue;
58751951Seric }
58851951Seric
58951951Seric /* they exist -- build the actual address */
59064350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
59164350Seric (void) strcpy(p, user);
59251951Seric (void) strcat(p, "@");
59351951Seric (void) strcat(p, up->udb_default);
59451951Seric if (tTd(28, 1))
59564350Seric printf("udbmatch ==> %s\n", p);
59651951Seric return p;
59766759Seric break;
59868786Seric #endif
59966759Seric
60066759Seric #ifdef HESIOD
60166759Seric case UDB_HESIOD:
60266759Seric /* get the default case for this database */
60366759Seric if (up->udb_default == NULL)
60466759Seric {
60566759Seric key.data = ":default:mailname";
60666759Seric key.size = strlen(key.data);
60766759Seric i = hes_udb_get(&key, &info);
60866759Seric
60966759Seric if (i != 0 || info.size <= 0)
61066759Seric {
61166759Seric /* no default case */
61266759Seric up->udb_default = "";
61366759Seric continue;
61466759Seric }
61566759Seric
61666759Seric /* save the default case */
61766759Seric up->udb_default = xalloc(info.size + 1);
61866759Seric bcopy(info.data, up->udb_default, info.size);
61966759Seric up->udb_default[info.size] = '\0';
62066759Seric }
62166759Seric else if (up->udb_default[0] == '\0')
62266759Seric continue;
62366759Seric
62466759Seric /* we have a default case -- verify user:maildrop */
62566759Seric key.data = keybuf;
62666759Seric key.size = keylen;
62766759Seric i = hes_udb_get(&key, &info);
62866759Seric if (i != 0 || info.size <= 0)
62966759Seric {
63066759Seric /* nope -- no aliasing for this user */
63166759Seric continue;
63266759Seric }
63366759Seric
63466759Seric /* they exist -- build the actual address */
63566759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
63666759Seric (void) strcpy(p, user);
63766759Seric (void) strcat(p, "@");
63866759Seric (void) strcat(p, up->udb_default);
63966759Seric if (tTd(28, 1))
64066759Seric printf("udbmatch ==> %s\n", p);
64166759Seric return p;
64266759Seric break;
64366759Seric #endif /* HESIOD */
64451951Seric }
64551951Seric }
64651951Seric
64751951Seric /* still nothing.... too bad */
64851951Seric return NULL;
64951951Seric }
65051951Seric /*
65168521Seric ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
65268521Seric **
65368521Seric ** Parameters:
65468521Seric ** map -- the map being queried.
65568521Seric ** name -- the name to look up.
65668521Seric ** av -- arguments to the map lookup.
65768521Seric ** statp -- to get any error status.
65868521Seric **
65968521Seric ** Returns:
66068521Seric ** NULL if name not found in map.
66168521Seric ** The rewritten name otherwise.
66268521Seric */
66368521Seric
66468521Seric char *
udb_map_lookup(map,name,av,statp)66568521Seric udb_map_lookup(map, name, av, statp)
66668521Seric MAP *map;
66768521Seric char *name;
66868521Seric char **av;
66968521Seric int *statp;
67068521Seric {
67168521Seric char *val;
67268521Seric
67368521Seric if (tTd(38, 20))
67468521Seric printf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
67568521Seric val = udbmatch(name, map->map_file);
67668521Seric if (val == NULL)
67768521Seric return NULL;
67868521Seric if (bitset(MF_MATCHONLY, map->map_mflags))
67968521Seric return map_rewrite(map, name, strlen(name), NULL);
68068521Seric else
68168521Seric return map_rewrite(map, val, strlen(val), av);
68268521Seric }
68368521Seric /*
68451951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
68551951Seric **
68651951Seric ** Parameters:
68751951Seric ** none.
68851951Seric **
68951951Seric ** Returns:
69051951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
69151951Seric ** database due to a host being down or some similar
69251951Seric ** (recoverable) situation.
69351951Seric ** EX_OK -- otherwise.
69451951Seric **
69551951Seric ** Side Effects:
69651951Seric ** Fills in the UdbEnts structure from UdbSpec.
69751951Seric */
69851951Seric
69951363Seric #define MAXUDBOPTS 27
70051363Seric
70151953Seric int
_udbx_init()70251362Seric _udbx_init()
70351362Seric {
70451362Seric register char *p;
70551362Seric register struct udbent *up;
70651360Seric
70751951Seric if (UdbInitialized)
70851951Seric return EX_OK;
70951951Seric
71051908Seric # ifdef UDB_DEFAULT_SPEC
71151908Seric if (UdbSpec == NULL)
71251908Seric UdbSpec = UDB_DEFAULT_SPEC;
71351908Seric # endif
71451908Seric
71551362Seric p = UdbSpec;
71651362Seric up = UdbEnts;
71751762Seric while (p != NULL)
71851362Seric {
71951362Seric char *spec;
720*69748Seric int nopts;
721*69748Seric # if 0
72251362Seric auto int rcode;
72351362Seric int nmx;
724*69748Seric int i;
72551362Seric register struct hostent *h;
72651362Seric char *mxhosts[MAXMXHOSTS + 1];
727*69748Seric # endif
72851363Seric struct option opts[MAXUDBOPTS + 1];
72951362Seric
73051362Seric while (*p == ' ' || *p == '\t' || *p == ',')
73151362Seric p++;
73251362Seric if (*p == '\0')
73351362Seric break;
73451362Seric spec = p;
73556795Seric p = strchr(p, ',');
73651761Seric if (p != NULL)
73751362Seric *p++ = '\0';
73851363Seric
73951363Seric /* extract options */
74051363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
74151363Seric
74251363Seric /*
74351363Seric ** Decode database specification.
74451363Seric **
74551363Seric ** In the sendmail tradition, the leading character
74651363Seric ** defines the semantics of the rest of the entry.
74751363Seric **
74851363Seric ** +hostname -- send a datagram to the udb server
74951363Seric ** on host "hostname" asking for the
75051363Seric ** home mail server for this user.
75151363Seric ** *hostname -- similar to +hostname, except that the
75251363Seric ** hostname is searched as an MX record;
75351363Seric ** resulting hosts are searched as for
75451363Seric ** +mxhostname. If no MX host is found,
75551363Seric ** this is the same as +hostname.
75651363Seric ** @hostname -- forward email to the indicated host.
75751363Seric ** This should be the last in the list,
75851363Seric ** since it always matches the input.
75951363Seric ** /dbname -- search the named database on the local
76051363Seric ** host using the Berkeley db package.
76151363Seric */
76251363Seric
76351362Seric switch (*spec)
76451360Seric {
76568786Seric #if 0
76651362Seric case '+': /* search remote database */
76751363Seric case '*': /* search remote database (expand MX) */
76851363Seric if (*spec == '*')
76951363Seric {
77066334Seric #if NAMED_BIND
77159273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
77257629Seric #else
77357629Seric mxhosts[0] = spec + 1;
77457629Seric nmx = 1;
77557629Seric rcode = 0;
77657629Seric #endif
77751363Seric if (tTd(28, 16))
77851363Seric {
77951363Seric int i;
78051362Seric
78151363Seric printf("getmxrr(%s): %d", spec + 1, nmx);
78251363Seric for (i = 0; i <= nmx; i++)
78351363Seric printf(" %s", mxhosts[i]);
78451363Seric printf("\n");
78551363Seric }
78651363Seric }
78751363Seric else
78851362Seric {
78951363Seric nmx = 1;
79051363Seric mxhosts[0] = spec + 1;
79151362Seric }
79251362Seric
79351362Seric for (i = 0; i < nmx; i++)
79451362Seric {
79568693Seric h = sm_gethostbyname(mxhosts[i]);
79651362Seric if (h == NULL)
79751362Seric continue;
79851362Seric up->udb_type = UDB_REMOTE;
79951362Seric up->udb_addr.sin_family = h->h_addrtype;
80051362Seric bcopy(h->h_addr_list[0],
80151362Seric (char *) &up->udb_addr.sin_addr,
80267421Seric INADDRSZ);
80351362Seric up->udb_addr.sin_port = UdbPort;
80451362Seric up->udb_timeout = UdbTimeout;
80551362Seric up++;
80651362Seric }
80751362Seric
80851362Seric /* set up a datagram socket */
80951362Seric if (UdbSock < 0)
81051362Seric {
81151362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
81251362Seric (void) fcntl(UdbSock, F_SETFD, 1);
81351362Seric }
81451362Seric break;
81568786Seric #endif
81651362Seric
81751362Seric case '@': /* forward to remote host */
81851362Seric up->udb_type = UDB_FORWARD;
81951362Seric up->udb_fwdhost = spec + 1;
82051362Seric up++;
82151362Seric break;
82251362Seric
82368786Seric #ifdef HESIOD
82466759Seric case 'h': /* use hesiod */
82566759Seric case 'H':
82666759Seric if (strcasecmp(spec, "hesiod") != 0)
82768786Seric goto badspec;
82866759Seric up->udb_type = UDB_HESIOD;
82966759Seric up++;
83068786Seric break;
83166759Seric #endif /* HESIOD */
83266759Seric
83368786Seric #ifdef NEWDB
83451362Seric case '/': /* look up remote name */
83551831Seric up->udb_dbname = spec;
83651923Seric errno = 0;
83751362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
83851362Seric if (up->udb_dbp == NULL)
83951923Seric {
84067763Seric if (tTd(28, 1))
84167763Seric {
84267763Seric int saveerrno = errno;
84367763Seric
84467763Seric printf("dbopen(%s): %s",
84567763Seric spec, errstring(errno));
84667763Seric errno = saveerrno;
84767763Seric }
84851923Seric if (errno != ENOENT && errno != EACCES)
84951951Seric {
85059615Seric #ifdef LOG
85159615Seric if (LogLevel > 2)
85259625Seric syslog(LOG_ERR, "dbopen(%s): %s",
85359625Seric spec, errstring(errno));
85459615Seric #endif
85551951Seric up->udb_type = UDB_EOLIST;
85651951Seric goto tempfail;
85751951Seric }
85851362Seric break;
85951923Seric }
86051951Seric up->udb_type = UDB_DBFETCH;
86151362Seric up++;
86251362Seric break;
86368786Seric #endif
86468786Seric
86568786Seric default:
86668786Seric badspec:
86768786Seric syserr("Unknown UDB spec %s", spec);
86868786Seric break;
86951360Seric }
87051362Seric }
87151362Seric up->udb_type = UDB_EOLIST;
87251360Seric
87351362Seric if (tTd(28, 4))
87451362Seric {
87551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
87651360Seric {
87751362Seric switch (up->udb_type)
87851362Seric {
87951362Seric case UDB_REMOTE:
88051362Seric printf("REMOTE: addr %s, timeo %d\n",
88160494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr),
88251362Seric up->udb_timeout);
88351362Seric break;
88451362Seric
88551951Seric case UDB_DBFETCH:
88669711Seric #ifdef NEWDB
88751951Seric printf("FETCH: file %s\n",
88851830Seric up->udb_dbname);
88969711Seric #else
89069711Seric printf("FETCH\n");
89169711Seric #endif
89251362Seric break;
89351362Seric
89451362Seric case UDB_FORWARD:
89551362Seric printf("FORWARD: host %s\n",
89651362Seric up->udb_fwdhost);
89751362Seric break;
89851362Seric
89966759Seric case UDB_HESIOD:
90066759Seric printf("HESIOD\n");
90166759Seric break;
90266759Seric
90351362Seric default:
90451362Seric printf("UNKNOWN\n");
90551362Seric break;
90651362Seric }
90751360Seric }
90850581Seric }
90951951Seric
91051951Seric UdbInitialized = TRUE;
91151955Seric errno = 0;
91251951Seric return EX_OK;
91351951Seric
91451951Seric /*
91551951Seric ** On temporary failure, back out anything we've already done
91651951Seric */
91751951Seric
91851951Seric tempfail:
91968786Seric #ifdef NEWDB
92051951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
92151951Seric {
92251951Seric if (up->udb_type == UDB_DBFETCH)
92351951Seric {
92451951Seric (*up->udb_dbp->close)(up->udb_dbp);
92551951Seric }
92651951Seric }
92768786Seric #endif
92851951Seric return EX_TEMPFAIL;
92951360Seric }
93050581Seric
93151363Seric int
_udb_parsespec(udbspec,opt,maxopts)93251363Seric _udb_parsespec(udbspec, opt, maxopts)
93351363Seric char *udbspec;
93451363Seric struct option opt[];
93551363Seric int maxopts;
93651363Seric {
93751363Seric register char *spec;
93851363Seric register char *spec_end;
93951363Seric register int optnum;
94051363Seric
94156795Seric spec_end = strchr(udbspec, ':');
94251363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
94351363Seric {
94451363Seric register char *p;
94551363Seric
94658050Seric while (isascii(*spec) && isspace(*spec))
94751363Seric spec++;
94856795Seric spec_end = strchr(spec, ':');
94951363Seric if (spec_end != NULL)
95051363Seric *spec_end++ = '\0';
95151363Seric
95251363Seric opt[optnum].name = spec;
95351363Seric opt[optnum].val = NULL;
95456795Seric p = strchr(spec, '=');
95551363Seric if (p != NULL)
95651363Seric opt[optnum].val = ++p;
95751363Seric }
95851363Seric return optnum;
95951363Seric }
96051363Seric
96166759Seric #ifdef HESIOD
96266759Seric
96366759Seric int
hes_udb_get(key,info)96466759Seric hes_udb_get(key, info)
96566759Seric DBT *key;
96666759Seric DBT *info;
96766759Seric {
96866759Seric char *name, *type;
96966759Seric char *p, **hp;
97068533Seric char kbuf[MAXKEY + 1];
97166759Seric
97268533Seric strcpy(kbuf, key->data);
97368533Seric name = kbuf;
97466759Seric type = strchr(name, ':');
97568544Seric if (type == NULL)
97666759Seric return 1;
97766759Seric *type++ = '\0';
97866759Seric
97966759Seric if (tTd(28, 1))
98066759Seric printf("hes_udb_get(%s, %s)\n", name, type);
98166759Seric
98266759Seric /* make the hesiod query */
98366759Seric hp = hes_resolve(name, type);
98469711Seric *--type = ':';
98566759Seric if (hp == NULL)
98666759Seric {
98766759Seric /* network problem or timeout */
98866759Seric if (hes_error() == HES_ER_NET)
98966759Seric return -1;
99066759Seric
99166759Seric return 1;
99266759Seric }
99366759Seric else
99466759Seric {
99566759Seric /*
99666759Seric ** If there are multiple matches, just return the
99769623Seric ** first one.
99866759Seric **
99966759Seric ** XXX These should really be returned; for example,
100066759Seric ** XXX it is legal for :maildrop to be multi-valued.
100166759Seric */
100266759Seric
100366759Seric info->data = hp[0];
100466759Seric info->size = (size_t) strlen(info->data);
100566759Seric }
100666759Seric
100766759Seric return 0;
100866759Seric }
100966759Seric #endif /* HESIOD */
101066759Seric
101151360Seric #else /* not USERDB */
101251360Seric
101351923Seric int
udbexpand(a,sendq,aliaslevel,e)101467982Seric udbexpand(a, sendq, aliaslevel, e)
101551360Seric ADDRESS *a;
101651360Seric ADDRESS **sendq;
101767982Seric int aliaslevel;
101855012Seric ENVELOPE *e;
101951360Seric {
102051923Seric return EX_OK;
102150581Seric }
102250581Seric
102350581Seric #endif /* USERDB */
1024