1 /* 2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 * $FreeBSD$ 13 */ 14 15 #include <sendmail.h> 16 17 SM_RCSID("@(#)$Id: mci.c,v 8.205.2.4 2003/03/31 17:35:27 ca Exp $") 18 19 #if NETINET || NETINET6 20 # include <arpa/inet.h> 21 #endif /* NETINET || NETINET6 */ 22 23 #include <dirent.h> 24 25 static int mci_generate_persistent_path __P((const char *, char *, 26 int, bool)); 27 static bool mci_load_persistent __P((MCI *)); 28 static void mci_uncache __P((MCI **, bool)); 29 static int mci_lock_host_statfile __P((MCI *)); 30 static int mci_read_persistent __P((SM_FILE_T *, MCI *)); 31 32 /* 33 ** Mail Connection Information (MCI) Caching Module. 34 ** 35 ** There are actually two separate things cached. The first is 36 ** the set of all open connections -- these are stored in a 37 ** (small) list. The second is stored in the symbol table; it 38 ** has the overall status for all hosts, whether or not there 39 ** is a connection open currently. 40 ** 41 ** There should never be too many connections open (since this 42 ** could flood the socket table), nor should a connection be 43 ** allowed to sit idly for too long. 44 ** 45 ** MaxMciCache is the maximum number of open connections that 46 ** will be supported. 47 ** 48 ** MciCacheTimeout is the time (in seconds) that a connection 49 ** is permitted to survive without activity. 50 ** 51 ** We actually try any cached connections by sending a NOOP 52 ** before we use them; if the NOOP fails we close down the 53 ** connection and reopen it. Note that this means that a 54 ** server SMTP that doesn't support NOOP will hose the 55 ** algorithm -- but that doesn't seem too likely. 56 ** 57 ** The persistent MCI code is donated by Mark Lovell and Paul 58 ** Vixie. It is based on the long term host status code in KJS 59 ** written by Paul but has been adapted by Mark to fit into the 60 ** MCI structure. 61 */ 62 63 static MCI **MciCache; /* the open connection cache */ 64 65 /* 66 ** MCI_CACHE -- enter a connection structure into the open connection cache 67 ** 68 ** This may cause something else to be flushed. 69 ** 70 ** Parameters: 71 ** mci -- the connection to cache. 72 ** 73 ** Returns: 74 ** none. 75 */ 76 77 void 78 mci_cache(mci) 79 register MCI *mci; 80 { 81 register MCI **mcislot; 82 83 /* 84 ** Find the best slot. This may cause expired connections 85 ** to be closed. 86 */ 87 88 mcislot = mci_scan(mci); 89 if (mcislot == NULL) 90 { 91 /* we don't support caching */ 92 return; 93 } 94 95 if (mci->mci_host == NULL) 96 return; 97 98 /* if this is already cached, we are done */ 99 if (bitset(MCIF_CACHED, mci->mci_flags)) 100 return; 101 102 /* otherwise we may have to clear the slot */ 103 if (*mcislot != NULL) 104 mci_uncache(mcislot, true); 105 106 if (tTd(42, 5)) 107 sm_dprintf("mci_cache: caching %p (%s) in slot %d\n", 108 mci, mci->mci_host, (int) (mcislot - MciCache)); 109 if (tTd(91, 100)) 110 sm_syslog(LOG_DEBUG, CurEnv->e_id, 111 "mci_cache: caching %lx (%.100s) in slot %d", 112 (unsigned long) mci, mci->mci_host, 113 (int) (mcislot - MciCache)); 114 115 *mcislot = mci; 116 mci->mci_flags |= MCIF_CACHED; 117 } 118 /* 119 ** MCI_SCAN -- scan the cache, flush junk, and return best slot 120 ** 121 ** Parameters: 122 ** savemci -- never flush this one. Can be null. 123 ** 124 ** Returns: 125 ** The LRU (or empty) slot. 126 */ 127 128 MCI ** 129 mci_scan(savemci) 130 MCI *savemci; 131 { 132 time_t now; 133 register MCI **bestmci; 134 register MCI *mci; 135 register int i; 136 137 if (MaxMciCache <= 0) 138 { 139 /* we don't support caching */ 140 return NULL; 141 } 142 143 if (MciCache == NULL) 144 { 145 /* first call */ 146 MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof *MciCache); 147 memset((char *) MciCache, '\0', MaxMciCache * sizeof *MciCache); 148 return &MciCache[0]; 149 } 150 151 now = curtime(); 152 bestmci = &MciCache[0]; 153 for (i = 0; i < MaxMciCache; i++) 154 { 155 mci = MciCache[i]; 156 if (mci == NULL || mci->mci_state == MCIS_CLOSED) 157 { 158 bestmci = &MciCache[i]; 159 continue; 160 } 161 if ((mci->mci_lastuse + MciCacheTimeout <= now || 162 (mci->mci_mailer != NULL && 163 mci->mci_mailer->m_maxdeliveries > 0 && 164 mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&& 165 mci != savemci) 166 { 167 /* connection idle too long or too many deliveries */ 168 bestmci = &MciCache[i]; 169 170 /* close it */ 171 mci_uncache(bestmci, true); 172 continue; 173 } 174 if (*bestmci == NULL) 175 continue; 176 if (mci->mci_lastuse < (*bestmci)->mci_lastuse) 177 bestmci = &MciCache[i]; 178 } 179 return bestmci; 180 } 181 /* 182 ** MCI_UNCACHE -- remove a connection from a slot. 183 ** 184 ** May close a connection. 185 ** 186 ** Parameters: 187 ** mcislot -- the slot to empty. 188 ** doquit -- if true, send QUIT protocol on this connection. 189 ** if false, we are assumed to be in a forked child; 190 ** all we want to do is close the file(s). 191 ** 192 ** Returns: 193 ** none. 194 */ 195 196 static void 197 mci_uncache(mcislot, doquit) 198 register MCI **mcislot; 199 bool doquit; 200 { 201 register MCI *mci; 202 extern ENVELOPE BlankEnvelope; 203 204 mci = *mcislot; 205 if (mci == NULL) 206 return; 207 *mcislot = NULL; 208 if (mci->mci_host == NULL) 209 return; 210 211 mci_unlock_host(mci); 212 213 if (tTd(42, 5)) 214 sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n", 215 mci, mci->mci_host, (int) (mcislot - MciCache), 216 doquit); 217 if (tTd(91, 100)) 218 sm_syslog(LOG_DEBUG, CurEnv->e_id, 219 "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)", 220 (unsigned long) mci, mci->mci_host, 221 (int) (mcislot - MciCache), doquit); 222 223 mci->mci_deliveries = 0; 224 if (doquit) 225 { 226 message("Closing connection to %s", mci->mci_host); 227 228 mci->mci_flags &= ~MCIF_CACHED; 229 230 /* only uses the envelope to flush the transcript file */ 231 if (mci->mci_state != MCIS_CLOSED) 232 smtpquit(mci->mci_mailer, mci, &BlankEnvelope); 233 #if XLA 234 xla_host_end(mci->mci_host); 235 #endif /* XLA */ 236 } 237 else 238 { 239 if (mci->mci_in != NULL) 240 (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 241 if (mci->mci_out != NULL) 242 (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 243 mci->mci_in = mci->mci_out = NULL; 244 mci->mci_state = MCIS_CLOSED; 245 mci->mci_exitstat = EX_OK; 246 mci->mci_errno = 0; 247 mci->mci_flags = 0; 248 249 mci->mci_retryrcpt = false; 250 mci->mci_tolist = NULL; 251 #if PIPELINING 252 mci->mci_okrcpts = 0; 253 #endif /* PIPELINING */ 254 } 255 256 SM_FREE_CLR(mci->mci_status); 257 SM_FREE_CLR(mci->mci_rstatus); 258 SM_FREE_CLR(mci->mci_heloname); 259 if (mci->mci_rpool != NULL) 260 { 261 sm_rpool_free(mci->mci_rpool); 262 mci->mci_macro.mac_rpool = NULL; 263 mci->mci_rpool = NULL; 264 } 265 } 266 /* 267 ** MCI_FLUSH -- flush the entire cache 268 ** 269 ** Parameters: 270 ** doquit -- if true, send QUIT protocol. 271 ** if false, just close the connection. 272 ** allbut -- but leave this one open. 273 ** 274 ** Returns: 275 ** none. 276 */ 277 278 void 279 mci_flush(doquit, allbut) 280 bool doquit; 281 MCI *allbut; 282 { 283 register int i; 284 285 if (MciCache == NULL) 286 return; 287 288 for (i = 0; i < MaxMciCache; i++) 289 { 290 if (allbut != MciCache[i]) 291 mci_uncache(&MciCache[i], doquit); 292 } 293 } 294 /* 295 ** MCI_GET -- get information about a particular host 296 ** 297 ** Parameters: 298 ** host -- host to look for. 299 ** m -- mailer. 300 ** 301 ** Returns: 302 ** mci for this host (might be new). 303 */ 304 305 MCI * 306 mci_get(host, m) 307 char *host; 308 MAILER *m; 309 { 310 register MCI *mci; 311 register STAB *s; 312 extern SOCKADDR CurHostAddr; 313 314 /* clear CurHostAddr so we don't get a bogus address with this name */ 315 memset(&CurHostAddr, '\0', sizeof CurHostAddr); 316 317 /* clear out any expired connections */ 318 (void) mci_scan(NULL); 319 320 if (m->m_mno < 0) 321 syserr("!negative mno %d (%s)", m->m_mno, m->m_name); 322 323 s = stab(host, ST_MCI + m->m_mno, ST_ENTER); 324 mci = &s->s_mci; 325 326 /* initialize per-message data */ 327 mci->mci_retryrcpt = false; 328 mci->mci_tolist = NULL; 329 #if PIPELINING 330 mci->mci_okrcpts = 0; 331 #endif /* PIPELINING */ 332 333 if (mci->mci_rpool == NULL) 334 mci->mci_rpool = sm_rpool_new_x(NULL); 335 336 if (mci->mci_macro.mac_rpool == NULL) 337 mci->mci_macro.mac_rpool = mci->mci_rpool; 338 339 /* 340 ** We don't need to load the persistent data if we have data 341 ** already loaded in the cache. 342 */ 343 344 if (mci->mci_host == NULL && 345 (mci->mci_host = s->s_name) != NULL && 346 !mci_load_persistent(mci)) 347 { 348 if (tTd(42, 2)) 349 sm_dprintf("mci_get(%s %s): lock failed\n", 350 host, m->m_name); 351 mci->mci_exitstat = EX_TEMPFAIL; 352 mci->mci_state = MCIS_CLOSED; 353 mci->mci_statfile = NULL; 354 return mci; 355 } 356 357 if (tTd(42, 2)) 358 { 359 sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n", 360 host, m->m_name, mci->mci_state, mci->mci_flags, 361 mci->mci_exitstat, mci->mci_errno); 362 } 363 364 if (mci->mci_state == MCIS_OPEN) 365 { 366 /* poke the connection to see if it's still alive */ 367 (void) smtpprobe(mci); 368 369 /* reset the stored state in the event of a timeout */ 370 if (mci->mci_state != MCIS_OPEN) 371 { 372 mci->mci_errno = 0; 373 mci->mci_exitstat = EX_OK; 374 mci->mci_state = MCIS_CLOSED; 375 } 376 else 377 { 378 /* get peer host address */ 379 /* (this should really be in the mci struct) */ 380 SOCKADDR_LEN_T socklen = sizeof CurHostAddr; 381 382 (void) getpeername(sm_io_getinfo(mci->mci_in, 383 SM_IO_WHAT_FD, NULL), 384 (struct sockaddr *) &CurHostAddr, &socklen); 385 } 386 } 387 if (mci->mci_state == MCIS_CLOSED) 388 { 389 time_t now = curtime(); 390 391 /* if this info is stale, ignore it */ 392 if (mci->mci_lastuse + MciInfoTimeout <= now) 393 { 394 mci->mci_lastuse = now; 395 mci->mci_errno = 0; 396 mci->mci_exitstat = EX_OK; 397 } 398 } 399 400 return mci; 401 } 402 /* 403 ** MCI_NEW -- allocate new MCI structure 404 ** 405 ** Parameters: 406 ** rpool -- if non-NULL: allocate from that rpool. 407 ** 408 ** Returns: 409 ** mci (new). 410 */ 411 412 MCI * 413 mci_new(rpool) 414 SM_RPOOL_T *rpool; 415 { 416 register MCI *mci; 417 418 if (rpool == NULL) 419 mci = (MCI *) sm_malloc_x(sizeof *mci); 420 else 421 mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof *mci); 422 memset((char *) mci, '\0', sizeof *mci); 423 mci->mci_rpool = sm_rpool_new_x(NULL); 424 mci->mci_macro.mac_rpool = mci->mci_rpool; 425 return mci; 426 } 427 /* 428 ** MCI_MATCH -- check connection cache for a particular host 429 ** 430 ** Parameters: 431 ** host -- host to look for. 432 ** m -- mailer. 433 ** 434 ** Returns: 435 ** true iff open connection exists. 436 */ 437 438 bool 439 mci_match(host, m) 440 char *host; 441 MAILER *m; 442 { 443 register MCI *mci; 444 register STAB *s; 445 446 if (m->m_mno < 0 || m->m_mno > MAXMAILERS) 447 return false; 448 s = stab(host, ST_MCI + m->m_mno, ST_FIND); 449 if (s == NULL) 450 return false; 451 452 mci = &s->s_mci; 453 return mci->mci_state == MCIS_OPEN; 454 } 455 /* 456 ** MCI_SETSTAT -- set status codes in MCI structure. 457 ** 458 ** Parameters: 459 ** mci -- the MCI structure to set. 460 ** xstat -- the exit status code. 461 ** dstat -- the DSN status code. 462 ** rstat -- the SMTP status code. 463 ** 464 ** Returns: 465 ** none. 466 */ 467 468 void 469 mci_setstat(mci, xstat, dstat, rstat) 470 MCI *mci; 471 int xstat; 472 char *dstat; 473 char *rstat; 474 { 475 /* protocol errors should never be interpreted as sticky */ 476 if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL) 477 mci->mci_exitstat = xstat; 478 479 SM_FREE_CLR(mci->mci_status); 480 if (dstat != NULL) 481 mci->mci_status = sm_strdup_x(dstat); 482 483 SM_FREE_CLR(mci->mci_rstatus); 484 if (rstat != NULL) 485 mci->mci_rstatus = sm_strdup_x(rstat); 486 } 487 /* 488 ** MCI_DUMP -- dump the contents of an MCI structure. 489 ** 490 ** Parameters: 491 ** mci -- the MCI structure to dump. 492 ** 493 ** Returns: 494 ** none. 495 ** 496 ** Side Effects: 497 ** none. 498 */ 499 500 struct mcifbits 501 { 502 int mcif_bit; /* flag bit */ 503 char *mcif_name; /* flag name */ 504 }; 505 static struct mcifbits MciFlags[] = 506 { 507 { MCIF_VALID, "VALID" }, 508 { MCIF_CACHED, "CACHED" }, 509 { MCIF_ESMTP, "ESMTP" }, 510 { MCIF_EXPN, "EXPN" }, 511 { MCIF_SIZE, "SIZE" }, 512 { MCIF_8BITMIME, "8BITMIME" }, 513 { MCIF_7BIT, "7BIT" }, 514 { MCIF_INHEADER, "INHEADER" }, 515 { MCIF_CVT8TO7, "CVT8TO7" }, 516 { MCIF_DSN, "DSN" }, 517 { MCIF_8BITOK, "8BITOK" }, 518 { MCIF_CVT7TO8, "CVT7TO8" }, 519 { MCIF_INMIME, "INMIME" }, 520 { MCIF_AUTH, "AUTH" }, 521 { MCIF_AUTHACT, "AUTHACT" }, 522 { MCIF_ENHSTAT, "ENHSTAT" }, 523 { MCIF_PIPELINED, "PIPELINED" }, 524 #if STARTTLS 525 { MCIF_TLS, "TLS" }, 526 { MCIF_TLSACT, "TLSACT" }, 527 #endif /* STARTTLS */ 528 { MCIF_DLVR_BY, "DLVR_BY" }, 529 { 0, NULL } 530 }; 531 532 void 533 mci_dump(mci, logit) 534 register MCI *mci; 535 bool logit; 536 { 537 register char *p; 538 char *sep; 539 char buf[4000]; 540 541 sep = logit ? " " : "\n\t"; 542 p = buf; 543 (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci); 544 p += strlen(p); 545 if (mci == NULL) 546 { 547 (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL"); 548 goto printit; 549 } 550 (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags); 551 p += strlen(p); 552 553 /* 554 ** The following check is just for paranoia. It protects the 555 ** assignment in the if() clause. If there's not some minimum 556 ** amount of space we can stop right now. The check will not 557 ** trigger as long as sizeof(buf)=4000. 558 */ 559 560 if (p >= buf + sizeof(buf) - 4) 561 goto printit; 562 if (mci->mci_flags != 0) 563 { 564 struct mcifbits *f; 565 566 *p++ = '<'; /* protected above */ 567 for (f = MciFlags; f->mcif_bit != 0; f++) 568 { 569 if (!bitset(f->mcif_bit, mci->mci_flags)) 570 continue; 571 (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2, 572 f->mcif_name, ","); 573 p += strlen(p); 574 } 575 p[-1] = '>'; 576 } 577 578 /* Note: sm_snprintf() takes care of NULL arguments for %s */ 579 (void) sm_snprintf(p, SPACELEFT(buf, p), 580 ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", 581 sep, mci->mci_errno, mci->mci_herrno, 582 mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep); 583 p += strlen(p); 584 (void) sm_snprintf(p, SPACELEFT(buf, p), 585 "maxsize=%ld, phase=%s, mailer=%s,%s", 586 mci->mci_maxsize, mci->mci_phase, 587 mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name, 588 sep); 589 p += strlen(p); 590 (void) sm_snprintf(p, SPACELEFT(buf, p), 591 "status=%s, rstatus=%s,%s", 592 mci->mci_status, mci->mci_rstatus, sep); 593 p += strlen(p); 594 (void) sm_snprintf(p, SPACELEFT(buf, p), 595 "host=%s, lastuse=%s", 596 mci->mci_host, ctime(&mci->mci_lastuse)); 597 printit: 598 if (logit) 599 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); 600 else 601 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", buf); 602 } 603 /* 604 ** MCI_DUMP_ALL -- print the entire MCI cache 605 ** 606 ** Parameters: 607 ** logit -- if set, log the result instead of printing 608 ** to stdout. 609 ** 610 ** Returns: 611 ** none. 612 */ 613 614 void 615 mci_dump_all(logit) 616 bool logit; 617 { 618 register int i; 619 620 if (MciCache == NULL) 621 return; 622 623 for (i = 0; i < MaxMciCache; i++) 624 mci_dump(MciCache[i], logit); 625 } 626 /* 627 ** MCI_LOCK_HOST -- Lock host while sending. 628 ** 629 ** If we are contacting a host, we'll need to 630 ** update the status information in the host status 631 ** file, and if we want to do that, we ought to have 632 ** locked it. This has the (according to some) 633 ** desirable effect of serializing connectivity with 634 ** remote hosts -- i.e.: one connection to a given 635 ** host at a time. 636 ** 637 ** Parameters: 638 ** mci -- containing the host we want to lock. 639 ** 640 ** Returns: 641 ** EX_OK -- got the lock. 642 ** EX_TEMPFAIL -- didn't get the lock. 643 */ 644 645 int 646 mci_lock_host(mci) 647 MCI *mci; 648 { 649 if (mci == NULL) 650 { 651 if (tTd(56, 1)) 652 sm_dprintf("mci_lock_host: NULL mci\n"); 653 return EX_OK; 654 } 655 656 if (!SingleThreadDelivery) 657 return EX_OK; 658 659 return mci_lock_host_statfile(mci); 660 } 661 662 static int 663 mci_lock_host_statfile(mci) 664 MCI *mci; 665 { 666 int save_errno = errno; 667 int retVal = EX_OK; 668 char fname[MAXPATHLEN]; 669 670 if (HostStatDir == NULL || mci->mci_host == NULL) 671 return EX_OK; 672 673 if (tTd(56, 2)) 674 sm_dprintf("mci_lock_host: attempting to lock %s\n", 675 mci->mci_host); 676 677 if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 678 true) < 0) 679 { 680 /* of course this should never happen */ 681 if (tTd(56, 2)) 682 sm_dprintf("mci_lock_host: Failed to generate host path for %s\n", 683 mci->mci_host); 684 685 retVal = EX_TEMPFAIL; 686 goto cleanup; 687 } 688 689 mci->mci_statfile = safefopen(fname, O_RDWR, FileMode, 690 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT); 691 692 if (mci->mci_statfile == NULL) 693 { 694 syserr("mci_lock_host: cannot create host lock file %s", fname); 695 goto cleanup; 696 } 697 698 if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 699 fname, "", LOCK_EX|LOCK_NB)) 700 { 701 if (tTd(56, 2)) 702 sm_dprintf("mci_lock_host: couldn't get lock on %s\n", 703 fname); 704 (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 705 mci->mci_statfile = NULL; 706 retVal = EX_TEMPFAIL; 707 goto cleanup; 708 } 709 710 if (tTd(56, 12) && mci->mci_statfile != NULL) 711 sm_dprintf("mci_lock_host: Sanity check -- lock is good\n"); 712 713 cleanup: 714 errno = save_errno; 715 return retVal; 716 } 717 /* 718 ** MCI_UNLOCK_HOST -- unlock host 719 ** 720 ** Clean up the lock on a host, close the file, let 721 ** someone else use it. 722 ** 723 ** Parameters: 724 ** mci -- us. 725 ** 726 ** Returns: 727 ** nothing. 728 */ 729 730 void 731 mci_unlock_host(mci) 732 MCI *mci; 733 { 734 int save_errno = errno; 735 736 if (mci == NULL) 737 { 738 if (tTd(56, 1)) 739 sm_dprintf("mci_unlock_host: NULL mci\n"); 740 return; 741 } 742 743 if (HostStatDir == NULL || mci->mci_host == NULL) 744 return; 745 746 if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) 747 { 748 if (tTd(56, 1)) 749 sm_dprintf("mci_unlock_host: stat file already locked\n"); 750 } 751 else 752 { 753 if (tTd(56, 2)) 754 sm_dprintf("mci_unlock_host: store prior to unlock\n"); 755 mci_store_persistent(mci); 756 } 757 758 if (mci->mci_statfile != NULL) 759 { 760 (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 761 mci->mci_statfile = NULL; 762 } 763 764 errno = save_errno; 765 } 766 /* 767 ** MCI_LOAD_PERSISTENT -- load persistent host info 768 ** 769 ** Load information about host that is kept 770 ** in common for all running sendmails. 771 ** 772 ** Parameters: 773 ** mci -- the host/connection to load persistent info for. 774 ** 775 ** Returns: 776 ** true -- lock was successful 777 ** false -- lock failed 778 */ 779 780 static bool 781 mci_load_persistent(mci) 782 MCI *mci; 783 { 784 int save_errno = errno; 785 bool locked = true; 786 SM_FILE_T *fp; 787 char fname[MAXPATHLEN]; 788 789 if (mci == NULL) 790 { 791 if (tTd(56, 1)) 792 sm_dprintf("mci_load_persistent: NULL mci\n"); 793 return true; 794 } 795 796 if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) 797 return true; 798 799 /* Already have the persistent information in memory */ 800 if (SingleThreadDelivery && mci->mci_statfile != NULL) 801 return true; 802 803 if (tTd(56, 1)) 804 sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n", 805 mci->mci_host); 806 807 if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 808 false) < 0) 809 { 810 /* Not much we can do if the file isn't there... */ 811 if (tTd(56, 1)) 812 sm_dprintf("mci_load_persistent: Couldn't generate host path\n"); 813 goto cleanup; 814 } 815 816 fp = safefopen(fname, O_RDONLY, FileMode, 817 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 818 if (fp == NULL) 819 { 820 /* I can't think of any reason this should ever happen */ 821 if (tTd(56, 1)) 822 sm_dprintf("mci_load_persistent: open(%s): %s\n", 823 fname, sm_errstring(errno)); 824 goto cleanup; 825 } 826 827 FileName = fname; 828 locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "", 829 LOCK_SH|LOCK_NB); 830 if (locked) 831 { 832 (void) mci_read_persistent(fp, mci); 833 (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, 834 "", LOCK_UN); 835 } 836 FileName = NULL; 837 (void) sm_io_close(fp, SM_TIME_DEFAULT); 838 839 cleanup: 840 errno = save_errno; 841 return locked; 842 } 843 /* 844 ** MCI_READ_PERSISTENT -- read persistent host status file 845 ** 846 ** Parameters: 847 ** fp -- the file pointer to read. 848 ** mci -- the pointer to fill in. 849 ** 850 ** Returns: 851 ** -1 -- if the file was corrupt. 852 ** 0 -- otherwise. 853 ** 854 ** Warning: 855 ** This code makes the assumption that this data 856 ** will be read in an atomic fashion, and that the data 857 ** was written in an atomic fashion. Any other functioning 858 ** may lead to some form of insanity. This should be 859 ** perfectly safe due to underlying stdio buffering. 860 */ 861 862 static int 863 mci_read_persistent(fp, mci) 864 SM_FILE_T *fp; 865 register MCI *mci; 866 { 867 int ver; 868 register char *p; 869 int saveLineNumber = LineNumber; 870 char buf[MAXLINE]; 871 872 if (fp == NULL) 873 syserr("mci_read_persistent: NULL fp"); 874 if (mci == NULL) 875 syserr("mci_read_persistent: NULL mci"); 876 if (tTd(56, 93)) 877 { 878 sm_dprintf("mci_read_persistent: fp=%lx, mci=", 879 (unsigned long) fp); 880 } 881 882 SM_FREE_CLR(mci->mci_status); 883 SM_FREE_CLR(mci->mci_rstatus); 884 885 sm_io_rewind(fp, SM_TIME_DEFAULT); 886 ver = -1; 887 LineNumber = 0; 888 while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 889 { 890 LineNumber++; 891 p = strchr(buf, '\n'); 892 if (p != NULL) 893 *p = '\0'; 894 switch (buf[0]) 895 { 896 case 'V': /* version stamp */ 897 ver = atoi(&buf[1]); 898 if (ver < 0 || ver > 0) 899 syserr("Unknown host status version %d: %d max", 900 ver, 0); 901 break; 902 903 case 'E': /* UNIX error number */ 904 mci->mci_errno = atoi(&buf[1]); 905 break; 906 907 case 'H': /* DNS error number */ 908 mci->mci_herrno = atoi(&buf[1]); 909 break; 910 911 case 'S': /* UNIX exit status */ 912 mci->mci_exitstat = atoi(&buf[1]); 913 break; 914 915 case 'D': /* DSN status */ 916 mci->mci_status = newstr(&buf[1]); 917 break; 918 919 case 'R': /* SMTP status */ 920 mci->mci_rstatus = newstr(&buf[1]); 921 break; 922 923 case 'U': /* last usage time */ 924 mci->mci_lastuse = atol(&buf[1]); 925 break; 926 927 case '.': /* end of file */ 928 if (tTd(56, 93)) 929 mci_dump(mci, false); 930 return 0; 931 932 default: 933 sm_syslog(LOG_CRIT, NOQID, 934 "%s: line %d: Unknown host status line \"%s\"", 935 FileName == NULL ? mci->mci_host : FileName, 936 LineNumber, buf); 937 LineNumber = saveLineNumber; 938 return -1; 939 } 940 } 941 LineNumber = saveLineNumber; 942 if (tTd(56, 93)) 943 sm_dprintf("incomplete (missing dot for EOF)\n"); 944 if (ver < 0) 945 return -1; 946 return 0; 947 } 948 /* 949 ** MCI_STORE_PERSISTENT -- Store persistent MCI information 950 ** 951 ** Store information about host that is kept 952 ** in common for all running sendmails. 953 ** 954 ** Parameters: 955 ** mci -- the host/connection to store persistent info for. 956 ** 957 ** Returns: 958 ** none. 959 */ 960 961 void 962 mci_store_persistent(mci) 963 MCI *mci; 964 { 965 int save_errno = errno; 966 967 if (mci == NULL) 968 { 969 if (tTd(56, 1)) 970 sm_dprintf("mci_store_persistent: NULL mci\n"); 971 return; 972 } 973 974 if (HostStatDir == NULL || mci->mci_host == NULL) 975 return; 976 977 if (tTd(56, 1)) 978 sm_dprintf("mci_store_persistent: Storing information for %s\n", 979 mci->mci_host); 980 981 if (mci->mci_statfile == NULL) 982 { 983 if (tTd(56, 1)) 984 sm_dprintf("mci_store_persistent: no statfile\n"); 985 return; 986 } 987 988 sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT); 989 #if !NOFTRUNCATE 990 (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 991 (off_t) 0); 992 #endif /* !NOFTRUNCATE */ 993 994 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n"); 995 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n", 996 mci->mci_errno); 997 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n", 998 mci->mci_herrno); 999 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n", 1000 mci->mci_exitstat); 1001 if (mci->mci_status != NULL) 1002 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 1003 "D%.80s\n", 1004 denlstring(mci->mci_status, true, false)); 1005 if (mci->mci_rstatus != NULL) 1006 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 1007 "R%.80s\n", 1008 denlstring(mci->mci_rstatus, true, false)); 1009 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n", 1010 (long)(mci->mci_lastuse)); 1011 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n"); 1012 1013 (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT); 1014 1015 errno = save_errno; 1016 return; 1017 } 1018 /* 1019 ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree 1020 ** 1021 ** Recursively find all the mci host files in `pathname'. Default to 1022 ** main host status directory if no path is provided. 1023 ** Call (*action)(pathname, host) for each file found. 1024 ** 1025 ** Note: all information is collected in a list before it is processed. 1026 ** This may not be the best way to do it, but it seems safest, since 1027 ** the file system would be touched while we are attempting to traverse 1028 ** the directory tree otherwise (during purges). 1029 ** 1030 ** Parameters: 1031 ** action -- function to call on each node. If returns < 0, 1032 ** return immediately. 1033 ** pathname -- root of tree. If null, use main host status 1034 ** directory. 1035 ** 1036 ** Returns: 1037 ** < 0 -- if any action routine returns a negative value, that 1038 ** value is returned. 1039 ** 0 -- if we successfully went to completion. 1040 ** > 0 -- return status from action() 1041 */ 1042 1043 int 1044 mci_traverse_persistent(action, pathname) 1045 int (*action)(); 1046 char *pathname; 1047 { 1048 struct stat statbuf; 1049 DIR *d; 1050 int ret; 1051 1052 if (pathname == NULL) 1053 pathname = HostStatDir; 1054 if (pathname == NULL) 1055 return -1; 1056 1057 if (tTd(56, 1)) 1058 sm_dprintf("mci_traverse: pathname is %s\n", pathname); 1059 1060 ret = stat(pathname, &statbuf); 1061 if (ret < 0) 1062 { 1063 if (tTd(56, 2)) 1064 sm_dprintf("mci_traverse: Failed to stat %s: %s\n", 1065 pathname, sm_errstring(errno)); 1066 return ret; 1067 } 1068 if (S_ISDIR(statbuf.st_mode)) 1069 { 1070 bool leftone, removedone; 1071 size_t len; 1072 char *newptr; 1073 struct dirent *e; 1074 char newpath[MAXPATHLEN]; 1075 1076 if ((d = opendir(pathname)) == NULL) 1077 { 1078 if (tTd(56, 2)) 1079 sm_dprintf("mci_traverse: opendir %s: %s\n", 1080 pathname, sm_errstring(errno)); 1081 return -1; 1082 } 1083 len = sizeof(newpath) - MAXNAMLEN - 3; 1084 if (sm_strlcpy(newpath, pathname, len) >= len) 1085 { 1086 if (tTd(56, 2)) 1087 sm_dprintf("mci_traverse: path \"%s\" too long", 1088 pathname); 1089 return -1; 1090 } 1091 newptr = newpath + strlen(newpath); 1092 *newptr++ = '/'; 1093 1094 /* 1095 ** repeat until no file has been removed 1096 ** this may become ugly when several files "expire" 1097 ** during these loops, but it's better than doing 1098 ** a rewinddir() inside the inner loop 1099 */ 1100 1101 do 1102 { 1103 leftone = removedone = false; 1104 while ((e = readdir(d)) != NULL) 1105 { 1106 if (e->d_name[0] == '.') 1107 continue; 1108 1109 (void) sm_strlcpy(newptr, e->d_name, 1110 sizeof newpath - 1111 (newptr - newpath)); 1112 1113 if (StopRequest) 1114 stop_sendmail(); 1115 ret = mci_traverse_persistent(action, newpath); 1116 if (ret < 0) 1117 break; 1118 if (ret == 1) 1119 leftone = true; 1120 if (!removedone && ret == 0 && 1121 action == mci_purge_persistent) 1122 removedone = true; 1123 } 1124 if (ret < 0) 1125 break; 1126 1127 /* 1128 ** The following appears to be 1129 ** necessary during purges, since 1130 ** we modify the directory structure 1131 */ 1132 1133 if (removedone) 1134 rewinddir(d); 1135 if (tTd(56, 40)) 1136 sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 1137 pathname, ret, removedone, leftone); 1138 } while (removedone); 1139 1140 /* purge (or whatever) the directory proper */ 1141 if (!leftone) 1142 { 1143 *--newptr = '\0'; 1144 ret = (*action)(newpath, NULL); 1145 } 1146 (void) closedir(d); 1147 } 1148 else if (S_ISREG(statbuf.st_mode)) 1149 { 1150 char *end = pathname + strlen(pathname) - 1; 1151 char *start; 1152 char *scan; 1153 char host[MAXHOSTNAMELEN]; 1154 char *hostptr = host; 1155 1156 /* 1157 ** Reconstruct the host name from the path to the 1158 ** persistent information. 1159 */ 1160 1161 do 1162 { 1163 if (hostptr != host) 1164 *(hostptr++) = '.'; 1165 start = end; 1166 while (start > pathname && *(start - 1) != '/') 1167 start--; 1168 1169 if (*end == '.') 1170 end--; 1171 1172 for (scan = start; scan <= end; scan++) 1173 *(hostptr++) = *scan; 1174 1175 end = start - 2; 1176 } while (end > pathname && *end == '.'); 1177 1178 *hostptr = '\0'; 1179 1180 /* 1181 ** Do something with the file containing the persistent 1182 ** information. 1183 */ 1184 1185 ret = (*action)(pathname, host); 1186 } 1187 1188 return ret; 1189 } 1190 /* 1191 ** MCI_PRINT_PERSISTENT -- print persistent info 1192 ** 1193 ** Dump the persistent information in the file 'pathname' 1194 ** 1195 ** Parameters: 1196 ** pathname -- the pathname to the status file. 1197 ** hostname -- the corresponding host name. 1198 ** 1199 ** Returns: 1200 ** 0 1201 */ 1202 1203 int 1204 mci_print_persistent(pathname, hostname) 1205 char *pathname; 1206 char *hostname; 1207 { 1208 static bool initflag = false; 1209 SM_FILE_T *fp; 1210 int width = Verbose ? 78 : 25; 1211 bool locked; 1212 MCI mcib; 1213 1214 /* skip directories */ 1215 if (hostname == NULL) 1216 return 0; 1217 1218 if (StopRequest) 1219 stop_sendmail(); 1220 1221 if (!initflag) 1222 { 1223 initflag = true; 1224 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1225 " -------------- Hostname --------------- How long ago ---------Results---------\n"); 1226 } 1227 1228 fp = safefopen(pathname, O_RDONLY, FileMode, 1229 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 1230 1231 if (fp == NULL) 1232 { 1233 if (tTd(56, 1)) 1234 sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 1235 pathname, sm_errstring(errno)); 1236 return 0; 1237 } 1238 1239 FileName = pathname; 1240 memset(&mcib, '\0', sizeof mcib); 1241 if (mci_read_persistent(fp, &mcib) < 0) 1242 { 1243 syserr("%s: could not read status file", pathname); 1244 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1245 FileName = NULL; 1246 return 0; 1247 } 1248 1249 locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 1250 "", LOCK_SH|LOCK_NB); 1251 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1252 FileName = NULL; 1253 1254 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 1255 locked ? '*' : ' ', hostname, 1256 pintvl(curtime() - mcib.mci_lastuse, true)); 1257 if (mcib.mci_rstatus != NULL) 1258 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 1259 mcib.mci_rstatus); 1260 else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 1261 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1262 "Deferred: %.*s\n", width - 10, 1263 sm_errstring(mcib.mci_errno)); 1264 else if (mcib.mci_exitstat != 0) 1265 { 1266 char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 1267 1268 if (exmsg == NULL) 1269 { 1270 char buf[80]; 1271 1272 (void) sm_snprintf(buf, sizeof buf, 1273 "Unknown mailer error %d", 1274 mcib.mci_exitstat); 1275 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 1276 width, buf); 1277 } 1278 else 1279 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 1280 width, &exmsg[5]); 1281 } 1282 else if (mcib.mci_errno == 0) 1283 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 1284 else 1285 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 1286 width - 4, sm_errstring(mcib.mci_errno)); 1287 1288 return 0; 1289 } 1290 /* 1291 ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 1292 ** 1293 ** Parameters: 1294 ** pathname -- path to the status file. 1295 ** hostname -- name of host corresponding to that file. 1296 ** NULL if this is a directory (domain). 1297 ** 1298 ** Returns: 1299 ** 0 -- ok 1300 ** 1 -- file not deleted (too young, incorrect format) 1301 ** < 0 -- some error occurred 1302 */ 1303 1304 int 1305 mci_purge_persistent(pathname, hostname) 1306 char *pathname; 1307 char *hostname; 1308 { 1309 struct stat statbuf; 1310 char *end = pathname + strlen(pathname) - 1; 1311 int ret; 1312 1313 if (tTd(56, 1)) 1314 sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 1315 1316 ret = stat(pathname, &statbuf); 1317 if (ret < 0) 1318 { 1319 if (tTd(56, 2)) 1320 sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 1321 pathname, sm_errstring(errno)); 1322 return ret; 1323 } 1324 if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 1325 return 1; 1326 if (hostname != NULL) 1327 { 1328 /* remove the file */ 1329 ret = unlink(pathname); 1330 if (ret < 0) 1331 { 1332 if (LogLevel > 8) 1333 sm_syslog(LOG_ERR, NOQID, 1334 "mci_purge_persistent: failed to unlink %s: %s", 1335 pathname, sm_errstring(errno)); 1336 if (tTd(56, 2)) 1337 sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 1338 pathname, sm_errstring(errno)); 1339 return ret; 1340 } 1341 } 1342 else 1343 { 1344 /* remove the directory */ 1345 if (*end != '.') 1346 return 1; 1347 1348 if (tTd(56, 1)) 1349 sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 1350 1351 ret = rmdir(pathname); 1352 if (ret < 0) 1353 { 1354 if (tTd(56, 2)) 1355 sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 1356 pathname, sm_errstring(errno)); 1357 return ret; 1358 } 1359 } 1360 1361 return 0; 1362 } 1363 /* 1364 ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 1365 ** 1366 ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 1367 ** putting the result into `path'. if `createflag' is set, intervening 1368 ** directories will be created as needed. 1369 ** 1370 ** Parameters: 1371 ** host -- host name to convert from. 1372 ** path -- place to store result. 1373 ** pathlen -- length of path buffer. 1374 ** createflag -- if set, create intervening directories as 1375 ** needed. 1376 ** 1377 ** Returns: 1378 ** 0 -- success 1379 ** -1 -- failure 1380 */ 1381 1382 static int 1383 mci_generate_persistent_path(host, path, pathlen, createflag) 1384 const char *host; 1385 char *path; 1386 int pathlen; 1387 bool createflag; 1388 { 1389 char *elem, *p, *x, ch; 1390 int ret = 0; 1391 int len; 1392 char t_host[MAXHOSTNAMELEN]; 1393 #if NETINET6 1394 struct in6_addr in6_addr; 1395 #endif /* NETINET6 */ 1396 1397 /* 1398 ** Rationality check the arguments. 1399 */ 1400 1401 if (host == NULL) 1402 { 1403 syserr("mci_generate_persistent_path: null host"); 1404 return -1; 1405 } 1406 if (path == NULL) 1407 { 1408 syserr("mci_generate_persistent_path: null path"); 1409 return -1; 1410 } 1411 1412 if (tTd(56, 80)) 1413 sm_dprintf("mci_generate_persistent_path(%s): ", host); 1414 1415 if (*host == '\0' || *host == '.') 1416 return -1; 1417 1418 /* make certain this is not a bracketed host number */ 1419 if (strlen(host) > sizeof t_host - 1) 1420 return -1; 1421 if (host[0] == '[') 1422 (void) sm_strlcpy(t_host, host + 1, sizeof t_host); 1423 else 1424 (void) sm_strlcpy(t_host, host, sizeof t_host); 1425 1426 /* 1427 ** Delete any trailing dots from the hostname. 1428 ** Leave 'elem' pointing at the \0. 1429 */ 1430 1431 elem = t_host + strlen(t_host); 1432 while (elem > t_host && 1433 (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 1434 *--elem = '\0'; 1435 1436 /* check for bogus bracketed address */ 1437 if (host[0] == '[') 1438 { 1439 bool good = false; 1440 # if NETINET6 1441 if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 1442 good = true; 1443 # endif /* NETINET6 */ 1444 # if NETINET 1445 if (inet_addr(t_host) != INADDR_NONE) 1446 good = true; 1447 # endif /* NETINET */ 1448 if (!good) 1449 return -1; 1450 } 1451 1452 /* check for what will be the final length of the path */ 1453 len = strlen(HostStatDir) + 2; 1454 for (p = (char *) t_host; *p != '\0'; p++) 1455 { 1456 if (*p == '.') 1457 len++; 1458 len++; 1459 if (p[0] == '.' && p[1] == '.') 1460 return -1; 1461 } 1462 if (len > pathlen || len < 1) 1463 return -1; 1464 (void) sm_strlcpy(path, HostStatDir, pathlen); 1465 p = path + strlen(path); 1466 while (elem > t_host) 1467 { 1468 if (!path_is_dir(path, createflag)) 1469 { 1470 ret = -1; 1471 break; 1472 } 1473 elem--; 1474 while (elem >= t_host && *elem != '.') 1475 elem--; 1476 *p++ = '/'; 1477 x = elem + 1; 1478 while ((ch = *x++) != '\0' && ch != '.') 1479 { 1480 if (isascii(ch) && isupper(ch)) 1481 ch = tolower(ch); 1482 if (ch == '/') 1483 ch = ':'; /* / -> : */ 1484 *p++ = ch; 1485 } 1486 if (elem >= t_host) 1487 *p++ = '.'; 1488 *p = '\0'; 1489 } 1490 if (tTd(56, 80)) 1491 { 1492 if (ret < 0) 1493 sm_dprintf("FAILURE %d\n", ret); 1494 else 1495 sm_dprintf("SUCCESS %s\n", path); 1496 } 1497 return ret; 1498 } 1499