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