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*66759Seric static char sccsid [] = "@(#)udb.c 8.7 (Berkeley) 04/12/94 (with USERDB)"; 1451360Seric #else 15*66759Seric static char sccsid [] = "@(#)udb.c 8.7 (Berkeley) 04/12/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 25*66759Seric #ifdef HESIOD 26*66759Seric #include <hesiod.h> 27*66759Seric #endif /* HESIOD */ 28*66759Seric 2950581Seric /* 3053654Seric ** UDB.C -- interface between sendmail and Berkeley User Data Base. 3150581Seric ** 3251363Seric ** This depends on the 4.4BSD db package. 3350581Seric */ 3450581Seric 3551362Seric 3651360Seric struct udbent 3751360Seric { 3851360Seric char *udb_spec; /* string version of spec */ 3951360Seric int udb_type; /* type of entry */ 4051951Seric char *udb_default; /* default host for outgoing mail */ 4151360Seric union 4251360Seric { 4351360Seric /* type UE_REMOTE -- do remote call for lookup */ 4451360Seric struct 4551360Seric { 4651360Seric struct sockaddr_in _udb_addr; /* address */ 4751360Seric int _udb_timeout; /* timeout */ 4851360Seric } udb_remote; 4951360Seric #define udb_addr udb_u.udb_remote._udb_addr 5051360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 5151360Seric 5251360Seric /* type UE_FORWARD -- forward message to remote */ 5351360Seric struct 5451360Seric { 5551360Seric char *_udb_fwdhost; /* name of forward host */ 5651360Seric } udb_forward; 5751360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 5851360Seric 5951951Seric /* type UE_FETCH -- lookup in local database */ 6051360Seric struct 6151360Seric { 6251360Seric char *_udb_dbname; /* pathname of database */ 6351360Seric DB *_udb_dbp; /* open database ptr */ 6451360Seric } udb_lookup; 6551360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 6651360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 6751360Seric } udb_u; 6851360Seric }; 6951360Seric 7051360Seric #define UDB_EOLIST 0 /* end of list */ 7151360Seric #define UDB_SKIP 1 /* skip this entry */ 7251360Seric #define UDB_REMOTE 2 /* look up in remote database */ 7351951Seric #define UDB_DBFETCH 3 /* look up in local database */ 7451360Seric #define UDB_FORWARD 4 /* forward to remote host */ 75*66759Seric #define UDB_HESIOD 5 /* look up via hesiod */ 7651360Seric 7751360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 7851360Seric 7951363Seric 8051363Seric struct option 8151363Seric { 8251363Seric char *name; 8351363Seric char *val; 8451363Seric }; 8551363Seric /* 8651363Seric ** UDBEXPAND -- look up user in database and expand 8751363Seric ** 8851363Seric ** Parameters: 8951363Seric ** a -- address to expand. 9051363Seric ** sendq -- pointer to head of sendq to put the expansions in. 9151363Seric ** 9251363Seric ** Returns: 9351923Seric ** EX_TEMPFAIL -- if something "odd" happened -- probably due 9451923Seric ** to accessing a file on an NFS server that is down. 9551923Seric ** EX_OK -- otherwise. 9651363Seric ** 9751363Seric ** Side Effects: 9851363Seric ** Modifies sendq. 9951363Seric */ 10051363Seric 10151363Seric int UdbPort = 1616; 10251363Seric int UdbTimeout = 10; 10351363Seric 10451953Seric struct udbent UdbEnts[MAXUDBENT + 1]; 10551953Seric int UdbSock = -1; 10651953Seric bool UdbInitialized = FALSE; 10751360Seric 10851923Seric int 10955012Seric udbexpand(a, sendq, e) 11050581Seric register ADDRESS *a; 11150581Seric ADDRESS **sendq; 11255012Seric register ENVELOPE *e; 11350581Seric { 11450581Seric int i; 11550581Seric register char *p; 11650581Seric DBT key; 11750581Seric DBT info; 11851360Seric bool breakout; 11951360Seric register struct udbent *up; 12051362Seric int keylen; 12158082Seric int naddrs; 12257232Seric char keybuf[MAXKEY]; 12357232Seric char buf[BUFSIZ]; 12450581Seric 12550581Seric if (tTd(28, 1)) 12658065Seric printf("udbexpand(%s)\n", a->q_paddr); 12750581Seric 12850581Seric /* make certain we are supposed to send to this address */ 12958154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 13051923Seric return EX_OK; 13155012Seric e->e_to = a->q_paddr; 13250581Seric 13351360Seric /* on first call, locate the database */ 13451951Seric if (!UdbInitialized) 13550581Seric { 13651923Seric extern int _udbx_init(); 13751362Seric 13851923Seric if (_udbx_init() == EX_TEMPFAIL) 13951923Seric return EX_TEMPFAIL; 14051362Seric } 14150581Seric 14251909Seric /* short circuit the process if no chance of a match */ 14351909Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 14451923Seric return EX_OK; 14551909Seric 146*66759Seric /* short circuit name begins with '\\' since it can't possibly match */ 147*66759Seric if (a->q_user[0] == '\\') 148*66759Seric return EX_OK; 149*66759Seric 15051362Seric /* if name is too long, assume it won't match */ 15151362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 15251923Seric return EX_OK; 15351360Seric 15451362Seric /* if name begins with a colon, it indicates our metadata */ 15551362Seric if (a->q_user[0] == ':') 15651923Seric return EX_OK; 15751360Seric 15851362Seric /* build actual database key */ 15951362Seric (void) strcpy(keybuf, a->q_user); 16051362Seric (void) strcat(keybuf, ":maildrop"); 16151362Seric keylen = strlen(keybuf); 16251360Seric 16351360Seric breakout = FALSE; 16451362Seric for (up = UdbEnts; !breakout; up++) 16550581Seric { 16651360Seric char *user; 16750581Seric 16851360Seric /* 16951360Seric ** Select action based on entry type. 17051360Seric ** 17151360Seric ** On dropping out of this switch, "class" should 17251360Seric ** explain the type of the data, and "user" should 17351360Seric ** contain the user information. 17451360Seric */ 17550581Seric 17651360Seric switch (up->udb_type) 17751360Seric { 17851951Seric case UDB_DBFETCH: 17951362Seric key.data = keybuf; 18051362Seric key.size = keylen; 18160990Seric if (tTd(28, 80)) 182*66759Seric printf("udbexpand: trying %s (%d) via db\n", 18364067Seric keybuf, keylen); 18451362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 18551923Seric if (i > 0 || info.size <= 0) 18651360Seric { 18751360Seric if (tTd(28, 2)) 18864067Seric printf("udbexpand: no match on %s (%d)\n", 18964067Seric keybuf, keylen); 19051360Seric continue; 19151360Seric } 19260990Seric if (tTd(28, 80)) 19360990Seric printf("udbexpand: match %.*s: %.*s\n", 19460990Seric key.size, key.data, info.size, info.data); 19550581Seric 19658082Seric naddrs = 0; 19758082Seric a->q_flags &= ~QSELFREF; 19851830Seric while (i == 0 && key.size == keylen && 19951830Seric bcmp(key.data, keybuf, keylen) == 0) 20051362Seric { 20158099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 20258154Seric { 20358154Seric a->q_flags |= QVERIFIED; 20458884Seric e->e_nrcpts++; 20558099Seric return EX_OK; 20658154Seric } 20758099Seric 20851830Seric breakout = TRUE; 20951362Seric if (info.size < sizeof buf) 21051362Seric user = buf; 21151362Seric else 21251362Seric user = xalloc(info.size + 1); 21351362Seric bcopy(info.data, user, info.size); 21451362Seric user[info.size] = '\0'; 21550581Seric 21658151Seric message("expanded to %s", user); 21757977Seric #ifdef LOG 21857977Seric if (LogLevel >= 10) 21957977Seric syslog(LOG_INFO, "%s: expand %s => %s", 22057977Seric e->e_id, e->e_to, user); 22157977Seric #endif 22251362Seric AliasLevel++; 22358082Seric naddrs += sendtolist(user, a, sendq, e); 22451362Seric AliasLevel--; 22551362Seric 22651362Seric if (user != buf) 22751362Seric free(user); 22851362Seric 22951362Seric /* get the next record */ 23051362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 23151830Seric } 23260990Seric 23360990Seric /* if nothing ever matched, try next database */ 23460990Seric if (!breakout) 23560990Seric continue; 23660990Seric 23758082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 23858065Seric { 23958065Seric if (tTd(28, 5)) 24058065Seric { 24158065Seric printf("udbexpand: QDONTSEND "); 24258065Seric printaddr(a, FALSE); 24358065Seric } 24458065Seric a->q_flags |= QDONTSEND; 24558065Seric } 24651923Seric if (i < 0) 24751923Seric { 24858010Seric syserr("udbexpand: db-get %.*s stat %d", 24958010Seric key.size, key.data, i); 25051923Seric return EX_TEMPFAIL; 25151923Seric } 25259707Seric 25359707Seric /* 25459707Seric ** If this address has a -request address, reflect 25559707Seric ** it into the envelope. 25659707Seric */ 25759707Seric 25859707Seric (void) strcpy(keybuf, a->q_user); 25959707Seric (void) strcat(keybuf, ":mailsender"); 26059707Seric keylen = strlen(keybuf); 26159707Seric key.data = keybuf; 26259707Seric key.size = keylen; 26359707Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 26459707Seric if (i != 0 || info.size <= 0) 26559707Seric break; 26659707Seric a->q_owner = xalloc(info.size + 1); 26759707Seric bcopy(info.data, a->q_owner, info.size); 26859707Seric a->q_owner[info.size] = '\0'; 26951360Seric break; 27051360Seric 271*66759Seric #ifdef HESIOD 272*66759Seric case UDB_HESIOD: 273*66759Seric key.data = keybuf; 274*66759Seric key.size = keylen; 275*66759Seric if (tTd(28, 80)) 276*66759Seric printf("udbexpand: trying %s (%d) via hesiod\n", 277*66759Seric keybuf, keylen); 278*66759Seric /* look up the key via hesiod */ 279*66759Seric i = hes_udb_get(&key, &info); 280*66759Seric if (i > 0 || info.size <= 0) 281*66759Seric { 282*66759Seric if (tTd(28, 2)) 283*66759Seric printf("udbexpand: no match on %s (%d)\n", 284*66759Seric keybuf, keylen); 285*66759Seric continue; 286*66759Seric } 287*66759Seric if (tTd(28, 80)) 288*66759Seric printf("udbexpand: match %.*s: %.*s\n", 289*66759Seric key.size, key.data, info.size, info.data); 290*66759Seric a->q_flags &= ~QSELFREF; 291*66759Seric 292*66759Seric if (bitset(EF_VRFYONLY, e->e_flags)) 293*66759Seric { 294*66759Seric a->q_flags |= QVERIFIED; 295*66759Seric e->e_nrcpts++; 296*66759Seric free(info.data); 297*66759Seric return EX_OK; 298*66759Seric } 299*66759Seric 300*66759Seric breakout = TRUE; 301*66759Seric if (info.size < sizeof buf) 302*66759Seric user = buf; 303*66759Seric else 304*66759Seric user = xalloc(info.size + 1); 305*66759Seric bcopy(info.data, user, info.size); 306*66759Seric user[info.size] = '\0'; 307*66759Seric free(info.data); 308*66759Seric 309*66759Seric message("hesioded to %s", user); 310*66759Seric #ifdef LOG 311*66759Seric if (LogLevel >= 10) 312*66759Seric syslog(LOG_INFO, "%s: hesiod %s => %s", 313*66759Seric e->e_id, e->e_to, user); 314*66759Seric #endif 315*66759Seric AliasLevel++; 316*66759Seric naddrs = sendtolist(user, a, sendq, e); 317*66759Seric AliasLevel--; 318*66759Seric 319*66759Seric if (user != buf) 320*66759Seric free(user); 321*66759Seric 322*66759Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 323*66759Seric { 324*66759Seric if (tTd(28, 5)) 325*66759Seric { 326*66759Seric printf("udbexpand: QDONTSEND "); 327*66759Seric printaddr(a, FALSE); 328*66759Seric } 329*66759Seric a->q_flags |= QDONTSEND; 330*66759Seric } 331*66759Seric if (i < 0) 332*66759Seric { 333*66759Seric syserr("udbexpand: hesiod-get %.*s stat %d", 334*66759Seric key.size, key.data, i); 335*66759Seric return EX_TEMPFAIL; 336*66759Seric } 337*66759Seric 338*66759Seric /* 339*66759Seric ** If this address has a -request address, reflect 340*66759Seric ** it into the envelope. 341*66759Seric */ 342*66759Seric 343*66759Seric (void) strcpy(keybuf, a->q_user); 344*66759Seric (void) strcat(keybuf, ":mailsender"); 345*66759Seric keylen = strlen(keybuf); 346*66759Seric key.data = keybuf; 347*66759Seric key.size = keylen; 348*66759Seric i = hes_udb_get(&key, &info); 349*66759Seric if (i != 0 || info.size <= 0) 350*66759Seric break; 351*66759Seric a->q_owner = xalloc(info.size + 1); 352*66759Seric bcopy(info.data, a->q_owner, info.size); 353*66759Seric a->q_owner[info.size] = '\0'; 354*66759Seric free(info.data); 355*66759Seric break; 356*66759Seric #endif /* HESIOD */ 357*66759Seric 35851360Seric case UDB_REMOTE: 35951741Seric /* not yet implemented */ 36051741Seric continue; 36151362Seric 36251360Seric case UDB_FORWARD: 36358099Seric if (bitset(EF_VRFYONLY, e->e_flags)) 36458099Seric return EX_OK; 36551360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 36651360Seric if (i < sizeof buf) 36751360Seric user = buf; 36851360Seric else 36951360Seric user = xalloc(i + 1); 37051360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 37158151Seric message("expanded to %s", user); 37258082Seric a->q_flags &= ~QSELFREF; 37351362Seric AliasLevel++; 37458082Seric naddrs = sendtolist(user, a, sendq, e); 37551362Seric AliasLevel--; 37658082Seric if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 37758065Seric { 37858065Seric if (tTd(28, 5)) 37958065Seric { 38058065Seric printf("udbexpand: QDONTSEND "); 38158065Seric printaddr(a, FALSE); 38258065Seric } 38358065Seric a->q_flags |= QDONTSEND; 38458065Seric } 38551362Seric if (user != buf) 38651362Seric free(user); 38751362Seric breakout = TRUE; 38851360Seric break; 38951360Seric 39051360Seric case UDB_EOLIST: 39151360Seric breakout = TRUE; 39251360Seric continue; 39351360Seric 39451360Seric default: 39551360Seric /* unknown entry type */ 39651360Seric continue; 39751360Seric } 39851362Seric } 39951923Seric return EX_OK; 40051362Seric } 40151951Seric /* 40251951Seric ** UDBSENDER -- return canonical external name of sender, given local name 40351951Seric ** 40451951Seric ** Parameters: 40551951Seric ** sender -- the name of the sender on the local machine. 40651951Seric ** 40751951Seric ** Returns: 40851951Seric ** The external name for this sender, if derivable from the 40951951Seric ** database. 41051951Seric ** NULL -- if nothing is changed from the database. 41151951Seric ** 41251951Seric ** Side Effects: 41351951Seric ** none. 41451951Seric */ 41551360Seric 41651951Seric char * 41751951Seric udbsender(sender) 41851951Seric char *sender; 41951951Seric { 42064350Seric extern char *udbmatch(); 42164350Seric 42264350Seric return udbmatch(sender, "mailname"); 42364350Seric } 42464350Seric 42564350Seric 42664350Seric char * 42764350Seric udbmatch(user, field) 42864350Seric char *user; 42964350Seric char *field; 43064350Seric { 43151951Seric register char *p; 43251951Seric register struct udbent *up; 43351951Seric int i; 43451951Seric int keylen; 43551951Seric DBT key, info; 43657232Seric char keybuf[MAXKEY]; 43751951Seric 43851951Seric if (tTd(28, 1)) 43964350Seric printf("udbmatch(%s, %s)\n", user, field); 44051951Seric 44151951Seric if (!UdbInitialized) 44251951Seric { 44351951Seric if (_udbx_init() == EX_TEMPFAIL) 44451951Seric return NULL; 44551951Seric } 44651951Seric 44751951Seric /* short circuit if no spec */ 44851951Seric if (UdbSpec == NULL || UdbSpec[0] == '\0') 44951951Seric return NULL; 45051951Seric 451*66759Seric /* short circuit name begins with '\\' since it can't possibly match */ 452*66759Seric if (user[0] == '\\') 453*66759Seric return NULL; 454*66759Seric 45551951Seric /* long names can never match and are a pain to deal with */ 45664350Seric if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 45751951Seric return NULL; 45851951Seric 45951951Seric /* names beginning with colons indicate metadata */ 46064350Seric if (user[0] == ':') 46151951Seric return NULL; 46251951Seric 46351951Seric /* build database key */ 46464350Seric (void) strcpy(keybuf, user); 46564350Seric (void) strcat(keybuf, ":"); 46664350Seric (void) strcat(keybuf, field); 46751951Seric keylen = strlen(keybuf); 46851951Seric 46951951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 47051951Seric { 47151951Seric /* 47251951Seric ** Select action based on entry type. 47351951Seric */ 47451951Seric 47551951Seric switch (up->udb_type) 47651951Seric { 47751951Seric case UDB_DBFETCH: 47851951Seric key.data = keybuf; 47951951Seric key.size = keylen; 48051951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 48151951Seric if (i != 0 || info.size <= 0) 48251951Seric { 48351951Seric if (tTd(28, 2)) 484*66759Seric printf("udbmatch: no match on %s (%d) via db\n", 48564067Seric keybuf, keylen); 48651951Seric continue; 48751951Seric } 48851951Seric 48951951Seric p = xalloc(info.size + 1); 49051951Seric bcopy(info.data, p, info.size); 49151951Seric p[info.size] = '\0'; 49251951Seric if (tTd(28, 1)) 49364350Seric printf("udbmatch ==> %s\n", p); 49451951Seric return p; 495*66759Seric break; 496*66759Seric 497*66759Seric #ifdef HESIOD 498*66759Seric case UDB_HESIOD: 499*66759Seric key.data = keybuf; 500*66759Seric key.size = keylen; 501*66759Seric i = hes_udb_get(&key, &info); 502*66759Seric if (i != 0 || info.size <= 0) 503*66759Seric { 504*66759Seric if (tTd(28, 2)) 505*66759Seric printf("udbmatch: no match on %s (%d) via hesiod\n", 506*66759Seric keybuf, keylen); 507*66759Seric continue; 508*66759Seric } 509*66759Seric 510*66759Seric p = xalloc(info.size + 1); 511*66759Seric bcopy(info.data, p, info.size); 512*66759Seric p[info.size] = '\0'; 513*66759Seric free(info.data); 514*66759Seric if (tTd(28, 1)) 515*66759Seric printf("udbmatch ==> %s\n", p); 516*66759Seric return p; 517*66759Seric break; 518*66759Seric #endif /* HESIOD */ 51951951Seric } 52051951Seric } 52151951Seric 52264350Seric if (strcmp(field, "mailname") != 0) 52364350Seric return NULL; 52464350Seric 52551951Seric /* 52651951Seric ** Nothing yet. Search again for a default case. But only 52751951Seric ** use it if we also have a forward (:maildrop) pointer already 52851951Seric ** in the database. 52951951Seric */ 53051951Seric 53151951Seric /* build database key */ 53264350Seric (void) strcpy(keybuf, user); 53351951Seric (void) strcat(keybuf, ":maildrop"); 53451951Seric keylen = strlen(keybuf); 53551951Seric 53651951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 53751951Seric { 53851951Seric switch (up->udb_type) 53951951Seric { 54051951Seric case UDB_DBFETCH: 54151951Seric /* get the default case for this database */ 54251951Seric if (up->udb_default == NULL) 54351951Seric { 54451951Seric key.data = ":default:mailname"; 54551951Seric key.size = strlen(key.data); 54651951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 54751951Seric if (i != 0 || info.size <= 0) 54851951Seric { 54951951Seric /* no default case */ 55051951Seric up->udb_default = ""; 55151951Seric continue; 55251951Seric } 55351951Seric 55451951Seric /* save the default case */ 55551951Seric up->udb_default = xalloc(info.size + 1); 55651951Seric bcopy(info.data, up->udb_default, info.size); 55751951Seric up->udb_default[info.size] = '\0'; 55851951Seric } 55951951Seric else if (up->udb_default[0] == '\0') 56051951Seric continue; 56151951Seric 56251951Seric /* we have a default case -- verify user:maildrop */ 56351951Seric key.data = keybuf; 56451951Seric key.size = keylen; 56551951Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 56651951Seric if (i != 0 || info.size <= 0) 56751951Seric { 56851951Seric /* nope -- no aliasing for this user */ 56951951Seric continue; 57051951Seric } 57151951Seric 57251951Seric /* they exist -- build the actual address */ 57364350Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 57464350Seric (void) strcpy(p, user); 57551951Seric (void) strcat(p, "@"); 57651951Seric (void) strcat(p, up->udb_default); 57751951Seric if (tTd(28, 1)) 57864350Seric printf("udbmatch ==> %s\n", p); 57951951Seric return p; 580*66759Seric break; 581*66759Seric 582*66759Seric #ifdef HESIOD 583*66759Seric case UDB_HESIOD: 584*66759Seric /* get the default case for this database */ 585*66759Seric if (up->udb_default == NULL) 586*66759Seric { 587*66759Seric key.data = ":default:mailname"; 588*66759Seric key.size = strlen(key.data); 589*66759Seric i = hes_udb_get(&key, &info); 590*66759Seric 591*66759Seric if (i != 0 || info.size <= 0) 592*66759Seric { 593*66759Seric /* no default case */ 594*66759Seric up->udb_default = ""; 595*66759Seric continue; 596*66759Seric } 597*66759Seric 598*66759Seric /* save the default case */ 599*66759Seric up->udb_default = xalloc(info.size + 1); 600*66759Seric bcopy(info.data, up->udb_default, info.size); 601*66759Seric up->udb_default[info.size] = '\0'; 602*66759Seric free(info.data); 603*66759Seric } 604*66759Seric else if (up->udb_default[0] == '\0') 605*66759Seric continue; 606*66759Seric 607*66759Seric /* we have a default case -- verify user:maildrop */ 608*66759Seric key.data = keybuf; 609*66759Seric key.size = keylen; 610*66759Seric i = hes_udb_get(&key, &info); 611*66759Seric if (i != 0 || info.size <= 0) 612*66759Seric { 613*66759Seric /* nope -- no aliasing for this user */ 614*66759Seric continue; 615*66759Seric } 616*66759Seric 617*66759Seric free(info.data); 618*66759Seric /* they exist -- build the actual address */ 619*66759Seric p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 620*66759Seric (void) strcpy(p, user); 621*66759Seric (void) strcat(p, "@"); 622*66759Seric (void) strcat(p, up->udb_default); 623*66759Seric if (tTd(28, 1)) 624*66759Seric printf("udbmatch ==> %s\n", p); 625*66759Seric return p; 626*66759Seric break; 627*66759Seric #endif /* HESIOD */ 62851951Seric } 62951951Seric } 63051951Seric 63151951Seric /* still nothing.... too bad */ 63251951Seric return NULL; 63351951Seric } 63451951Seric /* 63551951Seric ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 63651951Seric ** 63751951Seric ** Parameters: 63851951Seric ** none. 63951951Seric ** 64051951Seric ** Returns: 64151951Seric ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 64251951Seric ** database due to a host being down or some similar 64351951Seric ** (recoverable) situation. 64451951Seric ** EX_OK -- otherwise. 64551951Seric ** 64651951Seric ** Side Effects: 64751951Seric ** Fills in the UdbEnts structure from UdbSpec. 64851951Seric */ 64951951Seric 65051363Seric #define MAXUDBOPTS 27 65151363Seric 65251953Seric int 65351362Seric _udbx_init() 65451362Seric { 65551362Seric register char *p; 65651362Seric int i; 65751362Seric register struct udbent *up; 65857232Seric char buf[BUFSIZ]; 65951360Seric 66051951Seric if (UdbInitialized) 66151951Seric return EX_OK; 66251951Seric 66351908Seric # ifdef UDB_DEFAULT_SPEC 66451908Seric if (UdbSpec == NULL) 66551908Seric UdbSpec = UDB_DEFAULT_SPEC; 66651908Seric # endif 66751908Seric 66851362Seric p = UdbSpec; 66951362Seric up = UdbEnts; 67051762Seric while (p != NULL) 67151362Seric { 67251362Seric char *spec; 67351362Seric auto int rcode; 67451363Seric int nopts; 67551362Seric int nmx; 67651362Seric register struct hostent *h; 67751362Seric char *mxhosts[MAXMXHOSTS + 1]; 67851363Seric struct option opts[MAXUDBOPTS + 1]; 67951362Seric 68051362Seric while (*p == ' ' || *p == '\t' || *p == ',') 68151362Seric p++; 68251362Seric if (*p == '\0') 68351362Seric break; 68451362Seric spec = p; 68556795Seric p = strchr(p, ','); 68651761Seric if (p != NULL) 68751362Seric *p++ = '\0'; 68851363Seric 68951363Seric /* extract options */ 69051363Seric nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 69151363Seric 69251363Seric /* 69351363Seric ** Decode database specification. 69451363Seric ** 69551363Seric ** In the sendmail tradition, the leading character 69651363Seric ** defines the semantics of the rest of the entry. 69751363Seric ** 69851363Seric ** +hostname -- send a datagram to the udb server 69951363Seric ** on host "hostname" asking for the 70051363Seric ** home mail server for this user. 70151363Seric ** *hostname -- similar to +hostname, except that the 70251363Seric ** hostname is searched as an MX record; 70351363Seric ** resulting hosts are searched as for 70451363Seric ** +mxhostname. If no MX host is found, 70551363Seric ** this is the same as +hostname. 70651363Seric ** @hostname -- forward email to the indicated host. 70751363Seric ** This should be the last in the list, 70851363Seric ** since it always matches the input. 70951363Seric ** /dbname -- search the named database on the local 71051363Seric ** host using the Berkeley db package. 71151363Seric */ 71251363Seric 71351362Seric switch (*spec) 71451360Seric { 71551362Seric case '+': /* search remote database */ 71651363Seric case '*': /* search remote database (expand MX) */ 71751363Seric if (*spec == '*') 71851363Seric { 71966334Seric #if NAMED_BIND 72059273Seric nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 72157629Seric #else 72257629Seric mxhosts[0] = spec + 1; 72357629Seric nmx = 1; 72457629Seric rcode = 0; 72557629Seric #endif 72651363Seric if (tTd(28, 16)) 72751363Seric { 72851363Seric int i; 72951362Seric 73051363Seric printf("getmxrr(%s): %d", spec + 1, nmx); 73151363Seric for (i = 0; i <= nmx; i++) 73251363Seric printf(" %s", mxhosts[i]); 73351363Seric printf("\n"); 73451363Seric } 73551363Seric } 73651363Seric else 73751362Seric { 73851363Seric nmx = 1; 73951363Seric mxhosts[0] = spec + 1; 74051362Seric } 74151362Seric 74251362Seric for (i = 0; i < nmx; i++) 74351362Seric { 74451362Seric h = gethostbyname(mxhosts[i]); 74551362Seric if (h == NULL) 74651362Seric continue; 74751362Seric up->udb_type = UDB_REMOTE; 74851362Seric up->udb_addr.sin_family = h->h_addrtype; 74951362Seric bcopy(h->h_addr_list[0], 75051362Seric (char *) &up->udb_addr.sin_addr, 75164943Seric sizeof up->udb_addr.sin_addr); 75251362Seric up->udb_addr.sin_port = UdbPort; 75351362Seric up->udb_timeout = UdbTimeout; 75451362Seric up++; 75551362Seric } 75651362Seric 75751362Seric /* set up a datagram socket */ 75851362Seric if (UdbSock < 0) 75951362Seric { 76051362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 76151362Seric (void) fcntl(UdbSock, F_SETFD, 1); 76251362Seric } 76351362Seric break; 76451362Seric 76551362Seric case '@': /* forward to remote host */ 76651362Seric up->udb_type = UDB_FORWARD; 76751362Seric up->udb_fwdhost = spec + 1; 76851362Seric up++; 76951362Seric break; 77051362Seric 771*66759Seric case 'h': /* use hesiod */ 772*66759Seric case 'H': 773*66759Seric #ifdef HESIOD 774*66759Seric if (strcasecmp(spec, "hesiod") != 0) 775*66759Seric break; 776*66759Seric up->udb_type = UDB_HESIOD; 777*66759Seric up++; 778*66759Seric #endif /* HESIOD */ 779*66759Seric break; 780*66759Seric 78151362Seric case '/': /* look up remote name */ 78251831Seric up->udb_dbname = spec; 78351923Seric errno = 0; 78451362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 78551362Seric if (up->udb_dbp == NULL) 78651923Seric { 78751923Seric if (errno != ENOENT && errno != EACCES) 78851951Seric { 78959615Seric #ifdef LOG 79059615Seric if (LogLevel > 2) 79159625Seric syslog(LOG_ERR, "dbopen(%s): %s", 79259625Seric spec, errstring(errno)); 79359615Seric #endif 79451951Seric up->udb_type = UDB_EOLIST; 79551951Seric goto tempfail; 79651951Seric } 79751362Seric break; 79851923Seric } 79951951Seric up->udb_type = UDB_DBFETCH; 80051362Seric up++; 80151362Seric break; 80251360Seric } 80351362Seric } 80451362Seric up->udb_type = UDB_EOLIST; 80551360Seric 80651362Seric if (tTd(28, 4)) 80751362Seric { 80851951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 80951360Seric { 81051362Seric switch (up->udb_type) 81151362Seric { 81251362Seric case UDB_REMOTE: 81351362Seric printf("REMOTE: addr %s, timeo %d\n", 81460494Seric anynet_ntoa((SOCKADDR *) &up->udb_addr), 81551362Seric up->udb_timeout); 81651362Seric break; 81751362Seric 81851951Seric case UDB_DBFETCH: 81951951Seric printf("FETCH: file %s\n", 82051830Seric up->udb_dbname); 82151362Seric break; 82251362Seric 82351362Seric case UDB_FORWARD: 82451362Seric printf("FORWARD: host %s\n", 82551362Seric up->udb_fwdhost); 82651362Seric break; 82751362Seric 828*66759Seric case UDB_HESIOD: 829*66759Seric printf("HESIOD\n"); 830*66759Seric break; 831*66759Seric 83251362Seric default: 83351362Seric printf("UNKNOWN\n"); 83451362Seric break; 83551362Seric } 83651360Seric } 83750581Seric } 83851951Seric 83951951Seric UdbInitialized = TRUE; 84051955Seric errno = 0; 84151951Seric return EX_OK; 84251951Seric 84351951Seric /* 84451951Seric ** On temporary failure, back out anything we've already done 84551951Seric */ 84651951Seric 84751951Seric tempfail: 84851951Seric for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 84951951Seric { 85051951Seric if (up->udb_type == UDB_DBFETCH) 85151951Seric { 85251951Seric (*up->udb_dbp->close)(up->udb_dbp); 85351951Seric } 85451951Seric } 85551951Seric return EX_TEMPFAIL; 85651360Seric } 85750581Seric 85851363Seric int 85951363Seric _udb_parsespec(udbspec, opt, maxopts) 86051363Seric char *udbspec; 86151363Seric struct option opt[]; 86251363Seric int maxopts; 86351363Seric { 86451363Seric register char *spec; 86551363Seric register char *spec_end; 86651363Seric register int optnum; 86751363Seric 86856795Seric spec_end = strchr(udbspec, ':'); 86951363Seric for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 87051363Seric { 87151363Seric register char *p; 87251363Seric 87358050Seric while (isascii(*spec) && isspace(*spec)) 87451363Seric spec++; 87556795Seric spec_end = strchr(spec, ':'); 87651363Seric if (spec_end != NULL) 87751363Seric *spec_end++ = '\0'; 87851363Seric 87951363Seric opt[optnum].name = spec; 88051363Seric opt[optnum].val = NULL; 88156795Seric p = strchr(spec, '='); 88251363Seric if (p != NULL) 88351363Seric opt[optnum].val = ++p; 88451363Seric } 88551363Seric return optnum; 88651363Seric } 88751363Seric 888*66759Seric #ifdef HESIOD 889*66759Seric 890*66759Seric int 891*66759Seric hes_udb_get(key, info) 892*66759Seric DBT *key; 893*66759Seric DBT *info; 894*66759Seric { 895*66759Seric char *name, *type; 896*66759Seric char *p, **hp; 897*66759Seric 898*66759Seric name = key->data; 899*66759Seric type = strchr(name, ':'); 900*66759Seric if (type == NULL) 901*66759Seric return 1; 902*66759Seric 903*66759Seric *type++ = '\0'; 904*66759Seric 905*66759Seric if (tTd(28, 1)) 906*66759Seric printf("hes_udb_get(%s, %s)\n", name, type); 907*66759Seric 908*66759Seric /* make the hesiod query */ 909*66759Seric hp = hes_resolve(name, type); 910*66759Seric if (hp == NULL) 911*66759Seric { 912*66759Seric /* network problem or timeout */ 913*66759Seric if (hes_error() == HES_ER_NET) 914*66759Seric return -1; 915*66759Seric 916*66759Seric return 1; 917*66759Seric } 918*66759Seric else 919*66759Seric { 920*66759Seric /* 921*66759Seric ** If there are multiple matches, just return the 922*66759Seric ** first one and free the others. 923*66759Seric ** 924*66759Seric ** XXX These should really be returned; for example, 925*66759Seric ** XXX it is legal for :maildrop to be multi-valued. 926*66759Seric */ 927*66759Seric 928*66759Seric for (p = hp[1]; p; p++) 929*66759Seric free(p); 930*66759Seric 931*66759Seric info->data = hp[0]; 932*66759Seric info->size = (size_t) strlen(info->data); 933*66759Seric } 934*66759Seric 935*66759Seric return 0; 936*66759Seric } 937*66759Seric #endif /* HESIOD */ 938*66759Seric 93951360Seric #else /* not USERDB */ 94051360Seric 94151923Seric int 94255012Seric udbexpand(a, sendq, e) 94351360Seric ADDRESS *a; 94451360Seric ADDRESS **sendq; 94555012Seric ENVELOPE *e; 94651360Seric { 94751923Seric return EX_OK; 94850581Seric } 94950581Seric 95050581Seric #endif /* USERDB */ 951