1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 #ifdef USERDB 11 static char sccsid [] = "@(#)udb.c 5.4 (Berkeley) 10/11/91 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 5.4 (Berkeley) 10/11/91 (without USERDB)"; 14 #endif 15 #endif 16 17 #include "sendmail.h" 18 19 #ifdef USERDB 20 21 #include <sys/file.h> 22 #include <sys/time.h> 23 #include <fcntl.h> 24 #include <netdb.h> 25 #include <db.h> 26 27 /* 28 ** UDBEXPAND -- look up user in database and expand 29 ** 30 ** Parameters: 31 ** a -- address to expand. 32 ** sendq -- pointer to head of sendq to put the expansions in. 33 ** 34 ** Returns: 35 ** none. 36 ** 37 ** Side Effects: 38 ** Modifies sendq. 39 */ 40 41 int UdbPort = 1616; 42 int UdbTimeout = 10; 43 44 struct udbent 45 { 46 char *udb_spec; /* string version of spec */ 47 int udb_type; /* type of entry */ 48 union 49 { 50 /* type UE_REMOTE -- do remote call for lookup */ 51 struct 52 { 53 struct sockaddr_in _udb_addr; /* address */ 54 int _udb_timeout; /* timeout */ 55 } udb_remote; 56 #define udb_addr udb_u.udb_remote._udb_addr 57 #define udb_timeout udb_u.udb_remote._udb_timeout 58 59 /* type UE_FORWARD -- forward message to remote */ 60 struct 61 { 62 char *_udb_fwdhost; /* name of forward host */ 63 } udb_forward; 64 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 65 66 /* type UE_LOOKUP -- lookup in local database */ 67 struct 68 { 69 char *_udb_dbname; /* pathname of database */ 70 DB *_udb_dbp; /* open database ptr */ 71 } udb_lookup; 72 #define udb_dbname udb_u.udb_lookup._udb_dbname 73 #define udb_dbp udb_u.udb_lookup._udb_dbp 74 } udb_u; 75 }; 76 77 #define UDB_EOLIST 0 /* end of list */ 78 #define UDB_SKIP 1 /* skip this entry */ 79 #define UDB_REMOTE 2 /* look up in remote database */ 80 #define UDB_LOOKUP 3 /* look up in local database */ 81 #define UDB_FORWARD 4 /* forward to remote host */ 82 83 #define MAXUDBENT 10 /* maximum number of UDB entries */ 84 85 struct udbent UdbEnts[MAXUDBENT + 1]; 86 int UdbSock = -1; 87 88 void 89 udbexpand(a, sendq) 90 register ADDRESS *a; 91 ADDRESS **sendq; 92 { 93 int i; 94 register char *p; 95 DBT key; 96 DBT info; 97 static bool firstcall = TRUE; 98 bool breakout; 99 register struct udbent *up; 100 int keylen; 101 char keybuf[128]; 102 char buf[8192]; 103 104 if (tTd(28, 1)) 105 printf("expand(%s)\n", a->q_paddr); 106 107 /* make certain we are supposed to send to this address */ 108 if (bitset(QDONTSEND, a->q_flags) || 109 UdbSpec == NULL || UdbSpec[0] == '\0') 110 return; 111 CurEnv->e_to = a->q_paddr; 112 113 /* on first call, locate the database */ 114 if (firstcall) 115 { 116 extern void _udbx_init(); 117 118 _udbx_init(); 119 firstcall = FALSE; 120 } 121 122 /* if name is too long, assume it won't match */ 123 if (strlen(a->q_user) > sizeof keybuf - 12) 124 return; 125 126 /* if name begins with a colon, it indicates our metadata */ 127 if (a->q_user[0] == ':') 128 return; 129 130 /* build actual database key */ 131 (void) strcpy(keybuf, a->q_user); 132 (void) strcat(keybuf, ":maildrop"); 133 keylen = strlen(keybuf); 134 135 breakout = FALSE; 136 for (up = UdbEnts; !breakout; up++) 137 { 138 char *user; 139 struct timeval timeout; 140 fd_set fdset; 141 142 /* 143 ** Select action based on entry type. 144 ** 145 ** On dropping out of this switch, "class" should 146 ** explain the type of the data, and "user" should 147 ** contain the user information. 148 */ 149 150 switch (up->udb_type) 151 { 152 case UDB_LOOKUP: 153 key.data = keybuf; 154 key.size = keylen; 155 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 156 if (i != 0 || info.size <= 0) 157 { 158 if (i < 0) 159 syserr("udbexpand: db-get stat %s"); 160 if (tTd(28, 2)) 161 printf("expand: no match on %s\n", keybuf); 162 continue; 163 } 164 165 /* there is at least one match -- start processing */ 166 breakout = TRUE; 167 do 168 { 169 if (info.size < sizeof buf) 170 user = buf; 171 else 172 user = xalloc(info.size + 1); 173 bcopy(info.data, user, info.size); 174 user[info.size] = '\0'; 175 176 message(Arpa_Info, "expanded to %s", user); 177 AliasLevel++; 178 sendtolist(user, a, sendq); 179 AliasLevel--; 180 181 if (user != buf) 182 free(user); 183 184 /* get the next record */ 185 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 186 } while (i == 0 && key.size == keylen && 187 bcmp(key.data, keybuf, keylen) == 0); 188 break; 189 190 case UDB_REMOTE: 191 if (sendto(UdbSock, keybuf, keylen, 0, 192 (struct sockaddr *) &up->udb_addr, 193 sizeof up->udb_addr) < 0) 194 { 195 continue; 196 } 197 timeout.tv_sec = up->udb_timeout / 10; 198 timeout.tv_usec = (up->udb_timeout % 10) * 100000; 199 do 200 { 201 FD_ZERO(&fdset); 202 FD_SET(UdbSock, &fdset); 203 i = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout); 204 } while (i > 0 && !FD_ISSET(UdbSock, &fdset)); 205 if (i <= 0) 206 continue; 207 i = recvfrom(UdbSock, buf, sizeof buf - 1, 0, NULL, NULL); 208 if (i < 0) 209 continue; 210 if (buf[0] != ' ' && buf[0] != '-') 211 continue; 212 breakout = TRUE; 213 while (buf[0] == ' ' || buf[0] == '-') 214 { 215 user = &buf[1]; 216 buf[i] = '\0'; 217 message(Arpa_Info, "expanded to %s", user); 218 AliasLevel++; 219 sendtolist(user, a, sendq); 220 AliasLevel--; 221 222 /* try for next record */ 223 if (buf[0] == ' ') 224 break; 225 i = recvfrom(UdbSock, buf, sizeof buf - 1, 0, NULL, NULL); 226 if (i < 0) 227 break; 228 } 229 break; 230 231 case UDB_FORWARD: 232 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 233 if (i < sizeof buf) 234 user = buf; 235 else 236 user = xalloc(i + 1); 237 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 238 message(Arpa_Info, "expanded to %s", user); 239 AliasLevel++; 240 sendtolist(user, a, sendq); 241 AliasLevel--; 242 if (user != buf) 243 free(user); 244 breakout = TRUE; 245 break; 246 247 case UDB_EOLIST: 248 breakout = TRUE; 249 continue; 250 251 default: 252 /* unknown entry type */ 253 continue; 254 } 255 } 256 } 257 258 void 259 _udbx_init() 260 { 261 register char *p; 262 int i; 263 register struct udbent *up; 264 char buf[8192]; 265 266 p = UdbSpec; 267 up = UdbEnts; 268 for (;;) 269 { 270 char *spec; 271 auto int rcode; 272 int nmx; 273 register struct hostent *h; 274 char *mxhosts[MAXMXHOSTS + 1]; 275 276 while (*p == ' ' || *p == '\t' || *p == ',') 277 p++; 278 if (*p == '\0') 279 break; 280 spec = p; 281 p = index(p, ','); 282 if (*p != '\0') 283 *p++ = '\0'; 284 switch (*spec) 285 { 286 case '+': /* search remote database */ 287 h = gethostbyname(spec + 1); 288 if (h == NULL) 289 continue; 290 up->udb_type = UDB_REMOTE; 291 up->udb_addr.sin_family = h->h_addrtype; 292 up->udb_addr.sin_len = h->h_length; 293 bcopy(h->h_addr_list[0], 294 (char *) &up->udb_addr.sin_addr, 295 h->h_length); 296 up->udb_addr.sin_port = UdbPort; 297 up->udb_timeout = UdbTimeout; 298 up++; 299 300 /* set up a datagram socket */ 301 if (UdbSock < 0) 302 { 303 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 304 (void) fcntl(UdbSock, F_SETFD, 1); 305 } 306 break; 307 308 case '*': /* search remote database (expand MX) */ 309 nmx = getmxrr(spec + 1, mxhosts, "", &rcode); 310 if (tTd(28, 16)) 311 { 312 int i; 313 314 printf("getmxrr(%s): %d", spec + 1, nmx); 315 for (i = 0; i <= nmx; i++) 316 printf(" %s", mxhosts[i]); 317 printf("\n"); 318 } 319 for (i = 0; i < nmx; i++) 320 { 321 h = gethostbyname(mxhosts[i]); 322 if (h == NULL) 323 continue; 324 up->udb_type = UDB_REMOTE; 325 up->udb_addr.sin_family = h->h_addrtype; 326 up->udb_addr.sin_len = h->h_length; 327 bcopy(h->h_addr_list[0], 328 (char *) &up->udb_addr.sin_addr, 329 h->h_length); 330 up->udb_addr.sin_port = UdbPort; 331 up->udb_timeout = UdbTimeout; 332 up++; 333 } 334 335 /* set up a datagram socket */ 336 if (UdbSock < 0) 337 { 338 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 339 (void) fcntl(UdbSock, F_SETFD, 1); 340 } 341 break; 342 343 case '@': /* forward to remote host */ 344 up->udb_type = UDB_FORWARD; 345 up->udb_fwdhost = spec + 1; 346 up++; 347 break; 348 349 case '/': /* look up remote name */ 350 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 351 if (up->udb_dbp == NULL) 352 break; 353 up->udb_type = UDB_LOOKUP; 354 up++; 355 break; 356 } 357 } 358 up->udb_type = UDB_EOLIST; 359 360 if (tTd(28, 4)) 361 { 362 for (up = UdbEnts; ; up++) 363 { 364 switch (up->udb_type) 365 { 366 case UDB_EOLIST: 367 return; 368 369 case UDB_REMOTE: 370 printf("REMOTE: addr %s, timeo %d\n", 371 inet_ntoa(up->udb_addr.sin_addr), 372 up->udb_timeout); 373 break; 374 375 case UDB_LOOKUP: 376 printf("LOOKUP\n"); 377 break; 378 379 case UDB_FORWARD: 380 printf("FORWARD: host %s\n", 381 up->udb_fwdhost); 382 break; 383 384 default: 385 printf("UNKNOWN\n"); 386 break; 387 } 388 } 389 } 390 } 391 392 #else /* not USERDB */ 393 394 void 395 udbexpand(a, sendq) 396 ADDRESS *a; 397 ADDRESS **sendq; 398 { 399 return; 400 } 401 402 #endif /* USERDB */ 403