150581Seric /* 268839Seric * Copyright (c) 1983, 1995 Eric P. Allman 362532Sbostic * Copyright (c) 1988, 1993 462532Sbostic * The Regents of the University of California. All rights reserved. 550581Seric * 650581Seric * %sccs.include.redist.c% 750581Seric */ 850581Seric 960567Seric #include "sendmail.h" 1060567Seric 1150581Seric #ifndef lint 12*69711Seric #if !USERDB 13*69711Seric static char sccsid [] = "@(#)udb.c 8.22 (Berkeley) 05/27/95 (with USERDB)"; 1451360Seric #else 15*69711Seric static char sccsid [] = "@(#)udb.c 8.22 (Berkeley) 05/27/95 (without USERDB)"; 1650581Seric #endif 1751360Seric #endif 1850581Seric 19*69711Seric #if USERDB 2050581Seric 2151923Seric #include <errno.h> 2250581Seric 23*69711Seric #ifdef NEWDB 24*69711Seric # include <db.h> 25*69711Seric #else 26*69711Seric # define DBT struct _data_base_thang_ 27*69711Seric DBT 28*69711Seric { 29*69711Seric void *data; /* pointer to data */ 30*69711Seric size_t size; /* length of data */ 31*69711Seric }; 32*69711Seric #endif 33*69711Seric 3466759Seric #ifdef HESIOD 35*69711Seric # include <hesiod.h> 3666759Seric #endif /* HESIOD */ 3766759Seric 3850581Seric /* 3953654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 4050581Seric ** 4151363Seric ** This depends on the 4.4BSD db package. 4250581Seric */ 4350581Seric 4451362Seric 4551360Seric struct udbent 4651360Seric { 4751360Seric char *udb_spec; /* string version of spec */ 4851360Seric int udb_type; /* type of entry */ 4951951Seric char *udb_default; /* default host for outgoing mail */ 5051360Seric union 5151360Seric { 5251360Seric /* type UE_REMOTE -- do remote call for lookup */ 5351360Seric struct 5451360Seric { 5551360Seric struct sockaddr_in _udb_addr; /* address */ 5651360Seric int _udb_timeout; /* timeout */ 5751360Seric } udb_remote; 5851360Seric #define udb_addr udb_u.udb_remote._udb_addr 5951360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 6051360Seric 6151360Seric /* type UE_FORWARD -- forward message to remote */ 6251360Seric struct 6351360Seric { 6451360Seric char *_udb_fwdhost; /* name of forward host */ 6551360Seric } udb_forward; 6651360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 6751360Seric 68*69711Seric #ifdef NEWDB 6951951Seric /* type UE_FETCH -- lookup in local database */ 7051360Seric struct 7151360Seric { 7251360Seric char *_udb_dbname; /* pathname of database */ 7351360Seric DB *_udb_dbp; /* open database ptr */ 7451360Seric } udb_lookup; 7551360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 7651360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 77*69711Seric #endif 7851360Seric } udb_u; 7951360Seric }; 8051360Seric 8151360Seric #define UDB_EOLIST 0 /* end of list */ 8251360Seric #define UDB_SKIP 1 /* skip this entry */ 8351360Seric #define UDB_REMOTE 2 /* look up in remote database */ 8451951Seric #define UDB_DBFETCH 3 /* look up in local database */ 8551360Seric #define UDB_FORWARD 4 /* forward to remote host */ 8666759Seric #define UDB_HESIOD 5 /* look up via hesiod */ 8751360Seric 8851360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 8951360Seric 9051363Seric 9151363Seric struct option 9251363Seric { 9351363Seric char *name; 9451363Seric char *val; 9551363Seric }; 9651363Seric /* 9751363Seric ** UDBEXPAND -- look up user in database and expand 9851363Seric ** 9951363Seric ** Parameters: 10051363Seric ** a -- address to expand. 10151363Seric ** sendq -- pointer to head of sendq to put the expansions in. 10267982Seric ** aliaslevel -- the current alias nesting depth. 10367982Seric ** e -- the current envelope. 10451363Seric ** 10551363Seric ** Returns: 10651923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 10751923Seric ** to accessing a file on an NFS server that is down. 10851923Seric ** EX_OK -- otherwise. 10951363Seric ** 11051363Seric ** Side Effects: 11151363Seric ** Modifies sendq. 11251363Seric */ 11351363Seric 11451363Seric int UdbPort = 1616; 11551363Seric int UdbTimeout = 10; 11651363Seric 11751953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 11851953Seric int UdbSock = -1; 11951953Seric bool UdbInitialized = FALSE; 12051360Seric 12151923Seric int 12267982Seric udbexpand(a, sendq, aliaslevel, e) 12350581Seric register ADDRESS *a; 12450581Seric ADDRESS **sendq; 12567982Seric int aliaslevel; 12655012Seric register ENVELOPE *e; 12750581Seric { 12850581Seric int i; 12950581Seric register char *p; 13050581Seric DBT key; 13150581Seric DBT info; 13251360Seric bool breakout; 13351360Seric register struct udbent *up; 13451362Seric int keylen; 13558082Seric int naddrs; 13657232Seric char keybuf[MAXKEY]; 13757232Seric char buf[BUFSIZ]; 13850581Seric 13950581Seric if (tTd(28, 1)) 14058065Seric printf("udbexpand(%s)\n", a->q_paddr); 14150581Seric 14250581Seric /* make certain we are supposed to send to this address */ 14358154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 14451923Seric return EX_OK; 14555012Seric e->e_to = a->q_paddr; 14650581Seric 14751360Seric /* on first call, locate the database */ 14851951Seric if (!UdbInitialized) 14950581Seric { 15051923Seric extern int _udbx_init(); 15151362Seric 15251923Seric if (_udbx_init() == EX_TEMPFAIL) 15351923Seric return EX_TEMPFAIL; 15451362Seric } 15550581Seric 15651909Seric /* short circuit the process if no chance of a match */ 15751909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 15851923Seric return EX_OK; 15951909Seric 16066759Seric /* short circuit name begins with '\\' since it can't possibly match */ 16166759Seric if (a->q_user[0] == '\\') 16266759Seric return EX_OK; 16366759Seric 16451362Seric /* if name is too long, assume it won't match */ 16551362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 16651923Seric return EX_OK; 16751360Seric 16851362Seric /* if name begins with a colon, it indicates our metadata */ 16951362Seric if (a->q_user[0] == ':') 17051923Seric return EX_OK; 17151360Seric 17251362Seric /* build actual database key */ 17351362Seric (void) strcpy(keybuf, a->q_user); 17451362Seric (void) strcat(keybuf, ":maildrop"); 17551362Seric keylen = strlen(keybuf); 17651360Seric 17751360Seric breakout = FALSE; 17851362Seric for (up = UdbEnts; !breakout; up++) 17950581Seric { 18051360Seric char *user; 18150581Seric 18251360Seric /* 18351360Seric ** Select action based on entry type. 18451360Seric ** 18551360Seric ** On dropping out of this switch, "class" should 18651360Seric ** explain the type of the data, and "user" should 18751360Seric ** contain the user information. 18851360Seric */ 18950581Seric 19051360Seric switch (up->udb_type) 19151360Seric { 19268786Seric #ifdef NEWDB 19351951Seric case UDB_DBFETCH: 19451362Seric key.data = keybuf; 19551362Seric key.size = keylen; 19660990Seric if (tTd(28, 80)) 19766759Seric printf("udbexpand: trying %s (%d) via db\n", 19864067Seric keybuf, keylen); 19951362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 20051923Seric if (i > 0 || info.size <= 0) 20151360Seric { 20251360Seric if (tTd(28, 2)) 20364067Seric printf("udbexpand: no match on %s (%d)\n", 20464067Seric keybuf, keylen); 20551360Seric continue; 20651360Seric } 20760990Seric if (tTd(28, 80)) 20860990Seric printf("udbexpand: match %.*s: %.*s\n", 20960990Seric key.size, key.data, info.size, info.data); 21050581Seric 21158082Seric naddrs = 0; 21258082Seric a->q_flags &= ~QSELFREF; 21351830Seric while (i == 0 && key.size == keylen && 21451830Seric bcmp(key.data, keybuf, keylen) == 0) 21551362Seric { 21658099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 21758154Seric { 21858154Seric a->q_flags |= QVERIFIED; 21958884Seric e->e_nrcpts++; 22058099Seric return EX_OK; 22158154Seric } 22258099Seric 22351830Seric breakout = TRUE; 22451362Seric if (info.size < sizeof buf) 22551362Seric user = buf; 22651362Seric else 22751362Seric user = xalloc(info.size + 1); 22851362Seric bcopy(info.data, user, info.size); 22951362Seric user[info.size] = '\0'; 23050581Seric 23158151Seric message("expanded to %s", user); 23257977Seric #ifdef LOG 23357977Seric if (LogLevel >= 10) 23457977Seric syslog(LOG_INFO, "%s: expand %s => %s", 23557977Seric e->e_id, e->e_to, user); 23657977Seric #endif 23767982Seric naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e); 23851362Seric 23951362Seric if (user != buf) 24051362Seric free(user); 24151362Seric 24251362Seric /* get the next record */ 24351362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 24451830Seric } 24560990Seric 24660990Seric /* if nothing ever matched, try next database */ 24760990Seric if (!breakout) 24860990Seric continue; 24960990Seric 25058082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 25158065Seric { 25258065Seric if (tTd(28, 5)) 25358065Seric { 25458065Seric printf("udbexpand: QDONTSEND "); 25558065Seric printaddr(a, FALSE); 25658065Seric } 25758065Seric a->q_flags |= QDONTSEND; 25858065Seric } 25951923Seric if (i < 0) 26051923Seric { 26158010Seric syserr("udbexpand: db-get %.*s stat %d", 26258010Seric key.size, key.data, i); 26351923Seric return EX_TEMPFAIL; 26451923Seric } 26559707Seric 26659707Seric /* 26759707Seric ** If this address has a -request address, reflect 26859707Seric ** it into the envelope. 26959707Seric */ 27059707Seric 27159707Seric (void) strcpy(keybuf, a->q_user); 27259707Seric (void) strcat(keybuf, ":mailsender"); 27359707Seric keylen = strlen(keybuf); 27459707Seric key.data = keybuf; 27559707Seric key.size = keylen; 27659707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 27759707Seric if (i != 0 || info.size <= 0) 27859707Seric break; 27959707Seric a->q_owner = xalloc(info.size + 1); 28059707Seric bcopy(info.data, a->q_owner, info.size); 28159707Seric a->q_owner[info.size] = '\0'; 28266784Seric 28366784Seric /* announce delivery; NORECEIPT bit set later */ 28466784Seric if (e->e_xfp != NULL) 28566784Seric { 28666784Seric fprintf(e->e_xfp, 28766784Seric "Message delivered to mailing list %s\n", 28866784Seric a->q_paddr); 28966784Seric } 29068603Seric e->e_flags |= EF_SENDRECEIPT; 29168868Seric a->q_flags |= QDELIVERED|QEXPANDED; 29251360Seric break; 29368786Seric #endif 29451360Seric 29566759Seric #ifdef HESIOD 29666759Seric case UDB_HESIOD: 29766759Seric key.data = keybuf; 29866759Seric key.size = keylen; 29966759Seric if (tTd(28, 80)) 30066759Seric printf("udbexpand: trying %s (%d) via hesiod\n", 30166759Seric keybuf, keylen); 30266759Seric /* look up the key via hesiod */ 30366759Seric i = hes_udb_get(&key, &info); 30469623Seric if (i < 0) 30566759Seric { 30669623Seric syserr("udbexpand: hesiod-get %.*s stat %d", 30769623Seric key.size, key.data, i); 30869623Seric return EX_TEMPFAIL; 30969623Seric } 31069623Seric else if (i > 0 || info.size <= 0) 31169623Seric { 31266759Seric if (tTd(28, 2)) 31366759Seric printf("udbexpand: no match on %s (%d)\n", 31466759Seric keybuf, keylen); 31566759Seric continue; 31666759Seric } 31766759Seric if (tTd(28, 80)) 31866759Seric printf("udbexpand: match %.*s: %.*s\n", 31966759Seric key.size, key.data, info.size, info.data); 32066759Seric a->q_flags &= ~QSELFREF; 32166759Seric 32266759Seric if (bitset(EF_VRFYONLY, e->e_flags)) 32366759Seric { 32466759Seric a->q_flags |= QVERIFIED; 32566759Seric e->e_nrcpts++; 32666759Seric return EX_OK; 32766759Seric } 32866759Seric 32966759Seric breakout = TRUE; 33066759Seric if (info.size < sizeof buf) 33166759Seric user = buf; 33266759Seric else 33366759Seric user = xalloc(info.size + 1); 33466759Seric bcopy(info.data, user, info.size); 33566759Seric user[info.size] = '\0'; 33666759Seric 33766759Seric message("hesioded to %s", user); 33866759Seric #ifdef LOG 33966759Seric if (LogLevel >= 10) 34066759Seric syslog(LOG_INFO, "%s: hesiod %s => %s", 34166759Seric e->e_id, e->e_to, user); 34266759Seric #endif 34367982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 34466759Seric 34566759Seric if (user != buf) 34666759Seric free(user); 34766759Seric 34866759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 34966759Seric { 35066759Seric if (tTd(28, 5)) 35166759Seric { 35266759Seric printf("udbexpand: QDONTSEND "); 35366759Seric printaddr(a, FALSE); 35466759Seric } 35566759Seric a->q_flags |= QDONTSEND; 35666759Seric } 35766759Seric 35866759Seric /* 35966759Seric ** If this address has a -request address, reflect 36066759Seric ** it into the envelope. 36166759Seric */ 36266759Seric 36366759Seric (void) strcpy(keybuf, a->q_user); 36466759Seric (void) strcat(keybuf, ":mailsender"); 36566759Seric keylen = strlen(keybuf); 36666759Seric key.data = keybuf; 36766759Seric key.size = keylen; 36866759Seric i = hes_udb_get(&key, &info); 36966759Seric if (i != 0 || info.size <= 0) 37066759Seric break; 37166759Seric a->q_owner = xalloc(info.size + 1); 37266759Seric bcopy(info.data, a->q_owner, info.size); 37366759Seric a->q_owner[info.size] = '\0'; 37466759Seric break; 37566759Seric #endif /* HESIOD */ 37666759Seric 37751360Seric case UDB_REMOTE: 37851741Seric /* not yet implemented */ 37951741Seric continue; 38051362Seric 38151360Seric case UDB_FORWARD: 38258099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 38358099Seric return EX_OK; 38451360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 38551360Seric if (i < sizeof buf) 38651360Seric user = buf; 38751360Seric else 38851360Seric user = xalloc(i + 1); 38951360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 39058151Seric message("expanded to %s", user); 39158082Seric a->q_flags &= ~QSELFREF; 39267982Seric naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 39358082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 39458065Seric { 39558065Seric if (tTd(28, 5)) 39658065Seric { 39758065Seric printf("udbexpand: QDONTSEND "); 39858065Seric printaddr(a, FALSE); 39958065Seric } 40058065Seric a->q_flags |= QDONTSEND; 40158065Seric } 40251362Seric if (user != buf) 40351362Seric free(user); 40451362Seric breakout = TRUE; 40551360Seric break; 40651360Seric 40751360Seric case UDB_EOLIST: 40851360Seric breakout = TRUE; 40951360Seric continue; 41051360Seric 41151360Seric default: 41251360Seric /* unknown entry type */ 41351360Seric continue; 41451360Seric } 41551362Seric } 41651923Seric return EX_OK; 41751362Seric } 41851951Seric /* 41951951Seric ** UDBSENDER -- return canonical external name of sender, given local name 42051951Seric ** 42151951Seric ** Parameters: 42251951Seric ** sender -- the name of the sender on the local machine. 42351951Seric ** 42451951Seric ** Returns: 42551951Seric ** The external name for this sender, if derivable from the 42651951Seric ** database. 42751951Seric ** NULL -- if nothing is changed from the database. 42851951Seric ** 42951951Seric ** Side Effects: 43051951Seric ** none. 43151951Seric */ 43251360Seric 43351951Seric char * 43451951Seric udbsender(sender) 43551951Seric char *sender; 43651951Seric { 43764350Seric extern char *udbmatch(); 43864350Seric 43964350Seric return udbmatch(sender, "mailname"); 44064350Seric } 44164350Seric 44264350Seric 44364350Seric char * 44464350Seric udbmatch(user, field) 44564350Seric char *user; 44664350Seric char *field; 44764350Seric { 44851951Seric register char *p; 44951951Seric register struct udbent *up; 45051951Seric int i; 45151951Seric int keylen; 45251951Seric DBT key, info; 45357232Seric char keybuf[MAXKEY]; 45451951Seric 45551951Seric if (tTd(28, 1)) 45664350Seric printf("udbmatch(%s, %s)\n", user, field); 45751951Seric 45851951Seric if (!UdbInitialized) 45951951Seric { 46051951Seric if (_udbx_init() == EX_TEMPFAIL) 46151951Seric return NULL; 46251951Seric } 46351951Seric 46451951Seric /* short circuit if no spec */ 46551951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 46651951Seric return NULL; 46751951Seric 46866759Seric /* short circuit name begins with '\\' since it can't possibly match */ 46966759Seric if (user[0] == '\\') 47066759Seric return NULL; 47166759Seric 47251951Seric /* long names can never match and are a pain to deal with */ 47364350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 47451951Seric return NULL; 47551951Seric 47651951Seric /* names beginning with colons indicate metadata */ 47764350Seric if (user[0] == ':') 47851951Seric return NULL; 47951951Seric 48051951Seric /* build database key */ 48164350Seric (void) strcpy(keybuf, user); 48264350Seric (void) strcat(keybuf, ":"); 48364350Seric (void) strcat(keybuf, field); 48451951Seric keylen = strlen(keybuf); 48551951Seric 48651951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 48751951Seric { 48851951Seric /* 48951951Seric ** Select action based on entry type. 49051951Seric */ 49151951Seric 49251951Seric switch (up->udb_type) 49351951Seric { 49468786Seric #ifdef NEWDB 49551951Seric case UDB_DBFETCH: 49651951Seric key.data = keybuf; 49751951Seric key.size = keylen; 49851951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 49951951Seric if (i != 0 || info.size <= 0) 50051951Seric { 50151951Seric if (tTd(28, 2)) 50266759Seric printf("udbmatch: no match on %s (%d) via db\n", 50364067Seric keybuf, keylen); 50451951Seric continue; 50551951Seric } 50651951Seric 50751951Seric p = xalloc(info.size + 1); 50851951Seric bcopy(info.data, p, info.size); 50951951Seric p[info.size] = '\0'; 51051951Seric if (tTd(28, 1)) 51164350Seric printf("udbmatch ==> %s\n", p); 51251951Seric return p; 51366759Seric break; 51468786Seric #endif 51566759Seric 51666759Seric #ifdef HESIOD 51766759Seric case UDB_HESIOD: 51866759Seric key.data = keybuf; 51966759Seric key.size = keylen; 52066759Seric i = hes_udb_get(&key, &info); 52166759Seric if (i != 0 || info.size <= 0) 52266759Seric { 52366759Seric if (tTd(28, 2)) 52466759Seric printf("udbmatch: no match on %s (%d) via hesiod\n", 52566759Seric keybuf, keylen); 52666759Seric continue; 52766759Seric } 52866759Seric 52966759Seric p = xalloc(info.size + 1); 53066759Seric bcopy(info.data, p, info.size); 53166759Seric p[info.size] = '\0'; 53266759Seric if (tTd(28, 1)) 53366759Seric printf("udbmatch ==> %s\n", p); 53466759Seric return p; 53566759Seric #endif /* HESIOD */ 53651951Seric } 53751951Seric } 53851951Seric 53964350Seric if (strcmp(field, "mailname") != 0) 54064350Seric return NULL; 54164350Seric 54251951Seric /* 54351951Seric ** Nothing yet. Search again for a default case. But only 54451951Seric ** use it if we also have a forward (:maildrop) pointer already 54551951Seric ** in the database. 54651951Seric */ 54751951Seric 54851951Seric /* build database key */ 54964350Seric (void) strcpy(keybuf, user); 55051951Seric (void) strcat(keybuf, ":maildrop"); 55151951Seric keylen = strlen(keybuf); 55251951Seric 55351951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 55451951Seric { 55551951Seric switch (up->udb_type) 55651951Seric { 55768786Seric #ifdef NEWDB 55851951Seric case UDB_DBFETCH: 55951951Seric /* get the default case for this database */ 56051951Seric if (up->udb_default == NULL) 56151951Seric { 56251951Seric key.data = ":default:mailname"; 56351951Seric key.size = strlen(key.data); 56451951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 56551951Seric if (i != 0 || info.size <= 0) 56651951Seric { 56751951Seric /* no default case */ 56851951Seric up->udb_default = ""; 56951951Seric continue; 57051951Seric } 57151951Seric 57251951Seric /* save the default case */ 57351951Seric up->udb_default = xalloc(info.size + 1); 57451951Seric bcopy(info.data, up->udb_default, info.size); 57551951Seric up->udb_default[info.size] = '\0'; 57651951Seric } 57751951Seric else if (up->udb_default[0] == '\0') 57851951Seric continue; 57951951Seric 58051951Seric /* we have a default case -- verify user:maildrop */ 58151951Seric key.data = keybuf; 58251951Seric key.size = keylen; 58351951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 58451951Seric if (i != 0 || info.size <= 0) 58551951Seric { 58651951Seric /* nope -- no aliasing for this user */ 58751951Seric continue; 58851951Seric } 58951951Seric 59051951Seric /* they exist -- build the actual address */ 59164350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 59264350Seric (void) strcpy(p, user); 59351951Seric (void) strcat(p, "@"); 59451951Seric (void) strcat(p, up->udb_default); 59551951Seric if (tTd(28, 1)) 59664350Seric printf("udbmatch ==> %s\n", p); 59751951Seric return p; 59866759Seric break; 59968786Seric #endif 60066759Seric 60166759Seric #ifdef HESIOD 60266759Seric case UDB_HESIOD: 60366759Seric /* get the default case for this database */ 60466759Seric if (up->udb_default == NULL) 60566759Seric { 60666759Seric key.data = ":default:mailname"; 60766759Seric key.size = strlen(key.data); 60866759Seric i = hes_udb_get(&key, &info); 60966759Seric 61066759Seric if (i != 0 || info.size <= 0) 61166759Seric { 61266759Seric /* no default case */ 61366759Seric up->udb_default = ""; 61466759Seric continue; 61566759Seric } 61666759Seric 61766759Seric /* save the default case */ 61866759Seric up->udb_default = xalloc(info.size + 1); 61966759Seric bcopy(info.data, up->udb_default, info.size); 62066759Seric up->udb_default[info.size] = '\0'; 62166759Seric } 62266759Seric else if (up->udb_default[0] == '\0') 62366759Seric continue; 62466759Seric 62566759Seric /* we have a default case -- verify user:maildrop */ 62666759Seric key.data = keybuf; 62766759Seric key.size = keylen; 62866759Seric i = hes_udb_get(&key, &info); 62966759Seric if (i != 0 || info.size <= 0) 63066759Seric { 63166759Seric /* nope -- no aliasing for this user */ 63266759Seric continue; 63366759Seric } 63466759Seric 63566759Seric /* they exist -- build the actual address */ 63666759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 63766759Seric (void) strcpy(p, user); 63866759Seric (void) strcat(p, "@"); 63966759Seric (void) strcat(p, up->udb_default); 64066759Seric if (tTd(28, 1)) 64166759Seric printf("udbmatch ==> %s\n", p); 64266759Seric return p; 64366759Seric break; 64466759Seric #endif /* HESIOD */ 64551951Seric } 64651951Seric } 64751951Seric 64851951Seric /* still nothing.... too bad */ 64951951Seric return NULL; 65051951Seric } 65151951Seric /* 65268521Seric ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 65368521Seric ** 65468521Seric ** Parameters: 65568521Seric ** map -- the map being queried. 65668521Seric ** name -- the name to look up. 65768521Seric ** av -- arguments to the map lookup. 65868521Seric ** statp -- to get any error status. 65968521Seric ** 66068521Seric ** Returns: 66168521Seric ** NULL if name not found in map. 66268521Seric ** The rewritten name otherwise. 66368521Seric */ 66468521Seric 66568521Seric char * 66668521Seric udb_map_lookup(map, name, av, statp) 66768521Seric MAP *map; 66868521Seric char *name; 66968521Seric char **av; 67068521Seric int *statp; 67168521Seric { 67268521Seric char *val; 67368521Seric 67468521Seric if (tTd(38, 20)) 67568521Seric printf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 67668521Seric val = udbmatch(name, map->map_file); 67768521Seric if (val == NULL) 67868521Seric return NULL; 67968521Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 68068521Seric return map_rewrite(map, name, strlen(name), NULL); 68168521Seric else 68268521Seric return map_rewrite(map, val, strlen(val), av); 68368521Seric } 68468521Seric /* 68551951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 68651951Seric ** 68751951Seric ** Parameters: 68851951Seric ** none. 68951951Seric ** 69051951Seric ** Returns: 69151951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 69251951Seric ** database due to a host being down or some similar 69351951Seric ** (recoverable) situation. 69451951Seric ** EX_OK -- otherwise. 69551951Seric ** 69651951Seric ** Side Effects: 69751951Seric ** Fills in the UdbEnts structure from UdbSpec. 69851951Seric */ 69951951Seric 70051363Seric #define MAXUDBOPTS 27 70151363Seric 70251953Seric int 70351362Seric _udbx_init() 70451362Seric { 70551362Seric register char *p; 70651362Seric int i; 70751362Seric register struct udbent *up; 70857232Seric char buf[BUFSIZ]; 70951360Seric 71051951Seric if (UdbInitialized) 71151951Seric return EX_OK; 71251951Seric 71351908Seric # ifdef UDB_DEFAULT_SPEC 71451908Seric if (UdbSpec == NULL) 71551908Seric UdbSpec = UDB_DEFAULT_SPEC; 71651908Seric # endif 71751908Seric 71851362Seric p = UdbSpec; 71951362Seric up = UdbEnts; 72051762Seric while (p != NULL) 72151362Seric { 72251362Seric char *spec; 72351362Seric auto int rcode; 72451363Seric int nopts; 72551362Seric int nmx; 72651362Seric register struct hostent *h; 72751362Seric char *mxhosts[MAXMXHOSTS + 1]; 72851363Seric struct option opts[MAXUDBOPTS + 1]; 72951362Seric 73051362Seric while (*p == ' ' || *p == '\t' || *p == ',') 73151362Seric p++; 73251362Seric if (*p == '\0') 73351362Seric break; 73451362Seric spec = p; 73556795Seric p = strchr(p, ','); 73651761Seric if (p != NULL) 73751362Seric *p++ = '\0'; 73851363Seric 73951363Seric /* extract options */ 74051363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 74151363Seric 74251363Seric /* 74351363Seric ** Decode database specification. 74451363Seric ** 74551363Seric ** In the sendmail tradition, the leading character 74651363Seric ** defines the semantics of the rest of the entry. 74751363Seric ** 74851363Seric ** +hostname -- send a datagram to the udb server 74951363Seric ** on host "hostname" asking for the 75051363Seric ** home mail server for this user. 75151363Seric ** *hostname -- similar to +hostname, except that the 75251363Seric ** hostname is searched as an MX record; 75351363Seric ** resulting hosts are searched as for 75451363Seric ** +mxhostname. If no MX host is found, 75551363Seric ** this is the same as +hostname. 75651363Seric ** @hostname -- forward email to the indicated host. 75751363Seric ** This should be the last in the list, 75851363Seric ** since it always matches the input. 75951363Seric ** /dbname -- search the named database on the local 76051363Seric ** host using the Berkeley db package. 76151363Seric */ 76251363Seric 76351362Seric switch (*spec) 76451360Seric { 76568786Seric #if 0 76651362Seric case '+': /* search remote database */ 76751363Seric case '*': /* search remote database (expand MX) */ 76851363Seric if (*spec == '*') 76951363Seric { 77066334Seric #if NAMED_BIND 77159273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 77257629Seric #else 77357629Seric mxhosts[0] = spec + 1; 77457629Seric nmx = 1; 77557629Seric rcode = 0; 77657629Seric #endif 77751363Seric if (tTd(28, 16)) 77851363Seric { 77951363Seric int i; 78051362Seric 78151363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 78251363Seric for (i = 0; i <= nmx; i++) 78351363Seric printf(" %s", mxhosts[i]); 78451363Seric printf("\n"); 78551363Seric } 78651363Seric } 78751363Seric else 78851362Seric { 78951363Seric nmx = 1; 79051363Seric mxhosts[0] = spec + 1; 79151362Seric } 79251362Seric 79351362Seric for (i = 0; i < nmx; i++) 79451362Seric { 79568693Seric h = sm_gethostbyname(mxhosts[i]); 79651362Seric if (h == NULL) 79751362Seric continue; 79851362Seric up->udb_type = UDB_REMOTE; 79951362Seric up->udb_addr.sin_family = h->h_addrtype; 80051362Seric bcopy(h->h_addr_list[0], 80151362Seric (char *) &up->udb_addr.sin_addr, 80267421Seric INADDRSZ); 80351362Seric up->udb_addr.sin_port = UdbPort; 80451362Seric up->udb_timeout = UdbTimeout; 80551362Seric up++; 80651362Seric } 80751362Seric 80851362Seric /* set up a datagram socket */ 80951362Seric if (UdbSock < 0) 81051362Seric { 81151362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 81251362Seric (void) fcntl(UdbSock, F_SETFD, 1); 81351362Seric } 81451362Seric break; 81568786Seric #endif 81651362Seric 81751362Seric case '@': /* forward to remote host */ 81851362Seric up->udb_type = UDB_FORWARD; 81951362Seric up->udb_fwdhost = spec + 1; 82051362Seric up++; 82151362Seric break; 82251362Seric 82368786Seric #ifdef HESIOD 82466759Seric case 'h': /* use hesiod */ 82566759Seric case 'H': 82666759Seric if (strcasecmp(spec, "hesiod") != 0) 82768786Seric goto badspec; 82866759Seric up->udb_type = UDB_HESIOD; 82966759Seric up++; 83068786Seric break; 83166759Seric #endif /* HESIOD */ 83266759Seric 83368786Seric #ifdef NEWDB 83451362Seric case '/': /* look up remote name */ 83551831Seric up->udb_dbname = spec; 83651923Seric errno = 0; 83751362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 83851362Seric if (up->udb_dbp == NULL) 83951923Seric { 84067763Seric if (tTd(28, 1)) 84167763Seric { 84267763Seric int saveerrno = errno; 84367763Seric 84467763Seric printf("dbopen(%s): %s", 84567763Seric spec, errstring(errno)); 84667763Seric errno = saveerrno; 84767763Seric } 84851923Seric if (errno != ENOENT && errno != EACCES) 84951951Seric { 85059615Seric #ifdef LOG 85159615Seric if (LogLevel > 2) 85259625Seric syslog(LOG_ERR, "dbopen(%s): %s", 85359625Seric spec, errstring(errno)); 85459615Seric #endif 85551951Seric up->udb_type = UDB_EOLIST; 85651951Seric goto tempfail; 85751951Seric } 85851362Seric break; 85951923Seric } 86051951Seric up->udb_type = UDB_DBFETCH; 86151362Seric up++; 86251362Seric break; 86368786Seric #endif 86468786Seric 86568786Seric default: 86668786Seric badspec: 86768786Seric syserr("Unknown UDB spec %s", spec); 86868786Seric break; 86951360Seric } 87051362Seric } 87151362Seric up->udb_type = UDB_EOLIST; 87251360Seric 87351362Seric if (tTd(28, 4)) 87451362Seric { 87551951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 87651360Seric { 87751362Seric switch (up->udb_type) 87851362Seric { 87951362Seric case UDB_REMOTE: 88051362Seric printf("REMOTE: addr %s, timeo %d\n", 88160494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 88251362Seric up->udb_timeout); 88351362Seric break; 88451362Seric 88551951Seric case UDB_DBFETCH: 886*69711Seric #ifdef NEWDB 88751951Seric printf("FETCH: file %s\n", 88851830Seric up->udb_dbname); 889*69711Seric #else 890*69711Seric printf("FETCH\n"); 891*69711Seric #endif 89251362Seric break; 89351362Seric 89451362Seric case UDB_FORWARD: 89551362Seric printf("FORWARD: host %s\n", 89651362Seric up->udb_fwdhost); 89751362Seric break; 89851362Seric 89966759Seric case UDB_HESIOD: 90066759Seric printf("HESIOD\n"); 90166759Seric break; 90266759Seric 90351362Seric default: 90451362Seric printf("UNKNOWN\n"); 90551362Seric break; 90651362Seric } 90751360Seric } 90850581Seric } 90951951Seric 91051951Seric UdbInitialized = TRUE; 91151955Seric errno = 0; 91251951Seric return EX_OK; 91351951Seric 91451951Seric /* 91551951Seric ** On temporary failure, back out anything we've already done 91651951Seric */ 91751951Seric 91851951Seric tempfail: 91968786Seric #ifdef NEWDB 92051951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 92151951Seric { 92251951Seric if (up->udb_type == UDB_DBFETCH) 92351951Seric { 92451951Seric (*up->udb_dbp->close)(up->udb_dbp); 92551951Seric } 92651951Seric } 92768786Seric #endif 92851951Seric return EX_TEMPFAIL; 92951360Seric } 93050581Seric 93151363Seric int 93251363Seric _udb_parsespec(udbspec, opt, maxopts) 93351363Seric char *udbspec; 93451363Seric struct option opt[]; 93551363Seric int maxopts; 93651363Seric { 93751363Seric register char *spec; 93851363Seric register char *spec_end; 93951363Seric register int optnum; 94051363Seric 94156795Seric spec_end = strchr(udbspec, ':'); 94251363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 94351363Seric { 94451363Seric register char *p; 94551363Seric 94658050Seric while (isascii(*spec) && isspace(*spec)) 94751363Seric spec++; 94856795Seric spec_end = strchr(spec, ':'); 94951363Seric if (spec_end != NULL) 95051363Seric *spec_end++ = '\0'; 95151363Seric 95251363Seric opt[optnum].name = spec; 95351363Seric opt[optnum].val = NULL; 95456795Seric p = strchr(spec, '='); 95551363Seric if (p != NULL) 95651363Seric opt[optnum].val = ++p; 95751363Seric } 95851363Seric return optnum; 95951363Seric } 96051363Seric 96166759Seric #ifdef HESIOD 96266759Seric 96366759Seric int 96466759Seric hes_udb_get(key, info) 96566759Seric DBT *key; 96666759Seric DBT *info; 96766759Seric { 96866759Seric char *name, *type; 96966759Seric char *p, **hp; 97068533Seric char kbuf[MAXKEY + 1]; 97166759Seric 97268533Seric strcpy(kbuf, key->data); 97368533Seric name = kbuf; 97466759Seric type = strchr(name, ':'); 97568544Seric if (type == NULL) 97666759Seric return 1; 97766759Seric *type++ = '\0'; 97866759Seric 97966759Seric if (tTd(28, 1)) 98066759Seric printf("hes_udb_get(%s, %s)\n", name, type); 98166759Seric 98266759Seric /* make the hesiod query */ 98366759Seric hp = hes_resolve(name, type); 984*69711Seric *--type = ':'; 98566759Seric if (hp == NULL) 98666759Seric { 98766759Seric /* network problem or timeout */ 98866759Seric if (hes_error() == HES_ER_NET) 98966759Seric return -1; 99066759Seric 99166759Seric return 1; 99266759Seric } 99366759Seric else 99466759Seric { 99566759Seric /* 99666759Seric ** If there are multiple matches, just return the 99769623Seric ** first one. 99866759Seric ** 99966759Seric ** XXX These should really be returned; for example, 100066759Seric ** XXX it is legal for :maildrop to be multi-valued. 100166759Seric */ 100266759Seric 100366759Seric info->data = hp[0]; 100466759Seric info->size = (size_t) strlen(info->data); 100566759Seric } 100666759Seric 100766759Seric return 0; 100866759Seric } 100966759Seric #endif /* HESIOD */ 101066759Seric 101151360Seric #else /* not USERDB */ 101251360Seric 101351923Seric int 101467982Seric udbexpand(a, sendq, aliaslevel, e) 101551360Seric ADDRESS *a; 101651360Seric ADDRESS **sendq; 101767982Seric int aliaslevel; 101855012Seric ENVELOPE *e; 101951360Seric { 102051923Seric return EX_OK; 102150581Seric } 102250581Seric 102350581Seric #endif /* USERDB */ 1024