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.19 (Berkeley) 05/01/93 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 6.19 (Berkeley) 05/01/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 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, FALSE, &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 #ifdef LOG 565 if (LogLevel > 2) 566 syslog(LOG_ERR, "dbopen(%s): %s", 567 spec, errstring(errno)); 568 #endif 569 up->udb_type = UDB_EOLIST; 570 goto tempfail; 571 } 572 break; 573 } 574 up->udb_type = UDB_DBFETCH; 575 up++; 576 break; 577 } 578 } 579 up->udb_type = UDB_EOLIST; 580 581 if (tTd(28, 4)) 582 { 583 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 584 { 585 switch (up->udb_type) 586 { 587 case UDB_REMOTE: 588 printf("REMOTE: addr %s, timeo %d\n", 589 anynet_ntoa(&up->udb_addr), 590 up->udb_timeout); 591 break; 592 593 case UDB_DBFETCH: 594 printf("FETCH: file %s\n", 595 up->udb_dbname); 596 break; 597 598 case UDB_FORWARD: 599 printf("FORWARD: host %s\n", 600 up->udb_fwdhost); 601 break; 602 603 default: 604 printf("UNKNOWN\n"); 605 break; 606 } 607 } 608 } 609 610 UdbInitialized = TRUE; 611 errno = 0; 612 return EX_OK; 613 614 /* 615 ** On temporary failure, back out anything we've already done 616 */ 617 618 tempfail: 619 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 620 { 621 if (up->udb_type == UDB_DBFETCH) 622 { 623 (*up->udb_dbp->close)(up->udb_dbp); 624 } 625 } 626 return EX_TEMPFAIL; 627 } 628 629 int 630 _udb_parsespec(udbspec, opt, maxopts) 631 char *udbspec; 632 struct option opt[]; 633 int maxopts; 634 { 635 register char *spec; 636 register char *spec_end; 637 register int optnum; 638 639 spec_end = strchr(udbspec, ':'); 640 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 641 { 642 register char *p; 643 644 while (isascii(*spec) && isspace(*spec)) 645 spec++; 646 spec_end = strchr(spec, ':'); 647 if (spec_end != NULL) 648 *spec_end++ = '\0'; 649 650 opt[optnum].name = spec; 651 opt[optnum].val = NULL; 652 p = strchr(spec, '='); 653 if (p != NULL) 654 opt[optnum].val = ++p; 655 } 656 return optnum; 657 } 658 659 #else /* not USERDB */ 660 661 int 662 udbexpand(a, sendq, e) 663 ADDRESS *a; 664 ADDRESS **sendq; 665 ENVELOPE *e; 666 { 667 return EX_OK; 668 } 669 670 #endif /* USERDB */ 671