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