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