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.211 2003/03/31 17:35:50 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 ** fp -- output file pointer 492 ** mci -- the MCI structure to dump. 493 ** 494 ** Returns: 495 ** none. 496 ** 497 ** Side Effects: 498 ** none. 499 */ 500 501 struct mcifbits 502 { 503 int mcif_bit; /* flag bit */ 504 char *mcif_name; /* flag name */ 505 }; 506 static struct mcifbits MciFlags[] = 507 { 508 { MCIF_VALID, "VALID" }, 509 { MCIF_CACHED, "CACHED" }, 510 { MCIF_ESMTP, "ESMTP" }, 511 { MCIF_EXPN, "EXPN" }, 512 { MCIF_SIZE, "SIZE" }, 513 { MCIF_8BITMIME, "8BITMIME" }, 514 { MCIF_7BIT, "7BIT" }, 515 { MCIF_INHEADER, "INHEADER" }, 516 { MCIF_CVT8TO7, "CVT8TO7" }, 517 { MCIF_DSN, "DSN" }, 518 { MCIF_8BITOK, "8BITOK" }, 519 { MCIF_CVT7TO8, "CVT7TO8" }, 520 { MCIF_INMIME, "INMIME" }, 521 { MCIF_AUTH, "AUTH" }, 522 { MCIF_AUTHACT, "AUTHACT" }, 523 { MCIF_ENHSTAT, "ENHSTAT" }, 524 { MCIF_PIPELINED, "PIPELINED" }, 525 #if STARTTLS 526 { MCIF_TLS, "TLS" }, 527 { MCIF_TLSACT, "TLSACT" }, 528 #endif /* STARTTLS */ 529 { MCIF_DLVR_BY, "DLVR_BY" }, 530 { 0, NULL } 531 }; 532 533 void 534 mci_dump(fp, mci, logit) 535 SM_FILE_T *fp; 536 register MCI *mci; 537 bool logit; 538 { 539 register char *p; 540 char *sep; 541 char buf[4000]; 542 543 sep = logit ? " " : "\n\t"; 544 p = buf; 545 (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci); 546 p += strlen(p); 547 if (mci == NULL) 548 { 549 (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL"); 550 goto printit; 551 } 552 (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags); 553 p += strlen(p); 554 555 /* 556 ** The following check is just for paranoia. It protects the 557 ** assignment in the if() clause. If there's not some minimum 558 ** amount of space we can stop right now. The check will not 559 ** trigger as long as sizeof(buf)=4000. 560 */ 561 562 if (p >= buf + sizeof(buf) - 4) 563 goto printit; 564 if (mci->mci_flags != 0) 565 { 566 struct mcifbits *f; 567 568 *p++ = '<'; /* protected above */ 569 for (f = MciFlags; f->mcif_bit != 0; f++) 570 { 571 if (!bitset(f->mcif_bit, mci->mci_flags)) 572 continue; 573 (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2, 574 f->mcif_name, ","); 575 p += strlen(p); 576 } 577 p[-1] = '>'; 578 } 579 580 /* Note: sm_snprintf() takes care of NULL arguments for %s */ 581 (void) sm_snprintf(p, SPACELEFT(buf, p), 582 ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", 583 sep, mci->mci_errno, mci->mci_herrno, 584 mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep); 585 p += strlen(p); 586 (void) sm_snprintf(p, SPACELEFT(buf, p), 587 "maxsize=%ld, phase=%s, mailer=%s,%s", 588 mci->mci_maxsize, mci->mci_phase, 589 mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name, 590 sep); 591 p += strlen(p); 592 (void) sm_snprintf(p, SPACELEFT(buf, p), 593 "status=%s, rstatus=%s,%s", 594 mci->mci_status, mci->mci_rstatus, sep); 595 p += strlen(p); 596 (void) sm_snprintf(p, SPACELEFT(buf, p), 597 "host=%s, lastuse=%s", 598 mci->mci_host, ctime(&mci->mci_lastuse)); 599 printit: 600 if (logit) 601 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); 602 else 603 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf); 604 } 605 /* 606 ** MCI_DUMP_ALL -- print the entire MCI cache 607 ** 608 ** Parameters: 609 ** fp -- output file pointer 610 ** logit -- if set, log the result instead of printing 611 ** to stdout. 612 ** 613 ** Returns: 614 ** none. 615 */ 616 617 void 618 mci_dump_all(fp, logit) 619 SM_FILE_T *fp; 620 bool logit; 621 { 622 register int i; 623 624 if (MciCache == NULL) 625 return; 626 627 for (i = 0; i < MaxMciCache; i++) 628 mci_dump(fp, MciCache[i], logit); 629 } 630 /* 631 ** MCI_LOCK_HOST -- Lock host while sending. 632 ** 633 ** If we are contacting a host, we'll need to 634 ** update the status information in the host status 635 ** file, and if we want to do that, we ought to have 636 ** locked it. This has the (according to some) 637 ** desirable effect of serializing connectivity with 638 ** remote hosts -- i.e.: one connection to a given 639 ** host at a time. 640 ** 641 ** Parameters: 642 ** mci -- containing the host we want to lock. 643 ** 644 ** Returns: 645 ** EX_OK -- got the lock. 646 ** EX_TEMPFAIL -- didn't get the lock. 647 */ 648 649 int 650 mci_lock_host(mci) 651 MCI *mci; 652 { 653 if (mci == NULL) 654 { 655 if (tTd(56, 1)) 656 sm_dprintf("mci_lock_host: NULL mci\n"); 657 return EX_OK; 658 } 659 660 if (!SingleThreadDelivery) 661 return EX_OK; 662 663 return mci_lock_host_statfile(mci); 664 } 665 666 static int 667 mci_lock_host_statfile(mci) 668 MCI *mci; 669 { 670 int save_errno = errno; 671 int retVal = EX_OK; 672 char fname[MAXPATHLEN]; 673 674 if (HostStatDir == NULL || mci->mci_host == NULL) 675 return EX_OK; 676 677 if (tTd(56, 2)) 678 sm_dprintf("mci_lock_host: attempting to lock %s\n", 679 mci->mci_host); 680 681 if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 682 true) < 0) 683 { 684 /* of course this should never happen */ 685 if (tTd(56, 2)) 686 sm_dprintf("mci_lock_host: Failed to generate host path for %s\n", 687 mci->mci_host); 688 689 retVal = EX_TEMPFAIL; 690 goto cleanup; 691 } 692 693 mci->mci_statfile = safefopen(fname, O_RDWR, FileMode, 694 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT); 695 696 if (mci->mci_statfile == NULL) 697 { 698 syserr("mci_lock_host: cannot create host lock file %s", fname); 699 goto cleanup; 700 } 701 702 if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 703 fname, "", LOCK_EX|LOCK_NB)) 704 { 705 if (tTd(56, 2)) 706 sm_dprintf("mci_lock_host: couldn't get lock on %s\n", 707 fname); 708 (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 709 mci->mci_statfile = NULL; 710 retVal = EX_TEMPFAIL; 711 goto cleanup; 712 } 713 714 if (tTd(56, 12) && mci->mci_statfile != NULL) 715 sm_dprintf("mci_lock_host: Sanity check -- lock is good\n"); 716 717 cleanup: 718 errno = save_errno; 719 return retVal; 720 } 721 /* 722 ** MCI_UNLOCK_HOST -- unlock host 723 ** 724 ** Clean up the lock on a host, close the file, let 725 ** someone else use it. 726 ** 727 ** Parameters: 728 ** mci -- us. 729 ** 730 ** Returns: 731 ** nothing. 732 */ 733 734 void 735 mci_unlock_host(mci) 736 MCI *mci; 737 { 738 int save_errno = errno; 739 740 if (mci == NULL) 741 { 742 if (tTd(56, 1)) 743 sm_dprintf("mci_unlock_host: NULL mci\n"); 744 return; 745 } 746 747 if (HostStatDir == NULL || mci->mci_host == NULL) 748 return; 749 750 if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) 751 { 752 if (tTd(56, 1)) 753 sm_dprintf("mci_unlock_host: stat file already locked\n"); 754 } 755 else 756 { 757 if (tTd(56, 2)) 758 sm_dprintf("mci_unlock_host: store prior to unlock\n"); 759 mci_store_persistent(mci); 760 } 761 762 if (mci->mci_statfile != NULL) 763 { 764 (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 765 mci->mci_statfile = NULL; 766 } 767 768 errno = save_errno; 769 } 770 /* 771 ** MCI_LOAD_PERSISTENT -- load persistent host info 772 ** 773 ** Load information about host that is kept 774 ** in common for all running sendmails. 775 ** 776 ** Parameters: 777 ** mci -- the host/connection to load persistent info for. 778 ** 779 ** Returns: 780 ** true -- lock was successful 781 ** false -- lock failed 782 */ 783 784 static bool 785 mci_load_persistent(mci) 786 MCI *mci; 787 { 788 int save_errno = errno; 789 bool locked = true; 790 SM_FILE_T *fp; 791 char fname[MAXPATHLEN]; 792 793 if (mci == NULL) 794 { 795 if (tTd(56, 1)) 796 sm_dprintf("mci_load_persistent: NULL mci\n"); 797 return true; 798 } 799 800 if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) 801 return true; 802 803 /* Already have the persistent information in memory */ 804 if (SingleThreadDelivery && mci->mci_statfile != NULL) 805 return true; 806 807 if (tTd(56, 1)) 808 sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n", 809 mci->mci_host); 810 811 if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 812 false) < 0) 813 { 814 /* Not much we can do if the file isn't there... */ 815 if (tTd(56, 1)) 816 sm_dprintf("mci_load_persistent: Couldn't generate host path\n"); 817 goto cleanup; 818 } 819 820 fp = safefopen(fname, O_RDONLY, FileMode, 821 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 822 if (fp == NULL) 823 { 824 /* I can't think of any reason this should ever happen */ 825 if (tTd(56, 1)) 826 sm_dprintf("mci_load_persistent: open(%s): %s\n", 827 fname, sm_errstring(errno)); 828 goto cleanup; 829 } 830 831 FileName = fname; 832 locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "", 833 LOCK_SH|LOCK_NB); 834 if (locked) 835 { 836 (void) mci_read_persistent(fp, mci); 837 (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, 838 "", LOCK_UN); 839 } 840 FileName = NULL; 841 (void) sm_io_close(fp, SM_TIME_DEFAULT); 842 843 cleanup: 844 errno = save_errno; 845 return locked; 846 } 847 /* 848 ** MCI_READ_PERSISTENT -- read persistent host status file 849 ** 850 ** Parameters: 851 ** fp -- the file pointer to read. 852 ** mci -- the pointer to fill in. 853 ** 854 ** Returns: 855 ** -1 -- if the file was corrupt. 856 ** 0 -- otherwise. 857 ** 858 ** Warning: 859 ** This code makes the assumption that this data 860 ** will be read in an atomic fashion, and that the data 861 ** was written in an atomic fashion. Any other functioning 862 ** may lead to some form of insanity. This should be 863 ** perfectly safe due to underlying stdio buffering. 864 */ 865 866 static int 867 mci_read_persistent(fp, mci) 868 SM_FILE_T *fp; 869 register MCI *mci; 870 { 871 int ver; 872 register char *p; 873 int saveLineNumber = LineNumber; 874 char buf[MAXLINE]; 875 876 if (fp == NULL) 877 syserr("mci_read_persistent: NULL fp"); 878 if (mci == NULL) 879 syserr("mci_read_persistent: NULL mci"); 880 if (tTd(56, 93)) 881 { 882 sm_dprintf("mci_read_persistent: fp=%lx, mci=", 883 (unsigned long) fp); 884 } 885 886 SM_FREE_CLR(mci->mci_status); 887 SM_FREE_CLR(mci->mci_rstatus); 888 889 sm_io_rewind(fp, SM_TIME_DEFAULT); 890 ver = -1; 891 LineNumber = 0; 892 while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 893 { 894 LineNumber++; 895 p = strchr(buf, '\n'); 896 if (p != NULL) 897 *p = '\0'; 898 switch (buf[0]) 899 { 900 case 'V': /* version stamp */ 901 ver = atoi(&buf[1]); 902 if (ver < 0 || ver > 0) 903 syserr("Unknown host status version %d: %d max", 904 ver, 0); 905 break; 906 907 case 'E': /* UNIX error number */ 908 mci->mci_errno = atoi(&buf[1]); 909 break; 910 911 case 'H': /* DNS error number */ 912 mci->mci_herrno = atoi(&buf[1]); 913 break; 914 915 case 'S': /* UNIX exit status */ 916 mci->mci_exitstat = atoi(&buf[1]); 917 break; 918 919 case 'D': /* DSN status */ 920 mci->mci_status = newstr(&buf[1]); 921 break; 922 923 case 'R': /* SMTP status */ 924 mci->mci_rstatus = newstr(&buf[1]); 925 break; 926 927 case 'U': /* last usage time */ 928 mci->mci_lastuse = atol(&buf[1]); 929 break; 930 931 case '.': /* end of file */ 932 if (tTd(56, 93)) 933 mci_dump(sm_debug_file(), mci, false); 934 return 0; 935 936 default: 937 sm_syslog(LOG_CRIT, NOQID, 938 "%s: line %d: Unknown host status line \"%s\"", 939 FileName == NULL ? mci->mci_host : FileName, 940 LineNumber, buf); 941 LineNumber = saveLineNumber; 942 return -1; 943 } 944 } 945 LineNumber = saveLineNumber; 946 if (tTd(56, 93)) 947 sm_dprintf("incomplete (missing dot for EOF)\n"); 948 if (ver < 0) 949 return -1; 950 return 0; 951 } 952 /* 953 ** MCI_STORE_PERSISTENT -- Store persistent MCI information 954 ** 955 ** Store information about host that is kept 956 ** in common for all running sendmails. 957 ** 958 ** Parameters: 959 ** mci -- the host/connection to store persistent info for. 960 ** 961 ** Returns: 962 ** none. 963 */ 964 965 void 966 mci_store_persistent(mci) 967 MCI *mci; 968 { 969 int save_errno = errno; 970 971 if (mci == NULL) 972 { 973 if (tTd(56, 1)) 974 sm_dprintf("mci_store_persistent: NULL mci\n"); 975 return; 976 } 977 978 if (HostStatDir == NULL || mci->mci_host == NULL) 979 return; 980 981 if (tTd(56, 1)) 982 sm_dprintf("mci_store_persistent: Storing information for %s\n", 983 mci->mci_host); 984 985 if (mci->mci_statfile == NULL) 986 { 987 if (tTd(56, 1)) 988 sm_dprintf("mci_store_persistent: no statfile\n"); 989 return; 990 } 991 992 sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT); 993 #if !NOFTRUNCATE 994 (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 995 (off_t) 0); 996 #endif /* !NOFTRUNCATE */ 997 998 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n"); 999 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n", 1000 mci->mci_errno); 1001 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n", 1002 mci->mci_herrno); 1003 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n", 1004 mci->mci_exitstat); 1005 if (mci->mci_status != NULL) 1006 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 1007 "D%.80s\n", 1008 denlstring(mci->mci_status, true, false)); 1009 if (mci->mci_rstatus != NULL) 1010 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 1011 "R%.80s\n", 1012 denlstring(mci->mci_rstatus, true, false)); 1013 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n", 1014 (long)(mci->mci_lastuse)); 1015 (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n"); 1016 1017 (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT); 1018 1019 errno = save_errno; 1020 return; 1021 } 1022 /* 1023 ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree 1024 ** 1025 ** Recursively find all the mci host files in `pathname'. Default to 1026 ** main host status directory if no path is provided. 1027 ** Call (*action)(pathname, host) for each file found. 1028 ** 1029 ** Note: all information is collected in a list before it is processed. 1030 ** This may not be the best way to do it, but it seems safest, since 1031 ** the file system would be touched while we are attempting to traverse 1032 ** the directory tree otherwise (during purges). 1033 ** 1034 ** Parameters: 1035 ** action -- function to call on each node. If returns < 0, 1036 ** return immediately. 1037 ** pathname -- root of tree. If null, use main host status 1038 ** directory. 1039 ** 1040 ** Returns: 1041 ** < 0 -- if any action routine returns a negative value, that 1042 ** value is returned. 1043 ** 0 -- if we successfully went to completion. 1044 ** > 0 -- return status from action() 1045 */ 1046 1047 int 1048 mci_traverse_persistent(action, pathname) 1049 int (*action)(); 1050 char *pathname; 1051 { 1052 struct stat statbuf; 1053 DIR *d; 1054 int ret; 1055 1056 if (pathname == NULL) 1057 pathname = HostStatDir; 1058 if (pathname == NULL) 1059 return -1; 1060 1061 if (tTd(56, 1)) 1062 sm_dprintf("mci_traverse: pathname is %s\n", pathname); 1063 1064 ret = stat(pathname, &statbuf); 1065 if (ret < 0) 1066 { 1067 if (tTd(56, 2)) 1068 sm_dprintf("mci_traverse: Failed to stat %s: %s\n", 1069 pathname, sm_errstring(errno)); 1070 return ret; 1071 } 1072 if (S_ISDIR(statbuf.st_mode)) 1073 { 1074 bool leftone, removedone; 1075 size_t len; 1076 char *newptr; 1077 struct dirent *e; 1078 char newpath[MAXPATHLEN]; 1079 1080 if ((d = opendir(pathname)) == NULL) 1081 { 1082 if (tTd(56, 2)) 1083 sm_dprintf("mci_traverse: opendir %s: %s\n", 1084 pathname, sm_errstring(errno)); 1085 return -1; 1086 } 1087 len = sizeof(newpath) - MAXNAMLEN - 3; 1088 if (sm_strlcpy(newpath, pathname, len) >= len) 1089 { 1090 if (tTd(56, 2)) 1091 sm_dprintf("mci_traverse: path \"%s\" too long", 1092 pathname); 1093 return -1; 1094 } 1095 newptr = newpath + strlen(newpath); 1096 *newptr++ = '/'; 1097 1098 /* 1099 ** repeat until no file has been removed 1100 ** this may become ugly when several files "expire" 1101 ** during these loops, but it's better than doing 1102 ** a rewinddir() inside the inner loop 1103 */ 1104 1105 do 1106 { 1107 leftone = removedone = false; 1108 while ((e = readdir(d)) != NULL) 1109 { 1110 if (e->d_name[0] == '.') 1111 continue; 1112 1113 (void) sm_strlcpy(newptr, e->d_name, 1114 sizeof newpath - 1115 (newptr - newpath)); 1116 1117 if (StopRequest) 1118 stop_sendmail(); 1119 ret = mci_traverse_persistent(action, newpath); 1120 if (ret < 0) 1121 break; 1122 if (ret == 1) 1123 leftone = true; 1124 if (!removedone && ret == 0 && 1125 action == mci_purge_persistent) 1126 removedone = true; 1127 } 1128 if (ret < 0) 1129 break; 1130 1131 /* 1132 ** The following appears to be 1133 ** necessary during purges, since 1134 ** we modify the directory structure 1135 */ 1136 1137 if (removedone) 1138 rewinddir(d); 1139 if (tTd(56, 40)) 1140 sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 1141 pathname, ret, removedone, leftone); 1142 } while (removedone); 1143 1144 /* purge (or whatever) the directory proper */ 1145 if (!leftone) 1146 { 1147 *--newptr = '\0'; 1148 ret = (*action)(newpath, NULL); 1149 } 1150 (void) closedir(d); 1151 } 1152 else if (S_ISREG(statbuf.st_mode)) 1153 { 1154 char *end = pathname + strlen(pathname) - 1; 1155 char *start; 1156 char *scan; 1157 char host[MAXHOSTNAMELEN]; 1158 char *hostptr = host; 1159 1160 /* 1161 ** Reconstruct the host name from the path to the 1162 ** persistent information. 1163 */ 1164 1165 do 1166 { 1167 if (hostptr != host) 1168 *(hostptr++) = '.'; 1169 start = end; 1170 while (start > pathname && *(start - 1) != '/') 1171 start--; 1172 1173 if (*end == '.') 1174 end--; 1175 1176 for (scan = start; scan <= end; scan++) 1177 *(hostptr++) = *scan; 1178 1179 end = start - 2; 1180 } while (end > pathname && *end == '.'); 1181 1182 *hostptr = '\0'; 1183 1184 /* 1185 ** Do something with the file containing the persistent 1186 ** information. 1187 */ 1188 1189 ret = (*action)(pathname, host); 1190 } 1191 1192 return ret; 1193 } 1194 /* 1195 ** MCI_PRINT_PERSISTENT -- print persistent info 1196 ** 1197 ** Dump the persistent information in the file 'pathname' 1198 ** 1199 ** Parameters: 1200 ** pathname -- the pathname to the status file. 1201 ** hostname -- the corresponding host name. 1202 ** 1203 ** Returns: 1204 ** 0 1205 */ 1206 1207 int 1208 mci_print_persistent(pathname, hostname) 1209 char *pathname; 1210 char *hostname; 1211 { 1212 static bool initflag = false; 1213 SM_FILE_T *fp; 1214 int width = Verbose ? 78 : 25; 1215 bool locked; 1216 MCI mcib; 1217 1218 /* skip directories */ 1219 if (hostname == NULL) 1220 return 0; 1221 1222 if (StopRequest) 1223 stop_sendmail(); 1224 1225 if (!initflag) 1226 { 1227 initflag = true; 1228 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1229 " -------------- Hostname --------------- How long ago ---------Results---------\n"); 1230 } 1231 1232 fp = safefopen(pathname, O_RDONLY, FileMode, 1233 SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 1234 1235 if (fp == NULL) 1236 { 1237 if (tTd(56, 1)) 1238 sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 1239 pathname, sm_errstring(errno)); 1240 return 0; 1241 } 1242 1243 FileName = pathname; 1244 memset(&mcib, '\0', sizeof mcib); 1245 if (mci_read_persistent(fp, &mcib) < 0) 1246 { 1247 syserr("%s: could not read status file", pathname); 1248 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1249 FileName = NULL; 1250 return 0; 1251 } 1252 1253 locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 1254 "", LOCK_SH|LOCK_NB); 1255 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1256 FileName = NULL; 1257 1258 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 1259 locked ? '*' : ' ', hostname, 1260 pintvl(curtime() - mcib.mci_lastuse, true)); 1261 if (mcib.mci_rstatus != NULL) 1262 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 1263 mcib.mci_rstatus); 1264 else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 1265 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1266 "Deferred: %.*s\n", width - 10, 1267 sm_errstring(mcib.mci_errno)); 1268 else if (mcib.mci_exitstat != 0) 1269 { 1270 char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 1271 1272 if (exmsg == NULL) 1273 { 1274 char buf[80]; 1275 1276 (void) sm_snprintf(buf, sizeof buf, 1277 "Unknown mailer error %d", 1278 mcib.mci_exitstat); 1279 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 1280 width, buf); 1281 } 1282 else 1283 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 1284 width, &exmsg[5]); 1285 } 1286 else if (mcib.mci_errno == 0) 1287 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 1288 else 1289 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 1290 width - 4, sm_errstring(mcib.mci_errno)); 1291 1292 return 0; 1293 } 1294 /* 1295 ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 1296 ** 1297 ** Parameters: 1298 ** pathname -- path to the status file. 1299 ** hostname -- name of host corresponding to that file. 1300 ** NULL if this is a directory (domain). 1301 ** 1302 ** Returns: 1303 ** 0 -- ok 1304 ** 1 -- file not deleted (too young, incorrect format) 1305 ** < 0 -- some error occurred 1306 */ 1307 1308 int 1309 mci_purge_persistent(pathname, hostname) 1310 char *pathname; 1311 char *hostname; 1312 { 1313 struct stat statbuf; 1314 char *end = pathname + strlen(pathname) - 1; 1315 int ret; 1316 1317 if (tTd(56, 1)) 1318 sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 1319 1320 ret = stat(pathname, &statbuf); 1321 if (ret < 0) 1322 { 1323 if (tTd(56, 2)) 1324 sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 1325 pathname, sm_errstring(errno)); 1326 return ret; 1327 } 1328 if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 1329 return 1; 1330 if (hostname != NULL) 1331 { 1332 /* remove the file */ 1333 ret = unlink(pathname); 1334 if (ret < 0) 1335 { 1336 if (LogLevel > 8) 1337 sm_syslog(LOG_ERR, NOQID, 1338 "mci_purge_persistent: failed to unlink %s: %s", 1339 pathname, sm_errstring(errno)); 1340 if (tTd(56, 2)) 1341 sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 1342 pathname, sm_errstring(errno)); 1343 return ret; 1344 } 1345 } 1346 else 1347 { 1348 /* remove the directory */ 1349 if (*end != '.') 1350 return 1; 1351 1352 if (tTd(56, 1)) 1353 sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 1354 1355 ret = rmdir(pathname); 1356 if (ret < 0) 1357 { 1358 if (tTd(56, 2)) 1359 sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 1360 pathname, sm_errstring(errno)); 1361 return ret; 1362 } 1363 } 1364 1365 return 0; 1366 } 1367 /* 1368 ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 1369 ** 1370 ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 1371 ** putting the result into `path'. if `createflag' is set, intervening 1372 ** directories will be created as needed. 1373 ** 1374 ** Parameters: 1375 ** host -- host name to convert from. 1376 ** path -- place to store result. 1377 ** pathlen -- length of path buffer. 1378 ** createflag -- if set, create intervening directories as 1379 ** needed. 1380 ** 1381 ** Returns: 1382 ** 0 -- success 1383 ** -1 -- failure 1384 */ 1385 1386 static int 1387 mci_generate_persistent_path(host, path, pathlen, createflag) 1388 const char *host; 1389 char *path; 1390 int pathlen; 1391 bool createflag; 1392 { 1393 char *elem, *p, *x, ch; 1394 int ret = 0; 1395 int len; 1396 char t_host[MAXHOSTNAMELEN]; 1397 #if NETINET6 1398 struct in6_addr in6_addr; 1399 #endif /* NETINET6 */ 1400 1401 /* 1402 ** Rationality check the arguments. 1403 */ 1404 1405 if (host == NULL) 1406 { 1407 syserr("mci_generate_persistent_path: null host"); 1408 return -1; 1409 } 1410 if (path == NULL) 1411 { 1412 syserr("mci_generate_persistent_path: null path"); 1413 return -1; 1414 } 1415 1416 if (tTd(56, 80)) 1417 sm_dprintf("mci_generate_persistent_path(%s): ", host); 1418 1419 if (*host == '\0' || *host == '.') 1420 return -1; 1421 1422 /* make certain this is not a bracketed host number */ 1423 if (strlen(host) > sizeof t_host - 1) 1424 return -1; 1425 if (host[0] == '[') 1426 (void) sm_strlcpy(t_host, host + 1, sizeof t_host); 1427 else 1428 (void) sm_strlcpy(t_host, host, sizeof t_host); 1429 1430 /* 1431 ** Delete any trailing dots from the hostname. 1432 ** Leave 'elem' pointing at the \0. 1433 */ 1434 1435 elem = t_host + strlen(t_host); 1436 while (elem > t_host && 1437 (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 1438 *--elem = '\0'; 1439 1440 /* check for bogus bracketed address */ 1441 if (host[0] == '[') 1442 { 1443 bool good = false; 1444 # if NETINET6 1445 if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 1446 good = true; 1447 # endif /* NETINET6 */ 1448 # if NETINET 1449 if (inet_addr(t_host) != INADDR_NONE) 1450 good = true; 1451 # endif /* NETINET */ 1452 if (!good) 1453 return -1; 1454 } 1455 1456 /* check for what will be the final length of the path */ 1457 len = strlen(HostStatDir) + 2; 1458 for (p = (char *) t_host; *p != '\0'; p++) 1459 { 1460 if (*p == '.') 1461 len++; 1462 len++; 1463 if (p[0] == '.' && p[1] == '.') 1464 return -1; 1465 } 1466 if (len > pathlen || len < 1) 1467 return -1; 1468 (void) sm_strlcpy(path, HostStatDir, pathlen); 1469 p = path + strlen(path); 1470 while (elem > t_host) 1471 { 1472 if (!path_is_dir(path, createflag)) 1473 { 1474 ret = -1; 1475 break; 1476 } 1477 elem--; 1478 while (elem >= t_host && *elem != '.') 1479 elem--; 1480 *p++ = '/'; 1481 x = elem + 1; 1482 while ((ch = *x++) != '\0' && ch != '.') 1483 { 1484 if (isascii(ch) && isupper(ch)) 1485 ch = tolower(ch); 1486 if (ch == '/') 1487 ch = ':'; /* / -> : */ 1488 *p++ = ch; 1489 } 1490 if (elem >= t_host) 1491 *p++ = '.'; 1492 *p = '\0'; 1493 } 1494 if (tTd(56, 80)) 1495 { 1496 if (ret < 0) 1497 sm_dprintf("FAILURE %d\n", ret); 1498 else 1499 sm_dprintf("SUCCESS %s\n", path); 1500 } 1501 return ret; 1502 } 1503