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.17 (Berkeley) 12/15/91 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 5.17 (Berkeley) 12/15/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 <errno.h> 24 #include <fcntl.h> 25 #include <netdb.h> 26 #include <db.h> 27 28 /* 29 ** UDBEXPAND.C -- interface between sendmail and Berkeley User Data Base. 30 ** 31 ** This depends on the 4.4BSD db package. 32 */ 33 34 35 struct udbent 36 { 37 char *udb_spec; /* string version of spec */ 38 int udb_type; /* type of entry */ 39 char *udb_default; /* default host for outgoing mail */ 40 union 41 { 42 /* type UE_REMOTE -- do remote call for lookup */ 43 struct 44 { 45 struct sockaddr_in _udb_addr; /* address */ 46 int _udb_timeout; /* timeout */ 47 } udb_remote; 48 #define udb_addr udb_u.udb_remote._udb_addr 49 #define udb_timeout udb_u.udb_remote._udb_timeout 50 51 /* type UE_FORWARD -- forward message to remote */ 52 struct 53 { 54 char *_udb_fwdhost; /* name of forward host */ 55 } udb_forward; 56 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 57 58 /* type UE_FETCH -- lookup in local database */ 59 struct 60 { 61 char *_udb_dbname; /* pathname of database */ 62 DB *_udb_dbp; /* open database ptr */ 63 } udb_lookup; 64 #define udb_dbname udb_u.udb_lookup._udb_dbname 65 #define udb_dbp udb_u.udb_lookup._udb_dbp 66 } udb_u; 67 }; 68 69 #define UDB_EOLIST 0 /* end of list */ 70 #define UDB_SKIP 1 /* skip this entry */ 71 #define UDB_REMOTE 2 /* look up in remote database */ 72 #define UDB_DBFETCH 3 /* look up in local database */ 73 #define UDB_FORWARD 4 /* forward to remote host */ 74 75 #define MAXUDBENT 10 /* maximum number of UDB entries */ 76 77 78 struct option 79 { 80 char *name; 81 char *val; 82 }; 83 /* 84 ** UDBEXPAND -- look up user in database and expand 85 ** 86 ** Parameters: 87 ** a -- address to expand. 88 ** sendq -- pointer to head of sendq to put the expansions in. 89 ** 90 ** Returns: 91 ** EX_TEMPFAIL -- if something "odd" happened -- probably due 92 ** to accessing a file on an NFS server that is down. 93 ** EX_OK -- otherwise. 94 ** 95 ** Side Effects: 96 ** Modifies sendq. 97 */ 98 99 int UdbPort = 1616; 100 int UdbTimeout = 10; 101 102 struct udbent UdbEnts[MAXUDBENT + 1]; 103 int UdbSock = -1; 104 bool UdbInitialized = FALSE; 105 106 int 107 udbexpand(a, sendq) 108 register ADDRESS *a; 109 ADDRESS **sendq; 110 { 111 int i; 112 register char *p; 113 DBT key; 114 DBT info; 115 bool breakout; 116 register struct udbent *up; 117 int keylen; 118 char keybuf[128]; 119 char buf[8192]; 120 121 if (tTd(28, 1)) 122 printf("expand(%s)\n", a->q_paddr); 123 124 /* make certain we are supposed to send to this address */ 125 if (bitset(QDONTSEND, a->q_flags)) 126 return EX_OK; 127 CurEnv->e_to = a->q_paddr; 128 129 /* on first call, locate the database */ 130 if (!UdbInitialized) 131 { 132 extern int _udbx_init(); 133 134 if (_udbx_init() == EX_TEMPFAIL) 135 return EX_TEMPFAIL; 136 } 137 138 /* short circuit the process if no chance of a match */ 139 if (UdbSpec == NULL || UdbSpec[0] == '\0') 140 return EX_OK; 141 142 /* if name is too long, assume it won't match */ 143 if (strlen(a->q_user) > sizeof keybuf - 12) 144 return EX_OK; 145 146 /* if name begins with a colon, it indicates our metadata */ 147 if (a->q_user[0] == ':') 148 return EX_OK; 149 150 /* build actual database key */ 151 (void) strcpy(keybuf, a->q_user); 152 (void) strcat(keybuf, ":maildrop"); 153 keylen = strlen(keybuf); 154 155 breakout = FALSE; 156 for (up = UdbEnts; !breakout; up++) 157 { 158 char *user; 159 struct timeval timeout; 160 fd_set fdset; 161 162 /* 163 ** Select action based on entry type. 164 ** 165 ** On dropping out of this switch, "class" should 166 ** explain the type of the data, and "user" should 167 ** contain the user information. 168 */ 169 170 switch (up->udb_type) 171 { 172 case UDB_DBFETCH: 173 key.data = keybuf; 174 key.size = keylen; 175 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 176 if (i > 0 || info.size <= 0) 177 { 178 if (tTd(28, 2)) 179 printf("expand: no match on %s\n", keybuf); 180 continue; 181 } 182 183 while (i == 0 && key.size == keylen && 184 bcmp(key.data, keybuf, keylen) == 0) 185 { 186 breakout = TRUE; 187 if (info.size < sizeof buf) 188 user = buf; 189 else 190 user = xalloc(info.size + 1); 191 bcopy(info.data, user, info.size); 192 user[info.size] = '\0'; 193 194 message(Arpa_Info, "expanded to %s", user); 195 AliasLevel++; 196 sendtolist(user, a, sendq); 197 AliasLevel--; 198 199 if (user != buf) 200 free(user); 201 202 /* get the next record */ 203 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 204 } 205 if (i < 0) 206 { 207 syserr("udbexpand: db-get stat %s"); 208 return EX_TEMPFAIL; 209 } 210 break; 211 212 case UDB_REMOTE: 213 /* not yet implemented */ 214 continue; 215 216 case UDB_FORWARD: 217 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 218 if (i < sizeof buf) 219 user = buf; 220 else 221 user = xalloc(i + 1); 222 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 223 message(Arpa_Info, "expanded to %s", user); 224 AliasLevel++; 225 sendtolist(user, a, sendq); 226 AliasLevel--; 227 if (user != buf) 228 free(user); 229 breakout = TRUE; 230 break; 231 232 case UDB_EOLIST: 233 breakout = TRUE; 234 continue; 235 236 default: 237 /* unknown entry type */ 238 continue; 239 } 240 } 241 return EX_OK; 242 } 243 /* 244 ** UDBSENDER -- return canonical external name of sender, given local name 245 ** 246 ** Parameters: 247 ** sender -- the name of the sender on the local machine. 248 ** 249 ** Returns: 250 ** The external name for this sender, if derivable from the 251 ** database. 252 ** NULL -- if nothing is changed from the database. 253 ** 254 ** Side Effects: 255 ** none. 256 */ 257 258 char * 259 udbsender(sender) 260 char *sender; 261 { 262 register char *p; 263 register struct udbent *up; 264 int i; 265 int keylen; 266 DBT key, info; 267 char keybuf[128]; 268 269 if (tTd(28, 1)) 270 printf("udbsender(%s)\n", sender); 271 272 if (!UdbInitialized) 273 { 274 if (_udbx_init() == EX_TEMPFAIL) 275 return NULL; 276 } 277 278 /* short circuit if no spec */ 279 if (UdbSpec == NULL || UdbSpec[0] == '\0') 280 return NULL; 281 282 /* long names can never match and are a pain to deal with */ 283 if (strlen(sender) > sizeof keybuf - 12) 284 return NULL; 285 286 /* names beginning with colons indicate metadata */ 287 if (sender[0] == ':') 288 return NULL; 289 290 /* build database key */ 291 (void) strcpy(keybuf, sender); 292 (void) strcat(keybuf, ":mailname"); 293 keylen = strlen(keybuf); 294 295 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 296 { 297 /* 298 ** Select action based on entry type. 299 */ 300 301 switch (up->udb_type) 302 { 303 case UDB_DBFETCH: 304 key.data = keybuf; 305 key.size = keylen; 306 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 307 if (i != 0 || info.size <= 0) 308 { 309 if (tTd(28, 2)) 310 printf("udbsender: no match on %s\n", 311 keybuf); 312 continue; 313 } 314 315 p = xalloc(info.size + 1); 316 bcopy(info.data, p, info.size); 317 p[info.size] = '\0'; 318 if (tTd(28, 1)) 319 printf("udbsender ==> %s\n", p); 320 return p; 321 } 322 } 323 324 /* 325 ** Nothing yet. Search again for a default case. But only 326 ** use it if we also have a forward (:maildrop) pointer already 327 ** in the database. 328 */ 329 330 /* build database key */ 331 (void) strcpy(keybuf, sender); 332 (void) strcat(keybuf, ":maildrop"); 333 keylen = strlen(keybuf); 334 335 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 336 { 337 switch (up->udb_type) 338 { 339 case UDB_DBFETCH: 340 /* get the default case for this database */ 341 if (up->udb_default == NULL) 342 { 343 key.data = ":default:mailname"; 344 key.size = strlen(key.data); 345 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 346 if (i != 0 || info.size <= 0) 347 { 348 /* no default case */ 349 up->udb_default = ""; 350 continue; 351 } 352 353 /* save the default case */ 354 up->udb_default = xalloc(info.size + 1); 355 bcopy(info.data, up->udb_default, info.size); 356 up->udb_default[info.size] = '\0'; 357 } 358 else if (up->udb_default[0] == '\0') 359 continue; 360 361 /* we have a default case -- verify user:maildrop */ 362 key.data = keybuf; 363 key.size = keylen; 364 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 365 if (i != 0 || info.size <= 0) 366 { 367 /* nope -- no aliasing for this user */ 368 continue; 369 } 370 371 /* they exist -- build the actual address */ 372 p = xalloc(strlen(sender) + strlen(up->udb_default) + 2); 373 (void) strcpy(p, sender); 374 (void) strcat(p, "@"); 375 (void) strcat(p, up->udb_default); 376 if (tTd(28, 1)) 377 printf("udbsender ==> %s\n", p); 378 return p; 379 } 380 } 381 382 /* still nothing.... too bad */ 383 return NULL; 384 } 385 /* 386 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 387 ** 388 ** Parameters: 389 ** none. 390 ** 391 ** Returns: 392 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 393 ** database due to a host being down or some similar 394 ** (recoverable) situation. 395 ** EX_OK -- otherwise. 396 ** 397 ** Side Effects: 398 ** Fills in the UdbEnts structure from UdbSpec. 399 */ 400 401 #define MAXUDBOPTS 27 402 403 int 404 _udbx_init() 405 { 406 register char *p; 407 int i; 408 register struct udbent *up; 409 char buf[8192]; 410 411 if (UdbInitialized) 412 return EX_OK; 413 414 # ifdef UDB_DEFAULT_SPEC 415 if (UdbSpec == NULL) 416 UdbSpec = UDB_DEFAULT_SPEC; 417 # endif 418 419 p = UdbSpec; 420 up = UdbEnts; 421 while (p != NULL) 422 { 423 char *spec; 424 auto int rcode; 425 int nopts; 426 int nmx; 427 register struct hostent *h; 428 char *mxhosts[MAXMXHOSTS + 1]; 429 struct option opts[MAXUDBOPTS + 1]; 430 431 while (*p == ' ' || *p == '\t' || *p == ',') 432 p++; 433 if (*p == '\0') 434 break; 435 spec = p; 436 p = index(p, ','); 437 if (p != NULL) 438 *p++ = '\0'; 439 440 /* extract options */ 441 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 442 443 /* 444 ** Decode database specification. 445 ** 446 ** In the sendmail tradition, the leading character 447 ** defines the semantics of the rest of the entry. 448 ** 449 ** +hostname -- send a datagram to the udb server 450 ** on host "hostname" asking for the 451 ** home mail server for this user. 452 ** *hostname -- similar to +hostname, except that the 453 ** hostname is searched as an MX record; 454 ** resulting hosts are searched as for 455 ** +mxhostname. If no MX host is found, 456 ** this is the same as +hostname. 457 ** @hostname -- forward email to the indicated host. 458 ** This should be the last in the list, 459 ** since it always matches the input. 460 ** /dbname -- search the named database on the local 461 ** host using the Berkeley db package. 462 */ 463 464 switch (*spec) 465 { 466 case '+': /* search remote database */ 467 case '*': /* search remote database (expand MX) */ 468 if (*spec == '*') 469 { 470 nmx = getmxrr(spec + 1, mxhosts, "", &rcode); 471 if (tTd(28, 16)) 472 { 473 int i; 474 475 printf("getmxrr(%s): %d", spec + 1, nmx); 476 for (i = 0; i <= nmx; i++) 477 printf(" %s", mxhosts[i]); 478 printf("\n"); 479 } 480 } 481 else 482 { 483 nmx = 1; 484 mxhosts[0] = spec + 1; 485 } 486 487 for (i = 0; i < nmx; i++) 488 { 489 h = gethostbyname(mxhosts[i]); 490 if (h == NULL) 491 continue; 492 up->udb_type = UDB_REMOTE; 493 up->udb_addr.sin_family = h->h_addrtype; 494 bcopy(h->h_addr_list[0], 495 (char *) &up->udb_addr.sin_addr, 496 h->h_length); 497 up->udb_addr.sin_port = UdbPort; 498 up->udb_timeout = UdbTimeout; 499 up++; 500 } 501 502 /* set up a datagram socket */ 503 if (UdbSock < 0) 504 { 505 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 506 (void) fcntl(UdbSock, F_SETFD, 1); 507 } 508 break; 509 510 case '@': /* forward to remote host */ 511 up->udb_type = UDB_FORWARD; 512 up->udb_fwdhost = spec + 1; 513 up++; 514 break; 515 516 case '/': /* look up remote name */ 517 up->udb_dbname = spec; 518 errno = 0; 519 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 520 if (up->udb_dbp == NULL) 521 { 522 if (errno != ENOENT && errno != EACCES) 523 { 524 up->udb_type = UDB_EOLIST; 525 goto tempfail; 526 } 527 break; 528 } 529 up->udb_type = UDB_DBFETCH; 530 up++; 531 break; 532 } 533 } 534 up->udb_type = UDB_EOLIST; 535 536 if (tTd(28, 4)) 537 { 538 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 539 { 540 switch (up->udb_type) 541 { 542 case UDB_REMOTE: 543 printf("REMOTE: addr %s, timeo %d\n", 544 inet_ntoa(up->udb_addr.sin_addr), 545 up->udb_timeout); 546 break; 547 548 case UDB_DBFETCH: 549 printf("FETCH: file %s\n", 550 up->udb_dbname); 551 break; 552 553 case UDB_FORWARD: 554 printf("FORWARD: host %s\n", 555 up->udb_fwdhost); 556 break; 557 558 default: 559 printf("UNKNOWN\n"); 560 break; 561 } 562 } 563 } 564 565 UdbInitialized = TRUE; 566 errno = 0; 567 return EX_OK; 568 569 /* 570 ** On temporary failure, back out anything we've already done 571 */ 572 573 tempfail: 574 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 575 { 576 if (up->udb_type == UDB_DBFETCH) 577 { 578 (*up->udb_dbp->close)(up->udb_dbp); 579 } 580 } 581 return EX_TEMPFAIL; 582 } 583 584 int 585 _udb_parsespec(udbspec, opt, maxopts) 586 char *udbspec; 587 struct option opt[]; 588 int maxopts; 589 { 590 register char *spec; 591 register char *spec_end; 592 register int optnum; 593 594 spec_end = index(udbspec, ':'); 595 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 596 { 597 register char *p; 598 599 while (isspace(*spec)) 600 spec++; 601 spec_end = index(spec, ':'); 602 if (spec_end != NULL) 603 *spec_end++ = '\0'; 604 605 opt[optnum].name = spec; 606 opt[optnum].val = NULL; 607 p = index(spec, '='); 608 if (p != NULL) 609 opt[optnum].val = ++p; 610 } 611 return optnum; 612 } 613 614 #else /* not USERDB */ 615 616 int 617 udbexpand(a, sendq) 618 ADDRESS *a; 619 ADDRESS **sendq; 620 { 621 return EX_OK; 622 } 623 624 #endif /* USERDB */ 625