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