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