1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #include "sendmail.h" 14 15 #ifndef lint 16 #if USERDB 17 static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (with USERDB)"; 18 #else 19 static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (without USERDB)"; 20 #endif 21 #endif 22 23 #if USERDB 24 25 #include <errno.h> 26 27 #ifdef NEWDB 28 # include <db.h> 29 # ifndef DB_VERSION_MAJOR 30 # define DB_VERSION_MAJOR 1 31 # endif 32 #else 33 # define DBT struct _data_base_thang_ 34 DBT 35 { 36 void *data; /* pointer to data */ 37 size_t size; /* length of data */ 38 }; 39 #endif 40 41 /* 42 ** UDB.C -- interface between sendmail and Berkeley User Data Base. 43 ** 44 ** This depends on the 4.4BSD db package. 45 */ 46 47 48 struct udbent 49 { 50 char *udb_spec; /* string version of spec */ 51 int udb_type; /* type of entry */ 52 pid_t udb_pid; /* PID of process which opened db */ 53 char *udb_default; /* default host for outgoing mail */ 54 union 55 { 56 /* type UE_REMOTE -- do remote call for lookup */ 57 struct 58 { 59 struct sockaddr_in _udb_addr; /* address */ 60 int _udb_timeout; /* timeout */ 61 } udb_remote; 62 #define udb_addr udb_u.udb_remote._udb_addr 63 #define udb_timeout udb_u.udb_remote._udb_timeout 64 65 /* type UE_FORWARD -- forward message to remote */ 66 struct 67 { 68 char *_udb_fwdhost; /* name of forward host */ 69 } udb_forward; 70 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 71 72 #ifdef NEWDB 73 /* type UE_FETCH -- lookup in local database */ 74 struct 75 { 76 char *_udb_dbname; /* pathname of database */ 77 DB *_udb_dbp; /* open database ptr */ 78 } udb_lookup; 79 #define udb_dbname udb_u.udb_lookup._udb_dbname 80 #define udb_dbp udb_u.udb_lookup._udb_dbp 81 #endif 82 } udb_u; 83 }; 84 85 #define UDB_EOLIST 0 /* end of list */ 86 #define UDB_SKIP 1 /* skip this entry */ 87 #define UDB_REMOTE 2 /* look up in remote database */ 88 #define UDB_DBFETCH 3 /* look up in local database */ 89 #define UDB_FORWARD 4 /* forward to remote host */ 90 #define UDB_HESIOD 5 /* look up via hesiod */ 91 92 #define MAXUDBENT 10 /* maximum number of UDB entries */ 93 94 95 struct udb_option 96 { 97 char *name; 98 char *val; 99 }; 100 101 #ifdef HESIOD 102 extern int hes_udb_get __P((DBT *, DBT *)); 103 #endif 104 extern int _udbx_init __P((ENVELOPE *)); 105 /* 106 ** UDBEXPAND -- look up user in database and expand 107 ** 108 ** Parameters: 109 ** a -- address to expand. 110 ** sendq -- pointer to head of sendq to put the expansions in. 111 ** aliaslevel -- the current alias nesting depth. 112 ** e -- the current envelope. 113 ** 114 ** Returns: 115 ** EX_TEMPFAIL -- if something "odd" happened -- probably due 116 ** to accessing a file on an NFS server that is down. 117 ** EX_OK -- otherwise. 118 ** 119 ** Side Effects: 120 ** Modifies sendq. 121 */ 122 123 int UdbPort = 1616; 124 int UdbTimeout = 10; 125 126 struct udbent UdbEnts[MAXUDBENT + 1]; 127 int UdbSock = -1; 128 bool UdbInitialized = FALSE; 129 130 int 131 udbexpand(a, sendq, aliaslevel, e) 132 register ADDRESS *a; 133 ADDRESS **sendq; 134 int aliaslevel; 135 register ENVELOPE *e; 136 { 137 int i; 138 DBT key; 139 DBT info; 140 bool breakout; 141 register struct udbent *up; 142 int keylen; 143 int naddrs; 144 char *user; 145 char keybuf[MAXKEY]; 146 147 bzero(&key, sizeof key); 148 bzero(&info, sizeof info); 149 150 if (tTd(28, 1)) 151 printf("udbexpand(%s)\n", a->q_paddr); 152 153 /* make certain we are supposed to send to this address */ 154 if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 155 return EX_OK; 156 e->e_to = a->q_paddr; 157 158 /* on first call, locate the database */ 159 if (!UdbInitialized) 160 { 161 if (_udbx_init(e) == EX_TEMPFAIL) 162 return EX_TEMPFAIL; 163 } 164 165 /* short circuit the process if no chance of a match */ 166 if (UdbSpec == NULL || UdbSpec[0] == '\0') 167 return EX_OK; 168 169 /* extract user to do userdb matching on */ 170 user = a->q_user; 171 172 /* short circuit name begins with '\\' since it can't possibly match */ 173 /* (might want to treat this as unquoted instead) */ 174 if (user[0] == '\\') 175 return EX_OK; 176 177 /* if name is too long, assume it won't match */ 178 if (strlen(user) > (SIZE_T) sizeof keybuf - 12) 179 return EX_OK; 180 181 /* if name begins with a colon, it indicates our metadata */ 182 if (user[0] == ':') 183 return EX_OK; 184 185 /* build actual database key */ 186 (void) strcpy(keybuf, user); 187 (void) strcat(keybuf, ":maildrop"); 188 keylen = strlen(keybuf); 189 190 breakout = FALSE; 191 for (up = UdbEnts; !breakout; up++) 192 { 193 char *user; 194 int usersize; 195 int userleft; 196 char userbuf[MEMCHUNKSIZE]; 197 #if defined(HESIOD) && defined(HES_GETMAILHOST) 198 char pobuf[MAXNAME]; 199 #endif 200 #if defined(NEWDB) && DB_VERSION_MAJOR > 1 201 DBC *dbc = NULL; 202 #endif 203 204 user = userbuf; 205 userbuf[0] = '\0'; 206 usersize = sizeof userbuf; 207 userleft = sizeof userbuf - 1; 208 209 /* 210 ** Select action based on entry type. 211 ** 212 ** On dropping out of this switch, "class" should 213 ** explain the type of the data, and "user" should 214 ** contain the user information. 215 */ 216 217 switch (up->udb_type) 218 { 219 #ifdef NEWDB 220 case UDB_DBFETCH: 221 key.data = keybuf; 222 key.size = keylen; 223 if (tTd(28, 80)) 224 printf("udbexpand: trying %s (%d) via db\n", 225 keybuf, keylen); 226 #if DB_VERSION_MAJOR < 2 227 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 228 #else 229 i = 0; 230 if (dbc == NULL && 231 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6 232 (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 233 NULL, &dbc, 0)) != 0) 234 # else 235 (errno = (*up->udb_dbp->cursor)(up->udb_dbp, 236 NULL, &dbc)) != 0) 237 # endif 238 i = -1; 239 if (i != 0 || dbc == NULL || 240 (errno = dbc->c_get(dbc, &key, 241 &info, DB_SET)) != 0) 242 i = 1; 243 #endif 244 if (i > 0 || info.size <= 0) 245 { 246 if (tTd(28, 2)) 247 printf("udbexpand: no match on %s (%d)\n", 248 keybuf, keylen); 249 #if DB_VERSION_MAJOR > 1 250 if (dbc != NULL) 251 { 252 (void) dbc->c_close(dbc); 253 dbc = NULL; 254 } 255 #endif 256 break; 257 } 258 if (tTd(28, 80)) 259 printf("udbexpand: match %.*s: %.*s\n", 260 (int) key.size, (char *) key.data, 261 (int) info.size, (char *) info.data); 262 263 a->q_flags &= ~QSELFREF; 264 while (i == 0 && key.size == keylen && 265 bcmp(key.data, keybuf, keylen) == 0) 266 { 267 char *p; 268 269 if (bitset(EF_VRFYONLY, e->e_flags)) 270 { 271 a->q_flags |= QVERIFIED; 272 #if DB_VERSION_MAJOR > 1 273 if (dbc != NULL) 274 { 275 (void) dbc->c_close(dbc); 276 dbc = NULL; 277 } 278 #endif 279 return EX_OK; 280 } 281 282 breakout = TRUE; 283 if (info.size >= userleft - 1) 284 { 285 char *nuser; 286 int size = MEMCHUNKSIZE; 287 288 if (info.size > MEMCHUNKSIZE) 289 size = info.size; 290 nuser = xalloc(usersize + size); 291 292 bcopy(user, nuser, usersize); 293 if (user != userbuf) 294 free(user); 295 user = nuser; 296 usersize += size; 297 userleft += size; 298 } 299 p = &user[strlen(user)]; 300 if (p != user) 301 { 302 *p++ = ','; 303 userleft--; 304 } 305 bcopy(info.data, p, info.size); 306 p[info.size] = '\0'; 307 userleft -= info.size; 308 309 /* get the next record */ 310 #if DB_VERSION_MAJOR < 2 311 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 312 #else 313 i = 0; 314 if ((errno = dbc->c_get(dbc, &key, 315 &info, DB_NEXT)) != 0) 316 i = 1; 317 #endif 318 } 319 320 #if DB_VERSION_MAJOR > 1 321 if (dbc != NULL) 322 { 323 (void) dbc->c_close(dbc); 324 dbc = NULL; 325 } 326 #endif 327 328 /* if nothing ever matched, try next database */ 329 if (!breakout) 330 break; 331 332 message("expanded to %s", user); 333 if (LogLevel >= 10) 334 sm_syslog(LOG_INFO, e->e_id, 335 "expand %.100s => %s", 336 e->e_to, 337 shortenstring(user, MAXSHORTSTR)); 338 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 339 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 340 { 341 if (tTd(28, 5)) 342 { 343 printf("udbexpand: QDONTSEND "); 344 printaddr(a, FALSE); 345 } 346 a->q_flags |= QDONTSEND; 347 } 348 if (i < 0) 349 { 350 syserr("udbexpand: db-get %.*s stat %d", 351 (int) key.size, (char *) key.data, i); 352 return EX_TEMPFAIL; 353 } 354 355 /* 356 ** If this address has a -request address, reflect 357 ** it into the envelope. 358 */ 359 360 bzero(&key, sizeof key); 361 bzero(&info, sizeof info); 362 (void) strcpy(keybuf, a->q_user); 363 (void) strcat(keybuf, ":mailsender"); 364 keylen = strlen(keybuf); 365 key.data = keybuf; 366 key.size = keylen; 367 368 #if DB_VERSION_MAJOR < 2 369 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 370 #else 371 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 372 &key, &info, 0); 373 #endif 374 if (i != 0 || info.size <= 0) 375 break; 376 a->q_owner = xalloc(info.size + 1); 377 bcopy(info.data, a->q_owner, info.size); 378 a->q_owner[info.size] = '\0'; 379 380 /* announce delivery; NORECEIPT bit set later */ 381 if (e->e_xfp != NULL) 382 { 383 fprintf(e->e_xfp, 384 "Message delivered to mailing list %s\n", 385 a->q_paddr); 386 } 387 e->e_flags |= EF_SENDRECEIPT; 388 a->q_flags |= QDELIVERED|QEXPANDED; 389 break; 390 #endif 391 392 #ifdef HESIOD 393 case UDB_HESIOD: 394 key.data = keybuf; 395 key.size = keylen; 396 if (tTd(28, 80)) 397 printf("udbexpand: trying %s (%d) via hesiod\n", 398 keybuf, keylen); 399 /* look up the key via hesiod */ 400 i = hes_udb_get(&key, &info); 401 if (i < 0) 402 { 403 syserr("udbexpand: hesiod-get %.*s stat %d", 404 (int) key.size, (char *) key.data, i); 405 return EX_TEMPFAIL; 406 } 407 else if (i > 0 || info.size <= 0) 408 { 409 #if HES_GETMAILHOST 410 struct hes_postoffice *hp; 411 #endif 412 413 if (tTd(28, 2)) 414 printf("udbexpand: no match on %s (%d)\n", 415 (char *) keybuf, (int) keylen); 416 #if HES_GETMAILHOST 417 if (tTd(28, 8)) 418 printf(" ... trying hes_getmailhost(%s)\n", 419 a->q_user); 420 hp = hes_getmailhost(a->q_user); 421 if (hp == NULL) 422 { 423 if (hes_error() == HES_ER_NET) 424 { 425 syserr("udbexpand: hesiod-getmail %s stat %d", 426 a->q_user, hes_error()); 427 return EX_TEMPFAIL; 428 } 429 if (tTd(28, 2)) 430 printf("hes_getmailhost(%s): %d\n", 431 a->q_user, hes_error()); 432 break; 433 } 434 if (strlen(hp->po_name) + strlen(hp->po_host) > 435 sizeof pobuf - 2) 436 { 437 if (tTd(28, 2)) 438 printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n", 439 a->q_user, 440 hp->po_name, 441 hp->po_host); 442 break; 443 } 444 info.data = pobuf; 445 snprintf(pobuf, sizeof pobuf, "%s@%s", 446 hp->po_name, hp->po_host); 447 info.size = strlen(info.data); 448 #else 449 break; 450 #endif 451 } 452 if (tTd(28, 80)) 453 printf("udbexpand: match %.*s: %.*s\n", 454 (int) key.size, (char *) key.data, 455 (int) info.size, (char *) info.data); 456 a->q_flags &= ~QSELFREF; 457 458 if (bitset(EF_VRFYONLY, e->e_flags)) 459 { 460 a->q_flags |= QVERIFIED; 461 return EX_OK; 462 } 463 464 breakout = TRUE; 465 if (info.size >= usersize) 466 user = xalloc(info.size + 1); 467 bcopy(info.data, user, info.size); 468 user[info.size] = '\0'; 469 470 message("hesioded to %s", user); 471 if (LogLevel >= 10) 472 sm_syslog(LOG_INFO, e->e_id, 473 "hesiod %.100s => %s", 474 e->e_to, 475 shortenstring(user, MAXSHORTSTR)); 476 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 477 478 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 479 { 480 if (tTd(28, 5)) 481 { 482 printf("udbexpand: QDONTSEND "); 483 printaddr(a, FALSE); 484 } 485 a->q_flags |= QDONTSEND; 486 } 487 488 /* 489 ** If this address has a -request address, reflect 490 ** it into the envelope. 491 */ 492 493 (void) strcpy(keybuf, a->q_user); 494 (void) strcat(keybuf, ":mailsender"); 495 keylen = strlen(keybuf); 496 key.data = keybuf; 497 key.size = keylen; 498 i = hes_udb_get(&key, &info); 499 if (i != 0 || info.size <= 0) 500 break; 501 a->q_owner = xalloc(info.size + 1); 502 bcopy(info.data, a->q_owner, info.size); 503 a->q_owner[info.size] = '\0'; 504 break; 505 #endif /* HESIOD */ 506 507 case UDB_REMOTE: 508 /* not yet implemented */ 509 break; 510 511 case UDB_FORWARD: 512 if (bitset(EF_VRFYONLY, e->e_flags)) 513 return EX_OK; 514 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 515 if (i >= usersize) 516 { 517 usersize = i + 1; 518 user = xalloc(usersize); 519 } 520 (void) snprintf(user, usersize, "%s@%s", 521 a->q_user, up->udb_fwdhost); 522 message("expanded to %s", user); 523 a->q_flags &= ~QSELFREF; 524 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 525 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 526 { 527 if (tTd(28, 5)) 528 { 529 printf("udbexpand: QDONTSEND "); 530 printaddr(a, FALSE); 531 } 532 a->q_flags |= QDONTSEND; 533 } 534 breakout = TRUE; 535 break; 536 537 case UDB_EOLIST: 538 breakout = TRUE; 539 break; 540 541 default: 542 /* unknown entry type */ 543 break; 544 } 545 if (user != userbuf) 546 free(user); 547 } 548 return EX_OK; 549 } 550 /* 551 ** UDBSENDER -- return canonical external name of sender, given local name 552 ** 553 ** Parameters: 554 ** sender -- the name of the sender on the local machine. 555 ** 556 ** Returns: 557 ** The external name for this sender, if derivable from the 558 ** database. 559 ** NULL -- if nothing is changed from the database. 560 ** 561 ** Side Effects: 562 ** none. 563 */ 564 565 char * 566 udbsender(sender) 567 char *sender; 568 { 569 extern char *udbmatch __P((char *, char *)); 570 571 return udbmatch(sender, "mailname"); 572 } 573 574 575 char * 576 udbmatch(user, field) 577 char *user; 578 char *field; 579 { 580 register char *p; 581 register struct udbent *up; 582 int i; 583 int keylen; 584 DBT key, info; 585 char keybuf[MAXKEY]; 586 587 if (tTd(28, 1)) 588 printf("udbmatch(%s, %s)\n", user, field); 589 590 if (!UdbInitialized) 591 { 592 if (_udbx_init(CurEnv) == EX_TEMPFAIL) 593 return NULL; 594 } 595 596 /* short circuit if no spec */ 597 if (UdbSpec == NULL || UdbSpec[0] == '\0') 598 return NULL; 599 600 /* short circuit name begins with '\\' since it can't possibly match */ 601 if (user[0] == '\\') 602 return NULL; 603 604 /* long names can never match and are a pain to deal with */ 605 i = strlen(field); 606 if (i < sizeof "maildrop") 607 i = sizeof "maildrop"; 608 if ((strlen(user) + i) > sizeof keybuf - 4) 609 return NULL; 610 611 /* names beginning with colons indicate metadata */ 612 if (user[0] == ':') 613 return NULL; 614 615 /* build database key */ 616 (void) strcpy(keybuf, user); 617 (void) strcat(keybuf, ":"); 618 (void) strcat(keybuf, field); 619 keylen = strlen(keybuf); 620 621 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 622 { 623 /* 624 ** Select action based on entry type. 625 */ 626 627 switch (up->udb_type) 628 { 629 #ifdef NEWDB 630 case UDB_DBFETCH: 631 bzero(&key, sizeof key); 632 bzero(&info, sizeof info); 633 key.data = keybuf; 634 key.size = keylen; 635 #if DB_VERSION_MAJOR < 2 636 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 637 #else 638 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 639 &key, &info, 0); 640 #endif 641 if (i != 0 || info.size <= 0) 642 { 643 if (tTd(28, 2)) 644 printf("udbmatch: no match on %s (%d) via db\n", 645 keybuf, keylen); 646 continue; 647 } 648 649 p = xalloc(info.size + 1); 650 bcopy(info.data, p, info.size); 651 p[info.size] = '\0'; 652 if (tTd(28, 1)) 653 printf("udbmatch ==> %s\n", p); 654 return p; 655 #endif 656 657 #ifdef HESIOD 658 case UDB_HESIOD: 659 key.data = keybuf; 660 key.size = keylen; 661 i = hes_udb_get(&key, &info); 662 if (i != 0 || info.size <= 0) 663 { 664 if (tTd(28, 2)) 665 printf("udbmatch: no match on %s (%d) via hesiod\n", 666 keybuf, keylen); 667 continue; 668 } 669 670 p = xalloc(info.size + 1); 671 bcopy(info.data, p, info.size); 672 p[info.size] = '\0'; 673 if (tTd(28, 1)) 674 printf("udbmatch ==> %s\n", p); 675 return p; 676 #endif /* HESIOD */ 677 } 678 } 679 680 if (strcmp(field, "mailname") != 0) 681 return NULL; 682 683 /* 684 ** Nothing yet. Search again for a default case. But only 685 ** use it if we also have a forward (:maildrop) pointer already 686 ** in the database. 687 */ 688 689 /* build database key */ 690 (void) strcpy(keybuf, user); 691 (void) strcat(keybuf, ":maildrop"); 692 keylen = strlen(keybuf); 693 694 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 695 { 696 switch (up->udb_type) 697 { 698 #ifdef NEWDB 699 case UDB_DBFETCH: 700 /* get the default case for this database */ 701 if (up->udb_default == NULL) 702 { 703 bzero(&key, sizeof key); 704 bzero(&info, sizeof info); 705 key.data = ":default:mailname"; 706 key.size = strlen(key.data); 707 #if DB_VERSION_MAJOR < 2 708 i = (*up->udb_dbp->get)(up->udb_dbp, 709 &key, &info, 0); 710 #else 711 i = errno = (*up->udb_dbp->get)(up->udb_dbp, 712 NULL, &key, 713 &info, 0); 714 #endif 715 if (i != 0 || info.size <= 0) 716 { 717 /* no default case */ 718 up->udb_default = ""; 719 continue; 720 } 721 722 /* save the default case */ 723 up->udb_default = xalloc(info.size + 1); 724 bcopy(info.data, up->udb_default, info.size); 725 up->udb_default[info.size] = '\0'; 726 } 727 else if (up->udb_default[0] == '\0') 728 continue; 729 730 /* we have a default case -- verify user:maildrop */ 731 bzero(&key, sizeof key); 732 bzero(&info, sizeof info); 733 key.data = keybuf; 734 key.size = keylen; 735 #if DB_VERSION_MAJOR < 2 736 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 737 #else 738 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 739 &key, &info, 0); 740 #endif 741 if (i != 0 || info.size <= 0) 742 { 743 /* nope -- no aliasing for this user */ 744 continue; 745 } 746 747 /* they exist -- build the actual address */ 748 p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 749 (void) strcpy(p, user); 750 (void) strcat(p, "@"); 751 (void) strcat(p, up->udb_default); 752 if (tTd(28, 1)) 753 printf("udbmatch ==> %s\n", p); 754 return p; 755 #endif 756 757 #ifdef HESIOD 758 case UDB_HESIOD: 759 /* get the default case for this database */ 760 if (up->udb_default == NULL) 761 { 762 key.data = ":default:mailname"; 763 key.size = strlen(key.data); 764 i = hes_udb_get(&key, &info); 765 766 if (i != 0 || info.size <= 0) 767 { 768 /* no default case */ 769 up->udb_default = ""; 770 continue; 771 } 772 773 /* save the default case */ 774 up->udb_default = xalloc(info.size + 1); 775 bcopy(info.data, up->udb_default, info.size); 776 up->udb_default[info.size] = '\0'; 777 } 778 else if (up->udb_default[0] == '\0') 779 continue; 780 781 /* we have a default case -- verify user:maildrop */ 782 key.data = keybuf; 783 key.size = keylen; 784 i = hes_udb_get(&key, &info); 785 if (i != 0 || info.size <= 0) 786 { 787 /* nope -- no aliasing for this user */ 788 continue; 789 } 790 791 /* they exist -- build the actual address */ 792 p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 793 (void) strcpy(p, user); 794 (void) strcat(p, "@"); 795 (void) strcat(p, up->udb_default); 796 if (tTd(28, 1)) 797 printf("udbmatch ==> %s\n", p); 798 return p; 799 break; 800 #endif /* HESIOD */ 801 } 802 } 803 804 /* still nothing.... too bad */ 805 return NULL; 806 } 807 /* 808 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 809 ** 810 ** Parameters: 811 ** map -- the map being queried. 812 ** name -- the name to look up. 813 ** av -- arguments to the map lookup. 814 ** statp -- to get any error status. 815 ** 816 ** Returns: 817 ** NULL if name not found in map. 818 ** The rewritten name otherwise. 819 */ 820 821 /* ARGSUSED3 */ 822 char * 823 udb_map_lookup(map, name, av, statp) 824 MAP *map; 825 char *name; 826 char **av; 827 int *statp; 828 { 829 char *val; 830 char *key; 831 char keybuf[MAXNAME + 1]; 832 833 if (tTd(28, 20) || tTd(38, 20)) 834 printf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 835 836 if (bitset(MF_NOFOLDCASE, map->map_mflags)) 837 { 838 key = name; 839 } 840 else 841 { 842 int keysize = strlen(name); 843 844 if (keysize > sizeof keybuf - 1) 845 keysize = sizeof keybuf - 1; 846 bcopy(name, keybuf, keysize); 847 keybuf[keysize] = '\0'; 848 makelower(keybuf); 849 key = keybuf; 850 } 851 val = udbmatch(key, map->map_file); 852 if (val == NULL) 853 return NULL; 854 if (bitset(MF_MATCHONLY, map->map_mflags)) 855 return map_rewrite(map, name, strlen(name), NULL); 856 else 857 return map_rewrite(map, val, strlen(val), av); 858 } 859 /* 860 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 861 ** 862 ** Parameters: 863 ** e -- the current envelope. 864 ** 865 ** Returns: 866 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 867 ** database due to a host being down or some similar 868 ** (recoverable) situation. 869 ** EX_OK -- otherwise. 870 ** 871 ** Side Effects: 872 ** Fills in the UdbEnts structure from UdbSpec. 873 */ 874 875 #define MAXUDBOPTS 27 876 877 int 878 _udbx_init(e) 879 ENVELOPE *e; 880 { 881 int ents = 0; 882 register char *p; 883 register struct udbent *up; 884 885 if (UdbInitialized) 886 return EX_OK; 887 888 # ifdef UDB_DEFAULT_SPEC 889 if (UdbSpec == NULL) 890 UdbSpec = UDB_DEFAULT_SPEC; 891 # endif 892 893 p = UdbSpec; 894 up = UdbEnts; 895 while (p != NULL) 896 { 897 char *spec; 898 int l; 899 # if 0 900 auto int rcode; 901 int nmx; 902 int i; 903 register struct hostent *h; 904 char *mxhosts[MAXMXHOSTS + 1]; 905 # endif 906 struct udb_option opts[MAXUDBOPTS + 1]; 907 extern int _udb_parsespec __P((char *, struct udb_option [], int)); 908 909 while (*p == ' ' || *p == '\t' || *p == ',') 910 p++; 911 if (*p == '\0') 912 break; 913 spec = p; 914 p = strchr(p, ','); 915 if (p != NULL) 916 *p++ = '\0'; 917 918 if (ents >= MAXUDBENT) 919 { 920 syserr("Maximum number of UDB entries exceeded"); 921 break; 922 } 923 924 /* extract options */ 925 (void) _udb_parsespec(spec, opts, MAXUDBOPTS); 926 927 /* 928 ** Decode database specification. 929 ** 930 ** In the sendmail tradition, the leading character 931 ** defines the semantics of the rest of the entry. 932 ** 933 ** +hostname -- send a datagram to the udb server 934 ** on host "hostname" asking for the 935 ** home mail server for this user. 936 ** *hostname -- similar to +hostname, except that the 937 ** hostname is searched as an MX record; 938 ** resulting hosts are searched as for 939 ** +mxhostname. If no MX host is found, 940 ** this is the same as +hostname. 941 ** @hostname -- forward email to the indicated host. 942 ** This should be the last in the list, 943 ** since it always matches the input. 944 ** /dbname -- search the named database on the local 945 ** host using the Berkeley db package. 946 ** Hesiod -- search the named database with BIND 947 ** using the MIT Hesiod package. 948 */ 949 950 switch (*spec) 951 { 952 #if 0 953 case '+': /* search remote database */ 954 case '*': /* search remote database (expand MX) */ 955 if (*spec == '*') 956 { 957 #if NAMED_BIND 958 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 959 #else 960 mxhosts[0] = spec + 1; 961 nmx = 1; 962 rcode = 0; 963 #endif 964 if (tTd(28, 16)) 965 { 966 int i; 967 968 printf("getmxrr(%s): %d", spec + 1, nmx); 969 for (i = 0; i <= nmx; i++) 970 printf(" %s", mxhosts[i]); 971 printf("\n"); 972 } 973 } 974 else 975 { 976 nmx = 1; 977 mxhosts[0] = spec + 1; 978 } 979 980 for (i = 0; i < nmx; i++) 981 { 982 h = sm_gethostbyname(mxhosts[i]); 983 if (h == NULL) 984 continue; 985 up->udb_type = UDB_REMOTE; 986 up->udb_pid = getpid(); 987 up->udb_addr.sin_family = h->h_addrtype; 988 bcopy(h->h_addr_list[0], 989 (char *) &up->udb_addr.sin_addr, 990 INADDRSZ); 991 up->udb_addr.sin_port = UdbPort; 992 up->udb_timeout = UdbTimeout; 993 ents++; 994 up++; 995 } 996 997 /* set up a datagram socket */ 998 if (UdbSock < 0) 999 { 1000 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 1001 (void) fcntl(UdbSock, F_SETFD, 1); 1002 } 1003 break; 1004 #endif 1005 1006 case '@': /* forward to remote host */ 1007 up->udb_type = UDB_FORWARD; 1008 up->udb_pid = getpid(); 1009 up->udb_fwdhost = spec + 1; 1010 ents++; 1011 up++; 1012 break; 1013 1014 #ifdef HESIOD 1015 case 'h': /* use hesiod */ 1016 case 'H': 1017 if (strcasecmp(spec, "hesiod") != 0) 1018 goto badspec; 1019 up->udb_type = UDB_HESIOD; 1020 up->udb_pid = getpid(); 1021 ents++; 1022 up++; 1023 break; 1024 #endif /* HESIOD */ 1025 1026 #ifdef NEWDB 1027 case '/': /* look up remote name */ 1028 l = strlen(spec); 1029 if (l > 3 && strcmp(&spec[l - 3], ".db") == 0) 1030 { 1031 up->udb_dbname = spec; 1032 } 1033 else 1034 { 1035 up->udb_dbname = xalloc(l + 4); 1036 strcpy(up->udb_dbname, spec); 1037 strcat(up->udb_dbname, ".db"); 1038 } 1039 errno = 0; 1040 #if DB_VERSION_MAJOR < 2 1041 up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, 1042 0644, DB_BTREE, NULL); 1043 #else 1044 up->udb_dbp = NULL; 1045 errno = db_open(up->udb_dbname, DB_BTREE, DB_RDONLY, 1046 0644, NULL, NULL, &up->udb_dbp); 1047 #endif 1048 if (up->udb_dbp == NULL) 1049 { 1050 if (tTd(28, 1)) 1051 { 1052 int saveerrno = errno; 1053 1054 #if DB_VERSION_MAJOR < 2 1055 printf("dbopen(%s): %s\n", 1056 #else 1057 printf("db_open(%s): %s\n", 1058 #endif 1059 up->udb_dbname, 1060 errstring(errno)); 1061 errno = saveerrno; 1062 } 1063 if (errno != ENOENT && errno != EACCES) 1064 { 1065 if (LogLevel > 2) 1066 sm_syslog(LOG_ERR, e->e_id, 1067 #if DB_VERSION_MAJOR < 2 1068 "dbopen(%s): %s", 1069 #else 1070 "db_open(%s): %s", 1071 #endif 1072 up->udb_dbname, 1073 errstring(errno)); 1074 up->udb_type = UDB_EOLIST; 1075 if (up->udb_dbname != spec) 1076 free(up->udb_dbname); 1077 goto tempfail; 1078 } 1079 if (up->udb_dbname != spec) 1080 free(up->udb_dbname); 1081 break; 1082 } 1083 if (tTd(28, 1)) 1084 { 1085 #if DB_VERSION_MAJOR < 2 1086 printf("_udbx_init: dbopen(%s)\n", 1087 #else 1088 printf("_udbx_init: db_open(%s)\n", 1089 #endif 1090 up->udb_dbname); 1091 } 1092 up->udb_type = UDB_DBFETCH; 1093 up->udb_pid = getpid(); 1094 ents++; 1095 up++; 1096 break; 1097 #endif 1098 1099 default: 1100 badspec: 1101 syserr("Unknown UDB spec %s", spec); 1102 break; 1103 } 1104 } 1105 up->udb_type = UDB_EOLIST; 1106 1107 if (tTd(28, 4)) 1108 { 1109 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1110 { 1111 switch (up->udb_type) 1112 { 1113 #if DAEMON 1114 case UDB_REMOTE: 1115 printf("REMOTE: addr %s, timeo %d\n", 1116 anynet_ntoa((SOCKADDR *) &up->udb_addr), 1117 up->udb_timeout); 1118 break; 1119 #endif 1120 1121 case UDB_DBFETCH: 1122 #ifdef NEWDB 1123 printf("FETCH: file %s\n", 1124 up->udb_dbname); 1125 #else 1126 printf("FETCH\n"); 1127 #endif 1128 break; 1129 1130 case UDB_FORWARD: 1131 printf("FORWARD: host %s\n", 1132 up->udb_fwdhost); 1133 break; 1134 1135 case UDB_HESIOD: 1136 printf("HESIOD\n"); 1137 break; 1138 1139 default: 1140 printf("UNKNOWN\n"); 1141 break; 1142 } 1143 } 1144 } 1145 1146 UdbInitialized = TRUE; 1147 errno = 0; 1148 return EX_OK; 1149 1150 /* 1151 ** On temporary failure, back out anything we've already done 1152 */ 1153 1154 tempfail: 1155 #ifdef NEWDB 1156 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1157 { 1158 if (up->udb_type == UDB_DBFETCH) 1159 { 1160 #if DB_VERSION_MAJOR < 2 1161 (*up->udb_dbp->close)(up->udb_dbp); 1162 #else 1163 errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 1164 #endif 1165 if (tTd(28, 1)) 1166 { 1167 printf("_udbx_init: db->close(%s)\n", 1168 up->udb_dbname); 1169 } 1170 } 1171 } 1172 #endif 1173 return EX_TEMPFAIL; 1174 } 1175 1176 int 1177 _udb_parsespec(udbspec, opt, maxopts) 1178 char *udbspec; 1179 struct udb_option opt[]; 1180 int maxopts; 1181 { 1182 register char *spec; 1183 register char *spec_end; 1184 register int optnum; 1185 1186 spec_end = strchr(udbspec, ':'); 1187 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 1188 { 1189 register char *p; 1190 1191 while (isascii(*spec) && isspace(*spec)) 1192 spec++; 1193 spec_end = strchr(spec, ':'); 1194 if (spec_end != NULL) 1195 *spec_end++ = '\0'; 1196 1197 opt[optnum].name = spec; 1198 opt[optnum].val = NULL; 1199 p = strchr(spec, '='); 1200 if (p != NULL) 1201 opt[optnum].val = ++p; 1202 } 1203 return optnum; 1204 } 1205 /* 1206 ** _UDBX_CLOSE -- close all file based UDB entries. 1207 ** 1208 ** Parameters: 1209 ** none 1210 ** 1211 ** Returns: 1212 ** none 1213 */ 1214 void 1215 _udbx_close() 1216 { 1217 pid_t pid; 1218 struct udbent *up; 1219 1220 if (!UdbInitialized) 1221 return; 1222 1223 pid = getpid(); 1224 1225 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1226 { 1227 if (up->udb_pid != pid) 1228 continue; 1229 1230 #ifdef NEWDB 1231 if (up->udb_type == UDB_DBFETCH) 1232 { 1233 #if DB_VERSION_MAJOR < 2 1234 (*up->udb_dbp->close)(up->udb_dbp); 1235 #else 1236 errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 1237 #endif 1238 } 1239 if (tTd(28, 1)) 1240 { 1241 printf("_udbx_init: db->close(%s)\n", 1242 up->udb_dbname); 1243 } 1244 #endif 1245 } 1246 } 1247 1248 #ifdef HESIOD 1249 1250 int 1251 hes_udb_get(key, info) 1252 DBT *key; 1253 DBT *info; 1254 { 1255 char *name, *type; 1256 char **hp; 1257 char kbuf[MAXKEY + 1]; 1258 1259 if (strlen(key->data) >= (SIZE_T) sizeof kbuf) 1260 return 0; 1261 strcpy(kbuf, key->data); 1262 name = kbuf; 1263 type = strrchr(name, ':'); 1264 if (type == NULL) 1265 return 1; 1266 *type++ = '\0'; 1267 if (strchr(name, '@') != NULL) 1268 return 1; 1269 1270 if (tTd(28, 1)) 1271 printf("hes_udb_get(%s, %s)\n", name, type); 1272 1273 /* make the hesiod query */ 1274 #ifdef HESIOD_INIT 1275 if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0) 1276 return -1; 1277 hp = hesiod_resolve(HesiodContext, name, type); 1278 #else 1279 hp = hes_resolve(name, type); 1280 #endif /* HESIOD_INIT */ 1281 *--type = ':'; 1282 #ifdef HESIOD_INIT 1283 if (hp == NULL) 1284 return 1; 1285 if (*hp == NULL) 1286 { 1287 hesiod_free_list(HesiodContext, hp); 1288 if (errno == ECONNREFUSED || errno == EMSGSIZE) 1289 return -1; 1290 return 1; 1291 } 1292 #else 1293 if (hp == NULL || hp[0] == NULL) 1294 { 1295 /* network problem or timeout */ 1296 if (hes_error() == HES_ER_NET) 1297 return -1; 1298 1299 return 1; 1300 } 1301 #endif /* HESIOD_INIT */ 1302 else 1303 { 1304 /* 1305 ** If there are multiple matches, just return the 1306 ** first one. 1307 ** 1308 ** XXX These should really be returned; for example, 1309 ** XXX it is legal for :maildrop to be multi-valued. 1310 */ 1311 1312 info->data = hp[0]; 1313 info->size = (size_t) strlen(info->data); 1314 } 1315 1316 if (tTd(28, 80)) 1317 printf("hes_udb_get => %s\n", *hp); 1318 1319 return 0; 1320 } 1321 #endif /* HESIOD */ 1322 1323 #else /* not USERDB */ 1324 1325 int 1326 udbexpand(a, sendq, aliaslevel, e) 1327 ADDRESS *a; 1328 ADDRESS **sendq; 1329 int aliaslevel; 1330 ENVELOPE *e; 1331 { 1332 return EX_OK; 1333 } 1334 1335 #endif /* USERDB */ 1336