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