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