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