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.14 (Berkeley) 03/19/93 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 6.14 (Berkeley) 03/19/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 return EX_OK; 190 } 191 192 breakout = TRUE; 193 if (info.size < sizeof buf) 194 user = buf; 195 else 196 user = xalloc(info.size + 1); 197 bcopy(info.data, user, info.size); 198 user[info.size] = '\0'; 199 200 message("expanded to %s", user); 201 #ifdef LOG 202 if (LogLevel >= 10) 203 syslog(LOG_INFO, "%s: expand %s => %s", 204 e->e_id, e->e_to, user); 205 #endif 206 AliasLevel++; 207 naddrs += sendtolist(user, a, sendq, e); 208 AliasLevel--; 209 210 if (user != buf) 211 free(user); 212 213 /* get the next record */ 214 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 215 } 216 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 217 { 218 if (tTd(28, 5)) 219 { 220 printf("udbexpand: QDONTSEND "); 221 printaddr(a, FALSE); 222 } 223 a->q_flags |= QDONTSEND; 224 } 225 if (i < 0) 226 { 227 syserr("udbexpand: db-get %.*s stat %d", 228 key.size, key.data, i); 229 return EX_TEMPFAIL; 230 } 231 break; 232 233 case UDB_REMOTE: 234 /* not yet implemented */ 235 continue; 236 237 case UDB_FORWARD: 238 if (bitset(EF_VRFYONLY, e->e_flags)) 239 return EX_OK; 240 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 241 if (i < sizeof buf) 242 user = buf; 243 else 244 user = xalloc(i + 1); 245 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 246 message("expanded to %s", user); 247 a->q_flags &= ~QSELFREF; 248 AliasLevel++; 249 naddrs = sendtolist(user, a, sendq, e); 250 AliasLevel--; 251 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 252 { 253 if (tTd(28, 5)) 254 { 255 printf("udbexpand: QDONTSEND "); 256 printaddr(a, FALSE); 257 } 258 a->q_flags |= QDONTSEND; 259 } 260 if (user != buf) 261 free(user); 262 breakout = TRUE; 263 break; 264 265 case UDB_EOLIST: 266 breakout = TRUE; 267 continue; 268 269 default: 270 /* unknown entry type */ 271 continue; 272 } 273 } 274 return EX_OK; 275 } 276 /* 277 ** UDBSENDER -- return canonical external name of sender, given local name 278 ** 279 ** Parameters: 280 ** sender -- the name of the sender on the local machine. 281 ** 282 ** Returns: 283 ** The external name for this sender, if derivable from the 284 ** database. 285 ** NULL -- if nothing is changed from the database. 286 ** 287 ** Side Effects: 288 ** none. 289 */ 290 291 char * 292 udbsender(sender) 293 char *sender; 294 { 295 register char *p; 296 register struct udbent *up; 297 int i; 298 int keylen; 299 DBT key, info; 300 char keybuf[MAXKEY]; 301 302 if (tTd(28, 1)) 303 printf("udbsender(%s)\n", sender); 304 305 if (!UdbInitialized) 306 { 307 if (_udbx_init() == EX_TEMPFAIL) 308 return NULL; 309 } 310 311 /* short circuit if no spec */ 312 if (UdbSpec == NULL || UdbSpec[0] == '\0') 313 return NULL; 314 315 /* long names can never match and are a pain to deal with */ 316 if (strlen(sender) > sizeof keybuf - 12) 317 return NULL; 318 319 /* names beginning with colons indicate metadata */ 320 if (sender[0] == ':') 321 return NULL; 322 323 /* build database key */ 324 (void) strcpy(keybuf, sender); 325 (void) strcat(keybuf, ":mailname"); 326 keylen = strlen(keybuf); 327 328 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 329 { 330 /* 331 ** Select action based on entry type. 332 */ 333 334 switch (up->udb_type) 335 { 336 case UDB_DBFETCH: 337 key.data = keybuf; 338 key.size = keylen; 339 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 340 if (i != 0 || info.size <= 0) 341 { 342 if (tTd(28, 2)) 343 printf("udbsender: no match on %s\n", 344 keybuf); 345 continue; 346 } 347 348 p = xalloc(info.size + 1); 349 bcopy(info.data, p, info.size); 350 p[info.size] = '\0'; 351 if (tTd(28, 1)) 352 printf("udbsender ==> %s\n", p); 353 return p; 354 } 355 } 356 357 /* 358 ** Nothing yet. Search again for a default case. But only 359 ** use it if we also have a forward (:maildrop) pointer already 360 ** in the database. 361 */ 362 363 /* build database key */ 364 (void) strcpy(keybuf, sender); 365 (void) strcat(keybuf, ":maildrop"); 366 keylen = strlen(keybuf); 367 368 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 369 { 370 switch (up->udb_type) 371 { 372 case UDB_DBFETCH: 373 /* get the default case for this database */ 374 if (up->udb_default == NULL) 375 { 376 key.data = ":default:mailname"; 377 key.size = strlen(key.data); 378 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 379 if (i != 0 || info.size <= 0) 380 { 381 /* no default case */ 382 up->udb_default = ""; 383 continue; 384 } 385 386 /* save the default case */ 387 up->udb_default = xalloc(info.size + 1); 388 bcopy(info.data, up->udb_default, info.size); 389 up->udb_default[info.size] = '\0'; 390 } 391 else if (up->udb_default[0] == '\0') 392 continue; 393 394 /* we have a default case -- verify user:maildrop */ 395 key.data = keybuf; 396 key.size = keylen; 397 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 398 if (i != 0 || info.size <= 0) 399 { 400 /* nope -- no aliasing for this user */ 401 continue; 402 } 403 404 /* they exist -- build the actual address */ 405 p = xalloc(strlen(sender) + strlen(up->udb_default) + 2); 406 (void) strcpy(p, sender); 407 (void) strcat(p, "@"); 408 (void) strcat(p, up->udb_default); 409 if (tTd(28, 1)) 410 printf("udbsender ==> %s\n", p); 411 return p; 412 } 413 } 414 415 /* still nothing.... too bad */ 416 return NULL; 417 } 418 /* 419 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 420 ** 421 ** Parameters: 422 ** none. 423 ** 424 ** Returns: 425 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 426 ** database due to a host being down or some similar 427 ** (recoverable) situation. 428 ** EX_OK -- otherwise. 429 ** 430 ** Side Effects: 431 ** Fills in the UdbEnts structure from UdbSpec. 432 */ 433 434 #define MAXUDBOPTS 27 435 436 int 437 _udbx_init() 438 { 439 register char *p; 440 int i; 441 register struct udbent *up; 442 char buf[BUFSIZ]; 443 444 if (UdbInitialized) 445 return EX_OK; 446 447 # ifdef UDB_DEFAULT_SPEC 448 if (UdbSpec == NULL) 449 UdbSpec = UDB_DEFAULT_SPEC; 450 # endif 451 452 p = UdbSpec; 453 up = UdbEnts; 454 while (p != NULL) 455 { 456 char *spec; 457 auto int rcode; 458 int nopts; 459 int nmx; 460 register struct hostent *h; 461 char *mxhosts[MAXMXHOSTS + 1]; 462 struct option opts[MAXUDBOPTS + 1]; 463 464 while (*p == ' ' || *p == '\t' || *p == ',') 465 p++; 466 if (*p == '\0') 467 break; 468 spec = p; 469 p = strchr(p, ','); 470 if (p != NULL) 471 *p++ = '\0'; 472 473 /* extract options */ 474 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 475 476 /* 477 ** Decode database specification. 478 ** 479 ** In the sendmail tradition, the leading character 480 ** defines the semantics of the rest of the entry. 481 ** 482 ** +hostname -- send a datagram to the udb server 483 ** on host "hostname" asking for the 484 ** home mail server for this user. 485 ** *hostname -- similar to +hostname, except that the 486 ** hostname is searched as an MX record; 487 ** resulting hosts are searched as for 488 ** +mxhostname. If no MX host is found, 489 ** this is the same as +hostname. 490 ** @hostname -- forward email to the indicated host. 491 ** This should be the last in the list, 492 ** since it always matches the input. 493 ** /dbname -- search the named database on the local 494 ** host using the Berkeley db package. 495 */ 496 497 switch (*spec) 498 { 499 case '+': /* search remote database */ 500 case '*': /* search remote database (expand MX) */ 501 if (*spec == '*') 502 { 503 #ifdef NAMED_BIND 504 nmx = getmxrr(spec + 1, mxhosts, "", &rcode); 505 #else 506 mxhosts[0] = spec + 1; 507 nmx = 1; 508 rcode = 0; 509 #endif 510 if (tTd(28, 16)) 511 { 512 int i; 513 514 printf("getmxrr(%s): %d", spec + 1, nmx); 515 for (i = 0; i <= nmx; i++) 516 printf(" %s", mxhosts[i]); 517 printf("\n"); 518 } 519 } 520 else 521 { 522 nmx = 1; 523 mxhosts[0] = spec + 1; 524 } 525 526 for (i = 0; i < nmx; i++) 527 { 528 h = gethostbyname(mxhosts[i]); 529 if (h == NULL) 530 continue; 531 up->udb_type = UDB_REMOTE; 532 up->udb_addr.sin_family = h->h_addrtype; 533 up->udb_addr.sin_len = h->h_length; 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 anynet_ntoa(&up->udb_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