1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #include "sendmail.h" 10 11 #ifndef lint 12 #ifdef USERDB 13 static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 08/25/93 (with USERDB)"; 14 #else 15 static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 08/25/93 (without USERDB)"; 16 #endif 17 #endif 18 19 #ifdef USERDB 20 21 #include <sys/time.h> 22 #include <errno.h> 23 #include <netdb.h> 24 #include <db.h> 25 26 /* 27 ** UDB.C -- interface between sendmail and Berkeley User Data Base. 28 ** 29 ** This depends on the 4.4BSD db package. 30 */ 31 32 33 struct udbent 34 { 35 char *udb_spec; /* string version of spec */ 36 int udb_type; /* type of entry */ 37 char *udb_default; /* default host for outgoing mail */ 38 union 39 { 40 /* type UE_REMOTE -- do remote call for lookup */ 41 struct 42 { 43 struct sockaddr_in _udb_addr; /* address */ 44 int _udb_timeout; /* timeout */ 45 } udb_remote; 46 #define udb_addr udb_u.udb_remote._udb_addr 47 #define udb_timeout udb_u.udb_remote._udb_timeout 48 49 /* type UE_FORWARD -- forward message to remote */ 50 struct 51 { 52 char *_udb_fwdhost; /* name of forward host */ 53 } udb_forward; 54 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 55 56 /* type UE_FETCH -- lookup in local database */ 57 struct 58 { 59 char *_udb_dbname; /* pathname of database */ 60 DB *_udb_dbp; /* open database ptr */ 61 } udb_lookup; 62 #define udb_dbname udb_u.udb_lookup._udb_dbname 63 #define udb_dbp udb_u.udb_lookup._udb_dbp 64 } udb_u; 65 }; 66 67 #define UDB_EOLIST 0 /* end of list */ 68 #define UDB_SKIP 1 /* skip this entry */ 69 #define UDB_REMOTE 2 /* look up in remote database */ 70 #define UDB_DBFETCH 3 /* look up in local database */ 71 #define UDB_FORWARD 4 /* forward to remote host */ 72 73 #define MAXUDBENT 10 /* maximum number of UDB entries */ 74 75 76 struct option 77 { 78 char *name; 79 char *val; 80 }; 81 /* 82 ** UDBEXPAND -- look up user in database and expand 83 ** 84 ** Parameters: 85 ** a -- address to expand. 86 ** sendq -- pointer to head of sendq to put the expansions in. 87 ** 88 ** Returns: 89 ** EX_TEMPFAIL -- if something "odd" happened -- probably due 90 ** to accessing a file on an NFS server that is down. 91 ** EX_OK -- otherwise. 92 ** 93 ** Side Effects: 94 ** Modifies sendq. 95 */ 96 97 int UdbPort = 1616; 98 int UdbTimeout = 10; 99 100 struct udbent UdbEnts[MAXUDBENT + 1]; 101 int UdbSock = -1; 102 bool UdbInitialized = FALSE; 103 104 int 105 udbexpand(a, sendq, e) 106 register ADDRESS *a; 107 ADDRESS **sendq; 108 register ENVELOPE *e; 109 { 110 int i; 111 register char *p; 112 DBT key; 113 DBT info; 114 bool breakout; 115 register struct udbent *up; 116 int keylen; 117 int naddrs; 118 char keybuf[MAXKEY]; 119 char buf[BUFSIZ]; 120 121 if (tTd(28, 1)) 122 printf("udbexpand(%s)\n", a->q_paddr); 123 124 /* make certain we are supposed to send to this address */ 125 if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 126 return EX_OK; 127 e->e_to = a->q_paddr; 128 129 /* on first call, locate the database */ 130 if (!UdbInitialized) 131 { 132 extern int _udbx_init(); 133 134 if (_udbx_init() == EX_TEMPFAIL) 135 return EX_TEMPFAIL; 136 } 137 138 /* short circuit the process if no chance of a match */ 139 if (UdbSpec == NULL || UdbSpec[0] == '\0') 140 return EX_OK; 141 142 /* if name is too long, assume it won't match */ 143 if (strlen(a->q_user) > sizeof keybuf - 12) 144 return EX_OK; 145 146 /* if name begins with a colon, it indicates our metadata */ 147 if (a->q_user[0] == ':') 148 return EX_OK; 149 150 /* build actual database key */ 151 (void) strcpy(keybuf, a->q_user); 152 (void) strcat(keybuf, ":maildrop"); 153 keylen = strlen(keybuf); 154 155 breakout = FALSE; 156 for (up = UdbEnts; !breakout; up++) 157 { 158 char *user; 159 160 /* 161 ** Select action based on entry type. 162 ** 163 ** On dropping out of this switch, "class" should 164 ** explain the type of the data, and "user" should 165 ** contain the user information. 166 */ 167 168 switch (up->udb_type) 169 { 170 case UDB_DBFETCH: 171 key.data = keybuf; 172 key.size = keylen; 173 if (tTd(28, 80)) 174 printf("udbexpand: trying %s (%d)\n", 175 keybuf, keylen); 176 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 177 if (i > 0 || info.size <= 0) 178 { 179 if (tTd(28, 2)) 180 printf("udbexpand: no match on %s (%d)\n", 181 keybuf, keylen); 182 continue; 183 } 184 if (tTd(28, 80)) 185 printf("udbexpand: match %.*s: %.*s\n", 186 key.size, key.data, info.size, info.data); 187 188 naddrs = 0; 189 a->q_flags &= ~QSELFREF; 190 while (i == 0 && key.size == keylen && 191 bcmp(key.data, keybuf, keylen) == 0) 192 { 193 if (bitset(EF_VRFYONLY, e->e_flags)) 194 { 195 a->q_flags |= QVERIFIED; 196 e->e_nrcpts++; 197 return EX_OK; 198 } 199 200 breakout = TRUE; 201 if (info.size < sizeof buf) 202 user = buf; 203 else 204 user = xalloc(info.size + 1); 205 bcopy(info.data, user, info.size); 206 user[info.size] = '\0'; 207 208 message("expanded to %s", user); 209 #ifdef LOG 210 if (LogLevel >= 10) 211 syslog(LOG_INFO, "%s: expand %s => %s", 212 e->e_id, e->e_to, user); 213 #endif 214 AliasLevel++; 215 naddrs += sendtolist(user, a, sendq, e); 216 AliasLevel--; 217 218 if (user != buf) 219 free(user); 220 221 /* get the next record */ 222 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 223 } 224 225 /* if nothing ever matched, try next database */ 226 if (!breakout) 227 continue; 228 229 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 230 { 231 if (tTd(28, 5)) 232 { 233 printf("udbexpand: QDONTSEND "); 234 printaddr(a, FALSE); 235 } 236 a->q_flags |= QDONTSEND; 237 } 238 if (i < 0) 239 { 240 syserr("udbexpand: db-get %.*s stat %d", 241 key.size, key.data, i); 242 return EX_TEMPFAIL; 243 } 244 245 /* 246 ** If this address has a -request address, reflect 247 ** it into the envelope. 248 */ 249 250 (void) strcpy(keybuf, a->q_user); 251 (void) strcat(keybuf, ":mailsender"); 252 keylen = strlen(keybuf); 253 key.data = keybuf; 254 key.size = keylen; 255 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 256 if (i != 0 || info.size <= 0) 257 break; 258 a->q_owner = xalloc(info.size + 1); 259 bcopy(info.data, a->q_owner, info.size); 260 a->q_owner[info.size] = '\0'; 261 break; 262 263 case UDB_REMOTE: 264 /* not yet implemented */ 265 continue; 266 267 case UDB_FORWARD: 268 if (bitset(EF_VRFYONLY, e->e_flags)) 269 return EX_OK; 270 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 271 if (i < sizeof buf) 272 user = buf; 273 else 274 user = xalloc(i + 1); 275 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 276 message("expanded to %s", user); 277 a->q_flags &= ~QSELFREF; 278 AliasLevel++; 279 naddrs = sendtolist(user, a, sendq, e); 280 AliasLevel--; 281 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 282 { 283 if (tTd(28, 5)) 284 { 285 printf("udbexpand: QDONTSEND "); 286 printaddr(a, FALSE); 287 } 288 a->q_flags |= QDONTSEND; 289 } 290 if (user != buf) 291 free(user); 292 breakout = TRUE; 293 break; 294 295 case UDB_EOLIST: 296 breakout = TRUE; 297 continue; 298 299 default: 300 /* unknown entry type */ 301 continue; 302 } 303 } 304 return EX_OK; 305 } 306 /* 307 ** UDBSENDER -- return canonical external name of sender, given local name 308 ** 309 ** Parameters: 310 ** sender -- the name of the sender on the local machine. 311 ** 312 ** Returns: 313 ** The external name for this sender, if derivable from the 314 ** database. 315 ** NULL -- if nothing is changed from the database. 316 ** 317 ** Side Effects: 318 ** none. 319 */ 320 321 char * 322 udbsender(sender) 323 char *sender; 324 { 325 extern char *udbmatch(); 326 327 return udbmatch(sender, "mailname"); 328 } 329 330 331 char * 332 udbmatch(user, field) 333 char *user; 334 char *field; 335 { 336 register char *p; 337 register struct udbent *up; 338 int i; 339 int keylen; 340 DBT key, info; 341 char keybuf[MAXKEY]; 342 343 if (tTd(28, 1)) 344 printf("udbmatch(%s, %s)\n", user, field); 345 346 if (!UdbInitialized) 347 { 348 if (_udbx_init() == EX_TEMPFAIL) 349 return NULL; 350 } 351 352 /* short circuit if no spec */ 353 if (UdbSpec == NULL || UdbSpec[0] == '\0') 354 return NULL; 355 356 /* long names can never match and are a pain to deal with */ 357 if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 358 return NULL; 359 360 /* names beginning with colons indicate metadata */ 361 if (user[0] == ':') 362 return NULL; 363 364 /* build database key */ 365 (void) strcpy(keybuf, user); 366 (void) strcat(keybuf, ":"); 367 (void) strcat(keybuf, field); 368 keylen = strlen(keybuf); 369 370 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 371 { 372 /* 373 ** Select action based on entry type. 374 */ 375 376 switch (up->udb_type) 377 { 378 case UDB_DBFETCH: 379 key.data = keybuf; 380 key.size = keylen; 381 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 382 if (i != 0 || info.size <= 0) 383 { 384 if (tTd(28, 2)) 385 printf("udbmatch: no match on %s (%d)\n", 386 keybuf, keylen); 387 continue; 388 } 389 390 p = xalloc(info.size + 1); 391 bcopy(info.data, p, info.size); 392 p[info.size] = '\0'; 393 if (tTd(28, 1)) 394 printf("udbmatch ==> %s\n", p); 395 return p; 396 } 397 } 398 399 if (strcmp(field, "mailname") != 0) 400 return NULL; 401 402 /* 403 ** Nothing yet. Search again for a default case. But only 404 ** use it if we also have a forward (:maildrop) pointer already 405 ** in the database. 406 */ 407 408 /* build database key */ 409 (void) strcpy(keybuf, user); 410 (void) strcat(keybuf, ":maildrop"); 411 keylen = strlen(keybuf); 412 413 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 414 { 415 switch (up->udb_type) 416 { 417 case UDB_DBFETCH: 418 /* get the default case for this database */ 419 if (up->udb_default == NULL) 420 { 421 key.data = ":default:mailname"; 422 key.size = strlen(key.data); 423 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 424 if (i != 0 || info.size <= 0) 425 { 426 /* no default case */ 427 up->udb_default = ""; 428 continue; 429 } 430 431 /* save the default case */ 432 up->udb_default = xalloc(info.size + 1); 433 bcopy(info.data, up->udb_default, info.size); 434 up->udb_default[info.size] = '\0'; 435 } 436 else if (up->udb_default[0] == '\0') 437 continue; 438 439 /* we have a default case -- verify user:maildrop */ 440 key.data = keybuf; 441 key.size = keylen; 442 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 443 if (i != 0 || info.size <= 0) 444 { 445 /* nope -- no aliasing for this user */ 446 continue; 447 } 448 449 /* they exist -- build the actual address */ 450 p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 451 (void) strcpy(p, user); 452 (void) strcat(p, "@"); 453 (void) strcat(p, up->udb_default); 454 if (tTd(28, 1)) 455 printf("udbmatch ==> %s\n", p); 456 return p; 457 } 458 } 459 460 /* still nothing.... too bad */ 461 return NULL; 462 } 463 /* 464 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 465 ** 466 ** Parameters: 467 ** none. 468 ** 469 ** Returns: 470 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 471 ** database due to a host being down or some similar 472 ** (recoverable) situation. 473 ** EX_OK -- otherwise. 474 ** 475 ** Side Effects: 476 ** Fills in the UdbEnts structure from UdbSpec. 477 */ 478 479 #define MAXUDBOPTS 27 480 481 int 482 _udbx_init() 483 { 484 register char *p; 485 int i; 486 register struct udbent *up; 487 char buf[BUFSIZ]; 488 489 if (UdbInitialized) 490 return EX_OK; 491 492 # ifdef UDB_DEFAULT_SPEC 493 if (UdbSpec == NULL) 494 UdbSpec = UDB_DEFAULT_SPEC; 495 # endif 496 497 p = UdbSpec; 498 up = UdbEnts; 499 while (p != NULL) 500 { 501 char *spec; 502 auto int rcode; 503 int nopts; 504 int nmx; 505 register struct hostent *h; 506 char *mxhosts[MAXMXHOSTS + 1]; 507 struct option opts[MAXUDBOPTS + 1]; 508 509 while (*p == ' ' || *p == '\t' || *p == ',') 510 p++; 511 if (*p == '\0') 512 break; 513 spec = p; 514 p = strchr(p, ','); 515 if (p != NULL) 516 *p++ = '\0'; 517 518 /* extract options */ 519 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 520 521 /* 522 ** Decode database specification. 523 ** 524 ** In the sendmail tradition, the leading character 525 ** defines the semantics of the rest of the entry. 526 ** 527 ** +hostname -- send a datagram to the udb server 528 ** on host "hostname" asking for the 529 ** home mail server for this user. 530 ** *hostname -- similar to +hostname, except that the 531 ** hostname is searched as an MX record; 532 ** resulting hosts are searched as for 533 ** +mxhostname. If no MX host is found, 534 ** this is the same as +hostname. 535 ** @hostname -- forward email to the indicated host. 536 ** This should be the last in the list, 537 ** since it always matches the input. 538 ** /dbname -- search the named database on the local 539 ** host using the Berkeley db package. 540 */ 541 542 switch (*spec) 543 { 544 case '+': /* search remote database */ 545 case '*': /* search remote database (expand MX) */ 546 if (*spec == '*') 547 { 548 #ifdef NAMED_BIND 549 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 550 #else 551 mxhosts[0] = spec + 1; 552 nmx = 1; 553 rcode = 0; 554 #endif 555 if (tTd(28, 16)) 556 { 557 int i; 558 559 printf("getmxrr(%s): %d", spec + 1, nmx); 560 for (i = 0; i <= nmx; i++) 561 printf(" %s", mxhosts[i]); 562 printf("\n"); 563 } 564 } 565 else 566 { 567 nmx = 1; 568 mxhosts[0] = spec + 1; 569 } 570 571 for (i = 0; i < nmx; i++) 572 { 573 h = gethostbyname(mxhosts[i]); 574 if (h == NULL) 575 continue; 576 up->udb_type = UDB_REMOTE; 577 up->udb_addr.sin_family = h->h_addrtype; 578 bcopy(h->h_addr_list[0], 579 (char *) &up->udb_addr.sin_addr, 580 h->h_length); 581 up->udb_addr.sin_port = UdbPort; 582 up->udb_timeout = UdbTimeout; 583 up++; 584 } 585 586 /* set up a datagram socket */ 587 if (UdbSock < 0) 588 { 589 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 590 (void) fcntl(UdbSock, F_SETFD, 1); 591 } 592 break; 593 594 case '@': /* forward to remote host */ 595 up->udb_type = UDB_FORWARD; 596 up->udb_fwdhost = spec + 1; 597 up++; 598 break; 599 600 case '/': /* look up remote name */ 601 up->udb_dbname = spec; 602 errno = 0; 603 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 604 if (up->udb_dbp == NULL) 605 { 606 if (errno != ENOENT && errno != EACCES) 607 { 608 #ifdef LOG 609 if (LogLevel > 2) 610 syslog(LOG_ERR, "dbopen(%s): %s", 611 spec, errstring(errno)); 612 #endif 613 up->udb_type = UDB_EOLIST; 614 goto tempfail; 615 } 616 break; 617 } 618 up->udb_type = UDB_DBFETCH; 619 up++; 620 break; 621 } 622 } 623 up->udb_type = UDB_EOLIST; 624 625 if (tTd(28, 4)) 626 { 627 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 628 { 629 switch (up->udb_type) 630 { 631 case UDB_REMOTE: 632 printf("REMOTE: addr %s, timeo %d\n", 633 anynet_ntoa((SOCKADDR *) &up->udb_addr), 634 up->udb_timeout); 635 break; 636 637 case UDB_DBFETCH: 638 printf("FETCH: file %s\n", 639 up->udb_dbname); 640 break; 641 642 case UDB_FORWARD: 643 printf("FORWARD: host %s\n", 644 up->udb_fwdhost); 645 break; 646 647 default: 648 printf("UNKNOWN\n"); 649 break; 650 } 651 } 652 } 653 654 UdbInitialized = TRUE; 655 errno = 0; 656 return EX_OK; 657 658 /* 659 ** On temporary failure, back out anything we've already done 660 */ 661 662 tempfail: 663 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 664 { 665 if (up->udb_type == UDB_DBFETCH) 666 { 667 (*up->udb_dbp->close)(up->udb_dbp); 668 } 669 } 670 return EX_TEMPFAIL; 671 } 672 673 int 674 _udb_parsespec(udbspec, opt, maxopts) 675 char *udbspec; 676 struct option opt[]; 677 int maxopts; 678 { 679 register char *spec; 680 register char *spec_end; 681 register int optnum; 682 683 spec_end = strchr(udbspec, ':'); 684 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 685 { 686 register char *p; 687 688 while (isascii(*spec) && isspace(*spec)) 689 spec++; 690 spec_end = strchr(spec, ':'); 691 if (spec_end != NULL) 692 *spec_end++ = '\0'; 693 694 opt[optnum].name = spec; 695 opt[optnum].val = NULL; 696 p = strchr(spec, '='); 697 if (p != NULL) 698 opt[optnum].val = ++p; 699 } 700 return optnum; 701 } 702 703 #else /* not USERDB */ 704 705 int 706 udbexpand(a, sendq, e) 707 ADDRESS *a; 708 ADDRESS **sendq; 709 ENVELOPE *e; 710 { 711 return EX_OK; 712 } 713 714 #endif /* USERDB */ 715