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