udb.c revision 42575
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1988, 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#include "sendmail.h" 1438032Speter 1538032Speter#ifndef lint 1638032Speter#if USERDB 1742575Speterstatic char sccsid [] = "@(#)udb.c 8.70 (Berkeley) 12/21/1998 (with USERDB)"; 1838032Speter#else 1942575Speterstatic char sccsid [] = "@(#)udb.c 8.70 (Berkeley) 12/21/1998 (without USERDB)"; 2038032Speter#endif 2138032Speter#endif 2238032Speter 2338032Speter#if USERDB 2438032Speter 2538032Speter#include <errno.h> 2638032Speter 2738032Speter#ifdef NEWDB 2838032Speter# include <db.h> 2938032Speter# ifndef DB_VERSION_MAJOR 3038032Speter# define DB_VERSION_MAJOR 1 3138032Speter# endif 3238032Speter#else 3338032Speter# define DBT struct _data_base_thang_ 3438032SpeterDBT 3538032Speter{ 3638032Speter void *data; /* pointer to data */ 3738032Speter size_t size; /* length of data */ 3838032Speter}; 3938032Speter#endif 4038032Speter 4138032Speter/* 4238032Speter** UDB.C -- interface between sendmail and Berkeley User Data Base. 4338032Speter** 4438032Speter** This depends on the 4.4BSD db package. 4538032Speter*/ 4638032Speter 4738032Speter 4838032Speterstruct udbent 4938032Speter{ 5038032Speter char *udb_spec; /* string version of spec */ 5138032Speter int udb_type; /* type of entry */ 5242575Speter pid_t udb_pid; /* PID of process which opened db */ 5338032Speter char *udb_default; /* default host for outgoing mail */ 5438032Speter union 5538032Speter { 5638032Speter /* type UE_REMOTE -- do remote call for lookup */ 5738032Speter struct 5838032Speter { 5938032Speter struct sockaddr_in _udb_addr; /* address */ 6038032Speter int _udb_timeout; /* timeout */ 6138032Speter } udb_remote; 6238032Speter#define udb_addr udb_u.udb_remote._udb_addr 6338032Speter#define udb_timeout udb_u.udb_remote._udb_timeout 6438032Speter 6538032Speter /* type UE_FORWARD -- forward message to remote */ 6638032Speter struct 6738032Speter { 6838032Speter char *_udb_fwdhost; /* name of forward host */ 6938032Speter } udb_forward; 7038032Speter#define udb_fwdhost udb_u.udb_forward._udb_fwdhost 7138032Speter 7238032Speter#ifdef NEWDB 7338032Speter /* type UE_FETCH -- lookup in local database */ 7438032Speter struct 7538032Speter { 7638032Speter char *_udb_dbname; /* pathname of database */ 7738032Speter DB *_udb_dbp; /* open database ptr */ 7838032Speter } udb_lookup; 7938032Speter#define udb_dbname udb_u.udb_lookup._udb_dbname 8038032Speter#define udb_dbp udb_u.udb_lookup._udb_dbp 8138032Speter#endif 8238032Speter } udb_u; 8338032Speter}; 8438032Speter 8538032Speter#define UDB_EOLIST 0 /* end of list */ 8638032Speter#define UDB_SKIP 1 /* skip this entry */ 8738032Speter#define UDB_REMOTE 2 /* look up in remote database */ 8838032Speter#define UDB_DBFETCH 3 /* look up in local database */ 8938032Speter#define UDB_FORWARD 4 /* forward to remote host */ 9038032Speter#define UDB_HESIOD 5 /* look up via hesiod */ 9138032Speter 9238032Speter#define MAXUDBENT 10 /* maximum number of UDB entries */ 9338032Speter 9438032Speter 9542575Speterstruct udb_option 9638032Speter{ 9738032Speter char *name; 9838032Speter char *val; 9938032Speter}; 10038032Speter 10138032Speter#ifdef HESIOD 10238032Speterextern int hes_udb_get __P((DBT *, DBT *)); 10338032Speter#endif 10438032Speterextern int _udbx_init __P((ENVELOPE *)); 10538032Speter/* 10638032Speter** UDBEXPAND -- look up user in database and expand 10738032Speter** 10838032Speter** Parameters: 10938032Speter** a -- address to expand. 11038032Speter** sendq -- pointer to head of sendq to put the expansions in. 11138032Speter** aliaslevel -- the current alias nesting depth. 11238032Speter** e -- the current envelope. 11338032Speter** 11438032Speter** Returns: 11538032Speter** EX_TEMPFAIL -- if something "odd" happened -- probably due 11638032Speter** to accessing a file on an NFS server that is down. 11738032Speter** EX_OK -- otherwise. 11838032Speter** 11938032Speter** Side Effects: 12038032Speter** Modifies sendq. 12138032Speter*/ 12238032Speter 12338032Speterint UdbPort = 1616; 12438032Speterint UdbTimeout = 10; 12538032Speter 12638032Speterstruct udbent UdbEnts[MAXUDBENT + 1]; 12738032Speterint UdbSock = -1; 12838032Speterbool UdbInitialized = FALSE; 12938032Speter 13038032Speterint 13138032Speterudbexpand(a, sendq, aliaslevel, e) 13238032Speter register ADDRESS *a; 13338032Speter ADDRESS **sendq; 13438032Speter int aliaslevel; 13538032Speter register ENVELOPE *e; 13638032Speter{ 13738032Speter int i; 13838032Speter DBT key; 13938032Speter DBT info; 14038032Speter bool breakout; 14138032Speter register struct udbent *up; 14238032Speter int keylen; 14338032Speter int naddrs; 14442575Speter char *user; 14538032Speter char keybuf[MAXKEY]; 14638032Speter 14738032Speter bzero(&key, sizeof key); 14838032Speter bzero(&info, sizeof info); 14938032Speter 15038032Speter if (tTd(28, 1)) 15138032Speter printf("udbexpand(%s)\n", a->q_paddr); 15238032Speter 15338032Speter /* make certain we are supposed to send to this address */ 15438032Speter if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 15538032Speter return EX_OK; 15638032Speter e->e_to = a->q_paddr; 15738032Speter 15838032Speter /* on first call, locate the database */ 15938032Speter if (!UdbInitialized) 16038032Speter { 16138032Speter if (_udbx_init(e) == EX_TEMPFAIL) 16238032Speter return EX_TEMPFAIL; 16338032Speter } 16438032Speter 16538032Speter /* short circuit the process if no chance of a match */ 16638032Speter if (UdbSpec == NULL || UdbSpec[0] == '\0') 16738032Speter return EX_OK; 16838032Speter 16942575Speter /* extract user to do userdb matching on */ 17042575Speter user = a->q_user; 17142575Speter 17238032Speter /* short circuit name begins with '\\' since it can't possibly match */ 17342575Speter /* (might want to treat this as unquoted instead) */ 17442575Speter if (user[0] == '\\') 17538032Speter return EX_OK; 17638032Speter 17738032Speter /* if name is too long, assume it won't match */ 17842575Speter if (strlen(user) > (SIZE_T) sizeof keybuf - 12) 17938032Speter return EX_OK; 18038032Speter 18138032Speter /* if name begins with a colon, it indicates our metadata */ 18242575Speter if (user[0] == ':') 18338032Speter return EX_OK; 18438032Speter 18538032Speter /* build actual database key */ 18642575Speter (void) strcpy(keybuf, user); 18738032Speter (void) strcat(keybuf, ":maildrop"); 18838032Speter keylen = strlen(keybuf); 18938032Speter 19038032Speter breakout = FALSE; 19138032Speter for (up = UdbEnts; !breakout; up++) 19238032Speter { 19338032Speter char *user; 19438032Speter int usersize; 19538032Speter int userleft; 19638032Speter char userbuf[MEMCHUNKSIZE]; 19738032Speter#if defined(HESIOD) && defined(HES_GETMAILHOST) 19838032Speter char pobuf[MAXNAME]; 19938032Speter#endif 20038032Speter#if defined(NEWDB) && DB_VERSION_MAJOR > 1 20138032Speter DBC *dbc = NULL; 20238032Speter#endif 20338032Speter 20438032Speter user = userbuf; 20538032Speter userbuf[0] = '\0'; 20638032Speter usersize = sizeof userbuf; 20738032Speter userleft = sizeof userbuf - 1; 20838032Speter 20938032Speter /* 21038032Speter ** Select action based on entry type. 21138032Speter ** 21238032Speter ** On dropping out of this switch, "class" should 21338032Speter ** explain the type of the data, and "user" should 21438032Speter ** contain the user information. 21538032Speter */ 21638032Speter 21738032Speter switch (up->udb_type) 21838032Speter { 21938032Speter#ifdef NEWDB 22038032Speter case UDB_DBFETCH: 22138032Speter key.data = keybuf; 22238032Speter key.size = keylen; 22338032Speter if (tTd(28, 80)) 22438032Speter printf("udbexpand: trying %s (%d) via db\n", 22538032Speter keybuf, keylen); 22638032Speter#if DB_VERSION_MAJOR < 2 22738032Speter i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 22838032Speter#else 22938032Speter i = 0; 23038032Speter if (dbc == NULL && 23142575Speter# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6 23238032Speter (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 23342575Speter NULL, &dbc, 0)) != 0) 23442575Speter# else 23542575Speter (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 23638032Speter NULL, &dbc)) != 0) 23742575Speter# endif 23838032Speter i = -1; 23938032Speter if (i != 0 || dbc == NULL || 24038032Speter (errno = dbc->c_get(dbc, &key, 24138032Speter &info, DB_SET)) != 0) 24238032Speter i = 1; 24338032Speter#endif 24438032Speter if (i > 0 || info.size <= 0) 24538032Speter { 24638032Speter if (tTd(28, 2)) 24738032Speter printf("udbexpand: no match on %s (%d)\n", 24838032Speter keybuf, keylen); 24938032Speter#if DB_VERSION_MAJOR > 1 25038032Speter if (dbc != NULL) 25138032Speter { 25238032Speter (void) dbc->c_close(dbc); 25338032Speter dbc = NULL; 25438032Speter } 25538032Speter#endif 25638032Speter break; 25738032Speter } 25838032Speter if (tTd(28, 80)) 25938032Speter printf("udbexpand: match %.*s: %.*s\n", 26038032Speter (int) key.size, (char *) key.data, 26138032Speter (int) info.size, (char *) info.data); 26238032Speter 26338032Speter a->q_flags &= ~QSELFREF; 26438032Speter while (i == 0 && key.size == keylen && 26538032Speter bcmp(key.data, keybuf, keylen) == 0) 26638032Speter { 26738032Speter char *p; 26838032Speter 26938032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 27038032Speter { 27138032Speter a->q_flags |= QVERIFIED; 27238032Speter#if DB_VERSION_MAJOR > 1 27338032Speter if (dbc != NULL) 27438032Speter { 27538032Speter (void) dbc->c_close(dbc); 27638032Speter dbc = NULL; 27738032Speter } 27838032Speter#endif 27938032Speter return EX_OK; 28038032Speter } 28138032Speter 28238032Speter breakout = TRUE; 28338032Speter if (info.size >= userleft - 1) 28438032Speter { 28538032Speter char *nuser; 28638032Speter int size = MEMCHUNKSIZE; 28738032Speter 28838032Speter if (info.size > MEMCHUNKSIZE) 28938032Speter size = info.size; 29038032Speter nuser = xalloc(usersize + size); 29138032Speter 29238032Speter bcopy(user, nuser, usersize); 29338032Speter if (user != userbuf) 29438032Speter free(user); 29538032Speter user = nuser; 29638032Speter usersize += size; 29738032Speter userleft += size; 29838032Speter } 29938032Speter p = &user[strlen(user)]; 30038032Speter if (p != user) 30138032Speter { 30238032Speter *p++ = ','; 30338032Speter userleft--; 30438032Speter } 30538032Speter bcopy(info.data, p, info.size); 30638032Speter p[info.size] = '\0'; 30738032Speter userleft -= info.size; 30838032Speter 30938032Speter /* get the next record */ 31038032Speter#if DB_VERSION_MAJOR < 2 31138032Speter i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 31238032Speter#else 31338032Speter i = 0; 31438032Speter if ((errno = dbc->c_get(dbc, &key, 31538032Speter &info, DB_NEXT)) != 0) 31638032Speter i = 1; 31738032Speter#endif 31838032Speter } 31938032Speter 32038032Speter#if DB_VERSION_MAJOR > 1 32138032Speter if (dbc != NULL) 32238032Speter { 32338032Speter (void) dbc->c_close(dbc); 32438032Speter dbc = NULL; 32538032Speter } 32638032Speter#endif 32738032Speter 32838032Speter /* if nothing ever matched, try next database */ 32938032Speter if (!breakout) 33038032Speter break; 33138032Speter 33238032Speter message("expanded to %s", user); 33338032Speter if (LogLevel >= 10) 33438032Speter sm_syslog(LOG_INFO, e->e_id, 33538032Speter "expand %.100s => %s", 33638032Speter e->e_to, 33738032Speter shortenstring(user, MAXSHORTSTR)); 33838032Speter naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 33938032Speter if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 34038032Speter { 34138032Speter if (tTd(28, 5)) 34238032Speter { 34338032Speter printf("udbexpand: QDONTSEND "); 34438032Speter printaddr(a, FALSE); 34538032Speter } 34638032Speter a->q_flags |= QDONTSEND; 34738032Speter } 34838032Speter if (i < 0) 34938032Speter { 35038032Speter syserr("udbexpand: db-get %.*s stat %d", 35138032Speter (int) key.size, (char *) key.data, i); 35238032Speter return EX_TEMPFAIL; 35338032Speter } 35438032Speter 35538032Speter /* 35638032Speter ** If this address has a -request address, reflect 35738032Speter ** it into the envelope. 35838032Speter */ 35938032Speter 36038032Speter bzero(&key, sizeof key); 36138032Speter bzero(&info, sizeof info); 36238032Speter (void) strcpy(keybuf, a->q_user); 36338032Speter (void) strcat(keybuf, ":mailsender"); 36438032Speter keylen = strlen(keybuf); 36538032Speter key.data = keybuf; 36638032Speter key.size = keylen; 36738032Speter 36838032Speter#if DB_VERSION_MAJOR < 2 36938032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 37038032Speter#else 37138032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 37238032Speter &key, &info, 0); 37338032Speter#endif 37438032Speter if (i != 0 || info.size <= 0) 37538032Speter break; 37638032Speter a->q_owner = xalloc(info.size + 1); 37738032Speter bcopy(info.data, a->q_owner, info.size); 37838032Speter a->q_owner[info.size] = '\0'; 37938032Speter 38038032Speter /* announce delivery; NORECEIPT bit set later */ 38138032Speter if (e->e_xfp != NULL) 38238032Speter { 38338032Speter fprintf(e->e_xfp, 38438032Speter "Message delivered to mailing list %s\n", 38538032Speter a->q_paddr); 38638032Speter } 38738032Speter e->e_flags |= EF_SENDRECEIPT; 38838032Speter a->q_flags |= QDELIVERED|QEXPANDED; 38938032Speter break; 39038032Speter#endif 39138032Speter 39238032Speter#ifdef HESIOD 39338032Speter case UDB_HESIOD: 39438032Speter key.data = keybuf; 39538032Speter key.size = keylen; 39638032Speter if (tTd(28, 80)) 39738032Speter printf("udbexpand: trying %s (%d) via hesiod\n", 39838032Speter keybuf, keylen); 39938032Speter /* look up the key via hesiod */ 40038032Speter i = hes_udb_get(&key, &info); 40138032Speter if (i < 0) 40238032Speter { 40338032Speter syserr("udbexpand: hesiod-get %.*s stat %d", 40438032Speter (int) key.size, (char *) key.data, i); 40538032Speter return EX_TEMPFAIL; 40638032Speter } 40738032Speter else if (i > 0 || info.size <= 0) 40838032Speter { 40938032Speter#if HES_GETMAILHOST 41038032Speter struct hes_postoffice *hp; 41138032Speter#endif 41238032Speter 41338032Speter if (tTd(28, 2)) 41438032Speter printf("udbexpand: no match on %s (%d)\n", 41538032Speter (char *) keybuf, (int) keylen); 41638032Speter#if HES_GETMAILHOST 41738032Speter if (tTd(28, 8)) 41838032Speter printf(" ... trying hes_getmailhost(%s)\n", 41938032Speter a->q_user); 42038032Speter hp = hes_getmailhost(a->q_user); 42138032Speter if (hp == NULL) 42238032Speter { 42338032Speter if (hes_error() == HES_ER_NET) 42438032Speter { 42538032Speter syserr("udbexpand: hesiod-getmail %s stat %d", 42638032Speter a->q_user, hes_error()); 42738032Speter return EX_TEMPFAIL; 42838032Speter } 42938032Speter if (tTd(28, 2)) 43038032Speter printf("hes_getmailhost(%s): %d\n", 43138032Speter a->q_user, hes_error()); 43238032Speter break; 43338032Speter } 43438032Speter if (strlen(hp->po_name) + strlen(hp->po_host) > 43538032Speter sizeof pobuf - 2) 43638032Speter { 43738032Speter if (tTd(28, 2)) 43838032Speter printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n", 43938032Speter a->q_user, 44038032Speter hp->po_name, 44138032Speter hp->po_host); 44238032Speter break; 44338032Speter } 44438032Speter info.data = pobuf; 44538032Speter snprintf(pobuf, sizeof pobuf, "%s@%s", 44638032Speter hp->po_name, hp->po_host); 44738032Speter info.size = strlen(info.data); 44838032Speter#else 44938032Speter break; 45038032Speter#endif 45138032Speter } 45238032Speter if (tTd(28, 80)) 45338032Speter printf("udbexpand: match %.*s: %.*s\n", 45438032Speter (int) key.size, (char *) key.data, 45538032Speter (int) info.size, (char *) info.data); 45638032Speter a->q_flags &= ~QSELFREF; 45738032Speter 45838032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 45938032Speter { 46038032Speter a->q_flags |= QVERIFIED; 46138032Speter return EX_OK; 46238032Speter } 46338032Speter 46438032Speter breakout = TRUE; 46538032Speter if (info.size >= usersize) 46638032Speter user = xalloc(info.size + 1); 46738032Speter bcopy(info.data, user, info.size); 46838032Speter user[info.size] = '\0'; 46938032Speter 47038032Speter message("hesioded to %s", user); 47138032Speter if (LogLevel >= 10) 47238032Speter sm_syslog(LOG_INFO, e->e_id, 47338032Speter "hesiod %.100s => %s", 47438032Speter e->e_to, 47538032Speter shortenstring(user, MAXSHORTSTR)); 47638032Speter naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 47738032Speter 47838032Speter if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 47938032Speter { 48038032Speter if (tTd(28, 5)) 48138032Speter { 48238032Speter printf("udbexpand: QDONTSEND "); 48338032Speter printaddr(a, FALSE); 48438032Speter } 48538032Speter a->q_flags |= QDONTSEND; 48638032Speter } 48738032Speter 48838032Speter /* 48938032Speter ** If this address has a -request address, reflect 49038032Speter ** it into the envelope. 49138032Speter */ 49238032Speter 49338032Speter (void) strcpy(keybuf, a->q_user); 49438032Speter (void) strcat(keybuf, ":mailsender"); 49538032Speter keylen = strlen(keybuf); 49638032Speter key.data = keybuf; 49738032Speter key.size = keylen; 49838032Speter i = hes_udb_get(&key, &info); 49938032Speter if (i != 0 || info.size <= 0) 50038032Speter break; 50138032Speter a->q_owner = xalloc(info.size + 1); 50238032Speter bcopy(info.data, a->q_owner, info.size); 50338032Speter a->q_owner[info.size] = '\0'; 50438032Speter break; 50538032Speter#endif /* HESIOD */ 50638032Speter 50738032Speter case UDB_REMOTE: 50838032Speter /* not yet implemented */ 50938032Speter break; 51038032Speter 51138032Speter case UDB_FORWARD: 51238032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 51338032Speter return EX_OK; 51438032Speter i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 51538032Speter if (i >= usersize) 51638032Speter { 51738032Speter usersize = i + 1; 51838032Speter user = xalloc(usersize); 51938032Speter } 52038032Speter (void) snprintf(user, usersize, "%s@%s", 52138032Speter a->q_user, up->udb_fwdhost); 52238032Speter message("expanded to %s", user); 52338032Speter a->q_flags &= ~QSELFREF; 52438032Speter naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 52538032Speter if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 52638032Speter { 52738032Speter if (tTd(28, 5)) 52838032Speter { 52938032Speter printf("udbexpand: QDONTSEND "); 53038032Speter printaddr(a, FALSE); 53138032Speter } 53238032Speter a->q_flags |= QDONTSEND; 53338032Speter } 53438032Speter breakout = TRUE; 53538032Speter break; 53638032Speter 53738032Speter case UDB_EOLIST: 53838032Speter breakout = TRUE; 53938032Speter break; 54038032Speter 54138032Speter default: 54238032Speter /* unknown entry type */ 54338032Speter break; 54438032Speter } 54538032Speter if (user != userbuf) 54638032Speter free(user); 54738032Speter } 54838032Speter return EX_OK; 54938032Speter} 55038032Speter/* 55138032Speter** UDBSENDER -- return canonical external name of sender, given local name 55238032Speter** 55338032Speter** Parameters: 55438032Speter** sender -- the name of the sender on the local machine. 55538032Speter** 55638032Speter** Returns: 55738032Speter** The external name for this sender, if derivable from the 55838032Speter** database. 55938032Speter** NULL -- if nothing is changed from the database. 56038032Speter** 56138032Speter** Side Effects: 56238032Speter** none. 56338032Speter*/ 56438032Speter 56538032Speterchar * 56638032Speterudbsender(sender) 56738032Speter char *sender; 56838032Speter{ 56938032Speter extern char *udbmatch __P((char *, char *)); 57038032Speter 57138032Speter return udbmatch(sender, "mailname"); 57238032Speter} 57338032Speter 57438032Speter 57538032Speterchar * 57638032Speterudbmatch(user, field) 57738032Speter char *user; 57838032Speter char *field; 57938032Speter{ 58038032Speter register char *p; 58138032Speter register struct udbent *up; 58238032Speter int i; 58338032Speter int keylen; 58438032Speter DBT key, info; 58538032Speter char keybuf[MAXKEY]; 58638032Speter 58738032Speter if (tTd(28, 1)) 58838032Speter printf("udbmatch(%s, %s)\n", user, field); 58938032Speter 59038032Speter if (!UdbInitialized) 59138032Speter { 59238032Speter if (_udbx_init(CurEnv) == EX_TEMPFAIL) 59338032Speter return NULL; 59438032Speter } 59538032Speter 59638032Speter /* short circuit if no spec */ 59738032Speter if (UdbSpec == NULL || UdbSpec[0] == '\0') 59838032Speter return NULL; 59938032Speter 60038032Speter /* short circuit name begins with '\\' since it can't possibly match */ 60138032Speter if (user[0] == '\\') 60238032Speter return NULL; 60338032Speter 60438032Speter /* long names can never match and are a pain to deal with */ 60538032Speter i = strlen(field); 60638032Speter if (i < sizeof "maildrop") 60738032Speter i = sizeof "maildrop"; 60838032Speter if ((strlen(user) + i) > sizeof keybuf - 4) 60938032Speter return NULL; 61038032Speter 61138032Speter /* names beginning with colons indicate metadata */ 61238032Speter if (user[0] == ':') 61338032Speter return NULL; 61438032Speter 61538032Speter /* build database key */ 61638032Speter (void) strcpy(keybuf, user); 61738032Speter (void) strcat(keybuf, ":"); 61838032Speter (void) strcat(keybuf, field); 61938032Speter keylen = strlen(keybuf); 62038032Speter 62138032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 62238032Speter { 62338032Speter /* 62438032Speter ** Select action based on entry type. 62538032Speter */ 62638032Speter 62738032Speter switch (up->udb_type) 62838032Speter { 62938032Speter#ifdef NEWDB 63038032Speter case UDB_DBFETCH: 63138032Speter bzero(&key, sizeof key); 63238032Speter bzero(&info, sizeof info); 63338032Speter key.data = keybuf; 63438032Speter key.size = keylen; 63538032Speter#if DB_VERSION_MAJOR < 2 63638032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 63738032Speter#else 63838032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 63938032Speter &key, &info, 0); 64038032Speter#endif 64138032Speter if (i != 0 || info.size <= 0) 64238032Speter { 64338032Speter if (tTd(28, 2)) 64438032Speter printf("udbmatch: no match on %s (%d) via db\n", 64538032Speter keybuf, keylen); 64638032Speter continue; 64738032Speter } 64838032Speter 64938032Speter p = xalloc(info.size + 1); 65038032Speter bcopy(info.data, p, info.size); 65138032Speter p[info.size] = '\0'; 65238032Speter if (tTd(28, 1)) 65338032Speter printf("udbmatch ==> %s\n", p); 65438032Speter return p; 65538032Speter#endif 65638032Speter 65738032Speter#ifdef HESIOD 65838032Speter case UDB_HESIOD: 65938032Speter key.data = keybuf; 66038032Speter key.size = keylen; 66138032Speter i = hes_udb_get(&key, &info); 66238032Speter if (i != 0 || info.size <= 0) 66338032Speter { 66438032Speter if (tTd(28, 2)) 66538032Speter printf("udbmatch: no match on %s (%d) via hesiod\n", 66638032Speter keybuf, keylen); 66738032Speter continue; 66838032Speter } 66938032Speter 67038032Speter p = xalloc(info.size + 1); 67138032Speter bcopy(info.data, p, info.size); 67238032Speter p[info.size] = '\0'; 67338032Speter if (tTd(28, 1)) 67438032Speter printf("udbmatch ==> %s\n", p); 67538032Speter return p; 67638032Speter#endif /* HESIOD */ 67738032Speter } 67838032Speter } 67938032Speter 68038032Speter if (strcmp(field, "mailname") != 0) 68138032Speter return NULL; 68238032Speter 68338032Speter /* 68438032Speter ** Nothing yet. Search again for a default case. But only 68538032Speter ** use it if we also have a forward (:maildrop) pointer already 68638032Speter ** in the database. 68738032Speter */ 68838032Speter 68938032Speter /* build database key */ 69038032Speter (void) strcpy(keybuf, user); 69138032Speter (void) strcat(keybuf, ":maildrop"); 69238032Speter keylen = strlen(keybuf); 69338032Speter 69438032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 69538032Speter { 69638032Speter switch (up->udb_type) 69738032Speter { 69838032Speter#ifdef NEWDB 69938032Speter case UDB_DBFETCH: 70038032Speter /* get the default case for this database */ 70138032Speter if (up->udb_default == NULL) 70238032Speter { 70338032Speter bzero(&key, sizeof key); 70438032Speter bzero(&info, sizeof info); 70538032Speter key.data = ":default:mailname"; 70638032Speter key.size = strlen(key.data); 70738032Speter#if DB_VERSION_MAJOR < 2 70838032Speter i = (*up->udb_dbp->get)(up->udb_dbp, 70938032Speter &key, &info, 0); 71038032Speter#else 71138032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, 71238032Speter NULL, &key, 71338032Speter &info, 0); 71438032Speter#endif 71538032Speter if (i != 0 || info.size <= 0) 71638032Speter { 71738032Speter /* no default case */ 71838032Speter up->udb_default = ""; 71938032Speter continue; 72038032Speter } 72138032Speter 72238032Speter /* save the default case */ 72338032Speter up->udb_default = xalloc(info.size + 1); 72438032Speter bcopy(info.data, up->udb_default, info.size); 72538032Speter up->udb_default[info.size] = '\0'; 72638032Speter } 72738032Speter else if (up->udb_default[0] == '\0') 72838032Speter continue; 72938032Speter 73038032Speter /* we have a default case -- verify user:maildrop */ 73138032Speter bzero(&key, sizeof key); 73238032Speter bzero(&info, sizeof info); 73338032Speter key.data = keybuf; 73438032Speter key.size = keylen; 73538032Speter#if DB_VERSION_MAJOR < 2 73638032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 73738032Speter#else 73838032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 73938032Speter &key, &info, 0); 74038032Speter#endif 74138032Speter if (i != 0 || info.size <= 0) 74238032Speter { 74338032Speter /* nope -- no aliasing for this user */ 74438032Speter continue; 74538032Speter } 74638032Speter 74738032Speter /* they exist -- build the actual address */ 74838032Speter p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 74938032Speter (void) strcpy(p, user); 75038032Speter (void) strcat(p, "@"); 75138032Speter (void) strcat(p, up->udb_default); 75238032Speter if (tTd(28, 1)) 75338032Speter printf("udbmatch ==> %s\n", p); 75438032Speter return p; 75538032Speter#endif 75638032Speter 75738032Speter#ifdef HESIOD 75838032Speter case UDB_HESIOD: 75938032Speter /* get the default case for this database */ 76038032Speter if (up->udb_default == NULL) 76138032Speter { 76238032Speter key.data = ":default:mailname"; 76338032Speter key.size = strlen(key.data); 76438032Speter i = hes_udb_get(&key, &info); 76538032Speter 76638032Speter if (i != 0 || info.size <= 0) 76738032Speter { 76838032Speter /* no default case */ 76938032Speter up->udb_default = ""; 77038032Speter continue; 77138032Speter } 77238032Speter 77338032Speter /* save the default case */ 77438032Speter up->udb_default = xalloc(info.size + 1); 77538032Speter bcopy(info.data, up->udb_default, info.size); 77638032Speter up->udb_default[info.size] = '\0'; 77738032Speter } 77838032Speter else if (up->udb_default[0] == '\0') 77938032Speter continue; 78038032Speter 78138032Speter /* we have a default case -- verify user:maildrop */ 78238032Speter key.data = keybuf; 78338032Speter key.size = keylen; 78438032Speter i = hes_udb_get(&key, &info); 78538032Speter if (i != 0 || info.size <= 0) 78638032Speter { 78738032Speter /* nope -- no aliasing for this user */ 78838032Speter continue; 78938032Speter } 79038032Speter 79138032Speter /* they exist -- build the actual address */ 79238032Speter p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 79338032Speter (void) strcpy(p, user); 79438032Speter (void) strcat(p, "@"); 79538032Speter (void) strcat(p, up->udb_default); 79638032Speter if (tTd(28, 1)) 79738032Speter printf("udbmatch ==> %s\n", p); 79838032Speter return p; 79938032Speter break; 80038032Speter#endif /* HESIOD */ 80138032Speter } 80238032Speter } 80338032Speter 80438032Speter /* still nothing.... too bad */ 80538032Speter return NULL; 80638032Speter} 80738032Speter/* 80838032Speter** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 80938032Speter** 81038032Speter** Parameters: 81138032Speter** map -- the map being queried. 81238032Speter** name -- the name to look up. 81338032Speter** av -- arguments to the map lookup. 81438032Speter** statp -- to get any error status. 81538032Speter** 81638032Speter** Returns: 81738032Speter** NULL if name not found in map. 81838032Speter** The rewritten name otherwise. 81938032Speter*/ 82038032Speter 82138032Speter/* ARGSUSED3 */ 82238032Speterchar * 82338032Speterudb_map_lookup(map, name, av, statp) 82438032Speter MAP *map; 82538032Speter char *name; 82638032Speter char **av; 82738032Speter int *statp; 82838032Speter{ 82938032Speter char *val; 83038032Speter char *key; 83138032Speter char keybuf[MAXNAME + 1]; 83238032Speter 83338032Speter if (tTd(28, 20) || tTd(38, 20)) 83438032Speter printf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 83538032Speter 83638032Speter if (bitset(MF_NOFOLDCASE, map->map_mflags)) 83738032Speter { 83838032Speter key = name; 83938032Speter } 84038032Speter else 84138032Speter { 84238032Speter int keysize = strlen(name); 84338032Speter 84438032Speter if (keysize > sizeof keybuf - 1) 84538032Speter keysize = sizeof keybuf - 1; 84638032Speter bcopy(name, keybuf, keysize); 84738032Speter keybuf[keysize] = '\0'; 84838032Speter makelower(keybuf); 84938032Speter key = keybuf; 85038032Speter } 85138032Speter val = udbmatch(key, map->map_file); 85238032Speter if (val == NULL) 85338032Speter return NULL; 85438032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 85538032Speter return map_rewrite(map, name, strlen(name), NULL); 85638032Speter else 85738032Speter return map_rewrite(map, val, strlen(val), av); 85838032Speter} 85938032Speter/* 86038032Speter** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 86138032Speter** 86238032Speter** Parameters: 86338032Speter** e -- the current envelope. 86438032Speter** 86538032Speter** Returns: 86638032Speter** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 86738032Speter** database due to a host being down or some similar 86838032Speter** (recoverable) situation. 86938032Speter** EX_OK -- otherwise. 87038032Speter** 87138032Speter** Side Effects: 87238032Speter** Fills in the UdbEnts structure from UdbSpec. 87338032Speter*/ 87438032Speter 87538032Speter#define MAXUDBOPTS 27 87638032Speter 87738032Speterint 87838032Speter_udbx_init(e) 87938032Speter ENVELOPE *e; 88038032Speter{ 88138032Speter int ents = 0; 88238032Speter register char *p; 88338032Speter register struct udbent *up; 88438032Speter 88538032Speter if (UdbInitialized) 88638032Speter return EX_OK; 88738032Speter 88838032Speter# ifdef UDB_DEFAULT_SPEC 88938032Speter if (UdbSpec == NULL) 89038032Speter UdbSpec = UDB_DEFAULT_SPEC; 89138032Speter# endif 89238032Speter 89338032Speter p = UdbSpec; 89438032Speter up = UdbEnts; 89538032Speter while (p != NULL) 89638032Speter { 89738032Speter char *spec; 89838032Speter int l; 89938032Speter# if 0 90038032Speter auto int rcode; 90138032Speter int nmx; 90238032Speter int i; 90338032Speter register struct hostent *h; 90438032Speter char *mxhosts[MAXMXHOSTS + 1]; 90538032Speter# endif 90642575Speter struct udb_option opts[MAXUDBOPTS + 1]; 90742575Speter extern int _udb_parsespec __P((char *, struct udb_option [], int)); 90838032Speter 90938032Speter while (*p == ' ' || *p == '\t' || *p == ',') 91038032Speter p++; 91138032Speter if (*p == '\0') 91238032Speter break; 91338032Speter spec = p; 91438032Speter p = strchr(p, ','); 91538032Speter if (p != NULL) 91638032Speter *p++ = '\0'; 91738032Speter 91838032Speter if (ents >= MAXUDBENT) 91938032Speter { 92038032Speter syserr("Maximum number of UDB entries exceeded"); 92138032Speter break; 92238032Speter } 92338032Speter 92438032Speter /* extract options */ 92538032Speter (void) _udb_parsespec(spec, opts, MAXUDBOPTS); 92638032Speter 92738032Speter /* 92838032Speter ** Decode database specification. 92938032Speter ** 93038032Speter ** In the sendmail tradition, the leading character 93138032Speter ** defines the semantics of the rest of the entry. 93238032Speter ** 93338032Speter ** +hostname -- send a datagram to the udb server 93438032Speter ** on host "hostname" asking for the 93538032Speter ** home mail server for this user. 93638032Speter ** *hostname -- similar to +hostname, except that the 93738032Speter ** hostname is searched as an MX record; 93838032Speter ** resulting hosts are searched as for 93938032Speter ** +mxhostname. If no MX host is found, 94038032Speter ** this is the same as +hostname. 94138032Speter ** @hostname -- forward email to the indicated host. 94238032Speter ** This should be the last in the list, 94338032Speter ** since it always matches the input. 94438032Speter ** /dbname -- search the named database on the local 94538032Speter ** host using the Berkeley db package. 94638032Speter ** Hesiod -- search the named database with BIND 94738032Speter ** using the MIT Hesiod package. 94838032Speter */ 94938032Speter 95038032Speter switch (*spec) 95138032Speter { 95238032Speter#if 0 95338032Speter case '+': /* search remote database */ 95438032Speter case '*': /* search remote database (expand MX) */ 95538032Speter if (*spec == '*') 95638032Speter { 95738032Speter#if NAMED_BIND 95838032Speter nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 95938032Speter#else 96038032Speter mxhosts[0] = spec + 1; 96138032Speter nmx = 1; 96238032Speter rcode = 0; 96338032Speter#endif 96438032Speter if (tTd(28, 16)) 96538032Speter { 96638032Speter int i; 96738032Speter 96838032Speter printf("getmxrr(%s): %d", spec + 1, nmx); 96938032Speter for (i = 0; i <= nmx; i++) 97038032Speter printf(" %s", mxhosts[i]); 97138032Speter printf("\n"); 97238032Speter } 97338032Speter } 97438032Speter else 97538032Speter { 97638032Speter nmx = 1; 97738032Speter mxhosts[0] = spec + 1; 97838032Speter } 97938032Speter 98038032Speter for (i = 0; i < nmx; i++) 98138032Speter { 98238032Speter h = sm_gethostbyname(mxhosts[i]); 98338032Speter if (h == NULL) 98438032Speter continue; 98538032Speter up->udb_type = UDB_REMOTE; 98642575Speter up->udb_pid = getpid(); 98738032Speter up->udb_addr.sin_family = h->h_addrtype; 98838032Speter bcopy(h->h_addr_list[0], 98938032Speter (char *) &up->udb_addr.sin_addr, 99038032Speter INADDRSZ); 99138032Speter up->udb_addr.sin_port = UdbPort; 99238032Speter up->udb_timeout = UdbTimeout; 99338032Speter ents++; 99438032Speter up++; 99538032Speter } 99638032Speter 99738032Speter /* set up a datagram socket */ 99838032Speter if (UdbSock < 0) 99938032Speter { 100038032Speter UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 100138032Speter (void) fcntl(UdbSock, F_SETFD, 1); 100238032Speter } 100338032Speter break; 100438032Speter#endif 100538032Speter 100638032Speter case '@': /* forward to remote host */ 100738032Speter up->udb_type = UDB_FORWARD; 100842575Speter up->udb_pid = getpid(); 100938032Speter up->udb_fwdhost = spec + 1; 101038032Speter ents++; 101138032Speter up++; 101238032Speter break; 101338032Speter 101438032Speter#ifdef HESIOD 101538032Speter case 'h': /* use hesiod */ 101638032Speter case 'H': 101738032Speter if (strcasecmp(spec, "hesiod") != 0) 101838032Speter goto badspec; 101938032Speter up->udb_type = UDB_HESIOD; 102042575Speter up->udb_pid = getpid(); 102138032Speter ents++; 102238032Speter up++; 102338032Speter break; 102438032Speter#endif /* HESIOD */ 102538032Speter 102638032Speter#ifdef NEWDB 102738032Speter case '/': /* look up remote name */ 102838032Speter l = strlen(spec); 102938032Speter if (l > 3 && strcmp(&spec[l - 3], ".db") == 0) 103038032Speter { 103138032Speter up->udb_dbname = spec; 103238032Speter } 103338032Speter else 103438032Speter { 103538032Speter up->udb_dbname = xalloc(l + 4); 103638032Speter strcpy(up->udb_dbname, spec); 103738032Speter strcat(up->udb_dbname, ".db"); 103838032Speter } 103938032Speter errno = 0; 104038032Speter#if DB_VERSION_MAJOR < 2 104138032Speter up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, 104238032Speter 0644, DB_BTREE, NULL); 104338032Speter#else 104438032Speter up->udb_dbp = NULL; 104538032Speter errno = db_open(up->udb_dbname, DB_BTREE, DB_RDONLY, 104638032Speter 0644, NULL, NULL, &up->udb_dbp); 104738032Speter#endif 104838032Speter if (up->udb_dbp == NULL) 104938032Speter { 105038032Speter if (tTd(28, 1)) 105138032Speter { 105238032Speter int saveerrno = errno; 105338032Speter 105438032Speter#if DB_VERSION_MAJOR < 2 105538032Speter printf("dbopen(%s): %s\n", 105638032Speter#else 105738032Speter printf("db_open(%s): %s\n", 105838032Speter#endif 105938032Speter up->udb_dbname, 106038032Speter errstring(errno)); 106138032Speter errno = saveerrno; 106238032Speter } 106338032Speter if (errno != ENOENT && errno != EACCES) 106438032Speter { 106538032Speter if (LogLevel > 2) 106638032Speter sm_syslog(LOG_ERR, e->e_id, 106738032Speter#if DB_VERSION_MAJOR < 2 106838032Speter "dbopen(%s): %s", 106938032Speter#else 107038032Speter "db_open(%s): %s", 107138032Speter#endif 107238032Speter up->udb_dbname, 107338032Speter errstring(errno)); 107438032Speter up->udb_type = UDB_EOLIST; 107538032Speter if (up->udb_dbname != spec) 107638032Speter free(up->udb_dbname); 107738032Speter goto tempfail; 107838032Speter } 107938032Speter if (up->udb_dbname != spec) 108038032Speter free(up->udb_dbname); 108138032Speter break; 108238032Speter } 108342575Speter if (tTd(28, 1)) 108442575Speter { 108542575Speter#if DB_VERSION_MAJOR < 2 108642575Speter printf("_udbx_init: dbopen(%s)\n", 108742575Speter#else 108842575Speter printf("_udbx_init: db_open(%s)\n", 108942575Speter#endif 109042575Speter up->udb_dbname); 109142575Speter } 109238032Speter up->udb_type = UDB_DBFETCH; 109342575Speter up->udb_pid = getpid(); 109438032Speter ents++; 109538032Speter up++; 109638032Speter break; 109738032Speter#endif 109838032Speter 109938032Speter default: 110038032Speterbadspec: 110138032Speter syserr("Unknown UDB spec %s", spec); 110238032Speter break; 110338032Speter } 110438032Speter } 110538032Speter up->udb_type = UDB_EOLIST; 110638032Speter 110738032Speter if (tTd(28, 4)) 110838032Speter { 110938032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 111038032Speter { 111138032Speter switch (up->udb_type) 111238032Speter { 111338032Speter#if DAEMON 111438032Speter case UDB_REMOTE: 111538032Speter printf("REMOTE: addr %s, timeo %d\n", 111638032Speter anynet_ntoa((SOCKADDR *) &up->udb_addr), 111738032Speter up->udb_timeout); 111838032Speter break; 111938032Speter#endif 112038032Speter 112138032Speter case UDB_DBFETCH: 112238032Speter#ifdef NEWDB 112338032Speter printf("FETCH: file %s\n", 112438032Speter up->udb_dbname); 112538032Speter#else 112638032Speter printf("FETCH\n"); 112738032Speter#endif 112838032Speter break; 112938032Speter 113038032Speter case UDB_FORWARD: 113138032Speter printf("FORWARD: host %s\n", 113238032Speter up->udb_fwdhost); 113338032Speter break; 113438032Speter 113538032Speter case UDB_HESIOD: 113638032Speter printf("HESIOD\n"); 113738032Speter break; 113838032Speter 113938032Speter default: 114038032Speter printf("UNKNOWN\n"); 114138032Speter break; 114238032Speter } 114338032Speter } 114438032Speter } 114538032Speter 114638032Speter UdbInitialized = TRUE; 114738032Speter errno = 0; 114838032Speter return EX_OK; 114938032Speter 115038032Speter /* 115138032Speter ** On temporary failure, back out anything we've already done 115238032Speter */ 115338032Speter 115438032Speter tempfail: 115538032Speter#ifdef NEWDB 115638032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 115738032Speter { 115838032Speter if (up->udb_type == UDB_DBFETCH) 115938032Speter { 116038032Speter#if DB_VERSION_MAJOR < 2 116138032Speter (*up->udb_dbp->close)(up->udb_dbp); 116238032Speter#else 116338032Speter errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 116438032Speter#endif 116542575Speter if (tTd(28, 1)) 116642575Speter { 116742575Speter#if DB_VERSION_MAJOR < 2 116842575Speter printf("_udbx_init: db->close(%s)\n", 116942575Speter#else 117042575Speter printf("_udbx_init: db->close(%s)\n", 117142575Speter#endif 117242575Speter up->udb_dbname); 117342575Speter } 117438032Speter } 117538032Speter } 117638032Speter#endif 117738032Speter return EX_TEMPFAIL; 117838032Speter} 117938032Speter 118038032Speterint 118138032Speter_udb_parsespec(udbspec, opt, maxopts) 118238032Speter char *udbspec; 118342575Speter struct udb_option opt[]; 118438032Speter int maxopts; 118538032Speter{ 118638032Speter register char *spec; 118738032Speter register char *spec_end; 118838032Speter register int optnum; 118938032Speter 119038032Speter spec_end = strchr(udbspec, ':'); 119138032Speter for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 119238032Speter { 119338032Speter register char *p; 119438032Speter 119538032Speter while (isascii(*spec) && isspace(*spec)) 119638032Speter spec++; 119738032Speter spec_end = strchr(spec, ':'); 119838032Speter if (spec_end != NULL) 119938032Speter *spec_end++ = '\0'; 120038032Speter 120138032Speter opt[optnum].name = spec; 120238032Speter opt[optnum].val = NULL; 120338032Speter p = strchr(spec, '='); 120438032Speter if (p != NULL) 120538032Speter opt[optnum].val = ++p; 120638032Speter } 120738032Speter return optnum; 120838032Speter} 120942575Speter/* 121042575Speter** _UDBX_CLOSE -- close all file based UDB entries. 121142575Speter** 121242575Speter** Parameters: 121342575Speter** none 121442575Speter** 121542575Speter** Returns: 121642575Speter** none 121742575Speter*/ 121842575Spetervoid 121942575Speter_udbx_close() 122042575Speter{ 122142575Speter pid_t pid; 122242575Speter struct udbent *up; 122338032Speter 122442575Speter if (!UdbInitialized) 122542575Speter return; 122642575Speter 122742575Speter pid = getpid(); 122842575Speter 122942575Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 123042575Speter { 123142575Speter if (up->udb_pid != pid) 123242575Speter continue; 123342575Speter 123442575Speter#ifdef NEWDB 123542575Speter if (up->udb_type == UDB_DBFETCH) 123642575Speter { 123742575Speter#if DB_VERSION_MAJOR < 2 123842575Speter (*up->udb_dbp->close)(up->udb_dbp); 123942575Speter#else 124042575Speter errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 124142575Speter#endif 124242575Speter } 124342575Speter if (tTd(28, 1)) 124442575Speter { 124542575Speter#if DB_VERSION_MAJOR < 2 124642575Speter printf("_udbx_init: db->close(%s)\n", 124742575Speter#else 124842575Speter printf("_udbx_init: db->close(%s)\n", 124942575Speter#endif 125042575Speter up->udb_dbname); 125142575Speter } 125242575Speter#endif 125342575Speter } 125442575Speter} 125542575Speter 125638032Speter#ifdef HESIOD 125738032Speter 125838032Speterint 125938032Speterhes_udb_get(key, info) 126038032Speter DBT *key; 126138032Speter DBT *info; 126238032Speter{ 126338032Speter char *name, *type; 126438032Speter char **hp; 126538032Speter char kbuf[MAXKEY + 1]; 126638032Speter 126738032Speter if (strlen(key->data) >= (SIZE_T) sizeof kbuf) 126838032Speter return 0; 126938032Speter strcpy(kbuf, key->data); 127038032Speter name = kbuf; 127138032Speter type = strrchr(name, ':'); 127238032Speter if (type == NULL) 127338032Speter return 1; 127438032Speter *type++ = '\0'; 127538032Speter if (strchr(name, '@') != NULL) 127638032Speter return 1; 127738032Speter 127838032Speter if (tTd(28, 1)) 127938032Speter printf("hes_udb_get(%s, %s)\n", name, type); 128038032Speter 128138032Speter /* make the hesiod query */ 128238032Speter#ifdef HESIOD_INIT 128338032Speter if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0) 128438032Speter return -1; 128538032Speter hp = hesiod_resolve(HesiodContext, name, type); 128638032Speter#else 128738032Speter hp = hes_resolve(name, type); 128838032Speter#endif /* HESIOD_INIT */ 128938032Speter *--type = ':'; 129038032Speter#ifdef HESIOD_INIT 129138032Speter if (hp == NULL) 129238032Speter return 1; 129338032Speter if (*hp == NULL) 129438032Speter { 129538032Speter hesiod_free_list(HesiodContext, hp); 129638032Speter if (errno == ECONNREFUSED || errno == EMSGSIZE) 129738032Speter return -1; 129838032Speter return 1; 129938032Speter } 130038032Speter#else 130138032Speter if (hp == NULL || hp[0] == NULL) 130238032Speter { 130338032Speter /* network problem or timeout */ 130438032Speter if (hes_error() == HES_ER_NET) 130538032Speter return -1; 130638032Speter 130738032Speter return 1; 130838032Speter } 130938032Speter#endif /* HESIOD_INIT */ 131038032Speter else 131138032Speter { 131238032Speter /* 131338032Speter ** If there are multiple matches, just return the 131438032Speter ** first one. 131538032Speter ** 131638032Speter ** XXX These should really be returned; for example, 131738032Speter ** XXX it is legal for :maildrop to be multi-valued. 131838032Speter */ 131938032Speter 132038032Speter info->data = hp[0]; 132138032Speter info->size = (size_t) strlen(info->data); 132238032Speter } 132338032Speter 132438032Speter if (tTd(28, 80)) 132538032Speter printf("hes_udb_get => %s\n", *hp); 132638032Speter 132738032Speter return 0; 132838032Speter} 132938032Speter#endif /* HESIOD */ 133038032Speter 133138032Speter#else /* not USERDB */ 133238032Speter 133338032Speterint 133438032Speterudbexpand(a, sendq, aliaslevel, e) 133538032Speter ADDRESS *a; 133638032Speter ADDRESS **sendq; 133738032Speter int aliaslevel; 133838032Speter ENVELOPE *e; 133938032Speter{ 134038032Speter return EX_OK; 134138032Speter} 134238032Speter 134338032Speter#endif /* USERDB */ 1344