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*64350Seric static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 08/25/93 (with USERDB)"; 1451360Seric #else 15*64350Seric static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 08/25/93 (without USERDB)"; 1650581Seric #endif 1751360Seric #endif 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2151360Seric #include <sys/time.h> 2251923Seric #include <errno.h> 2351360Seric #include <netdb.h> 2450581Seric #include <db.h> 2550581Seric 2650581Seric /* 2753654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 2850581Seric ** 2951363Seric ** This depends on the 4.4BSD db package. 3050581Seric */ 3150581Seric 3251362Seric 3351360Seric struct udbent 3451360Seric { 3551360Seric char *udb_spec; /* string version of spec */ 3651360Seric int udb_type; /* type of entry */ 3751951Seric char *udb_default; /* default host for outgoing mail */ 3851360Seric union 3951360Seric { 4051360Seric /* type UE_REMOTE -- do remote call for lookup */ 4151360Seric struct 4251360Seric { 4351360Seric struct sockaddr_in _udb_addr; /* address */ 4451360Seric int _udb_timeout; /* timeout */ 4551360Seric } udb_remote; 4651360Seric #define udb_addr udb_u.udb_remote._udb_addr 4751360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 4851360Seric 4951360Seric /* type UE_FORWARD -- forward message to remote */ 5051360Seric struct 5151360Seric { 5251360Seric char *_udb_fwdhost; /* name of forward host */ 5351360Seric } udb_forward; 5451360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 5551360Seric 5651951Seric /* type UE_FETCH -- lookup in local database */ 5751360Seric struct 5851360Seric { 5951360Seric char *_udb_dbname; /* pathname of database */ 6051360Seric DB *_udb_dbp; /* open database ptr */ 6151360Seric } udb_lookup; 6251360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 6351360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 6451360Seric } udb_u; 6551360Seric }; 6651360Seric 6751360Seric #define UDB_EOLIST 0 /* end of list */ 6851360Seric #define UDB_SKIP 1 /* skip this entry */ 6951360Seric #define UDB_REMOTE 2 /* look up in remote database */ 7051951Seric #define UDB_DBFETCH 3 /* look up in local database */ 7151360Seric #define UDB_FORWARD 4 /* forward to remote host */ 7251360Seric 7351360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 7451360Seric 7551363Seric 7651363Seric struct option 7751363Seric { 7851363Seric char *name; 7951363Seric char *val; 8051363Seric }; 8151363Seric /* 8251363Seric ** UDBEXPAND -- look up user in database and expand 8351363Seric ** 8451363Seric ** Parameters: 8551363Seric ** a -- address to expand. 8651363Seric ** sendq -- pointer to head of sendq to put the expansions in. 8751363Seric ** 8851363Seric ** Returns: 8951923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 9051923Seric ** to accessing a file on an NFS server that is down. 9151923Seric ** EX_OK -- otherwise. 9251363Seric ** 9351363Seric ** Side Effects: 9451363Seric ** Modifies sendq. 9551363Seric */ 9651363Seric 9751363Seric int UdbPort = 1616; 9851363Seric int UdbTimeout = 10; 9951363Seric 10051953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10151953Seric int UdbSock = -1; 10251953Seric bool UdbInitialized = FALSE; 10351360Seric 10451923Seric int 10555012Seric udbexpand(a, sendq, e) 10650581Seric register ADDRESS *a; 10750581Seric ADDRESS **sendq; 10855012Seric register ENVELOPE *e; 10950581Seric { 11050581Seric int i; 11150581Seric register char *p; 11250581Seric DBT key; 11350581Seric DBT info; 11451360Seric bool breakout; 11551360Seric register struct udbent *up; 11651362Seric int keylen; 11758082Seric int naddrs; 11857232Seric char keybuf[MAXKEY]; 11957232Seric char buf[BUFSIZ]; 12050581Seric 12150581Seric if (tTd(28, 1)) 12258065Seric printf("udbexpand(%s)\n", a->q_paddr); 12350581Seric 12450581Seric /* make certain we are supposed to send to this address */ 12558154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 12651923Seric return EX_OK; 12755012Seric e->e_to = a->q_paddr; 12850581Seric 12951360Seric /* on first call, locate the database */ 13051951Seric if (!UdbInitialized) 13150581Seric { 13251923Seric extern int _udbx_init(); 13351362Seric 13451923Seric if (_udbx_init() == EX_TEMPFAIL) 13551923Seric return EX_TEMPFAIL; 13651362Seric } 13750581Seric 13851909Seric /* short circuit the process if no chance of a match */ 13951909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 14051923Seric return EX_OK; 14151909Seric 14251362Seric /* if name is too long, assume it won't match */ 14351362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 14451923Seric return EX_OK; 14551360Seric 14651362Seric /* if name begins with a colon, it indicates our metadata */ 14751362Seric if (a->q_user[0] == ':') 14851923Seric return EX_OK; 14951360Seric 15051362Seric /* build actual database key */ 15151362Seric (void) strcpy(keybuf, a->q_user); 15251362Seric (void) strcat(keybuf, ":maildrop"); 15351362Seric keylen = strlen(keybuf); 15451360Seric 15551360Seric breakout = FALSE; 15651362Seric for (up = UdbEnts; !breakout; up++) 15750581Seric { 15851360Seric char *user; 15950581Seric 16051360Seric /* 16151360Seric ** Select action based on entry type. 16251360Seric ** 16351360Seric ** On dropping out of this switch, "class" should 16451360Seric ** explain the type of the data, and "user" should 16551360Seric ** contain the user information. 16651360Seric */ 16750581Seric 16851360Seric switch (up->udb_type) 16951360Seric { 17051951Seric case UDB_DBFETCH: 17151362Seric key.data = keybuf; 17251362Seric key.size = keylen; 17360990Seric if (tTd(28, 80)) 17464067Seric printf("udbexpand: trying %s (%d)\n", 17564067Seric keybuf, keylen); 17651362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 17751923Seric if (i > 0 || info.size <= 0) 17851360Seric { 17951360Seric if (tTd(28, 2)) 18064067Seric printf("udbexpand: no match on %s (%d)\n", 18164067Seric keybuf, keylen); 18251360Seric continue; 18351360Seric } 18460990Seric if (tTd(28, 80)) 18560990Seric printf("udbexpand: match %.*s: %.*s\n", 18660990Seric key.size, key.data, info.size, info.data); 18750581Seric 18858082Seric naddrs = 0; 18958082Seric a->q_flags &= ~QSELFREF; 19051830Seric while (i == 0 && key.size == keylen && 19151830Seric bcmp(key.data, keybuf, keylen) == 0) 19251362Seric { 19358099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 19458154Seric { 19558154Seric a->q_flags |= QVERIFIED; 19658884Seric e->e_nrcpts++; 19758099Seric return EX_OK; 19858154Seric } 19958099Seric 20051830Seric breakout = TRUE; 20151362Seric if (info.size < sizeof buf) 20251362Seric user = buf; 20351362Seric else 20451362Seric user = xalloc(info.size + 1); 20551362Seric bcopy(info.data, user, info.size); 20651362Seric user[info.size] = '\0'; 20750581Seric 20858151Seric message("expanded to %s", user); 20957977Seric #ifdef LOG 21057977Seric if (LogLevel >= 10) 21157977Seric syslog(LOG_INFO, "%s: expand %s => %s", 21257977Seric e->e_id, e->e_to, user); 21357977Seric #endif 21451362Seric AliasLevel++; 21558082Seric naddrs += sendtolist(user, a, sendq, e); 21651362Seric AliasLevel--; 21751362Seric 21851362Seric if (user != buf) 21951362Seric free(user); 22051362Seric 22151362Seric /* get the next record */ 22251362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 22351830Seric } 22460990Seric 22560990Seric /* if nothing ever matched, try next database */ 22660990Seric if (!breakout) 22760990Seric continue; 22860990Seric 22958082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 23058065Seric { 23158065Seric if (tTd(28, 5)) 23258065Seric { 23358065Seric printf("udbexpand: QDONTSEND "); 23458065Seric printaddr(a, FALSE); 23558065Seric } 23658065Seric a->q_flags |= QDONTSEND; 23758065Seric } 23851923Seric if (i < 0) 23951923Seric { 24058010Seric syserr("udbexpand: db-get %.*s stat %d", 24158010Seric key.size, key.data, i); 24251923Seric return EX_TEMPFAIL; 24351923Seric } 24459707Seric 24559707Seric /* 24659707Seric ** If this address has a -request address, reflect 24759707Seric ** it into the envelope. 24859707Seric */ 24959707Seric 25059707Seric (void) strcpy(keybuf, a->q_user); 25159707Seric (void) strcat(keybuf, ":mailsender"); 25259707Seric keylen = strlen(keybuf); 25359707Seric key.data = keybuf; 25459707Seric key.size = keylen; 25559707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 25659707Seric if (i != 0 || info.size <= 0) 25759707Seric break; 25859707Seric a->q_owner = xalloc(info.size + 1); 25959707Seric bcopy(info.data, a->q_owner, info.size); 26059707Seric a->q_owner[info.size] = '\0'; 26151360Seric break; 26251360Seric 26351360Seric case UDB_REMOTE: 26451741Seric /* not yet implemented */ 26551741Seric continue; 26651362Seric 26751360Seric case UDB_FORWARD: 26858099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 26958099Seric return EX_OK; 27051360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 27151360Seric if (i < sizeof buf) 27251360Seric user = buf; 27351360Seric else 27451360Seric user = xalloc(i + 1); 27551360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 27658151Seric message("expanded to %s", user); 27758082Seric a->q_flags &= ~QSELFREF; 27851362Seric AliasLevel++; 27958082Seric naddrs = sendtolist(user, a, sendq, e); 28051362Seric AliasLevel--; 28158082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 28258065Seric { 28358065Seric if (tTd(28, 5)) 28458065Seric { 28558065Seric printf("udbexpand: QDONTSEND "); 28658065Seric printaddr(a, FALSE); 28758065Seric } 28858065Seric a->q_flags |= QDONTSEND; 28958065Seric } 29051362Seric if (user != buf) 29151362Seric free(user); 29251362Seric breakout = TRUE; 29351360Seric break; 29451360Seric 29551360Seric case UDB_EOLIST: 29651360Seric breakout = TRUE; 29751360Seric continue; 29851360Seric 29951360Seric default: 30051360Seric /* unknown entry type */ 30151360Seric continue; 30251360Seric } 30351362Seric } 30451923Seric return EX_OK; 30551362Seric } 30651951Seric /* 30751951Seric ** UDBSENDER -- return canonical external name of sender, given local name 30851951Seric ** 30951951Seric ** Parameters: 31051951Seric ** sender -- the name of the sender on the local machine. 31151951Seric ** 31251951Seric ** Returns: 31351951Seric ** The external name for this sender, if derivable from the 31451951Seric ** database. 31551951Seric ** NULL -- if nothing is changed from the database. 31651951Seric ** 31751951Seric ** Side Effects: 31851951Seric ** none. 31951951Seric */ 32051360Seric 32151951Seric char * 32251951Seric udbsender(sender) 32351951Seric char *sender; 32451951Seric { 325*64350Seric extern char *udbmatch(); 326*64350Seric 327*64350Seric return udbmatch(sender, "mailname"); 328*64350Seric } 329*64350Seric 330*64350Seric 331*64350Seric char * 332*64350Seric udbmatch(user, field) 333*64350Seric char *user; 334*64350Seric char *field; 335*64350Seric { 33651951Seric register char *p; 33751951Seric register struct udbent *up; 33851951Seric int i; 33951951Seric int keylen; 34051951Seric DBT key, info; 34157232Seric char keybuf[MAXKEY]; 34251951Seric 34351951Seric if (tTd(28, 1)) 344*64350Seric printf("udbmatch(%s, %s)\n", user, field); 34551951Seric 34651951Seric if (!UdbInitialized) 34751951Seric { 34851951Seric if (_udbx_init() == EX_TEMPFAIL) 34951951Seric return NULL; 35051951Seric } 35151951Seric 35251951Seric /* short circuit if no spec */ 35351951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 35451951Seric return NULL; 35551951Seric 35651951Seric /* long names can never match and are a pain to deal with */ 357*64350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 35851951Seric return NULL; 35951951Seric 36051951Seric /* names beginning with colons indicate metadata */ 361*64350Seric if (user[0] == ':') 36251951Seric return NULL; 36351951Seric 36451951Seric /* build database key */ 365*64350Seric (void) strcpy(keybuf, user); 366*64350Seric (void) strcat(keybuf, ":"); 367*64350Seric (void) strcat(keybuf, field); 36851951Seric keylen = strlen(keybuf); 36951951Seric 37051951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 37151951Seric { 37251951Seric /* 37351951Seric ** Select action based on entry type. 37451951Seric */ 37551951Seric 37651951Seric switch (up->udb_type) 37751951Seric { 37851951Seric case UDB_DBFETCH: 37951951Seric key.data = keybuf; 38051951Seric key.size = keylen; 38151951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 38251951Seric if (i != 0 || info.size <= 0) 38351951Seric { 38451951Seric if (tTd(28, 2)) 385*64350Seric printf("udbmatch: no match on %s (%d)\n", 38664067Seric keybuf, keylen); 38751951Seric continue; 38851951Seric } 38951951Seric 39051951Seric p = xalloc(info.size + 1); 39151951Seric bcopy(info.data, p, info.size); 39251951Seric p[info.size] = '\0'; 39351951Seric if (tTd(28, 1)) 394*64350Seric printf("udbmatch ==> %s\n", p); 39551951Seric return p; 39651951Seric } 39751951Seric } 39851951Seric 399*64350Seric if (strcmp(field, "mailname") != 0) 400*64350Seric return NULL; 401*64350Seric 40251951Seric /* 40351951Seric ** Nothing yet. Search again for a default case. But only 40451951Seric ** use it if we also have a forward (:maildrop) pointer already 40551951Seric ** in the database. 40651951Seric */ 40751951Seric 40851951Seric /* build database key */ 409*64350Seric (void) strcpy(keybuf, user); 41051951Seric (void) strcat(keybuf, ":maildrop"); 41151951Seric keylen = strlen(keybuf); 41251951Seric 41351951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 41451951Seric { 41551951Seric switch (up->udb_type) 41651951Seric { 41751951Seric case UDB_DBFETCH: 41851951Seric /* get the default case for this database */ 41951951Seric if (up->udb_default == NULL) 42051951Seric { 42151951Seric key.data = ":default:mailname"; 42251951Seric key.size = strlen(key.data); 42351951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 42451951Seric if (i != 0 || info.size <= 0) 42551951Seric { 42651951Seric /* no default case */ 42751951Seric up->udb_default = ""; 42851951Seric continue; 42951951Seric } 43051951Seric 43151951Seric /* save the default case */ 43251951Seric up->udb_default = xalloc(info.size + 1); 43351951Seric bcopy(info.data, up->udb_default, info.size); 43451951Seric up->udb_default[info.size] = '\0'; 43551951Seric } 43651951Seric else if (up->udb_default[0] == '\0') 43751951Seric continue; 43851951Seric 43951951Seric /* we have a default case -- verify user:maildrop */ 44051951Seric key.data = keybuf; 44151951Seric key.size = keylen; 44251951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 44351951Seric if (i != 0 || info.size <= 0) 44451951Seric { 44551951Seric /* nope -- no aliasing for this user */ 44651951Seric continue; 44751951Seric } 44851951Seric 44951951Seric /* they exist -- build the actual address */ 450*64350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 451*64350Seric (void) strcpy(p, user); 45251951Seric (void) strcat(p, "@"); 45351951Seric (void) strcat(p, up->udb_default); 45451951Seric if (tTd(28, 1)) 455*64350Seric printf("udbmatch ==> %s\n", p); 45651951Seric return p; 45751951Seric } 45851951Seric } 45951951Seric 46051951Seric /* still nothing.... too bad */ 46151951Seric return NULL; 46251951Seric } 46351951Seric /* 46451951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 46551951Seric ** 46651951Seric ** Parameters: 46751951Seric ** none. 46851951Seric ** 46951951Seric ** Returns: 47051951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 47151951Seric ** database due to a host being down or some similar 47251951Seric ** (recoverable) situation. 47351951Seric ** EX_OK -- otherwise. 47451951Seric ** 47551951Seric ** Side Effects: 47651951Seric ** Fills in the UdbEnts structure from UdbSpec. 47751951Seric */ 47851951Seric 47951363Seric #define MAXUDBOPTS 27 48051363Seric 48151953Seric int 48251362Seric _udbx_init() 48351362Seric { 48451362Seric register char *p; 48551362Seric int i; 48651362Seric register struct udbent *up; 48757232Seric char buf[BUFSIZ]; 48851360Seric 48951951Seric if (UdbInitialized) 49051951Seric return EX_OK; 49151951Seric 49251908Seric # ifdef UDB_DEFAULT_SPEC 49351908Seric if (UdbSpec == NULL) 49451908Seric UdbSpec = UDB_DEFAULT_SPEC; 49551908Seric # endif 49651908Seric 49751362Seric p = UdbSpec; 49851362Seric up = UdbEnts; 49951762Seric while (p != NULL) 50051362Seric { 50151362Seric char *spec; 50251362Seric auto int rcode; 50351363Seric int nopts; 50451362Seric int nmx; 50551362Seric register struct hostent *h; 50651362Seric char *mxhosts[MAXMXHOSTS + 1]; 50751363Seric struct option opts[MAXUDBOPTS + 1]; 50851362Seric 50951362Seric while (*p == ' ' || *p == '\t' || *p == ',') 51051362Seric p++; 51151362Seric if (*p == '\0') 51251362Seric break; 51351362Seric spec = p; 51456795Seric p = strchr(p, ','); 51551761Seric if (p != NULL) 51651362Seric *p++ = '\0'; 51751363Seric 51851363Seric /* extract options */ 51951363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 52051363Seric 52151363Seric /* 52251363Seric ** Decode database specification. 52351363Seric ** 52451363Seric ** In the sendmail tradition, the leading character 52551363Seric ** defines the semantics of the rest of the entry. 52651363Seric ** 52751363Seric ** +hostname -- send a datagram to the udb server 52851363Seric ** on host "hostname" asking for the 52951363Seric ** home mail server for this user. 53051363Seric ** *hostname -- similar to +hostname, except that the 53151363Seric ** hostname is searched as an MX record; 53251363Seric ** resulting hosts are searched as for 53351363Seric ** +mxhostname. If no MX host is found, 53451363Seric ** this is the same as +hostname. 53551363Seric ** @hostname -- forward email to the indicated host. 53651363Seric ** This should be the last in the list, 53751363Seric ** since it always matches the input. 53851363Seric ** /dbname -- search the named database on the local 53951363Seric ** host using the Berkeley db package. 54051363Seric */ 54151363Seric 54251362Seric switch (*spec) 54351360Seric { 54451362Seric case '+': /* search remote database */ 54551363Seric case '*': /* search remote database (expand MX) */ 54651363Seric if (*spec == '*') 54751363Seric { 54857629Seric #ifdef NAMED_BIND 54959273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 55057629Seric #else 55157629Seric mxhosts[0] = spec + 1; 55257629Seric nmx = 1; 55357629Seric rcode = 0; 55457629Seric #endif 55551363Seric if (tTd(28, 16)) 55651363Seric { 55751363Seric int i; 55851362Seric 55951363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 56051363Seric for (i = 0; i <= nmx; i++) 56151363Seric printf(" %s", mxhosts[i]); 56251363Seric printf("\n"); 56351363Seric } 56451363Seric } 56551363Seric else 56651362Seric { 56751363Seric nmx = 1; 56851363Seric mxhosts[0] = spec + 1; 56951362Seric } 57051362Seric 57151362Seric for (i = 0; i < nmx; i++) 57251362Seric { 57351362Seric h = gethostbyname(mxhosts[i]); 57451362Seric if (h == NULL) 57551362Seric continue; 57651362Seric up->udb_type = UDB_REMOTE; 57751362Seric up->udb_addr.sin_family = h->h_addrtype; 57851362Seric bcopy(h->h_addr_list[0], 57951362Seric (char *) &up->udb_addr.sin_addr, 58051362Seric h->h_length); 58151362Seric up->udb_addr.sin_port = UdbPort; 58251362Seric up->udb_timeout = UdbTimeout; 58351362Seric up++; 58451362Seric } 58551362Seric 58651362Seric /* set up a datagram socket */ 58751362Seric if (UdbSock < 0) 58851362Seric { 58951362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 59051362Seric (void) fcntl(UdbSock, F_SETFD, 1); 59151362Seric } 59251362Seric break; 59351362Seric 59451362Seric case '@': /* forward to remote host */ 59551362Seric up->udb_type = UDB_FORWARD; 59651362Seric up->udb_fwdhost = spec + 1; 59751362Seric up++; 59851362Seric break; 59951362Seric 60051362Seric case '/': /* look up remote name */ 60151831Seric up->udb_dbname = spec; 60251923Seric errno = 0; 60351362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 60451362Seric if (up->udb_dbp == NULL) 60551923Seric { 60651923Seric if (errno != ENOENT && errno != EACCES) 60751951Seric { 60859615Seric #ifdef LOG 60959615Seric if (LogLevel > 2) 61059625Seric syslog(LOG_ERR, "dbopen(%s): %s", 61159625Seric spec, errstring(errno)); 61259615Seric #endif 61351951Seric up->udb_type = UDB_EOLIST; 61451951Seric goto tempfail; 61551951Seric } 61651362Seric break; 61751923Seric } 61851951Seric up->udb_type = UDB_DBFETCH; 61951362Seric up++; 62051362Seric break; 62151360Seric } 62251362Seric } 62351362Seric up->udb_type = UDB_EOLIST; 62451360Seric 62551362Seric if (tTd(28, 4)) 62651362Seric { 62751951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 62851360Seric { 62951362Seric switch (up->udb_type) 63051362Seric { 63151362Seric case UDB_REMOTE: 63251362Seric printf("REMOTE: addr %s, timeo %d\n", 63360494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 63451362Seric up->udb_timeout); 63551362Seric break; 63651362Seric 63751951Seric case UDB_DBFETCH: 63851951Seric printf("FETCH: file %s\n", 63951830Seric up->udb_dbname); 64051362Seric break; 64151362Seric 64251362Seric case UDB_FORWARD: 64351362Seric printf("FORWARD: host %s\n", 64451362Seric up->udb_fwdhost); 64551362Seric break; 64651362Seric 64751362Seric default: 64851362Seric printf("UNKNOWN\n"); 64951362Seric break; 65051362Seric } 65151360Seric } 65250581Seric } 65351951Seric 65451951Seric UdbInitialized = TRUE; 65551955Seric errno = 0; 65651951Seric return EX_OK; 65751951Seric 65851951Seric /* 65951951Seric ** On temporary failure, back out anything we've already done 66051951Seric */ 66151951Seric 66251951Seric tempfail: 66351951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 66451951Seric { 66551951Seric if (up->udb_type == UDB_DBFETCH) 66651951Seric { 66751951Seric (*up->udb_dbp->close)(up->udb_dbp); 66851951Seric } 66951951Seric } 67051951Seric return EX_TEMPFAIL; 67151360Seric } 67250581Seric 67351363Seric int 67451363Seric _udb_parsespec(udbspec, opt, maxopts) 67551363Seric char *udbspec; 67651363Seric struct option opt[]; 67751363Seric int maxopts; 67851363Seric { 67951363Seric register char *spec; 68051363Seric register char *spec_end; 68151363Seric register int optnum; 68251363Seric 68356795Seric spec_end = strchr(udbspec, ':'); 68451363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 68551363Seric { 68651363Seric register char *p; 68751363Seric 68858050Seric while (isascii(*spec) && isspace(*spec)) 68951363Seric spec++; 69056795Seric spec_end = strchr(spec, ':'); 69151363Seric if (spec_end != NULL) 69251363Seric *spec_end++ = '\0'; 69351363Seric 69451363Seric opt[optnum].name = spec; 69551363Seric opt[optnum].val = NULL; 69656795Seric p = strchr(spec, '='); 69751363Seric if (p != NULL) 69851363Seric opt[optnum].val = ++p; 69951363Seric } 70051363Seric return optnum; 70151363Seric } 70251363Seric 70351360Seric #else /* not USERDB */ 70451360Seric 70551923Seric int 70655012Seric udbexpand(a, sendq, e) 70751360Seric ADDRESS *a; 70851360Seric ADDRESS **sendq; 70955012Seric ENVELOPE *e; 71051360Seric { 71151923Seric return EX_OK; 71250581Seric } 71350581Seric 71450581Seric #endif /* USERDB */ 715