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 10*51360Seric #ifdef USERDB 11*51360Seric static char sccsid [] = "@(#)udb.c 5.3 (Berkeley) 10/11/91 (with USERDB)"; 12*51360Seric #else 13*51360Seric static char sccsid [] = "@(#)udb.c 5.3 (Berkeley) 10/11/91 (without USERDB)"; 1450581Seric #endif 15*51360Seric #endif 1650581Seric 1750581Seric #include "sendmail.h" 1850581Seric 1950581Seric #ifdef USERDB 2050581Seric 2150581Seric #include <sys/file.h> 22*51360Seric #include <sys/time.h> 23*51360Seric #include <fcntl.h> 24*51360Seric #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*51360Seric struct udbent 42*51360Seric { 43*51360Seric char *udb_spec; /* string version of spec */ 44*51360Seric int udb_type; /* type of entry */ 45*51360Seric union 46*51360Seric { 47*51360Seric /* type UE_REMOTE -- do remote call for lookup */ 48*51360Seric struct 49*51360Seric { 50*51360Seric int _udb_addrlen; /* length of addr */ 51*51360Seric struct sockaddr_in _udb_addr; /* address */ 52*51360Seric int _udb_timeout; /* timeout */ 53*51360Seric } udb_remote; 54*51360Seric #define udb_addrlen udb_u.udb_remote._udb_addrlen 55*51360Seric #define udb_addr udb_u.udb_remote._udb_addr 56*51360Seric #define udb_timeout udb_u.udb_remote._udb_timeout 57*51360Seric 58*51360Seric /* type UE_FORWARD -- forward message to remote */ 59*51360Seric struct 60*51360Seric { 61*51360Seric char *_udb_fwdhost; /* name of forward host */ 62*51360Seric } udb_forward; 63*51360Seric #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 64*51360Seric 65*51360Seric /* type UE_LOOKUP -- lookup in local database */ 66*51360Seric struct 67*51360Seric { 68*51360Seric char *_udb_dbname; /* pathname of database */ 69*51360Seric DB *_udb_dbp; /* open database ptr */ 70*51360Seric } udb_lookup; 71*51360Seric #define udb_dbname udb_u.udb_lookup._udb_dbname 72*51360Seric #define udb_dbp udb_u.udb_lookup._udb_dbp 73*51360Seric } udb_u; 74*51360Seric }; 75*51360Seric 76*51360Seric #define UDB_EOLIST 0 /* end of list */ 77*51360Seric #define UDB_SKIP 1 /* skip this entry */ 78*51360Seric #define UDB_REMOTE 2 /* look up in remote database */ 79*51360Seric #define UDB_LOOKUP 3 /* look up in local database */ 80*51360Seric #define UDB_FORWARD 4 /* forward to remote host */ 81*51360Seric 82*51360Seric #define MAXUDBENT 10 /* maximum number of UDB entries */ 83*51360Seric 84*51360Seric 8550581Seric void 8650581Seric udbexpand(a, sendq) 8750581Seric register ADDRESS *a; 8850581Seric ADDRESS **sendq; 8950581Seric { 9050581Seric int i; 9150581Seric register char *p; 9250581Seric auto char *class; 9350581Seric auto char *list; 9450581Seric DBT key; 9550581Seric DBT info; 9650581Seric register char *bp; 97*51360Seric static bool firstcall = TRUE; 98*51360Seric static int udbsock = -1; 99*51360Seric bool breakout; 100*51360Seric register struct udbent *up; 101*51360Seric struct udbent udbents[MAXUDBENT + 1]; 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 */ 108*51360Seric if (bitset(QDONTSEND, a->q_flags) || 109*51360Seric UdbSpec == NULL || UdbSpec[0] == '\0') 11050581Seric return; 11150581Seric CurEnv->e_to = a->q_paddr; 11250581Seric 113*51360Seric /* on first call, locate the database */ 114*51360Seric if (firstcall) 11550581Seric { 116*51360Seric firstcall = FALSE; 117*51360Seric p = UdbSpec; 118*51360Seric up = udbents; 119*51360Seric for (;;) 12050581Seric { 121*51360Seric char *spec; 122*51360Seric auto int rcode; 123*51360Seric int nmx; 124*51360Seric char *mxhosts[MAXMXHOSTS + 1]; 12550581Seric 126*51360Seric while (*p == ' ' || *p == '\t' || *p == ',') 127*51360Seric p++; 128*51360Seric if (*p == '\0') 129*51360Seric break; 130*51360Seric spec = p; 131*51360Seric p = index(p, ','); 132*51360Seric if (*p != '\0') 133*51360Seric *p++ = '\0'; 134*51360Seric switch (*spec) 135*51360Seric { 136*51360Seric case '*': /* search remote database */ 137*51360Seric expand("\001j", buf, &buf[sizeof(buf) - 1], CurEnv); 138*51360Seric nmx = getmxrr(spec + 1, mxhosts, buf, &rcode); 139*51360Seric for (i = 0; i < nmx; i++) 140*51360Seric { 141*51360Seric register struct hostent *h; 142*51360Seric 143*51360Seric h = gethostbyname(mxhosts[i]); 144*51360Seric if (h == NULL) 145*51360Seric continue; 146*51360Seric up->udb_type = UDB_REMOTE; 147*51360Seric up->udb_addr.sin_family = h->h_addrtype; 148*51360Seric up->udb_addrlen = h->h_length; 149*51360Seric bcopy(h->h_addr_list[0], 150*51360Seric (char *) &up->udb_addr.sin_addr, 151*51360Seric h->h_length); 152*51360Seric up++; 153*51360Seric } 154*51360Seric 155*51360Seric /* set up a datagram socket */ 156*51360Seric if (udbsock < 0) 157*51360Seric { 158*51360Seric udbsock = socket(AF_INET, SOCK_DGRAM, 0); 159*51360Seric (void) fcntl(udbsock, F_SETFD, 1); 160*51360Seric } 161*51360Seric break; 162*51360Seric 163*51360Seric case '@': /* forward to remote host */ 164*51360Seric up->udb_type = UDB_FORWARD; 165*51360Seric up->udb_fwdhost = spec + 1; 166*51360Seric up++; 167*51360Seric break; 168*51360Seric 169*51360Seric case '/': /* look up remote name */ 170*51360Seric up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 171*51360Seric if (up->udb_dbp == NULL) 172*51360Seric break; 173*51360Seric up->udb_type = UDB_LOOKUP; 174*51360Seric up++; 175*51360Seric break; 176*51360Seric } 17750581Seric } 178*51360Seric up->udb_type = UDB_EOLIST; 17950581Seric } 18050581Seric 181*51360Seric breakout = FALSE; 182*51360Seric for (up = udbents; !breakout; up++) 18350581Seric { 184*51360Seric char *user; 185*51360Seric struct timeval timeout; 186*51360Seric fd_set fdset; 18750581Seric 188*51360Seric /* 189*51360Seric ** Select action based on entry type. 190*51360Seric ** 191*51360Seric ** On dropping out of this switch, "class" should 192*51360Seric ** explain the type of the data, and "user" should 193*51360Seric ** contain the user information. 194*51360Seric */ 19550581Seric 196*51360Seric switch (up->udb_type) 197*51360Seric { 198*51360Seric case UDB_LOOKUP: 199*51360Seric key.data = a->q_user; 200*51360Seric key.size = strlen(key.data); 201*51360Seric i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 202*51360Seric if (i != 0 || info.size <= 0) 203*51360Seric { 204*51360Seric if (i < 0) 205*51360Seric syserr("udbexpand: db-get stat %s"); 206*51360Seric if (tTd(28, 2)) 207*51360Seric printf("expand: no match on %s\n", key.data); 208*51360Seric continue; 209*51360Seric } 21050581Seric 211*51360Seric /* extract the class (first string) and data (second string) */ 212*51360Seric class = info.data; 213*51360Seric i = strlen((char *) info.data) + 1; 214*51360Seric p = (char *) info.data + i; 215*51360Seric i = info.size - i; 21650581Seric 217*51360Seric /* use internal buffer if it will fit; otherwise malloc */ 218*51360Seric if (i < sizeof buf) 219*51360Seric user = buf; 220*51360Seric else 221*51360Seric user = xalloc(i + 1); 222*51360Seric bcopy(p, user, i); 223*51360Seric user[i] = '\0'; 224*51360Seric break; 225*51360Seric 226*51360Seric case UDB_REMOTE: 227*51360Seric if (sendto(udbsock, a->q_user, strlen(a->q_user), 0, 228*51360Seric (struct sockaddr *) &up->udb_addr, 229*51360Seric up->udb_addrlen) < 0) 230*51360Seric { 231*51360Seric continue; 232*51360Seric } 233*51360Seric timeout.tv_sec = up->udb_timeout / 10; 234*51360Seric timeout.tv_usec = (up->udb_timeout % 10) * 100000; 235*51360Seric do 236*51360Seric { 237*51360Seric FD_ZERO(&fdset); 238*51360Seric FD_SET(udbsock, &fdset); 239*51360Seric i = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout); 240*51360Seric } while (i > 0 && !FD_ISSET(udbsock, &fdset)); 241*51360Seric if (i <= 0) 242*51360Seric continue; 243*51360Seric i = recvfrom(udbsock, buf, sizeof buf - 1, 0, NULL, NULL); 244*51360Seric if (i < 0) 245*51360Seric continue; 246*51360Seric class = buf; 247*51360Seric user = &buf[strlen(buf)]; 248*51360Seric buf[i] = '\0'; 249*51360Seric break; 250*51360Seric 251*51360Seric case UDB_FORWARD: 252*51360Seric class = "forward"; 253*51360Seric i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 254*51360Seric if (i < sizeof buf) 255*51360Seric user = buf; 256*51360Seric else 257*51360Seric user = xalloc(i + 1); 258*51360Seric (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 259*51360Seric break; 260*51360Seric 261*51360Seric case UDB_EOLIST: 262*51360Seric breakout = TRUE; 263*51360Seric continue; 264*51360Seric 265*51360Seric default: 266*51360Seric /* unknown entry type */ 267*51360Seric continue; 268*51360Seric } 269*51360Seric 270*51360Seric if (tTd(28, 1)) 271*51360Seric printf("Class %s: %s\n", class, user); 272*51360Seric 273*51360Seric /* do special processing based on class */ 274*51360Seric if (strcmp(class, "user") == 0 || strcmp(class, "forward") == 0) 275*51360Seric { 276*51360Seric message(Arpa_Info, "expanded to (%s) %s", class, user); 277*51360Seric AliasLevel++; 278*51360Seric sendtolist(user, a, sendq); 279*51360Seric AliasLevel--; 280*51360Seric breakout = TRUE; 281*51360Seric } 282*51360Seric 283*51360Seric /* free memory if we allocated it */ 284*51360Seric if (up->udb_type == UDB_FORWARD || up->udb_type == UDB_LOOKUP) 285*51360Seric { 286*51360Seric if (user != buf) 287*51360Seric free(user); 288*51360Seric } 28950581Seric } 290*51360Seric } 29150581Seric 292*51360Seric #else /* not USERDB */ 293*51360Seric 294*51360Seric void 295*51360Seric udbexpand(a, sendq) 296*51360Seric ADDRESS *a; 297*51360Seric ADDRESS **sendq; 298*51360Seric { 299*51360Seric return; 30050581Seric } 30150581Seric 30250581Seric #endif /* USERDB */ 303