150581Seric /* 250581Seric * Copyright (c) 1983 Eric P. Allman 350581Seric * Copyright (c) 1988 Regents of the University of California. 450581Seric * All rights reserved. 550581Seric * 650581Seric * %sccs.include.redist.c% 750581Seric */ 850581Seric 950581Seric #ifndef lint 1051360Seric #ifdef USERDB 11*51362Seric static char sccsid [] = "@(#)udb.c 5.4 (Berkeley) 10/11/91 (with USERDB)"; 1251360Seric #else 13*51362Seric static char sccsid [] = "@(#)udb.c 5.4 (Berkeley) 10/11/91 (without USERDB)"; 1450581Seric #endif 1551360Seric #endif 1650581Seric 1750581Seric #include "sendmail.h" 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2150581Seric #include <sys/file.h> 2251360Seric #include <sys/time.h> 2351360Seric #include <fcntl.h> 2451360Seric #include <netdb.h> 2550581Seric #include <db.h> 2650581Seric 2750581Seric /* 2850581Seric ** UDBEXPAND -- look up user in database and expand 2950581Seric ** 3050581Seric ** Parameters: 3150581Seric ** a -- address to expand. 3250581Seric ** sendq -- pointer to head of sendq to put the expansions in. 3350581Seric ** 3450581Seric ** Returns: 3550581Seric ** none. 3650581Seric ** 3750581Seric ** Side Effects: 3850581Seric ** Modifies sendq. 3950581Seric */ 4050581Seric 41*51362Seric int UdbPort = 1616; 42*51362Seric int UdbTimeout = 10; 43*51362Seric 4451360Seric struct udbent 4551360Seric { 4651360Seric char *udb_spec; /* string version of spec */ 4751360Seric int udb_type; /* type of entry */ 4851360Seric union 4951360Seric { 5051360Seric /* type UE_REMOTE -- do remote call for lookup */ 5151360Seric struct 5251360Seric { 5351360Seric struct sockaddr_in _udb_addr; /* address */ 5451360Seric int _udb_timeout; /* timeout */ 5551360Seric } udb_remote; 5651360Seric #define udb_addr udb_u.udb_remote._udb_addr 5751360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 5851360Seric 5951360Seric /* type UE_FORWARD -- forward message to remote */ 6051360Seric struct 6151360Seric { 6251360Seric char *_udb_fwdhost; /* name of forward host */ 6351360Seric } udb_forward; 6451360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 6551360Seric 6651360Seric /* type UE_LOOKUP -- lookup in local database */ 6751360Seric struct 6851360Seric { 6951360Seric char *_udb_dbname; /* pathname of database */ 7051360Seric DB *_udb_dbp; /* open database ptr */ 7151360Seric } udb_lookup; 7251360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 7351360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 7451360Seric } udb_u; 7551360Seric }; 7651360Seric 7751360Seric #define UDB_EOLIST 0 /* end of list */ 7851360Seric #define UDB_SKIP 1 /* skip this entry */ 7951360Seric #define UDB_REMOTE 2 /* look up in remote database */ 8051360Seric #define UDB_LOOKUP 3 /* look up in local database */ 8151360Seric #define UDB_FORWARD 4 /* forward to remote host */ 8251360Seric 8351360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 8451360Seric 85*51362Seric struct udbent UdbEnts[MAXUDBENT + 1]; 86*51362Seric int UdbSock = -1; 8751360Seric 8850581Seric void 8950581Seric udbexpand(a, sendq) 9050581Seric register ADDRESS *a; 9150581Seric ADDRESS **sendq; 9250581Seric { 9350581Seric int i; 9450581Seric register char *p; 9550581Seric DBT key; 9650581Seric DBT info; 9751360Seric static bool firstcall = TRUE; 9851360Seric bool breakout; 9951360Seric register struct udbent *up; 100*51362Seric int keylen; 101*51362Seric char keybuf[128]; 10250581Seric char buf[8192]; 10350581Seric 10450581Seric if (tTd(28, 1)) 10550581Seric printf("expand(%s)\n", a->q_paddr); 10650581Seric 10750581Seric /* make certain we are supposed to send to this address */ 10851360Seric if (bitset(QDONTSEND, a->q_flags) || 10951360Seric UdbSpec == NULL || UdbSpec[0] == '\0') 11050581Seric return; 11150581Seric CurEnv->e_to = a->q_paddr; 11250581Seric 11351360Seric /* on first call, locate the database */ 11451360Seric if (firstcall) 11550581Seric { 116*51362Seric extern void _udbx_init(); 117*51362Seric 118*51362Seric _udbx_init(); 11951360Seric firstcall = FALSE; 120*51362Seric } 12150581Seric 122*51362Seric /* if name is too long, assume it won't match */ 123*51362Seric if (strlen(a->q_user) > sizeof keybuf - 12) 124*51362Seric return; 12551360Seric 126*51362Seric /* if name begins with a colon, it indicates our metadata */ 127*51362Seric if (a->q_user[0] == ':') 128*51362Seric return; 12951360Seric 130*51362Seric /* build actual database key */ 131*51362Seric (void) strcpy(keybuf, a->q_user); 132*51362Seric (void) strcat(keybuf, ":maildrop"); 133*51362Seric keylen = strlen(keybuf); 13451360Seric 13551360Seric breakout = FALSE; 136*51362Seric for (up = UdbEnts; !breakout; up++) 13750581Seric { 13851360Seric char *user; 13951360Seric struct timeval timeout; 14051360Seric fd_set fdset; 14150581Seric 14251360Seric /* 14351360Seric ** Select action based on entry type. 14451360Seric ** 14551360Seric ** On dropping out of this switch, "class" should 14651360Seric ** explain the type of the data, and "user" should 14751360Seric ** contain the user information. 14851360Seric */ 14950581Seric 15051360Seric switch (up->udb_type) 15151360Seric { 15251360Seric case UDB_LOOKUP: 153*51362Seric key.data = keybuf; 154*51362Seric key.size = keylen; 155*51362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 15651360Seric if (i != 0 || info.size <= 0) 15751360Seric { 15851360Seric if (i < 0) 15951360Seric syserr("udbexpand: db-get stat %s"); 16051360Seric if (tTd(28, 2)) 161*51362Seric printf("expand: no match on %s\n", keybuf); 16251360Seric continue; 16351360Seric } 16450581Seric 165*51362Seric /* there is at least one match -- start processing */ 166*51362Seric breakout = TRUE; 167*51362Seric do 168*51362Seric { 169*51362Seric if (info.size < sizeof buf) 170*51362Seric user = buf; 171*51362Seric else 172*51362Seric user = xalloc(info.size + 1); 173*51362Seric bcopy(info.data, user, info.size); 174*51362Seric user[info.size] = '\0'; 17550581Seric 176*51362Seric message(Arpa_Info, "expanded to %s", user); 177*51362Seric AliasLevel++; 178*51362Seric sendtolist(user, a, sendq); 179*51362Seric AliasLevel--; 180*51362Seric 181*51362Seric if (user != buf) 182*51362Seric free(user); 183*51362Seric 184*51362Seric /* get the next record */ 185*51362Seric i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 186*51362Seric } while (i == 0 && key.size == keylen && 187*51362Seric bcmp(key.data, keybuf, keylen) == 0); 18851360Seric break; 18951360Seric 19051360Seric case UDB_REMOTE: 191*51362Seric if (sendto(UdbSock, keybuf, keylen, 0, 19251360Seric (struct sockaddr *) &up->udb_addr, 193*51362Seric sizeof up->udb_addr) < 0) 19451360Seric { 19551360Seric continue; 19651360Seric } 19751360Seric timeout.tv_sec = up->udb_timeout / 10; 19851360Seric timeout.tv_usec = (up->udb_timeout % 10) * 100000; 19951360Seric do 20051360Seric { 20151360Seric FD_ZERO(&fdset); 202*51362Seric FD_SET(UdbSock, &fdset); 20351360Seric i = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout); 204*51362Seric } while (i > 0 && !FD_ISSET(UdbSock, &fdset)); 20551360Seric if (i <= 0) 20651360Seric continue; 207*51362Seric i = recvfrom(UdbSock, buf, sizeof buf - 1, 0, NULL, NULL); 20851360Seric if (i < 0) 20951360Seric continue; 210*51362Seric if (buf[0] != ' ' && buf[0] != '-') 211*51362Seric continue; 212*51362Seric breakout = TRUE; 213*51362Seric while (buf[0] == ' ' || buf[0] == '-') 214*51362Seric { 215*51362Seric user = &buf[1]; 216*51362Seric buf[i] = '\0'; 217*51362Seric message(Arpa_Info, "expanded to %s", user); 218*51362Seric AliasLevel++; 219*51362Seric sendtolist(user, a, sendq); 220*51362Seric AliasLevel--; 221*51362Seric 222*51362Seric /* try for next record */ 223*51362Seric if (buf[0] == ' ') 224*51362Seric break; 225*51362Seric i = recvfrom(UdbSock, buf, sizeof buf - 1, 0, NULL, NULL); 226*51362Seric if (i < 0) 227*51362Seric break; 228*51362Seric } 22951360Seric break; 23051360Seric 23151360Seric case UDB_FORWARD: 23251360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 23351360Seric if (i < sizeof buf) 23451360Seric user = buf; 23551360Seric else 23651360Seric user = xalloc(i + 1); 23751360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 238*51362Seric message(Arpa_Info, "expanded to %s", user); 239*51362Seric AliasLevel++; 240*51362Seric sendtolist(user, a, sendq); 241*51362Seric AliasLevel--; 242*51362Seric if (user != buf) 243*51362Seric free(user); 244*51362Seric breakout = TRUE; 24551360Seric break; 24651360Seric 24751360Seric case UDB_EOLIST: 24851360Seric breakout = TRUE; 24951360Seric continue; 25051360Seric 25151360Seric default: 25251360Seric /* unknown entry type */ 25351360Seric continue; 25451360Seric } 255*51362Seric } 256*51362Seric } 25751360Seric 258*51362Seric void 259*51362Seric _udbx_init() 260*51362Seric { 261*51362Seric register char *p; 262*51362Seric int i; 263*51362Seric register struct udbent *up; 264*51362Seric char buf[8192]; 26551360Seric 266*51362Seric p = UdbSpec; 267*51362Seric up = UdbEnts; 268*51362Seric for (;;) 269*51362Seric { 270*51362Seric char *spec; 271*51362Seric auto int rcode; 272*51362Seric int nmx; 273*51362Seric register struct hostent *h; 274*51362Seric char *mxhosts[MAXMXHOSTS + 1]; 275*51362Seric 276*51362Seric while (*p == ' ' || *p == '\t' || *p == ',') 277*51362Seric p++; 278*51362Seric if (*p == '\0') 279*51362Seric break; 280*51362Seric spec = p; 281*51362Seric p = index(p, ','); 282*51362Seric if (*p != '\0') 283*51362Seric *p++ = '\0'; 284*51362Seric switch (*spec) 28551360Seric { 286*51362Seric case '+': /* search remote database */ 287*51362Seric h = gethostbyname(spec + 1); 288*51362Seric if (h == NULL) 289*51362Seric continue; 290*51362Seric up->udb_type = UDB_REMOTE; 291*51362Seric up->udb_addr.sin_family = h->h_addrtype; 292*51362Seric up->udb_addr.sin_len = h->h_length; 293*51362Seric bcopy(h->h_addr_list[0], 294*51362Seric (char *) &up->udb_addr.sin_addr, 295*51362Seric h->h_length); 296*51362Seric up->udb_addr.sin_port = UdbPort; 297*51362Seric up->udb_timeout = UdbTimeout; 298*51362Seric up++; 299*51362Seric 300*51362Seric /* set up a datagram socket */ 301*51362Seric if (UdbSock < 0) 302*51362Seric { 303*51362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 304*51362Seric (void) fcntl(UdbSock, F_SETFD, 1); 305*51362Seric } 306*51362Seric break; 307*51362Seric 308*51362Seric case '*': /* search remote database (expand MX) */ 309*51362Seric nmx = getmxrr(spec + 1, mxhosts, "", &rcode); 310*51362Seric if (tTd(28, 16)) 311*51362Seric { 312*51362Seric int i; 313*51362Seric 314*51362Seric printf("getmxrr(%s): %d", spec + 1, nmx); 315*51362Seric for (i = 0; i <= nmx; i++) 316*51362Seric printf(" %s", mxhosts[i]); 317*51362Seric printf("\n"); 318*51362Seric } 319*51362Seric for (i = 0; i < nmx; i++) 320*51362Seric { 321*51362Seric h = gethostbyname(mxhosts[i]); 322*51362Seric if (h == NULL) 323*51362Seric continue; 324*51362Seric up->udb_type = UDB_REMOTE; 325*51362Seric up->udb_addr.sin_family = h->h_addrtype; 326*51362Seric up->udb_addr.sin_len = h->h_length; 327*51362Seric bcopy(h->h_addr_list[0], 328*51362Seric (char *) &up->udb_addr.sin_addr, 329*51362Seric h->h_length); 330*51362Seric up->udb_addr.sin_port = UdbPort; 331*51362Seric up->udb_timeout = UdbTimeout; 332*51362Seric up++; 333*51362Seric } 334*51362Seric 335*51362Seric /* set up a datagram socket */ 336*51362Seric if (UdbSock < 0) 337*51362Seric { 338*51362Seric UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 339*51362Seric (void) fcntl(UdbSock, F_SETFD, 1); 340*51362Seric } 341*51362Seric break; 342*51362Seric 343*51362Seric case '@': /* forward to remote host */ 344*51362Seric up->udb_type = UDB_FORWARD; 345*51362Seric up->udb_fwdhost = spec + 1; 346*51362Seric up++; 347*51362Seric break; 348*51362Seric 349*51362Seric case '/': /* look up remote name */ 350*51362Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 351*51362Seric if (up->udb_dbp == NULL) 352*51362Seric break; 353*51362Seric up->udb_type = UDB_LOOKUP; 354*51362Seric up++; 355*51362Seric break; 35651360Seric } 357*51362Seric } 358*51362Seric up->udb_type = UDB_EOLIST; 35951360Seric 360*51362Seric if (tTd(28, 4)) 361*51362Seric { 362*51362Seric for (up = UdbEnts; ; up++) 36351360Seric { 364*51362Seric switch (up->udb_type) 365*51362Seric { 366*51362Seric case UDB_EOLIST: 367*51362Seric return; 368*51362Seric 369*51362Seric case UDB_REMOTE: 370*51362Seric printf("REMOTE: addr %s, timeo %d\n", 371*51362Seric inet_ntoa(up->udb_addr.sin_addr), 372*51362Seric up->udb_timeout); 373*51362Seric break; 374*51362Seric 375*51362Seric case UDB_LOOKUP: 376*51362Seric printf("LOOKUP\n"); 377*51362Seric break; 378*51362Seric 379*51362Seric case UDB_FORWARD: 380*51362Seric printf("FORWARD: host %s\n", 381*51362Seric up->udb_fwdhost); 382*51362Seric break; 383*51362Seric 384*51362Seric default: 385*51362Seric printf("UNKNOWN\n"); 386*51362Seric break; 387*51362Seric } 38851360Seric } 38950581Seric } 39051360Seric } 39150581Seric 39251360Seric #else /* not USERDB */ 39351360Seric 39451360Seric void 39551360Seric udbexpand(a, sendq) 39651360Seric ADDRESS *a; 39751360Seric ADDRESS **sendq; 39851360Seric { 39951360Seric return; 40050581Seric } 40150581Seric 40250581Seric #endif /* USERDB */ 403