150581Seric /* 250581Seric * Copyright (c) 1983 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 1251360Seric #ifdef USERDB 13*68786Seric static char sccsid [] = "@(#)udb.c 8.18 (Berkeley) 04/12/95 (with USERDB)"; 1451360Seric #else 15*68786Seric static char sccsid [] = "@(#)udb.c 8.18 (Berkeley) 04/12/95 (without USERDB)"; 1650581Seric #endif 1751360Seric #endif 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2151923Seric #include <errno.h> 2250581Seric #include <db.h> 2350581Seric 2466759Seric #ifdef HESIOD 2566759Seric #include <hesiod.h> 2666759Seric #endif /* HESIOD */ 2766759Seric 2850581Seric /* 2953654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 3050581Seric ** 3151363Seric ** This depends on the 4.4BSD db package. 3250581Seric */ 3350581Seric 3451362Seric 3551360Seric struct udbent 3651360Seric { 3751360Seric char *udb_spec; /* string version of spec */ 3851360Seric int udb_type; /* type of entry */ 3951951Seric char *udb_default; /* default host for outgoing mail */ 4051360Seric union 4151360Seric { 4251360Seric /* type UE_REMOTE -- do remote call for lookup */ 4351360Seric struct 4451360Seric { 4551360Seric struct sockaddr_in _udb_addr; /* address */ 4651360Seric int _udb_timeout; /* timeout */ 4751360Seric } udb_remote; 4851360Seric #define udb_addr udb_u.udb_remote._udb_addr 4951360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 5051360Seric 5151360Seric /* type UE_FORWARD -- forward message to remote */ 5251360Seric struct 5351360Seric { 5451360Seric char *_udb_fwdhost; /* name of forward host */ 5551360Seric } udb_forward; 5651360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 5751360Seric 5851951Seric /* type UE_FETCH -- lookup in local database */ 5951360Seric struct 6051360Seric { 6151360Seric char *_udb_dbname; /* pathname of database */ 6251360Seric DB *_udb_dbp; /* open database ptr */ 6351360Seric } udb_lookup; 6451360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 6551360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 6651360Seric } udb_u; 6751360Seric }; 6851360Seric 6951360Seric #define UDB_EOLIST 0 /* end of list */ 7051360Seric #define UDB_SKIP 1 /* skip this entry */ 7151360Seric #define UDB_REMOTE 2 /* look up in remote database */ 7251951Seric #define UDB_DBFETCH 3 /* look up in local database */ 7351360Seric #define UDB_FORWARD 4 /* forward to remote host */ 7466759Seric #define UDB_HESIOD 5 /* look up via hesiod */ 7551360Seric 7651360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 7751360Seric 7851363Seric 7951363Seric struct option 8051363Seric { 8151363Seric char *name; 8251363Seric char *val; 8351363Seric }; 8451363Seric /* 8551363Seric ** UDBEXPAND -- look up user in database and expand 8651363Seric ** 8751363Seric ** Parameters: 8851363Seric ** a -- address to expand. 8951363Seric ** sendq -- pointer to head of sendq to put the expansions in. 9067982Seric ** aliaslevel -- the current alias nesting depth. 9167982Seric ** e -- the current envelope. 9251363Seric ** 9351363Seric ** Returns: 9451923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 9551923Seric ** to accessing a file on an NFS server that is down. 9651923Seric ** EX_OK -- otherwise. 9751363Seric ** 9851363Seric ** Side Effects: 9951363Seric ** Modifies sendq. 10051363Seric */ 10151363Seric 10251363Seric int UdbPort = 1616; 10351363Seric int UdbTimeout = 10; 10451363Seric 10551953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10651953Seric int UdbSock = -1; 10751953Seric bool UdbInitialized = FALSE; 10851360Seric 10951923Seric int 11067982Seric udbexpand(a, sendq, aliaslevel, e) 11150581Seric register ADDRESS *a; 11250581Seric ADDRESS **sendq; 11367982Seric int aliaslevel; 11455012Seric register ENVELOPE *e; 11550581Seric { 11650581Seric int i; 11750581Seric register char *p; 11850581Seric DBT key; 11950581Seric DBT info; 12051360Seric bool breakout; 12151360Seric register struct udbent *up; 12251362Seric int keylen; 12358082Seric int naddrs; 12457232Seric char keybuf[MAXKEY]; 12557232Seric char buf[BUFSIZ]; 12650581Seric 12750581Seric if (tTd(28, 1)) 12858065Seric printf("udbexpand(%s)\n", a->q_paddr); 12950581Seric 13050581Seric /* make certain we are supposed to send to this address */ 13158154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 13251923Seric return EX_OK; 13355012Seric e->e_to = a->q_paddr; 13450581Seric 13551360Seric /* on first call, locate the database */ 13651951Seric if (!UdbInitialized) 13750581Seric { 13851923Seric extern int _udbx_init(); 13951362Seric 14051923Seric if (_udbx_init() == EX_TEMPFAIL) 14151923Seric return EX_TEMPFAIL; 14251362Seric } 14350581Seric 14451909Seric /* short circuit the process if no chance of a match */ 14551909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 14651923Seric return EX_OK; 14751909Seric 14866759Seric /* short circuit name begins with '\\' since it can't possibly match */ 14966759Seric if (a->q_user[0] == '\\') 15066759Seric return EX_OK; 15166759Seric 15251362Seric /* if name is too long, assume it won't match */ 15351362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 15451923Seric return EX_OK; 15551360Seric 15651362Seric /* if name begins with a colon, it indicates our metadata */ 15751362Seric if (a->q_user[0] == ':') 15851923Seric return EX_OK; 15951360Seric 16051362Seric /* build actual database key */ 16151362Seric (void) strcpy(keybuf, a->q_user); 16251362Seric (void) strcat(keybuf, ":maildrop"); 16351362Seric keylen = strlen(keybuf); 16451360Seric 16551360Seric breakout = FALSE; 16651362Seric for (up = UdbEnts; !breakout; up++) 16750581Seric { 16851360Seric char *user; 16950581Seric 17051360Seric /* 17151360Seric ** Select action based on entry type. 17251360Seric ** 17351360Seric ** On dropping out of this switch, "class" should 17451360Seric ** explain the type of the data, and "user" should 17551360Seric ** contain the user information. 17651360Seric */ 17750581Seric 17851360Seric switch (up->udb_type) 17951360Seric { 180*68786Seric #ifdef NEWDB 18151951Seric case UDB_DBFETCH: 18251362Seric key.data = keybuf; 18351362Seric key.size = keylen; 18460990Seric if (tTd(28, 80)) 18566759Seric printf("udbexpand: trying %s (%d) via db\n", 18664067Seric keybuf, keylen); 18751362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 18851923Seric if (i > 0 || info.size <= 0) 18951360Seric { 19051360Seric if (tTd(28, 2)) 19164067Seric printf("udbexpand: no match on %s (%d)\n", 19264067Seric keybuf, keylen); 19351360Seric continue; 19451360Seric } 19560990Seric if (tTd(28, 80)) 19660990Seric printf("udbexpand: match %.*s: %.*s\n", 19760990Seric key.size, key.data, info.size, info.data); 19850581Seric 19958082Seric naddrs = 0; 20058082Seric a->q_flags &= ~QSELFREF; 20151830Seric while (i == 0 && key.size == keylen && 20251830Seric bcmp(key.data, keybuf, keylen) == 0) 20351362Seric { 20458099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 20558154Seric { 20658154Seric a->q_flags |= QVERIFIED; 20758884Seric e->e_nrcpts++; 20858099Seric return EX_OK; 20958154Seric } 21058099Seric 21151830Seric breakout = TRUE; 21251362Seric if (info.size < sizeof buf) 21351362Seric user = buf; 21451362Seric else 21551362Seric user = xalloc(info.size + 1); 21651362Seric bcopy(info.data, user, info.size); 21751362Seric user[info.size] = '\0'; 21850581Seric 21958151Seric message("expanded to %s", user); 22057977Seric #ifdef LOG 22157977Seric if (LogLevel >= 10) 22257977Seric syslog(LOG_INFO, "%s: expand %s => %s", 22357977Seric e->e_id, e->e_to, user); 22457977Seric #endif 22567982Seric naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e); 22651362Seric 22751362Seric if (user != buf) 22851362Seric free(user); 22951362Seric 23051362Seric /* get the next record */ 23151362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 23251830Seric } 23360990Seric 23460990Seric /* if nothing ever matched, try next database */ 23560990Seric if (!breakout) 23660990Seric continue; 23760990Seric 23858082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 23958065Seric { 24058065Seric if (tTd(28, 5)) 24158065Seric { 24258065Seric printf("udbexpand: QDONTSEND "); 24358065Seric printaddr(a, FALSE); 24458065Seric } 24558065Seric a->q_flags |= QDONTSEND; 24658065Seric } 24751923Seric if (i < 0) 24851923Seric { 24958010Seric syserr("udbexpand: db-get %.*s stat %d", 25058010Seric key.size, key.data, i); 25151923Seric return EX_TEMPFAIL; 25251923Seric } 25359707Seric 25459707Seric /* 25559707Seric ** If this address has a -request address, reflect 25659707Seric ** it into the envelope. 25759707Seric */ 25859707Seric 25959707Seric (void) strcpy(keybuf, a->q_user); 26059707Seric (void) strcat(keybuf, ":mailsender"); 26159707Seric keylen = strlen(keybuf); 26259707Seric key.data = keybuf; 26359707Seric key.size = keylen; 26459707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 26559707Seric if (i != 0 || info.size <= 0) 26659707Seric break; 26759707Seric a->q_owner = xalloc(info.size + 1); 26859707Seric bcopy(info.data, a->q_owner, info.size); 26959707Seric a->q_owner[info.size] = '\0'; 27066784Seric 27166784Seric /* announce delivery; NORECEIPT bit set later */ 27266784Seric if (e->e_xfp != NULL) 27366784Seric { 27466784Seric fprintf(e->e_xfp, 27566784Seric "Message delivered to mailing list %s\n", 27666784Seric a->q_paddr); 27766784Seric } 27868603Seric e->e_flags |= EF_SENDRECEIPT; 27968603Seric a->q_flags |= QREPORT|QEXPLODED; 28051360Seric break; 281*68786Seric #endif 28251360Seric 28366759Seric #ifdef HESIOD 28466759Seric case UDB_HESIOD: 28566759Seric key.data = keybuf; 28666759Seric key.size = keylen; 28766759Seric if (tTd(28, 80)) 28866759Seric printf("udbexpand: trying %s (%d) via hesiod\n", 28966759Seric keybuf, keylen); 29066759Seric /* look up the key via hesiod */ 29166759Seric i = hes_udb_get(&key, &info); 29266759Seric if (i > 0 || info.size <= 0) 29366759Seric { 29466759Seric if (tTd(28, 2)) 29566759Seric printf("udbexpand: no match on %s (%d)\n", 29666759Seric keybuf, keylen); 29766759Seric continue; 29866759Seric } 29966759Seric if (tTd(28, 80)) 30066759Seric printf("udbexpand: match %.*s: %.*s\n", 30166759Seric key.size, key.data, info.size, info.data); 30266759Seric a->q_flags &= ~QSELFREF; 30366759Seric 30466759Seric if (bitset(EF_VRFYONLY, e->e_flags)) 30566759Seric { 30666759Seric a->q_flags |= QVERIFIED; 30766759Seric e->e_nrcpts++; 30866759Seric free(info.data); 30966759Seric return EX_OK; 31066759Seric } 31166759Seric 31266759Seric breakout = TRUE; 31366759Seric if (info.size < sizeof buf) 31466759Seric user = buf; 31566759Seric else 31666759Seric user = xalloc(info.size + 1); 31766759Seric bcopy(info.data, user, info.size); 31866759Seric user[info.size] = '\0'; 31966759Seric free(info.data); 32066759Seric 32166759Seric message("hesioded to %s", user); 32266759Seric #ifdef LOG 32366759Seric if (LogLevel >= 10) 32466759Seric syslog(LOG_INFO, "%s: hesiod %s => %s", 32566759Seric e->e_id, e->e_to, user); 32666759Seric #endif 32767982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 32866759Seric 32966759Seric if (user != buf) 33066759Seric free(user); 33166759Seric 33266759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 33366759Seric { 33466759Seric if (tTd(28, 5)) 33566759Seric { 33666759Seric printf("udbexpand: QDONTSEND "); 33766759Seric printaddr(a, FALSE); 33866759Seric } 33966759Seric a->q_flags |= QDONTSEND; 34066759Seric } 34166759Seric if (i < 0) 34266759Seric { 34366759Seric syserr("udbexpand: hesiod-get %.*s stat %d", 34466759Seric key.size, key.data, i); 34566759Seric return EX_TEMPFAIL; 34666759Seric } 34766759Seric 34866759Seric /* 34966759Seric ** If this address has a -request address, reflect 35066759Seric ** it into the envelope. 35166759Seric */ 35266759Seric 35366759Seric (void) strcpy(keybuf, a->q_user); 35466759Seric (void) strcat(keybuf, ":mailsender"); 35566759Seric keylen = strlen(keybuf); 35666759Seric key.data = keybuf; 35766759Seric key.size = keylen; 35866759Seric i = hes_udb_get(&key, &info); 35966759Seric if (i != 0 || info.size <= 0) 36066759Seric break; 36166759Seric a->q_owner = xalloc(info.size + 1); 36266759Seric bcopy(info.data, a->q_owner, info.size); 36366759Seric a->q_owner[info.size] = '\0'; 36466759Seric free(info.data); 36566759Seric break; 36666759Seric #endif /* HESIOD */ 36766759Seric 36851360Seric case UDB_REMOTE: 36951741Seric /* not yet implemented */ 37051741Seric continue; 37151362Seric 37251360Seric case UDB_FORWARD: 37358099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 37458099Seric return EX_OK; 37551360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 37651360Seric if (i < sizeof buf) 37751360Seric user = buf; 37851360Seric else 37951360Seric user = xalloc(i + 1); 38051360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 38158151Seric message("expanded to %s", user); 38258082Seric a->q_flags &= ~QSELFREF; 38367982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 38458082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 38558065Seric { 38658065Seric if (tTd(28, 5)) 38758065Seric { 38858065Seric printf("udbexpand: QDONTSEND "); 38958065Seric printaddr(a, FALSE); 39058065Seric } 39158065Seric a->q_flags |= QDONTSEND; 39258065Seric } 39351362Seric if (user != buf) 39451362Seric free(user); 39551362Seric breakout = TRUE; 39651360Seric break; 39751360Seric 39851360Seric case UDB_EOLIST: 39951360Seric breakout = TRUE; 40051360Seric continue; 40151360Seric 40251360Seric default: 40351360Seric /* unknown entry type */ 40451360Seric continue; 40551360Seric } 40651362Seric } 40751923Seric return EX_OK; 40851362Seric } 40951951Seric /* 41051951Seric ** UDBSENDER -- return canonical external name of sender, given local name 41151951Seric ** 41251951Seric ** Parameters: 41351951Seric ** sender -- the name of the sender on the local machine. 41451951Seric ** 41551951Seric ** Returns: 41651951Seric ** The external name for this sender, if derivable from the 41751951Seric ** database. 41851951Seric ** NULL -- if nothing is changed from the database. 41951951Seric ** 42051951Seric ** Side Effects: 42151951Seric ** none. 42251951Seric */ 42351360Seric 42451951Seric char * 42551951Seric udbsender(sender) 42651951Seric char *sender; 42751951Seric { 42864350Seric extern char *udbmatch(); 42964350Seric 43064350Seric return udbmatch(sender, "mailname"); 43164350Seric } 43264350Seric 43364350Seric 43464350Seric char * 43564350Seric udbmatch(user, field) 43664350Seric char *user; 43764350Seric char *field; 43864350Seric { 43951951Seric register char *p; 44051951Seric register struct udbent *up; 44151951Seric int i; 44251951Seric int keylen; 44351951Seric DBT key, info; 44457232Seric char keybuf[MAXKEY]; 44551951Seric 44651951Seric if (tTd(28, 1)) 44764350Seric printf("udbmatch(%s, %s)\n", user, field); 44851951Seric 44951951Seric if (!UdbInitialized) 45051951Seric { 45151951Seric if (_udbx_init() == EX_TEMPFAIL) 45251951Seric return NULL; 45351951Seric } 45451951Seric 45551951Seric /* short circuit if no spec */ 45651951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 45751951Seric return NULL; 45851951Seric 45966759Seric /* short circuit name begins with '\\' since it can't possibly match */ 46066759Seric if (user[0] == '\\') 46166759Seric return NULL; 46266759Seric 46351951Seric /* long names can never match and are a pain to deal with */ 46464350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 46551951Seric return NULL; 46651951Seric 46751951Seric /* names beginning with colons indicate metadata */ 46864350Seric if (user[0] == ':') 46951951Seric return NULL; 47051951Seric 47151951Seric /* build database key */ 47264350Seric (void) strcpy(keybuf, user); 47364350Seric (void) strcat(keybuf, ":"); 47464350Seric (void) strcat(keybuf, field); 47551951Seric keylen = strlen(keybuf); 47651951Seric 47751951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 47851951Seric { 47951951Seric /* 48051951Seric ** Select action based on entry type. 48151951Seric */ 48251951Seric 48351951Seric switch (up->udb_type) 48451951Seric { 485*68786Seric #ifdef NEWDB 48651951Seric case UDB_DBFETCH: 48751951Seric key.data = keybuf; 48851951Seric key.size = keylen; 48951951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 49051951Seric if (i != 0 || info.size <= 0) 49151951Seric { 49251951Seric if (tTd(28, 2)) 49366759Seric printf("udbmatch: no match on %s (%d) via db\n", 49464067Seric keybuf, keylen); 49551951Seric continue; 49651951Seric } 49751951Seric 49851951Seric p = xalloc(info.size + 1); 49951951Seric bcopy(info.data, p, info.size); 50051951Seric p[info.size] = '\0'; 50151951Seric if (tTd(28, 1)) 50264350Seric printf("udbmatch ==> %s\n", p); 50351951Seric return p; 50466759Seric break; 505*68786Seric #endif 50666759Seric 50766759Seric #ifdef HESIOD 50866759Seric case UDB_HESIOD: 50966759Seric key.data = keybuf; 51066759Seric key.size = keylen; 51166759Seric i = hes_udb_get(&key, &info); 51266759Seric if (i != 0 || info.size <= 0) 51366759Seric { 51466759Seric if (tTd(28, 2)) 51566759Seric printf("udbmatch: no match on %s (%d) via hesiod\n", 51666759Seric keybuf, keylen); 51766759Seric continue; 51866759Seric } 51966759Seric 52066759Seric p = xalloc(info.size + 1); 52166759Seric bcopy(info.data, p, info.size); 52266759Seric p[info.size] = '\0'; 52366759Seric free(info.data); 52466759Seric if (tTd(28, 1)) 52566759Seric printf("udbmatch ==> %s\n", p); 52666759Seric return p; 52766759Seric break; 52866759Seric #endif /* HESIOD */ 52951951Seric } 53051951Seric } 53151951Seric 53264350Seric if (strcmp(field, "mailname") != 0) 53364350Seric return NULL; 53464350Seric 53551951Seric /* 53651951Seric ** Nothing yet. Search again for a default case. But only 53751951Seric ** use it if we also have a forward (:maildrop) pointer already 53851951Seric ** in the database. 53951951Seric */ 54051951Seric 54151951Seric /* build database key */ 54264350Seric (void) strcpy(keybuf, user); 54351951Seric (void) strcat(keybuf, ":maildrop"); 54451951Seric keylen = strlen(keybuf); 54551951Seric 54651951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 54751951Seric { 54851951Seric switch (up->udb_type) 54951951Seric { 550*68786Seric #ifdef NEWDB 55151951Seric case UDB_DBFETCH: 55251951Seric /* get the default case for this database */ 55351951Seric if (up->udb_default == NULL) 55451951Seric { 55551951Seric key.data = ":default:mailname"; 55651951Seric key.size = strlen(key.data); 55751951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 55851951Seric if (i != 0 || info.size <= 0) 55951951Seric { 56051951Seric /* no default case */ 56151951Seric up->udb_default = ""; 56251951Seric continue; 56351951Seric } 56451951Seric 56551951Seric /* save the default case */ 56651951Seric up->udb_default = xalloc(info.size + 1); 56751951Seric bcopy(info.data, up->udb_default, info.size); 56851951Seric up->udb_default[info.size] = '\0'; 56951951Seric } 57051951Seric else if (up->udb_default[0] == '\0') 57151951Seric continue; 57251951Seric 57351951Seric /* we have a default case -- verify user:maildrop */ 57451951Seric key.data = keybuf; 57551951Seric key.size = keylen; 57651951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 57751951Seric if (i != 0 || info.size <= 0) 57851951Seric { 57951951Seric /* nope -- no aliasing for this user */ 58051951Seric continue; 58151951Seric } 58251951Seric 58351951Seric /* they exist -- build the actual address */ 58464350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 58564350Seric (void) strcpy(p, user); 58651951Seric (void) strcat(p, "@"); 58751951Seric (void) strcat(p, up->udb_default); 58851951Seric if (tTd(28, 1)) 58964350Seric printf("udbmatch ==> %s\n", p); 59051951Seric return p; 59166759Seric break; 592*68786Seric #endif 59366759Seric 59466759Seric #ifdef HESIOD 59566759Seric case UDB_HESIOD: 59666759Seric /* get the default case for this database */ 59766759Seric if (up->udb_default == NULL) 59866759Seric { 59966759Seric key.data = ":default:mailname"; 60066759Seric key.size = strlen(key.data); 60166759Seric i = hes_udb_get(&key, &info); 60266759Seric 60366759Seric if (i != 0 || info.size <= 0) 60466759Seric { 60566759Seric /* no default case */ 60666759Seric up->udb_default = ""; 60766759Seric continue; 60866759Seric } 60966759Seric 61066759Seric /* save the default case */ 61166759Seric up->udb_default = xalloc(info.size + 1); 61266759Seric bcopy(info.data, up->udb_default, info.size); 61366759Seric up->udb_default[info.size] = '\0'; 61466759Seric free(info.data); 61566759Seric } 61666759Seric else if (up->udb_default[0] == '\0') 61766759Seric continue; 61866759Seric 61966759Seric /* we have a default case -- verify user:maildrop */ 62066759Seric key.data = keybuf; 62166759Seric key.size = keylen; 62266759Seric i = hes_udb_get(&key, &info); 62366759Seric if (i != 0 || info.size <= 0) 62466759Seric { 62566759Seric /* nope -- no aliasing for this user */ 62666759Seric continue; 62766759Seric } 62866759Seric 62966759Seric free(info.data); 63066759Seric /* they exist -- build the actual address */ 63166759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 63266759Seric (void) strcpy(p, user); 63366759Seric (void) strcat(p, "@"); 63466759Seric (void) strcat(p, up->udb_default); 63566759Seric if (tTd(28, 1)) 63666759Seric printf("udbmatch ==> %s\n", p); 63766759Seric return p; 63866759Seric break; 63966759Seric #endif /* HESIOD */ 64051951Seric } 64151951Seric } 64251951Seric 64351951Seric /* still nothing.... too bad */ 64451951Seric return NULL; 64551951Seric } 64651951Seric /* 64768521Seric ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 64868521Seric ** 64968521Seric ** Parameters: 65068521Seric ** map -- the map being queried. 65168521Seric ** name -- the name to look up. 65268521Seric ** av -- arguments to the map lookup. 65368521Seric ** statp -- to get any error status. 65468521Seric ** 65568521Seric ** Returns: 65668521Seric ** NULL if name not found in map. 65768521Seric ** The rewritten name otherwise. 65868521Seric */ 65968521Seric 66068521Seric char * 66168521Seric udb_map_lookup(map, name, av, statp) 66268521Seric MAP *map; 66368521Seric char *name; 66468521Seric char **av; 66568521Seric int *statp; 66668521Seric { 66768521Seric char *val; 66868521Seric 66968521Seric if (tTd(38, 20)) 67068521Seric printf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 67168521Seric val = udbmatch(name, map->map_file); 67268521Seric if (val == NULL) 67368521Seric return NULL; 67468521Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 67568521Seric return map_rewrite(map, name, strlen(name), NULL); 67668521Seric else 67768521Seric return map_rewrite(map, val, strlen(val), av); 67868521Seric } 67968521Seric /* 68051951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 68151951Seric ** 68251951Seric ** Parameters: 68351951Seric ** none. 68451951Seric ** 68551951Seric ** Returns: 68651951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 68751951Seric ** database due to a host being down or some similar 68851951Seric ** (recoverable) situation. 68951951Seric ** EX_OK -- otherwise. 69051951Seric ** 69151951Seric ** Side Effects: 69251951Seric ** Fills in the UdbEnts structure from UdbSpec. 69351951Seric */ 69451951Seric 69551363Seric #define MAXUDBOPTS 27 69651363Seric 69751953Seric int 69851362Seric _udbx_init() 69951362Seric { 70051362Seric register char *p; 70151362Seric int i; 70251362Seric register struct udbent *up; 70357232Seric char buf[BUFSIZ]; 70451360Seric 70551951Seric if (UdbInitialized) 70651951Seric return EX_OK; 70751951Seric 70851908Seric # ifdef UDB_DEFAULT_SPEC 70951908Seric if (UdbSpec == NULL) 71051908Seric UdbSpec = UDB_DEFAULT_SPEC; 71151908Seric # endif 71251908Seric 71351362Seric p = UdbSpec; 71451362Seric up = UdbEnts; 71551762Seric while (p != NULL) 71651362Seric { 71751362Seric char *spec; 71851362Seric auto int rcode; 71951363Seric int nopts; 72051362Seric int nmx; 72151362Seric register struct hostent *h; 72251362Seric char *mxhosts[MAXMXHOSTS + 1]; 72351363Seric struct option opts[MAXUDBOPTS + 1]; 72451362Seric 72551362Seric while (*p == ' ' || *p == '\t' || *p == ',') 72651362Seric p++; 72751362Seric if (*p == '\0') 72851362Seric break; 72951362Seric spec = p; 73056795Seric p = strchr(p, ','); 73151761Seric if (p != NULL) 73251362Seric *p++ = '\0'; 73351363Seric 73451363Seric /* extract options */ 73551363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 73651363Seric 73751363Seric /* 73851363Seric ** Decode database specification. 73951363Seric ** 74051363Seric ** In the sendmail tradition, the leading character 74151363Seric ** defines the semantics of the rest of the entry. 74251363Seric ** 74351363Seric ** +hostname -- send a datagram to the udb server 74451363Seric ** on host "hostname" asking for the 74551363Seric ** home mail server for this user. 74651363Seric ** *hostname -- similar to +hostname, except that the 74751363Seric ** hostname is searched as an MX record; 74851363Seric ** resulting hosts are searched as for 74951363Seric ** +mxhostname. If no MX host is found, 75051363Seric ** this is the same as +hostname. 75151363Seric ** @hostname -- forward email to the indicated host. 75251363Seric ** This should be the last in the list, 75351363Seric ** since it always matches the input. 75451363Seric ** /dbname -- search the named database on the local 75551363Seric ** host using the Berkeley db package. 75651363Seric */ 75751363Seric 75851362Seric switch (*spec) 75951360Seric { 760*68786Seric #if 0 76151362Seric case '+': /* search remote database */ 76251363Seric case '*': /* search remote database (expand MX) */ 76351363Seric if (*spec == '*') 76451363Seric { 76566334Seric #if NAMED_BIND 76659273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 76757629Seric #else 76857629Seric mxhosts[0] = spec + 1; 76957629Seric nmx = 1; 77057629Seric rcode = 0; 77157629Seric #endif 77251363Seric if (tTd(28, 16)) 77351363Seric { 77451363Seric int i; 77551362Seric 77651363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 77751363Seric for (i = 0; i <= nmx; i++) 77851363Seric printf(" %s", mxhosts[i]); 77951363Seric printf("\n"); 78051363Seric } 78151363Seric } 78251363Seric else 78351362Seric { 78451363Seric nmx = 1; 78551363Seric mxhosts[0] = spec + 1; 78651362Seric } 78751362Seric 78851362Seric for (i = 0; i < nmx; i++) 78951362Seric { 79068693Seric h = sm_gethostbyname(mxhosts[i]); 79151362Seric if (h == NULL) 79251362Seric continue; 79351362Seric up->udb_type = UDB_REMOTE; 79451362Seric up->udb_addr.sin_family = h->h_addrtype; 79551362Seric bcopy(h->h_addr_list[0], 79651362Seric (char *) &up->udb_addr.sin_addr, 79767421Seric INADDRSZ); 79851362Seric up->udb_addr.sin_port = UdbPort; 79951362Seric up->udb_timeout = UdbTimeout; 80051362Seric up++; 80151362Seric } 80251362Seric 80351362Seric /* set up a datagram socket */ 80451362Seric if (UdbSock < 0) 80551362Seric { 80651362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 80751362Seric (void) fcntl(UdbSock, F_SETFD, 1); 80851362Seric } 80951362Seric break; 810*68786Seric #endif 81151362Seric 81251362Seric case '@': /* forward to remote host */ 81351362Seric up->udb_type = UDB_FORWARD; 81451362Seric up->udb_fwdhost = spec + 1; 81551362Seric up++; 81651362Seric break; 81751362Seric 818*68786Seric #ifdef HESIOD 81966759Seric case 'h': /* use hesiod */ 82066759Seric case 'H': 82166759Seric if (strcasecmp(spec, "hesiod") != 0) 822*68786Seric goto badspec; 82366759Seric up->udb_type = UDB_HESIOD; 82466759Seric up++; 825*68786Seric break; 82666759Seric #endif /* HESIOD */ 82766759Seric 828*68786Seric #ifdef NEWDB 82951362Seric case '/': /* look up remote name */ 83051831Seric up->udb_dbname = spec; 83151923Seric errno = 0; 83251362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 83351362Seric if (up->udb_dbp == NULL) 83451923Seric { 83567763Seric if (tTd(28, 1)) 83667763Seric { 83767763Seric int saveerrno = errno; 83867763Seric 83967763Seric printf("dbopen(%s): %s", 84067763Seric spec, errstring(errno)); 84167763Seric errno = saveerrno; 84267763Seric } 84351923Seric if (errno != ENOENT && errno != EACCES) 84451951Seric { 84559615Seric #ifdef LOG 84659615Seric if (LogLevel > 2) 84759625Seric syslog(LOG_ERR, "dbopen(%s): %s", 84859625Seric spec, errstring(errno)); 84959615Seric #endif 85051951Seric up->udb_type = UDB_EOLIST; 85151951Seric goto tempfail; 85251951Seric } 85351362Seric break; 85451923Seric } 85551951Seric up->udb_type = UDB_DBFETCH; 85651362Seric up++; 85751362Seric break; 858*68786Seric #endif 859*68786Seric 860*68786Seric default: 861*68786Seric badspec: 862*68786Seric syserr("Unknown UDB spec %s", spec); 863*68786Seric break; 86451360Seric } 86551362Seric } 86651362Seric up->udb_type = UDB_EOLIST; 86751360Seric 86851362Seric if (tTd(28, 4)) 86951362Seric { 87051951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 87151360Seric { 87251362Seric switch (up->udb_type) 87351362Seric { 87451362Seric case UDB_REMOTE: 87551362Seric printf("REMOTE: addr %s, timeo %d\n", 87660494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 87751362Seric up->udb_timeout); 87851362Seric break; 87951362Seric 88051951Seric case UDB_DBFETCH: 88151951Seric printf("FETCH: file %s\n", 88251830Seric up->udb_dbname); 88351362Seric break; 88451362Seric 88551362Seric case UDB_FORWARD: 88651362Seric printf("FORWARD: host %s\n", 88751362Seric up->udb_fwdhost); 88851362Seric break; 88951362Seric 89066759Seric case UDB_HESIOD: 89166759Seric printf("HESIOD\n"); 89266759Seric break; 89366759Seric 89451362Seric default: 89551362Seric printf("UNKNOWN\n"); 89651362Seric break; 89751362Seric } 89851360Seric } 89950581Seric } 90051951Seric 90151951Seric UdbInitialized = TRUE; 90251955Seric errno = 0; 90351951Seric return EX_OK; 90451951Seric 90551951Seric /* 90651951Seric ** On temporary failure, back out anything we've already done 90751951Seric */ 90851951Seric 90951951Seric tempfail: 910*68786Seric #ifdef NEWDB 91151951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 91251951Seric { 91351951Seric if (up->udb_type == UDB_DBFETCH) 91451951Seric { 91551951Seric (*up->udb_dbp->close)(up->udb_dbp); 91651951Seric } 91751951Seric } 918*68786Seric #endif 91951951Seric return EX_TEMPFAIL; 92051360Seric } 92150581Seric 92251363Seric int 92351363Seric _udb_parsespec(udbspec, opt, maxopts) 92451363Seric char *udbspec; 92551363Seric struct option opt[]; 92651363Seric int maxopts; 92751363Seric { 92851363Seric register char *spec; 92951363Seric register char *spec_end; 93051363Seric register int optnum; 93151363Seric 93256795Seric spec_end = strchr(udbspec, ':'); 93351363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 93451363Seric { 93551363Seric register char *p; 93651363Seric 93758050Seric while (isascii(*spec) && isspace(*spec)) 93851363Seric spec++; 93956795Seric spec_end = strchr(spec, ':'); 94051363Seric if (spec_end != NULL) 94151363Seric *spec_end++ = '\0'; 94251363Seric 94351363Seric opt[optnum].name = spec; 94451363Seric opt[optnum].val = NULL; 94556795Seric p = strchr(spec, '='); 94651363Seric if (p != NULL) 94751363Seric opt[optnum].val = ++p; 94851363Seric } 94951363Seric return optnum; 95051363Seric } 95151363Seric 95266759Seric #ifdef HESIOD 95366759Seric 95466759Seric int 95566759Seric hes_udb_get(key, info) 95666759Seric DBT *key; 95766759Seric DBT *info; 95866759Seric { 95966759Seric char *name, *type; 96066759Seric char *p, **hp; 96168533Seric char kbuf[MAXKEY + 1]; 96266759Seric 96368533Seric strcpy(kbuf, key->data); 96468533Seric name = kbuf; 96566759Seric type = strchr(name, ':'); 96668544Seric if (type == NULL) 96766759Seric return 1; 96866759Seric *type++ = '\0'; 96966759Seric 97066759Seric if (tTd(28, 1)) 97166759Seric printf("hes_udb_get(%s, %s)\n", name, type); 97266759Seric 97366759Seric /* make the hesiod query */ 97466759Seric hp = hes_resolve(name, type); 97566759Seric if (hp == NULL) 97666759Seric { 97766759Seric /* network problem or timeout */ 97866759Seric if (hes_error() == HES_ER_NET) 97966759Seric return -1; 98066759Seric 98166759Seric return 1; 98266759Seric } 98366759Seric else 98466759Seric { 98566759Seric /* 98666759Seric ** If there are multiple matches, just return the 98766759Seric ** first one and free the others. 98866759Seric ** 98966759Seric ** XXX These should really be returned; for example, 99066759Seric ** XXX it is legal for :maildrop to be multi-valued. 99166759Seric */ 99266759Seric 99366759Seric for (p = hp[1]; p; p++) 99466759Seric free(p); 99566759Seric 99666759Seric info->data = hp[0]; 99766759Seric info->size = (size_t) strlen(info->data); 99866759Seric } 99966759Seric 100066759Seric return 0; 100166759Seric } 100266759Seric #endif /* HESIOD */ 100366759Seric 100451360Seric #else /* not USERDB */ 100551360Seric 100651923Seric int 100767982Seric udbexpand(a, sendq, aliaslevel, e) 100851360Seric ADDRESS *a; 100951360Seric ADDRESS **sendq; 101067982Seric int aliaslevel; 101155012Seric ENVELOPE *e; 101251360Seric { 101351923Seric return EX_OK; 101450581Seric } 101550581Seric 101650581Seric #endif /* USERDB */ 1017