1c2aa98e2SPeter Wemm /* 2f9218d3dSGregory Neil Shapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 127660b554SGregory Neil Shapiro * $FreeBSD$ 13c2aa98e2SPeter Wemm */ 14c2aa98e2SPeter Wemm 153299c2f1SGregory Neil Shapiro #include <sendmail.h> 163299c2f1SGregory Neil Shapiro 17684b2a5fSGregory Neil Shapiro SM_RCSID("@(#)$Id: mci.c,v 8.212 2004/08/04 21:11:31 ca Exp $") 183299c2f1SGregory Neil Shapiro 193299c2f1SGregory Neil Shapiro #if NETINET || NETINET6 20c2aa98e2SPeter Wemm # include <arpa/inet.h> 213299c2f1SGregory Neil Shapiro #endif /* NETINET || NETINET6 */ 223299c2f1SGregory Neil Shapiro 23c2aa98e2SPeter Wemm #include <dirent.h> 24c2aa98e2SPeter Wemm 253299c2f1SGregory Neil Shapiro static int mci_generate_persistent_path __P((const char *, char *, 263299c2f1SGregory Neil Shapiro int, bool)); 273299c2f1SGregory Neil Shapiro static bool mci_load_persistent __P((MCI *)); 283299c2f1SGregory Neil Shapiro static void mci_uncache __P((MCI **, bool)); 293299c2f1SGregory Neil Shapiro static int mci_lock_host_statfile __P((MCI *)); 3012ed1c7cSGregory Neil Shapiro static int mci_read_persistent __P((SM_FILE_T *, MCI *)); 313299c2f1SGregory Neil Shapiro 32c2aa98e2SPeter Wemm /* 33c2aa98e2SPeter Wemm ** Mail Connection Information (MCI) Caching Module. 34c2aa98e2SPeter Wemm ** 35c2aa98e2SPeter Wemm ** There are actually two separate things cached. The first is 36c2aa98e2SPeter Wemm ** the set of all open connections -- these are stored in a 37c2aa98e2SPeter Wemm ** (small) list. The second is stored in the symbol table; it 38c2aa98e2SPeter Wemm ** has the overall status for all hosts, whether or not there 39c2aa98e2SPeter Wemm ** is a connection open currently. 40c2aa98e2SPeter Wemm ** 41c2aa98e2SPeter Wemm ** There should never be too many connections open (since this 42c2aa98e2SPeter Wemm ** could flood the socket table), nor should a connection be 43c2aa98e2SPeter Wemm ** allowed to sit idly for too long. 44c2aa98e2SPeter Wemm ** 45c2aa98e2SPeter Wemm ** MaxMciCache is the maximum number of open connections that 46c2aa98e2SPeter Wemm ** will be supported. 47c2aa98e2SPeter Wemm ** 48c2aa98e2SPeter Wemm ** MciCacheTimeout is the time (in seconds) that a connection 49c2aa98e2SPeter Wemm ** is permitted to survive without activity. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** We actually try any cached connections by sending a NOOP 52c2aa98e2SPeter Wemm ** before we use them; if the NOOP fails we close down the 53c2aa98e2SPeter Wemm ** connection and reopen it. Note that this means that a 54c2aa98e2SPeter Wemm ** server SMTP that doesn't support NOOP will hose the 55c2aa98e2SPeter Wemm ** algorithm -- but that doesn't seem too likely. 56c2aa98e2SPeter Wemm ** 57c2aa98e2SPeter Wemm ** The persistent MCI code is donated by Mark Lovell and Paul 58c2aa98e2SPeter Wemm ** Vixie. It is based on the long term host status code in KJS 59c2aa98e2SPeter Wemm ** written by Paul but has been adapted by Mark to fit into the 60c2aa98e2SPeter Wemm ** MCI structure. 61c2aa98e2SPeter Wemm */ 62c2aa98e2SPeter Wemm 633299c2f1SGregory Neil Shapiro static MCI **MciCache; /* the open connection cache */ 64c2aa98e2SPeter Wemm 6512ed1c7cSGregory Neil Shapiro /* 66c2aa98e2SPeter Wemm ** MCI_CACHE -- enter a connection structure into the open connection cache 67c2aa98e2SPeter Wemm ** 68c2aa98e2SPeter Wemm ** This may cause something else to be flushed. 69c2aa98e2SPeter Wemm ** 70c2aa98e2SPeter Wemm ** Parameters: 71c2aa98e2SPeter Wemm ** mci -- the connection to cache. 72c2aa98e2SPeter Wemm ** 73c2aa98e2SPeter Wemm ** Returns: 74c2aa98e2SPeter Wemm ** none. 75c2aa98e2SPeter Wemm */ 76c2aa98e2SPeter Wemm 77c2aa98e2SPeter Wemm void 78c2aa98e2SPeter Wemm mci_cache(mci) 79c2aa98e2SPeter Wemm register MCI *mci; 80c2aa98e2SPeter Wemm { 81c2aa98e2SPeter Wemm register MCI **mcislot; 82c2aa98e2SPeter Wemm 83c2aa98e2SPeter Wemm /* 84c2aa98e2SPeter Wemm ** Find the best slot. This may cause expired connections 85c2aa98e2SPeter Wemm ** to be closed. 86c2aa98e2SPeter Wemm */ 87c2aa98e2SPeter Wemm 88c2aa98e2SPeter Wemm mcislot = mci_scan(mci); 89c2aa98e2SPeter Wemm if (mcislot == NULL) 90c2aa98e2SPeter Wemm { 91c2aa98e2SPeter Wemm /* we don't support caching */ 92c2aa98e2SPeter Wemm return; 93c2aa98e2SPeter Wemm } 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 96c2aa98e2SPeter Wemm return; 97c2aa98e2SPeter Wemm 98c2aa98e2SPeter Wemm /* if this is already cached, we are done */ 99c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 100c2aa98e2SPeter Wemm return; 101c2aa98e2SPeter Wemm 102c2aa98e2SPeter Wemm /* otherwise we may have to clear the slot */ 103c2aa98e2SPeter Wemm if (*mcislot != NULL) 10412ed1c7cSGregory Neil Shapiro mci_uncache(mcislot, true); 105c2aa98e2SPeter Wemm 106c2aa98e2SPeter Wemm if (tTd(42, 5)) 10712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_cache: caching %p (%s) in slot %d\n", 10812ed1c7cSGregory Neil Shapiro mci, mci->mci_host, (int) (mcislot - MciCache)); 109c2aa98e2SPeter Wemm if (tTd(91, 100)) 110c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 1113299c2f1SGregory Neil Shapiro "mci_cache: caching %lx (%.100s) in slot %d", 11212ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 11312ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache)); 114c2aa98e2SPeter Wemm 115c2aa98e2SPeter Wemm *mcislot = mci; 116c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CACHED; 117c2aa98e2SPeter Wemm } 11812ed1c7cSGregory Neil Shapiro /* 119c2aa98e2SPeter Wemm ** MCI_SCAN -- scan the cache, flush junk, and return best slot 120c2aa98e2SPeter Wemm ** 121c2aa98e2SPeter Wemm ** Parameters: 122c2aa98e2SPeter Wemm ** savemci -- never flush this one. Can be null. 123c2aa98e2SPeter Wemm ** 124c2aa98e2SPeter Wemm ** Returns: 125c2aa98e2SPeter Wemm ** The LRU (or empty) slot. 126c2aa98e2SPeter Wemm */ 127c2aa98e2SPeter Wemm 128c2aa98e2SPeter Wemm MCI ** 129c2aa98e2SPeter Wemm mci_scan(savemci) 130c2aa98e2SPeter Wemm MCI *savemci; 131c2aa98e2SPeter Wemm { 132c2aa98e2SPeter Wemm time_t now; 133c2aa98e2SPeter Wemm register MCI **bestmci; 134c2aa98e2SPeter Wemm register MCI *mci; 135c2aa98e2SPeter Wemm register int i; 136c2aa98e2SPeter Wemm 137c2aa98e2SPeter Wemm if (MaxMciCache <= 0) 138c2aa98e2SPeter Wemm { 139c2aa98e2SPeter Wemm /* we don't support caching */ 140c2aa98e2SPeter Wemm return NULL; 141c2aa98e2SPeter Wemm } 142c2aa98e2SPeter Wemm 143c2aa98e2SPeter Wemm if (MciCache == NULL) 144c2aa98e2SPeter Wemm { 145c2aa98e2SPeter Wemm /* first call */ 14612ed1c7cSGregory Neil Shapiro MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof *MciCache); 1473299c2f1SGregory Neil Shapiro memset((char *) MciCache, '\0', MaxMciCache * sizeof *MciCache); 1483299c2f1SGregory Neil Shapiro return &MciCache[0]; 149c2aa98e2SPeter Wemm } 150c2aa98e2SPeter Wemm 151c2aa98e2SPeter Wemm now = curtime(); 152c2aa98e2SPeter Wemm bestmci = &MciCache[0]; 153c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 154c2aa98e2SPeter Wemm { 155c2aa98e2SPeter Wemm mci = MciCache[i]; 156c2aa98e2SPeter Wemm if (mci == NULL || mci->mci_state == MCIS_CLOSED) 157c2aa98e2SPeter Wemm { 158c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 159c2aa98e2SPeter Wemm continue; 160c2aa98e2SPeter Wemm } 161320f00e7SGregory Neil Shapiro if ((mci->mci_lastuse + MciCacheTimeout <= now || 1623299c2f1SGregory Neil Shapiro (mci->mci_mailer != NULL && 1633299c2f1SGregory Neil Shapiro mci->mci_mailer->m_maxdeliveries > 0 && 1643299c2f1SGregory Neil Shapiro mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&& 1653299c2f1SGregory Neil Shapiro mci != savemci) 166c2aa98e2SPeter Wemm { 1673299c2f1SGregory Neil Shapiro /* connection idle too long or too many deliveries */ 168c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 1693299c2f1SGregory Neil Shapiro 1703299c2f1SGregory Neil Shapiro /* close it */ 17112ed1c7cSGregory Neil Shapiro mci_uncache(bestmci, true); 172c2aa98e2SPeter Wemm continue; 173c2aa98e2SPeter Wemm } 174c2aa98e2SPeter Wemm if (*bestmci == NULL) 175c2aa98e2SPeter Wemm continue; 176c2aa98e2SPeter Wemm if (mci->mci_lastuse < (*bestmci)->mci_lastuse) 177c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 178c2aa98e2SPeter Wemm } 179c2aa98e2SPeter Wemm return bestmci; 180c2aa98e2SPeter Wemm } 18112ed1c7cSGregory Neil Shapiro /* 182c2aa98e2SPeter Wemm ** MCI_UNCACHE -- remove a connection from a slot. 183c2aa98e2SPeter Wemm ** 184c2aa98e2SPeter Wemm ** May close a connection. 185c2aa98e2SPeter Wemm ** 186c2aa98e2SPeter Wemm ** Parameters: 187c2aa98e2SPeter Wemm ** mcislot -- the slot to empty. 18812ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol on this connection. 18912ed1c7cSGregory Neil Shapiro ** if false, we are assumed to be in a forked child; 190c2aa98e2SPeter Wemm ** all we want to do is close the file(s). 191c2aa98e2SPeter Wemm ** 192c2aa98e2SPeter Wemm ** Returns: 193c2aa98e2SPeter Wemm ** none. 194c2aa98e2SPeter Wemm */ 195c2aa98e2SPeter Wemm 1963299c2f1SGregory Neil Shapiro static void 197c2aa98e2SPeter Wemm mci_uncache(mcislot, doquit) 198c2aa98e2SPeter Wemm register MCI **mcislot; 199c2aa98e2SPeter Wemm bool doquit; 200c2aa98e2SPeter Wemm { 201c2aa98e2SPeter Wemm register MCI *mci; 202c2aa98e2SPeter Wemm extern ENVELOPE BlankEnvelope; 203c2aa98e2SPeter Wemm 204c2aa98e2SPeter Wemm mci = *mcislot; 205c2aa98e2SPeter Wemm if (mci == NULL) 206c2aa98e2SPeter Wemm return; 207c2aa98e2SPeter Wemm *mcislot = NULL; 208c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 209c2aa98e2SPeter Wemm return; 210c2aa98e2SPeter Wemm 211c2aa98e2SPeter Wemm mci_unlock_host(mci); 212c2aa98e2SPeter Wemm 213c2aa98e2SPeter Wemm if (tTd(42, 5)) 21412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n", 21512ed1c7cSGregory Neil Shapiro mci, mci->mci_host, (int) (mcislot - MciCache), 21612ed1c7cSGregory Neil Shapiro doquit); 217c2aa98e2SPeter Wemm if (tTd(91, 100)) 218c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 2193299c2f1SGregory Neil Shapiro "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)", 22012ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 22112ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache), doquit); 222c2aa98e2SPeter Wemm 2233299c2f1SGregory Neil Shapiro mci->mci_deliveries = 0; 224c2aa98e2SPeter Wemm if (doquit) 225c2aa98e2SPeter Wemm { 226c2aa98e2SPeter Wemm message("Closing connection to %s", mci->mci_host); 227c2aa98e2SPeter Wemm 228c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_CACHED; 229c2aa98e2SPeter Wemm 230c2aa98e2SPeter Wemm /* only uses the envelope to flush the transcript file */ 231c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 232c2aa98e2SPeter Wemm smtpquit(mci->mci_mailer, mci, &BlankEnvelope); 23312ed1c7cSGregory Neil Shapiro #if XLA 234c2aa98e2SPeter Wemm xla_host_end(mci->mci_host); 2353299c2f1SGregory Neil Shapiro #endif /* XLA */ 236c2aa98e2SPeter Wemm } 237c2aa98e2SPeter Wemm else 238c2aa98e2SPeter Wemm { 239c2aa98e2SPeter Wemm if (mci->mci_in != NULL) 24012ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 241c2aa98e2SPeter Wemm if (mci->mci_out != NULL) 24212ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 243c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 244c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 245c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 246c2aa98e2SPeter Wemm mci->mci_errno = 0; 247c2aa98e2SPeter Wemm mci->mci_flags = 0; 24812ed1c7cSGregory Neil Shapiro 24912ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 25012ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 25112ed1c7cSGregory Neil Shapiro #if PIPELINING 25212ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 25312ed1c7cSGregory Neil Shapiro #endif /* PIPELINING */ 25412ed1c7cSGregory Neil Shapiro } 25512ed1c7cSGregory Neil Shapiro 25612ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 25712ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 25812ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_heloname); 25912ed1c7cSGregory Neil Shapiro if (mci->mci_rpool != NULL) 26012ed1c7cSGregory Neil Shapiro { 26112ed1c7cSGregory Neil Shapiro sm_rpool_free(mci->mci_rpool); 26212ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = NULL; 26312ed1c7cSGregory Neil Shapiro mci->mci_rpool = NULL; 264c2aa98e2SPeter Wemm } 265c2aa98e2SPeter Wemm } 26612ed1c7cSGregory Neil Shapiro /* 267c2aa98e2SPeter Wemm ** MCI_FLUSH -- flush the entire cache 268c2aa98e2SPeter Wemm ** 269c2aa98e2SPeter Wemm ** Parameters: 27012ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol. 27112ed1c7cSGregory Neil Shapiro ** if false, just close the connection. 272c2aa98e2SPeter Wemm ** allbut -- but leave this one open. 273c2aa98e2SPeter Wemm ** 274c2aa98e2SPeter Wemm ** Returns: 275c2aa98e2SPeter Wemm ** none. 276c2aa98e2SPeter Wemm */ 277c2aa98e2SPeter Wemm 278c2aa98e2SPeter Wemm void 279c2aa98e2SPeter Wemm mci_flush(doquit, allbut) 280c2aa98e2SPeter Wemm bool doquit; 281c2aa98e2SPeter Wemm MCI *allbut; 282c2aa98e2SPeter Wemm { 283c2aa98e2SPeter Wemm register int i; 284c2aa98e2SPeter Wemm 285c2aa98e2SPeter Wemm if (MciCache == NULL) 286c2aa98e2SPeter Wemm return; 287c2aa98e2SPeter Wemm 288c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 289c46d91b7SGregory Neil Shapiro { 290c2aa98e2SPeter Wemm if (allbut != MciCache[i]) 291c2aa98e2SPeter Wemm mci_uncache(&MciCache[i], doquit); 292c2aa98e2SPeter Wemm } 293c46d91b7SGregory Neil Shapiro } 29412ed1c7cSGregory Neil Shapiro /* 295c2aa98e2SPeter Wemm ** MCI_GET -- get information about a particular host 29612ed1c7cSGregory Neil Shapiro ** 29712ed1c7cSGregory Neil Shapiro ** Parameters: 29812ed1c7cSGregory Neil Shapiro ** host -- host to look for. 29912ed1c7cSGregory Neil Shapiro ** m -- mailer. 30012ed1c7cSGregory Neil Shapiro ** 30112ed1c7cSGregory Neil Shapiro ** Returns: 30212ed1c7cSGregory Neil Shapiro ** mci for this host (might be new). 303c2aa98e2SPeter Wemm */ 304c2aa98e2SPeter Wemm 305c2aa98e2SPeter Wemm MCI * 306c2aa98e2SPeter Wemm mci_get(host, m) 307c2aa98e2SPeter Wemm char *host; 308c2aa98e2SPeter Wemm MAILER *m; 309c2aa98e2SPeter Wemm { 310c2aa98e2SPeter Wemm register MCI *mci; 311c2aa98e2SPeter Wemm register STAB *s; 312c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 313c2aa98e2SPeter Wemm 314c2aa98e2SPeter Wemm /* clear CurHostAddr so we don't get a bogus address with this name */ 3153299c2f1SGregory Neil Shapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 316c2aa98e2SPeter Wemm 317c2aa98e2SPeter Wemm /* clear out any expired connections */ 318c2aa98e2SPeter Wemm (void) mci_scan(NULL); 319c2aa98e2SPeter Wemm 320c2aa98e2SPeter Wemm if (m->m_mno < 0) 321c46d91b7SGregory Neil Shapiro syserr("!negative mno %d (%s)", m->m_mno, m->m_name); 3223299c2f1SGregory Neil Shapiro 323c2aa98e2SPeter Wemm s = stab(host, ST_MCI + m->m_mno, ST_ENTER); 324c2aa98e2SPeter Wemm mci = &s->s_mci; 325c2aa98e2SPeter Wemm 32612ed1c7cSGregory Neil Shapiro /* initialize per-message data */ 32712ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 32812ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 32912ed1c7cSGregory Neil Shapiro #if PIPELINING 33012ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 33112ed1c7cSGregory Neil Shapiro #endif /* PIPELINING */ 33212ed1c7cSGregory Neil Shapiro 33312ed1c7cSGregory Neil Shapiro if (mci->mci_rpool == NULL) 33412ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 33512ed1c7cSGregory Neil Shapiro 33612ed1c7cSGregory Neil Shapiro if (mci->mci_macro.mac_rpool == NULL) 33712ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 33812ed1c7cSGregory Neil Shapiro 3393299c2f1SGregory Neil Shapiro /* 34012ed1c7cSGregory Neil Shapiro ** We don't need to load the persistent data if we have data 3413299c2f1SGregory Neil Shapiro ** already loaded in the cache. 3423299c2f1SGregory Neil Shapiro */ 3433299c2f1SGregory Neil Shapiro 3443299c2f1SGregory Neil Shapiro if (mci->mci_host == NULL && 3453299c2f1SGregory Neil Shapiro (mci->mci_host = s->s_name) != NULL && 3463299c2f1SGregory Neil Shapiro !mci_load_persistent(mci)) 347c2aa98e2SPeter Wemm { 348c2aa98e2SPeter Wemm if (tTd(42, 2)) 34912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): lock failed\n", 3503299c2f1SGregory Neil Shapiro host, m->m_name); 351c2aa98e2SPeter Wemm mci->mci_exitstat = EX_TEMPFAIL; 352c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 353c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 354c2aa98e2SPeter Wemm return mci; 355c2aa98e2SPeter Wemm } 356c2aa98e2SPeter Wemm 357c2aa98e2SPeter Wemm if (tTd(42, 2)) 358c2aa98e2SPeter Wemm { 35912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n", 360c2aa98e2SPeter Wemm host, m->m_name, mci->mci_state, mci->mci_flags, 361c2aa98e2SPeter Wemm mci->mci_exitstat, mci->mci_errno); 362c2aa98e2SPeter Wemm } 363c2aa98e2SPeter Wemm 364c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_OPEN) 365c2aa98e2SPeter Wemm { 366c2aa98e2SPeter Wemm /* poke the connection to see if it's still alive */ 367c2aa98e2SPeter Wemm (void) smtpprobe(mci); 368c2aa98e2SPeter Wemm 369c2aa98e2SPeter Wemm /* reset the stored state in the event of a timeout */ 370c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 371c2aa98e2SPeter Wemm { 372c2aa98e2SPeter Wemm mci->mci_errno = 0; 373c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 374c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 375c2aa98e2SPeter Wemm } 376c2aa98e2SPeter Wemm else 377c2aa98e2SPeter Wemm { 37812ed1c7cSGregory Neil Shapiro /* get peer host address */ 379c2aa98e2SPeter Wemm /* (this should really be in the mci struct) */ 380c2aa98e2SPeter Wemm SOCKADDR_LEN_T socklen = sizeof CurHostAddr; 381c2aa98e2SPeter Wemm 38212ed1c7cSGregory Neil Shapiro (void) getpeername(sm_io_getinfo(mci->mci_in, 38312ed1c7cSGregory Neil Shapiro SM_IO_WHAT_FD, NULL), 384c2aa98e2SPeter Wemm (struct sockaddr *) &CurHostAddr, &socklen); 385c2aa98e2SPeter Wemm } 386c2aa98e2SPeter Wemm } 387c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_CLOSED) 388c2aa98e2SPeter Wemm { 389c2aa98e2SPeter Wemm time_t now = curtime(); 390c2aa98e2SPeter Wemm 391c2aa98e2SPeter Wemm /* if this info is stale, ignore it */ 392320f00e7SGregory Neil Shapiro if (mci->mci_lastuse + MciInfoTimeout <= now) 393c2aa98e2SPeter Wemm { 394c2aa98e2SPeter Wemm mci->mci_lastuse = now; 395c2aa98e2SPeter Wemm mci->mci_errno = 0; 396c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 397c2aa98e2SPeter Wemm } 398c2aa98e2SPeter Wemm } 399c2aa98e2SPeter Wemm 400c2aa98e2SPeter Wemm return mci; 401c2aa98e2SPeter Wemm } 40212ed1c7cSGregory Neil Shapiro /* 40312ed1c7cSGregory Neil Shapiro ** MCI_NEW -- allocate new MCI structure 40412ed1c7cSGregory Neil Shapiro ** 40512ed1c7cSGregory Neil Shapiro ** Parameters: 40612ed1c7cSGregory Neil Shapiro ** rpool -- if non-NULL: allocate from that rpool. 40712ed1c7cSGregory Neil Shapiro ** 40812ed1c7cSGregory Neil Shapiro ** Returns: 40912ed1c7cSGregory Neil Shapiro ** mci (new). 41012ed1c7cSGregory Neil Shapiro */ 41112ed1c7cSGregory Neil Shapiro 41212ed1c7cSGregory Neil Shapiro MCI * 41312ed1c7cSGregory Neil Shapiro mci_new(rpool) 41412ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 41512ed1c7cSGregory Neil Shapiro { 41612ed1c7cSGregory Neil Shapiro register MCI *mci; 41712ed1c7cSGregory Neil Shapiro 41812ed1c7cSGregory Neil Shapiro if (rpool == NULL) 41912ed1c7cSGregory Neil Shapiro mci = (MCI *) sm_malloc_x(sizeof *mci); 42012ed1c7cSGregory Neil Shapiro else 42112ed1c7cSGregory Neil Shapiro mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof *mci); 42212ed1c7cSGregory Neil Shapiro memset((char *) mci, '\0', sizeof *mci); 42312ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 42412ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 42512ed1c7cSGregory Neil Shapiro return mci; 42612ed1c7cSGregory Neil Shapiro } 42712ed1c7cSGregory Neil Shapiro /* 4283299c2f1SGregory Neil Shapiro ** MCI_MATCH -- check connection cache for a particular host 42912ed1c7cSGregory Neil Shapiro ** 43012ed1c7cSGregory Neil Shapiro ** Parameters: 43112ed1c7cSGregory Neil Shapiro ** host -- host to look for. 43212ed1c7cSGregory Neil Shapiro ** m -- mailer. 43312ed1c7cSGregory Neil Shapiro ** 43412ed1c7cSGregory Neil Shapiro ** Returns: 43512ed1c7cSGregory Neil Shapiro ** true iff open connection exists. 4363299c2f1SGregory Neil Shapiro */ 4373299c2f1SGregory Neil Shapiro 4383299c2f1SGregory Neil Shapiro bool 4393299c2f1SGregory Neil Shapiro mci_match(host, m) 4403299c2f1SGregory Neil Shapiro char *host; 4413299c2f1SGregory Neil Shapiro MAILER *m; 4423299c2f1SGregory Neil Shapiro { 4433299c2f1SGregory Neil Shapiro register MCI *mci; 4443299c2f1SGregory Neil Shapiro register STAB *s; 4453299c2f1SGregory Neil Shapiro 446c46d91b7SGregory Neil Shapiro if (m->m_mno < 0 || m->m_mno > MAXMAILERS) 44712ed1c7cSGregory Neil Shapiro return false; 4483299c2f1SGregory Neil Shapiro s = stab(host, ST_MCI + m->m_mno, ST_FIND); 4493299c2f1SGregory Neil Shapiro if (s == NULL) 45012ed1c7cSGregory Neil Shapiro return false; 4513299c2f1SGregory Neil Shapiro 4523299c2f1SGregory Neil Shapiro mci = &s->s_mci; 45312ed1c7cSGregory Neil Shapiro return mci->mci_state == MCIS_OPEN; 4543299c2f1SGregory Neil Shapiro } 45512ed1c7cSGregory Neil Shapiro /* 456c2aa98e2SPeter Wemm ** MCI_SETSTAT -- set status codes in MCI structure. 457c2aa98e2SPeter Wemm ** 458c2aa98e2SPeter Wemm ** Parameters: 459c2aa98e2SPeter Wemm ** mci -- the MCI structure to set. 460c2aa98e2SPeter Wemm ** xstat -- the exit status code. 461c2aa98e2SPeter Wemm ** dstat -- the DSN status code. 462c2aa98e2SPeter Wemm ** rstat -- the SMTP status code. 463c2aa98e2SPeter Wemm ** 464c2aa98e2SPeter Wemm ** Returns: 465c2aa98e2SPeter Wemm ** none. 466c2aa98e2SPeter Wemm */ 467c2aa98e2SPeter Wemm 468c2aa98e2SPeter Wemm void 469c2aa98e2SPeter Wemm mci_setstat(mci, xstat, dstat, rstat) 470c2aa98e2SPeter Wemm MCI *mci; 471c2aa98e2SPeter Wemm int xstat; 472c2aa98e2SPeter Wemm char *dstat; 473c2aa98e2SPeter Wemm char *rstat; 474c2aa98e2SPeter Wemm { 475c2aa98e2SPeter Wemm /* protocol errors should never be interpreted as sticky */ 476c2aa98e2SPeter Wemm if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL) 477c2aa98e2SPeter Wemm mci->mci_exitstat = xstat; 478c2aa98e2SPeter Wemm 47912ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 48012ed1c7cSGregory Neil Shapiro if (dstat != NULL) 48112ed1c7cSGregory Neil Shapiro mci->mci_status = sm_strdup_x(dstat); 48212ed1c7cSGregory Neil Shapiro 48312ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 484c2aa98e2SPeter Wemm if (rstat != NULL) 48512ed1c7cSGregory Neil Shapiro mci->mci_rstatus = sm_strdup_x(rstat); 486c2aa98e2SPeter Wemm } 48712ed1c7cSGregory Neil Shapiro /* 488c2aa98e2SPeter Wemm ** MCI_DUMP -- dump the contents of an MCI structure. 489c2aa98e2SPeter Wemm ** 490c2aa98e2SPeter Wemm ** Parameters: 491bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 492c2aa98e2SPeter Wemm ** mci -- the MCI structure to dump. 493c2aa98e2SPeter Wemm ** 494c2aa98e2SPeter Wemm ** Returns: 495c2aa98e2SPeter Wemm ** none. 496c2aa98e2SPeter Wemm ** 497c2aa98e2SPeter Wemm ** Side Effects: 498c2aa98e2SPeter Wemm ** none. 499c2aa98e2SPeter Wemm */ 500c2aa98e2SPeter Wemm 501c2aa98e2SPeter Wemm struct mcifbits 502c2aa98e2SPeter Wemm { 503c2aa98e2SPeter Wemm int mcif_bit; /* flag bit */ 504c2aa98e2SPeter Wemm char *mcif_name; /* flag name */ 505c2aa98e2SPeter Wemm }; 5063299c2f1SGregory Neil Shapiro static struct mcifbits MciFlags[] = 507c2aa98e2SPeter Wemm { 508c2aa98e2SPeter Wemm { MCIF_VALID, "VALID" }, 509c2aa98e2SPeter Wemm { MCIF_CACHED, "CACHED" }, 510c2aa98e2SPeter Wemm { MCIF_ESMTP, "ESMTP" }, 511c2aa98e2SPeter Wemm { MCIF_EXPN, "EXPN" }, 512c2aa98e2SPeter Wemm { MCIF_SIZE, "SIZE" }, 513c2aa98e2SPeter Wemm { MCIF_8BITMIME, "8BITMIME" }, 514c2aa98e2SPeter Wemm { MCIF_7BIT, "7BIT" }, 515c2aa98e2SPeter Wemm { MCIF_INHEADER, "INHEADER" }, 516c2aa98e2SPeter Wemm { MCIF_CVT8TO7, "CVT8TO7" }, 517c2aa98e2SPeter Wemm { MCIF_DSN, "DSN" }, 518c2aa98e2SPeter Wemm { MCIF_8BITOK, "8BITOK" }, 519c2aa98e2SPeter Wemm { MCIF_CVT7TO8, "CVT7TO8" }, 520c2aa98e2SPeter Wemm { MCIF_INMIME, "INMIME" }, 52112ed1c7cSGregory Neil Shapiro { MCIF_AUTH, "AUTH" }, 52212ed1c7cSGregory Neil Shapiro { MCIF_AUTHACT, "AUTHACT" }, 52312ed1c7cSGregory Neil Shapiro { MCIF_ENHSTAT, "ENHSTAT" }, 52412ed1c7cSGregory Neil Shapiro { MCIF_PIPELINED, "PIPELINED" }, 52512ed1c7cSGregory Neil Shapiro #if STARTTLS 52612ed1c7cSGregory Neil Shapiro { MCIF_TLS, "TLS" }, 52712ed1c7cSGregory Neil Shapiro { MCIF_TLSACT, "TLSACT" }, 52812ed1c7cSGregory Neil Shapiro #endif /* STARTTLS */ 52912ed1c7cSGregory Neil Shapiro { MCIF_DLVR_BY, "DLVR_BY" }, 530c2aa98e2SPeter Wemm { 0, NULL } 531c2aa98e2SPeter Wemm }; 532c2aa98e2SPeter Wemm 533c2aa98e2SPeter Wemm void 534bfb62e91SGregory Neil Shapiro mci_dump(fp, mci, logit) 535bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 536c2aa98e2SPeter Wemm register MCI *mci; 537c2aa98e2SPeter Wemm bool logit; 538c2aa98e2SPeter Wemm { 539c2aa98e2SPeter Wemm register char *p; 540c2aa98e2SPeter Wemm char *sep; 541c2aa98e2SPeter Wemm char buf[4000]; 542c2aa98e2SPeter Wemm 543c2aa98e2SPeter Wemm sep = logit ? " " : "\n\t"; 544c2aa98e2SPeter Wemm p = buf; 54512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci); 546c2aa98e2SPeter Wemm p += strlen(p); 547c2aa98e2SPeter Wemm if (mci == NULL) 548c2aa98e2SPeter Wemm { 54912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL"); 550c2aa98e2SPeter Wemm goto printit; 551c2aa98e2SPeter Wemm } 55212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags); 553c2aa98e2SPeter Wemm p += strlen(p); 5547660b554SGregory Neil Shapiro 5557660b554SGregory Neil Shapiro /* 5567660b554SGregory Neil Shapiro ** The following check is just for paranoia. It protects the 5577660b554SGregory Neil Shapiro ** assignment in the if() clause. If there's not some minimum 5587660b554SGregory Neil Shapiro ** amount of space we can stop right now. The check will not 5597660b554SGregory Neil Shapiro ** trigger as long as sizeof(buf)=4000. 5607660b554SGregory Neil Shapiro */ 5617660b554SGregory Neil Shapiro 5627660b554SGregory Neil Shapiro if (p >= buf + sizeof(buf) - 4) 5637660b554SGregory Neil Shapiro goto printit; 564c2aa98e2SPeter Wemm if (mci->mci_flags != 0) 565c2aa98e2SPeter Wemm { 566c2aa98e2SPeter Wemm struct mcifbits *f; 567c2aa98e2SPeter Wemm 5687660b554SGregory Neil Shapiro *p++ = '<'; /* protected above */ 569c2aa98e2SPeter Wemm for (f = MciFlags; f->mcif_bit != 0; f++) 570c2aa98e2SPeter Wemm { 571c2aa98e2SPeter Wemm if (!bitset(f->mcif_bit, mci->mci_flags)) 572c2aa98e2SPeter Wemm continue; 57312ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2, 57412ed1c7cSGregory Neil Shapiro f->mcif_name, ","); 575c2aa98e2SPeter Wemm p += strlen(p); 576c2aa98e2SPeter Wemm } 577c2aa98e2SPeter Wemm p[-1] = '>'; 578c2aa98e2SPeter Wemm } 57912ed1c7cSGregory Neil Shapiro 58012ed1c7cSGregory Neil Shapiro /* Note: sm_snprintf() takes care of NULL arguments for %s */ 58112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 582c2aa98e2SPeter Wemm ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", 583c2aa98e2SPeter Wemm sep, mci->mci_errno, mci->mci_herrno, 5843299c2f1SGregory Neil Shapiro mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep); 585c2aa98e2SPeter Wemm p += strlen(p); 58612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 587c2aa98e2SPeter Wemm "maxsize=%ld, phase=%s, mailer=%s,%s", 58812ed1c7cSGregory Neil Shapiro mci->mci_maxsize, mci->mci_phase, 589c2aa98e2SPeter Wemm mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name, 590c2aa98e2SPeter Wemm sep); 591c2aa98e2SPeter Wemm p += strlen(p); 59212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 593c2aa98e2SPeter Wemm "status=%s, rstatus=%s,%s", 59412ed1c7cSGregory Neil Shapiro mci->mci_status, mci->mci_rstatus, sep); 595c2aa98e2SPeter Wemm p += strlen(p); 59612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 597c2aa98e2SPeter Wemm "host=%s, lastuse=%s", 59812ed1c7cSGregory Neil Shapiro mci->mci_host, ctime(&mci->mci_lastuse)); 599c2aa98e2SPeter Wemm printit: 600c2aa98e2SPeter Wemm if (logit) 601c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); 602c2aa98e2SPeter Wemm else 603bfb62e91SGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf); 604c2aa98e2SPeter Wemm } 60512ed1c7cSGregory Neil Shapiro /* 606c2aa98e2SPeter Wemm ** MCI_DUMP_ALL -- print the entire MCI cache 607c2aa98e2SPeter Wemm ** 608c2aa98e2SPeter Wemm ** Parameters: 609bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 610c2aa98e2SPeter Wemm ** logit -- if set, log the result instead of printing 611c2aa98e2SPeter Wemm ** to stdout. 612c2aa98e2SPeter Wemm ** 613c2aa98e2SPeter Wemm ** Returns: 614c2aa98e2SPeter Wemm ** none. 615c2aa98e2SPeter Wemm */ 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm void 618bfb62e91SGregory Neil Shapiro mci_dump_all(fp, logit) 619bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 620c2aa98e2SPeter Wemm bool logit; 621c2aa98e2SPeter Wemm { 622c2aa98e2SPeter Wemm register int i; 623c2aa98e2SPeter Wemm 624c2aa98e2SPeter Wemm if (MciCache == NULL) 625c2aa98e2SPeter Wemm return; 626c2aa98e2SPeter Wemm 627c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 628bfb62e91SGregory Neil Shapiro mci_dump(fp, MciCache[i], logit); 629c2aa98e2SPeter Wemm } 63012ed1c7cSGregory Neil Shapiro /* 631c2aa98e2SPeter Wemm ** MCI_LOCK_HOST -- Lock host while sending. 632c2aa98e2SPeter Wemm ** 633c2aa98e2SPeter Wemm ** If we are contacting a host, we'll need to 634c2aa98e2SPeter Wemm ** update the status information in the host status 635c2aa98e2SPeter Wemm ** file, and if we want to do that, we ought to have 636c2aa98e2SPeter Wemm ** locked it. This has the (according to some) 637c2aa98e2SPeter Wemm ** desirable effect of serializing connectivity with 63812ed1c7cSGregory Neil Shapiro ** remote hosts -- i.e.: one connection to a given 639c2aa98e2SPeter Wemm ** host at a time. 640c2aa98e2SPeter Wemm ** 641c2aa98e2SPeter Wemm ** Parameters: 642c2aa98e2SPeter Wemm ** mci -- containing the host we want to lock. 643c2aa98e2SPeter Wemm ** 644c2aa98e2SPeter Wemm ** Returns: 645c2aa98e2SPeter Wemm ** EX_OK -- got the lock. 646c2aa98e2SPeter Wemm ** EX_TEMPFAIL -- didn't get the lock. 647c2aa98e2SPeter Wemm */ 648c2aa98e2SPeter Wemm 649c2aa98e2SPeter Wemm int 650c2aa98e2SPeter Wemm mci_lock_host(mci) 651c2aa98e2SPeter Wemm MCI *mci; 652c2aa98e2SPeter Wemm { 653c2aa98e2SPeter Wemm if (mci == NULL) 654c2aa98e2SPeter Wemm { 655c2aa98e2SPeter Wemm if (tTd(56, 1)) 65612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: NULL mci\n"); 657c2aa98e2SPeter Wemm return EX_OK; 658c2aa98e2SPeter Wemm } 659c2aa98e2SPeter Wemm 660c2aa98e2SPeter Wemm if (!SingleThreadDelivery) 661c2aa98e2SPeter Wemm return EX_OK; 662c2aa98e2SPeter Wemm 663c2aa98e2SPeter Wemm return mci_lock_host_statfile(mci); 664c2aa98e2SPeter Wemm } 665c2aa98e2SPeter Wemm 6663299c2f1SGregory Neil Shapiro static int 667c2aa98e2SPeter Wemm mci_lock_host_statfile(mci) 668c2aa98e2SPeter Wemm MCI *mci; 669c2aa98e2SPeter Wemm { 6703299c2f1SGregory Neil Shapiro int save_errno = errno; 671c2aa98e2SPeter Wemm int retVal = EX_OK; 67288ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 673c2aa98e2SPeter Wemm 674c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 675c2aa98e2SPeter Wemm return EX_OK; 676c2aa98e2SPeter Wemm 677c2aa98e2SPeter Wemm if (tTd(56, 2)) 67812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: attempting to lock %s\n", 679c2aa98e2SPeter Wemm mci->mci_host); 680c2aa98e2SPeter Wemm 68112ed1c7cSGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 68212ed1c7cSGregory Neil Shapiro true) < 0) 683c2aa98e2SPeter Wemm { 684c2aa98e2SPeter Wemm /* of course this should never happen */ 685c2aa98e2SPeter Wemm if (tTd(56, 2)) 68612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Failed to generate host path for %s\n", 687c2aa98e2SPeter Wemm mci->mci_host); 688c2aa98e2SPeter Wemm 689c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 690c2aa98e2SPeter Wemm goto cleanup; 691c2aa98e2SPeter Wemm } 692c2aa98e2SPeter Wemm 693c2aa98e2SPeter Wemm mci->mci_statfile = safefopen(fname, O_RDWR, FileMode, 694c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT); 695c2aa98e2SPeter Wemm 696c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 697c2aa98e2SPeter Wemm { 69812ed1c7cSGregory Neil Shapiro syserr("mci_lock_host: cannot create host lock file %s", fname); 699c2aa98e2SPeter Wemm goto cleanup; 700c2aa98e2SPeter Wemm } 701c2aa98e2SPeter Wemm 70212ed1c7cSGregory Neil Shapiro if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 70312ed1c7cSGregory Neil Shapiro fname, "", LOCK_EX|LOCK_NB)) 704c2aa98e2SPeter Wemm { 705c2aa98e2SPeter Wemm if (tTd(56, 2)) 70612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: couldn't get lock on %s\n", 707c2aa98e2SPeter Wemm fname); 70812ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 709c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 710c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 711c2aa98e2SPeter Wemm goto cleanup; 712c2aa98e2SPeter Wemm } 713c2aa98e2SPeter Wemm 714c2aa98e2SPeter Wemm if (tTd(56, 12) && mci->mci_statfile != NULL) 71512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Sanity check -- lock is good\n"); 716c2aa98e2SPeter Wemm 717c2aa98e2SPeter Wemm cleanup: 7183299c2f1SGregory Neil Shapiro errno = save_errno; 719c2aa98e2SPeter Wemm return retVal; 720c2aa98e2SPeter Wemm } 72112ed1c7cSGregory Neil Shapiro /* 722c2aa98e2SPeter Wemm ** MCI_UNLOCK_HOST -- unlock host 723c2aa98e2SPeter Wemm ** 724c2aa98e2SPeter Wemm ** Clean up the lock on a host, close the file, let 725c2aa98e2SPeter Wemm ** someone else use it. 726c2aa98e2SPeter Wemm ** 727c2aa98e2SPeter Wemm ** Parameters: 728c2aa98e2SPeter Wemm ** mci -- us. 729c2aa98e2SPeter Wemm ** 730c2aa98e2SPeter Wemm ** Returns: 731c2aa98e2SPeter Wemm ** nothing. 732c2aa98e2SPeter Wemm */ 733c2aa98e2SPeter Wemm 734c2aa98e2SPeter Wemm void 735c2aa98e2SPeter Wemm mci_unlock_host(mci) 736c2aa98e2SPeter Wemm MCI *mci; 737c2aa98e2SPeter Wemm { 7383299c2f1SGregory Neil Shapiro int save_errno = errno; 739c2aa98e2SPeter Wemm 740c2aa98e2SPeter Wemm if (mci == NULL) 741c2aa98e2SPeter Wemm { 742c2aa98e2SPeter Wemm if (tTd(56, 1)) 74312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: NULL mci\n"); 744c2aa98e2SPeter Wemm return; 745c2aa98e2SPeter Wemm } 746c2aa98e2SPeter Wemm 747c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 748c2aa98e2SPeter Wemm return; 749c2aa98e2SPeter Wemm 750c2aa98e2SPeter Wemm if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) 751c2aa98e2SPeter Wemm { 752c2aa98e2SPeter Wemm if (tTd(56, 1)) 75312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: stat file already locked\n"); 754c2aa98e2SPeter Wemm } 755c2aa98e2SPeter Wemm else 756c2aa98e2SPeter Wemm { 757c2aa98e2SPeter Wemm if (tTd(56, 2)) 75812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: store prior to unlock\n"); 759c2aa98e2SPeter Wemm mci_store_persistent(mci); 760c2aa98e2SPeter Wemm } 761c2aa98e2SPeter Wemm 762c2aa98e2SPeter Wemm if (mci->mci_statfile != NULL) 763c2aa98e2SPeter Wemm { 76412ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 765c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 766c2aa98e2SPeter Wemm } 767c2aa98e2SPeter Wemm 7683299c2f1SGregory Neil Shapiro errno = save_errno; 769c2aa98e2SPeter Wemm } 77012ed1c7cSGregory Neil Shapiro /* 771c2aa98e2SPeter Wemm ** MCI_LOAD_PERSISTENT -- load persistent host info 772c2aa98e2SPeter Wemm ** 773c2aa98e2SPeter Wemm ** Load information about host that is kept 774c2aa98e2SPeter Wemm ** in common for all running sendmails. 775c2aa98e2SPeter Wemm ** 776c2aa98e2SPeter Wemm ** Parameters: 77712ed1c7cSGregory Neil Shapiro ** mci -- the host/connection to load persistent info for. 778c2aa98e2SPeter Wemm ** 779c2aa98e2SPeter Wemm ** Returns: 78012ed1c7cSGregory Neil Shapiro ** true -- lock was successful 78112ed1c7cSGregory Neil Shapiro ** false -- lock failed 782c2aa98e2SPeter Wemm */ 783c2aa98e2SPeter Wemm 7843299c2f1SGregory Neil Shapiro static bool 785c2aa98e2SPeter Wemm mci_load_persistent(mci) 786c2aa98e2SPeter Wemm MCI *mci; 787c2aa98e2SPeter Wemm { 7883299c2f1SGregory Neil Shapiro int save_errno = errno; 78912ed1c7cSGregory Neil Shapiro bool locked = true; 79012ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 79188ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 792c2aa98e2SPeter Wemm 793c2aa98e2SPeter Wemm if (mci == NULL) 794c2aa98e2SPeter Wemm { 795c2aa98e2SPeter Wemm if (tTd(56, 1)) 79612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: NULL mci\n"); 79712ed1c7cSGregory Neil Shapiro return true; 798c2aa98e2SPeter Wemm } 799c2aa98e2SPeter Wemm 800c2aa98e2SPeter Wemm if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) 80112ed1c7cSGregory Neil Shapiro return true; 802c2aa98e2SPeter Wemm 803c2aa98e2SPeter Wemm /* Already have the persistent information in memory */ 804c2aa98e2SPeter Wemm if (SingleThreadDelivery && mci->mci_statfile != NULL) 80512ed1c7cSGregory Neil Shapiro return true; 806c2aa98e2SPeter Wemm 807c2aa98e2SPeter Wemm if (tTd(56, 1)) 80812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n", 809c2aa98e2SPeter Wemm mci->mci_host); 810c2aa98e2SPeter Wemm 81112ed1c7cSGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, 81212ed1c7cSGregory Neil Shapiro false) < 0) 813c2aa98e2SPeter Wemm { 814c2aa98e2SPeter Wemm /* Not much we can do if the file isn't there... */ 815c2aa98e2SPeter Wemm if (tTd(56, 1)) 81612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Couldn't generate host path\n"); 817c2aa98e2SPeter Wemm goto cleanup; 818c2aa98e2SPeter Wemm } 819c2aa98e2SPeter Wemm 820c2aa98e2SPeter Wemm fp = safefopen(fname, O_RDONLY, FileMode, 821c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 822c2aa98e2SPeter Wemm if (fp == NULL) 823c2aa98e2SPeter Wemm { 824c2aa98e2SPeter Wemm /* I can't think of any reason this should ever happen */ 825c2aa98e2SPeter Wemm if (tTd(56, 1)) 82612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: open(%s): %s\n", 82712ed1c7cSGregory Neil Shapiro fname, sm_errstring(errno)); 828c2aa98e2SPeter Wemm goto cleanup; 829c2aa98e2SPeter Wemm } 830c2aa98e2SPeter Wemm 831c2aa98e2SPeter Wemm FileName = fname; 83212ed1c7cSGregory Neil Shapiro locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "", 83312ed1c7cSGregory Neil Shapiro LOCK_SH|LOCK_NB); 834c2aa98e2SPeter Wemm if (locked) 8353299c2f1SGregory Neil Shapiro { 8363299c2f1SGregory Neil Shapiro (void) mci_read_persistent(fp, mci); 83712ed1c7cSGregory Neil Shapiro (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, 83812ed1c7cSGregory Neil Shapiro "", LOCK_UN); 8393299c2f1SGregory Neil Shapiro } 8403299c2f1SGregory Neil Shapiro FileName = NULL; 84112ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 842c2aa98e2SPeter Wemm 843c2aa98e2SPeter Wemm cleanup: 8443299c2f1SGregory Neil Shapiro errno = save_errno; 845c2aa98e2SPeter Wemm return locked; 846c2aa98e2SPeter Wemm } 84712ed1c7cSGregory Neil Shapiro /* 848c2aa98e2SPeter Wemm ** MCI_READ_PERSISTENT -- read persistent host status file 849c2aa98e2SPeter Wemm ** 850c2aa98e2SPeter Wemm ** Parameters: 851c2aa98e2SPeter Wemm ** fp -- the file pointer to read. 852c2aa98e2SPeter Wemm ** mci -- the pointer to fill in. 853c2aa98e2SPeter Wemm ** 854c2aa98e2SPeter Wemm ** Returns: 855c2aa98e2SPeter Wemm ** -1 -- if the file was corrupt. 856c2aa98e2SPeter Wemm ** 0 -- otherwise. 857c2aa98e2SPeter Wemm ** 858c2aa98e2SPeter Wemm ** Warning: 859c2aa98e2SPeter Wemm ** This code makes the assumption that this data 860c2aa98e2SPeter Wemm ** will be read in an atomic fashion, and that the data 861c2aa98e2SPeter Wemm ** was written in an atomic fashion. Any other functioning 862c2aa98e2SPeter Wemm ** may lead to some form of insanity. This should be 863c2aa98e2SPeter Wemm ** perfectly safe due to underlying stdio buffering. 864c2aa98e2SPeter Wemm */ 865c2aa98e2SPeter Wemm 8663299c2f1SGregory Neil Shapiro static int 867c2aa98e2SPeter Wemm mci_read_persistent(fp, mci) 86812ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 869c2aa98e2SPeter Wemm register MCI *mci; 870c2aa98e2SPeter Wemm { 871c2aa98e2SPeter Wemm int ver; 872c2aa98e2SPeter Wemm register char *p; 873c2aa98e2SPeter Wemm int saveLineNumber = LineNumber; 874c2aa98e2SPeter Wemm char buf[MAXLINE]; 875c2aa98e2SPeter Wemm 876c2aa98e2SPeter Wemm if (fp == NULL) 877c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL fp"); 878c2aa98e2SPeter Wemm if (mci == NULL) 879c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL mci"); 880c2aa98e2SPeter Wemm if (tTd(56, 93)) 881c2aa98e2SPeter Wemm { 88212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_read_persistent: fp=%lx, mci=", 88312ed1c7cSGregory Neil Shapiro (unsigned long) fp); 884c2aa98e2SPeter Wemm } 885c2aa98e2SPeter Wemm 88612ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 88712ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 888c2aa98e2SPeter Wemm 88912ed1c7cSGregory Neil Shapiro sm_io_rewind(fp, SM_TIME_DEFAULT); 890c2aa98e2SPeter Wemm ver = -1; 891c2aa98e2SPeter Wemm LineNumber = 0; 89212ed1c7cSGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 893c2aa98e2SPeter Wemm { 894c2aa98e2SPeter Wemm LineNumber++; 895c2aa98e2SPeter Wemm p = strchr(buf, '\n'); 896c2aa98e2SPeter Wemm if (p != NULL) 897c2aa98e2SPeter Wemm *p = '\0'; 898c2aa98e2SPeter Wemm switch (buf[0]) 899c2aa98e2SPeter Wemm { 900c2aa98e2SPeter Wemm case 'V': /* version stamp */ 901c2aa98e2SPeter Wemm ver = atoi(&buf[1]); 902c2aa98e2SPeter Wemm if (ver < 0 || ver > 0) 903c2aa98e2SPeter Wemm syserr("Unknown host status version %d: %d max", 904c2aa98e2SPeter Wemm ver, 0); 905c2aa98e2SPeter Wemm break; 906c2aa98e2SPeter Wemm 907c2aa98e2SPeter Wemm case 'E': /* UNIX error number */ 908c2aa98e2SPeter Wemm mci->mci_errno = atoi(&buf[1]); 909c2aa98e2SPeter Wemm break; 910c2aa98e2SPeter Wemm 911c2aa98e2SPeter Wemm case 'H': /* DNS error number */ 912c2aa98e2SPeter Wemm mci->mci_herrno = atoi(&buf[1]); 913c2aa98e2SPeter Wemm break; 914c2aa98e2SPeter Wemm 915c2aa98e2SPeter Wemm case 'S': /* UNIX exit status */ 916c2aa98e2SPeter Wemm mci->mci_exitstat = atoi(&buf[1]); 917c2aa98e2SPeter Wemm break; 918c2aa98e2SPeter Wemm 919c2aa98e2SPeter Wemm case 'D': /* DSN status */ 920c2aa98e2SPeter Wemm mci->mci_status = newstr(&buf[1]); 921c2aa98e2SPeter Wemm break; 922c2aa98e2SPeter Wemm 923c2aa98e2SPeter Wemm case 'R': /* SMTP status */ 924c2aa98e2SPeter Wemm mci->mci_rstatus = newstr(&buf[1]); 925c2aa98e2SPeter Wemm break; 926c2aa98e2SPeter Wemm 927c2aa98e2SPeter Wemm case 'U': /* last usage time */ 928c2aa98e2SPeter Wemm mci->mci_lastuse = atol(&buf[1]); 929c2aa98e2SPeter Wemm break; 930c2aa98e2SPeter Wemm 931c2aa98e2SPeter Wemm case '.': /* end of file */ 93212ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 933bfb62e91SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 934c2aa98e2SPeter Wemm return 0; 935c2aa98e2SPeter Wemm 936c2aa98e2SPeter Wemm default: 937c2aa98e2SPeter Wemm sm_syslog(LOG_CRIT, NOQID, 938c2aa98e2SPeter Wemm "%s: line %d: Unknown host status line \"%s\"", 939c2aa98e2SPeter Wemm FileName == NULL ? mci->mci_host : FileName, 940c2aa98e2SPeter Wemm LineNumber, buf); 941c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 942c2aa98e2SPeter Wemm return -1; 943c2aa98e2SPeter Wemm } 944c2aa98e2SPeter Wemm } 945c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 94612ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 94712ed1c7cSGregory Neil Shapiro sm_dprintf("incomplete (missing dot for EOF)\n"); 948c2aa98e2SPeter Wemm if (ver < 0) 949c2aa98e2SPeter Wemm return -1; 950c2aa98e2SPeter Wemm return 0; 951c2aa98e2SPeter Wemm } 95212ed1c7cSGregory Neil Shapiro /* 953c2aa98e2SPeter Wemm ** MCI_STORE_PERSISTENT -- Store persistent MCI information 954c2aa98e2SPeter Wemm ** 955c2aa98e2SPeter Wemm ** Store information about host that is kept 956c2aa98e2SPeter Wemm ** in common for all running sendmails. 957c2aa98e2SPeter Wemm ** 958c2aa98e2SPeter Wemm ** Parameters: 959c2aa98e2SPeter Wemm ** mci -- the host/connection to store persistent info for. 960c2aa98e2SPeter Wemm ** 961c2aa98e2SPeter Wemm ** Returns: 962c2aa98e2SPeter Wemm ** none. 963c2aa98e2SPeter Wemm */ 964c2aa98e2SPeter Wemm 965c2aa98e2SPeter Wemm void 966c2aa98e2SPeter Wemm mci_store_persistent(mci) 967c2aa98e2SPeter Wemm MCI *mci; 968c2aa98e2SPeter Wemm { 9693299c2f1SGregory Neil Shapiro int save_errno = errno; 970c2aa98e2SPeter Wemm 971c2aa98e2SPeter Wemm if (mci == NULL) 972c2aa98e2SPeter Wemm { 973c2aa98e2SPeter Wemm if (tTd(56, 1)) 97412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: NULL mci\n"); 975c2aa98e2SPeter Wemm return; 976c2aa98e2SPeter Wemm } 977c2aa98e2SPeter Wemm 978c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 979c2aa98e2SPeter Wemm return; 980c2aa98e2SPeter Wemm 981c2aa98e2SPeter Wemm if (tTd(56, 1)) 98212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: Storing information for %s\n", 983c2aa98e2SPeter Wemm mci->mci_host); 984c2aa98e2SPeter Wemm 985c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 986c2aa98e2SPeter Wemm { 987c2aa98e2SPeter Wemm if (tTd(56, 1)) 98812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: no statfile\n"); 989c2aa98e2SPeter Wemm return; 990c2aa98e2SPeter Wemm } 991c2aa98e2SPeter Wemm 99212ed1c7cSGregory Neil Shapiro sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT); 993c2aa98e2SPeter Wemm #if !NOFTRUNCATE 99412ed1c7cSGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 99512ed1c7cSGregory Neil Shapiro (off_t) 0); 9963299c2f1SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 997c2aa98e2SPeter Wemm 99812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n"); 99912ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n", 100012ed1c7cSGregory Neil Shapiro mci->mci_errno); 100112ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n", 100212ed1c7cSGregory Neil Shapiro mci->mci_herrno); 100312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n", 100412ed1c7cSGregory Neil Shapiro mci->mci_exitstat); 1005c2aa98e2SPeter Wemm if (mci->mci_status != NULL) 100612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 100712ed1c7cSGregory Neil Shapiro "D%.80s\n", 100812ed1c7cSGregory Neil Shapiro denlstring(mci->mci_status, true, false)); 1009c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 101012ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 101112ed1c7cSGregory Neil Shapiro "R%.80s\n", 101212ed1c7cSGregory Neil Shapiro denlstring(mci->mci_rstatus, true, false)); 101312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n", 101412ed1c7cSGregory Neil Shapiro (long)(mci->mci_lastuse)); 101512ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n"); 1016c2aa98e2SPeter Wemm 101712ed1c7cSGregory Neil Shapiro (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT); 1018c2aa98e2SPeter Wemm 10193299c2f1SGregory Neil Shapiro errno = save_errno; 1020c2aa98e2SPeter Wemm return; 1021c2aa98e2SPeter Wemm } 102212ed1c7cSGregory Neil Shapiro /* 1023c2aa98e2SPeter Wemm ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree 1024c2aa98e2SPeter Wemm ** 1025c2aa98e2SPeter Wemm ** Recursively find all the mci host files in `pathname'. Default to 1026c2aa98e2SPeter Wemm ** main host status directory if no path is provided. 1027c2aa98e2SPeter Wemm ** Call (*action)(pathname, host) for each file found. 1028c2aa98e2SPeter Wemm ** 1029c2aa98e2SPeter Wemm ** Note: all information is collected in a list before it is processed. 1030c2aa98e2SPeter Wemm ** This may not be the best way to do it, but it seems safest, since 1031c2aa98e2SPeter Wemm ** the file system would be touched while we are attempting to traverse 1032c2aa98e2SPeter Wemm ** the directory tree otherwise (during purges). 1033c2aa98e2SPeter Wemm ** 1034c2aa98e2SPeter Wemm ** Parameters: 1035c2aa98e2SPeter Wemm ** action -- function to call on each node. If returns < 0, 1036c2aa98e2SPeter Wemm ** return immediately. 1037c2aa98e2SPeter Wemm ** pathname -- root of tree. If null, use main host status 1038c2aa98e2SPeter Wemm ** directory. 1039c2aa98e2SPeter Wemm ** 1040c2aa98e2SPeter Wemm ** Returns: 1041c2aa98e2SPeter Wemm ** < 0 -- if any action routine returns a negative value, that 1042c2aa98e2SPeter Wemm ** value is returned. 1043c2aa98e2SPeter Wemm ** 0 -- if we successfully went to completion. 10443299c2f1SGregory Neil Shapiro ** > 0 -- return status from action() 1045c2aa98e2SPeter Wemm */ 1046c2aa98e2SPeter Wemm 1047c2aa98e2SPeter Wemm int 1048c2aa98e2SPeter Wemm mci_traverse_persistent(action, pathname) 1049684b2a5fSGregory Neil Shapiro int (*action)__P((char *, char *)); 1050c2aa98e2SPeter Wemm char *pathname; 1051c2aa98e2SPeter Wemm { 1052c2aa98e2SPeter Wemm struct stat statbuf; 1053c2aa98e2SPeter Wemm DIR *d; 1054c2aa98e2SPeter Wemm int ret; 1055c2aa98e2SPeter Wemm 1056c2aa98e2SPeter Wemm if (pathname == NULL) 1057c2aa98e2SPeter Wemm pathname = HostStatDir; 1058c2aa98e2SPeter Wemm if (pathname == NULL) 1059c2aa98e2SPeter Wemm return -1; 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm if (tTd(56, 1)) 106212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: pathname is %s\n", pathname); 1063c2aa98e2SPeter Wemm 1064c2aa98e2SPeter Wemm ret = stat(pathname, &statbuf); 1065c2aa98e2SPeter Wemm if (ret < 0) 1066c2aa98e2SPeter Wemm { 1067c2aa98e2SPeter Wemm if (tTd(56, 2)) 106812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: Failed to stat %s: %s\n", 106912ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1070c2aa98e2SPeter Wemm return ret; 1071c2aa98e2SPeter Wemm } 1072c2aa98e2SPeter Wemm if (S_ISDIR(statbuf.st_mode)) 1073c2aa98e2SPeter Wemm { 10743299c2f1SGregory Neil Shapiro bool leftone, removedone; 107512ed1c7cSGregory Neil Shapiro size_t len; 107612ed1c7cSGregory Neil Shapiro char *newptr; 107712ed1c7cSGregory Neil Shapiro struct dirent *e; 107888ad41d4SGregory Neil Shapiro char newpath[MAXPATHLEN]; 1079c2aa98e2SPeter Wemm 1080c2aa98e2SPeter Wemm if ((d = opendir(pathname)) == NULL) 1081c2aa98e2SPeter Wemm { 1082c2aa98e2SPeter Wemm if (tTd(56, 2)) 108312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: opendir %s: %s\n", 108412ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1085c2aa98e2SPeter Wemm return -1; 1086c2aa98e2SPeter Wemm } 108712ed1c7cSGregory Neil Shapiro len = sizeof(newpath) - MAXNAMLEN - 3; 108812ed1c7cSGregory Neil Shapiro if (sm_strlcpy(newpath, pathname, len) >= len) 1089c2aa98e2SPeter Wemm { 1090c2aa98e2SPeter Wemm if (tTd(56, 2)) 109112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path \"%s\" too long", 1092c2aa98e2SPeter Wemm pathname); 1093c2aa98e2SPeter Wemm return -1; 1094c2aa98e2SPeter Wemm } 1095c2aa98e2SPeter Wemm newptr = newpath + strlen(newpath); 1096c2aa98e2SPeter Wemm *newptr++ = '/'; 1097c2aa98e2SPeter Wemm 10983299c2f1SGregory Neil Shapiro /* 10993299c2f1SGregory Neil Shapiro ** repeat until no file has been removed 11003299c2f1SGregory Neil Shapiro ** this may become ugly when several files "expire" 11013299c2f1SGregory Neil Shapiro ** during these loops, but it's better than doing 11023299c2f1SGregory Neil Shapiro ** a rewinddir() inside the inner loop 11033299c2f1SGregory Neil Shapiro */ 110412ed1c7cSGregory Neil Shapiro 11053299c2f1SGregory Neil Shapiro do 11063299c2f1SGregory Neil Shapiro { 110712ed1c7cSGregory Neil Shapiro leftone = removedone = false; 1108c2aa98e2SPeter Wemm while ((e = readdir(d)) != NULL) 1109c2aa98e2SPeter Wemm { 1110c2aa98e2SPeter Wemm if (e->d_name[0] == '.') 1111c2aa98e2SPeter Wemm continue; 1112c2aa98e2SPeter Wemm 111312ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(newptr, e->d_name, 11143299c2f1SGregory Neil Shapiro sizeof newpath - 11153299c2f1SGregory Neil Shapiro (newptr - newpath)); 1116c2aa98e2SPeter Wemm 1117c0c4794dSGregory Neil Shapiro if (StopRequest) 1118c0c4794dSGregory Neil Shapiro stop_sendmail(); 1119c2aa98e2SPeter Wemm ret = mci_traverse_persistent(action, newpath); 1120c2aa98e2SPeter Wemm if (ret < 0) 1121c2aa98e2SPeter Wemm break; 11223299c2f1SGregory Neil Shapiro if (ret == 1) 112312ed1c7cSGregory Neil Shapiro leftone = true; 11243299c2f1SGregory Neil Shapiro if (!removedone && ret == 0 && 11253299c2f1SGregory Neil Shapiro action == mci_purge_persistent) 112612ed1c7cSGregory Neil Shapiro removedone = true; 11273299c2f1SGregory Neil Shapiro } 11283299c2f1SGregory Neil Shapiro if (ret < 0) 11293299c2f1SGregory Neil Shapiro break; 113012ed1c7cSGregory Neil Shapiro 1131c2aa98e2SPeter Wemm /* 1132c2aa98e2SPeter Wemm ** The following appears to be 1133c2aa98e2SPeter Wemm ** necessary during purges, since 1134c2aa98e2SPeter Wemm ** we modify the directory structure 1135c2aa98e2SPeter Wemm */ 113612ed1c7cSGregory Neil Shapiro 11373299c2f1SGregory Neil Shapiro if (removedone) 1138c2aa98e2SPeter Wemm rewinddir(d); 11393299c2f1SGregory Neil Shapiro if (tTd(56, 40)) 114012ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 11413299c2f1SGregory Neil Shapiro pathname, ret, removedone, leftone); 11423299c2f1SGregory Neil Shapiro } while (removedone); 1143c2aa98e2SPeter Wemm 1144c2aa98e2SPeter Wemm /* purge (or whatever) the directory proper */ 11453299c2f1SGregory Neil Shapiro if (!leftone) 11463299c2f1SGregory Neil Shapiro { 1147c2aa98e2SPeter Wemm *--newptr = '\0'; 1148c2aa98e2SPeter Wemm ret = (*action)(newpath, NULL); 11493299c2f1SGregory Neil Shapiro } 11503299c2f1SGregory Neil Shapiro (void) closedir(d); 1151c2aa98e2SPeter Wemm } 1152c2aa98e2SPeter Wemm else if (S_ISREG(statbuf.st_mode)) 1153c2aa98e2SPeter Wemm { 1154c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 1155c2aa98e2SPeter Wemm char *start; 1156c2aa98e2SPeter Wemm char *scan; 1157c2aa98e2SPeter Wemm char host[MAXHOSTNAMELEN]; 1158c2aa98e2SPeter Wemm char *hostptr = host; 1159c2aa98e2SPeter Wemm 1160c2aa98e2SPeter Wemm /* 1161c2aa98e2SPeter Wemm ** Reconstruct the host name from the path to the 1162c2aa98e2SPeter Wemm ** persistent information. 1163c2aa98e2SPeter Wemm */ 1164c2aa98e2SPeter Wemm 1165c2aa98e2SPeter Wemm do 1166c2aa98e2SPeter Wemm { 1167c2aa98e2SPeter Wemm if (hostptr != host) 1168c2aa98e2SPeter Wemm *(hostptr++) = '.'; 1169c2aa98e2SPeter Wemm start = end; 11707660b554SGregory Neil Shapiro while (start > pathname && *(start - 1) != '/') 1171c2aa98e2SPeter Wemm start--; 1172c2aa98e2SPeter Wemm 1173c2aa98e2SPeter Wemm if (*end == '.') 1174c2aa98e2SPeter Wemm end--; 1175c2aa98e2SPeter Wemm 1176c2aa98e2SPeter Wemm for (scan = start; scan <= end; scan++) 1177c2aa98e2SPeter Wemm *(hostptr++) = *scan; 1178c2aa98e2SPeter Wemm 1179c2aa98e2SPeter Wemm end = start - 2; 11807660b554SGregory Neil Shapiro } while (end > pathname && *end == '.'); 1181c2aa98e2SPeter Wemm 1182c2aa98e2SPeter Wemm *hostptr = '\0'; 1183c2aa98e2SPeter Wemm 1184c2aa98e2SPeter Wemm /* 1185c2aa98e2SPeter Wemm ** Do something with the file containing the persistent 1186c2aa98e2SPeter Wemm ** information. 1187c2aa98e2SPeter Wemm */ 118812ed1c7cSGregory Neil Shapiro 1189c2aa98e2SPeter Wemm ret = (*action)(pathname, host); 1190c2aa98e2SPeter Wemm } 1191c2aa98e2SPeter Wemm 1192c2aa98e2SPeter Wemm return ret; 1193c2aa98e2SPeter Wemm } 119412ed1c7cSGregory Neil Shapiro /* 11953299c2f1SGregory Neil Shapiro ** MCI_PRINT_PERSISTENT -- print persistent info 1196c2aa98e2SPeter Wemm ** 1197c2aa98e2SPeter Wemm ** Dump the persistent information in the file 'pathname' 1198c2aa98e2SPeter Wemm ** 1199c2aa98e2SPeter Wemm ** Parameters: 1200c2aa98e2SPeter Wemm ** pathname -- the pathname to the status file. 1201c2aa98e2SPeter Wemm ** hostname -- the corresponding host name. 1202c2aa98e2SPeter Wemm ** 1203c2aa98e2SPeter Wemm ** Returns: 1204c2aa98e2SPeter Wemm ** 0 1205c2aa98e2SPeter Wemm */ 1206c2aa98e2SPeter Wemm 1207c2aa98e2SPeter Wemm int 1208c2aa98e2SPeter Wemm mci_print_persistent(pathname, hostname) 1209c2aa98e2SPeter Wemm char *pathname; 1210c2aa98e2SPeter Wemm char *hostname; 1211c2aa98e2SPeter Wemm { 121212ed1c7cSGregory Neil Shapiro static bool initflag = false; 121312ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 1214c2aa98e2SPeter Wemm int width = Verbose ? 78 : 25; 1215c2aa98e2SPeter Wemm bool locked; 1216c2aa98e2SPeter Wemm MCI mcib; 1217c2aa98e2SPeter Wemm 1218c2aa98e2SPeter Wemm /* skip directories */ 1219c2aa98e2SPeter Wemm if (hostname == NULL) 1220c2aa98e2SPeter Wemm return 0; 1221c2aa98e2SPeter Wemm 1222c0c4794dSGregory Neil Shapiro if (StopRequest) 1223c0c4794dSGregory Neil Shapiro stop_sendmail(); 1224c0c4794dSGregory Neil Shapiro 1225c2aa98e2SPeter Wemm if (!initflag) 1226c2aa98e2SPeter Wemm { 122712ed1c7cSGregory Neil Shapiro initflag = true; 122812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 122912ed1c7cSGregory Neil Shapiro " -------------- Hostname --------------- How long ago ---------Results---------\n"); 1230c2aa98e2SPeter Wemm } 1231c2aa98e2SPeter Wemm 123212ed1c7cSGregory Neil Shapiro fp = safefopen(pathname, O_RDONLY, FileMode, 1233c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 1234c2aa98e2SPeter Wemm 1235c2aa98e2SPeter Wemm if (fp == NULL) 1236c2aa98e2SPeter Wemm { 1237c2aa98e2SPeter Wemm if (tTd(56, 1)) 123812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 123912ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1240c2aa98e2SPeter Wemm return 0; 1241c2aa98e2SPeter Wemm } 1242c2aa98e2SPeter Wemm 1243c2aa98e2SPeter Wemm FileName = pathname; 12443299c2f1SGregory Neil Shapiro memset(&mcib, '\0', sizeof mcib); 1245c2aa98e2SPeter Wemm if (mci_read_persistent(fp, &mcib) < 0) 1246c2aa98e2SPeter Wemm { 1247c2aa98e2SPeter Wemm syserr("%s: could not read status file", pathname); 124812ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1249c2aa98e2SPeter Wemm FileName = NULL; 1250c2aa98e2SPeter Wemm return 0; 1251c2aa98e2SPeter Wemm } 1252c2aa98e2SPeter Wemm 125312ed1c7cSGregory Neil Shapiro locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 125412ed1c7cSGregory Neil Shapiro "", LOCK_SH|LOCK_NB); 125512ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1256c2aa98e2SPeter Wemm FileName = NULL; 1257c2aa98e2SPeter Wemm 125812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 1259c2aa98e2SPeter Wemm locked ? '*' : ' ', hostname, 126012ed1c7cSGregory Neil Shapiro pintvl(curtime() - mcib.mci_lastuse, true)); 1261c2aa98e2SPeter Wemm if (mcib.mci_rstatus != NULL) 126212ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 126312ed1c7cSGregory Neil Shapiro mcib.mci_rstatus); 1264c2aa98e2SPeter Wemm else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 126512ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 126612ed1c7cSGregory Neil Shapiro "Deferred: %.*s\n", width - 10, 126712ed1c7cSGregory Neil Shapiro sm_errstring(mcib.mci_errno)); 1268c2aa98e2SPeter Wemm else if (mcib.mci_exitstat != 0) 1269c2aa98e2SPeter Wemm { 127012ed1c7cSGregory Neil Shapiro char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 1271c2aa98e2SPeter Wemm 127212ed1c7cSGregory Neil Shapiro if (exmsg == NULL) 1273c2aa98e2SPeter Wemm { 1274c2aa98e2SPeter Wemm char buf[80]; 1275c2aa98e2SPeter Wemm 127612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, 127712ed1c7cSGregory Neil Shapiro "Unknown mailer error %d", 1278c2aa98e2SPeter Wemm mcib.mci_exitstat); 127912ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 128012ed1c7cSGregory Neil Shapiro width, buf); 1281c2aa98e2SPeter Wemm } 1282c2aa98e2SPeter Wemm else 128312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 128412ed1c7cSGregory Neil Shapiro width, &exmsg[5]); 1285c2aa98e2SPeter Wemm } 1286c2aa98e2SPeter Wemm else if (mcib.mci_errno == 0) 128712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 1288c2aa98e2SPeter Wemm else 128912ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 129012ed1c7cSGregory Neil Shapiro width - 4, sm_errstring(mcib.mci_errno)); 1291c2aa98e2SPeter Wemm 1292c2aa98e2SPeter Wemm return 0; 1293c2aa98e2SPeter Wemm } 129412ed1c7cSGregory Neil Shapiro /* 1295c2aa98e2SPeter Wemm ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 1296c2aa98e2SPeter Wemm ** 1297c2aa98e2SPeter Wemm ** Parameters: 1298c2aa98e2SPeter Wemm ** pathname -- path to the status file. 1299c2aa98e2SPeter Wemm ** hostname -- name of host corresponding to that file. 1300c2aa98e2SPeter Wemm ** NULL if this is a directory (domain). 1301c2aa98e2SPeter Wemm ** 1302c2aa98e2SPeter Wemm ** Returns: 13033299c2f1SGregory Neil Shapiro ** 0 -- ok 13043299c2f1SGregory Neil Shapiro ** 1 -- file not deleted (too young, incorrect format) 13053299c2f1SGregory Neil Shapiro ** < 0 -- some error occurred 1306c2aa98e2SPeter Wemm */ 1307c2aa98e2SPeter Wemm 1308c2aa98e2SPeter Wemm int 1309c2aa98e2SPeter Wemm mci_purge_persistent(pathname, hostname) 1310c2aa98e2SPeter Wemm char *pathname; 1311c2aa98e2SPeter Wemm char *hostname; 1312c2aa98e2SPeter Wemm { 13133299c2f1SGregory Neil Shapiro struct stat statbuf; 1314c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 13153299c2f1SGregory Neil Shapiro int ret; 1316c2aa98e2SPeter Wemm 1317c2aa98e2SPeter Wemm if (tTd(56, 1)) 131812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 1319c2aa98e2SPeter Wemm 13203299c2f1SGregory Neil Shapiro ret = stat(pathname, &statbuf); 13213299c2f1SGregory Neil Shapiro if (ret < 0) 13223299c2f1SGregory Neil Shapiro { 13233299c2f1SGregory Neil Shapiro if (tTd(56, 2)) 132412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 132512ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 13263299c2f1SGregory Neil Shapiro return ret; 13273299c2f1SGregory Neil Shapiro } 1328320f00e7SGregory Neil Shapiro if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 13293299c2f1SGregory Neil Shapiro return 1; 1330c2aa98e2SPeter Wemm if (hostname != NULL) 1331c2aa98e2SPeter Wemm { 1332c2aa98e2SPeter Wemm /* remove the file */ 133312ed1c7cSGregory Neil Shapiro ret = unlink(pathname); 133412ed1c7cSGregory Neil Shapiro if (ret < 0) 1335c2aa98e2SPeter Wemm { 133612ed1c7cSGregory Neil Shapiro if (LogLevel > 8) 133712ed1c7cSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 133812ed1c7cSGregory Neil Shapiro "mci_purge_persistent: failed to unlink %s: %s", 133912ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1340c2aa98e2SPeter Wemm if (tTd(56, 2)) 134112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 134212ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 134312ed1c7cSGregory Neil Shapiro return ret; 1344c2aa98e2SPeter Wemm } 1345c2aa98e2SPeter Wemm } 1346c2aa98e2SPeter Wemm else 1347c2aa98e2SPeter Wemm { 1348c2aa98e2SPeter Wemm /* remove the directory */ 1349c2aa98e2SPeter Wemm if (*end != '.') 13503299c2f1SGregory Neil Shapiro return 1; 1351c2aa98e2SPeter Wemm 1352c2aa98e2SPeter Wemm if (tTd(56, 1)) 135312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 1354c2aa98e2SPeter Wemm 135512ed1c7cSGregory Neil Shapiro ret = rmdir(pathname); 135612ed1c7cSGregory Neil Shapiro if (ret < 0) 1357c2aa98e2SPeter Wemm { 1358c2aa98e2SPeter Wemm if (tTd(56, 2)) 135912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 136012ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 136112ed1c7cSGregory Neil Shapiro return ret; 1362c2aa98e2SPeter Wemm } 1363c2aa98e2SPeter Wemm } 1364c2aa98e2SPeter Wemm 1365c2aa98e2SPeter Wemm return 0; 1366c2aa98e2SPeter Wemm } 136712ed1c7cSGregory Neil Shapiro /* 1368c2aa98e2SPeter Wemm ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 1369c2aa98e2SPeter Wemm ** 13707660b554SGregory Neil Shapiro ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 1371c2aa98e2SPeter Wemm ** putting the result into `path'. if `createflag' is set, intervening 1372c2aa98e2SPeter Wemm ** directories will be created as needed. 1373c2aa98e2SPeter Wemm ** 1374c2aa98e2SPeter Wemm ** Parameters: 1375c2aa98e2SPeter Wemm ** host -- host name to convert from. 1376c2aa98e2SPeter Wemm ** path -- place to store result. 1377c2aa98e2SPeter Wemm ** pathlen -- length of path buffer. 1378c2aa98e2SPeter Wemm ** createflag -- if set, create intervening directories as 1379c2aa98e2SPeter Wemm ** needed. 1380c2aa98e2SPeter Wemm ** 1381c2aa98e2SPeter Wemm ** Returns: 1382c2aa98e2SPeter Wemm ** 0 -- success 1383c2aa98e2SPeter Wemm ** -1 -- failure 1384c2aa98e2SPeter Wemm */ 1385c2aa98e2SPeter Wemm 13863299c2f1SGregory Neil Shapiro static int 1387c2aa98e2SPeter Wemm mci_generate_persistent_path(host, path, pathlen, createflag) 1388c2aa98e2SPeter Wemm const char *host; 1389c2aa98e2SPeter Wemm char *path; 1390c2aa98e2SPeter Wemm int pathlen; 1391c2aa98e2SPeter Wemm bool createflag; 1392c2aa98e2SPeter Wemm { 1393c2aa98e2SPeter Wemm char *elem, *p, *x, ch; 1394c2aa98e2SPeter Wemm int ret = 0; 1395c2aa98e2SPeter Wemm int len; 1396c2aa98e2SPeter Wemm char t_host[MAXHOSTNAMELEN]; 13973299c2f1SGregory Neil Shapiro #if NETINET6 13983299c2f1SGregory Neil Shapiro struct in6_addr in6_addr; 13993299c2f1SGregory Neil Shapiro #endif /* NETINET6 */ 1400c2aa98e2SPeter Wemm 1401c2aa98e2SPeter Wemm /* 1402c2aa98e2SPeter Wemm ** Rationality check the arguments. 1403c2aa98e2SPeter Wemm */ 1404c2aa98e2SPeter Wemm 1405c2aa98e2SPeter Wemm if (host == NULL) 1406c2aa98e2SPeter Wemm { 1407c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null host"); 1408c2aa98e2SPeter Wemm return -1; 1409c2aa98e2SPeter Wemm } 1410c2aa98e2SPeter Wemm if (path == NULL) 1411c2aa98e2SPeter Wemm { 1412c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null path"); 1413c2aa98e2SPeter Wemm return -1; 1414c2aa98e2SPeter Wemm } 1415c2aa98e2SPeter Wemm 1416c2aa98e2SPeter Wemm if (tTd(56, 80)) 141712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_generate_persistent_path(%s): ", host); 1418c2aa98e2SPeter Wemm 1419c2aa98e2SPeter Wemm if (*host == '\0' || *host == '.') 1420c2aa98e2SPeter Wemm return -1; 1421c2aa98e2SPeter Wemm 1422c2aa98e2SPeter Wemm /* make certain this is not a bracketed host number */ 1423c2aa98e2SPeter Wemm if (strlen(host) > sizeof t_host - 1) 1424c2aa98e2SPeter Wemm return -1; 1425c2aa98e2SPeter Wemm if (host[0] == '[') 142612ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(t_host, host + 1, sizeof t_host); 1427c2aa98e2SPeter Wemm else 142812ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(t_host, host, sizeof t_host); 1429c2aa98e2SPeter Wemm 1430c2aa98e2SPeter Wemm /* 1431c2aa98e2SPeter Wemm ** Delete any trailing dots from the hostname. 1432c2aa98e2SPeter Wemm ** Leave 'elem' pointing at the \0. 1433c2aa98e2SPeter Wemm */ 1434c2aa98e2SPeter Wemm 1435c2aa98e2SPeter Wemm elem = t_host + strlen(t_host); 1436c2aa98e2SPeter Wemm while (elem > t_host && 1437c2aa98e2SPeter Wemm (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 1438c2aa98e2SPeter Wemm *--elem = '\0'; 1439c2aa98e2SPeter Wemm 1440c2aa98e2SPeter Wemm /* check for bogus bracketed address */ 144112ed1c7cSGregory Neil Shapiro if (host[0] == '[') 144212ed1c7cSGregory Neil Shapiro { 144312ed1c7cSGregory Neil Shapiro bool good = false; 14443299c2f1SGregory Neil Shapiro # if NETINET6 144512ed1c7cSGregory Neil Shapiro if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 144612ed1c7cSGregory Neil Shapiro good = true; 14473299c2f1SGregory Neil Shapiro # endif /* NETINET6 */ 14483299c2f1SGregory Neil Shapiro # if NETINET 144912ed1c7cSGregory Neil Shapiro if (inet_addr(t_host) != INADDR_NONE) 145012ed1c7cSGregory Neil Shapiro good = true; 14513299c2f1SGregory Neil Shapiro # endif /* NETINET */ 145212ed1c7cSGregory Neil Shapiro if (!good) 1453c2aa98e2SPeter Wemm return -1; 145412ed1c7cSGregory Neil Shapiro } 1455c2aa98e2SPeter Wemm 1456c2aa98e2SPeter Wemm /* check for what will be the final length of the path */ 1457c2aa98e2SPeter Wemm len = strlen(HostStatDir) + 2; 1458c2aa98e2SPeter Wemm for (p = (char *) t_host; *p != '\0'; p++) 1459c2aa98e2SPeter Wemm { 1460c2aa98e2SPeter Wemm if (*p == '.') 1461c2aa98e2SPeter Wemm len++; 1462c2aa98e2SPeter Wemm len++; 1463c2aa98e2SPeter Wemm if (p[0] == '.' && p[1] == '.') 1464c2aa98e2SPeter Wemm return -1; 1465c2aa98e2SPeter Wemm } 1466c2aa98e2SPeter Wemm if (len > pathlen || len < 1) 1467c2aa98e2SPeter Wemm return -1; 146812ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(path, HostStatDir, pathlen); 1469c2aa98e2SPeter Wemm p = path + strlen(path); 1470c2aa98e2SPeter Wemm while (elem > t_host) 1471c2aa98e2SPeter Wemm { 1472c2aa98e2SPeter Wemm if (!path_is_dir(path, createflag)) 1473c2aa98e2SPeter Wemm { 1474c2aa98e2SPeter Wemm ret = -1; 1475c2aa98e2SPeter Wemm break; 1476c2aa98e2SPeter Wemm } 1477c2aa98e2SPeter Wemm elem--; 1478c2aa98e2SPeter Wemm while (elem >= t_host && *elem != '.') 1479c2aa98e2SPeter Wemm elem--; 1480c2aa98e2SPeter Wemm *p++ = '/'; 1481c2aa98e2SPeter Wemm x = elem + 1; 1482c2aa98e2SPeter Wemm while ((ch = *x++) != '\0' && ch != '.') 1483c2aa98e2SPeter Wemm { 1484c2aa98e2SPeter Wemm if (isascii(ch) && isupper(ch)) 1485c2aa98e2SPeter Wemm ch = tolower(ch); 1486c2aa98e2SPeter Wemm if (ch == '/') 1487c2aa98e2SPeter Wemm ch = ':'; /* / -> : */ 1488c2aa98e2SPeter Wemm *p++ = ch; 1489c2aa98e2SPeter Wemm } 1490c2aa98e2SPeter Wemm if (elem >= t_host) 1491c2aa98e2SPeter Wemm *p++ = '.'; 1492c2aa98e2SPeter Wemm *p = '\0'; 1493c2aa98e2SPeter Wemm } 1494c2aa98e2SPeter Wemm if (tTd(56, 80)) 1495c2aa98e2SPeter Wemm { 1496c2aa98e2SPeter Wemm if (ret < 0) 149712ed1c7cSGregory Neil Shapiro sm_dprintf("FAILURE %d\n", ret); 1498c2aa98e2SPeter Wemm else 149912ed1c7cSGregory Neil Shapiro sm_dprintf("SUCCESS %s\n", path); 1500c2aa98e2SPeter Wemm } 15013299c2f1SGregory Neil Shapiro return ret; 1502c2aa98e2SPeter Wemm } 1503