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