1 /* 2 * Copyright (c) 1998-2003, 2006 Proofpoint, 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 #include "map.h" 16 17 #if USERDB 18 SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)") 19 #else 20 SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)") 21 #endif 22 23 #if USERDB 24 25 #include <sm/sendmail.h> 26 # if NEWDB 27 # include "sm/bdb.h" 28 # else /* NEWDB */ 29 # define DBT struct _data_base_thang_ 30 DBT 31 { 32 void *data; /* pointer to data */ 33 size_t size; /* length of data */ 34 }; 35 # endif /* NEWDB */ 36 37 /* 38 ** UDB.C -- interface between sendmail and Berkeley User Data Base. 39 ** 40 ** This depends on the 4.4BSD db package. 41 */ 42 43 44 struct udbent 45 { 46 char *udb_spec; /* string version of spec */ 47 int udb_type; /* type of entry */ 48 pid_t udb_pid; /* PID of process which opened db */ 49 char *udb_default; /* default host for outgoing mail */ 50 union 51 { 52 # if NETINET || NETINET6 53 /* type UE_REMOTE -- do remote call for lookup */ 54 struct 55 { 56 SOCKADDR _udb_addr; /* address */ 57 int _udb_timeout; /* timeout */ 58 } udb_remote; 59 # define udb_addr udb_u.udb_remote._udb_addr 60 # define udb_timeout udb_u.udb_remote._udb_timeout 61 # endif /* NETINET || NETINET6 */ 62 63 /* type UE_FORWARD -- forward message to remote */ 64 struct 65 { 66 char *_udb_fwdhost; /* name of forward host */ 67 } udb_forward; 68 # define udb_fwdhost udb_u.udb_forward._udb_fwdhost 69 70 # if NEWDB 71 /* type UE_FETCH -- lookup in local database */ 72 struct 73 { 74 char *_udb_dbname; /* pathname of database */ 75 DB *_udb_dbp; /* open database ptr */ 76 } udb_lookup; 77 # define udb_dbname udb_u.udb_lookup._udb_dbname 78 # define udb_dbp udb_u.udb_lookup._udb_dbp 79 # endif /* NEWDB */ 80 } udb_u; 81 }; 82 83 # define UDB_EOLIST 0 /* end of list */ 84 # define UDB_SKIP 1 /* skip this entry */ 85 # define UDB_REMOTE 2 /* look up in remote database */ 86 # define UDB_DBFETCH 3 /* look up in local database */ 87 # define UDB_FORWARD 4 /* forward to remote host */ 88 # define UDB_HESIOD 5 /* look up via hesiod */ 89 90 # define MAXUDBENT 10 /* maximum number of UDB entries */ 91 92 93 struct udb_option 94 { 95 char *udbo_name; 96 char *udbo_val; 97 }; 98 99 # if HESIOD 100 static int hes_udb_get __P((DBT *, DBT *)); 101 # endif 102 static char *udbmatch __P((char *, char *, SM_RPOOL_T *)); 103 static int _udbx_init __P((ENVELOPE *)); 104 static int _udb_parsespec __P((char *, struct udb_option [], int)); 105 106 /* 107 ** UDBEXPAND -- look up user in database and expand 108 ** 109 ** Parameters: 110 ** a -- address to expand. 111 ** sendq -- pointer to head of sendq to put the expansions in. 112 ** aliaslevel -- the current alias nesting depth. 113 ** e -- the current envelope. 114 ** 115 ** Returns: 116 ** EX_TEMPFAIL -- if something "odd" happened -- probably due 117 ** to accessing a file on an NFS server that is down. 118 ** EX_OK -- otherwise. 119 ** 120 ** Side Effects: 121 ** Modifies sendq. 122 */ 123 124 static struct udbent UdbEnts[MAXUDBENT + 1]; 125 static bool UdbInitialized = false; 126 127 int 128 udbexpand(a, sendq, aliaslevel, e) 129 register ADDRESS *a; 130 ADDRESS **sendq; 131 int aliaslevel; 132 register ENVELOPE *e; 133 { 134 int i; 135 DBT key; 136 DBT info; 137 bool breakout; 138 register struct udbent *up; 139 int keylen; 140 int naddrs; 141 char *user; 142 char keybuf[MAXUDBKEY]; 143 144 memset(&key, '\0', sizeof(key)); 145 memset(&info, '\0', sizeof(info)); 146 147 if (tTd(28, 1)) 148 sm_dprintf("udbexpand(%s)\n", a->q_paddr); 149 150 /* make certain we are supposed to send to this address */ 151 if (!QS_IS_SENDABLE(a->q_state)) 152 return EX_OK; 153 e->e_to = a->q_paddr; 154 155 /* on first call, locate the database */ 156 if (!UdbInitialized) 157 { 158 if (_udbx_init(e) == EX_TEMPFAIL) 159 return EX_TEMPFAIL; 160 } 161 162 /* short circuit the process if no chance of a match */ 163 if (SM_IS_EMPTY(UdbSpec)) 164 return EX_OK; 165 166 /* extract user to do userdb matching on */ 167 user = a->q_user; 168 169 /* short circuit name begins with '\\' since it can't possibly match */ 170 /* (might want to treat this as unquoted instead) */ 171 if (user[0] == '\\') 172 return EX_OK; 173 174 /* if name begins with a colon, it indicates our metadata */ 175 if (user[0] == ':') 176 return EX_OK; 177 178 keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop"); 179 180 /* if name is too long, assume it won't match */ 181 if (keylen >= sizeof(keybuf)) 182 return EX_OK; 183 184 /* build actual database key */ 185 186 breakout = false; 187 for (up = UdbEnts; !breakout; up++) 188 { 189 int usersize; 190 # if NEWDB 191 int userleft; 192 # endif 193 char userbuf[MEMCHUNKSIZE]; 194 # if HESIOD && HES_GETMAILHOST 195 char pobuf[MAXNAME]; /* EAI:should be ok, no UTF8? */ 196 # endif 197 # if defined(NEWDB) && DB_VERSION_MAJOR > 1 198 DBC *dbc = NULL; 199 # endif 200 201 user = userbuf; 202 userbuf[0] = '\0'; 203 usersize = sizeof(userbuf); 204 # if NEWDB 205 userleft = sizeof(userbuf) - 1; 206 # endif 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 # if NEWDB 219 case UDB_DBFETCH: 220 key.data = keybuf; 221 key.size = keylen; 222 if (tTd(28, 80)) 223 sm_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 sm_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 sm_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 = sm_malloc_x(usersize + size); 290 291 memmove(nuser, user, usersize); 292 if (user != userbuf) 293 sm_free(user); /* XXX */ 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 sm_dprintf("udbexpand: QS_EXPANDED "); 343 printaddr(sm_debug_file(), 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) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user, 362 ":mailsender"); 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 370 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 371 &key, &info, 0); 372 # endif 373 if (i != 0 || info.size <= 0) 374 break; 375 a->q_owner = sm_rpool_malloc_x(e->e_rpool, 376 info.size + 1); 377 memmove(a->q_owner, info.data, 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 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 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 /* NEWDB */ 391 392 # if HESIOD 393 case UDB_HESIOD: 394 key.data = keybuf; 395 key.size = keylen; 396 if (tTd(28, 80)) 397 sm_dprintf("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 sm_dprintf("udbexpand: no match on %s (%d)\n", 415 (char *) keybuf, (int) keylen); 416 # if HES_GETMAILHOST 417 if (tTd(28, 8)) 418 sm_dprintf(" ... 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 sm_dprintf("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 sm_dprintf("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 (void) sm_snprintf(pobuf, sizeof(pobuf), 446 "%s@%s", hp->po_name, hp->po_host); 447 info.size = strlen(info.data); 448 # else /* HES_GETMAILHOST */ 449 break; 450 # endif /* HES_GETMAILHOST */ 451 } 452 if (tTd(28, 80)) 453 sm_dprintf("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_state = QS_VERIFIED; 461 return EX_OK; 462 } 463 464 breakout = true; 465 if (info.size >= usersize) 466 user = sm_malloc_x(info.size + 1); 467 memmove(user, info.data, 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 sm_dprintf("udbexpand: QS_EXPANDED "); 483 printaddr(sm_debug_file(), a, false); 484 } 485 a->q_state = QS_EXPANDED; 486 } 487 488 /* 489 ** If this address has a -request address, reflect 490 ** it into the envelope. 491 */ 492 493 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user, 494 ":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 = sm_rpool_malloc_x(e->e_rpool, 502 info.size + 1); 503 memmove(a->q_owner, info.data, info.size); 504 a->q_owner[info.size] = '\0'; 505 break; 506 # endif /* HESIOD */ 507 508 case UDB_REMOTE: 509 /* not yet implemented */ 510 break; 511 512 case UDB_FORWARD: 513 if (bitset(EF_VRFYONLY, e->e_flags)) 514 { 515 a->q_state = QS_VERIFIED; 516 return EX_OK; 517 } 518 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 519 if (i >= usersize) 520 { 521 usersize = i + 1; 522 user = sm_malloc_x(usersize); 523 } 524 (void) sm_strlcpyn(user, usersize, 3, 525 a->q_user, "@", up->udb_fwdhost); 526 message("expanded to %s", user); 527 a->q_flags &= ~QSELFREF; 528 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 529 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 530 { 531 if (tTd(28, 5)) 532 { 533 sm_dprintf("udbexpand: QS_EXPANDED "); 534 printaddr(sm_debug_file(), a, false); 535 } 536 a->q_state = QS_EXPANDED; 537 } 538 breakout = true; 539 break; 540 541 case UDB_EOLIST: 542 breakout = true; 543 break; 544 545 default: 546 /* unknown entry type */ 547 break; 548 } 549 /* XXX if an exception occurs, there is a storage leak */ 550 if (user != userbuf) 551 sm_free(user); /* XXX */ 552 } 553 return EX_OK; 554 } 555 /* 556 ** UDBSENDER -- return canonical external name of sender, given local name 557 ** 558 ** Parameters: 559 ** sender -- the name of the sender on the local machine. 560 ** rpool -- resource pool from which to allocate result 561 ** 562 ** Returns: 563 ** The external name for this sender, if derivable from the 564 ** database. Storage allocated from rpool. 565 ** NULL -- if nothing is changed from the database. 566 ** 567 ** Side Effects: 568 ** none. 569 */ 570 571 char * 572 udbsender(sender, rpool) 573 char *sender; 574 SM_RPOOL_T *rpool; 575 { 576 return udbmatch(sender, "mailname", rpool); 577 } 578 /* 579 ** UDBMATCH -- match user in field, return result of lookup. 580 ** 581 ** Parameters: 582 ** user -- the name of the user. 583 ** field -- the field to lookup. 584 ** rpool -- resource pool from which to allocate result 585 ** 586 ** Returns: 587 ** The external name for this sender, if derivable from the 588 ** database. Storage allocated from rpool. 589 ** NULL -- if nothing is changed from the database. 590 ** 591 ** Side Effects: 592 ** none. 593 */ 594 595 static char * 596 udbmatch(user, field, rpool) 597 char *user; 598 char *field; 599 SM_RPOOL_T *rpool; 600 { 601 register char *p; 602 register struct udbent *up; 603 int i; 604 int keylen; 605 DBT key, info; 606 char keybuf[MAXUDBKEY]; 607 608 if (tTd(28, 1)) 609 sm_dprintf("udbmatch(%s, %s)\n", user, field); 610 611 if (!UdbInitialized) 612 { 613 if (_udbx_init(CurEnv) == EX_TEMPFAIL) 614 return NULL; 615 } 616 617 /* short circuit if no spec */ 618 if (SM_IS_EMPTY(UdbSpec)) 619 return NULL; 620 621 /* short circuit name begins with '\\' since it can't possibly match */ 622 if (user[0] == '\\') 623 return NULL; 624 625 /* long names can never match and are a pain to deal with */ 626 i = strlen(field); 627 if (i < sizeof("maildrop")) 628 i = sizeof("maildrop"); 629 if ((strlen(user) + i) > sizeof(keybuf) - 4) 630 return NULL; 631 632 /* names beginning with colons indicate metadata */ 633 if (user[0] == ':') 634 return NULL; 635 636 /* build database key */ 637 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field); 638 keylen = strlen(keybuf); 639 640 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 641 { 642 /* 643 ** Select action based on entry type. 644 */ 645 646 switch (up->udb_type) 647 { 648 # if NEWDB 649 case UDB_DBFETCH: 650 memset(&key, '\0', sizeof(key)); 651 memset(&info, '\0', sizeof(info)); 652 key.data = keybuf; 653 key.size = keylen; 654 # if DB_VERSION_MAJOR < 2 655 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 656 # else 657 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 658 &key, &info, 0); 659 # endif 660 if (i != 0 || info.size <= 0) 661 { 662 if (tTd(28, 2)) 663 sm_dprintf("udbmatch: no match on %s (%d) via db\n", 664 keybuf, keylen); 665 continue; 666 } 667 668 p = sm_rpool_malloc_x(rpool, info.size + 1); 669 memmove(p, info.data, info.size); 670 p[info.size] = '\0'; 671 if (tTd(28, 1)) 672 sm_dprintf("udbmatch ==> %s\n", p); 673 return p; 674 # endif /* NEWDB */ 675 676 # if HESIOD 677 case UDB_HESIOD: 678 key.data = keybuf; 679 key.size = keylen; 680 i = hes_udb_get(&key, &info); 681 if (i != 0 || info.size <= 0) 682 { 683 if (tTd(28, 2)) 684 sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n", 685 keybuf, keylen); 686 continue; 687 } 688 689 p = sm_rpool_malloc_x(rpool, info.size + 1); 690 memmove(p, info.data, info.size); 691 p[info.size] = '\0'; 692 if (tTd(28, 1)) 693 sm_dprintf("udbmatch ==> %s\n", p); 694 return p; 695 # endif /* HESIOD */ 696 } 697 } 698 699 if (strcmp(field, "mailname") != 0) 700 return NULL; 701 702 /* 703 ** Nothing yet. Search again for a default case. But only 704 ** use it if we also have a forward (:maildrop) pointer already 705 ** in the database. 706 */ 707 708 /* build database key */ 709 (void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop"); 710 keylen = strlen(keybuf); 711 712 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 713 { 714 switch (up->udb_type) 715 { 716 # if NEWDB 717 case UDB_DBFETCH: 718 /* get the default case for this database */ 719 if (up->udb_default == NULL) 720 { 721 memset(&key, '\0', sizeof(key)); 722 memset(&info, '\0', sizeof(info)); 723 key.data = ":default:mailname"; 724 key.size = strlen(key.data); 725 # if DB_VERSION_MAJOR < 2 726 i = (*up->udb_dbp->get)(up->udb_dbp, 727 &key, &info, 0); 728 # else /* DB_VERSION_MAJOR < 2 */ 729 i = errno = (*up->udb_dbp->get)(up->udb_dbp, 730 NULL, &key, 731 &info, 0); 732 # endif /* DB_VERSION_MAJOR < 2 */ 733 if (i != 0 || info.size <= 0) 734 { 735 /* no default case */ 736 up->udb_default = ""; 737 continue; 738 } 739 740 /* save the default case */ 741 up->udb_default = sm_pmalloc_x(info.size + 1); 742 memmove(up->udb_default, info.data, info.size); 743 up->udb_default[info.size] = '\0'; 744 } 745 else if (up->udb_default[0] == '\0') 746 continue; 747 748 /* we have a default case -- verify user:maildrop */ 749 memset(&key, '\0', sizeof(key)); 750 memset(&info, '\0', sizeof(info)); 751 key.data = keybuf; 752 key.size = keylen; 753 # if DB_VERSION_MAJOR < 2 754 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 755 # else 756 i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, 757 &key, &info, 0); 758 # endif 759 if (i != 0 || info.size <= 0) 760 { 761 /* nope -- no aliasing for this user */ 762 continue; 763 } 764 765 /* they exist -- build the actual address */ 766 i = strlen(user) + strlen(up->udb_default) + 2; 767 p = sm_rpool_malloc_x(rpool, i); 768 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default); 769 if (tTd(28, 1)) 770 sm_dprintf("udbmatch ==> %s\n", p); 771 return p; 772 # endif /* NEWDB */ 773 774 # if HESIOD 775 case UDB_HESIOD: 776 /* get the default case for this database */ 777 if (up->udb_default == NULL) 778 { 779 key.data = ":default:mailname"; 780 key.size = strlen(key.data); 781 i = hes_udb_get(&key, &info); 782 783 if (i != 0 || info.size <= 0) 784 { 785 /* no default case */ 786 up->udb_default = ""; 787 continue; 788 } 789 790 /* save the default case */ 791 up->udb_default = sm_pmalloc_x(info.size + 1); 792 memmove(up->udb_default, info.data, info.size); 793 up->udb_default[info.size] = '\0'; 794 } 795 else if (up->udb_default[0] == '\0') 796 continue; 797 798 /* we have a default case -- verify user:maildrop */ 799 key.data = keybuf; 800 key.size = keylen; 801 i = hes_udb_get(&key, &info); 802 if (i != 0 || info.size <= 0) 803 { 804 /* nope -- no aliasing for this user */ 805 continue; 806 } 807 808 /* they exist -- build the actual address */ 809 i = strlen(user) + strlen(up->udb_default) + 2; 810 p = sm_rpool_malloc_x(rpool, i); 811 (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default); 812 if (tTd(28, 1)) 813 sm_dprintf("udbmatch ==> %s\n", p); 814 return p; 815 break; 816 # endif /* HESIOD */ 817 } 818 } 819 820 /* still nothing.... too bad */ 821 return NULL; 822 } 823 /* 824 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 825 ** 826 ** Parameters: 827 ** map -- the map being queried. 828 ** name -- the name to look up. 829 ** av -- arguments to the map lookup. 830 ** statp -- to get any error status. 831 ** 832 ** Returns: 833 ** NULL if name not found in map. 834 ** The rewritten name otherwise. 835 */ 836 837 /* ARGSUSED3 */ 838 char * 839 udb_map_lookup(map, name, av, statp) 840 MAP *map; 841 char *name; 842 char **av; 843 int *statp; 844 { 845 char *val; 846 char *key; 847 char *SM_NONVOLATILE result = NULL; 848 char keybuf[MAXNAME + 1]; /* EAI:ok */ 849 850 if (tTd(28, 20) || tTd(38, 20)) 851 sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 852 853 if (bitset(MF_NOFOLDCASE, map->map_mflags)) 854 key = name; 855 else 856 { 857 int keysize = strlen(name); 858 859 if (keysize > sizeof(keybuf) - 1) 860 keysize = sizeof(keybuf) - 1; 861 memmove(keybuf, name, keysize); 862 keybuf[keysize] = '\0'; 863 makelower_buf(keybuf, keybuf, sizeof(keybuf)); 864 key = keybuf; 865 } 866 val = udbmatch(key, map->map_file, NULL); 867 if (val == NULL) 868 return NULL; 869 SM_TRY 870 if (bitset(MF_MATCHONLY, map->map_mflags)) 871 result = map_rewrite(map, name, strlen(name), NULL); 872 else 873 result = map_rewrite(map, val, strlen(val), av); 874 SM_FINALLY 875 sm_free(val); 876 SM_END_TRY 877 if (key != name && key != keybuf) 878 SM_FREE(key); 879 return result; 880 } 881 /* 882 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 883 ** 884 ** Parameters: 885 ** e -- the current envelope. 886 ** 887 ** Returns: 888 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 889 ** database due to a host being down or some similar 890 ** (recoverable) situation. 891 ** EX_OK -- otherwise. 892 ** 893 ** Side Effects: 894 ** Fills in the UdbEnts structure from UdbSpec. 895 */ 896 897 # define MAXUDBOPTS 27 898 899 static int 900 _udbx_init(e) 901 ENVELOPE *e; 902 { 903 int ents = 0; 904 register char *p; 905 register struct udbent *up; 906 907 if (UdbInitialized) 908 return EX_OK; 909 910 # ifdef UDB_DEFAULT_SPEC 911 if (UdbSpec == NULL) 912 UdbSpec = UDB_DEFAULT_SPEC; 913 # endif 914 915 p = UdbSpec; 916 up = UdbEnts; 917 while (p != NULL) 918 { 919 char *spec; 920 # if NEWDB 921 int l; 922 # endif 923 struct udb_option opts[MAXUDBOPTS + 1]; 924 925 while (*p == ' ' || *p == '\t' || *p == ',') 926 p++; 927 if (*p == '\0') 928 break; 929 spec = p; 930 p = strchr(p, ','); 931 if (p != NULL) 932 *p++ = '\0'; 933 934 if (ents >= MAXUDBENT) 935 { 936 syserr("Maximum number of UDB entries exceeded"); 937 break; 938 } 939 940 /* extract options */ 941 (void) _udb_parsespec(spec, opts, MAXUDBOPTS); 942 943 /* 944 ** Decode database specification. 945 ** 946 ** In the sendmail tradition, the leading character 947 ** defines the semantics of the rest of the entry. 948 ** 949 ** @hostname -- forward email to the indicated host. 950 ** This should be the last in the list, 951 ** since it always matches the input. 952 ** /dbname -- search the named database on the local 953 ** host using the Berkeley db package. 954 ** Hesiod -- search the named database with BIND 955 ** using the MIT Hesiod package. 956 */ 957 958 switch (*spec) 959 { 960 case '@': /* forward to remote host */ 961 up->udb_type = UDB_FORWARD; 962 up->udb_pid = CurrentPid; 963 up->udb_fwdhost = spec + 1; 964 ents++; 965 up++; 966 break; 967 968 # if HESIOD 969 case 'h': /* use hesiod */ 970 case 'H': 971 if (!SM_STRCASEEQ(spec, "hesiod")) 972 goto badspec; 973 up->udb_type = UDB_HESIOD; 974 up->udb_pid = CurrentPid; 975 ents++; 976 up++; 977 break; 978 # endif /* HESIOD */ 979 980 # if NEWDB 981 case '/': /* look up remote name */ 982 l = strlen(spec); 983 if (l > 3 && strcmp(&spec[l - 3], ".db") == 0) 984 { 985 up->udb_dbname = spec; 986 } 987 else 988 { 989 up->udb_dbname = sm_pmalloc_x(l + 4); 990 (void) sm_strlcpyn(up->udb_dbname, l + 4, 2, 991 spec, ".db"); 992 } 993 errno = 0; 994 # if DB_VERSION_MAJOR < 2 995 up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, 996 0644, DB_BTREE, NULL); 997 # else /* DB_VERSION_MAJOR < 2 */ 998 { 999 int flags = DB_RDONLY; 1000 # if DB_VERSION_MAJOR > 2 1001 int ret; 1002 # endif /* DB_VERSION_MAJOR > 2 */ 1003 1004 SM_DB_FLAG_ADD(flags); 1005 up->udb_dbp = NULL; 1006 # if DB_VERSION_MAJOR > 2 1007 ret = db_create(&up->udb_dbp, NULL, 0); 1008 if (ret != 0) 1009 { 1010 (void) up->udb_dbp->close(up->udb_dbp, 1011 0); 1012 up->udb_dbp = NULL; 1013 } 1014 else 1015 { 1016 ret = up->udb_dbp->open(up->udb_dbp, 1017 DBTXN 1018 up->udb_dbname, 1019 NULL, 1020 DB_BTREE, 1021 flags, 1022 0644); 1023 if (ret != 0) 1024 { 1025 # ifdef DB_OLD_VERSION 1026 if (ret == DB_OLD_VERSION) 1027 ret = EINVAL; 1028 # endif 1029 (void) up->udb_dbp->close(up->udb_dbp, 0); 1030 up->udb_dbp = NULL; 1031 } 1032 } 1033 errno = ret; 1034 # else /* DB_VERSION_MAJOR > 2 */ 1035 errno = db_open(up->udb_dbname, DB_BTREE, 1036 flags, 0644, NULL, 1037 NULL, &up->udb_dbp); 1038 # endif /* DB_VERSION_MAJOR > 2 */ 1039 } 1040 # endif /* DB_VERSION_MAJOR < 2 */ 1041 if (up->udb_dbp == NULL) 1042 { 1043 if (tTd(28, 1)) 1044 { 1045 int save_errno = errno; 1046 1047 # if DB_VERSION_MAJOR < 2 1048 sm_dprintf("dbopen(%s): %s\n", 1049 # else /* DB_VERSION_MAJOR < 2 */ 1050 sm_dprintf("db_open(%s): %s\n", 1051 # endif /* DB_VERSION_MAJOR < 2 */ 1052 up->udb_dbname, 1053 sm_errstring(errno)); 1054 errno = save_errno; 1055 } 1056 if (errno != ENOENT && errno != EACCES) 1057 { 1058 if (LogLevel > 2) 1059 sm_syslog(LOG_ERR, e->e_id, 1060 # if DB_VERSION_MAJOR < 2 1061 "dbopen(%s): %s", 1062 # else /* DB_VERSION_MAJOR < 2 */ 1063 "db_open(%s): %s", 1064 # endif /* DB_VERSION_MAJOR < 2 */ 1065 up->udb_dbname, 1066 sm_errstring(errno)); 1067 up->udb_type = UDB_EOLIST; 1068 if (up->udb_dbname != spec) 1069 sm_free(up->udb_dbname); /* XXX */ 1070 goto tempfail; 1071 } 1072 if (up->udb_dbname != spec) 1073 sm_free(up->udb_dbname); /* XXX */ 1074 break; 1075 } 1076 if (tTd(28, 1)) 1077 { 1078 # if DB_VERSION_MAJOR < 2 1079 sm_dprintf("_udbx_init: dbopen(%s)\n", 1080 # else /* DB_VERSION_MAJOR < 2 */ 1081 sm_dprintf("_udbx_init: db_open(%s)\n", 1082 # endif /* DB_VERSION_MAJOR < 2 */ 1083 up->udb_dbname); 1084 } 1085 up->udb_type = UDB_DBFETCH; 1086 up->udb_pid = CurrentPid; 1087 ents++; 1088 up++; 1089 break; 1090 # endif /* NEWDB */ 1091 1092 default: 1093 # if HESIOD 1094 badspec: 1095 # endif 1096 syserr("Unknown UDB spec %s", spec); 1097 break; 1098 } 1099 } 1100 up->udb_type = UDB_EOLIST; 1101 1102 if (tTd(28, 4)) 1103 { 1104 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1105 { 1106 switch (up->udb_type) 1107 { 1108 case UDB_REMOTE: 1109 sm_dprintf("REMOTE: addr %s, timeo %d\n", 1110 anynet_ntoa((SOCKADDR *) &up->udb_addr), 1111 up->udb_timeout); 1112 break; 1113 1114 case UDB_DBFETCH: 1115 # if NEWDB 1116 sm_dprintf("FETCH: file %s\n", up->udb_dbname); 1117 # else 1118 sm_dprintf("FETCH\n"); 1119 # endif 1120 break; 1121 1122 case UDB_FORWARD: 1123 sm_dprintf("FORWARD: host %s\n", 1124 up->udb_fwdhost); 1125 break; 1126 1127 case UDB_HESIOD: 1128 sm_dprintf("HESIOD\n"); 1129 break; 1130 1131 default: 1132 sm_dprintf("UNKNOWN\n"); 1133 break; 1134 } 1135 } 1136 } 1137 1138 UdbInitialized = true; 1139 errno = 0; 1140 return EX_OK; 1141 1142 /* 1143 ** On temporary failure, back out anything we've already done 1144 */ 1145 1146 # if NEWDB 1147 tempfail: 1148 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1149 { 1150 if (up->udb_type == UDB_DBFETCH) 1151 { 1152 # if DB_VERSION_MAJOR < 2 1153 (*up->udb_dbp->close)(up->udb_dbp); 1154 # else 1155 errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 1156 # endif 1157 if (tTd(28, 1)) 1158 sm_dprintf("_udbx_init: db->close(%s)\n", 1159 up->udb_dbname); 1160 } 1161 } 1162 # endif /* NEWDB */ 1163 return EX_TEMPFAIL; 1164 } 1165 1166 static int 1167 _udb_parsespec(udbspec, opt, maxopts) 1168 char *udbspec; 1169 struct udb_option opt[]; 1170 int maxopts; 1171 { 1172 register char *spec; 1173 register char *spec_end; 1174 register int optnum; 1175 1176 spec_end = strchr(udbspec, ':'); 1177 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 1178 { 1179 register char *p; 1180 1181 while (SM_ISSPACE(*spec)) 1182 spec++; 1183 spec_end = strchr(spec, ':'); 1184 if (spec_end != NULL) 1185 *spec_end++ = '\0'; 1186 1187 opt[optnum].udbo_name = spec; 1188 opt[optnum].udbo_val = NULL; 1189 p = strchr(spec, '='); 1190 if (p != NULL) 1191 opt[optnum].udbo_val = ++p; 1192 } 1193 return optnum; 1194 } 1195 /* 1196 ** _UDBX_CLOSE -- close all file based UDB entries. 1197 ** 1198 ** Parameters: 1199 ** none 1200 ** 1201 ** Returns: 1202 ** none 1203 */ 1204 void 1205 _udbx_close() 1206 { 1207 struct udbent *up; 1208 1209 if (!UdbInitialized) 1210 return; 1211 1212 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 1213 { 1214 if (up->udb_pid != CurrentPid) 1215 continue; 1216 1217 # if NEWDB 1218 if (up->udb_type == UDB_DBFETCH) 1219 { 1220 # if DB_VERSION_MAJOR < 2 1221 (*up->udb_dbp->close)(up->udb_dbp); 1222 # else 1223 errno = (*up->udb_dbp->close)(up->udb_dbp, 0); 1224 # endif 1225 } 1226 if (tTd(28, 1)) 1227 sm_dprintf("_udbx_close: db->close(%s)\n", 1228 up->udb_dbname); 1229 # endif /* NEWDB */ 1230 } 1231 } 1232 1233 # if HESIOD 1234 1235 static int 1236 hes_udb_get(key, info) 1237 DBT *key; 1238 DBT *info; 1239 { 1240 char *name, *type; 1241 char **hp; 1242 char kbuf[MAXUDBKEY + 1]; 1243 1244 if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf)) 1245 return 0; 1246 name = kbuf; 1247 type = strrchr(name, ':'); 1248 if (type == NULL) 1249 return 1; 1250 *type++ = '\0'; 1251 if (strchr(name, '@') != NULL) 1252 return 1; 1253 1254 if (tTd(28, 1)) 1255 sm_dprintf("hes_udb_get(%s, %s)\n", name, type); 1256 1257 /* make the hesiod query */ 1258 # ifdef HESIOD_INIT 1259 if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0) 1260 return -1; 1261 hp = hesiod_resolve(HesiodContext, name, type); 1262 # else 1263 hp = hes_resolve(name, type); 1264 # endif 1265 *--type = ':'; 1266 # ifdef HESIOD_INIT 1267 if (hp == NULL) 1268 return 1; 1269 if (*hp == NULL) 1270 { 1271 hesiod_free_list(HesiodContext, hp); 1272 if (errno == ECONNREFUSED || errno == EMSGSIZE) 1273 return -1; 1274 return 1; 1275 } 1276 # else /* HESIOD_INIT */ 1277 if (SM_IS_EMPTY(hp)) 1278 { 1279 /* network problem or timeout */ 1280 if (hes_error() == HES_ER_NET) 1281 return -1; 1282 1283 return 1; 1284 } 1285 # endif /* HESIOD_INIT */ 1286 else 1287 { 1288 /* 1289 ** If there are multiple matches, just return the 1290 ** first one. 1291 ** 1292 ** XXX These should really be returned; for example, 1293 ** XXX it is legal for :maildrop to be multi-valued. 1294 */ 1295 1296 info->data = hp[0]; 1297 info->size = (size_t) strlen(info->data); 1298 } 1299 1300 if (tTd(28, 80)) 1301 sm_dprintf("hes_udb_get => %s\n", *hp); 1302 1303 return 0; 1304 } 1305 # endif /* HESIOD */ 1306 1307 #else /* USERDB */ 1308 1309 int 1310 udbexpand(a, sendq, aliaslevel, e) 1311 ADDRESS *a; 1312 ADDRESS **sendq; 1313 int aliaslevel; 1314 ENVELOPE *e; 1315 { 1316 return EX_OK; 1317 } 1318 1319 #endif /* USERDB */ 1320