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