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