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