138032Speter/* 2261370Sgshapiro * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 15168515Sgshapiro#include "map.h" 1638032Speter 1790792Sgshapiro#if USERDB 18266711SgshapiroSM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)") 1990792Sgshapiro#else /* USERDB */ 20266711SgshapiroSM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)") 2190792Sgshapiro#endif /* USERDB */ 2238032Speter 2338032Speter#if USERDB 2438032Speter 25168515Sgshapiro#include <sm/sendmail.h> 2690792Sgshapiro# if NEWDB 27110560Sgshapiro# include "sm/bdb.h" 2864562Sgshapiro# else /* NEWDB */ 2964562Sgshapiro# define DBT struct _data_base_thang_ 3038032SpeterDBT 3138032Speter{ 3238032Speter void *data; /* pointer to data */ 3338032Speter size_t size; /* length of data */ 3438032Speter}; 3564562Sgshapiro# endif /* NEWDB */ 3638032Speter 3738032Speter/* 3838032Speter** UDB.C -- interface between sendmail and Berkeley User Data Base. 3938032Speter** 4038032Speter** This depends on the 4.4BSD db package. 4138032Speter*/ 4238032Speter 4338032Speter 4438032Speterstruct udbent 4538032Speter{ 4638032Speter char *udb_spec; /* string version of spec */ 4738032Speter int udb_type; /* type of entry */ 4842575Speter pid_t udb_pid; /* PID of process which opened db */ 4938032Speter char *udb_default; /* default host for outgoing mail */ 5038032Speter union 5138032Speter { 5264562Sgshapiro# if NETINET || NETINET6 5338032Speter /* type UE_REMOTE -- do remote call for lookup */ 5438032Speter struct 5538032Speter { 5664562Sgshapiro SOCKADDR _udb_addr; /* address */ 5738032Speter int _udb_timeout; /* timeout */ 5838032Speter } udb_remote; 5964562Sgshapiro# define udb_addr udb_u.udb_remote._udb_addr 6064562Sgshapiro# define udb_timeout udb_u.udb_remote._udb_timeout 6164562Sgshapiro# endif /* NETINET || NETINET6 */ 6238032Speter 6338032Speter /* type UE_FORWARD -- forward message to remote */ 6438032Speter struct 6538032Speter { 6638032Speter char *_udb_fwdhost; /* name of forward host */ 6738032Speter } udb_forward; 6864562Sgshapiro# define udb_fwdhost udb_u.udb_forward._udb_fwdhost 6938032Speter 7090792Sgshapiro# if NEWDB 7138032Speter /* type UE_FETCH -- lookup in local database */ 7238032Speter struct 7338032Speter { 7438032Speter char *_udb_dbname; /* pathname of database */ 7538032Speter DB *_udb_dbp; /* open database ptr */ 7638032Speter } udb_lookup; 7764562Sgshapiro# define udb_dbname udb_u.udb_lookup._udb_dbname 7864562Sgshapiro# define udb_dbp udb_u.udb_lookup._udb_dbp 7964562Sgshapiro# endif /* NEWDB */ 8038032Speter } udb_u; 8138032Speter}; 8238032Speter 8364562Sgshapiro# define UDB_EOLIST 0 /* end of list */ 8464562Sgshapiro# define UDB_SKIP 1 /* skip this entry */ 8564562Sgshapiro# define UDB_REMOTE 2 /* look up in remote database */ 8664562Sgshapiro# define UDB_DBFETCH 3 /* look up in local database */ 8764562Sgshapiro# define UDB_FORWARD 4 /* forward to remote host */ 8864562Sgshapiro# define UDB_HESIOD 5 /* look up via hesiod */ 8938032Speter 9064562Sgshapiro# define MAXUDBENT 10 /* maximum number of UDB entries */ 9138032Speter 9238032Speter 9342575Speterstruct udb_option 9438032Speter{ 9564562Sgshapiro char *udbo_name; 9664562Sgshapiro char *udbo_val; 9738032Speter}; 9838032Speter 9990792Sgshapiro# if HESIOD 10064562Sgshapirostatic int hes_udb_get __P((DBT *, DBT *)); 10164562Sgshapiro# endif /* HESIOD */ 10290792Sgshapirostatic char *udbmatch __P((char *, char *, SM_RPOOL_T *)); 10364562Sgshapirostatic int _udbx_init __P((ENVELOPE *)); 10464562Sgshapirostatic int _udb_parsespec __P((char *, struct udb_option [], int)); 10564562Sgshapiro 10664562Sgshapiro/* 10738032Speter** UDBEXPAND -- look up user in database and expand 10838032Speter** 10938032Speter** Parameters: 11038032Speter** a -- address to expand. 11138032Speter** sendq -- pointer to head of sendq to put the expansions in. 11238032Speter** aliaslevel -- the current alias nesting depth. 11338032Speter** e -- the current envelope. 11438032Speter** 11538032Speter** Returns: 11638032Speter** EX_TEMPFAIL -- if something "odd" happened -- probably due 11738032Speter** to accessing a file on an NFS server that is down. 11838032Speter** EX_OK -- otherwise. 11938032Speter** 12038032Speter** Side Effects: 12138032Speter** Modifies sendq. 12238032Speter*/ 12338032Speter 12464562Sgshapirostatic struct udbent UdbEnts[MAXUDBENT + 1]; 12590792Sgshapirostatic bool UdbInitialized = false; 12638032Speter 12738032Speterint 12838032Speterudbexpand(a, sendq, aliaslevel, e) 12938032Speter register ADDRESS *a; 13038032Speter ADDRESS **sendq; 13138032Speter int aliaslevel; 13238032Speter register ENVELOPE *e; 13338032Speter{ 13438032Speter int i; 13538032Speter DBT key; 13638032Speter DBT info; 13738032Speter bool breakout; 13838032Speter register struct udbent *up; 13938032Speter int keylen; 14038032Speter int naddrs; 14142575Speter char *user; 142157001Sgshapiro char keybuf[MAXUDBKEY]; 14338032Speter 144168515Sgshapiro memset(&key, '\0', sizeof(key)); 145168515Sgshapiro memset(&info, '\0', sizeof(info)); 14638032Speter 14738032Speter if (tTd(28, 1)) 14890792Sgshapiro sm_dprintf("udbexpand(%s)\n", a->q_paddr); 14938032Speter 15038032Speter /* make certain we are supposed to send to this address */ 15164562Sgshapiro if (!QS_IS_SENDABLE(a->q_state)) 15238032Speter return EX_OK; 15338032Speter e->e_to = a->q_paddr; 15438032Speter 15538032Speter /* on first call, locate the database */ 15638032Speter if (!UdbInitialized) 15738032Speter { 15838032Speter if (_udbx_init(e) == EX_TEMPFAIL) 15938032Speter return EX_TEMPFAIL; 16038032Speter } 16138032Speter 16238032Speter /* short circuit the process if no chance of a match */ 16338032Speter if (UdbSpec == NULL || UdbSpec[0] == '\0') 16438032Speter return EX_OK; 16538032Speter 16642575Speter /* extract user to do userdb matching on */ 16742575Speter user = a->q_user; 16842575Speter 16938032Speter /* short circuit name begins with '\\' since it can't possibly match */ 17042575Speter /* (might want to treat this as unquoted instead) */ 17142575Speter if (user[0] == '\\') 17238032Speter return EX_OK; 17338032Speter 17438032Speter /* if name begins with a colon, it indicates our metadata */ 17542575Speter if (user[0] == ':') 17638032Speter return EX_OK; 17738032Speter 178168515Sgshapiro keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop"); 17990792Sgshapiro 18090792Sgshapiro /* if name is too long, assume it won't match */ 181168515Sgshapiro if (keylen >= sizeof(keybuf)) 18290792Sgshapiro return EX_OK; 18390792Sgshapiro 18438032Speter /* build actual database key */ 18538032Speter 18690792Sgshapiro breakout = false; 18738032Speter for (up = UdbEnts; !breakout; up++) 18838032Speter { 18938032Speter int usersize; 19038032Speter int userleft; 19138032Speter char userbuf[MEMCHUNKSIZE]; 192110560Sgshapiro# if HESIOD && HES_GETMAILHOST 19338032Speter char pobuf[MAXNAME]; 194110560Sgshapiro# endif /* HESIOD && HES_GETMAILHOST */ 19564562Sgshapiro# if defined(NEWDB) && DB_VERSION_MAJOR > 1 19638032Speter DBC *dbc = NULL; 19764562Sgshapiro# endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */ 19838032Speter 19938032Speter user = userbuf; 20038032Speter userbuf[0] = '\0'; 201168515Sgshapiro usersize = sizeof(userbuf); 202168515Sgshapiro userleft = sizeof(userbuf) - 1; 20338032Speter 20438032Speter /* 20538032Speter ** Select action based on entry type. 20638032Speter ** 20738032Speter ** On dropping out of this switch, "class" should 20838032Speter ** explain the type of the data, and "user" should 20938032Speter ** contain the user information. 21038032Speter */ 21138032Speter 21238032Speter switch (up->udb_type) 21338032Speter { 21490792Sgshapiro# if NEWDB 21538032Speter case UDB_DBFETCH: 21638032Speter key.data = keybuf; 21738032Speter key.size = keylen; 21838032Speter if (tTd(28, 80)) 21990792Sgshapiro sm_dprintf("udbexpand: trying %s (%d) via db\n", 22038032Speter keybuf, keylen); 22164562Sgshapiro# if DB_VERSION_MAJOR < 2 22238032Speter i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 22364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 22438032Speter i = 0; 22538032Speter if (dbc == NULL && 22664562Sgshapiro# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 22738032Speter (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 22842575Speter NULL, &dbc, 0)) != 0) 22964562Sgshapiro# else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */ 23042575Speter (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 23138032Speter NULL, &dbc)) != 0) 23264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */ 23338032Speter i = -1; 23438032Speter if (i != 0 || dbc == NULL || 23538032Speter (errno = dbc->c_get(dbc, &key, 23638032Speter &info, DB_SET)) != 0) 23738032Speter i = 1; 23864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 23938032Speter if (i > 0 || info.size <= 0) 24038032Speter { 24138032Speter if (tTd(28, 2)) 24290792Sgshapiro sm_dprintf("udbexpand: no match on %s (%d)\n", 24338032Speter keybuf, keylen); 24464562Sgshapiro# if DB_VERSION_MAJOR > 1 24564562Sgshapiro if (dbc != NULL) 24638032Speter { 24738032Speter (void) dbc->c_close(dbc); 24838032Speter dbc = NULL; 24938032Speter } 25064562Sgshapiro# endif /* DB_VERSION_MAJOR > 1 */ 25138032Speter break; 25238032Speter } 25338032Speter if (tTd(28, 80)) 25490792Sgshapiro sm_dprintf("udbexpand: match %.*s: %.*s\n", 25538032Speter (int) key.size, (char *) key.data, 25638032Speter (int) info.size, (char *) info.data); 25738032Speter 25838032Speter a->q_flags &= ~QSELFREF; 25938032Speter while (i == 0 && key.size == keylen && 26064562Sgshapiro memcmp(key.data, keybuf, keylen) == 0) 26138032Speter { 26238032Speter char *p; 26338032Speter 26438032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 26538032Speter { 26664562Sgshapiro a->q_state = QS_VERIFIED; 26764562Sgshapiro# if DB_VERSION_MAJOR > 1 26838032Speter if (dbc != NULL) 26938032Speter { 27038032Speter (void) dbc->c_close(dbc); 27138032Speter dbc = NULL; 27238032Speter } 27364562Sgshapiro# endif /* DB_VERSION_MAJOR > 1 */ 27438032Speter return EX_OK; 27538032Speter } 27638032Speter 27790792Sgshapiro breakout = true; 27838032Speter if (info.size >= userleft - 1) 27938032Speter { 28038032Speter char *nuser; 28138032Speter int size = MEMCHUNKSIZE; 28238032Speter 28338032Speter if (info.size > MEMCHUNKSIZE) 28438032Speter size = info.size; 28590792Sgshapiro nuser = sm_malloc_x(usersize + size); 28638032Speter 28764562Sgshapiro memmove(nuser, user, usersize); 28838032Speter if (user != userbuf) 28990792Sgshapiro sm_free(user); /* XXX */ 29038032Speter user = nuser; 29138032Speter usersize += size; 29238032Speter userleft += size; 29338032Speter } 29438032Speter p = &user[strlen(user)]; 29538032Speter if (p != user) 29638032Speter { 29738032Speter *p++ = ','; 29838032Speter userleft--; 29938032Speter } 30064562Sgshapiro memmove(p, info.data, info.size); 30138032Speter p[info.size] = '\0'; 30238032Speter userleft -= info.size; 30338032Speter 30438032Speter /* get the next record */ 30564562Sgshapiro# if DB_VERSION_MAJOR < 2 30638032Speter i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 30764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 30838032Speter i = 0; 30938032Speter if ((errno = dbc->c_get(dbc, &key, 31038032Speter &info, DB_NEXT)) != 0) 31138032Speter i = 1; 31264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 31338032Speter } 31438032Speter 31564562Sgshapiro# if DB_VERSION_MAJOR > 1 31638032Speter if (dbc != NULL) 31738032Speter { 31838032Speter (void) dbc->c_close(dbc); 31938032Speter dbc = NULL; 32038032Speter } 32164562Sgshapiro# endif /* DB_VERSION_MAJOR > 1 */ 32238032Speter 32338032Speter /* if nothing ever matched, try next database */ 32438032Speter if (!breakout) 32538032Speter break; 32638032Speter 32738032Speter message("expanded to %s", user); 32864562Sgshapiro if (LogLevel > 10) 32938032Speter sm_syslog(LOG_INFO, e->e_id, 33064562Sgshapiro "expand %.100s => %s", 33164562Sgshapiro e->e_to, 33264562Sgshapiro shortenstring(user, MAXSHORTSTR)); 33338032Speter naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 33438032Speter if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 33538032Speter { 33638032Speter if (tTd(28, 5)) 33738032Speter { 33890792Sgshapiro sm_dprintf("udbexpand: QS_EXPANDED "); 339132943Sgshapiro printaddr(sm_debug_file(), a, false); 34038032Speter } 34164562Sgshapiro a->q_state = QS_EXPANDED; 34238032Speter } 34338032Speter if (i < 0) 34438032Speter { 34538032Speter syserr("udbexpand: db-get %.*s stat %d", 34638032Speter (int) key.size, (char *) key.data, i); 34738032Speter return EX_TEMPFAIL; 34838032Speter } 34938032Speter 35038032Speter /* 35138032Speter ** If this address has a -request address, reflect 35238032Speter ** it into the envelope. 35338032Speter */ 35438032Speter 355168515Sgshapiro memset(&key, '\0', sizeof(key)); 356168515Sgshapiro memset(&info, '\0', sizeof(info)); 357168515Sgshapiro (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user, 35890792Sgshapiro ":mailsender"); 35938032Speter keylen = strlen(keybuf); 36038032Speter key.data = keybuf; 36138032Speter key.size = keylen; 36238032Speter 36364562Sgshapiro# if DB_VERSION_MAJOR < 2 36438032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 36564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 36638032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 36738032Speter &key, &info, 0); 36864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 36938032Speter if (i != 0 || info.size <= 0) 37038032Speter break; 37190792Sgshapiro a->q_owner = sm_rpool_malloc_x(e->e_rpool, 37290792Sgshapiro info.size + 1); 37364562Sgshapiro memmove(a->q_owner, info.data, info.size); 37438032Speter a->q_owner[info.size] = '\0'; 37538032Speter 37638032Speter /* announce delivery; NORECEIPT bit set later */ 37738032Speter if (e->e_xfp != NULL) 37838032Speter { 37990792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 38090792Sgshapiro "Message delivered to mailing list %s\n", 38190792Sgshapiro a->q_paddr); 38238032Speter } 38338032Speter e->e_flags |= EF_SENDRECEIPT; 38438032Speter a->q_flags |= QDELIVERED|QEXPANDED; 38538032Speter break; 38664562Sgshapiro# endif /* NEWDB */ 38738032Speter 38890792Sgshapiro# if HESIOD 38938032Speter case UDB_HESIOD: 39038032Speter key.data = keybuf; 39138032Speter key.size = keylen; 39238032Speter if (tTd(28, 80)) 39390792Sgshapiro sm_dprintf("udbexpand: trying %s (%d) via hesiod\n", 39438032Speter keybuf, keylen); 39538032Speter /* look up the key via hesiod */ 39638032Speter i = hes_udb_get(&key, &info); 39738032Speter if (i < 0) 39838032Speter { 39938032Speter syserr("udbexpand: hesiod-get %.*s stat %d", 40038032Speter (int) key.size, (char *) key.data, i); 40138032Speter return EX_TEMPFAIL; 40238032Speter } 40338032Speter else if (i > 0 || info.size <= 0) 40438032Speter { 40564562Sgshapiro# if HES_GETMAILHOST 40638032Speter struct hes_postoffice *hp; 40764562Sgshapiro# endif /* HES_GETMAILHOST */ 40838032Speter 40938032Speter if (tTd(28, 2)) 41090792Sgshapiro sm_dprintf("udbexpand: no match on %s (%d)\n", 41138032Speter (char *) keybuf, (int) keylen); 41264562Sgshapiro# if HES_GETMAILHOST 41338032Speter if (tTd(28, 8)) 41490792Sgshapiro sm_dprintf(" ... trying hes_getmailhost(%s)\n", 41538032Speter a->q_user); 41638032Speter hp = hes_getmailhost(a->q_user); 41738032Speter if (hp == NULL) 41838032Speter { 41938032Speter if (hes_error() == HES_ER_NET) 42038032Speter { 42138032Speter syserr("udbexpand: hesiod-getmail %s stat %d", 42238032Speter a->q_user, hes_error()); 42338032Speter return EX_TEMPFAIL; 42438032Speter } 42538032Speter if (tTd(28, 2)) 42690792Sgshapiro sm_dprintf("hes_getmailhost(%s): %d\n", 42738032Speter a->q_user, hes_error()); 42838032Speter break; 42938032Speter } 43038032Speter if (strlen(hp->po_name) + strlen(hp->po_host) > 431168515Sgshapiro sizeof(pobuf) - 2) 43238032Speter { 43338032Speter if (tTd(28, 2)) 43490792Sgshapiro sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n", 43538032Speter a->q_user, 43638032Speter hp->po_name, 43738032Speter hp->po_host); 43838032Speter break; 43938032Speter } 44038032Speter info.data = pobuf; 441168515Sgshapiro (void) sm_snprintf(pobuf, sizeof(pobuf), 44290792Sgshapiro "%s@%s", hp->po_name, hp->po_host); 44338032Speter info.size = strlen(info.data); 44464562Sgshapiro# else /* HES_GETMAILHOST */ 44538032Speter break; 44664562Sgshapiro# endif /* HES_GETMAILHOST */ 44738032Speter } 44838032Speter if (tTd(28, 80)) 44990792Sgshapiro sm_dprintf("udbexpand: match %.*s: %.*s\n", 45038032Speter (int) key.size, (char *) key.data, 45138032Speter (int) info.size, (char *) info.data); 45238032Speter a->q_flags &= ~QSELFREF; 45338032Speter 45438032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 45538032Speter { 45664562Sgshapiro a->q_state = QS_VERIFIED; 45738032Speter return EX_OK; 45838032Speter } 45938032Speter 46090792Sgshapiro breakout = true; 46138032Speter if (info.size >= usersize) 46290792Sgshapiro user = sm_malloc_x(info.size + 1); 46364562Sgshapiro memmove(user, info.data, info.size); 46438032Speter user[info.size] = '\0'; 46538032Speter 46638032Speter message("hesioded to %s", user); 46764562Sgshapiro if (LogLevel > 10) 46838032Speter sm_syslog(LOG_INFO, e->e_id, 46964562Sgshapiro "hesiod %.100s => %s", 47064562Sgshapiro e->e_to, 47164562Sgshapiro shortenstring(user, MAXSHORTSTR)); 47238032Speter naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 47338032Speter 47438032Speter if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 47538032Speter { 47638032Speter if (tTd(28, 5)) 47738032Speter { 47890792Sgshapiro sm_dprintf("udbexpand: QS_EXPANDED "); 479132943Sgshapiro printaddr(sm_debug_file(), a, false); 48038032Speter } 48164562Sgshapiro a->q_state = QS_EXPANDED; 48238032Speter } 48338032Speter 48438032Speter /* 48538032Speter ** If this address has a -request address, reflect 48638032Speter ** it into the envelope. 48738032Speter */ 48838032Speter 489168515Sgshapiro (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user, 49090792Sgshapiro ":mailsender"); 49138032Speter keylen = strlen(keybuf); 49238032Speter key.data = keybuf; 49338032Speter key.size = keylen; 49438032Speter i = hes_udb_get(&key, &info); 49538032Speter if (i != 0 || info.size <= 0) 49638032Speter break; 49790792Sgshapiro a->q_owner = sm_rpool_malloc_x(e->e_rpool, 49890792Sgshapiro info.size + 1); 49964562Sgshapiro memmove(a->q_owner, info.data, info.size); 50038032Speter a->q_owner[info.size] = '\0'; 50138032Speter break; 50264562Sgshapiro# endif /* HESIOD */ 50338032Speter 50438032Speter case UDB_REMOTE: 50538032Speter /* not yet implemented */ 50638032Speter break; 50738032Speter 50838032Speter case UDB_FORWARD: 50938032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 51064562Sgshapiro { 51164562Sgshapiro a->q_state = QS_VERIFIED; 51238032Speter return EX_OK; 51364562Sgshapiro } 51438032Speter i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 51538032Speter if (i >= usersize) 51638032Speter { 51738032Speter usersize = i + 1; 51890792Sgshapiro user = sm_malloc_x(usersize); 51938032Speter } 52090792Sgshapiro (void) sm_strlcpyn(user, usersize, 3, 52190792Sgshapiro 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 { 52990792Sgshapiro sm_dprintf("udbexpand: QS_EXPANDED "); 530132943Sgshapiro printaddr(sm_debug_file(), a, false); 53138032Speter } 53264562Sgshapiro a->q_state = QS_EXPANDED; 53338032Speter } 53490792Sgshapiro breakout = true; 53538032Speter break; 53638032Speter 53738032Speter case UDB_EOLIST: 53890792Sgshapiro breakout = true; 53938032Speter break; 54038032Speter 54138032Speter default: 54238032Speter /* unknown entry type */ 54338032Speter break; 54438032Speter } 54590792Sgshapiro /* XXX if an exception occurs, there is a storage leak */ 54638032Speter if (user != userbuf) 54790792Sgshapiro sm_free(user); /* XXX */ 54838032Speter } 54938032Speter return EX_OK; 55038032Speter} 55190792Sgshapiro/* 55238032Speter** UDBSENDER -- return canonical external name of sender, given local name 55338032Speter** 55438032Speter** Parameters: 55538032Speter** sender -- the name of the sender on the local machine. 55690792Sgshapiro** rpool -- resource pool from which to allocate result 55738032Speter** 55838032Speter** Returns: 55938032Speter** The external name for this sender, if derivable from the 56090792Sgshapiro** database. Storage allocated from rpool. 56138032Speter** NULL -- if nothing is changed from the database. 56238032Speter** 56338032Speter** Side Effects: 56438032Speter** none. 56538032Speter*/ 56638032Speter 56738032Speterchar * 56890792Sgshapiroudbsender(sender, rpool) 56938032Speter char *sender; 57090792Sgshapiro SM_RPOOL_T *rpool; 57138032Speter{ 57290792Sgshapiro return udbmatch(sender, "mailname", rpool); 57338032Speter} 57490792Sgshapiro/* 57564562Sgshapiro** UDBMATCH -- match user in field, return result of lookup. 57664562Sgshapiro** 57764562Sgshapiro** Parameters: 57864562Sgshapiro** user -- the name of the user. 57964562Sgshapiro** field -- the field to lookup. 58090792Sgshapiro** rpool -- resource pool from which to allocate result 58164562Sgshapiro** 58264562Sgshapiro** Returns: 58364562Sgshapiro** The external name for this sender, if derivable from the 58490792Sgshapiro** database. Storage allocated from rpool. 58564562Sgshapiro** NULL -- if nothing is changed from the database. 58664562Sgshapiro** 58764562Sgshapiro** Side Effects: 58864562Sgshapiro** none. 58964562Sgshapiro*/ 59038032Speter 59164562Sgshapirostatic char * 59290792Sgshapiroudbmatch(user, field, rpool) 59338032Speter char *user; 59438032Speter char *field; 59590792Sgshapiro SM_RPOOL_T *rpool; 59638032Speter{ 59738032Speter register char *p; 59838032Speter register struct udbent *up; 59938032Speter int i; 60038032Speter int keylen; 60138032Speter DBT key, info; 602157001Sgshapiro char keybuf[MAXUDBKEY]; 60338032Speter 60438032Speter if (tTd(28, 1)) 60590792Sgshapiro sm_dprintf("udbmatch(%s, %s)\n", user, field); 60638032Speter 60738032Speter if (!UdbInitialized) 60838032Speter { 60938032Speter if (_udbx_init(CurEnv) == EX_TEMPFAIL) 61038032Speter return NULL; 61138032Speter } 61238032Speter 61338032Speter /* short circuit if no spec */ 61438032Speter if (UdbSpec == NULL || UdbSpec[0] == '\0') 61538032Speter return NULL; 61638032Speter 61738032Speter /* short circuit name begins with '\\' since it can't possibly match */ 61838032Speter if (user[0] == '\\') 61938032Speter return NULL; 62038032Speter 62138032Speter /* long names can never match and are a pain to deal with */ 62238032Speter i = strlen(field); 623168515Sgshapiro if (i < sizeof("maildrop")) 624168515Sgshapiro i = sizeof("maildrop"); 625168515Sgshapiro if ((strlen(user) + i) > sizeof(keybuf) - 4) 62638032Speter return NULL; 62738032Speter 62838032Speter /* names beginning with colons indicate metadata */ 62938032Speter if (user[0] == ':') 63038032Speter return NULL; 63138032Speter 63238032Speter /* build database key */ 633168515Sgshapiro (void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field); 63438032Speter keylen = strlen(keybuf); 63538032Speter 63638032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 63738032Speter { 63838032Speter /* 63938032Speter ** Select action based on entry type. 64038032Speter */ 64138032Speter 64238032Speter switch (up->udb_type) 64338032Speter { 64490792Sgshapiro# if NEWDB 64538032Speter case UDB_DBFETCH: 646168515Sgshapiro memset(&key, '\0', sizeof(key)); 647168515Sgshapiro memset(&info, '\0', sizeof(info)); 64838032Speter key.data = keybuf; 64938032Speter key.size = keylen; 65064562Sgshapiro# if DB_VERSION_MAJOR < 2 65138032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 65264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 65338032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 65438032Speter &key, &info, 0); 65564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 65638032Speter if (i != 0 || info.size <= 0) 65738032Speter { 65838032Speter if (tTd(28, 2)) 65990792Sgshapiro sm_dprintf("udbmatch: no match on %s (%d) via db\n", 66064562Sgshapiro keybuf, keylen); 66138032Speter continue; 66238032Speter } 66338032Speter 66490792Sgshapiro p = sm_rpool_malloc_x(rpool, info.size + 1); 66564562Sgshapiro memmove(p, info.data, info.size); 66638032Speter p[info.size] = '\0'; 66738032Speter if (tTd(28, 1)) 66890792Sgshapiro sm_dprintf("udbmatch ==> %s\n", p); 66938032Speter return p; 67064562Sgshapiro# endif /* NEWDB */ 67138032Speter 67290792Sgshapiro# if HESIOD 67338032Speter case UDB_HESIOD: 67438032Speter key.data = keybuf; 67538032Speter key.size = keylen; 67664562Sgshapiro i = hes_udb_get(&key, &info); 67738032Speter if (i != 0 || info.size <= 0) 67838032Speter { 67938032Speter if (tTd(28, 2)) 68090792Sgshapiro sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n", 68164562Sgshapiro keybuf, keylen); 68238032Speter continue; 68338032Speter } 68438032Speter 68590792Sgshapiro p = sm_rpool_malloc_x(rpool, info.size + 1); 68664562Sgshapiro memmove(p, info.data, info.size); 68738032Speter p[info.size] = '\0'; 68838032Speter if (tTd(28, 1)) 68990792Sgshapiro sm_dprintf("udbmatch ==> %s\n", p); 69038032Speter return p; 69164562Sgshapiro# endif /* HESIOD */ 69238032Speter } 69338032Speter } 69438032Speter 69538032Speter if (strcmp(field, "mailname") != 0) 69638032Speter return NULL; 69738032Speter 69838032Speter /* 69938032Speter ** Nothing yet. Search again for a default case. But only 70038032Speter ** use it if we also have a forward (:maildrop) pointer already 70138032Speter ** in the database. 70238032Speter */ 70338032Speter 70438032Speter /* build database key */ 705168515Sgshapiro (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop"); 70638032Speter keylen = strlen(keybuf); 70738032Speter 70838032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 70938032Speter { 71038032Speter switch (up->udb_type) 71138032Speter { 71290792Sgshapiro# if NEWDB 71338032Speter case UDB_DBFETCH: 71438032Speter /* get the default case for this database */ 71538032Speter if (up->udb_default == NULL) 71638032Speter { 717168515Sgshapiro memset(&key, '\0', sizeof(key)); 718168515Sgshapiro memset(&info, '\0', sizeof(info)); 71938032Speter key.data = ":default:mailname"; 72038032Speter key.size = strlen(key.data); 72164562Sgshapiro# if DB_VERSION_MAJOR < 2 72238032Speter i = (*up->udb_dbp->get)(up->udb_dbp, 72338032Speter &key, &info, 0); 72464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 72538032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, 72638032Speter NULL, &key, 72738032Speter &info, 0); 72864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 72938032Speter if (i != 0 || info.size <= 0) 73038032Speter { 73138032Speter /* no default case */ 73238032Speter up->udb_default = ""; 73338032Speter continue; 73438032Speter } 73538032Speter 73638032Speter /* save the default case */ 73790792Sgshapiro up->udb_default = sm_pmalloc_x(info.size + 1); 73864562Sgshapiro memmove(up->udb_default, info.data, info.size); 73938032Speter up->udb_default[info.size] = '\0'; 74038032Speter } 74138032Speter else if (up->udb_default[0] == '\0') 74238032Speter continue; 74338032Speter 74438032Speter /* we have a default case -- verify user:maildrop */ 745168515Sgshapiro memset(&key, '\0', sizeof(key)); 746168515Sgshapiro memset(&info, '\0', sizeof(info)); 74738032Speter key.data = keybuf; 74838032Speter key.size = keylen; 74964562Sgshapiro# if DB_VERSION_MAJOR < 2 75038032Speter i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 75164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 75238032Speter i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 75338032Speter &key, &info, 0); 75464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 75538032Speter if (i != 0 || info.size <= 0) 75638032Speter { 75738032Speter /* nope -- no aliasing for this user */ 75838032Speter continue; 75938032Speter } 76038032Speter 76138032Speter /* they exist -- build the actual address */ 76264562Sgshapiro i = strlen(user) + strlen(up->udb_default) + 2; 76390792Sgshapiro p = sm_rpool_malloc_x(rpool, i); 76490792Sgshapiro (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default); 76538032Speter if (tTd(28, 1)) 76690792Sgshapiro sm_dprintf("udbmatch ==> %s\n", p); 76738032Speter return p; 76864562Sgshapiro# endif /* NEWDB */ 76938032Speter 77090792Sgshapiro# if HESIOD 77138032Speter case UDB_HESIOD: 77238032Speter /* get the default case for this database */ 77338032Speter if (up->udb_default == NULL) 77438032Speter { 77538032Speter key.data = ":default:mailname"; 77638032Speter key.size = strlen(key.data); 77764562Sgshapiro i = hes_udb_get(&key, &info); 77838032Speter 77938032Speter if (i != 0 || info.size <= 0) 78038032Speter { 78138032Speter /* no default case */ 78238032Speter up->udb_default = ""; 78338032Speter continue; 78438032Speter } 78538032Speter 78638032Speter /* save the default case */ 78790792Sgshapiro up->udb_default = sm_pmalloc_x(info.size + 1); 78864562Sgshapiro memmove(up->udb_default, info.data, info.size); 78938032Speter up->udb_default[info.size] = '\0'; 79038032Speter } 79138032Speter else if (up->udb_default[0] == '\0') 79238032Speter continue; 79338032Speter 79438032Speter /* we have a default case -- verify user:maildrop */ 79538032Speter key.data = keybuf; 79638032Speter key.size = keylen; 79738032Speter i = hes_udb_get(&key, &info); 79838032Speter if (i != 0 || info.size <= 0) 79938032Speter { 80038032Speter /* nope -- no aliasing for this user */ 80138032Speter continue; 80238032Speter } 80338032Speter 80438032Speter /* they exist -- build the actual address */ 80564562Sgshapiro i = strlen(user) + strlen(up->udb_default) + 2; 80690792Sgshapiro p = sm_rpool_malloc_x(rpool, i); 80790792Sgshapiro (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default); 80838032Speter if (tTd(28, 1)) 80990792Sgshapiro sm_dprintf("udbmatch ==> %s\n", p); 81038032Speter return p; 81138032Speter break; 81264562Sgshapiro# endif /* HESIOD */ 81338032Speter } 81438032Speter } 81538032Speter 81638032Speter /* still nothing.... too bad */ 81738032Speter return NULL; 81838032Speter} 81990792Sgshapiro/* 82038032Speter** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 82138032Speter** 82238032Speter** Parameters: 82338032Speter** map -- the map being queried. 82438032Speter** name -- the name to look up. 82538032Speter** av -- arguments to the map lookup. 82638032Speter** statp -- to get any error status. 82738032Speter** 82838032Speter** Returns: 82938032Speter** NULL if name not found in map. 83038032Speter** The rewritten name otherwise. 83138032Speter*/ 83238032Speter 83338032Speter/* ARGSUSED3 */ 83438032Speterchar * 83538032Speterudb_map_lookup(map, name, av, statp) 83638032Speter MAP *map; 83738032Speter char *name; 83838032Speter char **av; 83938032Speter int *statp; 84038032Speter{ 84138032Speter char *val; 84238032Speter char *key; 84390792Sgshapiro char *SM_NONVOLATILE result = NULL; 84438032Speter char keybuf[MAXNAME + 1]; 84538032Speter 84638032Speter if (tTd(28, 20) || tTd(38, 20)) 84790792Sgshapiro sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 84838032Speter 84938032Speter if (bitset(MF_NOFOLDCASE, map->map_mflags)) 85038032Speter { 85138032Speter key = name; 85238032Speter } 85338032Speter else 85438032Speter { 85538032Speter int keysize = strlen(name); 85638032Speter 857168515Sgshapiro if (keysize > sizeof(keybuf) - 1) 858168515Sgshapiro keysize = sizeof(keybuf) - 1; 85964562Sgshapiro memmove(keybuf, name, keysize); 86038032Speter keybuf[keysize] = '\0'; 86138032Speter makelower(keybuf); 86238032Speter key = keybuf; 86338032Speter } 86490792Sgshapiro val = udbmatch(key, map->map_file, NULL); 86538032Speter if (val == NULL) 86638032Speter return NULL; 86790792Sgshapiro SM_TRY 86890792Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 86990792Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 87090792Sgshapiro else 87190792Sgshapiro result = map_rewrite(map, val, strlen(val), av); 87290792Sgshapiro SM_FINALLY 87390792Sgshapiro sm_free(val); 87490792Sgshapiro SM_END_TRY 87590792Sgshapiro return result; 87638032Speter} 87790792Sgshapiro/* 87838032Speter** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 87938032Speter** 88038032Speter** Parameters: 88138032Speter** e -- the current envelope. 88238032Speter** 88338032Speter** Returns: 88438032Speter** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 88538032Speter** database due to a host being down or some similar 88638032Speter** (recoverable) situation. 88738032Speter** EX_OK -- otherwise. 88838032Speter** 88938032Speter** Side Effects: 89038032Speter** Fills in the UdbEnts structure from UdbSpec. 89138032Speter*/ 89238032Speter 89364562Sgshapiro# define MAXUDBOPTS 27 89438032Speter 89564562Sgshapirostatic int 89638032Speter_udbx_init(e) 89738032Speter ENVELOPE *e; 89838032Speter{ 89938032Speter int ents = 0; 90038032Speter register char *p; 90138032Speter register struct udbent *up; 90238032Speter 90338032Speter if (UdbInitialized) 90438032Speter return EX_OK; 90538032Speter 90638032Speter# ifdef UDB_DEFAULT_SPEC 90738032Speter if (UdbSpec == NULL) 90838032Speter UdbSpec = UDB_DEFAULT_SPEC; 90964562Sgshapiro# endif /* UDB_DEFAULT_SPEC */ 91038032Speter 91138032Speter p = UdbSpec; 91238032Speter up = UdbEnts; 91338032Speter while (p != NULL) 91438032Speter { 91538032Speter char *spec; 91638032Speter int l; 91742575Speter struct udb_option opts[MAXUDBOPTS + 1]; 91838032Speter 91938032Speter while (*p == ' ' || *p == '\t' || *p == ',') 92038032Speter p++; 92138032Speter if (*p == '\0') 92238032Speter break; 92338032Speter spec = p; 92438032Speter p = strchr(p, ','); 92538032Speter if (p != NULL) 92638032Speter *p++ = '\0'; 92738032Speter 92838032Speter if (ents >= MAXUDBENT) 92938032Speter { 93038032Speter syserr("Maximum number of UDB entries exceeded"); 93138032Speter break; 93238032Speter } 93338032Speter 93438032Speter /* extract options */ 93538032Speter (void) _udb_parsespec(spec, opts, MAXUDBOPTS); 93638032Speter 93738032Speter /* 93838032Speter ** Decode database specification. 93938032Speter ** 94038032Speter ** In the sendmail tradition, the leading character 94138032Speter ** defines the semantics of the rest of the entry. 94238032Speter ** 94338032Speter ** @hostname -- forward email to the indicated host. 94438032Speter ** This should be the last in the list, 94538032Speter ** since it always matches the input. 94638032Speter ** /dbname -- search the named database on the local 94738032Speter ** host using the Berkeley db package. 94838032Speter ** Hesiod -- search the named database with BIND 94938032Speter ** using the MIT Hesiod package. 95038032Speter */ 95138032Speter 95238032Speter switch (*spec) 95338032Speter { 95438032Speter case '@': /* forward to remote host */ 95538032Speter up->udb_type = UDB_FORWARD; 95690792Sgshapiro up->udb_pid = CurrentPid; 95738032Speter up->udb_fwdhost = spec + 1; 95838032Speter ents++; 95938032Speter up++; 96038032Speter break; 96138032Speter 96290792Sgshapiro# if HESIOD 96338032Speter case 'h': /* use hesiod */ 96438032Speter case 'H': 96590792Sgshapiro if (sm_strcasecmp(spec, "hesiod") != 0) 96638032Speter goto badspec; 96738032Speter up->udb_type = UDB_HESIOD; 96890792Sgshapiro up->udb_pid = CurrentPid; 96938032Speter ents++; 97038032Speter up++; 97138032Speter break; 97264562Sgshapiro# endif /* HESIOD */ 97338032Speter 97490792Sgshapiro# if NEWDB 97538032Speter case '/': /* look up remote name */ 97638032Speter l = strlen(spec); 97738032Speter if (l > 3 && strcmp(&spec[l - 3], ".db") == 0) 97838032Speter { 97938032Speter up->udb_dbname = spec; 98038032Speter } 98138032Speter else 98238032Speter { 98390792Sgshapiro up->udb_dbname = sm_pmalloc_x(l + 4); 98490792Sgshapiro (void) sm_strlcpyn(up->udb_dbname, l + 4, 2, 98590792Sgshapiro spec, ".db"); 98638032Speter } 98738032Speter errno = 0; 98864562Sgshapiro# if DB_VERSION_MAJOR < 2 98938032Speter up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, 99038032Speter 0644, DB_BTREE, NULL); 99164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 99264562Sgshapiro { 99364562Sgshapiro int flags = DB_RDONLY; 99464562Sgshapiro# if DB_VERSION_MAJOR > 2 99564562Sgshapiro int ret; 99664562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 99764562Sgshapiro 998110560Sgshapiro SM_DB_FLAG_ADD(flags); 99964562Sgshapiro up->udb_dbp = NULL; 100064562Sgshapiro# if DB_VERSION_MAJOR > 2 100164562Sgshapiro ret = db_create(&up->udb_dbp, NULL, 0); 100264562Sgshapiro if (ret != 0) 100364562Sgshapiro { 100464562Sgshapiro (void) up->udb_dbp->close(up->udb_dbp, 100564562Sgshapiro 0); 100664562Sgshapiro up->udb_dbp = NULL; 100764562Sgshapiro } 100864562Sgshapiro else 100964562Sgshapiro { 101064562Sgshapiro ret = up->udb_dbp->open(up->udb_dbp, 1011110560Sgshapiro DBTXN 101264562Sgshapiro up->udb_dbname, 101364562Sgshapiro NULL, 101464562Sgshapiro DB_BTREE, 101564562Sgshapiro flags, 101664562Sgshapiro 0644); 101764562Sgshapiro if (ret != 0) 101864562Sgshapiro { 101973188Sgshapiro#ifdef DB_OLD_VERSION 102073188Sgshapiro if (ret == DB_OLD_VERSION) 102173188Sgshapiro ret = EINVAL; 102273188Sgshapiro#endif /* DB_OLD_VERSION */ 102364562Sgshapiro (void) up->udb_dbp->close(up->udb_dbp, 0); 102464562Sgshapiro up->udb_dbp = NULL; 102564562Sgshapiro } 102664562Sgshapiro } 102764562Sgshapiro errno = ret; 102864562Sgshapiro# else /* DB_VERSION_MAJOR > 2 */ 102964562Sgshapiro errno = db_open(up->udb_dbname, DB_BTREE, 103064562Sgshapiro flags, 0644, NULL, 103164562Sgshapiro NULL, &up->udb_dbp); 103264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 103364562Sgshapiro } 103464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 103538032Speter if (up->udb_dbp == NULL) 103638032Speter { 103738032Speter if (tTd(28, 1)) 103838032Speter { 103964562Sgshapiro int save_errno = errno; 104038032Speter 104164562Sgshapiro# if DB_VERSION_MAJOR < 2 104290792Sgshapiro sm_dprintf("dbopen(%s): %s\n", 104364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 104490792Sgshapiro sm_dprintf("db_open(%s): %s\n", 104564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 104638032Speter up->udb_dbname, 104790792Sgshapiro sm_errstring(errno)); 104864562Sgshapiro errno = save_errno; 104938032Speter } 105038032Speter if (errno != ENOENT && errno != EACCES) 105138032Speter { 105238032Speter if (LogLevel > 2) 105338032Speter sm_syslog(LOG_ERR, e->e_id, 105464562Sgshapiro# if DB_VERSION_MAJOR < 2 105564562Sgshapiro "dbopen(%s): %s", 105664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 105764562Sgshapiro "db_open(%s): %s", 105864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 105964562Sgshapiro up->udb_dbname, 106090792Sgshapiro sm_errstring(errno)); 106138032Speter up->udb_type = UDB_EOLIST; 106238032Speter if (up->udb_dbname != spec) 106390792Sgshapiro sm_free(up->udb_dbname); /* XXX */ 106438032Speter goto tempfail; 106538032Speter } 106638032Speter if (up->udb_dbname != spec) 106790792Sgshapiro sm_free(up->udb_dbname); /* XXX */ 106838032Speter break; 106938032Speter } 107042575Speter if (tTd(28, 1)) 107142575Speter { 107264562Sgshapiro# if DB_VERSION_MAJOR < 2 107390792Sgshapiro sm_dprintf("_udbx_init: dbopen(%s)\n", 107464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 107590792Sgshapiro sm_dprintf("_udbx_init: db_open(%s)\n", 107664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 107742575Speter up->udb_dbname); 107842575Speter } 107938032Speter up->udb_type = UDB_DBFETCH; 108090792Sgshapiro up->udb_pid = CurrentPid; 108138032Speter ents++; 108238032Speter up++; 108338032Speter break; 108464562Sgshapiro# endif /* NEWDB */ 108538032Speter 108638032Speter default: 108790792Sgshapiro# if HESIOD 108838032Speterbadspec: 108964562Sgshapiro# endif /* HESIOD */ 109038032Speter syserr("Unknown UDB spec %s", spec); 109138032Speter break; 109238032Speter } 109338032Speter } 109438032Speter up->udb_type = UDB_EOLIST; 109538032Speter 109638032Speter if (tTd(28, 4)) 109738032Speter { 109838032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 109938032Speter { 110038032Speter switch (up->udb_type) 110138032Speter { 110238032Speter case UDB_REMOTE: 110390792Sgshapiro sm_dprintf("REMOTE: addr %s, timeo %d\n", 110490792Sgshapiro anynet_ntoa((SOCKADDR *) &up->udb_addr), 110590792Sgshapiro up->udb_timeout); 110638032Speter break; 110738032Speter 110838032Speter case UDB_DBFETCH: 110990792Sgshapiro# if NEWDB 111090792Sgshapiro sm_dprintf("FETCH: file %s\n", 111138032Speter up->udb_dbname); 111264562Sgshapiro# else /* NEWDB */ 111390792Sgshapiro sm_dprintf("FETCH\n"); 111464562Sgshapiro# endif /* NEWDB */ 111538032Speter break; 111638032Speter 111738032Speter case UDB_FORWARD: 111890792Sgshapiro sm_dprintf("FORWARD: host %s\n", 111938032Speter up->udb_fwdhost); 112038032Speter break; 112138032Speter 112238032Speter case UDB_HESIOD: 112390792Sgshapiro sm_dprintf("HESIOD\n"); 112438032Speter break; 112538032Speter 112638032Speter default: 112790792Sgshapiro sm_dprintf("UNKNOWN\n"); 112838032Speter break; 112938032Speter } 113038032Speter } 113138032Speter } 113238032Speter 113390792Sgshapiro UdbInitialized = true; 113438032Speter errno = 0; 113538032Speter return EX_OK; 113638032Speter 113738032Speter /* 113838032Speter ** On temporary failure, back out anything we've already done 113938032Speter */ 114038032Speter 114138032Speter tempfail: 114290792Sgshapiro# if NEWDB 114338032Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 114438032Speter { 114538032Speter if (up->udb_type == UDB_DBFETCH) 114638032Speter { 114764562Sgshapiro# if DB_VERSION_MAJOR < 2 114838032Speter (*up->udb_dbp->close)(up->udb_dbp); 114964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 115038032Speter errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 115164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 115242575Speter if (tTd(28, 1)) 115390792Sgshapiro sm_dprintf("_udbx_init: db->close(%s)\n", 115442575Speter up->udb_dbname); 115538032Speter } 115638032Speter } 115764562Sgshapiro# endif /* NEWDB */ 115838032Speter return EX_TEMPFAIL; 115938032Speter} 116038032Speter 116164562Sgshapirostatic int 116238032Speter_udb_parsespec(udbspec, opt, maxopts) 116338032Speter char *udbspec; 116442575Speter struct udb_option opt[]; 116538032Speter int maxopts; 116638032Speter{ 116738032Speter register char *spec; 116838032Speter register char *spec_end; 116938032Speter register int optnum; 117038032Speter 117138032Speter spec_end = strchr(udbspec, ':'); 117238032Speter for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 117338032Speter { 117438032Speter register char *p; 117538032Speter 117638032Speter while (isascii(*spec) && isspace(*spec)) 117738032Speter spec++; 117838032Speter spec_end = strchr(spec, ':'); 117938032Speter if (spec_end != NULL) 118038032Speter *spec_end++ = '\0'; 118138032Speter 118264562Sgshapiro opt[optnum].udbo_name = spec; 118364562Sgshapiro opt[optnum].udbo_val = NULL; 118438032Speter p = strchr(spec, '='); 118538032Speter if (p != NULL) 118664562Sgshapiro opt[optnum].udbo_val = ++p; 118738032Speter } 118838032Speter return optnum; 118938032Speter} 119090792Sgshapiro/* 119142575Speter** _UDBX_CLOSE -- close all file based UDB entries. 119242575Speter** 119342575Speter** Parameters: 119442575Speter** none 119542575Speter** 119642575Speter** Returns: 119742575Speter** none 119842575Speter*/ 119942575Spetervoid 120042575Speter_udbx_close() 120142575Speter{ 120242575Speter struct udbent *up; 120338032Speter 120442575Speter if (!UdbInitialized) 120542575Speter return; 120642575Speter 120742575Speter for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 120842575Speter { 120990792Sgshapiro if (up->udb_pid != CurrentPid) 121042575Speter continue; 121164562Sgshapiro 121290792Sgshapiro# if NEWDB 121342575Speter if (up->udb_type == UDB_DBFETCH) 121442575Speter { 121564562Sgshapiro# if DB_VERSION_MAJOR < 2 121642575Speter (*up->udb_dbp->close)(up->udb_dbp); 121764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 121842575Speter errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 121964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 122042575Speter } 122142575Speter if (tTd(28, 1)) 1222223067Sgshapiro sm_dprintf("_udbx_close: db->close(%s)\n", 122342575Speter up->udb_dbname); 122464562Sgshapiro# endif /* NEWDB */ 122542575Speter } 122642575Speter} 122742575Speter 122890792Sgshapiro# if HESIOD 122938032Speter 123064562Sgshapirostatic int 123138032Speterhes_udb_get(key, info) 123238032Speter DBT *key; 123338032Speter DBT *info; 123438032Speter{ 123538032Speter char *name, *type; 123638032Speter char **hp; 1237157001Sgshapiro char kbuf[MAXUDBKEY + 1]; 123838032Speter 1239168515Sgshapiro if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf)) 124038032Speter return 0; 124138032Speter name = kbuf; 124238032Speter type = strrchr(name, ':'); 124338032Speter if (type == NULL) 124438032Speter return 1; 124538032Speter *type++ = '\0'; 124638032Speter if (strchr(name, '@') != NULL) 124738032Speter return 1; 124838032Speter 124938032Speter if (tTd(28, 1)) 125090792Sgshapiro sm_dprintf("hes_udb_get(%s, %s)\n", name, type); 125138032Speter 125238032Speter /* make the hesiod query */ 125364562Sgshapiro# ifdef HESIOD_INIT 125438032Speter if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0) 125538032Speter return -1; 125638032Speter hp = hesiod_resolve(HesiodContext, name, type); 125764562Sgshapiro# else /* HESIOD_INIT */ 125838032Speter hp = hes_resolve(name, type); 125964562Sgshapiro# endif /* HESIOD_INIT */ 126038032Speter *--type = ':'; 126164562Sgshapiro# ifdef HESIOD_INIT 126238032Speter if (hp == NULL) 126338032Speter return 1; 126438032Speter if (*hp == NULL) 126538032Speter { 126638032Speter hesiod_free_list(HesiodContext, hp); 126738032Speter if (errno == ECONNREFUSED || errno == EMSGSIZE) 126838032Speter return -1; 126938032Speter return 1; 127038032Speter } 127164562Sgshapiro# else /* HESIOD_INIT */ 127238032Speter if (hp == NULL || hp[0] == NULL) 127338032Speter { 127438032Speter /* network problem or timeout */ 127538032Speter if (hes_error() == HES_ER_NET) 127638032Speter return -1; 127738032Speter 127838032Speter return 1; 127938032Speter } 128064562Sgshapiro# endif /* HESIOD_INIT */ 128138032Speter else 128238032Speter { 128338032Speter /* 128438032Speter ** If there are multiple matches, just return the 128538032Speter ** first one. 128638032Speter ** 128738032Speter ** XXX These should really be returned; for example, 128838032Speter ** XXX it is legal for :maildrop to be multi-valued. 128938032Speter */ 129038032Speter 129138032Speter info->data = hp[0]; 129238032Speter info->size = (size_t) strlen(info->data); 129338032Speter } 129438032Speter 129538032Speter if (tTd(28, 80)) 129690792Sgshapiro sm_dprintf("hes_udb_get => %s\n", *hp); 129738032Speter 129838032Speter return 0; 129938032Speter} 130064562Sgshapiro# endif /* HESIOD */ 130138032Speter 130264562Sgshapiro#else /* USERDB */ 130338032Speter 130438032Speterint 130538032Speterudbexpand(a, sendq, aliaslevel, e) 130638032Speter ADDRESS *a; 130738032Speter ADDRESS **sendq; 130838032Speter int aliaslevel; 130938032Speter ENVELOPE *e; 131038032Speter{ 131138032Speter return EX_OK; 131238032Speter} 131338032Speter 131438032Speter#endif /* USERDB */ 1315