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.1 (Berkeley) 06/07/93 (with USERDB)"; 14 #else 15 static char sccsid [] = "@(#)udb.c 8.1 (Berkeley) 06/07/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\n", keybuf); 175 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 176 if (i > 0 || info.size <= 0) 177 { 178 if (tTd(28, 2)) 179 printf("udbexpand: no match on %s\n", keybuf); 180 continue; 181 } 182 if (tTd(28, 80)) 183 printf("udbexpand: match %.*s: %.*s\n", 184 key.size, key.data, info.size, info.data); 185 186 naddrs = 0; 187 a->q_flags &= ~QSELFREF; 188 while (i == 0 && key.size == keylen && 189 bcmp(key.data, keybuf, keylen) == 0) 190 { 191 if (bitset(EF_VRFYONLY, e->e_flags)) 192 { 193 a->q_flags |= QVERIFIED; 194 e->e_nrcpts++; 195 return EX_OK; 196 } 197 198 breakout = TRUE; 199 if (info.size < sizeof buf) 200 user = buf; 201 else 202 user = xalloc(info.size + 1); 203 bcopy(info.data, user, info.size); 204 user[info.size] = '\0'; 205 206 message("expanded to %s", user); 207 #ifdef LOG 208 if (LogLevel >= 10) 209 syslog(LOG_INFO, "%s: expand %s => %s", 210 e->e_id, e->e_to, user); 211 #endif 212 AliasLevel++; 213 naddrs += sendtolist(user, a, sendq, e); 214 AliasLevel--; 215 216 if (user != buf) 217 free(user); 218 219 /* get the next record */ 220 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 221 } 222 223 /* if nothing ever matched, try next database */ 224 if (!breakout) 225 continue; 226 227 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 228 { 229 if (tTd(28, 5)) 230 { 231 printf("udbexpand: QDONTSEND "); 232 printaddr(a, FALSE); 233 } 234 a->q_flags |= QDONTSEND; 235 } 236 if (i < 0) 237 { 238 syserr("udbexpand: db-get %.*s stat %d", 239 key.size, key.data, i); 240 return EX_TEMPFAIL; 241 } 242 243 /* 244 ** If this address has a -request address, reflect 245 ** it into the envelope. 246 */ 247 248 (void) strcpy(keybuf, a->q_user); 249 (void) strcat(keybuf, ":mailsender"); 250 keylen = strlen(keybuf); 251 key.data = keybuf; 252 key.size = keylen; 253 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 254 if (i != 0 || info.size <= 0) 255 break; 256 a->q_owner = xalloc(info.size + 1); 257 bcopy(info.data, a->q_owner, info.size); 258 a->q_owner[info.size] = '\0'; 259 break; 260 261 case UDB_REMOTE: 262 /* not yet implemented */ 263 continue; 264 265 case UDB_FORWARD: 266 if (bitset(EF_VRFYONLY, e->e_flags)) 267 return EX_OK; 268 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 269 if (i < sizeof buf) 270 user = buf; 271 else 272 user = xalloc(i + 1); 273 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 274 message("expanded to %s", user); 275 a->q_flags &= ~QSELFREF; 276 AliasLevel++; 277 naddrs = sendtolist(user, a, sendq, e); 278 AliasLevel--; 279 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 280 { 281 if (tTd(28, 5)) 282 { 283 printf("udbexpand: QDONTSEND "); 284 printaddr(a, FALSE); 285 } 286 a->q_flags |= QDONTSEND; 287 } 288 if (user != buf) 289 free(user); 290 breakout = TRUE; 291 break; 292 293 case UDB_EOLIST: 294 breakout = TRUE; 295 continue; 296 297 default: 298 /* unknown entry type */ 299 continue; 300 } 301 } 302 return EX_OK; 303 } 304 /* 305 ** UDBSENDER -- return canonical external name of sender, given local name 306 ** 307 ** Parameters: 308 ** sender -- the name of the sender on the local machine. 309 ** 310 ** Returns: 311 ** The external name for this sender, if derivable from the 312 ** database. 313 ** NULL -- if nothing is changed from the database. 314 ** 315 ** Side Effects: 316 ** none. 317 */ 318 319 char * 320 udbsender(sender) 321 char *sender; 322 { 323 register char *p; 324 register struct udbent *up; 325 int i; 326 int keylen; 327 DBT key, info; 328 char keybuf[MAXKEY]; 329 330 if (tTd(28, 1)) 331 printf("udbsender(%s)\n", sender); 332 333 if (!UdbInitialized) 334 { 335 if (_udbx_init() == EX_TEMPFAIL) 336 return NULL; 337 } 338 339 /* short circuit if no spec */ 340 if (UdbSpec == NULL || UdbSpec[0] == '\0') 341 return NULL; 342 343 /* long names can never match and are a pain to deal with */ 344 if (strlen(sender) > sizeof keybuf - 12) 345 return NULL; 346 347 /* names beginning with colons indicate metadata */ 348 if (sender[0] == ':') 349 return NULL; 350 351 /* build database key */ 352 (void) strcpy(keybuf, sender); 353 (void) strcat(keybuf, ":mailname"); 354 keylen = strlen(keybuf); 355 356 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 357 { 358 /* 359 ** Select action based on entry type. 360 */ 361 362 switch (up->udb_type) 363 { 364 case UDB_DBFETCH: 365 key.data = keybuf; 366 key.size = keylen; 367 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 368 if (i != 0 || info.size <= 0) 369 { 370 if (tTd(28, 2)) 371 printf("udbsender: no match on %s\n", 372 keybuf); 373 continue; 374 } 375 376 p = xalloc(info.size + 1); 377 bcopy(info.data, p, info.size); 378 p[info.size] = '\0'; 379 if (tTd(28, 1)) 380 printf("udbsender ==> %s\n", p); 381 return p; 382 } 383 } 384 385 /* 386 ** Nothing yet. Search again for a default case. But only 387 ** use it if we also have a forward (:maildrop) pointer already 388 ** in the database. 389 */ 390 391 /* build database key */ 392 (void) strcpy(keybuf, sender); 393 (void) strcat(keybuf, ":maildrop"); 394 keylen = strlen(keybuf); 395 396 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 397 { 398 switch (up->udb_type) 399 { 400 case UDB_DBFETCH: 401 /* get the default case for this database */ 402 if (up->udb_default == NULL) 403 { 404 key.data = ":default:mailname"; 405 key.size = strlen(key.data); 406 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 407 if (i != 0 || info.size <= 0) 408 { 409 /* no default case */ 410 up->udb_default = ""; 411 continue; 412 } 413 414 /* save the default case */ 415 up->udb_default = xalloc(info.size + 1); 416 bcopy(info.data, up->udb_default, info.size); 417 up->udb_default[info.size] = '\0'; 418 } 419 else if (up->udb_default[0] == '\0') 420 continue; 421 422 /* we have a default case -- verify user:maildrop */ 423 key.data = keybuf; 424 key.size = keylen; 425 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 426 if (i != 0 || info.size <= 0) 427 { 428 /* nope -- no aliasing for this user */ 429 continue; 430 } 431 432 /* they exist -- build the actual address */ 433 p = xalloc(strlen(sender) + strlen(up->udb_default) + 2); 434 (void) strcpy(p, sender); 435 (void) strcat(p, "@"); 436 (void) strcat(p, up->udb_default); 437 if (tTd(28, 1)) 438 printf("udbsender ==> %s\n", p); 439 return p; 440 } 441 } 442 443 /* still nothing.... too bad */ 444 return NULL; 445 } 446 /* 447 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 448 ** 449 ** Parameters: 450 ** none. 451 ** 452 ** Returns: 453 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 454 ** database due to a host being down or some similar 455 ** (recoverable) situation. 456 ** EX_OK -- otherwise. 457 ** 458 ** Side Effects: 459 ** Fills in the UdbEnts structure from UdbSpec. 460 */ 461 462 #define MAXUDBOPTS 27 463 464 int 465 _udbx_init() 466 { 467 register char *p; 468 int i; 469 register struct udbent *up; 470 char buf[BUFSIZ]; 471 472 if (UdbInitialized) 473 return EX_OK; 474 475 # ifdef UDB_DEFAULT_SPEC 476 if (UdbSpec == NULL) 477 UdbSpec = UDB_DEFAULT_SPEC; 478 # endif 479 480 p = UdbSpec; 481 up = UdbEnts; 482 while (p != NULL) 483 { 484 char *spec; 485 auto int rcode; 486 int nopts; 487 int nmx; 488 register struct hostent *h; 489 char *mxhosts[MAXMXHOSTS + 1]; 490 struct option opts[MAXUDBOPTS + 1]; 491 492 while (*p == ' ' || *p == '\t' || *p == ',') 493 p++; 494 if (*p == '\0') 495 break; 496 spec = p; 497 p = strchr(p, ','); 498 if (p != NULL) 499 *p++ = '\0'; 500 501 /* extract options */ 502 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 503 504 /* 505 ** Decode database specification. 506 ** 507 ** In the sendmail tradition, the leading character 508 ** defines the semantics of the rest of the entry. 509 ** 510 ** +hostname -- send a datagram to the udb server 511 ** on host "hostname" asking for the 512 ** home mail server for this user. 513 ** *hostname -- similar to +hostname, except that the 514 ** hostname is searched as an MX record; 515 ** resulting hosts are searched as for 516 ** +mxhostname. If no MX host is found, 517 ** this is the same as +hostname. 518 ** @hostname -- forward email to the indicated host. 519 ** This should be the last in the list, 520 ** since it always matches the input. 521 ** /dbname -- search the named database on the local 522 ** host using the Berkeley db package. 523 */ 524 525 switch (*spec) 526 { 527 case '+': /* search remote database */ 528 case '*': /* search remote database (expand MX) */ 529 if (*spec == '*') 530 { 531 #ifdef NAMED_BIND 532 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 533 #else 534 mxhosts[0] = spec + 1; 535 nmx = 1; 536 rcode = 0; 537 #endif 538 if (tTd(28, 16)) 539 { 540 int i; 541 542 printf("getmxrr(%s): %d", spec + 1, nmx); 543 for (i = 0; i <= nmx; i++) 544 printf(" %s", mxhosts[i]); 545 printf("\n"); 546 } 547 } 548 else 549 { 550 nmx = 1; 551 mxhosts[0] = spec + 1; 552 } 553 554 for (i = 0; i < nmx; i++) 555 { 556 h = gethostbyname(mxhosts[i]); 557 if (h == NULL) 558 continue; 559 up->udb_type = UDB_REMOTE; 560 up->udb_addr.sin_family = h->h_addrtype; 561 bcopy(h->h_addr_list[0], 562 (char *) &up->udb_addr.sin_addr, 563 h->h_length); 564 up->udb_addr.sin_port = UdbPort; 565 up->udb_timeout = UdbTimeout; 566 up++; 567 } 568 569 /* set up a datagram socket */ 570 if (UdbSock < 0) 571 { 572 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 573 (void) fcntl(UdbSock, F_SETFD, 1); 574 } 575 break; 576 577 case '@': /* forward to remote host */ 578 up->udb_type = UDB_FORWARD; 579 up->udb_fwdhost = spec + 1; 580 up++; 581 break; 582 583 case '/': /* look up remote name */ 584 up->udb_dbname = spec; 585 errno = 0; 586 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 587 if (up->udb_dbp == NULL) 588 { 589 if (errno != ENOENT && errno != EACCES) 590 { 591 #ifdef LOG 592 if (LogLevel > 2) 593 syslog(LOG_ERR, "dbopen(%s): %s", 594 spec, errstring(errno)); 595 #endif 596 up->udb_type = UDB_EOLIST; 597 goto tempfail; 598 } 599 break; 600 } 601 up->udb_type = UDB_DBFETCH; 602 up++; 603 break; 604 } 605 } 606 up->udb_type = UDB_EOLIST; 607 608 if (tTd(28, 4)) 609 { 610 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 611 { 612 switch (up->udb_type) 613 { 614 case UDB_REMOTE: 615 printf("REMOTE: addr %s, timeo %d\n", 616 anynet_ntoa((SOCKADDR *) &up->udb_addr), 617 up->udb_timeout); 618 break; 619 620 case UDB_DBFETCH: 621 printf("FETCH: file %s\n", 622 up->udb_dbname); 623 break; 624 625 case UDB_FORWARD: 626 printf("FORWARD: host %s\n", 627 up->udb_fwdhost); 628 break; 629 630 default: 631 printf("UNKNOWN\n"); 632 break; 633 } 634 } 635 } 636 637 UdbInitialized = TRUE; 638 errno = 0; 639 return EX_OK; 640 641 /* 642 ** On temporary failure, back out anything we've already done 643 */ 644 645 tempfail: 646 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 647 { 648 if (up->udb_type == UDB_DBFETCH) 649 { 650 (*up->udb_dbp->close)(up->udb_dbp); 651 } 652 } 653 return EX_TEMPFAIL; 654 } 655 656 int 657 _udb_parsespec(udbspec, opt, maxopts) 658 char *udbspec; 659 struct option opt[]; 660 int maxopts; 661 { 662 register char *spec; 663 register char *spec_end; 664 register int optnum; 665 666 spec_end = strchr(udbspec, ':'); 667 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 668 { 669 register char *p; 670 671 while (isascii(*spec) && isspace(*spec)) 672 spec++; 673 spec_end = strchr(spec, ':'); 674 if (spec_end != NULL) 675 *spec_end++ = '\0'; 676 677 opt[optnum].name = spec; 678 opt[optnum].val = NULL; 679 p = strchr(spec, '='); 680 if (p != NULL) 681 opt[optnum].val = ++p; 682 } 683 return optnum; 684 } 685 686 #else /* not USERDB */ 687 688 int 689 udbexpand(a, sendq, e) 690 ADDRESS *a; 691 ADDRESS **sendq; 692 ENVELOPE *e; 693 { 694 return EX_OK; 695 } 696 697 #endif /* USERDB */ 698