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*67982Seric static char sccsid [] = "@(#)udb.c 8.12 (Berkeley) 11/22/94 (with USERDB)"; 1451360Seric #else 15*67982Seric static char sccsid [] = "@(#)udb.c 8.12 (Berkeley) 11/22/94 (without USERDB)"; 1650581Seric #endif 1751360Seric #endif 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2151923Seric #include <errno.h> 2251360Seric #include <netdb.h> 2350581Seric #include <db.h> 2450581Seric 2566759Seric #ifdef HESIOD 2666759Seric #include <hesiod.h> 2766759Seric #endif /* HESIOD */ 2866759Seric 2950581Seric /* 3053654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 3150581Seric ** 3251363Seric ** This depends on the 4.4BSD db package. 3350581Seric */ 3450581Seric 3551362Seric 3651360Seric struct udbent 3751360Seric { 3851360Seric char *udb_spec; /* string version of spec */ 3951360Seric int udb_type; /* type of entry */ 4051951Seric char *udb_default; /* default host for outgoing mail */ 4151360Seric union 4251360Seric { 4351360Seric /* type UE_REMOTE -- do remote call for lookup */ 4451360Seric struct 4551360Seric { 4651360Seric struct sockaddr_in _udb_addr; /* address */ 4751360Seric int _udb_timeout; /* timeout */ 4851360Seric } udb_remote; 4951360Seric #define udb_addr udb_u.udb_remote._udb_addr 5051360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 5151360Seric 5251360Seric /* type UE_FORWARD -- forward message to remote */ 5351360Seric struct 5451360Seric { 5551360Seric char *_udb_fwdhost; /* name of forward host */ 5651360Seric } udb_forward; 5751360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 5851360Seric 5951951Seric /* type UE_FETCH -- lookup in local database */ 6051360Seric struct 6151360Seric { 6251360Seric char *_udb_dbname; /* pathname of database */ 6351360Seric DB *_udb_dbp; /* open database ptr */ 6451360Seric } udb_lookup; 6551360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 6651360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 6751360Seric } udb_u; 6851360Seric }; 6951360Seric 7051360Seric #define UDB_EOLIST 0 /* end of list */ 7151360Seric #define UDB_SKIP 1 /* skip this entry */ 7251360Seric #define UDB_REMOTE 2 /* look up in remote database */ 7351951Seric #define UDB_DBFETCH 3 /* look up in local database */ 7451360Seric #define UDB_FORWARD 4 /* forward to remote host */ 7566759Seric #define UDB_HESIOD 5 /* look up via hesiod */ 7651360Seric 7751360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 7851360Seric 7951363Seric 8051363Seric struct option 8151363Seric { 8251363Seric char *name; 8351363Seric char *val; 8451363Seric }; 8551363Seric /* 8651363Seric ** UDBEXPAND -- look up user in database and expand 8751363Seric ** 8851363Seric ** Parameters: 8951363Seric ** a -- address to expand. 9051363Seric ** sendq -- pointer to head of sendq to put the expansions in. 91*67982Seric ** aliaslevel -- the current alias nesting depth. 92*67982Seric ** e -- the current envelope. 9351363Seric ** 9451363Seric ** Returns: 9551923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 9651923Seric ** to accessing a file on an NFS server that is down. 9751923Seric ** EX_OK -- otherwise. 9851363Seric ** 9951363Seric ** Side Effects: 10051363Seric ** Modifies sendq. 10151363Seric */ 10251363Seric 10351363Seric int UdbPort = 1616; 10451363Seric int UdbTimeout = 10; 10551363Seric 10651953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10751953Seric int UdbSock = -1; 10851953Seric bool UdbInitialized = FALSE; 10951360Seric 11051923Seric int 111*67982Seric udbexpand(a, sendq, aliaslevel, e) 11250581Seric register ADDRESS *a; 11350581Seric ADDRESS **sendq; 114*67982Seric int aliaslevel; 11555012Seric register ENVELOPE *e; 11650581Seric { 11750581Seric int i; 11850581Seric register char *p; 11950581Seric DBT key; 12050581Seric DBT info; 12151360Seric bool breakout; 12251360Seric register struct udbent *up; 12351362Seric int keylen; 12458082Seric int naddrs; 12557232Seric char keybuf[MAXKEY]; 12657232Seric char buf[BUFSIZ]; 12750581Seric 12850581Seric if (tTd(28, 1)) 12958065Seric printf("udbexpand(%s)\n", a->q_paddr); 13050581Seric 13150581Seric /* make certain we are supposed to send to this address */ 13258154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 13351923Seric return EX_OK; 13455012Seric e->e_to = a->q_paddr; 13550581Seric 13651360Seric /* on first call, locate the database */ 13751951Seric if (!UdbInitialized) 13850581Seric { 13951923Seric extern int _udbx_init(); 14051362Seric 14151923Seric if (_udbx_init() == EX_TEMPFAIL) 14251923Seric return EX_TEMPFAIL; 14351362Seric } 14450581Seric 14551909Seric /* short circuit the process if no chance of a match */ 14651909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 14751923Seric return EX_OK; 14851909Seric 14966759Seric /* short circuit name begins with '\\' since it can't possibly match */ 15066759Seric if (a->q_user[0] == '\\') 15166759Seric return EX_OK; 15266759Seric 15351362Seric /* if name is too long, assume it won't match */ 15451362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 15551923Seric return EX_OK; 15651360Seric 15751362Seric /* if name begins with a colon, it indicates our metadata */ 15851362Seric if (a->q_user[0] == ':') 15951923Seric return EX_OK; 16051360Seric 16151362Seric /* build actual database key */ 16251362Seric (void) strcpy(keybuf, a->q_user); 16351362Seric (void) strcat(keybuf, ":maildrop"); 16451362Seric keylen = strlen(keybuf); 16551360Seric 16651360Seric breakout = FALSE; 16751362Seric for (up = UdbEnts; !breakout; up++) 16850581Seric { 16951360Seric char *user; 17050581Seric 17151360Seric /* 17251360Seric ** Select action based on entry type. 17351360Seric ** 17451360Seric ** On dropping out of this switch, "class" should 17551360Seric ** explain the type of the data, and "user" should 17651360Seric ** contain the user information. 17751360Seric */ 17850581Seric 17951360Seric switch (up->udb_type) 18051360Seric { 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 225*67982Seric 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 e->e_flags |= EF_SENDRECEIPT; 27866784Seric } 27951360Seric break; 28051360Seric 28166759Seric #ifdef HESIOD 28266759Seric case UDB_HESIOD: 28366759Seric key.data = keybuf; 28466759Seric key.size = keylen; 28566759Seric if (tTd(28, 80)) 28666759Seric printf("udbexpand: trying %s (%d) via hesiod\n", 28766759Seric keybuf, keylen); 28866759Seric /* look up the key via hesiod */ 28966759Seric i = hes_udb_get(&key, &info); 29066759Seric if (i > 0 || info.size <= 0) 29166759Seric { 29266759Seric if (tTd(28, 2)) 29366759Seric printf("udbexpand: no match on %s (%d)\n", 29466759Seric keybuf, keylen); 29566759Seric continue; 29666759Seric } 29766759Seric if (tTd(28, 80)) 29866759Seric printf("udbexpand: match %.*s: %.*s\n", 29966759Seric key.size, key.data, info.size, info.data); 30066759Seric a->q_flags &= ~QSELFREF; 30166759Seric 30266759Seric if (bitset(EF_VRFYONLY, e->e_flags)) 30366759Seric { 30466759Seric a->q_flags |= QVERIFIED; 30566759Seric e->e_nrcpts++; 30666759Seric free(info.data); 30766759Seric return EX_OK; 30866759Seric } 30966759Seric 31066759Seric breakout = TRUE; 31166759Seric if (info.size < sizeof buf) 31266759Seric user = buf; 31366759Seric else 31466759Seric user = xalloc(info.size + 1); 31566759Seric bcopy(info.data, user, info.size); 31666759Seric user[info.size] = '\0'; 31766759Seric free(info.data); 31866759Seric 31966759Seric message("hesioded to %s", user); 32066759Seric #ifdef LOG 32166759Seric if (LogLevel >= 10) 32266759Seric syslog(LOG_INFO, "%s: hesiod %s => %s", 32366759Seric e->e_id, e->e_to, user); 32466759Seric #endif 325*67982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 32666759Seric 32766759Seric if (user != buf) 32866759Seric free(user); 32966759Seric 33066759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 33166759Seric { 33266759Seric if (tTd(28, 5)) 33366759Seric { 33466759Seric printf("udbexpand: QDONTSEND "); 33566759Seric printaddr(a, FALSE); 33666759Seric } 33766759Seric a->q_flags |= QDONTSEND; 33866759Seric } 33966759Seric if (i < 0) 34066759Seric { 34166759Seric syserr("udbexpand: hesiod-get %.*s stat %d", 34266759Seric key.size, key.data, i); 34366759Seric return EX_TEMPFAIL; 34466759Seric } 34566759Seric 34666759Seric /* 34766759Seric ** If this address has a -request address, reflect 34866759Seric ** it into the envelope. 34966759Seric */ 35066759Seric 35166759Seric (void) strcpy(keybuf, a->q_user); 35266759Seric (void) strcat(keybuf, ":mailsender"); 35366759Seric keylen = strlen(keybuf); 35466759Seric key.data = keybuf; 35566759Seric key.size = keylen; 35666759Seric i = hes_udb_get(&key, &info); 35766759Seric if (i != 0 || info.size <= 0) 35866759Seric break; 35966759Seric a->q_owner = xalloc(info.size + 1); 36066759Seric bcopy(info.data, a->q_owner, info.size); 36166759Seric a->q_owner[info.size] = '\0'; 36266759Seric free(info.data); 36366759Seric break; 36466759Seric #endif /* HESIOD */ 36566759Seric 36651360Seric case UDB_REMOTE: 36751741Seric /* not yet implemented */ 36851741Seric continue; 36951362Seric 37051360Seric case UDB_FORWARD: 37158099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 37258099Seric return EX_OK; 37351360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 37451360Seric if (i < sizeof buf) 37551360Seric user = buf; 37651360Seric else 37751360Seric user = xalloc(i + 1); 37851360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 37958151Seric message("expanded to %s", user); 38058082Seric a->q_flags &= ~QSELFREF; 381*67982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 38258082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 38358065Seric { 38458065Seric if (tTd(28, 5)) 38558065Seric { 38658065Seric printf("udbexpand: QDONTSEND "); 38758065Seric printaddr(a, FALSE); 38858065Seric } 38958065Seric a->q_flags |= QDONTSEND; 39058065Seric } 39151362Seric if (user != buf) 39251362Seric free(user); 39351362Seric breakout = TRUE; 39451360Seric break; 39551360Seric 39651360Seric case UDB_EOLIST: 39751360Seric breakout = TRUE; 39851360Seric continue; 39951360Seric 40051360Seric default: 40151360Seric /* unknown entry type */ 40251360Seric continue; 40351360Seric } 40451362Seric } 40551923Seric return EX_OK; 40651362Seric } 40751951Seric /* 40851951Seric ** UDBSENDER -- return canonical external name of sender, given local name 40951951Seric ** 41051951Seric ** Parameters: 41151951Seric ** sender -- the name of the sender on the local machine. 41251951Seric ** 41351951Seric ** Returns: 41451951Seric ** The external name for this sender, if derivable from the 41551951Seric ** database. 41651951Seric ** NULL -- if nothing is changed from the database. 41751951Seric ** 41851951Seric ** Side Effects: 41951951Seric ** none. 42051951Seric */ 42151360Seric 42251951Seric char * 42351951Seric udbsender(sender) 42451951Seric char *sender; 42551951Seric { 42664350Seric extern char *udbmatch(); 42764350Seric 42864350Seric return udbmatch(sender, "mailname"); 42964350Seric } 43064350Seric 43164350Seric 43264350Seric char * 43364350Seric udbmatch(user, field) 43464350Seric char *user; 43564350Seric char *field; 43664350Seric { 43751951Seric register char *p; 43851951Seric register struct udbent *up; 43951951Seric int i; 44051951Seric int keylen; 44151951Seric DBT key, info; 44257232Seric char keybuf[MAXKEY]; 44351951Seric 44451951Seric if (tTd(28, 1)) 44564350Seric printf("udbmatch(%s, %s)\n", user, field); 44651951Seric 44751951Seric if (!UdbInitialized) 44851951Seric { 44951951Seric if (_udbx_init() == EX_TEMPFAIL) 45051951Seric return NULL; 45151951Seric } 45251951Seric 45351951Seric /* short circuit if no spec */ 45451951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 45551951Seric return NULL; 45651951Seric 45766759Seric /* short circuit name begins with '\\' since it can't possibly match */ 45866759Seric if (user[0] == '\\') 45966759Seric return NULL; 46066759Seric 46151951Seric /* long names can never match and are a pain to deal with */ 46264350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 46351951Seric return NULL; 46451951Seric 46551951Seric /* names beginning with colons indicate metadata */ 46664350Seric if (user[0] == ':') 46751951Seric return NULL; 46851951Seric 46951951Seric /* build database key */ 47064350Seric (void) strcpy(keybuf, user); 47164350Seric (void) strcat(keybuf, ":"); 47264350Seric (void) strcat(keybuf, field); 47351951Seric keylen = strlen(keybuf); 47451951Seric 47551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 47651951Seric { 47751951Seric /* 47851951Seric ** Select action based on entry type. 47951951Seric */ 48051951Seric 48151951Seric switch (up->udb_type) 48251951Seric { 48351951Seric case UDB_DBFETCH: 48451951Seric key.data = keybuf; 48551951Seric key.size = keylen; 48651951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 48751951Seric if (i != 0 || info.size <= 0) 48851951Seric { 48951951Seric if (tTd(28, 2)) 49066759Seric printf("udbmatch: no match on %s (%d) via db\n", 49164067Seric keybuf, keylen); 49251951Seric continue; 49351951Seric } 49451951Seric 49551951Seric p = xalloc(info.size + 1); 49651951Seric bcopy(info.data, p, info.size); 49751951Seric p[info.size] = '\0'; 49851951Seric if (tTd(28, 1)) 49964350Seric printf("udbmatch ==> %s\n", p); 50051951Seric return p; 50166759Seric break; 50266759Seric 50366759Seric #ifdef HESIOD 50466759Seric case UDB_HESIOD: 50566759Seric key.data = keybuf; 50666759Seric key.size = keylen; 50766759Seric i = hes_udb_get(&key, &info); 50866759Seric if (i != 0 || info.size <= 0) 50966759Seric { 51066759Seric if (tTd(28, 2)) 51166759Seric printf("udbmatch: no match on %s (%d) via hesiod\n", 51266759Seric keybuf, keylen); 51366759Seric continue; 51466759Seric } 51566759Seric 51666759Seric p = xalloc(info.size + 1); 51766759Seric bcopy(info.data, p, info.size); 51866759Seric p[info.size] = '\0'; 51966759Seric free(info.data); 52066759Seric if (tTd(28, 1)) 52166759Seric printf("udbmatch ==> %s\n", p); 52266759Seric return p; 52366759Seric break; 52466759Seric #endif /* HESIOD */ 52551951Seric } 52651951Seric } 52751951Seric 52864350Seric if (strcmp(field, "mailname") != 0) 52964350Seric return NULL; 53064350Seric 53151951Seric /* 53251951Seric ** Nothing yet. Search again for a default case. But only 53351951Seric ** use it if we also have a forward (:maildrop) pointer already 53451951Seric ** in the database. 53551951Seric */ 53651951Seric 53751951Seric /* build database key */ 53864350Seric (void) strcpy(keybuf, user); 53951951Seric (void) strcat(keybuf, ":maildrop"); 54051951Seric keylen = strlen(keybuf); 54151951Seric 54251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 54351951Seric { 54451951Seric switch (up->udb_type) 54551951Seric { 54651951Seric case UDB_DBFETCH: 54751951Seric /* get the default case for this database */ 54851951Seric if (up->udb_default == NULL) 54951951Seric { 55051951Seric key.data = ":default:mailname"; 55151951Seric key.size = strlen(key.data); 55251951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 55351951Seric if (i != 0 || info.size <= 0) 55451951Seric { 55551951Seric /* no default case */ 55651951Seric up->udb_default = ""; 55751951Seric continue; 55851951Seric } 55951951Seric 56051951Seric /* save the default case */ 56151951Seric up->udb_default = xalloc(info.size + 1); 56251951Seric bcopy(info.data, up->udb_default, info.size); 56351951Seric up->udb_default[info.size] = '\0'; 56451951Seric } 56551951Seric else if (up->udb_default[0] == '\0') 56651951Seric continue; 56751951Seric 56851951Seric /* we have a default case -- verify user:maildrop */ 56951951Seric key.data = keybuf; 57051951Seric key.size = keylen; 57151951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 57251951Seric if (i != 0 || info.size <= 0) 57351951Seric { 57451951Seric /* nope -- no aliasing for this user */ 57551951Seric continue; 57651951Seric } 57751951Seric 57851951Seric /* they exist -- build the actual address */ 57964350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 58064350Seric (void) strcpy(p, user); 58151951Seric (void) strcat(p, "@"); 58251951Seric (void) strcat(p, up->udb_default); 58351951Seric if (tTd(28, 1)) 58464350Seric printf("udbmatch ==> %s\n", p); 58551951Seric return p; 58666759Seric break; 58766759Seric 58866759Seric #ifdef HESIOD 58966759Seric case UDB_HESIOD: 59066759Seric /* get the default case for this database */ 59166759Seric if (up->udb_default == NULL) 59266759Seric { 59366759Seric key.data = ":default:mailname"; 59466759Seric key.size = strlen(key.data); 59566759Seric i = hes_udb_get(&key, &info); 59666759Seric 59766759Seric if (i != 0 || info.size <= 0) 59866759Seric { 59966759Seric /* no default case */ 60066759Seric up->udb_default = ""; 60166759Seric continue; 60266759Seric } 60366759Seric 60466759Seric /* save the default case */ 60566759Seric up->udb_default = xalloc(info.size + 1); 60666759Seric bcopy(info.data, up->udb_default, info.size); 60766759Seric up->udb_default[info.size] = '\0'; 60866759Seric free(info.data); 60966759Seric } 61066759Seric else if (up->udb_default[0] == '\0') 61166759Seric continue; 61266759Seric 61366759Seric /* we have a default case -- verify user:maildrop */ 61466759Seric key.data = keybuf; 61566759Seric key.size = keylen; 61666759Seric i = hes_udb_get(&key, &info); 61766759Seric if (i != 0 || info.size <= 0) 61866759Seric { 61966759Seric /* nope -- no aliasing for this user */ 62066759Seric continue; 62166759Seric } 62266759Seric 62366759Seric free(info.data); 62466759Seric /* they exist -- build the actual address */ 62566759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 62666759Seric (void) strcpy(p, user); 62766759Seric (void) strcat(p, "@"); 62866759Seric (void) strcat(p, up->udb_default); 62966759Seric if (tTd(28, 1)) 63066759Seric printf("udbmatch ==> %s\n", p); 63166759Seric return p; 63266759Seric break; 63366759Seric #endif /* HESIOD */ 63451951Seric } 63551951Seric } 63651951Seric 63751951Seric /* still nothing.... too bad */ 63851951Seric return NULL; 63951951Seric } 64051951Seric /* 64151951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 64251951Seric ** 64351951Seric ** Parameters: 64451951Seric ** none. 64551951Seric ** 64651951Seric ** Returns: 64751951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 64851951Seric ** database due to a host being down or some similar 64951951Seric ** (recoverable) situation. 65051951Seric ** EX_OK -- otherwise. 65151951Seric ** 65251951Seric ** Side Effects: 65351951Seric ** Fills in the UdbEnts structure from UdbSpec. 65451951Seric */ 65551951Seric 65651363Seric #define MAXUDBOPTS 27 65751363Seric 65851953Seric int 65951362Seric _udbx_init() 66051362Seric { 66151362Seric register char *p; 66251362Seric int i; 66351362Seric register struct udbent *up; 66457232Seric char buf[BUFSIZ]; 66551360Seric 66651951Seric if (UdbInitialized) 66751951Seric return EX_OK; 66851951Seric 66951908Seric # ifdef UDB_DEFAULT_SPEC 67051908Seric if (UdbSpec == NULL) 67151908Seric UdbSpec = UDB_DEFAULT_SPEC; 67251908Seric # endif 67351908Seric 67451362Seric p = UdbSpec; 67551362Seric up = UdbEnts; 67651762Seric while (p != NULL) 67751362Seric { 67851362Seric char *spec; 67951362Seric auto int rcode; 68051363Seric int nopts; 68151362Seric int nmx; 68251362Seric register struct hostent *h; 68351362Seric char *mxhosts[MAXMXHOSTS + 1]; 68451363Seric struct option opts[MAXUDBOPTS + 1]; 68551362Seric 68651362Seric while (*p == ' ' || *p == '\t' || *p == ',') 68751362Seric p++; 68851362Seric if (*p == '\0') 68951362Seric break; 69051362Seric spec = p; 69156795Seric p = strchr(p, ','); 69251761Seric if (p != NULL) 69351362Seric *p++ = '\0'; 69451363Seric 69551363Seric /* extract options */ 69651363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 69751363Seric 69851363Seric /* 69951363Seric ** Decode database specification. 70051363Seric ** 70151363Seric ** In the sendmail tradition, the leading character 70251363Seric ** defines the semantics of the rest of the entry. 70351363Seric ** 70451363Seric ** +hostname -- send a datagram to the udb server 70551363Seric ** on host "hostname" asking for the 70651363Seric ** home mail server for this user. 70751363Seric ** *hostname -- similar to +hostname, except that the 70851363Seric ** hostname is searched as an MX record; 70951363Seric ** resulting hosts are searched as for 71051363Seric ** +mxhostname. If no MX host is found, 71151363Seric ** this is the same as +hostname. 71251363Seric ** @hostname -- forward email to the indicated host. 71351363Seric ** This should be the last in the list, 71451363Seric ** since it always matches the input. 71551363Seric ** /dbname -- search the named database on the local 71651363Seric ** host using the Berkeley db package. 71751363Seric */ 71851363Seric 71951362Seric switch (*spec) 72051360Seric { 72151362Seric case '+': /* search remote database */ 72251363Seric case '*': /* search remote database (expand MX) */ 72351363Seric if (*spec == '*') 72451363Seric { 72566334Seric #if NAMED_BIND 72659273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 72757629Seric #else 72857629Seric mxhosts[0] = spec + 1; 72957629Seric nmx = 1; 73057629Seric rcode = 0; 73157629Seric #endif 73251363Seric if (tTd(28, 16)) 73351363Seric { 73451363Seric int i; 73551362Seric 73651363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 73751363Seric for (i = 0; i <= nmx; i++) 73851363Seric printf(" %s", mxhosts[i]); 73951363Seric printf("\n"); 74051363Seric } 74151363Seric } 74251363Seric else 74351362Seric { 74451363Seric nmx = 1; 74551363Seric mxhosts[0] = spec + 1; 74651362Seric } 74751362Seric 74851362Seric for (i = 0; i < nmx; i++) 74951362Seric { 75051362Seric h = gethostbyname(mxhosts[i]); 75151362Seric if (h == NULL) 75251362Seric continue; 75351362Seric up->udb_type = UDB_REMOTE; 75451362Seric up->udb_addr.sin_family = h->h_addrtype; 75551362Seric bcopy(h->h_addr_list[0], 75651362Seric (char *) &up->udb_addr.sin_addr, 75767421Seric INADDRSZ); 75851362Seric up->udb_addr.sin_port = UdbPort; 75951362Seric up->udb_timeout = UdbTimeout; 76051362Seric up++; 76151362Seric } 76251362Seric 76351362Seric /* set up a datagram socket */ 76451362Seric if (UdbSock < 0) 76551362Seric { 76651362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 76751362Seric (void) fcntl(UdbSock, F_SETFD, 1); 76851362Seric } 76951362Seric break; 77051362Seric 77151362Seric case '@': /* forward to remote host */ 77251362Seric up->udb_type = UDB_FORWARD; 77351362Seric up->udb_fwdhost = spec + 1; 77451362Seric up++; 77551362Seric break; 77651362Seric 77766759Seric case 'h': /* use hesiod */ 77866759Seric case 'H': 77966759Seric #ifdef HESIOD 78066759Seric if (strcasecmp(spec, "hesiod") != 0) 78166759Seric break; 78266759Seric up->udb_type = UDB_HESIOD; 78366759Seric up++; 78466759Seric #endif /* HESIOD */ 78566759Seric break; 78666759Seric 78751362Seric case '/': /* look up remote name */ 78851831Seric up->udb_dbname = spec; 78951923Seric errno = 0; 79051362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 79151362Seric if (up->udb_dbp == NULL) 79251923Seric { 79367763Seric if (tTd(28, 1)) 79467763Seric { 79567763Seric int saveerrno = errno; 79667763Seric 79767763Seric printf("dbopen(%s): %s", 79867763Seric spec, errstring(errno)); 79967763Seric errno = saveerrno; 80067763Seric } 80151923Seric if (errno != ENOENT && errno != EACCES) 80251951Seric { 80359615Seric #ifdef LOG 80459615Seric if (LogLevel > 2) 80559625Seric syslog(LOG_ERR, "dbopen(%s): %s", 80659625Seric spec, errstring(errno)); 80759615Seric #endif 80851951Seric up->udb_type = UDB_EOLIST; 80951951Seric goto tempfail; 81051951Seric } 81151362Seric break; 81251923Seric } 81351951Seric up->udb_type = UDB_DBFETCH; 81451362Seric up++; 81551362Seric break; 81651360Seric } 81751362Seric } 81851362Seric up->udb_type = UDB_EOLIST; 81951360Seric 82051362Seric if (tTd(28, 4)) 82151362Seric { 82251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 82351360Seric { 82451362Seric switch (up->udb_type) 82551362Seric { 82651362Seric case UDB_REMOTE: 82751362Seric printf("REMOTE: addr %s, timeo %d\n", 82860494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 82951362Seric up->udb_timeout); 83051362Seric break; 83151362Seric 83251951Seric case UDB_DBFETCH: 83351951Seric printf("FETCH: file %s\n", 83451830Seric up->udb_dbname); 83551362Seric break; 83651362Seric 83751362Seric case UDB_FORWARD: 83851362Seric printf("FORWARD: host %s\n", 83951362Seric up->udb_fwdhost); 84051362Seric break; 84151362Seric 84266759Seric case UDB_HESIOD: 84366759Seric printf("HESIOD\n"); 84466759Seric break; 84566759Seric 84651362Seric default: 84751362Seric printf("UNKNOWN\n"); 84851362Seric break; 84951362Seric } 85051360Seric } 85150581Seric } 85251951Seric 85351951Seric UdbInitialized = TRUE; 85451955Seric errno = 0; 85551951Seric return EX_OK; 85651951Seric 85751951Seric /* 85851951Seric ** On temporary failure, back out anything we've already done 85951951Seric */ 86051951Seric 86151951Seric tempfail: 86251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 86351951Seric { 86451951Seric if (up->udb_type == UDB_DBFETCH) 86551951Seric { 86651951Seric (*up->udb_dbp->close)(up->udb_dbp); 86751951Seric } 86851951Seric } 86951951Seric return EX_TEMPFAIL; 87051360Seric } 87150581Seric 87251363Seric int 87351363Seric _udb_parsespec(udbspec, opt, maxopts) 87451363Seric char *udbspec; 87551363Seric struct option opt[]; 87651363Seric int maxopts; 87751363Seric { 87851363Seric register char *spec; 87951363Seric register char *spec_end; 88051363Seric register int optnum; 88151363Seric 88256795Seric spec_end = strchr(udbspec, ':'); 88351363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 88451363Seric { 88551363Seric register char *p; 88651363Seric 88758050Seric while (isascii(*spec) && isspace(*spec)) 88851363Seric spec++; 88956795Seric spec_end = strchr(spec, ':'); 89051363Seric if (spec_end != NULL) 89151363Seric *spec_end++ = '\0'; 89251363Seric 89351363Seric opt[optnum].name = spec; 89451363Seric opt[optnum].val = NULL; 89556795Seric p = strchr(spec, '='); 89651363Seric if (p != NULL) 89751363Seric opt[optnum].val = ++p; 89851363Seric } 89951363Seric return optnum; 90051363Seric } 90151363Seric 90266759Seric #ifdef HESIOD 90366759Seric 90466759Seric int 90566759Seric hes_udb_get(key, info) 90666759Seric DBT *key; 90766759Seric DBT *info; 90866759Seric { 90966759Seric char *name, *type; 91066759Seric char *p, **hp; 91166759Seric 91266759Seric name = key->data; 91366759Seric type = strchr(name, ':'); 91466759Seric if (type == NULL) 91566759Seric return 1; 91666759Seric 91766759Seric *type++ = '\0'; 91866759Seric 91966759Seric if (tTd(28, 1)) 92066759Seric printf("hes_udb_get(%s, %s)\n", name, type); 92166759Seric 92266759Seric /* make the hesiod query */ 92366759Seric hp = hes_resolve(name, type); 92466759Seric if (hp == NULL) 92566759Seric { 92666759Seric /* network problem or timeout */ 92766759Seric if (hes_error() == HES_ER_NET) 92866759Seric return -1; 92966759Seric 93066759Seric return 1; 93166759Seric } 93266759Seric else 93366759Seric { 93466759Seric /* 93566759Seric ** If there are multiple matches, just return the 93666759Seric ** first one and free the others. 93766759Seric ** 93866759Seric ** XXX These should really be returned; for example, 93966759Seric ** XXX it is legal for :maildrop to be multi-valued. 94066759Seric */ 94166759Seric 94266759Seric for (p = hp[1]; p; p++) 94366759Seric free(p); 94466759Seric 94566759Seric info->data = hp[0]; 94666759Seric info->size = (size_t) strlen(info->data); 94766759Seric } 94866759Seric 94966759Seric return 0; 95066759Seric } 95166759Seric #endif /* HESIOD */ 95266759Seric 95351360Seric #else /* not USERDB */ 95451360Seric 95551923Seric int 956*67982Seric udbexpand(a, sendq, aliaslevel, e) 95751360Seric ADDRESS *a; 95851360Seric ADDRESS **sendq; 959*67982Seric int aliaslevel; 96055012Seric ENVELOPE *e; 96151360Seric { 96251923Seric return EX_OK; 96350581Seric } 96450581Seric 96550581Seric #endif /* USERDB */ 966