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