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