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