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*67763Seric static char sccsid [] = "@(#)udb.c 8.11 (Berkeley) 09/08/94 (with USERDB)"; 1451360Seric #else 15*67763Seric static char sccsid [] = "@(#)udb.c 8.11 (Berkeley) 09/08/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. 9151363Seric ** 9251363Seric ** Returns: 9351923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 9451923Seric ** to accessing a file on an NFS server that is down. 9551923Seric ** EX_OK -- otherwise. 9651363Seric ** 9751363Seric ** Side Effects: 9851363Seric ** Modifies sendq. 9951363Seric */ 10051363Seric 10151363Seric int UdbPort = 1616; 10251363Seric int UdbTimeout = 10; 10351363Seric 10451953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10551953Seric int UdbSock = -1; 10651953Seric bool UdbInitialized = FALSE; 10751360Seric 10851923Seric int 10955012Seric udbexpand(a, sendq, e) 11050581Seric register ADDRESS *a; 11150581Seric ADDRESS **sendq; 11255012Seric register ENVELOPE *e; 11350581Seric { 11450581Seric int i; 11550581Seric register char *p; 11650581Seric DBT key; 11750581Seric DBT info; 11851360Seric bool breakout; 11951360Seric register struct udbent *up; 12051362Seric int keylen; 12158082Seric int naddrs; 12257232Seric char keybuf[MAXKEY]; 12357232Seric char buf[BUFSIZ]; 12450581Seric 12550581Seric if (tTd(28, 1)) 12658065Seric printf("udbexpand(%s)\n", a->q_paddr); 12750581Seric 12850581Seric /* make certain we are supposed to send to this address */ 12958154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 13051923Seric return EX_OK; 13155012Seric e->e_to = a->q_paddr; 13250581Seric 13351360Seric /* on first call, locate the database */ 13451951Seric if (!UdbInitialized) 13550581Seric { 13651923Seric extern int _udbx_init(); 13751362Seric 13851923Seric if (_udbx_init() == EX_TEMPFAIL) 13951923Seric return EX_TEMPFAIL; 14051362Seric } 14150581Seric 14251909Seric /* short circuit the process if no chance of a match */ 14351909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 14451923Seric return EX_OK; 14551909Seric 14666759Seric /* short circuit name begins with '\\' since it can't possibly match */ 14766759Seric if (a->q_user[0] == '\\') 14866759Seric return EX_OK; 14966759Seric 15051362Seric /* if name is too long, assume it won't match */ 15151362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 15251923Seric return EX_OK; 15351360Seric 15451362Seric /* if name begins with a colon, it indicates our metadata */ 15551362Seric if (a->q_user[0] == ':') 15651923Seric return EX_OK; 15751360Seric 15851362Seric /* build actual database key */ 15951362Seric (void) strcpy(keybuf, a->q_user); 16051362Seric (void) strcat(keybuf, ":maildrop"); 16151362Seric keylen = strlen(keybuf); 16251360Seric 16351360Seric breakout = FALSE; 16451362Seric for (up = UdbEnts; !breakout; up++) 16550581Seric { 16651360Seric char *user; 16750581Seric 16851360Seric /* 16951360Seric ** Select action based on entry type. 17051360Seric ** 17151360Seric ** On dropping out of this switch, "class" should 17251360Seric ** explain the type of the data, and "user" should 17351360Seric ** contain the user information. 17451360Seric */ 17550581Seric 17651360Seric switch (up->udb_type) 17751360Seric { 17851951Seric case UDB_DBFETCH: 17951362Seric key.data = keybuf; 18051362Seric key.size = keylen; 18160990Seric if (tTd(28, 80)) 18266759Seric printf("udbexpand: trying %s (%d) via db\n", 18364067Seric keybuf, keylen); 18451362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 18551923Seric if (i > 0 || info.size <= 0) 18651360Seric { 18751360Seric if (tTd(28, 2)) 18864067Seric printf("udbexpand: no match on %s (%d)\n", 18964067Seric keybuf, keylen); 19051360Seric continue; 19151360Seric } 19260990Seric if (tTd(28, 80)) 19360990Seric printf("udbexpand: match %.*s: %.*s\n", 19460990Seric key.size, key.data, info.size, info.data); 19550581Seric 19658082Seric naddrs = 0; 19758082Seric a->q_flags &= ~QSELFREF; 19851830Seric while (i == 0 && key.size == keylen && 19951830Seric bcmp(key.data, keybuf, keylen) == 0) 20051362Seric { 20158099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 20258154Seric { 20358154Seric a->q_flags |= QVERIFIED; 20458884Seric e->e_nrcpts++; 20558099Seric return EX_OK; 20658154Seric } 20758099Seric 20851830Seric breakout = TRUE; 20951362Seric if (info.size < sizeof buf) 21051362Seric user = buf; 21151362Seric else 21251362Seric user = xalloc(info.size + 1); 21351362Seric bcopy(info.data, user, info.size); 21451362Seric user[info.size] = '\0'; 21550581Seric 21658151Seric message("expanded to %s", user); 21757977Seric #ifdef LOG 21857977Seric if (LogLevel >= 10) 21957977Seric syslog(LOG_INFO, "%s: expand %s => %s", 22057977Seric e->e_id, e->e_to, user); 22157977Seric #endif 22251362Seric AliasLevel++; 22358082Seric naddrs += sendtolist(user, a, sendq, e); 22451362Seric AliasLevel--; 22551362Seric 22651362Seric if (user != buf) 22751362Seric free(user); 22851362Seric 22951362Seric /* get the next record */ 23051362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 23151830Seric } 23260990Seric 23360990Seric /* if nothing ever matched, try next database */ 23460990Seric if (!breakout) 23560990Seric continue; 23660990Seric 23758082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 23858065Seric { 23958065Seric if (tTd(28, 5)) 24058065Seric { 24158065Seric printf("udbexpand: QDONTSEND "); 24258065Seric printaddr(a, FALSE); 24358065Seric } 24458065Seric a->q_flags |= QDONTSEND; 24558065Seric } 24651923Seric if (i < 0) 24751923Seric { 24858010Seric syserr("udbexpand: db-get %.*s stat %d", 24958010Seric key.size, key.data, i); 25051923Seric return EX_TEMPFAIL; 25151923Seric } 25259707Seric 25359707Seric /* 25459707Seric ** If this address has a -request address, reflect 25559707Seric ** it into the envelope. 25659707Seric */ 25759707Seric 25859707Seric (void) strcpy(keybuf, a->q_user); 25959707Seric (void) strcat(keybuf, ":mailsender"); 26059707Seric keylen = strlen(keybuf); 26159707Seric key.data = keybuf; 26259707Seric key.size = keylen; 26359707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 26459707Seric if (i != 0 || info.size <= 0) 26559707Seric break; 26659707Seric a->q_owner = xalloc(info.size + 1); 26759707Seric bcopy(info.data, a->q_owner, info.size); 26859707Seric a->q_owner[info.size] = '\0'; 26966784Seric 27066784Seric /* announce delivery; NORECEIPT bit set later */ 27166784Seric if (e->e_xfp != NULL) 27266784Seric { 27366784Seric fprintf(e->e_xfp, 27466784Seric "Message delivered to mailing list %s\n", 27566784Seric a->q_paddr); 27666784Seric e->e_flags |= EF_SENDRECEIPT; 27766784Seric } 27851360Seric break; 27951360Seric 28066759Seric #ifdef HESIOD 28166759Seric case UDB_HESIOD: 28266759Seric key.data = keybuf; 28366759Seric key.size = keylen; 28466759Seric if (tTd(28, 80)) 28566759Seric printf("udbexpand: trying %s (%d) via hesiod\n", 28666759Seric keybuf, keylen); 28766759Seric /* look up the key via hesiod */ 28866759Seric i = hes_udb_get(&key, &info); 28966759Seric if (i > 0 || info.size <= 0) 29066759Seric { 29166759Seric if (tTd(28, 2)) 29266759Seric printf("udbexpand: no match on %s (%d)\n", 29366759Seric keybuf, keylen); 29466759Seric continue; 29566759Seric } 29666759Seric if (tTd(28, 80)) 29766759Seric printf("udbexpand: match %.*s: %.*s\n", 29866759Seric key.size, key.data, info.size, info.data); 29966759Seric a->q_flags &= ~QSELFREF; 30066759Seric 30166759Seric if (bitset(EF_VRFYONLY, e->e_flags)) 30266759Seric { 30366759Seric a->q_flags |= QVERIFIED; 30466759Seric e->e_nrcpts++; 30566759Seric free(info.data); 30666759Seric return EX_OK; 30766759Seric } 30866759Seric 30966759Seric breakout = TRUE; 31066759Seric if (info.size < sizeof buf) 31166759Seric user = buf; 31266759Seric else 31366759Seric user = xalloc(info.size + 1); 31466759Seric bcopy(info.data, user, info.size); 31566759Seric user[info.size] = '\0'; 31666759Seric free(info.data); 31766759Seric 31866759Seric message("hesioded to %s", user); 31966759Seric #ifdef LOG 32066759Seric if (LogLevel >= 10) 32166759Seric syslog(LOG_INFO, "%s: hesiod %s => %s", 32266759Seric e->e_id, e->e_to, user); 32366759Seric #endif 32466759Seric AliasLevel++; 32566759Seric naddrs = sendtolist(user, a, sendq, e); 32666759Seric AliasLevel--; 32766759Seric 32866759Seric if (user != buf) 32966759Seric free(user); 33066759Seric 33166759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 33266759Seric { 33366759Seric if (tTd(28, 5)) 33466759Seric { 33566759Seric printf("udbexpand: QDONTSEND "); 33666759Seric printaddr(a, FALSE); 33766759Seric } 33866759Seric a->q_flags |= QDONTSEND; 33966759Seric } 34066759Seric if (i < 0) 34166759Seric { 34266759Seric syserr("udbexpand: hesiod-get %.*s stat %d", 34366759Seric key.size, key.data, i); 34466759Seric return EX_TEMPFAIL; 34566759Seric } 34666759Seric 34766759Seric /* 34866759Seric ** If this address has a -request address, reflect 34966759Seric ** it into the envelope. 35066759Seric */ 35166759Seric 35266759Seric (void) strcpy(keybuf, a->q_user); 35366759Seric (void) strcat(keybuf, ":mailsender"); 35466759Seric keylen = strlen(keybuf); 35566759Seric key.data = keybuf; 35666759Seric key.size = keylen; 35766759Seric i = hes_udb_get(&key, &info); 35866759Seric if (i != 0 || info.size <= 0) 35966759Seric break; 36066759Seric a->q_owner = xalloc(info.size + 1); 36166759Seric bcopy(info.data, a->q_owner, info.size); 36266759Seric a->q_owner[info.size] = '\0'; 36366759Seric free(info.data); 36466759Seric break; 36566759Seric #endif /* HESIOD */ 36666759Seric 36751360Seric case UDB_REMOTE: 36851741Seric /* not yet implemented */ 36951741Seric continue; 37051362Seric 37151360Seric case UDB_FORWARD: 37258099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 37358099Seric return EX_OK; 37451360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 37551360Seric if (i < sizeof buf) 37651360Seric user = buf; 37751360Seric else 37851360Seric user = xalloc(i + 1); 37951360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 38058151Seric message("expanded to %s", user); 38158082Seric a->q_flags &= ~QSELFREF; 38251362Seric AliasLevel++; 38358082Seric naddrs = sendtolist(user, a, sendq, e); 38451362Seric AliasLevel--; 38558082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 38658065Seric { 38758065Seric if (tTd(28, 5)) 38858065Seric { 38958065Seric printf("udbexpand: QDONTSEND "); 39058065Seric printaddr(a, FALSE); 39158065Seric } 39258065Seric a->q_flags |= QDONTSEND; 39358065Seric } 39451362Seric if (user != buf) 39551362Seric free(user); 39651362Seric breakout = TRUE; 39751360Seric break; 39851360Seric 39951360Seric case UDB_EOLIST: 40051360Seric breakout = TRUE; 40151360Seric continue; 40251360Seric 40351360Seric default: 40451360Seric /* unknown entry type */ 40551360Seric continue; 40651360Seric } 40751362Seric } 40851923Seric return EX_OK; 40951362Seric } 41051951Seric /* 41151951Seric ** UDBSENDER -- return canonical external name of sender, given local name 41251951Seric ** 41351951Seric ** Parameters: 41451951Seric ** sender -- the name of the sender on the local machine. 41551951Seric ** 41651951Seric ** Returns: 41751951Seric ** The external name for this sender, if derivable from the 41851951Seric ** database. 41951951Seric ** NULL -- if nothing is changed from the database. 42051951Seric ** 42151951Seric ** Side Effects: 42251951Seric ** none. 42351951Seric */ 42451360Seric 42551951Seric char * 42651951Seric udbsender(sender) 42751951Seric char *sender; 42851951Seric { 42964350Seric extern char *udbmatch(); 43064350Seric 43164350Seric return udbmatch(sender, "mailname"); 43264350Seric } 43364350Seric 43464350Seric 43564350Seric char * 43664350Seric udbmatch(user, field) 43764350Seric char *user; 43864350Seric char *field; 43964350Seric { 44051951Seric register char *p; 44151951Seric register struct udbent *up; 44251951Seric int i; 44351951Seric int keylen; 44451951Seric DBT key, info; 44557232Seric char keybuf[MAXKEY]; 44651951Seric 44751951Seric if (tTd(28, 1)) 44864350Seric printf("udbmatch(%s, %s)\n", user, field); 44951951Seric 45051951Seric if (!UdbInitialized) 45151951Seric { 45251951Seric if (_udbx_init() == EX_TEMPFAIL) 45351951Seric return NULL; 45451951Seric } 45551951Seric 45651951Seric /* short circuit if no spec */ 45751951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 45851951Seric return NULL; 45951951Seric 46066759Seric /* short circuit name begins with '\\' since it can't possibly match */ 46166759Seric if (user[0] == '\\') 46266759Seric return NULL; 46366759Seric 46451951Seric /* long names can never match and are a pain to deal with */ 46564350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 46651951Seric return NULL; 46751951Seric 46851951Seric /* names beginning with colons indicate metadata */ 46964350Seric if (user[0] == ':') 47051951Seric return NULL; 47151951Seric 47251951Seric /* build database key */ 47364350Seric (void) strcpy(keybuf, user); 47464350Seric (void) strcat(keybuf, ":"); 47564350Seric (void) strcat(keybuf, field); 47651951Seric keylen = strlen(keybuf); 47751951Seric 47851951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 47951951Seric { 48051951Seric /* 48151951Seric ** Select action based on entry type. 48251951Seric */ 48351951Seric 48451951Seric switch (up->udb_type) 48551951Seric { 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; 50566759Seric 50666759Seric #ifdef HESIOD 50766759Seric case UDB_HESIOD: 50866759Seric key.data = keybuf; 50966759Seric key.size = keylen; 51066759Seric i = hes_udb_get(&key, &info); 51166759Seric if (i != 0 || info.size <= 0) 51266759Seric { 51366759Seric if (tTd(28, 2)) 51466759Seric printf("udbmatch: no match on %s (%d) via hesiod\n", 51566759Seric keybuf, keylen); 51666759Seric continue; 51766759Seric } 51866759Seric 51966759Seric p = xalloc(info.size + 1); 52066759Seric bcopy(info.data, p, info.size); 52166759Seric p[info.size] = '\0'; 52266759Seric free(info.data); 52366759Seric if (tTd(28, 1)) 52466759Seric printf("udbmatch ==> %s\n", p); 52566759Seric return p; 52666759Seric break; 52766759Seric #endif /* HESIOD */ 52851951Seric } 52951951Seric } 53051951Seric 53164350Seric if (strcmp(field, "mailname") != 0) 53264350Seric return NULL; 53364350Seric 53451951Seric /* 53551951Seric ** Nothing yet. Search again for a default case. But only 53651951Seric ** use it if we also have a forward (:maildrop) pointer already 53751951Seric ** in the database. 53851951Seric */ 53951951Seric 54051951Seric /* build database key */ 54164350Seric (void) strcpy(keybuf, user); 54251951Seric (void) strcat(keybuf, ":maildrop"); 54351951Seric keylen = strlen(keybuf); 54451951Seric 54551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 54651951Seric { 54751951Seric switch (up->udb_type) 54851951Seric { 54951951Seric case UDB_DBFETCH: 55051951Seric /* get the default case for this database */ 55151951Seric if (up->udb_default == NULL) 55251951Seric { 55351951Seric key.data = ":default:mailname"; 55451951Seric key.size = strlen(key.data); 55551951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 55651951Seric if (i != 0 || info.size <= 0) 55751951Seric { 55851951Seric /* no default case */ 55951951Seric up->udb_default = ""; 56051951Seric continue; 56151951Seric } 56251951Seric 56351951Seric /* save the default case */ 56451951Seric up->udb_default = xalloc(info.size + 1); 56551951Seric bcopy(info.data, up->udb_default, info.size); 56651951Seric up->udb_default[info.size] = '\0'; 56751951Seric } 56851951Seric else if (up->udb_default[0] == '\0') 56951951Seric continue; 57051951Seric 57151951Seric /* we have a default case -- verify user:maildrop */ 57251951Seric key.data = keybuf; 57351951Seric key.size = keylen; 57451951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 57551951Seric if (i != 0 || info.size <= 0) 57651951Seric { 57751951Seric /* nope -- no aliasing for this user */ 57851951Seric continue; 57951951Seric } 58051951Seric 58151951Seric /* they exist -- build the actual address */ 58264350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 58364350Seric (void) strcpy(p, user); 58451951Seric (void) strcat(p, "@"); 58551951Seric (void) strcat(p, up->udb_default); 58651951Seric if (tTd(28, 1)) 58764350Seric printf("udbmatch ==> %s\n", p); 58851951Seric return p; 58966759Seric break; 59066759Seric 59166759Seric #ifdef HESIOD 59266759Seric case UDB_HESIOD: 59366759Seric /* get the default case for this database */ 59466759Seric if (up->udb_default == NULL) 59566759Seric { 59666759Seric key.data = ":default:mailname"; 59766759Seric key.size = strlen(key.data); 59866759Seric i = hes_udb_get(&key, &info); 59966759Seric 60066759Seric if (i != 0 || info.size <= 0) 60166759Seric { 60266759Seric /* no default case */ 60366759Seric up->udb_default = ""; 60466759Seric continue; 60566759Seric } 60666759Seric 60766759Seric /* save the default case */ 60866759Seric up->udb_default = xalloc(info.size + 1); 60966759Seric bcopy(info.data, up->udb_default, info.size); 61066759Seric up->udb_default[info.size] = '\0'; 61166759Seric free(info.data); 61266759Seric } 61366759Seric else if (up->udb_default[0] == '\0') 61466759Seric continue; 61566759Seric 61666759Seric /* we have a default case -- verify user:maildrop */ 61766759Seric key.data = keybuf; 61866759Seric key.size = keylen; 61966759Seric i = hes_udb_get(&key, &info); 62066759Seric if (i != 0 || info.size <= 0) 62166759Seric { 62266759Seric /* nope -- no aliasing for this user */ 62366759Seric continue; 62466759Seric } 62566759Seric 62666759Seric free(info.data); 62766759Seric /* they exist -- build the actual address */ 62866759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 62966759Seric (void) strcpy(p, user); 63066759Seric (void) strcat(p, "@"); 63166759Seric (void) strcat(p, up->udb_default); 63266759Seric if (tTd(28, 1)) 63366759Seric printf("udbmatch ==> %s\n", p); 63466759Seric return p; 63566759Seric break; 63666759Seric #endif /* HESIOD */ 63751951Seric } 63851951Seric } 63951951Seric 64051951Seric /* still nothing.... too bad */ 64151951Seric return NULL; 64251951Seric } 64351951Seric /* 64451951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 64551951Seric ** 64651951Seric ** Parameters: 64751951Seric ** none. 64851951Seric ** 64951951Seric ** Returns: 65051951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 65151951Seric ** database due to a host being down or some similar 65251951Seric ** (recoverable) situation. 65351951Seric ** EX_OK -- otherwise. 65451951Seric ** 65551951Seric ** Side Effects: 65651951Seric ** Fills in the UdbEnts structure from UdbSpec. 65751951Seric */ 65851951Seric 65951363Seric #define MAXUDBOPTS 27 66051363Seric 66151953Seric int 66251362Seric _udbx_init() 66351362Seric { 66451362Seric register char *p; 66551362Seric int i; 66651362Seric register struct udbent *up; 66757232Seric char buf[BUFSIZ]; 66851360Seric 66951951Seric if (UdbInitialized) 67051951Seric return EX_OK; 67151951Seric 67251908Seric # ifdef UDB_DEFAULT_SPEC 67351908Seric if (UdbSpec == NULL) 67451908Seric UdbSpec = UDB_DEFAULT_SPEC; 67551908Seric # endif 67651908Seric 67751362Seric p = UdbSpec; 67851362Seric up = UdbEnts; 67951762Seric while (p != NULL) 68051362Seric { 68151362Seric char *spec; 68251362Seric auto int rcode; 68351363Seric int nopts; 68451362Seric int nmx; 68551362Seric register struct hostent *h; 68651362Seric char *mxhosts[MAXMXHOSTS + 1]; 68751363Seric struct option opts[MAXUDBOPTS + 1]; 68851362Seric 68951362Seric while (*p == ' ' || *p == '\t' || *p == ',') 69051362Seric p++; 69151362Seric if (*p == '\0') 69251362Seric break; 69351362Seric spec = p; 69456795Seric p = strchr(p, ','); 69551761Seric if (p != NULL) 69651362Seric *p++ = '\0'; 69751363Seric 69851363Seric /* extract options */ 69951363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 70051363Seric 70151363Seric /* 70251363Seric ** Decode database specification. 70351363Seric ** 70451363Seric ** In the sendmail tradition, the leading character 70551363Seric ** defines the semantics of the rest of the entry. 70651363Seric ** 70751363Seric ** +hostname -- send a datagram to the udb server 70851363Seric ** on host "hostname" asking for the 70951363Seric ** home mail server for this user. 71051363Seric ** *hostname -- similar to +hostname, except that the 71151363Seric ** hostname is searched as an MX record; 71251363Seric ** resulting hosts are searched as for 71351363Seric ** +mxhostname. If no MX host is found, 71451363Seric ** this is the same as +hostname. 71551363Seric ** @hostname -- forward email to the indicated host. 71651363Seric ** This should be the last in the list, 71751363Seric ** since it always matches the input. 71851363Seric ** /dbname -- search the named database on the local 71951363Seric ** host using the Berkeley db package. 72051363Seric */ 72151363Seric 72251362Seric switch (*spec) 72351360Seric { 72451362Seric case '+': /* search remote database */ 72551363Seric case '*': /* search remote database (expand MX) */ 72651363Seric if (*spec == '*') 72751363Seric { 72866334Seric #if NAMED_BIND 72959273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 73057629Seric #else 73157629Seric mxhosts[0] = spec + 1; 73257629Seric nmx = 1; 73357629Seric rcode = 0; 73457629Seric #endif 73551363Seric if (tTd(28, 16)) 73651363Seric { 73751363Seric int i; 73851362Seric 73951363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 74051363Seric for (i = 0; i <= nmx; i++) 74151363Seric printf(" %s", mxhosts[i]); 74251363Seric printf("\n"); 74351363Seric } 74451363Seric } 74551363Seric else 74651362Seric { 74751363Seric nmx = 1; 74851363Seric mxhosts[0] = spec + 1; 74951362Seric } 75051362Seric 75151362Seric for (i = 0; i < nmx; i++) 75251362Seric { 75351362Seric h = gethostbyname(mxhosts[i]); 75451362Seric if (h == NULL) 75551362Seric continue; 75651362Seric up->udb_type = UDB_REMOTE; 75751362Seric up->udb_addr.sin_family = h->h_addrtype; 75851362Seric bcopy(h->h_addr_list[0], 75951362Seric (char *) &up->udb_addr.sin_addr, 76067421Seric INADDRSZ); 76151362Seric up->udb_addr.sin_port = UdbPort; 76251362Seric up->udb_timeout = UdbTimeout; 76351362Seric up++; 76451362Seric } 76551362Seric 76651362Seric /* set up a datagram socket */ 76751362Seric if (UdbSock < 0) 76851362Seric { 76951362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 77051362Seric (void) fcntl(UdbSock, F_SETFD, 1); 77151362Seric } 77251362Seric break; 77351362Seric 77451362Seric case '@': /* forward to remote host */ 77551362Seric up->udb_type = UDB_FORWARD; 77651362Seric up->udb_fwdhost = spec + 1; 77751362Seric up++; 77851362Seric break; 77951362Seric 78066759Seric case 'h': /* use hesiod */ 78166759Seric case 'H': 78266759Seric #ifdef HESIOD 78366759Seric if (strcasecmp(spec, "hesiod") != 0) 78466759Seric break; 78566759Seric up->udb_type = UDB_HESIOD; 78666759Seric up++; 78766759Seric #endif /* HESIOD */ 78866759Seric break; 78966759Seric 79051362Seric case '/': /* look up remote name */ 79151831Seric up->udb_dbname = spec; 79251923Seric errno = 0; 79351362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 79451362Seric if (up->udb_dbp == NULL) 79551923Seric { 796*67763Seric if (tTd(28, 1)) 797*67763Seric { 798*67763Seric int saveerrno = errno; 799*67763Seric 800*67763Seric printf("dbopen(%s): %s", 801*67763Seric spec, errstring(errno)); 802*67763Seric errno = saveerrno; 803*67763Seric } 80451923Seric if (errno != ENOENT && errno != EACCES) 80551951Seric { 80659615Seric #ifdef LOG 80759615Seric if (LogLevel > 2) 80859625Seric syslog(LOG_ERR, "dbopen(%s): %s", 80959625Seric spec, errstring(errno)); 81059615Seric #endif 81151951Seric up->udb_type = UDB_EOLIST; 81251951Seric goto tempfail; 81351951Seric } 81451362Seric break; 81551923Seric } 81651951Seric up->udb_type = UDB_DBFETCH; 81751362Seric up++; 81851362Seric break; 81951360Seric } 82051362Seric } 82151362Seric up->udb_type = UDB_EOLIST; 82251360Seric 82351362Seric if (tTd(28, 4)) 82451362Seric { 82551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 82651360Seric { 82751362Seric switch (up->udb_type) 82851362Seric { 82951362Seric case UDB_REMOTE: 83051362Seric printf("REMOTE: addr %s, timeo %d\n", 83160494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 83251362Seric up->udb_timeout); 83351362Seric break; 83451362Seric 83551951Seric case UDB_DBFETCH: 83651951Seric printf("FETCH: file %s\n", 83751830Seric up->udb_dbname); 83851362Seric break; 83951362Seric 84051362Seric case UDB_FORWARD: 84151362Seric printf("FORWARD: host %s\n", 84251362Seric up->udb_fwdhost); 84351362Seric break; 84451362Seric 84566759Seric case UDB_HESIOD: 84666759Seric printf("HESIOD\n"); 84766759Seric break; 84866759Seric 84951362Seric default: 85051362Seric printf("UNKNOWN\n"); 85151362Seric break; 85251362Seric } 85351360Seric } 85450581Seric } 85551951Seric 85651951Seric UdbInitialized = TRUE; 85751955Seric errno = 0; 85851951Seric return EX_OK; 85951951Seric 86051951Seric /* 86151951Seric ** On temporary failure, back out anything we've already done 86251951Seric */ 86351951Seric 86451951Seric tempfail: 86551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 86651951Seric { 86751951Seric if (up->udb_type == UDB_DBFETCH) 86851951Seric { 86951951Seric (*up->udb_dbp->close)(up->udb_dbp); 87051951Seric } 87151951Seric } 87251951Seric return EX_TEMPFAIL; 87351360Seric } 87450581Seric 87551363Seric int 87651363Seric _udb_parsespec(udbspec, opt, maxopts) 87751363Seric char *udbspec; 87851363Seric struct option opt[]; 87951363Seric int maxopts; 88051363Seric { 88151363Seric register char *spec; 88251363Seric register char *spec_end; 88351363Seric register int optnum; 88451363Seric 88556795Seric spec_end = strchr(udbspec, ':'); 88651363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 88751363Seric { 88851363Seric register char *p; 88951363Seric 89058050Seric while (isascii(*spec) && isspace(*spec)) 89151363Seric spec++; 89256795Seric spec_end = strchr(spec, ':'); 89351363Seric if (spec_end != NULL) 89451363Seric *spec_end++ = '\0'; 89551363Seric 89651363Seric opt[optnum].name = spec; 89751363Seric opt[optnum].val = NULL; 89856795Seric p = strchr(spec, '='); 89951363Seric if (p != NULL) 90051363Seric opt[optnum].val = ++p; 90151363Seric } 90251363Seric return optnum; 90351363Seric } 90451363Seric 90566759Seric #ifdef HESIOD 90666759Seric 90766759Seric int 90866759Seric hes_udb_get(key, info) 90966759Seric DBT *key; 91066759Seric DBT *info; 91166759Seric { 91266759Seric char *name, *type; 91366759Seric char *p, **hp; 91466759Seric 91566759Seric name = key->data; 91666759Seric type = strchr(name, ':'); 91766759Seric if (type == NULL) 91866759Seric return 1; 91966759Seric 92066759Seric *type++ = '\0'; 92166759Seric 92266759Seric if (tTd(28, 1)) 92366759Seric printf("hes_udb_get(%s, %s)\n", name, type); 92466759Seric 92566759Seric /* make the hesiod query */ 92666759Seric hp = hes_resolve(name, type); 92766759Seric if (hp == NULL) 92866759Seric { 92966759Seric /* network problem or timeout */ 93066759Seric if (hes_error() == HES_ER_NET) 93166759Seric return -1; 93266759Seric 93366759Seric return 1; 93466759Seric } 93566759Seric else 93666759Seric { 93766759Seric /* 93866759Seric ** If there are multiple matches, just return the 93966759Seric ** first one and free the others. 94066759Seric ** 94166759Seric ** XXX These should really be returned; for example, 94266759Seric ** XXX it is legal for :maildrop to be multi-valued. 94366759Seric */ 94466759Seric 94566759Seric for (p = hp[1]; p; p++) 94666759Seric free(p); 94766759Seric 94866759Seric info->data = hp[0]; 94966759Seric info->size = (size_t) strlen(info->data); 95066759Seric } 95166759Seric 95266759Seric return 0; 95366759Seric } 95466759Seric #endif /* HESIOD */ 95566759Seric 95651360Seric #else /* not USERDB */ 95751360Seric 95851923Seric int 95955012Seric udbexpand(a, sendq, e) 96051360Seric ADDRESS *a; 96151360Seric ADDRESS **sendq; 96255012Seric ENVELOPE *e; 96351360Seric { 96451923Seric return EX_OK; 96550581Seric } 96650581Seric 96750581Seric #endif /* USERDB */ 968