1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2005, 2010 Proofpoint, 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 * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 143299c2f1SGregory Neil Shapiro #include <sendmail.h> 153299c2f1SGregory Neil Shapiro 16*4313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: mci.c,v 8.225 2013-11-22 20:51:56 ca Exp $") 173299c2f1SGregory Neil Shapiro 183299c2f1SGregory Neil Shapiro #if NETINET || NETINET6 19c2aa98e2SPeter Wemm # include <arpa/inet.h> 203299c2f1SGregory Neil Shapiro #endif /* NETINET || NETINET6 */ 213299c2f1SGregory Neil Shapiro 22c2aa98e2SPeter Wemm #include <dirent.h> 23c2aa98e2SPeter Wemm 243299c2f1SGregory Neil Shapiro static int mci_generate_persistent_path __P((const char *, char *, 253299c2f1SGregory Neil Shapiro int, bool)); 263299c2f1SGregory Neil Shapiro static bool mci_load_persistent __P((MCI *)); 273299c2f1SGregory Neil Shapiro static void mci_uncache __P((MCI **, bool)); 283299c2f1SGregory Neil Shapiro static int mci_lock_host_statfile __P((MCI *)); 2912ed1c7cSGregory Neil Shapiro static int mci_read_persistent __P((SM_FILE_T *, MCI *)); 303299c2f1SGregory Neil Shapiro 31c2aa98e2SPeter Wemm /* 32c2aa98e2SPeter Wemm ** Mail Connection Information (MCI) Caching Module. 33c2aa98e2SPeter Wemm ** 34c2aa98e2SPeter Wemm ** There are actually two separate things cached. The first is 35c2aa98e2SPeter Wemm ** the set of all open connections -- these are stored in a 36c2aa98e2SPeter Wemm ** (small) list. The second is stored in the symbol table; it 37c2aa98e2SPeter Wemm ** has the overall status for all hosts, whether or not there 38c2aa98e2SPeter Wemm ** is a connection open currently. 39c2aa98e2SPeter Wemm ** 40c2aa98e2SPeter Wemm ** There should never be too many connections open (since this 41c2aa98e2SPeter Wemm ** could flood the socket table), nor should a connection be 42c2aa98e2SPeter Wemm ** allowed to sit idly for too long. 43c2aa98e2SPeter Wemm ** 44c2aa98e2SPeter Wemm ** MaxMciCache is the maximum number of open connections that 45c2aa98e2SPeter Wemm ** will be supported. 46c2aa98e2SPeter Wemm ** 47c2aa98e2SPeter Wemm ** MciCacheTimeout is the time (in seconds) that a connection 48c2aa98e2SPeter Wemm ** is permitted to survive without activity. 49c2aa98e2SPeter Wemm ** 50567a2fc9SGregory Neil Shapiro ** We actually try any cached connections by sending a RSET 51567a2fc9SGregory Neil Shapiro ** before we use them; if the RSET fails we close down the 52567a2fc9SGregory Neil Shapiro ** connection and reopen it (see smtpprobe()). 53c2aa98e2SPeter Wemm ** 54c2aa98e2SPeter Wemm ** The persistent MCI code is donated by Mark Lovell and Paul 55c2aa98e2SPeter Wemm ** Vixie. It is based on the long term host status code in KJS 56c2aa98e2SPeter Wemm ** written by Paul but has been adapted by Mark to fit into the 57c2aa98e2SPeter Wemm ** MCI structure. 58c2aa98e2SPeter Wemm */ 59c2aa98e2SPeter Wemm 603299c2f1SGregory Neil Shapiro static MCI **MciCache; /* the open connection cache */ 61c2aa98e2SPeter Wemm 6212ed1c7cSGregory Neil Shapiro /* 63c2aa98e2SPeter Wemm ** MCI_CACHE -- enter a connection structure into the open connection cache 64c2aa98e2SPeter Wemm ** 65c2aa98e2SPeter Wemm ** This may cause something else to be flushed. 66c2aa98e2SPeter Wemm ** 67c2aa98e2SPeter Wemm ** Parameters: 68c2aa98e2SPeter Wemm ** mci -- the connection to cache. 69c2aa98e2SPeter Wemm ** 70c2aa98e2SPeter Wemm ** Returns: 71c2aa98e2SPeter Wemm ** none. 72c2aa98e2SPeter Wemm */ 73c2aa98e2SPeter Wemm 74c2aa98e2SPeter Wemm void 75c2aa98e2SPeter Wemm mci_cache(mci) 76c2aa98e2SPeter Wemm register MCI *mci; 77c2aa98e2SPeter Wemm { 78c2aa98e2SPeter Wemm register MCI **mcislot; 79c2aa98e2SPeter Wemm 80c2aa98e2SPeter Wemm /* 81c2aa98e2SPeter Wemm ** Find the best slot. This may cause expired connections 82c2aa98e2SPeter Wemm ** to be closed. 83c2aa98e2SPeter Wemm */ 84c2aa98e2SPeter Wemm 85c2aa98e2SPeter Wemm mcislot = mci_scan(mci); 86c2aa98e2SPeter Wemm if (mcislot == NULL) 87c2aa98e2SPeter Wemm { 88c2aa98e2SPeter Wemm /* we don't support caching */ 89c2aa98e2SPeter Wemm return; 90c2aa98e2SPeter Wemm } 91c2aa98e2SPeter Wemm 92c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 93c2aa98e2SPeter Wemm return; 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm /* if this is already cached, we are done */ 96c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 97c2aa98e2SPeter Wemm return; 98c2aa98e2SPeter Wemm 99c2aa98e2SPeter Wemm /* otherwise we may have to clear the slot */ 100c2aa98e2SPeter Wemm if (*mcislot != NULL) 10112ed1c7cSGregory Neil Shapiro mci_uncache(mcislot, true); 102c2aa98e2SPeter Wemm 103c2aa98e2SPeter Wemm if (tTd(42, 5)) 10412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_cache: caching %p (%s) in slot %d\n", 10512ed1c7cSGregory Neil Shapiro mci, mci->mci_host, (int) (mcislot - MciCache)); 106c2aa98e2SPeter Wemm if (tTd(91, 100)) 107c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 1083299c2f1SGregory Neil Shapiro "mci_cache: caching %lx (%.100s) in slot %d", 10912ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 11012ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache)); 111c2aa98e2SPeter Wemm 112c2aa98e2SPeter Wemm *mcislot = mci; 113c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CACHED; 114c2aa98e2SPeter Wemm } 11512ed1c7cSGregory Neil Shapiro /* 116c2aa98e2SPeter Wemm ** MCI_SCAN -- scan the cache, flush junk, and return best slot 117c2aa98e2SPeter Wemm ** 118c2aa98e2SPeter Wemm ** Parameters: 119c2aa98e2SPeter Wemm ** savemci -- never flush this one. Can be null. 120c2aa98e2SPeter Wemm ** 121c2aa98e2SPeter Wemm ** Returns: 122c2aa98e2SPeter Wemm ** The LRU (or empty) slot. 123c2aa98e2SPeter Wemm */ 124c2aa98e2SPeter Wemm 125c2aa98e2SPeter Wemm MCI ** 126c2aa98e2SPeter Wemm mci_scan(savemci) 127c2aa98e2SPeter Wemm MCI *savemci; 128c2aa98e2SPeter Wemm { 129c2aa98e2SPeter Wemm time_t now; 130c2aa98e2SPeter Wemm register MCI **bestmci; 131c2aa98e2SPeter Wemm register MCI *mci; 132c2aa98e2SPeter Wemm register int i; 133c2aa98e2SPeter Wemm 134c2aa98e2SPeter Wemm if (MaxMciCache <= 0) 135c2aa98e2SPeter Wemm { 136c2aa98e2SPeter Wemm /* we don't support caching */ 137c2aa98e2SPeter Wemm return NULL; 138c2aa98e2SPeter Wemm } 139c2aa98e2SPeter Wemm 140c2aa98e2SPeter Wemm if (MciCache == NULL) 141c2aa98e2SPeter Wemm { 142c2aa98e2SPeter Wemm /* first call */ 143951742c4SGregory Neil Shapiro MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof(*MciCache)); 144951742c4SGregory Neil Shapiro memset((char *) MciCache, '\0', MaxMciCache * sizeof(*MciCache)); 1453299c2f1SGregory Neil Shapiro return &MciCache[0]; 146c2aa98e2SPeter Wemm } 147c2aa98e2SPeter Wemm 148c2aa98e2SPeter Wemm now = curtime(); 149c2aa98e2SPeter Wemm bestmci = &MciCache[0]; 150c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 151c2aa98e2SPeter Wemm { 152c2aa98e2SPeter Wemm mci = MciCache[i]; 153c2aa98e2SPeter Wemm if (mci == NULL || mci->mci_state == MCIS_CLOSED) 154c2aa98e2SPeter Wemm { 155c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 156c2aa98e2SPeter Wemm continue; 157c2aa98e2SPeter Wemm } 158320f00e7SGregory Neil Shapiro if ((mci->mci_lastuse + MciCacheTimeout <= now || 1593299c2f1SGregory Neil Shapiro (mci->mci_mailer != NULL && 1603299c2f1SGregory Neil Shapiro mci->mci_mailer->m_maxdeliveries > 0 && 1613299c2f1SGregory Neil Shapiro mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&& 1623299c2f1SGregory Neil Shapiro mci != savemci) 163c2aa98e2SPeter Wemm { 1643299c2f1SGregory Neil Shapiro /* connection idle too long or too many deliveries */ 165c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 1663299c2f1SGregory Neil Shapiro 1673299c2f1SGregory Neil Shapiro /* close it */ 16812ed1c7cSGregory Neil Shapiro mci_uncache(bestmci, true); 169c2aa98e2SPeter Wemm continue; 170c2aa98e2SPeter Wemm } 171c2aa98e2SPeter Wemm if (*bestmci == NULL) 172c2aa98e2SPeter Wemm continue; 173c2aa98e2SPeter Wemm if (mci->mci_lastuse < (*bestmci)->mci_lastuse) 174c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 175c2aa98e2SPeter Wemm } 176c2aa98e2SPeter Wemm return bestmci; 177c2aa98e2SPeter Wemm } 17812ed1c7cSGregory Neil Shapiro /* 179c2aa98e2SPeter Wemm ** MCI_UNCACHE -- remove a connection from a slot. 180c2aa98e2SPeter Wemm ** 181c2aa98e2SPeter Wemm ** May close a connection. 182c2aa98e2SPeter Wemm ** 183c2aa98e2SPeter Wemm ** Parameters: 184c2aa98e2SPeter Wemm ** mcislot -- the slot to empty. 18512ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol on this connection. 18612ed1c7cSGregory Neil Shapiro ** if false, we are assumed to be in a forked child; 187c2aa98e2SPeter Wemm ** all we want to do is close the file(s). 188c2aa98e2SPeter Wemm ** 189c2aa98e2SPeter Wemm ** Returns: 190c2aa98e2SPeter Wemm ** none. 191c2aa98e2SPeter Wemm */ 192c2aa98e2SPeter Wemm 1933299c2f1SGregory Neil Shapiro static void 194c2aa98e2SPeter Wemm mci_uncache(mcislot, doquit) 195c2aa98e2SPeter Wemm register MCI **mcislot; 196c2aa98e2SPeter Wemm bool doquit; 197c2aa98e2SPeter Wemm { 198c2aa98e2SPeter Wemm register MCI *mci; 199c2aa98e2SPeter Wemm extern ENVELOPE BlankEnvelope; 200c2aa98e2SPeter Wemm 201c2aa98e2SPeter Wemm mci = *mcislot; 202c2aa98e2SPeter Wemm if (mci == NULL) 203c2aa98e2SPeter Wemm return; 204c2aa98e2SPeter Wemm *mcislot = NULL; 205c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 206c2aa98e2SPeter Wemm return; 207c2aa98e2SPeter Wemm 208c2aa98e2SPeter Wemm mci_unlock_host(mci); 209c2aa98e2SPeter Wemm 210c2aa98e2SPeter Wemm if (tTd(42, 5)) 21112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n", 21212ed1c7cSGregory Neil Shapiro mci, mci->mci_host, (int) (mcislot - MciCache), 21312ed1c7cSGregory Neil Shapiro doquit); 214c2aa98e2SPeter Wemm if (tTd(91, 100)) 215c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 2163299c2f1SGregory Neil Shapiro "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)", 21712ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 21812ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache), doquit); 219c2aa98e2SPeter Wemm 2203299c2f1SGregory Neil Shapiro mci->mci_deliveries = 0; 221c2aa98e2SPeter Wemm if (doquit) 222c2aa98e2SPeter Wemm { 223c2aa98e2SPeter Wemm message("Closing connection to %s", mci->mci_host); 224c2aa98e2SPeter Wemm 225c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_CACHED; 226c2aa98e2SPeter Wemm 227c2aa98e2SPeter Wemm /* only uses the envelope to flush the transcript file */ 228c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 229c2aa98e2SPeter Wemm smtpquit(mci->mci_mailer, mci, &BlankEnvelope); 23012ed1c7cSGregory Neil Shapiro #if XLA 231c2aa98e2SPeter Wemm xla_host_end(mci->mci_host); 2323299c2f1SGregory Neil Shapiro #endif /* XLA */ 233c2aa98e2SPeter Wemm } 234c2aa98e2SPeter Wemm else 235c2aa98e2SPeter Wemm { 236c2aa98e2SPeter Wemm if (mci->mci_in != NULL) 23712ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 238c2aa98e2SPeter Wemm if (mci->mci_out != NULL) 23912ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 240c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 241c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 242c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 243c2aa98e2SPeter Wemm mci->mci_errno = 0; 244c2aa98e2SPeter Wemm mci->mci_flags = 0; 24512ed1c7cSGregory Neil Shapiro 24612ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 24712ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 24812ed1c7cSGregory Neil Shapiro #if PIPELINING 24912ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 25012ed1c7cSGregory Neil Shapiro #endif /* PIPELINING */ 25112ed1c7cSGregory Neil Shapiro } 25212ed1c7cSGregory Neil Shapiro 25312ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 25412ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 25512ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_heloname); 25612ed1c7cSGregory Neil Shapiro if (mci->mci_rpool != NULL) 25712ed1c7cSGregory Neil Shapiro { 25812ed1c7cSGregory Neil Shapiro sm_rpool_free(mci->mci_rpool); 25912ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = NULL; 26012ed1c7cSGregory Neil Shapiro mci->mci_rpool = NULL; 261c2aa98e2SPeter Wemm } 262c2aa98e2SPeter Wemm } 26312ed1c7cSGregory Neil Shapiro /* 264c2aa98e2SPeter Wemm ** MCI_FLUSH -- flush the entire cache 265c2aa98e2SPeter Wemm ** 266c2aa98e2SPeter Wemm ** Parameters: 26712ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol. 26812ed1c7cSGregory Neil Shapiro ** if false, just close the connection. 269c2aa98e2SPeter Wemm ** allbut -- but leave this one open. 270c2aa98e2SPeter Wemm ** 271c2aa98e2SPeter Wemm ** Returns: 272c2aa98e2SPeter Wemm ** none. 273c2aa98e2SPeter Wemm */ 274c2aa98e2SPeter Wemm 275c2aa98e2SPeter Wemm void 276c2aa98e2SPeter Wemm mci_flush(doquit, allbut) 277c2aa98e2SPeter Wemm bool doquit; 278c2aa98e2SPeter Wemm MCI *allbut; 279c2aa98e2SPeter Wemm { 280c2aa98e2SPeter Wemm register int i; 281c2aa98e2SPeter Wemm 282c2aa98e2SPeter Wemm if (MciCache == NULL) 283c2aa98e2SPeter Wemm return; 284c2aa98e2SPeter Wemm 285c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 286c46d91b7SGregory Neil Shapiro { 287c2aa98e2SPeter Wemm if (allbut != MciCache[i]) 288c2aa98e2SPeter Wemm mci_uncache(&MciCache[i], doquit); 289c2aa98e2SPeter Wemm } 290c46d91b7SGregory Neil Shapiro } 2916f9c8e5bSGregory Neil Shapiro 2926f9c8e5bSGregory Neil Shapiro /* 2936f9c8e5bSGregory Neil Shapiro ** MCI_CLR_EXTENSIONS -- clear knowledge about SMTP extensions 2946f9c8e5bSGregory Neil Shapiro ** 2956f9c8e5bSGregory Neil Shapiro ** Parameters: 2966f9c8e5bSGregory Neil Shapiro ** mci -- the connection to clear. 2976f9c8e5bSGregory Neil Shapiro ** 2986f9c8e5bSGregory Neil Shapiro ** Returns: 2996f9c8e5bSGregory Neil Shapiro ** none. 3006f9c8e5bSGregory Neil Shapiro */ 3016f9c8e5bSGregory Neil Shapiro 3026f9c8e5bSGregory Neil Shapiro void 3036f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci) 3046f9c8e5bSGregory Neil Shapiro MCI *mci; 3056f9c8e5bSGregory Neil Shapiro { 3066f9c8e5bSGregory Neil Shapiro if (mci == NULL) 3076f9c8e5bSGregory Neil Shapiro return; 3086f9c8e5bSGregory Neil Shapiro 3096f9c8e5bSGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 3106f9c8e5bSGregory Neil Shapiro mci->mci_maxsize = 0; 3116f9c8e5bSGregory Neil Shapiro mci->mci_min_by = 0; 3126f9c8e5bSGregory Neil Shapiro #if SASL 3136f9c8e5bSGregory Neil Shapiro mci->mci_saslcap = NULL; 3146f9c8e5bSGregory Neil Shapiro #endif /* SASL */ 3156f9c8e5bSGregory Neil Shapiro } 3166f9c8e5bSGregory Neil Shapiro 31712ed1c7cSGregory Neil Shapiro /* 318c2aa98e2SPeter Wemm ** MCI_GET -- get information about a particular host 31912ed1c7cSGregory Neil Shapiro ** 32012ed1c7cSGregory Neil Shapiro ** Parameters: 32112ed1c7cSGregory Neil Shapiro ** host -- host to look for. 32212ed1c7cSGregory Neil Shapiro ** m -- mailer. 32312ed1c7cSGregory Neil Shapiro ** 32412ed1c7cSGregory Neil Shapiro ** Returns: 32512ed1c7cSGregory Neil Shapiro ** mci for this host (might be new). 326c2aa98e2SPeter Wemm */ 327c2aa98e2SPeter Wemm 328c2aa98e2SPeter Wemm MCI * 329c2aa98e2SPeter Wemm mci_get(host, m) 330c2aa98e2SPeter Wemm char *host; 331c2aa98e2SPeter Wemm MAILER *m; 332c2aa98e2SPeter Wemm { 333c2aa98e2SPeter Wemm register MCI *mci; 334c2aa98e2SPeter Wemm register STAB *s; 335c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 336c2aa98e2SPeter Wemm 337c2aa98e2SPeter Wemm /* clear CurHostAddr so we don't get a bogus address with this name */ 338951742c4SGregory Neil Shapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 339c2aa98e2SPeter Wemm 340c2aa98e2SPeter Wemm /* clear out any expired connections */ 341c2aa98e2SPeter Wemm (void) mci_scan(NULL); 342c2aa98e2SPeter Wemm 343c2aa98e2SPeter Wemm if (m->m_mno < 0) 344c46d91b7SGregory Neil Shapiro syserr("!negative mno %d (%s)", m->m_mno, m->m_name); 3453299c2f1SGregory Neil Shapiro 346c2aa98e2SPeter Wemm s = stab(host, ST_MCI + m->m_mno, ST_ENTER); 347c2aa98e2SPeter Wemm mci = &s->s_mci; 348c2aa98e2SPeter Wemm 34912ed1c7cSGregory Neil Shapiro /* initialize per-message data */ 35012ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 35112ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 35212ed1c7cSGregory Neil Shapiro #if PIPELINING 35312ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 35412ed1c7cSGregory Neil Shapiro #endif /* PIPELINING */ 35512ed1c7cSGregory Neil Shapiro 35612ed1c7cSGregory Neil Shapiro if (mci->mci_rpool == NULL) 35712ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 35812ed1c7cSGregory Neil Shapiro 35912ed1c7cSGregory Neil Shapiro if (mci->mci_macro.mac_rpool == NULL) 36012ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 36112ed1c7cSGregory Neil Shapiro 3623299c2f1SGregory Neil Shapiro /* 36312ed1c7cSGregory Neil Shapiro ** We don't need to load the persistent data if we have data 3643299c2f1SGregory Neil Shapiro ** already loaded in the cache. 3653299c2f1SGregory Neil Shapiro */ 3663299c2f1SGregory Neil Shapiro 3673299c2f1SGregory Neil Shapiro if (mci->mci_host == NULL && 3683299c2f1SGregory Neil Shapiro (mci->mci_host = s->s_name) != NULL && 3693299c2f1SGregory Neil Shapiro !mci_load_persistent(mci)) 370c2aa98e2SPeter Wemm { 371c2aa98e2SPeter Wemm if (tTd(42, 2)) 37212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): lock failed\n", 3733299c2f1SGregory Neil Shapiro host, m->m_name); 374c2aa98e2SPeter Wemm mci->mci_exitstat = EX_TEMPFAIL; 375c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 376c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 377c2aa98e2SPeter Wemm return mci; 378c2aa98e2SPeter Wemm } 379c2aa98e2SPeter Wemm 380c2aa98e2SPeter Wemm if (tTd(42, 2)) 381c2aa98e2SPeter Wemm { 38212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n", 383c2aa98e2SPeter Wemm host, m->m_name, mci->mci_state, mci->mci_flags, 384c2aa98e2SPeter Wemm mci->mci_exitstat, mci->mci_errno); 385c2aa98e2SPeter Wemm } 386c2aa98e2SPeter Wemm 387c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_OPEN) 388c2aa98e2SPeter Wemm { 389c2aa98e2SPeter Wemm /* poke the connection to see if it's still alive */ 390c2aa98e2SPeter Wemm (void) smtpprobe(mci); 391c2aa98e2SPeter Wemm 392c2aa98e2SPeter Wemm /* reset the stored state in the event of a timeout */ 393c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 394c2aa98e2SPeter Wemm { 395c2aa98e2SPeter Wemm mci->mci_errno = 0; 396c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 397c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 398c2aa98e2SPeter Wemm } 399c2aa98e2SPeter Wemm else 400c2aa98e2SPeter Wemm { 40112ed1c7cSGregory Neil Shapiro /* get peer host address */ 402c2aa98e2SPeter Wemm /* (this should really be in the mci struct) */ 403951742c4SGregory Neil Shapiro SOCKADDR_LEN_T socklen = sizeof(CurHostAddr); 404c2aa98e2SPeter Wemm 40512ed1c7cSGregory Neil Shapiro (void) getpeername(sm_io_getinfo(mci->mci_in, 40612ed1c7cSGregory Neil Shapiro SM_IO_WHAT_FD, NULL), 407c2aa98e2SPeter Wemm (struct sockaddr *) &CurHostAddr, &socklen); 408c2aa98e2SPeter Wemm } 409c2aa98e2SPeter Wemm } 410c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_CLOSED) 411c2aa98e2SPeter Wemm { 412c2aa98e2SPeter Wemm time_t now = curtime(); 413c2aa98e2SPeter Wemm 414c2aa98e2SPeter Wemm /* if this info is stale, ignore it */ 415320f00e7SGregory Neil Shapiro if (mci->mci_lastuse + MciInfoTimeout <= now) 416c2aa98e2SPeter Wemm { 417c2aa98e2SPeter Wemm mci->mci_lastuse = now; 418c2aa98e2SPeter Wemm mci->mci_errno = 0; 419c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 420c2aa98e2SPeter Wemm } 421c2aa98e2SPeter Wemm } 422c2aa98e2SPeter Wemm 423c2aa98e2SPeter Wemm return mci; 424c2aa98e2SPeter Wemm } 425dbda3744SGregory Neil Shapiro 426dbda3744SGregory Neil Shapiro /* 427dbda3744SGregory Neil Shapiro ** MCI_CLOSE -- (forcefully) close files used for a connection. 428dbda3744SGregory Neil Shapiro ** Note: this is a last resort, usually smtpquit() or endmailer() 429dbda3744SGregory Neil Shapiro ** should be used to close a connection. 430dbda3744SGregory Neil Shapiro ** 431dbda3744SGregory Neil Shapiro ** Parameters: 432dbda3744SGregory Neil Shapiro ** mci -- the connection to close. 433dbda3744SGregory Neil Shapiro ** where -- where has this been called? 434dbda3744SGregory Neil Shapiro ** 435dbda3744SGregory Neil Shapiro ** Returns: 436dbda3744SGregory Neil Shapiro ** none. 437dbda3744SGregory Neil Shapiro */ 438dbda3744SGregory Neil Shapiro 439dbda3744SGregory Neil Shapiro void 440dbda3744SGregory Neil Shapiro mci_close(mci, where) 441dbda3744SGregory Neil Shapiro MCI *mci; 442dbda3744SGregory Neil Shapiro char *where; 443dbda3744SGregory Neil Shapiro { 444dbda3744SGregory Neil Shapiro bool dumped; 445dbda3744SGregory Neil Shapiro 446dbda3744SGregory Neil Shapiro if (mci == NULL) 447dbda3744SGregory Neil Shapiro return; 448dbda3744SGregory Neil Shapiro dumped = false; 449dbda3744SGregory Neil Shapiro if (mci->mci_out != NULL) 450dbda3744SGregory Neil Shapiro { 451dbda3744SGregory Neil Shapiro if (tTd(56, 1)) 452dbda3744SGregory Neil Shapiro { 453dbda3744SGregory Neil Shapiro sm_dprintf("mci_close: mci_out!=NULL, where=%s\n", 454dbda3744SGregory Neil Shapiro where); 455dbda3744SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 456dbda3744SGregory Neil Shapiro dumped = true; 457dbda3744SGregory Neil Shapiro } 458dbda3744SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 459dbda3744SGregory Neil Shapiro mci->mci_out = NULL; 460dbda3744SGregory Neil Shapiro } 461dbda3744SGregory Neil Shapiro if (mci->mci_in != NULL) 462dbda3744SGregory Neil Shapiro { 463dbda3744SGregory Neil Shapiro if (tTd(56, 1)) 464dbda3744SGregory Neil Shapiro { 465dbda3744SGregory Neil Shapiro sm_dprintf("mci_close: mci_in!=NULL, where=%s\n", 466dbda3744SGregory Neil Shapiro where); 467dbda3744SGregory Neil Shapiro if (!dumped) 468dbda3744SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 469dbda3744SGregory Neil Shapiro } 470dbda3744SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 471dbda3744SGregory Neil Shapiro mci->mci_in = NULL; 472dbda3744SGregory Neil Shapiro } 473dbda3744SGregory Neil Shapiro mci->mci_state = MCIS_CLOSED; 474dbda3744SGregory Neil Shapiro } 475dbda3744SGregory Neil Shapiro 47612ed1c7cSGregory Neil Shapiro /* 47712ed1c7cSGregory Neil Shapiro ** MCI_NEW -- allocate new MCI structure 47812ed1c7cSGregory Neil Shapiro ** 47912ed1c7cSGregory Neil Shapiro ** Parameters: 48012ed1c7cSGregory Neil Shapiro ** rpool -- if non-NULL: allocate from that rpool. 48112ed1c7cSGregory Neil Shapiro ** 48212ed1c7cSGregory Neil Shapiro ** Returns: 48312ed1c7cSGregory Neil Shapiro ** mci (new). 48412ed1c7cSGregory Neil Shapiro */ 48512ed1c7cSGregory Neil Shapiro 48612ed1c7cSGregory Neil Shapiro MCI * 48712ed1c7cSGregory Neil Shapiro mci_new(rpool) 48812ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 48912ed1c7cSGregory Neil Shapiro { 49012ed1c7cSGregory Neil Shapiro register MCI *mci; 49112ed1c7cSGregory Neil Shapiro 49212ed1c7cSGregory Neil Shapiro if (rpool == NULL) 493951742c4SGregory Neil Shapiro mci = (MCI *) sm_malloc_x(sizeof(*mci)); 49412ed1c7cSGregory Neil Shapiro else 495951742c4SGregory Neil Shapiro mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof(*mci)); 496951742c4SGregory Neil Shapiro memset((char *) mci, '\0', sizeof(*mci)); 49712ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 49812ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 49912ed1c7cSGregory Neil Shapiro return mci; 50012ed1c7cSGregory Neil Shapiro } 50112ed1c7cSGregory Neil Shapiro /* 5023299c2f1SGregory Neil Shapiro ** MCI_MATCH -- check connection cache for a particular host 50312ed1c7cSGregory Neil Shapiro ** 50412ed1c7cSGregory Neil Shapiro ** Parameters: 50512ed1c7cSGregory Neil Shapiro ** host -- host to look for. 50612ed1c7cSGregory Neil Shapiro ** m -- mailer. 50712ed1c7cSGregory Neil Shapiro ** 50812ed1c7cSGregory Neil Shapiro ** Returns: 50912ed1c7cSGregory Neil Shapiro ** true iff open connection exists. 5103299c2f1SGregory Neil Shapiro */ 5113299c2f1SGregory Neil Shapiro 5123299c2f1SGregory Neil Shapiro bool 5133299c2f1SGregory Neil Shapiro mci_match(host, m) 5143299c2f1SGregory Neil Shapiro char *host; 5153299c2f1SGregory Neil Shapiro MAILER *m; 5163299c2f1SGregory Neil Shapiro { 5173299c2f1SGregory Neil Shapiro register MCI *mci; 5183299c2f1SGregory Neil Shapiro register STAB *s; 5193299c2f1SGregory Neil Shapiro 520c46d91b7SGregory Neil Shapiro if (m->m_mno < 0 || m->m_mno > MAXMAILERS) 52112ed1c7cSGregory Neil Shapiro return false; 5223299c2f1SGregory Neil Shapiro s = stab(host, ST_MCI + m->m_mno, ST_FIND); 5233299c2f1SGregory Neil Shapiro if (s == NULL) 52412ed1c7cSGregory Neil Shapiro return false; 5253299c2f1SGregory Neil Shapiro 5263299c2f1SGregory Neil Shapiro mci = &s->s_mci; 52712ed1c7cSGregory Neil Shapiro return mci->mci_state == MCIS_OPEN; 5283299c2f1SGregory Neil Shapiro } 52912ed1c7cSGregory Neil Shapiro /* 530c2aa98e2SPeter Wemm ** MCI_SETSTAT -- set status codes in MCI structure. 531c2aa98e2SPeter Wemm ** 532c2aa98e2SPeter Wemm ** Parameters: 533c2aa98e2SPeter Wemm ** mci -- the MCI structure to set. 534c2aa98e2SPeter Wemm ** xstat -- the exit status code. 535c2aa98e2SPeter Wemm ** dstat -- the DSN status code. 536c2aa98e2SPeter Wemm ** rstat -- the SMTP status code. 537c2aa98e2SPeter Wemm ** 538c2aa98e2SPeter Wemm ** Returns: 539c2aa98e2SPeter Wemm ** none. 540c2aa98e2SPeter Wemm */ 541c2aa98e2SPeter Wemm 542c2aa98e2SPeter Wemm void 543c2aa98e2SPeter Wemm mci_setstat(mci, xstat, dstat, rstat) 544c2aa98e2SPeter Wemm MCI *mci; 545c2aa98e2SPeter Wemm int xstat; 546c2aa98e2SPeter Wemm char *dstat; 547c2aa98e2SPeter Wemm char *rstat; 548c2aa98e2SPeter Wemm { 549c2aa98e2SPeter Wemm /* protocol errors should never be interpreted as sticky */ 550c2aa98e2SPeter Wemm if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL) 551c2aa98e2SPeter Wemm mci->mci_exitstat = xstat; 552c2aa98e2SPeter Wemm 55312ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 55412ed1c7cSGregory Neil Shapiro if (dstat != NULL) 55512ed1c7cSGregory Neil Shapiro mci->mci_status = sm_strdup_x(dstat); 55612ed1c7cSGregory Neil Shapiro 55712ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 558c2aa98e2SPeter Wemm if (rstat != NULL) 55912ed1c7cSGregory Neil Shapiro mci->mci_rstatus = sm_strdup_x(rstat); 560c2aa98e2SPeter Wemm } 56112ed1c7cSGregory Neil Shapiro /* 562c2aa98e2SPeter Wemm ** MCI_DUMP -- dump the contents of an MCI structure. 563c2aa98e2SPeter Wemm ** 564c2aa98e2SPeter Wemm ** Parameters: 565bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 566c2aa98e2SPeter Wemm ** mci -- the MCI structure to dump. 567c2aa98e2SPeter Wemm ** 568c2aa98e2SPeter Wemm ** Returns: 569c2aa98e2SPeter Wemm ** none. 570c2aa98e2SPeter Wemm ** 571c2aa98e2SPeter Wemm ** Side Effects: 572c2aa98e2SPeter Wemm ** none. 573c2aa98e2SPeter Wemm */ 574c2aa98e2SPeter Wemm 575c2aa98e2SPeter Wemm struct mcifbits 576c2aa98e2SPeter Wemm { 577c2aa98e2SPeter Wemm int mcif_bit; /* flag bit */ 578c2aa98e2SPeter Wemm char *mcif_name; /* flag name */ 579c2aa98e2SPeter Wemm }; 5803299c2f1SGregory Neil Shapiro static struct mcifbits MciFlags[] = 581c2aa98e2SPeter Wemm { 582c2aa98e2SPeter Wemm { MCIF_VALID, "VALID" }, 583c2aa98e2SPeter Wemm { MCIF_CACHED, "CACHED" }, 584c2aa98e2SPeter Wemm { MCIF_ESMTP, "ESMTP" }, 585c2aa98e2SPeter Wemm { MCIF_EXPN, "EXPN" }, 586c2aa98e2SPeter Wemm { MCIF_SIZE, "SIZE" }, 587c2aa98e2SPeter Wemm { MCIF_8BITMIME, "8BITMIME" }, 588c2aa98e2SPeter Wemm { MCIF_7BIT, "7BIT" }, 589c2aa98e2SPeter Wemm { MCIF_INHEADER, "INHEADER" }, 590c2aa98e2SPeter Wemm { MCIF_CVT8TO7, "CVT8TO7" }, 591c2aa98e2SPeter Wemm { MCIF_DSN, "DSN" }, 592c2aa98e2SPeter Wemm { MCIF_8BITOK, "8BITOK" }, 593c2aa98e2SPeter Wemm { MCIF_CVT7TO8, "CVT7TO8" }, 594c2aa98e2SPeter Wemm { MCIF_INMIME, "INMIME" }, 59512ed1c7cSGregory Neil Shapiro { MCIF_AUTH, "AUTH" }, 5966f9c8e5bSGregory Neil Shapiro { MCIF_AUTH2, "AUTH2" }, 59712ed1c7cSGregory Neil Shapiro { MCIF_AUTHACT, "AUTHACT" }, 59812ed1c7cSGregory Neil Shapiro { MCIF_ENHSTAT, "ENHSTAT" }, 59912ed1c7cSGregory Neil Shapiro { MCIF_PIPELINED, "PIPELINED" }, 60012ed1c7cSGregory Neil Shapiro #if STARTTLS 60112ed1c7cSGregory Neil Shapiro { MCIF_TLS, "TLS" }, 60212ed1c7cSGregory Neil Shapiro { MCIF_TLSACT, "TLSACT" }, 60312ed1c7cSGregory Neil Shapiro #endif /* STARTTLS */ 60412ed1c7cSGregory Neil Shapiro { MCIF_DLVR_BY, "DLVR_BY" }, 605c2aa98e2SPeter Wemm { 0, NULL } 606c2aa98e2SPeter Wemm }; 607c2aa98e2SPeter Wemm 608c2aa98e2SPeter Wemm void 609bfb62e91SGregory Neil Shapiro mci_dump(fp, mci, logit) 610bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 611c2aa98e2SPeter Wemm register MCI *mci; 612c2aa98e2SPeter Wemm bool logit; 613c2aa98e2SPeter Wemm { 614c2aa98e2SPeter Wemm register char *p; 615c2aa98e2SPeter Wemm char *sep; 616c2aa98e2SPeter Wemm char buf[4000]; 617c2aa98e2SPeter Wemm 618c2aa98e2SPeter Wemm sep = logit ? " " : "\n\t"; 619c2aa98e2SPeter Wemm p = buf; 62012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci); 621c2aa98e2SPeter Wemm p += strlen(p); 622c2aa98e2SPeter Wemm if (mci == NULL) 623c2aa98e2SPeter Wemm { 62412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL"); 625c2aa98e2SPeter Wemm goto printit; 626c2aa98e2SPeter Wemm } 62712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags); 628c2aa98e2SPeter Wemm p += strlen(p); 6297660b554SGregory Neil Shapiro 6307660b554SGregory Neil Shapiro /* 6317660b554SGregory Neil Shapiro ** The following check is just for paranoia. It protects the 6327660b554SGregory Neil Shapiro ** assignment in the if() clause. If there's not some minimum 6337660b554SGregory Neil Shapiro ** amount of space we can stop right now. The check will not 6347660b554SGregory Neil Shapiro ** trigger as long as sizeof(buf)=4000. 6357660b554SGregory Neil Shapiro */ 6367660b554SGregory Neil Shapiro 6377660b554SGregory Neil Shapiro if (p >= buf + sizeof(buf) - 4) 6387660b554SGregory Neil Shapiro goto printit; 639c2aa98e2SPeter Wemm if (mci->mci_flags != 0) 640c2aa98e2SPeter Wemm { 641c2aa98e2SPeter Wemm struct mcifbits *f; 642c2aa98e2SPeter Wemm 6437660b554SGregory Neil Shapiro *p++ = '<'; /* protected above */ 644c2aa98e2SPeter Wemm for (f = MciFlags; f->mcif_bit != 0; f++) 645c2aa98e2SPeter Wemm { 646c2aa98e2SPeter Wemm if (!bitset(f->mcif_bit, mci->mci_flags)) 647c2aa98e2SPeter Wemm continue; 64812ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2, 64912ed1c7cSGregory Neil Shapiro f->mcif_name, ","); 650c2aa98e2SPeter Wemm p += strlen(p); 651c2aa98e2SPeter Wemm } 652c2aa98e2SPeter Wemm p[-1] = '>'; 653c2aa98e2SPeter Wemm } 65412ed1c7cSGregory Neil Shapiro 65512ed1c7cSGregory Neil Shapiro /* Note: sm_snprintf() takes care of NULL arguments for %s */ 65612ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 657c2aa98e2SPeter Wemm ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", 658c2aa98e2SPeter Wemm sep, mci->mci_errno, mci->mci_herrno, 6593299c2f1SGregory Neil Shapiro mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep); 660c2aa98e2SPeter Wemm p += strlen(p); 66112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 662c2aa98e2SPeter Wemm "maxsize=%ld, phase=%s, mailer=%s,%s", 66312ed1c7cSGregory Neil Shapiro mci->mci_maxsize, mci->mci_phase, 664c2aa98e2SPeter Wemm mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name, 665c2aa98e2SPeter Wemm sep); 666c2aa98e2SPeter Wemm p += strlen(p); 66712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 668c2aa98e2SPeter Wemm "status=%s, rstatus=%s,%s", 66912ed1c7cSGregory Neil Shapiro mci->mci_status, mci->mci_rstatus, sep); 670c2aa98e2SPeter Wemm p += strlen(p); 67112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 672c2aa98e2SPeter Wemm "host=%s, lastuse=%s", 67312ed1c7cSGregory Neil Shapiro mci->mci_host, ctime(&mci->mci_lastuse)); 674c2aa98e2SPeter Wemm printit: 675c2aa98e2SPeter Wemm if (logit) 676c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); 677c2aa98e2SPeter Wemm else 678bfb62e91SGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf); 679c2aa98e2SPeter Wemm } 68012ed1c7cSGregory Neil Shapiro /* 681c2aa98e2SPeter Wemm ** MCI_DUMP_ALL -- print the entire MCI cache 682c2aa98e2SPeter Wemm ** 683c2aa98e2SPeter Wemm ** Parameters: 684bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 685c2aa98e2SPeter Wemm ** logit -- if set, log the result instead of printing 686c2aa98e2SPeter Wemm ** to stdout. 687c2aa98e2SPeter Wemm ** 688c2aa98e2SPeter Wemm ** Returns: 689c2aa98e2SPeter Wemm ** none. 690c2aa98e2SPeter Wemm */ 691c2aa98e2SPeter Wemm 692c2aa98e2SPeter Wemm void 693bfb62e91SGregory Neil Shapiro mci_dump_all(fp, logit) 694bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 695c2aa98e2SPeter Wemm bool logit; 696c2aa98e2SPeter Wemm { 697c2aa98e2SPeter Wemm register int i; 698c2aa98e2SPeter Wemm 699c2aa98e2SPeter Wemm if (MciCache == NULL) 700c2aa98e2SPeter Wemm return; 701c2aa98e2SPeter Wemm 702c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 703bfb62e91SGregory Neil Shapiro mci_dump(fp, MciCache[i], logit); 704c2aa98e2SPeter Wemm } 70512ed1c7cSGregory Neil Shapiro /* 706c2aa98e2SPeter Wemm ** MCI_LOCK_HOST -- Lock host while sending. 707c2aa98e2SPeter Wemm ** 708c2aa98e2SPeter Wemm ** If we are contacting a host, we'll need to 709c2aa98e2SPeter Wemm ** update the status information in the host status 710c2aa98e2SPeter Wemm ** file, and if we want to do that, we ought to have 711c2aa98e2SPeter Wemm ** locked it. This has the (according to some) 712c2aa98e2SPeter Wemm ** desirable effect of serializing connectivity with 71312ed1c7cSGregory Neil Shapiro ** remote hosts -- i.e.: one connection to a given 714c2aa98e2SPeter Wemm ** host at a time. 715c2aa98e2SPeter Wemm ** 716c2aa98e2SPeter Wemm ** Parameters: 717c2aa98e2SPeter Wemm ** mci -- containing the host we want to lock. 718c2aa98e2SPeter Wemm ** 719c2aa98e2SPeter Wemm ** Returns: 720c2aa98e2SPeter Wemm ** EX_OK -- got the lock. 721c2aa98e2SPeter Wemm ** EX_TEMPFAIL -- didn't get the lock. 722c2aa98e2SPeter Wemm */ 723c2aa98e2SPeter Wemm 724c2aa98e2SPeter Wemm int 725c2aa98e2SPeter Wemm mci_lock_host(mci) 726c2aa98e2SPeter Wemm MCI *mci; 727c2aa98e2SPeter Wemm { 728c2aa98e2SPeter Wemm if (mci == NULL) 729c2aa98e2SPeter Wemm { 730c2aa98e2SPeter Wemm if (tTd(56, 1)) 73112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: NULL mci\n"); 732c2aa98e2SPeter Wemm return EX_OK; 733c2aa98e2SPeter Wemm } 734c2aa98e2SPeter Wemm 735c2aa98e2SPeter Wemm if (!SingleThreadDelivery) 736c2aa98e2SPeter Wemm return EX_OK; 737c2aa98e2SPeter Wemm 738c2aa98e2SPeter Wemm return mci_lock_host_statfile(mci); 739c2aa98e2SPeter Wemm } 740c2aa98e2SPeter Wemm 7413299c2f1SGregory Neil Shapiro static int 742c2aa98e2SPeter Wemm mci_lock_host_statfile(mci) 743c2aa98e2SPeter Wemm MCI *mci; 744c2aa98e2SPeter Wemm { 7453299c2f1SGregory Neil Shapiro int save_errno = errno; 746c2aa98e2SPeter Wemm int retVal = EX_OK; 74788ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 750c2aa98e2SPeter Wemm return EX_OK; 751c2aa98e2SPeter Wemm 752c2aa98e2SPeter Wemm if (tTd(56, 2)) 75312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: attempting to lock %s\n", 754c2aa98e2SPeter Wemm mci->mci_host); 755c2aa98e2SPeter Wemm 756951742c4SGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname), 75712ed1c7cSGregory Neil Shapiro true) < 0) 758c2aa98e2SPeter Wemm { 759c2aa98e2SPeter Wemm /* of course this should never happen */ 760c2aa98e2SPeter Wemm if (tTd(56, 2)) 76112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Failed to generate host path for %s\n", 762c2aa98e2SPeter Wemm mci->mci_host); 763c2aa98e2SPeter Wemm 764c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 765c2aa98e2SPeter Wemm goto cleanup; 766c2aa98e2SPeter Wemm } 767c2aa98e2SPeter Wemm 768c2aa98e2SPeter Wemm mci->mci_statfile = safefopen(fname, O_RDWR, FileMode, 769c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT); 770c2aa98e2SPeter Wemm 771c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 772c2aa98e2SPeter Wemm { 77312ed1c7cSGregory Neil Shapiro syserr("mci_lock_host: cannot create host lock file %s", fname); 774c2aa98e2SPeter Wemm goto cleanup; 775c2aa98e2SPeter Wemm } 776c2aa98e2SPeter Wemm 77712ed1c7cSGregory Neil Shapiro if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 77812ed1c7cSGregory Neil Shapiro fname, "", LOCK_EX|LOCK_NB)) 779c2aa98e2SPeter Wemm { 780c2aa98e2SPeter Wemm if (tTd(56, 2)) 78112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: couldn't get lock on %s\n", 782c2aa98e2SPeter Wemm fname); 78312ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 784c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 785c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 786c2aa98e2SPeter Wemm goto cleanup; 787c2aa98e2SPeter Wemm } 788c2aa98e2SPeter Wemm 789c2aa98e2SPeter Wemm if (tTd(56, 12) && mci->mci_statfile != NULL) 79012ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Sanity check -- lock is good\n"); 791c2aa98e2SPeter Wemm 792c2aa98e2SPeter Wemm cleanup: 7933299c2f1SGregory Neil Shapiro errno = save_errno; 794c2aa98e2SPeter Wemm return retVal; 795c2aa98e2SPeter Wemm } 79612ed1c7cSGregory Neil Shapiro /* 797c2aa98e2SPeter Wemm ** MCI_UNLOCK_HOST -- unlock host 798c2aa98e2SPeter Wemm ** 799c2aa98e2SPeter Wemm ** Clean up the lock on a host, close the file, let 800c2aa98e2SPeter Wemm ** someone else use it. 801c2aa98e2SPeter Wemm ** 802c2aa98e2SPeter Wemm ** Parameters: 803c2aa98e2SPeter Wemm ** mci -- us. 804c2aa98e2SPeter Wemm ** 805c2aa98e2SPeter Wemm ** Returns: 806c2aa98e2SPeter Wemm ** nothing. 807c2aa98e2SPeter Wemm */ 808c2aa98e2SPeter Wemm 809c2aa98e2SPeter Wemm void 810c2aa98e2SPeter Wemm mci_unlock_host(mci) 811c2aa98e2SPeter Wemm MCI *mci; 812c2aa98e2SPeter Wemm { 8133299c2f1SGregory Neil Shapiro int save_errno = errno; 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm if (mci == NULL) 816c2aa98e2SPeter Wemm { 817c2aa98e2SPeter Wemm if (tTd(56, 1)) 81812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: NULL mci\n"); 819c2aa98e2SPeter Wemm return; 820c2aa98e2SPeter Wemm } 821c2aa98e2SPeter Wemm 822c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 823c2aa98e2SPeter Wemm return; 824c2aa98e2SPeter Wemm 825c2aa98e2SPeter Wemm if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) 826c2aa98e2SPeter Wemm { 827c2aa98e2SPeter Wemm if (tTd(56, 1)) 82812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: stat file already locked\n"); 829c2aa98e2SPeter Wemm } 830c2aa98e2SPeter Wemm else 831c2aa98e2SPeter Wemm { 832c2aa98e2SPeter Wemm if (tTd(56, 2)) 83312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: store prior to unlock\n"); 834c2aa98e2SPeter Wemm mci_store_persistent(mci); 835c2aa98e2SPeter Wemm } 836c2aa98e2SPeter Wemm 837c2aa98e2SPeter Wemm if (mci->mci_statfile != NULL) 838c2aa98e2SPeter Wemm { 83912ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 840c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 841c2aa98e2SPeter Wemm } 842c2aa98e2SPeter Wemm 8433299c2f1SGregory Neil Shapiro errno = save_errno; 844c2aa98e2SPeter Wemm } 84512ed1c7cSGregory Neil Shapiro /* 846c2aa98e2SPeter Wemm ** MCI_LOAD_PERSISTENT -- load persistent host info 847c2aa98e2SPeter Wemm ** 848c2aa98e2SPeter Wemm ** Load information about host that is kept 849c2aa98e2SPeter Wemm ** in common for all running sendmails. 850c2aa98e2SPeter Wemm ** 851c2aa98e2SPeter Wemm ** Parameters: 85212ed1c7cSGregory Neil Shapiro ** mci -- the host/connection to load persistent info for. 853c2aa98e2SPeter Wemm ** 854c2aa98e2SPeter Wemm ** Returns: 85512ed1c7cSGregory Neil Shapiro ** true -- lock was successful 85612ed1c7cSGregory Neil Shapiro ** false -- lock failed 857c2aa98e2SPeter Wemm */ 858c2aa98e2SPeter Wemm 8593299c2f1SGregory Neil Shapiro static bool 860c2aa98e2SPeter Wemm mci_load_persistent(mci) 861c2aa98e2SPeter Wemm MCI *mci; 862c2aa98e2SPeter Wemm { 8633299c2f1SGregory Neil Shapiro int save_errno = errno; 86412ed1c7cSGregory Neil Shapiro bool locked = true; 86512ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 86688ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 867c2aa98e2SPeter Wemm 868c2aa98e2SPeter Wemm if (mci == NULL) 869c2aa98e2SPeter Wemm { 870c2aa98e2SPeter Wemm if (tTd(56, 1)) 87112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: NULL mci\n"); 87212ed1c7cSGregory Neil Shapiro return true; 873c2aa98e2SPeter Wemm } 874c2aa98e2SPeter Wemm 875c2aa98e2SPeter Wemm if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) 87612ed1c7cSGregory Neil Shapiro return true; 877c2aa98e2SPeter Wemm 878c2aa98e2SPeter Wemm /* Already have the persistent information in memory */ 879c2aa98e2SPeter Wemm if (SingleThreadDelivery && mci->mci_statfile != NULL) 88012ed1c7cSGregory Neil Shapiro return true; 881c2aa98e2SPeter Wemm 882c2aa98e2SPeter Wemm if (tTd(56, 1)) 88312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n", 884c2aa98e2SPeter Wemm mci->mci_host); 885c2aa98e2SPeter Wemm 886951742c4SGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname), 88712ed1c7cSGregory Neil Shapiro false) < 0) 888c2aa98e2SPeter Wemm { 889c2aa98e2SPeter Wemm /* Not much we can do if the file isn't there... */ 890c2aa98e2SPeter Wemm if (tTd(56, 1)) 89112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Couldn't generate host path\n"); 892c2aa98e2SPeter Wemm goto cleanup; 893c2aa98e2SPeter Wemm } 894c2aa98e2SPeter Wemm 895c2aa98e2SPeter Wemm fp = safefopen(fname, O_RDONLY, FileMode, 896c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 897c2aa98e2SPeter Wemm if (fp == NULL) 898c2aa98e2SPeter Wemm { 899c2aa98e2SPeter Wemm /* I can't think of any reason this should ever happen */ 900c2aa98e2SPeter Wemm if (tTd(56, 1)) 90112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: open(%s): %s\n", 90212ed1c7cSGregory Neil Shapiro fname, sm_errstring(errno)); 903c2aa98e2SPeter Wemm goto cleanup; 904c2aa98e2SPeter Wemm } 905c2aa98e2SPeter Wemm 906c2aa98e2SPeter Wemm FileName = fname; 90712ed1c7cSGregory Neil Shapiro locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "", 90812ed1c7cSGregory Neil Shapiro LOCK_SH|LOCK_NB); 909c2aa98e2SPeter Wemm if (locked) 9103299c2f1SGregory Neil Shapiro { 9113299c2f1SGregory Neil Shapiro (void) mci_read_persistent(fp, mci); 91212ed1c7cSGregory Neil Shapiro (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, 91312ed1c7cSGregory Neil Shapiro "", LOCK_UN); 9143299c2f1SGregory Neil Shapiro } 9153299c2f1SGregory Neil Shapiro FileName = NULL; 91612ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 917c2aa98e2SPeter Wemm 918c2aa98e2SPeter Wemm cleanup: 9193299c2f1SGregory Neil Shapiro errno = save_errno; 920c2aa98e2SPeter Wemm return locked; 921c2aa98e2SPeter Wemm } 92212ed1c7cSGregory Neil Shapiro /* 923c2aa98e2SPeter Wemm ** MCI_READ_PERSISTENT -- read persistent host status file 924c2aa98e2SPeter Wemm ** 925c2aa98e2SPeter Wemm ** Parameters: 926c2aa98e2SPeter Wemm ** fp -- the file pointer to read. 927c2aa98e2SPeter Wemm ** mci -- the pointer to fill in. 928c2aa98e2SPeter Wemm ** 929c2aa98e2SPeter Wemm ** Returns: 930c2aa98e2SPeter Wemm ** -1 -- if the file was corrupt. 931c2aa98e2SPeter Wemm ** 0 -- otherwise. 932c2aa98e2SPeter Wemm ** 933c2aa98e2SPeter Wemm ** Warning: 934c2aa98e2SPeter Wemm ** This code makes the assumption that this data 935c2aa98e2SPeter Wemm ** will be read in an atomic fashion, and that the data 936c2aa98e2SPeter Wemm ** was written in an atomic fashion. Any other functioning 937c2aa98e2SPeter Wemm ** may lead to some form of insanity. This should be 938c2aa98e2SPeter Wemm ** perfectly safe due to underlying stdio buffering. 939c2aa98e2SPeter Wemm */ 940c2aa98e2SPeter Wemm 9413299c2f1SGregory Neil Shapiro static int 942c2aa98e2SPeter Wemm mci_read_persistent(fp, mci) 94312ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 944c2aa98e2SPeter Wemm register MCI *mci; 945c2aa98e2SPeter Wemm { 946c2aa98e2SPeter Wemm int ver; 947c2aa98e2SPeter Wemm register char *p; 948c2aa98e2SPeter Wemm int saveLineNumber = LineNumber; 949c2aa98e2SPeter Wemm char buf[MAXLINE]; 950c2aa98e2SPeter Wemm 951c2aa98e2SPeter Wemm if (fp == NULL) 952355d91e3SGregory Neil Shapiro { 953c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL fp"); 954355d91e3SGregory Neil Shapiro /* NOTREACHED */ 955355d91e3SGregory Neil Shapiro return -1; 956355d91e3SGregory Neil Shapiro } 957c2aa98e2SPeter Wemm if (mci == NULL) 958355d91e3SGregory Neil Shapiro { 959c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL mci"); 960355d91e3SGregory Neil Shapiro /* NOTREACHED */ 961355d91e3SGregory Neil Shapiro return -1; 962355d91e3SGregory Neil Shapiro } 963c2aa98e2SPeter Wemm if (tTd(56, 93)) 964c2aa98e2SPeter Wemm { 96512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_read_persistent: fp=%lx, mci=", 96612ed1c7cSGregory Neil Shapiro (unsigned long) fp); 967c2aa98e2SPeter Wemm } 968c2aa98e2SPeter Wemm 96912ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_status); 97012ed1c7cSGregory Neil Shapiro SM_FREE_CLR(mci->mci_rstatus); 971c2aa98e2SPeter Wemm 97212ed1c7cSGregory Neil Shapiro sm_io_rewind(fp, SM_TIME_DEFAULT); 973c2aa98e2SPeter Wemm ver = -1; 974c2aa98e2SPeter Wemm LineNumber = 0; 975552d4955SGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0) 976c2aa98e2SPeter Wemm { 977c2aa98e2SPeter Wemm LineNumber++; 978c2aa98e2SPeter Wemm p = strchr(buf, '\n'); 979c2aa98e2SPeter Wemm if (p != NULL) 980c2aa98e2SPeter Wemm *p = '\0'; 981c2aa98e2SPeter Wemm switch (buf[0]) 982c2aa98e2SPeter Wemm { 983c2aa98e2SPeter Wemm case 'V': /* version stamp */ 984c2aa98e2SPeter Wemm ver = atoi(&buf[1]); 985c2aa98e2SPeter Wemm if (ver < 0 || ver > 0) 986c2aa98e2SPeter Wemm syserr("Unknown host status version %d: %d max", 987c2aa98e2SPeter Wemm ver, 0); 988c2aa98e2SPeter Wemm break; 989c2aa98e2SPeter Wemm 990c2aa98e2SPeter Wemm case 'E': /* UNIX error number */ 991c2aa98e2SPeter Wemm mci->mci_errno = atoi(&buf[1]); 992c2aa98e2SPeter Wemm break; 993c2aa98e2SPeter Wemm 994c2aa98e2SPeter Wemm case 'H': /* DNS error number */ 995c2aa98e2SPeter Wemm mci->mci_herrno = atoi(&buf[1]); 996c2aa98e2SPeter Wemm break; 997c2aa98e2SPeter Wemm 998c2aa98e2SPeter Wemm case 'S': /* UNIX exit status */ 999c2aa98e2SPeter Wemm mci->mci_exitstat = atoi(&buf[1]); 1000c2aa98e2SPeter Wemm break; 1001c2aa98e2SPeter Wemm 1002c2aa98e2SPeter Wemm case 'D': /* DSN status */ 1003c2aa98e2SPeter Wemm mci->mci_status = newstr(&buf[1]); 1004c2aa98e2SPeter Wemm break; 1005c2aa98e2SPeter Wemm 1006c2aa98e2SPeter Wemm case 'R': /* SMTP status */ 1007c2aa98e2SPeter Wemm mci->mci_rstatus = newstr(&buf[1]); 1008c2aa98e2SPeter Wemm break; 1009c2aa98e2SPeter Wemm 1010c2aa98e2SPeter Wemm case 'U': /* last usage time */ 1011c2aa98e2SPeter Wemm mci->mci_lastuse = atol(&buf[1]); 1012c2aa98e2SPeter Wemm break; 1013c2aa98e2SPeter Wemm 1014c2aa98e2SPeter Wemm case '.': /* end of file */ 101512ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 1016bfb62e91SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 1017c2aa98e2SPeter Wemm return 0; 1018c2aa98e2SPeter Wemm 1019c2aa98e2SPeter Wemm default: 1020c2aa98e2SPeter Wemm sm_syslog(LOG_CRIT, NOQID, 1021c2aa98e2SPeter Wemm "%s: line %d: Unknown host status line \"%s\"", 1022c2aa98e2SPeter Wemm FileName == NULL ? mci->mci_host : FileName, 1023c2aa98e2SPeter Wemm LineNumber, buf); 1024c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 1025c2aa98e2SPeter Wemm return -1; 1026c2aa98e2SPeter Wemm } 1027c2aa98e2SPeter Wemm } 1028c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 102912ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 103012ed1c7cSGregory Neil Shapiro sm_dprintf("incomplete (missing dot for EOF)\n"); 1031c2aa98e2SPeter Wemm if (ver < 0) 1032c2aa98e2SPeter Wemm return -1; 1033c2aa98e2SPeter Wemm return 0; 1034c2aa98e2SPeter Wemm } 103512ed1c7cSGregory Neil Shapiro /* 1036c2aa98e2SPeter Wemm ** MCI_STORE_PERSISTENT -- Store persistent MCI information 1037c2aa98e2SPeter Wemm ** 1038c2aa98e2SPeter Wemm ** Store information about host that is kept 1039c2aa98e2SPeter Wemm ** in common for all running sendmails. 1040c2aa98e2SPeter Wemm ** 1041c2aa98e2SPeter Wemm ** Parameters: 1042c2aa98e2SPeter Wemm ** mci -- the host/connection to store persistent info for. 1043c2aa98e2SPeter Wemm ** 1044c2aa98e2SPeter Wemm ** Returns: 1045c2aa98e2SPeter Wemm ** none. 1046c2aa98e2SPeter Wemm */ 1047c2aa98e2SPeter Wemm 1048c2aa98e2SPeter Wemm void 1049c2aa98e2SPeter Wemm mci_store_persistent(mci) 1050c2aa98e2SPeter Wemm MCI *mci; 1051c2aa98e2SPeter Wemm { 10523299c2f1SGregory Neil Shapiro int save_errno = errno; 1053c2aa98e2SPeter Wemm 1054c2aa98e2SPeter Wemm if (mci == NULL) 1055c2aa98e2SPeter Wemm { 1056c2aa98e2SPeter Wemm if (tTd(56, 1)) 105712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: NULL mci\n"); 1058c2aa98e2SPeter Wemm return; 1059c2aa98e2SPeter Wemm } 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 1062c2aa98e2SPeter Wemm return; 1063c2aa98e2SPeter Wemm 1064c2aa98e2SPeter Wemm if (tTd(56, 1)) 106512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: Storing information for %s\n", 1066c2aa98e2SPeter Wemm mci->mci_host); 1067c2aa98e2SPeter Wemm 1068c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 1069c2aa98e2SPeter Wemm { 1070c2aa98e2SPeter Wemm if (tTd(56, 1)) 107112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: no statfile\n"); 1072c2aa98e2SPeter Wemm return; 1073c2aa98e2SPeter Wemm } 1074c2aa98e2SPeter Wemm 107512ed1c7cSGregory Neil Shapiro sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT); 1076c2aa98e2SPeter Wemm #if !NOFTRUNCATE 107712ed1c7cSGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 107812ed1c7cSGregory Neil Shapiro (off_t) 0); 10793299c2f1SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 1080c2aa98e2SPeter Wemm 108112ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n"); 108212ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n", 108312ed1c7cSGregory Neil Shapiro mci->mci_errno); 108412ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n", 108512ed1c7cSGregory Neil Shapiro mci->mci_herrno); 108612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n", 108712ed1c7cSGregory Neil Shapiro mci->mci_exitstat); 1088c2aa98e2SPeter Wemm if (mci->mci_status != NULL) 108912ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 109012ed1c7cSGregory Neil Shapiro "D%.80s\n", 109112ed1c7cSGregory Neil Shapiro denlstring(mci->mci_status, true, false)); 1092c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 109312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 109412ed1c7cSGregory Neil Shapiro "R%.80s\n", 109512ed1c7cSGregory Neil Shapiro denlstring(mci->mci_rstatus, true, false)); 109612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n", 109712ed1c7cSGregory Neil Shapiro (long)(mci->mci_lastuse)); 109812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n"); 1099c2aa98e2SPeter Wemm 110012ed1c7cSGregory Neil Shapiro (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT); 1101c2aa98e2SPeter Wemm 11023299c2f1SGregory Neil Shapiro errno = save_errno; 1103c2aa98e2SPeter Wemm return; 1104c2aa98e2SPeter Wemm } 110512ed1c7cSGregory Neil Shapiro /* 1106c2aa98e2SPeter Wemm ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree 1107c2aa98e2SPeter Wemm ** 1108c2aa98e2SPeter Wemm ** Recursively find all the mci host files in `pathname'. Default to 1109c2aa98e2SPeter Wemm ** main host status directory if no path is provided. 1110c2aa98e2SPeter Wemm ** Call (*action)(pathname, host) for each file found. 1111c2aa98e2SPeter Wemm ** 1112c2aa98e2SPeter Wemm ** Note: all information is collected in a list before it is processed. 1113c2aa98e2SPeter Wemm ** This may not be the best way to do it, but it seems safest, since 1114c2aa98e2SPeter Wemm ** the file system would be touched while we are attempting to traverse 1115c2aa98e2SPeter Wemm ** the directory tree otherwise (during purges). 1116c2aa98e2SPeter Wemm ** 1117c2aa98e2SPeter Wemm ** Parameters: 1118c2aa98e2SPeter Wemm ** action -- function to call on each node. If returns < 0, 1119c2aa98e2SPeter Wemm ** return immediately. 1120c2aa98e2SPeter Wemm ** pathname -- root of tree. If null, use main host status 1121c2aa98e2SPeter Wemm ** directory. 1122c2aa98e2SPeter Wemm ** 1123c2aa98e2SPeter Wemm ** Returns: 1124c2aa98e2SPeter Wemm ** < 0 -- if any action routine returns a negative value, that 1125c2aa98e2SPeter Wemm ** value is returned. 1126c2aa98e2SPeter Wemm ** 0 -- if we successfully went to completion. 11273299c2f1SGregory Neil Shapiro ** > 0 -- return status from action() 1128c2aa98e2SPeter Wemm */ 1129c2aa98e2SPeter Wemm 1130c2aa98e2SPeter Wemm int 1131c2aa98e2SPeter Wemm mci_traverse_persistent(action, pathname) 1132684b2a5fSGregory Neil Shapiro int (*action)__P((char *, char *)); 1133c2aa98e2SPeter Wemm char *pathname; 1134c2aa98e2SPeter Wemm { 1135c2aa98e2SPeter Wemm struct stat statbuf; 1136c2aa98e2SPeter Wemm DIR *d; 1137c2aa98e2SPeter Wemm int ret; 1138c2aa98e2SPeter Wemm 1139c2aa98e2SPeter Wemm if (pathname == NULL) 1140c2aa98e2SPeter Wemm pathname = HostStatDir; 1141c2aa98e2SPeter Wemm if (pathname == NULL) 1142c2aa98e2SPeter Wemm return -1; 1143c2aa98e2SPeter Wemm 1144c2aa98e2SPeter Wemm if (tTd(56, 1)) 114512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: pathname is %s\n", pathname); 1146c2aa98e2SPeter Wemm 1147c2aa98e2SPeter Wemm ret = stat(pathname, &statbuf); 1148c2aa98e2SPeter Wemm if (ret < 0) 1149c2aa98e2SPeter Wemm { 1150c2aa98e2SPeter Wemm if (tTd(56, 2)) 115112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: Failed to stat %s: %s\n", 115212ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1153c2aa98e2SPeter Wemm return ret; 1154c2aa98e2SPeter Wemm } 1155c2aa98e2SPeter Wemm if (S_ISDIR(statbuf.st_mode)) 1156c2aa98e2SPeter Wemm { 11573299c2f1SGregory Neil Shapiro bool leftone, removedone; 115812ed1c7cSGregory Neil Shapiro size_t len; 115912ed1c7cSGregory Neil Shapiro char *newptr; 116012ed1c7cSGregory Neil Shapiro struct dirent *e; 116188ad41d4SGregory Neil Shapiro char newpath[MAXPATHLEN]; 1162567a2fc9SGregory Neil Shapiro #if MAXPATHLEN <= MAXNAMLEN - 3 1163567a2fc9SGregory Neil Shapiro ERROR "MAXPATHLEN <= MAXNAMLEN - 3" 1164567a2fc9SGregory Neil Shapiro #endif /* MAXPATHLEN <= MAXNAMLEN - 3 */ 1165c2aa98e2SPeter Wemm 1166c2aa98e2SPeter Wemm if ((d = opendir(pathname)) == NULL) 1167c2aa98e2SPeter Wemm { 1168c2aa98e2SPeter Wemm if (tTd(56, 2)) 116912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: opendir %s: %s\n", 117012ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1171c2aa98e2SPeter Wemm return -1; 1172c2aa98e2SPeter Wemm } 1173e3793f76SGregory Neil Shapiro 1174e3793f76SGregory Neil Shapiro /* 1175e3793f76SGregory Neil Shapiro ** Reserve space for trailing '/', at least one 1176e3793f76SGregory Neil Shapiro ** character, and '\0' 1177e3793f76SGregory Neil Shapiro */ 1178e3793f76SGregory Neil Shapiro 1179e3793f76SGregory Neil Shapiro len = sizeof(newpath) - 3; 118012ed1c7cSGregory Neil Shapiro if (sm_strlcpy(newpath, pathname, len) >= len) 1181c2aa98e2SPeter Wemm { 1182e3793f76SGregory Neil Shapiro int save_errno = errno; 1183e3793f76SGregory Neil Shapiro 1184c2aa98e2SPeter Wemm if (tTd(56, 2)) 118512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path \"%s\" too long", 1186c2aa98e2SPeter Wemm pathname); 1187e3793f76SGregory Neil Shapiro (void) closedir(d); 1188e3793f76SGregory Neil Shapiro errno = save_errno; 1189c2aa98e2SPeter Wemm return -1; 1190c2aa98e2SPeter Wemm } 1191c2aa98e2SPeter Wemm newptr = newpath + strlen(newpath); 1192c2aa98e2SPeter Wemm *newptr++ = '/'; 1193e3793f76SGregory Neil Shapiro len = sizeof(newpath) - (newptr - newpath); 1194c2aa98e2SPeter Wemm 11953299c2f1SGregory Neil Shapiro /* 11963299c2f1SGregory Neil Shapiro ** repeat until no file has been removed 11973299c2f1SGregory Neil Shapiro ** this may become ugly when several files "expire" 11983299c2f1SGregory Neil Shapiro ** during these loops, but it's better than doing 11993299c2f1SGregory Neil Shapiro ** a rewinddir() inside the inner loop 12003299c2f1SGregory Neil Shapiro */ 120112ed1c7cSGregory Neil Shapiro 12023299c2f1SGregory Neil Shapiro do 12033299c2f1SGregory Neil Shapiro { 120412ed1c7cSGregory Neil Shapiro leftone = removedone = false; 1205c2aa98e2SPeter Wemm while ((e = readdir(d)) != NULL) 1206c2aa98e2SPeter Wemm { 1207c2aa98e2SPeter Wemm if (e->d_name[0] == '.') 1208c2aa98e2SPeter Wemm continue; 1209c2aa98e2SPeter Wemm 1210e3793f76SGregory Neil Shapiro if (sm_strlcpy(newptr, e->d_name, len) >= len) 1211e3793f76SGregory Neil Shapiro { 1212e3793f76SGregory Neil Shapiro /* Skip truncated copies */ 1213e3793f76SGregory Neil Shapiro if (tTd(56, 4)) 1214e3793f76SGregory Neil Shapiro { 1215e3793f76SGregory Neil Shapiro *newptr = '\0'; 1216e3793f76SGregory Neil Shapiro sm_dprintf("mci_traverse: path \"%s%s\" too long", 1217e3793f76SGregory Neil Shapiro newpath, e->d_name); 1218e3793f76SGregory Neil Shapiro } 1219e3793f76SGregory Neil Shapiro continue; 1220e3793f76SGregory Neil Shapiro } 1221c2aa98e2SPeter Wemm 1222c0c4794dSGregory Neil Shapiro if (StopRequest) 1223c0c4794dSGregory Neil Shapiro stop_sendmail(); 1224c2aa98e2SPeter Wemm ret = mci_traverse_persistent(action, newpath); 1225c2aa98e2SPeter Wemm if (ret < 0) 1226c2aa98e2SPeter Wemm break; 12273299c2f1SGregory Neil Shapiro if (ret == 1) 122812ed1c7cSGregory Neil Shapiro leftone = true; 12293299c2f1SGregory Neil Shapiro if (!removedone && ret == 0 && 12303299c2f1SGregory Neil Shapiro action == mci_purge_persistent) 123112ed1c7cSGregory Neil Shapiro removedone = true; 12323299c2f1SGregory Neil Shapiro } 12333299c2f1SGregory Neil Shapiro if (ret < 0) 12343299c2f1SGregory Neil Shapiro break; 123512ed1c7cSGregory Neil Shapiro 1236c2aa98e2SPeter Wemm /* 1237c2aa98e2SPeter Wemm ** The following appears to be 1238c2aa98e2SPeter Wemm ** necessary during purges, since 1239c2aa98e2SPeter Wemm ** we modify the directory structure 1240c2aa98e2SPeter Wemm */ 124112ed1c7cSGregory Neil Shapiro 12423299c2f1SGregory Neil Shapiro if (removedone) 1243c2aa98e2SPeter Wemm rewinddir(d); 12443299c2f1SGregory Neil Shapiro if (tTd(56, 40)) 124512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 12463299c2f1SGregory Neil Shapiro pathname, ret, removedone, leftone); 12473299c2f1SGregory Neil Shapiro } while (removedone); 1248c2aa98e2SPeter Wemm 1249c2aa98e2SPeter Wemm /* purge (or whatever) the directory proper */ 12503299c2f1SGregory Neil Shapiro if (!leftone) 12513299c2f1SGregory Neil Shapiro { 1252c2aa98e2SPeter Wemm *--newptr = '\0'; 1253c2aa98e2SPeter Wemm ret = (*action)(newpath, NULL); 12543299c2f1SGregory Neil Shapiro } 12553299c2f1SGregory Neil Shapiro (void) closedir(d); 1256c2aa98e2SPeter Wemm } 1257c2aa98e2SPeter Wemm else if (S_ISREG(statbuf.st_mode)) 1258c2aa98e2SPeter Wemm { 1259c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 1260c2aa98e2SPeter Wemm char *start; 1261c2aa98e2SPeter Wemm char *scan; 1262c2aa98e2SPeter Wemm char host[MAXHOSTNAMELEN]; 1263c2aa98e2SPeter Wemm char *hostptr = host; 1264c2aa98e2SPeter Wemm 1265c2aa98e2SPeter Wemm /* 1266c2aa98e2SPeter Wemm ** Reconstruct the host name from the path to the 1267c2aa98e2SPeter Wemm ** persistent information. 1268c2aa98e2SPeter Wemm */ 1269c2aa98e2SPeter Wemm 1270c2aa98e2SPeter Wemm do 1271c2aa98e2SPeter Wemm { 1272c2aa98e2SPeter Wemm if (hostptr != host) 1273c2aa98e2SPeter Wemm *(hostptr++) = '.'; 1274c2aa98e2SPeter Wemm start = end; 12757660b554SGregory Neil Shapiro while (start > pathname && *(start - 1) != '/') 1276c2aa98e2SPeter Wemm start--; 1277c2aa98e2SPeter Wemm 1278c2aa98e2SPeter Wemm if (*end == '.') 1279c2aa98e2SPeter Wemm end--; 1280c2aa98e2SPeter Wemm 1281c2aa98e2SPeter Wemm for (scan = start; scan <= end; scan++) 1282c2aa98e2SPeter Wemm *(hostptr++) = *scan; 1283c2aa98e2SPeter Wemm 1284c2aa98e2SPeter Wemm end = start - 2; 12857660b554SGregory Neil Shapiro } while (end > pathname && *end == '.'); 1286c2aa98e2SPeter Wemm 1287c2aa98e2SPeter Wemm *hostptr = '\0'; 1288c2aa98e2SPeter Wemm 1289c2aa98e2SPeter Wemm /* 1290c2aa98e2SPeter Wemm ** Do something with the file containing the persistent 1291c2aa98e2SPeter Wemm ** information. 1292c2aa98e2SPeter Wemm */ 129312ed1c7cSGregory Neil Shapiro 1294c2aa98e2SPeter Wemm ret = (*action)(pathname, host); 1295c2aa98e2SPeter Wemm } 1296c2aa98e2SPeter Wemm 1297c2aa98e2SPeter Wemm return ret; 1298c2aa98e2SPeter Wemm } 129912ed1c7cSGregory Neil Shapiro /* 13003299c2f1SGregory Neil Shapiro ** MCI_PRINT_PERSISTENT -- print persistent info 1301c2aa98e2SPeter Wemm ** 1302c2aa98e2SPeter Wemm ** Dump the persistent information in the file 'pathname' 1303c2aa98e2SPeter Wemm ** 1304c2aa98e2SPeter Wemm ** Parameters: 1305c2aa98e2SPeter Wemm ** pathname -- the pathname to the status file. 1306c2aa98e2SPeter Wemm ** hostname -- the corresponding host name. 1307c2aa98e2SPeter Wemm ** 1308c2aa98e2SPeter Wemm ** Returns: 1309c2aa98e2SPeter Wemm ** 0 1310c2aa98e2SPeter Wemm */ 1311c2aa98e2SPeter Wemm 1312c2aa98e2SPeter Wemm int 1313c2aa98e2SPeter Wemm mci_print_persistent(pathname, hostname) 1314c2aa98e2SPeter Wemm char *pathname; 1315c2aa98e2SPeter Wemm char *hostname; 1316c2aa98e2SPeter Wemm { 131712ed1c7cSGregory Neil Shapiro static bool initflag = false; 131812ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 1319c2aa98e2SPeter Wemm int width = Verbose ? 78 : 25; 1320c2aa98e2SPeter Wemm bool locked; 1321c2aa98e2SPeter Wemm MCI mcib; 1322c2aa98e2SPeter Wemm 1323c2aa98e2SPeter Wemm /* skip directories */ 1324c2aa98e2SPeter Wemm if (hostname == NULL) 1325c2aa98e2SPeter Wemm return 0; 1326c2aa98e2SPeter Wemm 1327c0c4794dSGregory Neil Shapiro if (StopRequest) 1328c0c4794dSGregory Neil Shapiro stop_sendmail(); 1329c0c4794dSGregory Neil Shapiro 1330c2aa98e2SPeter Wemm if (!initflag) 1331c2aa98e2SPeter Wemm { 133212ed1c7cSGregory Neil Shapiro initflag = true; 133312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 133412ed1c7cSGregory Neil Shapiro " -------------- Hostname --------------- How long ago ---------Results---------\n"); 1335c2aa98e2SPeter Wemm } 1336c2aa98e2SPeter Wemm 133712ed1c7cSGregory Neil Shapiro fp = safefopen(pathname, O_RDONLY, FileMode, 1338c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 1339c2aa98e2SPeter Wemm 1340c2aa98e2SPeter Wemm if (fp == NULL) 1341c2aa98e2SPeter Wemm { 1342c2aa98e2SPeter Wemm if (tTd(56, 1)) 134312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 134412ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1345c2aa98e2SPeter Wemm return 0; 1346c2aa98e2SPeter Wemm } 1347c2aa98e2SPeter Wemm 1348c2aa98e2SPeter Wemm FileName = pathname; 1349951742c4SGregory Neil Shapiro memset(&mcib, '\0', sizeof(mcib)); 1350c2aa98e2SPeter Wemm if (mci_read_persistent(fp, &mcib) < 0) 1351c2aa98e2SPeter Wemm { 1352c2aa98e2SPeter Wemm syserr("%s: could not read status file", pathname); 135312ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1354c2aa98e2SPeter Wemm FileName = NULL; 1355c2aa98e2SPeter Wemm return 0; 1356c2aa98e2SPeter Wemm } 1357c2aa98e2SPeter Wemm 135812ed1c7cSGregory Neil Shapiro locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 135912ed1c7cSGregory Neil Shapiro "", LOCK_SH|LOCK_NB); 136012ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1361c2aa98e2SPeter Wemm FileName = NULL; 1362c2aa98e2SPeter Wemm 136312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 1364c2aa98e2SPeter Wemm locked ? '*' : ' ', hostname, 136512ed1c7cSGregory Neil Shapiro pintvl(curtime() - mcib.mci_lastuse, true)); 1366c2aa98e2SPeter Wemm if (mcib.mci_rstatus != NULL) 136712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 136812ed1c7cSGregory Neil Shapiro mcib.mci_rstatus); 1369c2aa98e2SPeter Wemm else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 137012ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 137112ed1c7cSGregory Neil Shapiro "Deferred: %.*s\n", width - 10, 137212ed1c7cSGregory Neil Shapiro sm_errstring(mcib.mci_errno)); 1373c2aa98e2SPeter Wemm else if (mcib.mci_exitstat != 0) 1374c2aa98e2SPeter Wemm { 137512ed1c7cSGregory Neil Shapiro char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 1376c2aa98e2SPeter Wemm 137712ed1c7cSGregory Neil Shapiro if (exmsg == NULL) 1378c2aa98e2SPeter Wemm { 1379c2aa98e2SPeter Wemm char buf[80]; 1380c2aa98e2SPeter Wemm 1381951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 138212ed1c7cSGregory Neil Shapiro "Unknown mailer error %d", 1383c2aa98e2SPeter Wemm mcib.mci_exitstat); 138412ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 138512ed1c7cSGregory Neil Shapiro width, buf); 1386c2aa98e2SPeter Wemm } 1387c2aa98e2SPeter Wemm else 138812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 138912ed1c7cSGregory Neil Shapiro width, &exmsg[5]); 1390c2aa98e2SPeter Wemm } 1391c2aa98e2SPeter Wemm else if (mcib.mci_errno == 0) 139212ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 1393c2aa98e2SPeter Wemm else 139412ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 139512ed1c7cSGregory Neil Shapiro width - 4, sm_errstring(mcib.mci_errno)); 1396c2aa98e2SPeter Wemm 1397c2aa98e2SPeter Wemm return 0; 1398c2aa98e2SPeter Wemm } 139912ed1c7cSGregory Neil Shapiro /* 1400c2aa98e2SPeter Wemm ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 1401c2aa98e2SPeter Wemm ** 1402c2aa98e2SPeter Wemm ** Parameters: 1403c2aa98e2SPeter Wemm ** pathname -- path to the status file. 1404c2aa98e2SPeter Wemm ** hostname -- name of host corresponding to that file. 1405c2aa98e2SPeter Wemm ** NULL if this is a directory (domain). 1406c2aa98e2SPeter Wemm ** 1407c2aa98e2SPeter Wemm ** Returns: 14083299c2f1SGregory Neil Shapiro ** 0 -- ok 14093299c2f1SGregory Neil Shapiro ** 1 -- file not deleted (too young, incorrect format) 14103299c2f1SGregory Neil Shapiro ** < 0 -- some error occurred 1411c2aa98e2SPeter Wemm */ 1412c2aa98e2SPeter Wemm 1413c2aa98e2SPeter Wemm int 1414c2aa98e2SPeter Wemm mci_purge_persistent(pathname, hostname) 1415c2aa98e2SPeter Wemm char *pathname; 1416c2aa98e2SPeter Wemm char *hostname; 1417c2aa98e2SPeter Wemm { 14183299c2f1SGregory Neil Shapiro struct stat statbuf; 1419c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 14203299c2f1SGregory Neil Shapiro int ret; 1421c2aa98e2SPeter Wemm 1422c2aa98e2SPeter Wemm if (tTd(56, 1)) 142312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 1424c2aa98e2SPeter Wemm 14253299c2f1SGregory Neil Shapiro ret = stat(pathname, &statbuf); 14263299c2f1SGregory Neil Shapiro if (ret < 0) 14273299c2f1SGregory Neil Shapiro { 14283299c2f1SGregory Neil Shapiro if (tTd(56, 2)) 142912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 143012ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 14313299c2f1SGregory Neil Shapiro return ret; 14323299c2f1SGregory Neil Shapiro } 1433320f00e7SGregory Neil Shapiro if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 14343299c2f1SGregory Neil Shapiro return 1; 1435c2aa98e2SPeter Wemm if (hostname != NULL) 1436c2aa98e2SPeter Wemm { 1437c2aa98e2SPeter Wemm /* remove the file */ 143812ed1c7cSGregory Neil Shapiro ret = unlink(pathname); 143912ed1c7cSGregory Neil Shapiro if (ret < 0) 1440c2aa98e2SPeter Wemm { 144112ed1c7cSGregory Neil Shapiro if (LogLevel > 8) 144212ed1c7cSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 144312ed1c7cSGregory Neil Shapiro "mci_purge_persistent: failed to unlink %s: %s", 144412ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1445c2aa98e2SPeter Wemm if (tTd(56, 2)) 144612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 144712ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 144812ed1c7cSGregory Neil Shapiro return ret; 1449c2aa98e2SPeter Wemm } 1450c2aa98e2SPeter Wemm } 1451c2aa98e2SPeter Wemm else 1452c2aa98e2SPeter Wemm { 1453c2aa98e2SPeter Wemm /* remove the directory */ 1454c2aa98e2SPeter Wemm if (*end != '.') 14553299c2f1SGregory Neil Shapiro return 1; 1456c2aa98e2SPeter Wemm 1457c2aa98e2SPeter Wemm if (tTd(56, 1)) 145812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 1459c2aa98e2SPeter Wemm 146012ed1c7cSGregory Neil Shapiro ret = rmdir(pathname); 146112ed1c7cSGregory Neil Shapiro if (ret < 0) 1462c2aa98e2SPeter Wemm { 1463c2aa98e2SPeter Wemm if (tTd(56, 2)) 146412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 146512ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 146612ed1c7cSGregory Neil Shapiro return ret; 1467c2aa98e2SPeter Wemm } 1468c2aa98e2SPeter Wemm } 1469c2aa98e2SPeter Wemm 1470c2aa98e2SPeter Wemm return 0; 1471c2aa98e2SPeter Wemm } 147212ed1c7cSGregory Neil Shapiro /* 1473c2aa98e2SPeter Wemm ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 1474c2aa98e2SPeter Wemm ** 14757660b554SGregory Neil Shapiro ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 1476c2aa98e2SPeter Wemm ** putting the result into `path'. if `createflag' is set, intervening 1477c2aa98e2SPeter Wemm ** directories will be created as needed. 1478c2aa98e2SPeter Wemm ** 1479c2aa98e2SPeter Wemm ** Parameters: 1480c2aa98e2SPeter Wemm ** host -- host name to convert from. 1481c2aa98e2SPeter Wemm ** path -- place to store result. 1482c2aa98e2SPeter Wemm ** pathlen -- length of path buffer. 1483c2aa98e2SPeter Wemm ** createflag -- if set, create intervening directories as 1484c2aa98e2SPeter Wemm ** needed. 1485c2aa98e2SPeter Wemm ** 1486c2aa98e2SPeter Wemm ** Returns: 1487c2aa98e2SPeter Wemm ** 0 -- success 1488c2aa98e2SPeter Wemm ** -1 -- failure 1489c2aa98e2SPeter Wemm */ 1490c2aa98e2SPeter Wemm 14913299c2f1SGregory Neil Shapiro static int 1492c2aa98e2SPeter Wemm mci_generate_persistent_path(host, path, pathlen, createflag) 1493c2aa98e2SPeter Wemm const char *host; 1494c2aa98e2SPeter Wemm char *path; 1495c2aa98e2SPeter Wemm int pathlen; 1496c2aa98e2SPeter Wemm bool createflag; 1497c2aa98e2SPeter Wemm { 1498c2aa98e2SPeter Wemm char *elem, *p, *x, ch; 1499c2aa98e2SPeter Wemm int ret = 0; 1500c2aa98e2SPeter Wemm int len; 1501c2aa98e2SPeter Wemm char t_host[MAXHOSTNAMELEN]; 15023299c2f1SGregory Neil Shapiro #if NETINET6 15033299c2f1SGregory Neil Shapiro struct in6_addr in6_addr; 15043299c2f1SGregory Neil Shapiro #endif /* NETINET6 */ 1505c2aa98e2SPeter Wemm 1506c2aa98e2SPeter Wemm /* 1507c2aa98e2SPeter Wemm ** Rationality check the arguments. 1508c2aa98e2SPeter Wemm */ 1509c2aa98e2SPeter Wemm 1510c2aa98e2SPeter Wemm if (host == NULL) 1511c2aa98e2SPeter Wemm { 1512c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null host"); 1513c2aa98e2SPeter Wemm return -1; 1514c2aa98e2SPeter Wemm } 1515c2aa98e2SPeter Wemm if (path == NULL) 1516c2aa98e2SPeter Wemm { 1517c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null path"); 1518c2aa98e2SPeter Wemm return -1; 1519c2aa98e2SPeter Wemm } 1520c2aa98e2SPeter Wemm 1521c2aa98e2SPeter Wemm if (tTd(56, 80)) 152212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_generate_persistent_path(%s): ", host); 1523c2aa98e2SPeter Wemm 1524c2aa98e2SPeter Wemm if (*host == '\0' || *host == '.') 1525c2aa98e2SPeter Wemm return -1; 1526c2aa98e2SPeter Wemm 1527c2aa98e2SPeter Wemm /* make certain this is not a bracketed host number */ 1528951742c4SGregory Neil Shapiro if (strlen(host) > sizeof(t_host) - 1) 1529c2aa98e2SPeter Wemm return -1; 1530c2aa98e2SPeter Wemm if (host[0] == '[') 1531951742c4SGregory Neil Shapiro (void) sm_strlcpy(t_host, host + 1, sizeof(t_host)); 1532c2aa98e2SPeter Wemm else 1533951742c4SGregory Neil Shapiro (void) sm_strlcpy(t_host, host, sizeof(t_host)); 1534c2aa98e2SPeter Wemm 1535c2aa98e2SPeter Wemm /* 1536c2aa98e2SPeter Wemm ** Delete any trailing dots from the hostname. 1537c2aa98e2SPeter Wemm ** Leave 'elem' pointing at the \0. 1538c2aa98e2SPeter Wemm */ 1539c2aa98e2SPeter Wemm 1540c2aa98e2SPeter Wemm elem = t_host + strlen(t_host); 1541c2aa98e2SPeter Wemm while (elem > t_host && 1542c2aa98e2SPeter Wemm (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 1543c2aa98e2SPeter Wemm *--elem = '\0'; 1544c2aa98e2SPeter Wemm 1545c2aa98e2SPeter Wemm /* check for bogus bracketed address */ 154612ed1c7cSGregory Neil Shapiro if (host[0] == '[') 154712ed1c7cSGregory Neil Shapiro { 154812ed1c7cSGregory Neil Shapiro bool good = false; 15493299c2f1SGregory Neil Shapiro # if NETINET6 155012ed1c7cSGregory Neil Shapiro if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 155112ed1c7cSGregory Neil Shapiro good = true; 15523299c2f1SGregory Neil Shapiro # endif /* NETINET6 */ 15533299c2f1SGregory Neil Shapiro # if NETINET 155412ed1c7cSGregory Neil Shapiro if (inet_addr(t_host) != INADDR_NONE) 155512ed1c7cSGregory Neil Shapiro good = true; 15563299c2f1SGregory Neil Shapiro # endif /* NETINET */ 155712ed1c7cSGregory Neil Shapiro if (!good) 1558c2aa98e2SPeter Wemm return -1; 155912ed1c7cSGregory Neil Shapiro } 1560c2aa98e2SPeter Wemm 1561c2aa98e2SPeter Wemm /* check for what will be the final length of the path */ 1562c2aa98e2SPeter Wemm len = strlen(HostStatDir) + 2; 1563c2aa98e2SPeter Wemm for (p = (char *) t_host; *p != '\0'; p++) 1564c2aa98e2SPeter Wemm { 1565c2aa98e2SPeter Wemm if (*p == '.') 1566c2aa98e2SPeter Wemm len++; 1567c2aa98e2SPeter Wemm len++; 1568c2aa98e2SPeter Wemm if (p[0] == '.' && p[1] == '.') 1569c2aa98e2SPeter Wemm return -1; 1570c2aa98e2SPeter Wemm } 1571c2aa98e2SPeter Wemm if (len > pathlen || len < 1) 1572c2aa98e2SPeter Wemm return -1; 157312ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(path, HostStatDir, pathlen); 1574c2aa98e2SPeter Wemm p = path + strlen(path); 1575c2aa98e2SPeter Wemm while (elem > t_host) 1576c2aa98e2SPeter Wemm { 1577c2aa98e2SPeter Wemm if (!path_is_dir(path, createflag)) 1578c2aa98e2SPeter Wemm { 1579c2aa98e2SPeter Wemm ret = -1; 1580c2aa98e2SPeter Wemm break; 1581c2aa98e2SPeter Wemm } 1582c2aa98e2SPeter Wemm elem--; 1583c2aa98e2SPeter Wemm while (elem >= t_host && *elem != '.') 1584c2aa98e2SPeter Wemm elem--; 1585c2aa98e2SPeter Wemm *p++ = '/'; 1586c2aa98e2SPeter Wemm x = elem + 1; 1587c2aa98e2SPeter Wemm while ((ch = *x++) != '\0' && ch != '.') 1588c2aa98e2SPeter Wemm { 1589c2aa98e2SPeter Wemm if (isascii(ch) && isupper(ch)) 1590c2aa98e2SPeter Wemm ch = tolower(ch); 1591c2aa98e2SPeter Wemm if (ch == '/') 1592c2aa98e2SPeter Wemm ch = ':'; /* / -> : */ 1593c2aa98e2SPeter Wemm *p++ = ch; 1594c2aa98e2SPeter Wemm } 1595c2aa98e2SPeter Wemm if (elem >= t_host) 1596c2aa98e2SPeter Wemm *p++ = '.'; 1597c2aa98e2SPeter Wemm *p = '\0'; 1598c2aa98e2SPeter Wemm } 1599c2aa98e2SPeter Wemm if (tTd(56, 80)) 1600c2aa98e2SPeter Wemm { 1601c2aa98e2SPeter Wemm if (ret < 0) 160212ed1c7cSGregory Neil Shapiro sm_dprintf("FAILURE %d\n", ret); 1603c2aa98e2SPeter Wemm else 160412ed1c7cSGregory Neil Shapiro sm_dprintf("SUCCESS %s\n", path); 1605c2aa98e2SPeter Wemm } 16063299c2f1SGregory Neil Shapiro return ret; 1607c2aa98e2SPeter Wemm } 1608