150581Seric /* 250581Seric * Copyright (c) 1983 Eric P. Allman 362532Sbostic * Copyright (c) 1988, 1993 462532Sbostic * The Regents of the University of California. All rights reserved. 550581Seric * 650581Seric * %sccs.include.redist.c% 750581Seric */ 850581Seric 960567Seric #include "sendmail.h" 1060567Seric 1150581Seric #ifndef lint 1251360Seric #ifdef USERDB 13*66334Seric static char sccsid [] = "@(#)udb.c 8.6 (Berkeley) 03/11/94 (with USERDB)"; 1451360Seric #else 15*66334Seric static char sccsid [] = "@(#)udb.c 8.6 (Berkeley) 03/11/94 (without USERDB)"; 1650581Seric #endif 1751360Seric #endif 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2151923Seric #include <errno.h> 2251360Seric #include <netdb.h> 2350581Seric #include <db.h> 2450581Seric 2550581Seric /* 2653654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 2750581Seric ** 2851363Seric ** This depends on the 4.4BSD db package. 2950581Seric */ 3050581Seric 3151362Seric 3251360Seric struct udbent 3351360Seric { 3451360Seric char *udb_spec; /* string version of spec */ 3551360Seric int udb_type; /* type of entry */ 3651951Seric char *udb_default; /* default host for outgoing mail */ 3751360Seric union 3851360Seric { 3951360Seric /* type UE_REMOTE -- do remote call for lookup */ 4051360Seric struct 4151360Seric { 4251360Seric struct sockaddr_in _udb_addr; /* address */ 4351360Seric int _udb_timeout; /* timeout */ 4451360Seric } udb_remote; 4551360Seric #define udb_addr udb_u.udb_remote._udb_addr 4651360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 4751360Seric 4851360Seric /* type UE_FORWARD -- forward message to remote */ 4951360Seric struct 5051360Seric { 5151360Seric char *_udb_fwdhost; /* name of forward host */ 5251360Seric } udb_forward; 5351360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 5451360Seric 5551951Seric /* type UE_FETCH -- lookup in local database */ 5651360Seric struct 5751360Seric { 5851360Seric char *_udb_dbname; /* pathname of database */ 5951360Seric DB *_udb_dbp; /* open database ptr */ 6051360Seric } udb_lookup; 6151360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 6251360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 6351360Seric } udb_u; 6451360Seric }; 6551360Seric 6651360Seric #define UDB_EOLIST 0 /* end of list */ 6751360Seric #define UDB_SKIP 1 /* skip this entry */ 6851360Seric #define UDB_REMOTE 2 /* look up in remote database */ 6951951Seric #define UDB_DBFETCH 3 /* look up in local database */ 7051360Seric #define UDB_FORWARD 4 /* forward to remote host */ 7151360Seric 7251360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 7351360Seric 7451363Seric 7551363Seric struct option 7651363Seric { 7751363Seric char *name; 7851363Seric char *val; 7951363Seric }; 8051363Seric /* 8151363Seric ** UDBEXPAND -- look up user in database and expand 8251363Seric ** 8351363Seric ** Parameters: 8451363Seric ** a -- address to expand. 8551363Seric ** sendq -- pointer to head of sendq to put the expansions in. 8651363Seric ** 8751363Seric ** Returns: 8851923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 8951923Seric ** to accessing a file on an NFS server that is down. 9051923Seric ** EX_OK -- otherwise. 9151363Seric ** 9251363Seric ** Side Effects: 9351363Seric ** Modifies sendq. 9451363Seric */ 9551363Seric 9651363Seric int UdbPort = 1616; 9751363Seric int UdbTimeout = 10; 9851363Seric 9951953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10051953Seric int UdbSock = -1; 10151953Seric bool UdbInitialized = FALSE; 10251360Seric 10351923Seric int 10455012Seric udbexpand(a, sendq, e) 10550581Seric register ADDRESS *a; 10650581Seric ADDRESS **sendq; 10755012Seric register ENVELOPE *e; 10850581Seric { 10950581Seric int i; 11050581Seric register char *p; 11150581Seric DBT key; 11250581Seric DBT info; 11351360Seric bool breakout; 11451360Seric register struct udbent *up; 11551362Seric int keylen; 11658082Seric int naddrs; 11757232Seric char keybuf[MAXKEY]; 11857232Seric char buf[BUFSIZ]; 11950581Seric 12050581Seric if (tTd(28, 1)) 12158065Seric printf("udbexpand(%s)\n", a->q_paddr); 12250581Seric 12350581Seric /* make certain we are supposed to send to this address */ 12458154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 12551923Seric return EX_OK; 12655012Seric e->e_to = a->q_paddr; 12750581Seric 12851360Seric /* on first call, locate the database */ 12951951Seric if (!UdbInitialized) 13050581Seric { 13151923Seric extern int _udbx_init(); 13251362Seric 13351923Seric if (_udbx_init() == EX_TEMPFAIL) 13451923Seric return EX_TEMPFAIL; 13551362Seric } 13650581Seric 13751909Seric /* short circuit the process if no chance of a match */ 13851909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 13951923Seric return EX_OK; 14051909Seric 14151362Seric /* if name is too long, assume it won't match */ 14251362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 14351923Seric return EX_OK; 14451360Seric 14551362Seric /* if name begins with a colon, it indicates our metadata */ 14651362Seric if (a->q_user[0] == ':') 14751923Seric return EX_OK; 14851360Seric 14951362Seric /* build actual database key */ 15051362Seric (void) strcpy(keybuf, a->q_user); 15151362Seric (void) strcat(keybuf, ":maildrop"); 15251362Seric keylen = strlen(keybuf); 15351360Seric 15451360Seric breakout = FALSE; 15551362Seric for (up = UdbEnts; !breakout; up++) 15650581Seric { 15751360Seric char *user; 15850581Seric 15951360Seric /* 16051360Seric ** Select action based on entry type. 16151360Seric ** 16251360Seric ** On dropping out of this switch, "class" should 16351360Seric ** explain the type of the data, and "user" should 16451360Seric ** contain the user information. 16551360Seric */ 16650581Seric 16751360Seric switch (up->udb_type) 16851360Seric { 16951951Seric case UDB_DBFETCH: 17051362Seric key.data = keybuf; 17151362Seric key.size = keylen; 17260990Seric if (tTd(28, 80)) 17364067Seric printf("udbexpand: trying %s (%d)\n", 17464067Seric keybuf, keylen); 17551362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 17651923Seric if (i > 0 || info.size <= 0) 17751360Seric { 17851360Seric if (tTd(28, 2)) 17964067Seric printf("udbexpand: no match on %s (%d)\n", 18064067Seric keybuf, keylen); 18151360Seric continue; 18251360Seric } 18360990Seric if (tTd(28, 80)) 18460990Seric printf("udbexpand: match %.*s: %.*s\n", 18560990Seric key.size, key.data, info.size, info.data); 18650581Seric 18758082Seric naddrs = 0; 18858082Seric a->q_flags &= ~QSELFREF; 18951830Seric while (i == 0 && key.size == keylen && 19051830Seric bcmp(key.data, keybuf, keylen) == 0) 19151362Seric { 19258099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 19358154Seric { 19458154Seric a->q_flags |= QVERIFIED; 19558884Seric e->e_nrcpts++; 19658099Seric return EX_OK; 19758154Seric } 19858099Seric 19951830Seric breakout = TRUE; 20051362Seric if (info.size < sizeof buf) 20151362Seric user = buf; 20251362Seric else 20351362Seric user = xalloc(info.size + 1); 20451362Seric bcopy(info.data, user, info.size); 20551362Seric user[info.size] = '\0'; 20650581Seric 20758151Seric message("expanded to %s", user); 20857977Seric #ifdef LOG 20957977Seric if (LogLevel >= 10) 21057977Seric syslog(LOG_INFO, "%s: expand %s => %s", 21157977Seric e->e_id, e->e_to, user); 21257977Seric #endif 21351362Seric AliasLevel++; 21458082Seric naddrs += sendtolist(user, a, sendq, e); 21551362Seric AliasLevel--; 21651362Seric 21751362Seric if (user != buf) 21851362Seric free(user); 21951362Seric 22051362Seric /* get the next record */ 22151362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 22251830Seric } 22360990Seric 22460990Seric /* if nothing ever matched, try next database */ 22560990Seric if (!breakout) 22660990Seric continue; 22760990Seric 22858082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 22958065Seric { 23058065Seric if (tTd(28, 5)) 23158065Seric { 23258065Seric printf("udbexpand: QDONTSEND "); 23358065Seric printaddr(a, FALSE); 23458065Seric } 23558065Seric a->q_flags |= QDONTSEND; 23658065Seric } 23751923Seric if (i < 0) 23851923Seric { 23958010Seric syserr("udbexpand: db-get %.*s stat %d", 24058010Seric key.size, key.data, i); 24151923Seric return EX_TEMPFAIL; 24251923Seric } 24359707Seric 24459707Seric /* 24559707Seric ** If this address has a -request address, reflect 24659707Seric ** it into the envelope. 24759707Seric */ 24859707Seric 24959707Seric (void) strcpy(keybuf, a->q_user); 25059707Seric (void) strcat(keybuf, ":mailsender"); 25159707Seric keylen = strlen(keybuf); 25259707Seric key.data = keybuf; 25359707Seric key.size = keylen; 25459707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 25559707Seric if (i != 0 || info.size <= 0) 25659707Seric break; 25759707Seric a->q_owner = xalloc(info.size + 1); 25859707Seric bcopy(info.data, a->q_owner, info.size); 25959707Seric a->q_owner[info.size] = '\0'; 26051360Seric break; 26151360Seric 26251360Seric case UDB_REMOTE: 26351741Seric /* not yet implemented */ 26451741Seric continue; 26551362Seric 26651360Seric case UDB_FORWARD: 26758099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 26858099Seric return EX_OK; 26951360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 27051360Seric if (i < sizeof buf) 27151360Seric user = buf; 27251360Seric else 27351360Seric user = xalloc(i + 1); 27451360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 27558151Seric message("expanded to %s", user); 27658082Seric a->q_flags &= ~QSELFREF; 27751362Seric AliasLevel++; 27858082Seric naddrs = sendtolist(user, a, sendq, e); 27951362Seric AliasLevel--; 28058082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 28158065Seric { 28258065Seric if (tTd(28, 5)) 28358065Seric { 28458065Seric printf("udbexpand: QDONTSEND "); 28558065Seric printaddr(a, FALSE); 28658065Seric } 28758065Seric a->q_flags |= QDONTSEND; 28858065Seric } 28951362Seric if (user != buf) 29051362Seric free(user); 29151362Seric breakout = TRUE; 29251360Seric break; 29351360Seric 29451360Seric case UDB_EOLIST: 29551360Seric breakout = TRUE; 29651360Seric continue; 29751360Seric 29851360Seric default: 29951360Seric /* unknown entry type */ 30051360Seric continue; 30151360Seric } 30251362Seric } 30351923Seric return EX_OK; 30451362Seric } 30551951Seric /* 30651951Seric ** UDBSENDER -- return canonical external name of sender, given local name 30751951Seric ** 30851951Seric ** Parameters: 30951951Seric ** sender -- the name of the sender on the local machine. 31051951Seric ** 31151951Seric ** Returns: 31251951Seric ** The external name for this sender, if derivable from the 31351951Seric ** database. 31451951Seric ** NULL -- if nothing is changed from the database. 31551951Seric ** 31651951Seric ** Side Effects: 31751951Seric ** none. 31851951Seric */ 31951360Seric 32051951Seric char * 32151951Seric udbsender(sender) 32251951Seric char *sender; 32351951Seric { 32464350Seric extern char *udbmatch(); 32564350Seric 32664350Seric return udbmatch(sender, "mailname"); 32764350Seric } 32864350Seric 32964350Seric 33064350Seric char * 33164350Seric udbmatch(user, field) 33264350Seric char *user; 33364350Seric char *field; 33464350Seric { 33551951Seric register char *p; 33651951Seric register struct udbent *up; 33751951Seric int i; 33851951Seric int keylen; 33951951Seric DBT key, info; 34057232Seric char keybuf[MAXKEY]; 34151951Seric 34251951Seric if (tTd(28, 1)) 34364350Seric printf("udbmatch(%s, %s)\n", user, field); 34451951Seric 34551951Seric if (!UdbInitialized) 34651951Seric { 34751951Seric if (_udbx_init() == EX_TEMPFAIL) 34851951Seric return NULL; 34951951Seric } 35051951Seric 35151951Seric /* short circuit if no spec */ 35251951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 35351951Seric return NULL; 35451951Seric 35551951Seric /* long names can never match and are a pain to deal with */ 35664350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 35751951Seric return NULL; 35851951Seric 35951951Seric /* names beginning with colons indicate metadata */ 36064350Seric if (user[0] == ':') 36151951Seric return NULL; 36251951Seric 36351951Seric /* build database key */ 36464350Seric (void) strcpy(keybuf, user); 36564350Seric (void) strcat(keybuf, ":"); 36664350Seric (void) strcat(keybuf, field); 36751951Seric keylen = strlen(keybuf); 36851951Seric 36951951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 37051951Seric { 37151951Seric /* 37251951Seric ** Select action based on entry type. 37351951Seric */ 37451951Seric 37551951Seric switch (up->udb_type) 37651951Seric { 37751951Seric case UDB_DBFETCH: 37851951Seric key.data = keybuf; 37951951Seric key.size = keylen; 38051951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 38151951Seric if (i != 0 || info.size <= 0) 38251951Seric { 38351951Seric if (tTd(28, 2)) 38464350Seric printf("udbmatch: no match on %s (%d)\n", 38564067Seric keybuf, keylen); 38651951Seric continue; 38751951Seric } 38851951Seric 38951951Seric p = xalloc(info.size + 1); 39051951Seric bcopy(info.data, p, info.size); 39151951Seric p[info.size] = '\0'; 39251951Seric if (tTd(28, 1)) 39364350Seric printf("udbmatch ==> %s\n", p); 39451951Seric return p; 39551951Seric } 39651951Seric } 39751951Seric 39864350Seric if (strcmp(field, "mailname") != 0) 39964350Seric return NULL; 40064350Seric 40151951Seric /* 40251951Seric ** Nothing yet. Search again for a default case. But only 40351951Seric ** use it if we also have a forward (:maildrop) pointer already 40451951Seric ** in the database. 40551951Seric */ 40651951Seric 40751951Seric /* build database key */ 40864350Seric (void) strcpy(keybuf, user); 40951951Seric (void) strcat(keybuf, ":maildrop"); 41051951Seric keylen = strlen(keybuf); 41151951Seric 41251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 41351951Seric { 41451951Seric switch (up->udb_type) 41551951Seric { 41651951Seric case UDB_DBFETCH: 41751951Seric /* get the default case for this database */ 41851951Seric if (up->udb_default == NULL) 41951951Seric { 42051951Seric key.data = ":default:mailname"; 42151951Seric key.size = strlen(key.data); 42251951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 42351951Seric if (i != 0 || info.size <= 0) 42451951Seric { 42551951Seric /* no default case */ 42651951Seric up->udb_default = ""; 42751951Seric continue; 42851951Seric } 42951951Seric 43051951Seric /* save the default case */ 43151951Seric up->udb_default = xalloc(info.size + 1); 43251951Seric bcopy(info.data, up->udb_default, info.size); 43351951Seric up->udb_default[info.size] = '\0'; 43451951Seric } 43551951Seric else if (up->udb_default[0] == '\0') 43651951Seric continue; 43751951Seric 43851951Seric /* we have a default case -- verify user:maildrop */ 43951951Seric key.data = keybuf; 44051951Seric key.size = keylen; 44151951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 44251951Seric if (i != 0 || info.size <= 0) 44351951Seric { 44451951Seric /* nope -- no aliasing for this user */ 44551951Seric continue; 44651951Seric } 44751951Seric 44851951Seric /* they exist -- build the actual address */ 44964350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 45064350Seric (void) strcpy(p, user); 45151951Seric (void) strcat(p, "@"); 45251951Seric (void) strcat(p, up->udb_default); 45351951Seric if (tTd(28, 1)) 45464350Seric printf("udbmatch ==> %s\n", p); 45551951Seric return p; 45651951Seric } 45751951Seric } 45851951Seric 45951951Seric /* still nothing.... too bad */ 46051951Seric return NULL; 46151951Seric } 46251951Seric /* 46351951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 46451951Seric ** 46551951Seric ** Parameters: 46651951Seric ** none. 46751951Seric ** 46851951Seric ** Returns: 46951951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 47051951Seric ** database due to a host being down or some similar 47151951Seric ** (recoverable) situation. 47251951Seric ** EX_OK -- otherwise. 47351951Seric ** 47451951Seric ** Side Effects: 47551951Seric ** Fills in the UdbEnts structure from UdbSpec. 47651951Seric */ 47751951Seric 47851363Seric #define MAXUDBOPTS 27 47951363Seric 48051953Seric int 48151362Seric _udbx_init() 48251362Seric { 48351362Seric register char *p; 48451362Seric int i; 48551362Seric register struct udbent *up; 48657232Seric char buf[BUFSIZ]; 48751360Seric 48851951Seric if (UdbInitialized) 48951951Seric return EX_OK; 49051951Seric 49151908Seric # ifdef UDB_DEFAULT_SPEC 49251908Seric if (UdbSpec == NULL) 49351908Seric UdbSpec = UDB_DEFAULT_SPEC; 49451908Seric # endif 49551908Seric 49651362Seric p = UdbSpec; 49751362Seric up = UdbEnts; 49851762Seric while (p != NULL) 49951362Seric { 50051362Seric char *spec; 50151362Seric auto int rcode; 50251363Seric int nopts; 50351362Seric int nmx; 50451362Seric register struct hostent *h; 50551362Seric char *mxhosts[MAXMXHOSTS + 1]; 50651363Seric struct option opts[MAXUDBOPTS + 1]; 50751362Seric 50851362Seric while (*p == ' ' || *p == '\t' || *p == ',') 50951362Seric p++; 51051362Seric if (*p == '\0') 51151362Seric break; 51251362Seric spec = p; 51356795Seric p = strchr(p, ','); 51451761Seric if (p != NULL) 51551362Seric *p++ = '\0'; 51651363Seric 51751363Seric /* extract options */ 51851363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 51951363Seric 52051363Seric /* 52151363Seric ** Decode database specification. 52251363Seric ** 52351363Seric ** In the sendmail tradition, the leading character 52451363Seric ** defines the semantics of the rest of the entry. 52551363Seric ** 52651363Seric ** +hostname -- send a datagram to the udb server 52751363Seric ** on host "hostname" asking for the 52851363Seric ** home mail server for this user. 52951363Seric ** *hostname -- similar to +hostname, except that the 53051363Seric ** hostname is searched as an MX record; 53151363Seric ** resulting hosts are searched as for 53251363Seric ** +mxhostname. If no MX host is found, 53351363Seric ** this is the same as +hostname. 53451363Seric ** @hostname -- forward email to the indicated host. 53551363Seric ** This should be the last in the list, 53651363Seric ** since it always matches the input. 53751363Seric ** /dbname -- search the named database on the local 53851363Seric ** host using the Berkeley db package. 53951363Seric */ 54051363Seric 54151362Seric switch (*spec) 54251360Seric { 54351362Seric case '+': /* search remote database */ 54451363Seric case '*': /* search remote database (expand MX) */ 54551363Seric if (*spec == '*') 54651363Seric { 547*66334Seric #if NAMED_BIND 54859273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 54957629Seric #else 55057629Seric mxhosts[0] = spec + 1; 55157629Seric nmx = 1; 55257629Seric rcode = 0; 55357629Seric #endif 55451363Seric if (tTd(28, 16)) 55551363Seric { 55651363Seric int i; 55751362Seric 55851363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 55951363Seric for (i = 0; i <= nmx; i++) 56051363Seric printf(" %s", mxhosts[i]); 56151363Seric printf("\n"); 56251363Seric } 56351363Seric } 56451363Seric else 56551362Seric { 56651363Seric nmx = 1; 56751363Seric mxhosts[0] = spec + 1; 56851362Seric } 56951362Seric 57051362Seric for (i = 0; i < nmx; i++) 57151362Seric { 57251362Seric h = gethostbyname(mxhosts[i]); 57351362Seric if (h == NULL) 57451362Seric continue; 57551362Seric up->udb_type = UDB_REMOTE; 57651362Seric up->udb_addr.sin_family = h->h_addrtype; 57751362Seric bcopy(h->h_addr_list[0], 57851362Seric (char *) &up->udb_addr.sin_addr, 57964943Seric sizeof up->udb_addr.sin_addr); 58051362Seric up->udb_addr.sin_port = UdbPort; 58151362Seric up->udb_timeout = UdbTimeout; 58251362Seric up++; 58351362Seric } 58451362Seric 58551362Seric /* set up a datagram socket */ 58651362Seric if (UdbSock < 0) 58751362Seric { 58851362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 58951362Seric (void) fcntl(UdbSock, F_SETFD, 1); 59051362Seric } 59151362Seric break; 59251362Seric 59351362Seric case '@': /* forward to remote host */ 59451362Seric up->udb_type = UDB_FORWARD; 59551362Seric up->udb_fwdhost = spec + 1; 59651362Seric up++; 59751362Seric break; 59851362Seric 59951362Seric case '/': /* look up remote name */ 60051831Seric up->udb_dbname = spec; 60151923Seric errno = 0; 60251362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 60351362Seric if (up->udb_dbp == NULL) 60451923Seric { 60551923Seric if (errno != ENOENT && errno != EACCES) 60651951Seric { 60759615Seric #ifdef LOG 60859615Seric if (LogLevel > 2) 60959625Seric syslog(LOG_ERR, "dbopen(%s): %s", 61059625Seric spec, errstring(errno)); 61159615Seric #endif 61251951Seric up->udb_type = UDB_EOLIST; 61351951Seric goto tempfail; 61451951Seric } 61551362Seric break; 61651923Seric } 61751951Seric up->udb_type = UDB_DBFETCH; 61851362Seric up++; 61951362Seric break; 62051360Seric } 62151362Seric } 62251362Seric up->udb_type = UDB_EOLIST; 62351360Seric 62451362Seric if (tTd(28, 4)) 62551362Seric { 62651951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 62751360Seric { 62851362Seric switch (up->udb_type) 62951362Seric { 63051362Seric case UDB_REMOTE: 63151362Seric printf("REMOTE: addr %s, timeo %d\n", 63260494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 63351362Seric up->udb_timeout); 63451362Seric break; 63551362Seric 63651951Seric case UDB_DBFETCH: 63751951Seric printf("FETCH: file %s\n", 63851830Seric up->udb_dbname); 63951362Seric break; 64051362Seric 64151362Seric case UDB_FORWARD: 64251362Seric printf("FORWARD: host %s\n", 64351362Seric up->udb_fwdhost); 64451362Seric break; 64551362Seric 64651362Seric default: 64751362Seric printf("UNKNOWN\n"); 64851362Seric break; 64951362Seric } 65051360Seric } 65150581Seric } 65251951Seric 65351951Seric UdbInitialized = TRUE; 65451955Seric errno = 0; 65551951Seric return EX_OK; 65651951Seric 65751951Seric /* 65851951Seric ** On temporary failure, back out anything we've already done 65951951Seric */ 66051951Seric 66151951Seric tempfail: 66251951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 66351951Seric { 66451951Seric if (up->udb_type == UDB_DBFETCH) 66551951Seric { 66651951Seric (*up->udb_dbp->close)(up->udb_dbp); 66751951Seric } 66851951Seric } 66951951Seric return EX_TEMPFAIL; 67051360Seric } 67150581Seric 67251363Seric int 67351363Seric _udb_parsespec(udbspec, opt, maxopts) 67451363Seric char *udbspec; 67551363Seric struct option opt[]; 67651363Seric int maxopts; 67751363Seric { 67851363Seric register char *spec; 67951363Seric register char *spec_end; 68051363Seric register int optnum; 68151363Seric 68256795Seric spec_end = strchr(udbspec, ':'); 68351363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 68451363Seric { 68551363Seric register char *p; 68651363Seric 68758050Seric while (isascii(*spec) && isspace(*spec)) 68851363Seric spec++; 68956795Seric spec_end = strchr(spec, ':'); 69051363Seric if (spec_end != NULL) 69151363Seric *spec_end++ = '\0'; 69251363Seric 69351363Seric opt[optnum].name = spec; 69451363Seric opt[optnum].val = NULL; 69556795Seric p = strchr(spec, '='); 69651363Seric if (p != NULL) 69751363Seric opt[optnum].val = ++p; 69851363Seric } 69951363Seric return optnum; 70051363Seric } 70151363Seric 70251360Seric #else /* not USERDB */ 70351360Seric 70451923Seric int 70555012Seric udbexpand(a, sendq, e) 70651360Seric ADDRESS *a; 70751360Seric ADDRESS **sendq; 70855012Seric ENVELOPE *e; 70951360Seric { 71051923Seric return EX_OK; 71150581Seric } 71250581Seric 71350581Seric #endif /* USERDB */ 714