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