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 164313cc83SGregory 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> 20*5b0945b5SGregory Neil Shapiro #endif 213299c2f1SGregory Neil Shapiro 22c2aa98e2SPeter Wemm #include <dirent.h> 23*5b0945b5SGregory Neil Shapiro #if STARTTLS 24*5b0945b5SGregory Neil Shapiro # include <tls.h> 25*5b0945b5SGregory Neil Shapiro #endif 26c2aa98e2SPeter Wemm 273299c2f1SGregory Neil Shapiro static int mci_generate_persistent_path __P((const char *, char *, 283299c2f1SGregory Neil Shapiro int, bool)); 293299c2f1SGregory Neil Shapiro static bool mci_load_persistent __P((MCI *)); 303299c2f1SGregory Neil Shapiro static void mci_uncache __P((MCI **, bool)); 31*5b0945b5SGregory Neil Shapiro static void mci_clear __P((MCI *)); 323299c2f1SGregory Neil Shapiro static int mci_lock_host_statfile __P((MCI *)); 3312ed1c7cSGregory Neil Shapiro static int mci_read_persistent __P((SM_FILE_T *, MCI *)); 343299c2f1SGregory Neil Shapiro 35c2aa98e2SPeter Wemm /* 36c2aa98e2SPeter Wemm ** Mail Connection Information (MCI) Caching Module. 37c2aa98e2SPeter Wemm ** 38c2aa98e2SPeter Wemm ** There are actually two separate things cached. The first is 39c2aa98e2SPeter Wemm ** the set of all open connections -- these are stored in a 40c2aa98e2SPeter Wemm ** (small) list. The second is stored in the symbol table; it 41c2aa98e2SPeter Wemm ** has the overall status for all hosts, whether or not there 42c2aa98e2SPeter Wemm ** is a connection open currently. 43c2aa98e2SPeter Wemm ** 44c2aa98e2SPeter Wemm ** There should never be too many connections open (since this 45c2aa98e2SPeter Wemm ** could flood the socket table), nor should a connection be 46c2aa98e2SPeter Wemm ** allowed to sit idly for too long. 47c2aa98e2SPeter Wemm ** 48c2aa98e2SPeter Wemm ** MaxMciCache is the maximum number of open connections that 49c2aa98e2SPeter Wemm ** will be supported. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** MciCacheTimeout is the time (in seconds) that a connection 52c2aa98e2SPeter Wemm ** is permitted to survive without activity. 53c2aa98e2SPeter Wemm ** 54567a2fc9SGregory Neil Shapiro ** We actually try any cached connections by sending a RSET 55567a2fc9SGregory Neil Shapiro ** before we use them; if the RSET fails we close down the 56567a2fc9SGregory Neil Shapiro ** connection and reopen it (see smtpprobe()). 57c2aa98e2SPeter Wemm ** 58c2aa98e2SPeter Wemm ** The persistent MCI code is donated by Mark Lovell and Paul 59c2aa98e2SPeter Wemm ** Vixie. It is based on the long term host status code in KJS 60c2aa98e2SPeter Wemm ** written by Paul but has been adapted by Mark to fit into the 61c2aa98e2SPeter Wemm ** MCI structure. 62c2aa98e2SPeter Wemm */ 63c2aa98e2SPeter Wemm 643299c2f1SGregory Neil Shapiro static MCI **MciCache; /* the open connection cache */ 65c2aa98e2SPeter Wemm 6612ed1c7cSGregory Neil Shapiro /* 67c2aa98e2SPeter Wemm ** MCI_CACHE -- enter a connection structure into the open connection cache 68c2aa98e2SPeter Wemm ** 69c2aa98e2SPeter Wemm ** This may cause something else to be flushed. 70c2aa98e2SPeter Wemm ** 71c2aa98e2SPeter Wemm ** Parameters: 72c2aa98e2SPeter Wemm ** mci -- the connection to cache. 73c2aa98e2SPeter Wemm ** 74c2aa98e2SPeter Wemm ** Returns: 75c2aa98e2SPeter Wemm ** none. 76c2aa98e2SPeter Wemm */ 77c2aa98e2SPeter Wemm 78c2aa98e2SPeter Wemm void 79c2aa98e2SPeter Wemm mci_cache(mci) 80c2aa98e2SPeter Wemm register MCI *mci; 81c2aa98e2SPeter Wemm { 82c2aa98e2SPeter Wemm register MCI **mcislot; 83c2aa98e2SPeter Wemm 84c2aa98e2SPeter Wemm /* 85c2aa98e2SPeter Wemm ** Find the best slot. This may cause expired connections 86c2aa98e2SPeter Wemm ** to be closed. 87c2aa98e2SPeter Wemm */ 88c2aa98e2SPeter Wemm 89c2aa98e2SPeter Wemm mcislot = mci_scan(mci); 90c2aa98e2SPeter Wemm if (mcislot == NULL) 91c2aa98e2SPeter Wemm { 92c2aa98e2SPeter Wemm /* we don't support caching */ 93c2aa98e2SPeter Wemm return; 94c2aa98e2SPeter Wemm } 95c2aa98e2SPeter Wemm 96c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 97c2aa98e2SPeter Wemm return; 98c2aa98e2SPeter Wemm 99c2aa98e2SPeter Wemm /* if this is already cached, we are done */ 100c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 101c2aa98e2SPeter Wemm return; 102c2aa98e2SPeter Wemm 103c2aa98e2SPeter Wemm /* otherwise we may have to clear the slot */ 104c2aa98e2SPeter Wemm if (*mcislot != NULL) 10512ed1c7cSGregory Neil Shapiro mci_uncache(mcislot, true); 106c2aa98e2SPeter Wemm 107c2aa98e2SPeter Wemm if (tTd(42, 5)) 10812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_cache: caching %p (%s) in slot %d\n", 109*5b0945b5SGregory Neil Shapiro (void *)mci, mci->mci_host, (int) (mcislot - MciCache)); 110c2aa98e2SPeter Wemm if (tTd(91, 100)) 111c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 1123299c2f1SGregory Neil Shapiro "mci_cache: caching %lx (%.100s) in slot %d", 11312ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 11412ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache)); 115c2aa98e2SPeter Wemm 116c2aa98e2SPeter Wemm *mcislot = mci; 117c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CACHED; 118c2aa98e2SPeter Wemm } 11912ed1c7cSGregory Neil Shapiro /* 120c2aa98e2SPeter Wemm ** MCI_SCAN -- scan the cache, flush junk, and return best slot 121c2aa98e2SPeter Wemm ** 122c2aa98e2SPeter Wemm ** Parameters: 123c2aa98e2SPeter Wemm ** savemci -- never flush this one. Can be null. 124c2aa98e2SPeter Wemm ** 125c2aa98e2SPeter Wemm ** Returns: 126c2aa98e2SPeter Wemm ** The LRU (or empty) slot. 127c2aa98e2SPeter Wemm */ 128c2aa98e2SPeter Wemm 129c2aa98e2SPeter Wemm MCI ** 130c2aa98e2SPeter Wemm mci_scan(savemci) 131c2aa98e2SPeter Wemm MCI *savemci; 132c2aa98e2SPeter Wemm { 133c2aa98e2SPeter Wemm time_t now; 134c2aa98e2SPeter Wemm register MCI **bestmci; 135c2aa98e2SPeter Wemm register MCI *mci; 136c2aa98e2SPeter Wemm register int i; 137c2aa98e2SPeter Wemm 138c2aa98e2SPeter Wemm if (MaxMciCache <= 0) 139c2aa98e2SPeter Wemm { 140c2aa98e2SPeter Wemm /* we don't support caching */ 141c2aa98e2SPeter Wemm return NULL; 142c2aa98e2SPeter Wemm } 143c2aa98e2SPeter Wemm 144c2aa98e2SPeter Wemm if (MciCache == NULL) 145c2aa98e2SPeter Wemm { 146c2aa98e2SPeter Wemm /* first call */ 147951742c4SGregory Neil Shapiro MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof(*MciCache)); 148951742c4SGregory Neil Shapiro memset((char *) MciCache, '\0', MaxMciCache * sizeof(*MciCache)); 1493299c2f1SGregory Neil Shapiro return &MciCache[0]; 150c2aa98e2SPeter Wemm } 151c2aa98e2SPeter Wemm 152c2aa98e2SPeter Wemm now = curtime(); 153c2aa98e2SPeter Wemm bestmci = &MciCache[0]; 154c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 155c2aa98e2SPeter Wemm { 156c2aa98e2SPeter Wemm mci = MciCache[i]; 157c2aa98e2SPeter Wemm if (mci == NULL || mci->mci_state == MCIS_CLOSED) 158c2aa98e2SPeter Wemm { 159c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 160c2aa98e2SPeter Wemm continue; 161c2aa98e2SPeter Wemm } 162320f00e7SGregory Neil Shapiro if ((mci->mci_lastuse + MciCacheTimeout <= now || 1633299c2f1SGregory Neil Shapiro (mci->mci_mailer != NULL && 1643299c2f1SGregory Neil Shapiro mci->mci_mailer->m_maxdeliveries > 0 && 1653299c2f1SGregory Neil Shapiro mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&& 1663299c2f1SGregory Neil Shapiro mci != savemci) 167c2aa98e2SPeter Wemm { 1683299c2f1SGregory Neil Shapiro /* connection idle too long or too many deliveries */ 169c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 1703299c2f1SGregory Neil Shapiro 1713299c2f1SGregory Neil Shapiro /* close it */ 17212ed1c7cSGregory Neil Shapiro mci_uncache(bestmci, true); 173c2aa98e2SPeter Wemm continue; 174c2aa98e2SPeter Wemm } 175c2aa98e2SPeter Wemm if (*bestmci == NULL) 176c2aa98e2SPeter Wemm continue; 177c2aa98e2SPeter Wemm if (mci->mci_lastuse < (*bestmci)->mci_lastuse) 178c2aa98e2SPeter Wemm bestmci = &MciCache[i]; 179c2aa98e2SPeter Wemm } 180c2aa98e2SPeter Wemm return bestmci; 181c2aa98e2SPeter Wemm } 18212ed1c7cSGregory Neil Shapiro /* 183c2aa98e2SPeter Wemm ** MCI_UNCACHE -- remove a connection from a slot. 184c2aa98e2SPeter Wemm ** 185c2aa98e2SPeter Wemm ** May close a connection. 186c2aa98e2SPeter Wemm ** 187c2aa98e2SPeter Wemm ** Parameters: 188c2aa98e2SPeter Wemm ** mcislot -- the slot to empty. 18912ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol on this connection. 19012ed1c7cSGregory Neil Shapiro ** if false, we are assumed to be in a forked child; 191c2aa98e2SPeter Wemm ** all we want to do is close the file(s). 192c2aa98e2SPeter Wemm ** 193c2aa98e2SPeter Wemm ** Returns: 194c2aa98e2SPeter Wemm ** none. 195c2aa98e2SPeter Wemm */ 196c2aa98e2SPeter Wemm 1973299c2f1SGregory Neil Shapiro static void 198c2aa98e2SPeter Wemm mci_uncache(mcislot, doquit) 199c2aa98e2SPeter Wemm register MCI **mcislot; 200c2aa98e2SPeter Wemm bool doquit; 201c2aa98e2SPeter Wemm { 202c2aa98e2SPeter Wemm register MCI *mci; 203c2aa98e2SPeter Wemm extern ENVELOPE BlankEnvelope; 204c2aa98e2SPeter Wemm 205c2aa98e2SPeter Wemm mci = *mcislot; 206c2aa98e2SPeter Wemm if (mci == NULL) 207c2aa98e2SPeter Wemm return; 208c2aa98e2SPeter Wemm *mcislot = NULL; 209c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 210c2aa98e2SPeter Wemm return; 211c2aa98e2SPeter Wemm 212c2aa98e2SPeter Wemm mci_unlock_host(mci); 213c2aa98e2SPeter Wemm 214c2aa98e2SPeter Wemm if (tTd(42, 5)) 21512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n", 216*5b0945b5SGregory Neil Shapiro (void *)mci, mci->mci_host, (int) (mcislot - MciCache), 21712ed1c7cSGregory Neil Shapiro doquit); 218c2aa98e2SPeter Wemm if (tTd(91, 100)) 219c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 2203299c2f1SGregory Neil Shapiro "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)", 22112ed1c7cSGregory Neil Shapiro (unsigned long) mci, mci->mci_host, 22212ed1c7cSGregory Neil Shapiro (int) (mcislot - MciCache), doquit); 223c2aa98e2SPeter Wemm 2243299c2f1SGregory Neil Shapiro mci->mci_deliveries = 0; 225c2aa98e2SPeter Wemm if (doquit) 226c2aa98e2SPeter Wemm { 227c2aa98e2SPeter Wemm message("Closing connection to %s", mci->mci_host); 228c2aa98e2SPeter Wemm 229c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_CACHED; 230c2aa98e2SPeter Wemm 231c2aa98e2SPeter Wemm /* only uses the envelope to flush the transcript file */ 232c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 233c2aa98e2SPeter Wemm smtpquit(mci->mci_mailer, mci, &BlankEnvelope); 23412ed1c7cSGregory Neil Shapiro #if XLA 235c2aa98e2SPeter Wemm xla_host_end(mci->mci_host); 236*5b0945b5SGregory Neil Shapiro #endif 237c2aa98e2SPeter Wemm } 238c2aa98e2SPeter Wemm else 239c2aa98e2SPeter Wemm { 240c2aa98e2SPeter Wemm if (mci->mci_in != NULL) 24112ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 242c2aa98e2SPeter Wemm if (mci->mci_out != NULL) 24312ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 244c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 245c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 246c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 247c2aa98e2SPeter Wemm mci->mci_errno = 0; 248c2aa98e2SPeter Wemm mci->mci_flags = 0; 24912ed1c7cSGregory Neil Shapiro 25012ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 25112ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 25212ed1c7cSGregory Neil Shapiro #if PIPELINING 25312ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 254*5b0945b5SGregory Neil Shapiro #endif 25512ed1c7cSGregory Neil Shapiro } 25612ed1c7cSGregory Neil Shapiro 257*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_status); 258*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_rstatus); 259*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_heloname); 260*5b0945b5SGregory Neil Shapiro mci_clear(mci); 26112ed1c7cSGregory Neil Shapiro if (mci->mci_rpool != NULL) 26212ed1c7cSGregory Neil Shapiro { 26312ed1c7cSGregory Neil Shapiro sm_rpool_free(mci->mci_rpool); 26412ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = NULL; 26512ed1c7cSGregory Neil Shapiro mci->mci_rpool = NULL; 266c2aa98e2SPeter Wemm } 267c2aa98e2SPeter Wemm } 26812ed1c7cSGregory Neil Shapiro /* 269c2aa98e2SPeter Wemm ** MCI_FLUSH -- flush the entire cache 270c2aa98e2SPeter Wemm ** 271c2aa98e2SPeter Wemm ** Parameters: 27212ed1c7cSGregory Neil Shapiro ** doquit -- if true, send QUIT protocol. 27312ed1c7cSGregory Neil Shapiro ** if false, just close the connection. 274c2aa98e2SPeter Wemm ** allbut -- but leave this one open. 275c2aa98e2SPeter Wemm ** 276c2aa98e2SPeter Wemm ** Returns: 277c2aa98e2SPeter Wemm ** none. 278c2aa98e2SPeter Wemm */ 279c2aa98e2SPeter Wemm 280c2aa98e2SPeter Wemm void 281c2aa98e2SPeter Wemm mci_flush(doquit, allbut) 282c2aa98e2SPeter Wemm bool doquit; 283c2aa98e2SPeter Wemm MCI *allbut; 284c2aa98e2SPeter Wemm { 285c2aa98e2SPeter Wemm register int i; 286c2aa98e2SPeter Wemm 287c2aa98e2SPeter Wemm if (MciCache == NULL) 288c2aa98e2SPeter Wemm return; 289c2aa98e2SPeter Wemm 290c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 291c46d91b7SGregory Neil Shapiro { 292c2aa98e2SPeter Wemm if (allbut != MciCache[i]) 293c2aa98e2SPeter Wemm mci_uncache(&MciCache[i], doquit); 294c2aa98e2SPeter Wemm } 295c46d91b7SGregory Neil Shapiro } 2966f9c8e5bSGregory Neil Shapiro 2976f9c8e5bSGregory Neil Shapiro /* 2986f9c8e5bSGregory Neil Shapiro ** MCI_CLR_EXTENSIONS -- clear knowledge about SMTP extensions 2996f9c8e5bSGregory Neil Shapiro ** 3006f9c8e5bSGregory Neil Shapiro ** Parameters: 3016f9c8e5bSGregory Neil Shapiro ** mci -- the connection to clear. 3026f9c8e5bSGregory Neil Shapiro ** 3036f9c8e5bSGregory Neil Shapiro ** Returns: 3046f9c8e5bSGregory Neil Shapiro ** none. 3056f9c8e5bSGregory Neil Shapiro */ 3066f9c8e5bSGregory Neil Shapiro 3076f9c8e5bSGregory Neil Shapiro void 3086f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci) 3096f9c8e5bSGregory Neil Shapiro MCI *mci; 3106f9c8e5bSGregory Neil Shapiro { 3116f9c8e5bSGregory Neil Shapiro if (mci == NULL) 3126f9c8e5bSGregory Neil Shapiro return; 3136f9c8e5bSGregory Neil Shapiro 3146f9c8e5bSGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 3156f9c8e5bSGregory Neil Shapiro mci->mci_maxsize = 0; 3166f9c8e5bSGregory Neil Shapiro mci->mci_min_by = 0; 3176f9c8e5bSGregory Neil Shapiro #if SASL 3186f9c8e5bSGregory Neil Shapiro mci->mci_saslcap = NULL; 319*5b0945b5SGregory Neil Shapiro #endif 3206f9c8e5bSGregory Neil Shapiro } 3216f9c8e5bSGregory Neil Shapiro 32212ed1c7cSGregory Neil Shapiro /* 323*5b0945b5SGregory Neil Shapiro ** MCI_CLEAR -- clear mci 324*5b0945b5SGregory Neil Shapiro ** 325*5b0945b5SGregory Neil Shapiro ** Parameters: 326*5b0945b5SGregory Neil Shapiro ** mci -- the connection to clear. 327*5b0945b5SGregory Neil Shapiro ** 328*5b0945b5SGregory Neil Shapiro ** Returns: 329*5b0945b5SGregory Neil Shapiro ** none. 330*5b0945b5SGregory Neil Shapiro */ 331*5b0945b5SGregory Neil Shapiro 332*5b0945b5SGregory Neil Shapiro static void 333*5b0945b5SGregory Neil Shapiro mci_clear(mci) 334*5b0945b5SGregory Neil Shapiro MCI *mci; 335*5b0945b5SGregory Neil Shapiro { 336*5b0945b5SGregory Neil Shapiro if (mci == NULL) 337*5b0945b5SGregory Neil Shapiro return; 338*5b0945b5SGregory Neil Shapiro 339*5b0945b5SGregory Neil Shapiro mci->mci_maxsize = 0; 340*5b0945b5SGregory Neil Shapiro mci->mci_min_by = 0; 341*5b0945b5SGregory Neil Shapiro mci->mci_deliveries = 0; 342*5b0945b5SGregory Neil Shapiro #if SASL 343*5b0945b5SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 344*5b0945b5SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 345*5b0945b5SGregory Neil Shapiro #endif 346*5b0945b5SGregory Neil Shapiro #if STARTTLS 347*5b0945b5SGregory Neil Shapiro if (bitset(MCIF_TLSACT, mci->mci_flags) && mci->mci_ssl != NULL) 348*5b0945b5SGregory Neil Shapiro SM_SSL_FREE(mci->mci_ssl); 349*5b0945b5SGregory Neil Shapiro #endif 350*5b0945b5SGregory Neil Shapiro 351*5b0945b5SGregory Neil Shapiro /* which flags to preserve? */ 352*5b0945b5SGregory Neil Shapiro mci->mci_flags &= MCIF_CACHED; 353*5b0945b5SGregory Neil Shapiro mactabclear(&mci->mci_macro); 354*5b0945b5SGregory Neil Shapiro } 355*5b0945b5SGregory Neil Shapiro 356*5b0945b5SGregory Neil Shapiro 357*5b0945b5SGregory Neil Shapiro /* 358c2aa98e2SPeter Wemm ** MCI_GET -- get information about a particular host 35912ed1c7cSGregory Neil Shapiro ** 36012ed1c7cSGregory Neil Shapiro ** Parameters: 36112ed1c7cSGregory Neil Shapiro ** host -- host to look for. 36212ed1c7cSGregory Neil Shapiro ** m -- mailer. 36312ed1c7cSGregory Neil Shapiro ** 36412ed1c7cSGregory Neil Shapiro ** Returns: 36512ed1c7cSGregory Neil Shapiro ** mci for this host (might be new). 366c2aa98e2SPeter Wemm */ 367c2aa98e2SPeter Wemm 368c2aa98e2SPeter Wemm MCI * 369c2aa98e2SPeter Wemm mci_get(host, m) 370c2aa98e2SPeter Wemm char *host; 371c2aa98e2SPeter Wemm MAILER *m; 372c2aa98e2SPeter Wemm { 373c2aa98e2SPeter Wemm register MCI *mci; 374c2aa98e2SPeter Wemm register STAB *s; 375c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 376c2aa98e2SPeter Wemm 377c2aa98e2SPeter Wemm /* clear CurHostAddr so we don't get a bogus address with this name */ 378951742c4SGregory Neil Shapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 379c2aa98e2SPeter Wemm 380c2aa98e2SPeter Wemm /* clear out any expired connections */ 381c2aa98e2SPeter Wemm (void) mci_scan(NULL); 382c2aa98e2SPeter Wemm 383c2aa98e2SPeter Wemm if (m->m_mno < 0) 384c46d91b7SGregory Neil Shapiro syserr("!negative mno %d (%s)", m->m_mno, m->m_name); 3853299c2f1SGregory Neil Shapiro 386c2aa98e2SPeter Wemm s = stab(host, ST_MCI + m->m_mno, ST_ENTER); 387c2aa98e2SPeter Wemm mci = &s->s_mci; 388c2aa98e2SPeter Wemm 38912ed1c7cSGregory Neil Shapiro /* initialize per-message data */ 39012ed1c7cSGregory Neil Shapiro mci->mci_retryrcpt = false; 39112ed1c7cSGregory Neil Shapiro mci->mci_tolist = NULL; 39212ed1c7cSGregory Neil Shapiro #if PIPELINING 39312ed1c7cSGregory Neil Shapiro mci->mci_okrcpts = 0; 394*5b0945b5SGregory Neil Shapiro #endif 395da7d7b9cSGregory Neil Shapiro mci->mci_flags &= ~MCIF_NOTSTICKY; 39612ed1c7cSGregory Neil Shapiro 39712ed1c7cSGregory Neil Shapiro if (mci->mci_rpool == NULL) 39812ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 39912ed1c7cSGregory Neil Shapiro 40012ed1c7cSGregory Neil Shapiro if (mci->mci_macro.mac_rpool == NULL) 40112ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 40212ed1c7cSGregory Neil Shapiro 4033299c2f1SGregory Neil Shapiro /* 40412ed1c7cSGregory Neil Shapiro ** We don't need to load the persistent data if we have data 4053299c2f1SGregory Neil Shapiro ** already loaded in the cache. 4063299c2f1SGregory Neil Shapiro */ 4073299c2f1SGregory Neil Shapiro 4083299c2f1SGregory Neil Shapiro if (mci->mci_host == NULL && 4093299c2f1SGregory Neil Shapiro (mci->mci_host = s->s_name) != NULL && 4103299c2f1SGregory Neil Shapiro !mci_load_persistent(mci)) 411c2aa98e2SPeter Wemm { 412c2aa98e2SPeter Wemm if (tTd(42, 2)) 41312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): lock failed\n", 4143299c2f1SGregory Neil Shapiro host, m->m_name); 415c2aa98e2SPeter Wemm mci->mci_exitstat = EX_TEMPFAIL; 416c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 417c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 418c2aa98e2SPeter Wemm return mci; 419c2aa98e2SPeter Wemm } 420c2aa98e2SPeter Wemm 421c2aa98e2SPeter Wemm if (tTd(42, 2)) 422c2aa98e2SPeter Wemm { 42312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n", 424c2aa98e2SPeter Wemm host, m->m_name, mci->mci_state, mci->mci_flags, 425c2aa98e2SPeter Wemm mci->mci_exitstat, mci->mci_errno); 426c2aa98e2SPeter Wemm } 427c2aa98e2SPeter Wemm 428c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_OPEN) 429c2aa98e2SPeter Wemm { 430c2aa98e2SPeter Wemm /* poke the connection to see if it's still alive */ 431c2aa98e2SPeter Wemm (void) smtpprobe(mci); 432c2aa98e2SPeter Wemm 433c2aa98e2SPeter Wemm /* reset the stored state in the event of a timeout */ 434c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 435c2aa98e2SPeter Wemm { 436c2aa98e2SPeter Wemm mci->mci_errno = 0; 437c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 438c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 439c2aa98e2SPeter Wemm } 440c2aa98e2SPeter Wemm else 441c2aa98e2SPeter Wemm { 44212ed1c7cSGregory Neil Shapiro /* get peer host address */ 443c2aa98e2SPeter Wemm /* (this should really be in the mci struct) */ 444951742c4SGregory Neil Shapiro SOCKADDR_LEN_T socklen = sizeof(CurHostAddr); 445c2aa98e2SPeter Wemm 44612ed1c7cSGregory Neil Shapiro (void) getpeername(sm_io_getinfo(mci->mci_in, 44712ed1c7cSGregory Neil Shapiro SM_IO_WHAT_FD, NULL), 448c2aa98e2SPeter Wemm (struct sockaddr *) &CurHostAddr, &socklen); 449c2aa98e2SPeter Wemm } 450c2aa98e2SPeter Wemm } 451c2aa98e2SPeter Wemm if (mci->mci_state == MCIS_CLOSED) 452c2aa98e2SPeter Wemm { 453c2aa98e2SPeter Wemm time_t now = curtime(); 454c2aa98e2SPeter Wemm 455c2aa98e2SPeter Wemm /* if this info is stale, ignore it */ 456320f00e7SGregory Neil Shapiro if (mci->mci_lastuse + MciInfoTimeout <= now) 457c2aa98e2SPeter Wemm { 458c2aa98e2SPeter Wemm mci->mci_lastuse = now; 459c2aa98e2SPeter Wemm mci->mci_errno = 0; 460c2aa98e2SPeter Wemm mci->mci_exitstat = EX_OK; 461c2aa98e2SPeter Wemm } 462*5b0945b5SGregory Neil Shapiro mci_clear(mci); 463c2aa98e2SPeter Wemm } 464c2aa98e2SPeter Wemm 465c2aa98e2SPeter Wemm return mci; 466c2aa98e2SPeter Wemm } 467dbda3744SGregory Neil Shapiro 468dbda3744SGregory Neil Shapiro /* 469dbda3744SGregory Neil Shapiro ** MCI_CLOSE -- (forcefully) close files used for a connection. 470dbda3744SGregory Neil Shapiro ** Note: this is a last resort, usually smtpquit() or endmailer() 471dbda3744SGregory Neil Shapiro ** should be used to close a connection. 472dbda3744SGregory Neil Shapiro ** 473dbda3744SGregory Neil Shapiro ** Parameters: 474dbda3744SGregory Neil Shapiro ** mci -- the connection to close. 475dbda3744SGregory Neil Shapiro ** where -- where has this been called? 476dbda3744SGregory Neil Shapiro ** 477dbda3744SGregory Neil Shapiro ** Returns: 478dbda3744SGregory Neil Shapiro ** none. 479dbda3744SGregory Neil Shapiro */ 480dbda3744SGregory Neil Shapiro 481dbda3744SGregory Neil Shapiro void 482dbda3744SGregory Neil Shapiro mci_close(mci, where) 483dbda3744SGregory Neil Shapiro MCI *mci; 484dbda3744SGregory Neil Shapiro char *where; 485dbda3744SGregory Neil Shapiro { 486dbda3744SGregory Neil Shapiro bool dumped; 487dbda3744SGregory Neil Shapiro 488dbda3744SGregory Neil Shapiro if (mci == NULL) 489dbda3744SGregory Neil Shapiro return; 490dbda3744SGregory Neil Shapiro dumped = false; 491dbda3744SGregory Neil Shapiro if (mci->mci_out != NULL) 492dbda3744SGregory Neil Shapiro { 493dbda3744SGregory Neil Shapiro if (tTd(56, 1)) 494dbda3744SGregory Neil Shapiro { 495dbda3744SGregory Neil Shapiro sm_dprintf("mci_close: mci_out!=NULL, where=%s\n", 496dbda3744SGregory Neil Shapiro where); 497dbda3744SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 498dbda3744SGregory Neil Shapiro dumped = true; 499dbda3744SGregory Neil Shapiro } 500dbda3744SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 501dbda3744SGregory Neil Shapiro mci->mci_out = NULL; 502dbda3744SGregory Neil Shapiro } 503dbda3744SGregory Neil Shapiro if (mci->mci_in != NULL) 504dbda3744SGregory Neil Shapiro { 505dbda3744SGregory Neil Shapiro if (tTd(56, 1)) 506dbda3744SGregory Neil Shapiro { 507dbda3744SGregory Neil Shapiro sm_dprintf("mci_close: mci_in!=NULL, where=%s\n", 508dbda3744SGregory Neil Shapiro where); 509dbda3744SGregory Neil Shapiro if (!dumped) 510dbda3744SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 511dbda3744SGregory Neil Shapiro } 512dbda3744SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 513dbda3744SGregory Neil Shapiro mci->mci_in = NULL; 514dbda3744SGregory Neil Shapiro } 515dbda3744SGregory Neil Shapiro mci->mci_state = MCIS_CLOSED; 516dbda3744SGregory Neil Shapiro } 517dbda3744SGregory Neil Shapiro 51812ed1c7cSGregory Neil Shapiro /* 51912ed1c7cSGregory Neil Shapiro ** MCI_NEW -- allocate new MCI structure 52012ed1c7cSGregory Neil Shapiro ** 52112ed1c7cSGregory Neil Shapiro ** Parameters: 52212ed1c7cSGregory Neil Shapiro ** rpool -- if non-NULL: allocate from that rpool. 52312ed1c7cSGregory Neil Shapiro ** 52412ed1c7cSGregory Neil Shapiro ** Returns: 52512ed1c7cSGregory Neil Shapiro ** mci (new). 52612ed1c7cSGregory Neil Shapiro */ 52712ed1c7cSGregory Neil Shapiro 52812ed1c7cSGregory Neil Shapiro MCI * 52912ed1c7cSGregory Neil Shapiro mci_new(rpool) 53012ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool; 53112ed1c7cSGregory Neil Shapiro { 53212ed1c7cSGregory Neil Shapiro register MCI *mci; 53312ed1c7cSGregory Neil Shapiro 53412ed1c7cSGregory Neil Shapiro if (rpool == NULL) 535951742c4SGregory Neil Shapiro mci = (MCI *) sm_malloc_x(sizeof(*mci)); 53612ed1c7cSGregory Neil Shapiro else 537951742c4SGregory Neil Shapiro mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof(*mci)); 538951742c4SGregory Neil Shapiro memset((char *) mci, '\0', sizeof(*mci)); 53912ed1c7cSGregory Neil Shapiro mci->mci_rpool = sm_rpool_new_x(NULL); 54012ed1c7cSGregory Neil Shapiro mci->mci_macro.mac_rpool = mci->mci_rpool; 54112ed1c7cSGregory Neil Shapiro return mci; 54212ed1c7cSGregory Neil Shapiro } 54312ed1c7cSGregory Neil Shapiro /* 5443299c2f1SGregory Neil Shapiro ** MCI_MATCH -- check connection cache for a particular host 54512ed1c7cSGregory Neil Shapiro ** 54612ed1c7cSGregory Neil Shapiro ** Parameters: 54712ed1c7cSGregory Neil Shapiro ** host -- host to look for. 54812ed1c7cSGregory Neil Shapiro ** m -- mailer. 54912ed1c7cSGregory Neil Shapiro ** 55012ed1c7cSGregory Neil Shapiro ** Returns: 55112ed1c7cSGregory Neil Shapiro ** true iff open connection exists. 5523299c2f1SGregory Neil Shapiro */ 5533299c2f1SGregory Neil Shapiro 5543299c2f1SGregory Neil Shapiro bool 5553299c2f1SGregory Neil Shapiro mci_match(host, m) 5563299c2f1SGregory Neil Shapiro char *host; 5573299c2f1SGregory Neil Shapiro MAILER *m; 5583299c2f1SGregory Neil Shapiro { 5593299c2f1SGregory Neil Shapiro register MCI *mci; 5603299c2f1SGregory Neil Shapiro register STAB *s; 5613299c2f1SGregory Neil Shapiro 562c46d91b7SGregory Neil Shapiro if (m->m_mno < 0 || m->m_mno > MAXMAILERS) 56312ed1c7cSGregory Neil Shapiro return false; 5643299c2f1SGregory Neil Shapiro s = stab(host, ST_MCI + m->m_mno, ST_FIND); 5653299c2f1SGregory Neil Shapiro if (s == NULL) 56612ed1c7cSGregory Neil Shapiro return false; 5673299c2f1SGregory Neil Shapiro 5683299c2f1SGregory Neil Shapiro mci = &s->s_mci; 56912ed1c7cSGregory Neil Shapiro return mci->mci_state == MCIS_OPEN; 5703299c2f1SGregory Neil Shapiro } 57112ed1c7cSGregory Neil Shapiro /* 572c2aa98e2SPeter Wemm ** MCI_SETSTAT -- set status codes in MCI structure. 573c2aa98e2SPeter Wemm ** 574c2aa98e2SPeter Wemm ** Parameters: 575c2aa98e2SPeter Wemm ** mci -- the MCI structure to set. 576c2aa98e2SPeter Wemm ** xstat -- the exit status code. 577c2aa98e2SPeter Wemm ** dstat -- the DSN status code. 578c2aa98e2SPeter Wemm ** rstat -- the SMTP status code. 579c2aa98e2SPeter Wemm ** 580c2aa98e2SPeter Wemm ** Returns: 581c2aa98e2SPeter Wemm ** none. 582c2aa98e2SPeter Wemm */ 583c2aa98e2SPeter Wemm 584c2aa98e2SPeter Wemm void 585c2aa98e2SPeter Wemm mci_setstat(mci, xstat, dstat, rstat) 586c2aa98e2SPeter Wemm MCI *mci; 587c2aa98e2SPeter Wemm int xstat; 588c2aa98e2SPeter Wemm char *dstat; 589c2aa98e2SPeter Wemm char *rstat; 590c2aa98e2SPeter Wemm { 591c2aa98e2SPeter Wemm /* protocol errors should never be interpreted as sticky */ 592c2aa98e2SPeter Wemm if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL) 593c2aa98e2SPeter Wemm mci->mci_exitstat = xstat; 594c2aa98e2SPeter Wemm 595*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_status); 59612ed1c7cSGregory Neil Shapiro if (dstat != NULL) 59712ed1c7cSGregory Neil Shapiro mci->mci_status = sm_strdup_x(dstat); 59812ed1c7cSGregory Neil Shapiro 599*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_rstatus); 600c2aa98e2SPeter Wemm if (rstat != NULL) 60112ed1c7cSGregory Neil Shapiro mci->mci_rstatus = sm_strdup_x(rstat); 602c2aa98e2SPeter Wemm } 60312ed1c7cSGregory Neil Shapiro /* 604c2aa98e2SPeter Wemm ** MCI_DUMP -- dump the contents of an MCI structure. 605c2aa98e2SPeter Wemm ** 606c2aa98e2SPeter Wemm ** Parameters: 607bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 608c2aa98e2SPeter Wemm ** mci -- the MCI structure to dump. 609c2aa98e2SPeter Wemm ** 610c2aa98e2SPeter Wemm ** Returns: 611c2aa98e2SPeter Wemm ** none. 612c2aa98e2SPeter Wemm ** 613c2aa98e2SPeter Wemm ** Side Effects: 614c2aa98e2SPeter Wemm ** none. 615c2aa98e2SPeter Wemm */ 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm struct mcifbits 618c2aa98e2SPeter Wemm { 619c2aa98e2SPeter Wemm int mcif_bit; /* flag bit */ 620c2aa98e2SPeter Wemm char *mcif_name; /* flag name */ 621c2aa98e2SPeter Wemm }; 6223299c2f1SGregory Neil Shapiro static struct mcifbits MciFlags[] = 623c2aa98e2SPeter Wemm { 624c2aa98e2SPeter Wemm { MCIF_CACHED, "CACHED" }, 625c2aa98e2SPeter Wemm { MCIF_ESMTP, "ESMTP" }, 626c2aa98e2SPeter Wemm { MCIF_EXPN, "EXPN" }, 627c2aa98e2SPeter Wemm { MCIF_SIZE, "SIZE" }, 628c2aa98e2SPeter Wemm { MCIF_8BITMIME, "8BITMIME" }, 629c2aa98e2SPeter Wemm { MCIF_7BIT, "7BIT" }, 630c2aa98e2SPeter Wemm { MCIF_INHEADER, "INHEADER" }, 631c2aa98e2SPeter Wemm { MCIF_CVT8TO7, "CVT8TO7" }, 632c2aa98e2SPeter Wemm { MCIF_DSN, "DSN" }, 633c2aa98e2SPeter Wemm { MCIF_8BITOK, "8BITOK" }, 634c2aa98e2SPeter Wemm { MCIF_CVT7TO8, "CVT7TO8" }, 635c2aa98e2SPeter Wemm { MCIF_INMIME, "INMIME" }, 63612ed1c7cSGregory Neil Shapiro { MCIF_AUTH, "AUTH" }, 6376f9c8e5bSGregory Neil Shapiro { MCIF_AUTH2, "AUTH2" }, 63812ed1c7cSGregory Neil Shapiro { MCIF_AUTHACT, "AUTHACT" }, 63912ed1c7cSGregory Neil Shapiro { MCIF_ENHSTAT, "ENHSTAT" }, 64012ed1c7cSGregory Neil Shapiro { MCIF_PIPELINED, "PIPELINED" }, 641*5b0945b5SGregory Neil Shapiro { MCIF_VERB, "VERB" }, 64212ed1c7cSGregory Neil Shapiro #if STARTTLS 64312ed1c7cSGregory Neil Shapiro { MCIF_TLS, "TLS" }, 64412ed1c7cSGregory Neil Shapiro { MCIF_TLSACT, "TLSACT" }, 645*5b0945b5SGregory Neil Shapiro #endif 64612ed1c7cSGregory Neil Shapiro { MCIF_DLVR_BY, "DLVR_BY" }, 647*5b0945b5SGregory Neil Shapiro { MCIF_INLONGLINE, "INLONGLINE" }, 648*5b0945b5SGregory Neil Shapiro { MCIF_NOTSTICKY, "NOTSTICKY" }, 649c2aa98e2SPeter Wemm { 0, NULL } 650c2aa98e2SPeter Wemm }; 651c2aa98e2SPeter Wemm 652c2aa98e2SPeter Wemm void 653bfb62e91SGregory Neil Shapiro mci_dump(fp, mci, logit) 654bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 655c2aa98e2SPeter Wemm register MCI *mci; 656c2aa98e2SPeter Wemm bool logit; 657c2aa98e2SPeter Wemm { 658c2aa98e2SPeter Wemm register char *p; 659c2aa98e2SPeter Wemm char *sep; 660c2aa98e2SPeter Wemm char buf[4000]; 661c2aa98e2SPeter Wemm 662c2aa98e2SPeter Wemm sep = logit ? " " : "\n\t"; 663c2aa98e2SPeter Wemm p = buf; 664*5b0945b5SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", (void *)mci); 665c2aa98e2SPeter Wemm p += strlen(p); 666c2aa98e2SPeter Wemm if (mci == NULL) 667c2aa98e2SPeter Wemm { 66812ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL"); 669c2aa98e2SPeter Wemm goto printit; 670c2aa98e2SPeter Wemm } 67112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags); 672c2aa98e2SPeter Wemm p += strlen(p); 6737660b554SGregory Neil Shapiro 6747660b554SGregory Neil Shapiro /* 6757660b554SGregory Neil Shapiro ** The following check is just for paranoia. It protects the 6767660b554SGregory Neil Shapiro ** assignment in the if() clause. If there's not some minimum 6777660b554SGregory Neil Shapiro ** amount of space we can stop right now. The check will not 6787660b554SGregory Neil Shapiro ** trigger as long as sizeof(buf)=4000. 6797660b554SGregory Neil Shapiro */ 6807660b554SGregory Neil Shapiro 6817660b554SGregory Neil Shapiro if (p >= buf + sizeof(buf) - 4) 6827660b554SGregory Neil Shapiro goto printit; 683c2aa98e2SPeter Wemm if (mci->mci_flags != 0) 684c2aa98e2SPeter Wemm { 685c2aa98e2SPeter Wemm struct mcifbits *f; 686c2aa98e2SPeter Wemm 6877660b554SGregory Neil Shapiro *p++ = '<'; /* protected above */ 688c2aa98e2SPeter Wemm for (f = MciFlags; f->mcif_bit != 0; f++) 689c2aa98e2SPeter Wemm { 690c2aa98e2SPeter Wemm if (!bitset(f->mcif_bit, mci->mci_flags)) 691c2aa98e2SPeter Wemm continue; 69212ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2, 69312ed1c7cSGregory Neil Shapiro f->mcif_name, ","); 694c2aa98e2SPeter Wemm p += strlen(p); 695c2aa98e2SPeter Wemm } 696c2aa98e2SPeter Wemm p[-1] = '>'; 697c2aa98e2SPeter Wemm } 69812ed1c7cSGregory Neil Shapiro 69912ed1c7cSGregory Neil Shapiro /* Note: sm_snprintf() takes care of NULL arguments for %s */ 70012ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 701c2aa98e2SPeter Wemm ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", 702c2aa98e2SPeter Wemm sep, mci->mci_errno, mci->mci_herrno, 7033299c2f1SGregory Neil Shapiro mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep); 704c2aa98e2SPeter Wemm p += strlen(p); 70512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 706c2aa98e2SPeter Wemm "maxsize=%ld, phase=%s, mailer=%s,%s", 70712ed1c7cSGregory Neil Shapiro mci->mci_maxsize, mci->mci_phase, 708c2aa98e2SPeter Wemm mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name, 709c2aa98e2SPeter Wemm sep); 710c2aa98e2SPeter Wemm p += strlen(p); 71112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 712c2aa98e2SPeter Wemm "status=%s, rstatus=%s,%s", 71312ed1c7cSGregory Neil Shapiro mci->mci_status, mci->mci_rstatus, sep); 714c2aa98e2SPeter Wemm p += strlen(p); 71512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 716c2aa98e2SPeter Wemm "host=%s, lastuse=%s", 71712ed1c7cSGregory Neil Shapiro mci->mci_host, ctime(&mci->mci_lastuse)); 718c2aa98e2SPeter Wemm printit: 719c2aa98e2SPeter Wemm if (logit) 720c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); 721c2aa98e2SPeter Wemm else 722bfb62e91SGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf); 723c2aa98e2SPeter Wemm } 72412ed1c7cSGregory Neil Shapiro /* 725c2aa98e2SPeter Wemm ** MCI_DUMP_ALL -- print the entire MCI cache 726c2aa98e2SPeter Wemm ** 727c2aa98e2SPeter Wemm ** Parameters: 728bfb62e91SGregory Neil Shapiro ** fp -- output file pointer 729c2aa98e2SPeter Wemm ** logit -- if set, log the result instead of printing 730c2aa98e2SPeter Wemm ** to stdout. 731c2aa98e2SPeter Wemm ** 732c2aa98e2SPeter Wemm ** Returns: 733c2aa98e2SPeter Wemm ** none. 734c2aa98e2SPeter Wemm */ 735c2aa98e2SPeter Wemm 736c2aa98e2SPeter Wemm void 737bfb62e91SGregory Neil Shapiro mci_dump_all(fp, logit) 738bfb62e91SGregory Neil Shapiro SM_FILE_T *fp; 739c2aa98e2SPeter Wemm bool logit; 740c2aa98e2SPeter Wemm { 741c2aa98e2SPeter Wemm register int i; 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm if (MciCache == NULL) 744c2aa98e2SPeter Wemm return; 745c2aa98e2SPeter Wemm 746c2aa98e2SPeter Wemm for (i = 0; i < MaxMciCache; i++) 747bfb62e91SGregory Neil Shapiro mci_dump(fp, MciCache[i], logit); 748c2aa98e2SPeter Wemm } 74912ed1c7cSGregory Neil Shapiro /* 750c2aa98e2SPeter Wemm ** MCI_LOCK_HOST -- Lock host while sending. 751c2aa98e2SPeter Wemm ** 752c2aa98e2SPeter Wemm ** If we are contacting a host, we'll need to 753c2aa98e2SPeter Wemm ** update the status information in the host status 754c2aa98e2SPeter Wemm ** file, and if we want to do that, we ought to have 755c2aa98e2SPeter Wemm ** locked it. This has the (according to some) 756c2aa98e2SPeter Wemm ** desirable effect of serializing connectivity with 75712ed1c7cSGregory Neil Shapiro ** remote hosts -- i.e.: one connection to a given 758c2aa98e2SPeter Wemm ** host at a time. 759c2aa98e2SPeter Wemm ** 760c2aa98e2SPeter Wemm ** Parameters: 761c2aa98e2SPeter Wemm ** mci -- containing the host we want to lock. 762c2aa98e2SPeter Wemm ** 763c2aa98e2SPeter Wemm ** Returns: 764c2aa98e2SPeter Wemm ** EX_OK -- got the lock. 765c2aa98e2SPeter Wemm ** EX_TEMPFAIL -- didn't get the lock. 766c2aa98e2SPeter Wemm */ 767c2aa98e2SPeter Wemm 768c2aa98e2SPeter Wemm int 769c2aa98e2SPeter Wemm mci_lock_host(mci) 770c2aa98e2SPeter Wemm MCI *mci; 771c2aa98e2SPeter Wemm { 772c2aa98e2SPeter Wemm if (mci == NULL) 773c2aa98e2SPeter Wemm { 774c2aa98e2SPeter Wemm if (tTd(56, 1)) 77512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: NULL mci\n"); 776c2aa98e2SPeter Wemm return EX_OK; 777c2aa98e2SPeter Wemm } 778c2aa98e2SPeter Wemm 779c2aa98e2SPeter Wemm if (!SingleThreadDelivery) 780c2aa98e2SPeter Wemm return EX_OK; 781c2aa98e2SPeter Wemm 782c2aa98e2SPeter Wemm return mci_lock_host_statfile(mci); 783c2aa98e2SPeter Wemm } 784c2aa98e2SPeter Wemm 7853299c2f1SGregory Neil Shapiro static int 786c2aa98e2SPeter Wemm mci_lock_host_statfile(mci) 787c2aa98e2SPeter Wemm MCI *mci; 788c2aa98e2SPeter Wemm { 7893299c2f1SGregory Neil Shapiro int save_errno = errno; 790c2aa98e2SPeter Wemm int retVal = EX_OK; 79188ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 792c2aa98e2SPeter Wemm 793c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 794c2aa98e2SPeter Wemm return EX_OK; 795c2aa98e2SPeter Wemm 796c2aa98e2SPeter Wemm if (tTd(56, 2)) 79712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: attempting to lock %s\n", 798c2aa98e2SPeter Wemm mci->mci_host); 799c2aa98e2SPeter Wemm 800951742c4SGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname), 80112ed1c7cSGregory Neil Shapiro true) < 0) 802c2aa98e2SPeter Wemm { 803c2aa98e2SPeter Wemm /* of course this should never happen */ 804c2aa98e2SPeter Wemm if (tTd(56, 2)) 80512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Failed to generate host path for %s\n", 806c2aa98e2SPeter Wemm mci->mci_host); 807c2aa98e2SPeter Wemm 808c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 809c2aa98e2SPeter Wemm goto cleanup; 810c2aa98e2SPeter Wemm } 811c2aa98e2SPeter Wemm 812c2aa98e2SPeter Wemm mci->mci_statfile = safefopen(fname, O_RDWR, FileMode, 813c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT); 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 816c2aa98e2SPeter Wemm { 81712ed1c7cSGregory Neil Shapiro syserr("mci_lock_host: cannot create host lock file %s", fname); 818c2aa98e2SPeter Wemm goto cleanup; 819c2aa98e2SPeter Wemm } 820c2aa98e2SPeter Wemm 82112ed1c7cSGregory Neil Shapiro if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 82212ed1c7cSGregory Neil Shapiro fname, "", LOCK_EX|LOCK_NB)) 823c2aa98e2SPeter Wemm { 824c2aa98e2SPeter Wemm if (tTd(56, 2)) 82512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: couldn't get lock on %s\n", 826c2aa98e2SPeter Wemm fname); 82712ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 828c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 829c2aa98e2SPeter Wemm retVal = EX_TEMPFAIL; 830c2aa98e2SPeter Wemm goto cleanup; 831c2aa98e2SPeter Wemm } 832c2aa98e2SPeter Wemm 833c2aa98e2SPeter Wemm if (tTd(56, 12) && mci->mci_statfile != NULL) 83412ed1c7cSGregory Neil Shapiro sm_dprintf("mci_lock_host: Sanity check -- lock is good\n"); 835c2aa98e2SPeter Wemm 836c2aa98e2SPeter Wemm cleanup: 8373299c2f1SGregory Neil Shapiro errno = save_errno; 838c2aa98e2SPeter Wemm return retVal; 839c2aa98e2SPeter Wemm } 84012ed1c7cSGregory Neil Shapiro /* 841c2aa98e2SPeter Wemm ** MCI_UNLOCK_HOST -- unlock host 842c2aa98e2SPeter Wemm ** 843c2aa98e2SPeter Wemm ** Clean up the lock on a host, close the file, let 844c2aa98e2SPeter Wemm ** someone else use it. 845c2aa98e2SPeter Wemm ** 846c2aa98e2SPeter Wemm ** Parameters: 847c2aa98e2SPeter Wemm ** mci -- us. 848c2aa98e2SPeter Wemm ** 849c2aa98e2SPeter Wemm ** Returns: 850c2aa98e2SPeter Wemm ** nothing. 851c2aa98e2SPeter Wemm */ 852c2aa98e2SPeter Wemm 853c2aa98e2SPeter Wemm void 854c2aa98e2SPeter Wemm mci_unlock_host(mci) 855c2aa98e2SPeter Wemm MCI *mci; 856c2aa98e2SPeter Wemm { 8573299c2f1SGregory Neil Shapiro int save_errno = errno; 858c2aa98e2SPeter Wemm 859c2aa98e2SPeter Wemm if (mci == NULL) 860c2aa98e2SPeter Wemm { 861c2aa98e2SPeter Wemm if (tTd(56, 1)) 86212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: NULL mci\n"); 863c2aa98e2SPeter Wemm return; 864c2aa98e2SPeter Wemm } 865c2aa98e2SPeter Wemm 866c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 867c2aa98e2SPeter Wemm return; 868c2aa98e2SPeter Wemm 869c2aa98e2SPeter Wemm if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) 870c2aa98e2SPeter Wemm { 871c2aa98e2SPeter Wemm if (tTd(56, 1)) 87212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: stat file already locked\n"); 873c2aa98e2SPeter Wemm } 874c2aa98e2SPeter Wemm else 875c2aa98e2SPeter Wemm { 876c2aa98e2SPeter Wemm if (tTd(56, 2)) 87712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_unlock_host: store prior to unlock\n"); 878c2aa98e2SPeter Wemm mci_store_persistent(mci); 879c2aa98e2SPeter Wemm } 880c2aa98e2SPeter Wemm 881c2aa98e2SPeter Wemm if (mci->mci_statfile != NULL) 882c2aa98e2SPeter Wemm { 88312ed1c7cSGregory Neil Shapiro (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT); 884c2aa98e2SPeter Wemm mci->mci_statfile = NULL; 885c2aa98e2SPeter Wemm } 886c2aa98e2SPeter Wemm 8873299c2f1SGregory Neil Shapiro errno = save_errno; 888c2aa98e2SPeter Wemm } 88912ed1c7cSGregory Neil Shapiro /* 890c2aa98e2SPeter Wemm ** MCI_LOAD_PERSISTENT -- load persistent host info 891c2aa98e2SPeter Wemm ** 892c2aa98e2SPeter Wemm ** Load information about host that is kept 893c2aa98e2SPeter Wemm ** in common for all running sendmails. 894c2aa98e2SPeter Wemm ** 895c2aa98e2SPeter Wemm ** Parameters: 89612ed1c7cSGregory Neil Shapiro ** mci -- the host/connection to load persistent info for. 897c2aa98e2SPeter Wemm ** 898c2aa98e2SPeter Wemm ** Returns: 89912ed1c7cSGregory Neil Shapiro ** true -- lock was successful 90012ed1c7cSGregory Neil Shapiro ** false -- lock failed 901c2aa98e2SPeter Wemm */ 902c2aa98e2SPeter Wemm 9033299c2f1SGregory Neil Shapiro static bool 904c2aa98e2SPeter Wemm mci_load_persistent(mci) 905c2aa98e2SPeter Wemm MCI *mci; 906c2aa98e2SPeter Wemm { 9073299c2f1SGregory Neil Shapiro int save_errno = errno; 90812ed1c7cSGregory Neil Shapiro bool locked = true; 90912ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 91088ad41d4SGregory Neil Shapiro char fname[MAXPATHLEN]; 911c2aa98e2SPeter Wemm 912c2aa98e2SPeter Wemm if (mci == NULL) 913c2aa98e2SPeter Wemm { 914c2aa98e2SPeter Wemm if (tTd(56, 1)) 91512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: NULL mci\n"); 91612ed1c7cSGregory Neil Shapiro return true; 917c2aa98e2SPeter Wemm } 918c2aa98e2SPeter Wemm 919c2aa98e2SPeter Wemm if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) 92012ed1c7cSGregory Neil Shapiro return true; 921c2aa98e2SPeter Wemm 922c2aa98e2SPeter Wemm /* Already have the persistent information in memory */ 923c2aa98e2SPeter Wemm if (SingleThreadDelivery && mci->mci_statfile != NULL) 92412ed1c7cSGregory Neil Shapiro return true; 925c2aa98e2SPeter Wemm 926c2aa98e2SPeter Wemm if (tTd(56, 1)) 92712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n", 928c2aa98e2SPeter Wemm mci->mci_host); 929c2aa98e2SPeter Wemm 930951742c4SGregory Neil Shapiro if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname), 93112ed1c7cSGregory Neil Shapiro false) < 0) 932c2aa98e2SPeter Wemm { 933c2aa98e2SPeter Wemm /* Not much we can do if the file isn't there... */ 934c2aa98e2SPeter Wemm if (tTd(56, 1)) 93512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: Couldn't generate host path\n"); 936c2aa98e2SPeter Wemm goto cleanup; 937c2aa98e2SPeter Wemm } 938c2aa98e2SPeter Wemm 939c2aa98e2SPeter Wemm fp = safefopen(fname, O_RDONLY, FileMode, 940c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 941c2aa98e2SPeter Wemm if (fp == NULL) 942c2aa98e2SPeter Wemm { 943c2aa98e2SPeter Wemm /* I can't think of any reason this should ever happen */ 944c2aa98e2SPeter Wemm if (tTd(56, 1)) 94512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_load_persistent: open(%s): %s\n", 94612ed1c7cSGregory Neil Shapiro fname, sm_errstring(errno)); 947c2aa98e2SPeter Wemm goto cleanup; 948c2aa98e2SPeter Wemm } 949c2aa98e2SPeter Wemm 950c2aa98e2SPeter Wemm FileName = fname; 95112ed1c7cSGregory Neil Shapiro locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "", 95212ed1c7cSGregory Neil Shapiro LOCK_SH|LOCK_NB); 953c2aa98e2SPeter Wemm if (locked) 9543299c2f1SGregory Neil Shapiro { 9553299c2f1SGregory Neil Shapiro (void) mci_read_persistent(fp, mci); 95612ed1c7cSGregory Neil Shapiro (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, 95712ed1c7cSGregory Neil Shapiro "", LOCK_UN); 9583299c2f1SGregory Neil Shapiro } 9593299c2f1SGregory Neil Shapiro FileName = NULL; 96012ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 961c2aa98e2SPeter Wemm 962c2aa98e2SPeter Wemm cleanup: 9633299c2f1SGregory Neil Shapiro errno = save_errno; 964c2aa98e2SPeter Wemm return locked; 965c2aa98e2SPeter Wemm } 96612ed1c7cSGregory Neil Shapiro /* 967c2aa98e2SPeter Wemm ** MCI_READ_PERSISTENT -- read persistent host status file 968c2aa98e2SPeter Wemm ** 969c2aa98e2SPeter Wemm ** Parameters: 970c2aa98e2SPeter Wemm ** fp -- the file pointer to read. 971c2aa98e2SPeter Wemm ** mci -- the pointer to fill in. 972c2aa98e2SPeter Wemm ** 973c2aa98e2SPeter Wemm ** Returns: 974c2aa98e2SPeter Wemm ** -1 -- if the file was corrupt. 975c2aa98e2SPeter Wemm ** 0 -- otherwise. 976c2aa98e2SPeter Wemm ** 977c2aa98e2SPeter Wemm ** Warning: 978c2aa98e2SPeter Wemm ** This code makes the assumption that this data 979c2aa98e2SPeter Wemm ** will be read in an atomic fashion, and that the data 980c2aa98e2SPeter Wemm ** was written in an atomic fashion. Any other functioning 981c2aa98e2SPeter Wemm ** may lead to some form of insanity. This should be 982c2aa98e2SPeter Wemm ** perfectly safe due to underlying stdio buffering. 983c2aa98e2SPeter Wemm */ 984c2aa98e2SPeter Wemm 9853299c2f1SGregory Neil Shapiro static int 986c2aa98e2SPeter Wemm mci_read_persistent(fp, mci) 98712ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 988c2aa98e2SPeter Wemm register MCI *mci; 989c2aa98e2SPeter Wemm { 990c2aa98e2SPeter Wemm int ver; 991c2aa98e2SPeter Wemm register char *p; 992c2aa98e2SPeter Wemm int saveLineNumber = LineNumber; 993c2aa98e2SPeter Wemm char buf[MAXLINE]; 994c2aa98e2SPeter Wemm 995c2aa98e2SPeter Wemm if (fp == NULL) 996355d91e3SGregory Neil Shapiro { 997c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL fp"); 998355d91e3SGregory Neil Shapiro /* NOTREACHED */ 999355d91e3SGregory Neil Shapiro return -1; 1000355d91e3SGregory Neil Shapiro } 1001c2aa98e2SPeter Wemm if (mci == NULL) 1002355d91e3SGregory Neil Shapiro { 1003c2aa98e2SPeter Wemm syserr("mci_read_persistent: NULL mci"); 1004355d91e3SGregory Neil Shapiro /* NOTREACHED */ 1005355d91e3SGregory Neil Shapiro return -1; 1006355d91e3SGregory Neil Shapiro } 1007c2aa98e2SPeter Wemm if (tTd(56, 93)) 1008c2aa98e2SPeter Wemm { 100912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_read_persistent: fp=%lx, mci=", 101012ed1c7cSGregory Neil Shapiro (unsigned long) fp); 1011c2aa98e2SPeter Wemm } 1012c2aa98e2SPeter Wemm 1013*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_status); 1014*5b0945b5SGregory Neil Shapiro SM_FREE(mci->mci_rstatus); 1015c2aa98e2SPeter Wemm 101612ed1c7cSGregory Neil Shapiro sm_io_rewind(fp, SM_TIME_DEFAULT); 1017c2aa98e2SPeter Wemm ver = -1; 1018c2aa98e2SPeter Wemm LineNumber = 0; 1019552d4955SGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0) 1020c2aa98e2SPeter Wemm { 1021c2aa98e2SPeter Wemm LineNumber++; 1022c2aa98e2SPeter Wemm p = strchr(buf, '\n'); 1023c2aa98e2SPeter Wemm if (p != NULL) 1024c2aa98e2SPeter Wemm *p = '\0'; 1025c2aa98e2SPeter Wemm switch (buf[0]) 1026c2aa98e2SPeter Wemm { 1027c2aa98e2SPeter Wemm case 'V': /* version stamp */ 1028c2aa98e2SPeter Wemm ver = atoi(&buf[1]); 1029c2aa98e2SPeter Wemm if (ver < 0 || ver > 0) 1030c2aa98e2SPeter Wemm syserr("Unknown host status version %d: %d max", 1031c2aa98e2SPeter Wemm ver, 0); 1032c2aa98e2SPeter Wemm break; 1033c2aa98e2SPeter Wemm 1034c2aa98e2SPeter Wemm case 'E': /* UNIX error number */ 1035c2aa98e2SPeter Wemm mci->mci_errno = atoi(&buf[1]); 1036c2aa98e2SPeter Wemm break; 1037c2aa98e2SPeter Wemm 1038c2aa98e2SPeter Wemm case 'H': /* DNS error number */ 1039c2aa98e2SPeter Wemm mci->mci_herrno = atoi(&buf[1]); 1040c2aa98e2SPeter Wemm break; 1041c2aa98e2SPeter Wemm 1042c2aa98e2SPeter Wemm case 'S': /* UNIX exit status */ 1043c2aa98e2SPeter Wemm mci->mci_exitstat = atoi(&buf[1]); 1044c2aa98e2SPeter Wemm break; 1045c2aa98e2SPeter Wemm 1046c2aa98e2SPeter Wemm case 'D': /* DSN status */ 1047c2aa98e2SPeter Wemm mci->mci_status = newstr(&buf[1]); 1048c2aa98e2SPeter Wemm break; 1049c2aa98e2SPeter Wemm 1050c2aa98e2SPeter Wemm case 'R': /* SMTP status */ 1051c2aa98e2SPeter Wemm mci->mci_rstatus = newstr(&buf[1]); 1052c2aa98e2SPeter Wemm break; 1053c2aa98e2SPeter Wemm 1054c2aa98e2SPeter Wemm case 'U': /* last usage time */ 1055c2aa98e2SPeter Wemm mci->mci_lastuse = atol(&buf[1]); 1056c2aa98e2SPeter Wemm break; 1057c2aa98e2SPeter Wemm 1058c2aa98e2SPeter Wemm case '.': /* end of file */ 105912ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 1060bfb62e91SGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 1061c2aa98e2SPeter Wemm return 0; 1062c2aa98e2SPeter Wemm 1063c2aa98e2SPeter Wemm default: 1064c2aa98e2SPeter Wemm sm_syslog(LOG_CRIT, NOQID, 1065c2aa98e2SPeter Wemm "%s: line %d: Unknown host status line \"%s\"", 1066c2aa98e2SPeter Wemm FileName == NULL ? mci->mci_host : FileName, 1067c2aa98e2SPeter Wemm LineNumber, buf); 1068c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 1069c2aa98e2SPeter Wemm return -1; 1070c2aa98e2SPeter Wemm } 1071c2aa98e2SPeter Wemm } 1072c2aa98e2SPeter Wemm LineNumber = saveLineNumber; 107312ed1c7cSGregory Neil Shapiro if (tTd(56, 93)) 107412ed1c7cSGregory Neil Shapiro sm_dprintf("incomplete (missing dot for EOF)\n"); 1075c2aa98e2SPeter Wemm if (ver < 0) 1076c2aa98e2SPeter Wemm return -1; 1077c2aa98e2SPeter Wemm return 0; 1078c2aa98e2SPeter Wemm } 107912ed1c7cSGregory Neil Shapiro /* 1080c2aa98e2SPeter Wemm ** MCI_STORE_PERSISTENT -- Store persistent MCI information 1081c2aa98e2SPeter Wemm ** 1082c2aa98e2SPeter Wemm ** Store information about host that is kept 1083c2aa98e2SPeter Wemm ** in common for all running sendmails. 1084c2aa98e2SPeter Wemm ** 1085c2aa98e2SPeter Wemm ** Parameters: 1086c2aa98e2SPeter Wemm ** mci -- the host/connection to store persistent info for. 1087c2aa98e2SPeter Wemm ** 1088c2aa98e2SPeter Wemm ** Returns: 1089c2aa98e2SPeter Wemm ** none. 1090c2aa98e2SPeter Wemm */ 1091c2aa98e2SPeter Wemm 1092c2aa98e2SPeter Wemm void 1093c2aa98e2SPeter Wemm mci_store_persistent(mci) 1094c2aa98e2SPeter Wemm MCI *mci; 1095c2aa98e2SPeter Wemm { 10963299c2f1SGregory Neil Shapiro int save_errno = errno; 1097c2aa98e2SPeter Wemm 1098c2aa98e2SPeter Wemm if (mci == NULL) 1099c2aa98e2SPeter Wemm { 1100c2aa98e2SPeter Wemm if (tTd(56, 1)) 110112ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: NULL mci\n"); 1102c2aa98e2SPeter Wemm return; 1103c2aa98e2SPeter Wemm } 1104c2aa98e2SPeter Wemm 1105c2aa98e2SPeter Wemm if (HostStatDir == NULL || mci->mci_host == NULL) 1106c2aa98e2SPeter Wemm return; 1107c2aa98e2SPeter Wemm 1108c2aa98e2SPeter Wemm if (tTd(56, 1)) 110912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: Storing information for %s\n", 1110c2aa98e2SPeter Wemm mci->mci_host); 1111c2aa98e2SPeter Wemm 1112c2aa98e2SPeter Wemm if (mci->mci_statfile == NULL) 1113c2aa98e2SPeter Wemm { 1114c2aa98e2SPeter Wemm if (tTd(56, 1)) 111512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_store_persistent: no statfile\n"); 1116c2aa98e2SPeter Wemm return; 1117c2aa98e2SPeter Wemm } 1118c2aa98e2SPeter Wemm 111912ed1c7cSGregory Neil Shapiro sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT); 1120c2aa98e2SPeter Wemm #if !NOFTRUNCATE 112112ed1c7cSGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL), 112212ed1c7cSGregory Neil Shapiro (off_t) 0); 1123*5b0945b5SGregory Neil Shapiro #endif 1124c2aa98e2SPeter Wemm 112512ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n"); 112612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n", 112712ed1c7cSGregory Neil Shapiro mci->mci_errno); 112812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n", 112912ed1c7cSGregory Neil Shapiro mci->mci_herrno); 113012ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n", 113112ed1c7cSGregory Neil Shapiro mci->mci_exitstat); 1132c2aa98e2SPeter Wemm if (mci->mci_status != NULL) 113312ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 113412ed1c7cSGregory Neil Shapiro "D%.80s\n", 113512ed1c7cSGregory Neil Shapiro denlstring(mci->mci_status, true, false)); 1136c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 113712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, 113812ed1c7cSGregory Neil Shapiro "R%.80s\n", 113912ed1c7cSGregory Neil Shapiro denlstring(mci->mci_rstatus, true, false)); 114012ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n", 114112ed1c7cSGregory Neil Shapiro (long)(mci->mci_lastuse)); 114212ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n"); 1143c2aa98e2SPeter Wemm 114412ed1c7cSGregory Neil Shapiro (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT); 1145c2aa98e2SPeter Wemm 11463299c2f1SGregory Neil Shapiro errno = save_errno; 1147c2aa98e2SPeter Wemm return; 1148c2aa98e2SPeter Wemm } 114912ed1c7cSGregory Neil Shapiro /* 1150c2aa98e2SPeter Wemm ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree 1151c2aa98e2SPeter Wemm ** 1152c2aa98e2SPeter Wemm ** Recursively find all the mci host files in `pathname'. Default to 1153c2aa98e2SPeter Wemm ** main host status directory if no path is provided. 1154c2aa98e2SPeter Wemm ** Call (*action)(pathname, host) for each file found. 1155c2aa98e2SPeter Wemm ** 1156c2aa98e2SPeter Wemm ** Note: all information is collected in a list before it is processed. 1157c2aa98e2SPeter Wemm ** This may not be the best way to do it, but it seems safest, since 1158c2aa98e2SPeter Wemm ** the file system would be touched while we are attempting to traverse 1159c2aa98e2SPeter Wemm ** the directory tree otherwise (during purges). 1160c2aa98e2SPeter Wemm ** 1161c2aa98e2SPeter Wemm ** Parameters: 1162c2aa98e2SPeter Wemm ** action -- function to call on each node. If returns < 0, 1163c2aa98e2SPeter Wemm ** return immediately. 1164c2aa98e2SPeter Wemm ** pathname -- root of tree. If null, use main host status 1165c2aa98e2SPeter Wemm ** directory. 1166c2aa98e2SPeter Wemm ** 1167c2aa98e2SPeter Wemm ** Returns: 1168c2aa98e2SPeter Wemm ** < 0 -- if any action routine returns a negative value, that 1169c2aa98e2SPeter Wemm ** value is returned. 1170c2aa98e2SPeter Wemm ** 0 -- if we successfully went to completion. 11713299c2f1SGregory Neil Shapiro ** > 0 -- return status from action() 1172c2aa98e2SPeter Wemm */ 1173c2aa98e2SPeter Wemm 1174c2aa98e2SPeter Wemm int 1175c2aa98e2SPeter Wemm mci_traverse_persistent(action, pathname) 1176684b2a5fSGregory Neil Shapiro int (*action)__P((char *, char *)); 1177c2aa98e2SPeter Wemm char *pathname; 1178c2aa98e2SPeter Wemm { 1179c2aa98e2SPeter Wemm struct stat statbuf; 1180c2aa98e2SPeter Wemm DIR *d; 1181c2aa98e2SPeter Wemm int ret; 1182c2aa98e2SPeter Wemm 1183c2aa98e2SPeter Wemm if (pathname == NULL) 1184c2aa98e2SPeter Wemm pathname = HostStatDir; 1185c2aa98e2SPeter Wemm if (pathname == NULL) 1186c2aa98e2SPeter Wemm return -1; 1187c2aa98e2SPeter Wemm 1188c2aa98e2SPeter Wemm if (tTd(56, 1)) 118912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: pathname is %s\n", pathname); 1190c2aa98e2SPeter Wemm 1191c2aa98e2SPeter Wemm ret = stat(pathname, &statbuf); 1192c2aa98e2SPeter Wemm if (ret < 0) 1193c2aa98e2SPeter Wemm { 1194c2aa98e2SPeter Wemm if (tTd(56, 2)) 119512ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: Failed to stat %s: %s\n", 119612ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1197c2aa98e2SPeter Wemm return ret; 1198c2aa98e2SPeter Wemm } 1199c2aa98e2SPeter Wemm if (S_ISDIR(statbuf.st_mode)) 1200c2aa98e2SPeter Wemm { 12013299c2f1SGregory Neil Shapiro bool leftone, removedone; 120212ed1c7cSGregory Neil Shapiro size_t len; 120312ed1c7cSGregory Neil Shapiro char *newptr; 120412ed1c7cSGregory Neil Shapiro struct dirent *e; 120588ad41d4SGregory Neil Shapiro char newpath[MAXPATHLEN]; 1206567a2fc9SGregory Neil Shapiro #if MAXPATHLEN <= MAXNAMLEN - 3 1207567a2fc9SGregory Neil Shapiro ERROR "MAXPATHLEN <= MAXNAMLEN - 3" 1208*5b0945b5SGregory Neil Shapiro #endif 1209c2aa98e2SPeter Wemm 1210c2aa98e2SPeter Wemm if ((d = opendir(pathname)) == NULL) 1211c2aa98e2SPeter Wemm { 1212c2aa98e2SPeter Wemm if (tTd(56, 2)) 121312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: opendir %s: %s\n", 121412ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1215c2aa98e2SPeter Wemm return -1; 1216c2aa98e2SPeter Wemm } 1217e3793f76SGregory Neil Shapiro 1218e3793f76SGregory Neil Shapiro /* 1219e3793f76SGregory Neil Shapiro ** Reserve space for trailing '/', at least one 1220e3793f76SGregory Neil Shapiro ** character, and '\0' 1221e3793f76SGregory Neil Shapiro */ 1222e3793f76SGregory Neil Shapiro 1223e3793f76SGregory Neil Shapiro len = sizeof(newpath) - 3; 122412ed1c7cSGregory Neil Shapiro if (sm_strlcpy(newpath, pathname, len) >= len) 1225c2aa98e2SPeter Wemm { 1226e3793f76SGregory Neil Shapiro int save_errno = errno; 1227e3793f76SGregory Neil Shapiro 1228c2aa98e2SPeter Wemm if (tTd(56, 2)) 122912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path \"%s\" too long", 1230c2aa98e2SPeter Wemm pathname); 1231e3793f76SGregory Neil Shapiro (void) closedir(d); 1232e3793f76SGregory Neil Shapiro errno = save_errno; 1233c2aa98e2SPeter Wemm return -1; 1234c2aa98e2SPeter Wemm } 1235c2aa98e2SPeter Wemm newptr = newpath + strlen(newpath); 1236c2aa98e2SPeter Wemm *newptr++ = '/'; 1237e3793f76SGregory Neil Shapiro len = sizeof(newpath) - (newptr - newpath); 1238c2aa98e2SPeter Wemm 12393299c2f1SGregory Neil Shapiro /* 12403299c2f1SGregory Neil Shapiro ** repeat until no file has been removed 12413299c2f1SGregory Neil Shapiro ** this may become ugly when several files "expire" 12423299c2f1SGregory Neil Shapiro ** during these loops, but it's better than doing 12433299c2f1SGregory Neil Shapiro ** a rewinddir() inside the inner loop 12443299c2f1SGregory Neil Shapiro */ 124512ed1c7cSGregory Neil Shapiro 12463299c2f1SGregory Neil Shapiro do 12473299c2f1SGregory Neil Shapiro { 124812ed1c7cSGregory Neil Shapiro leftone = removedone = false; 1249c2aa98e2SPeter Wemm while ((e = readdir(d)) != NULL) 1250c2aa98e2SPeter Wemm { 1251c2aa98e2SPeter Wemm if (e->d_name[0] == '.') 1252c2aa98e2SPeter Wemm continue; 1253c2aa98e2SPeter Wemm 1254e3793f76SGregory Neil Shapiro if (sm_strlcpy(newptr, e->d_name, len) >= len) 1255e3793f76SGregory Neil Shapiro { 1256e3793f76SGregory Neil Shapiro /* Skip truncated copies */ 1257e3793f76SGregory Neil Shapiro if (tTd(56, 4)) 1258e3793f76SGregory Neil Shapiro { 1259e3793f76SGregory Neil Shapiro *newptr = '\0'; 1260e3793f76SGregory Neil Shapiro sm_dprintf("mci_traverse: path \"%s%s\" too long", 1261e3793f76SGregory Neil Shapiro newpath, e->d_name); 1262e3793f76SGregory Neil Shapiro } 1263e3793f76SGregory Neil Shapiro continue; 1264e3793f76SGregory Neil Shapiro } 1265c2aa98e2SPeter Wemm 1266c0c4794dSGregory Neil Shapiro if (StopRequest) 1267c0c4794dSGregory Neil Shapiro stop_sendmail(); 1268c2aa98e2SPeter Wemm ret = mci_traverse_persistent(action, newpath); 1269c2aa98e2SPeter Wemm if (ret < 0) 1270c2aa98e2SPeter Wemm break; 12713299c2f1SGregory Neil Shapiro if (ret == 1) 127212ed1c7cSGregory Neil Shapiro leftone = true; 12733299c2f1SGregory Neil Shapiro if (!removedone && ret == 0 && 12743299c2f1SGregory Neil Shapiro action == mci_purge_persistent) 127512ed1c7cSGregory Neil Shapiro removedone = true; 12763299c2f1SGregory Neil Shapiro } 12773299c2f1SGregory Neil Shapiro if (ret < 0) 12783299c2f1SGregory Neil Shapiro break; 127912ed1c7cSGregory Neil Shapiro 1280c2aa98e2SPeter Wemm /* 1281c2aa98e2SPeter Wemm ** The following appears to be 1282c2aa98e2SPeter Wemm ** necessary during purges, since 1283c2aa98e2SPeter Wemm ** we modify the directory structure 1284c2aa98e2SPeter Wemm */ 128512ed1c7cSGregory Neil Shapiro 12863299c2f1SGregory Neil Shapiro if (removedone) 1287c2aa98e2SPeter Wemm rewinddir(d); 12883299c2f1SGregory Neil Shapiro if (tTd(56, 40)) 128912ed1c7cSGregory Neil Shapiro sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 12903299c2f1SGregory Neil Shapiro pathname, ret, removedone, leftone); 12913299c2f1SGregory Neil Shapiro } while (removedone); 1292c2aa98e2SPeter Wemm 1293c2aa98e2SPeter Wemm /* purge (or whatever) the directory proper */ 12943299c2f1SGregory Neil Shapiro if (!leftone) 12953299c2f1SGregory Neil Shapiro { 1296c2aa98e2SPeter Wemm *--newptr = '\0'; 1297c2aa98e2SPeter Wemm ret = (*action)(newpath, NULL); 12983299c2f1SGregory Neil Shapiro } 12993299c2f1SGregory Neil Shapiro (void) closedir(d); 1300c2aa98e2SPeter Wemm } 1301c2aa98e2SPeter Wemm else if (S_ISREG(statbuf.st_mode)) 1302c2aa98e2SPeter Wemm { 1303c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 1304c2aa98e2SPeter Wemm char *start; 1305c2aa98e2SPeter Wemm char *scan; 1306c2aa98e2SPeter Wemm char host[MAXHOSTNAMELEN]; 1307c2aa98e2SPeter Wemm char *hostptr = host; 1308c2aa98e2SPeter Wemm 1309c2aa98e2SPeter Wemm /* 1310c2aa98e2SPeter Wemm ** Reconstruct the host name from the path to the 1311c2aa98e2SPeter Wemm ** persistent information. 1312c2aa98e2SPeter Wemm */ 1313c2aa98e2SPeter Wemm 1314c2aa98e2SPeter Wemm do 1315c2aa98e2SPeter Wemm { 1316c2aa98e2SPeter Wemm if (hostptr != host) 1317c2aa98e2SPeter Wemm *(hostptr++) = '.'; 1318c2aa98e2SPeter Wemm start = end; 13197660b554SGregory Neil Shapiro while (start > pathname && *(start - 1) != '/') 1320c2aa98e2SPeter Wemm start--; 1321c2aa98e2SPeter Wemm 1322c2aa98e2SPeter Wemm if (*end == '.') 1323c2aa98e2SPeter Wemm end--; 1324c2aa98e2SPeter Wemm 1325c2aa98e2SPeter Wemm for (scan = start; scan <= end; scan++) 1326c2aa98e2SPeter Wemm *(hostptr++) = *scan; 1327c2aa98e2SPeter Wemm 1328c2aa98e2SPeter Wemm end = start - 2; 13297660b554SGregory Neil Shapiro } while (end > pathname && *end == '.'); 1330c2aa98e2SPeter Wemm 1331c2aa98e2SPeter Wemm *hostptr = '\0'; 1332c2aa98e2SPeter Wemm 1333c2aa98e2SPeter Wemm /* 1334c2aa98e2SPeter Wemm ** Do something with the file containing the persistent 1335c2aa98e2SPeter Wemm ** information. 1336c2aa98e2SPeter Wemm */ 133712ed1c7cSGregory Neil Shapiro 1338c2aa98e2SPeter Wemm ret = (*action)(pathname, host); 1339c2aa98e2SPeter Wemm } 1340c2aa98e2SPeter Wemm 1341c2aa98e2SPeter Wemm return ret; 1342c2aa98e2SPeter Wemm } 134312ed1c7cSGregory Neil Shapiro /* 13443299c2f1SGregory Neil Shapiro ** MCI_PRINT_PERSISTENT -- print persistent info 1345c2aa98e2SPeter Wemm ** 1346c2aa98e2SPeter Wemm ** Dump the persistent information in the file 'pathname' 1347c2aa98e2SPeter Wemm ** 1348c2aa98e2SPeter Wemm ** Parameters: 1349c2aa98e2SPeter Wemm ** pathname -- the pathname to the status file. 1350c2aa98e2SPeter Wemm ** hostname -- the corresponding host name. 1351c2aa98e2SPeter Wemm ** 1352c2aa98e2SPeter Wemm ** Returns: 1353c2aa98e2SPeter Wemm ** 0 1354c2aa98e2SPeter Wemm */ 1355c2aa98e2SPeter Wemm 1356c2aa98e2SPeter Wemm int 1357c2aa98e2SPeter Wemm mci_print_persistent(pathname, hostname) 1358c2aa98e2SPeter Wemm char *pathname; 1359c2aa98e2SPeter Wemm char *hostname; 1360c2aa98e2SPeter Wemm { 136112ed1c7cSGregory Neil Shapiro static bool initflag = false; 136212ed1c7cSGregory Neil Shapiro SM_FILE_T *fp; 1363c2aa98e2SPeter Wemm int width = Verbose ? 78 : 25; 1364c2aa98e2SPeter Wemm bool locked; 1365c2aa98e2SPeter Wemm MCI mcib; 1366c2aa98e2SPeter Wemm 1367c2aa98e2SPeter Wemm /* skip directories */ 1368c2aa98e2SPeter Wemm if (hostname == NULL) 1369c2aa98e2SPeter Wemm return 0; 1370c2aa98e2SPeter Wemm 1371c0c4794dSGregory Neil Shapiro if (StopRequest) 1372c0c4794dSGregory Neil Shapiro stop_sendmail(); 1373c0c4794dSGregory Neil Shapiro 1374c2aa98e2SPeter Wemm if (!initflag) 1375c2aa98e2SPeter Wemm { 137612ed1c7cSGregory Neil Shapiro initflag = true; 137712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 137812ed1c7cSGregory Neil Shapiro " -------------- Hostname --------------- How long ago ---------Results---------\n"); 1379c2aa98e2SPeter Wemm } 1380c2aa98e2SPeter Wemm 138112ed1c7cSGregory Neil Shapiro fp = safefopen(pathname, O_RDONLY, FileMode, 1382c2aa98e2SPeter Wemm SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 1383c2aa98e2SPeter Wemm 1384c2aa98e2SPeter Wemm if (fp == NULL) 1385c2aa98e2SPeter Wemm { 1386c2aa98e2SPeter Wemm if (tTd(56, 1)) 138712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 138812ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1389c2aa98e2SPeter Wemm return 0; 1390c2aa98e2SPeter Wemm } 1391c2aa98e2SPeter Wemm 1392c2aa98e2SPeter Wemm FileName = pathname; 1393951742c4SGregory Neil Shapiro memset(&mcib, '\0', sizeof(mcib)); 1394c2aa98e2SPeter Wemm if (mci_read_persistent(fp, &mcib) < 0) 1395c2aa98e2SPeter Wemm { 1396c2aa98e2SPeter Wemm syserr("%s: could not read status file", pathname); 139712ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1398c2aa98e2SPeter Wemm FileName = NULL; 1399c2aa98e2SPeter Wemm return 0; 1400c2aa98e2SPeter Wemm } 1401c2aa98e2SPeter Wemm 140212ed1c7cSGregory Neil Shapiro locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 140312ed1c7cSGregory Neil Shapiro "", LOCK_SH|LOCK_NB); 140412ed1c7cSGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1405c2aa98e2SPeter Wemm FileName = NULL; 1406c2aa98e2SPeter Wemm 140712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 1408c2aa98e2SPeter Wemm locked ? '*' : ' ', hostname, 140912ed1c7cSGregory Neil Shapiro pintvl(curtime() - mcib.mci_lastuse, true)); 1410c2aa98e2SPeter Wemm if (mcib.mci_rstatus != NULL) 141112ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 141212ed1c7cSGregory Neil Shapiro mcib.mci_rstatus); 1413c2aa98e2SPeter Wemm else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 141412ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 141512ed1c7cSGregory Neil Shapiro "Deferred: %.*s\n", width - 10, 141612ed1c7cSGregory Neil Shapiro sm_errstring(mcib.mci_errno)); 1417c2aa98e2SPeter Wemm else if (mcib.mci_exitstat != 0) 1418c2aa98e2SPeter Wemm { 141912ed1c7cSGregory Neil Shapiro char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 1420c2aa98e2SPeter Wemm 142112ed1c7cSGregory Neil Shapiro if (exmsg == NULL) 1422c2aa98e2SPeter Wemm { 1423c2aa98e2SPeter Wemm char buf[80]; 1424c2aa98e2SPeter Wemm 1425951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 142612ed1c7cSGregory Neil Shapiro "Unknown mailer error %d", 1427c2aa98e2SPeter Wemm mcib.mci_exitstat); 142812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 142912ed1c7cSGregory Neil Shapiro width, buf); 1430c2aa98e2SPeter Wemm } 1431c2aa98e2SPeter Wemm else 143212ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 143312ed1c7cSGregory Neil Shapiro width, &exmsg[5]); 1434c2aa98e2SPeter Wemm } 1435c2aa98e2SPeter Wemm else if (mcib.mci_errno == 0) 143612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 1437c2aa98e2SPeter Wemm else 143812ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 143912ed1c7cSGregory Neil Shapiro width - 4, sm_errstring(mcib.mci_errno)); 1440c2aa98e2SPeter Wemm 1441c2aa98e2SPeter Wemm return 0; 1442c2aa98e2SPeter Wemm } 144312ed1c7cSGregory Neil Shapiro /* 1444c2aa98e2SPeter Wemm ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 1445c2aa98e2SPeter Wemm ** 1446c2aa98e2SPeter Wemm ** Parameters: 1447c2aa98e2SPeter Wemm ** pathname -- path to the status file. 1448c2aa98e2SPeter Wemm ** hostname -- name of host corresponding to that file. 1449c2aa98e2SPeter Wemm ** NULL if this is a directory (domain). 1450c2aa98e2SPeter Wemm ** 1451c2aa98e2SPeter Wemm ** Returns: 14523299c2f1SGregory Neil Shapiro ** 0 -- ok 14533299c2f1SGregory Neil Shapiro ** 1 -- file not deleted (too young, incorrect format) 14543299c2f1SGregory Neil Shapiro ** < 0 -- some error occurred 1455c2aa98e2SPeter Wemm */ 1456c2aa98e2SPeter Wemm 1457c2aa98e2SPeter Wemm int 1458c2aa98e2SPeter Wemm mci_purge_persistent(pathname, hostname) 1459c2aa98e2SPeter Wemm char *pathname; 1460c2aa98e2SPeter Wemm char *hostname; 1461c2aa98e2SPeter Wemm { 14623299c2f1SGregory Neil Shapiro struct stat statbuf; 1463c2aa98e2SPeter Wemm char *end = pathname + strlen(pathname) - 1; 14643299c2f1SGregory Neil Shapiro int ret; 1465c2aa98e2SPeter Wemm 1466c2aa98e2SPeter Wemm if (tTd(56, 1)) 146712ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 1468c2aa98e2SPeter Wemm 14693299c2f1SGregory Neil Shapiro ret = stat(pathname, &statbuf); 14703299c2f1SGregory Neil Shapiro if (ret < 0) 14713299c2f1SGregory Neil Shapiro { 14723299c2f1SGregory Neil Shapiro if (tTd(56, 2)) 147312ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 147412ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 14753299c2f1SGregory Neil Shapiro return ret; 14763299c2f1SGregory Neil Shapiro } 1477320f00e7SGregory Neil Shapiro if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 14783299c2f1SGregory Neil Shapiro return 1; 1479c2aa98e2SPeter Wemm if (hostname != NULL) 1480c2aa98e2SPeter Wemm { 1481c2aa98e2SPeter Wemm /* remove the file */ 148212ed1c7cSGregory Neil Shapiro ret = unlink(pathname); 148312ed1c7cSGregory Neil Shapiro if (ret < 0) 1484c2aa98e2SPeter Wemm { 148512ed1c7cSGregory Neil Shapiro if (LogLevel > 8) 148612ed1c7cSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 148712ed1c7cSGregory Neil Shapiro "mci_purge_persistent: failed to unlink %s: %s", 148812ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 1489c2aa98e2SPeter Wemm if (tTd(56, 2)) 149012ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 149112ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 149212ed1c7cSGregory Neil Shapiro return ret; 1493c2aa98e2SPeter Wemm } 1494c2aa98e2SPeter Wemm } 1495c2aa98e2SPeter Wemm else 1496c2aa98e2SPeter Wemm { 1497c2aa98e2SPeter Wemm /* remove the directory */ 1498c2aa98e2SPeter Wemm if (*end != '.') 14993299c2f1SGregory Neil Shapiro return 1; 1500c2aa98e2SPeter Wemm 1501c2aa98e2SPeter Wemm if (tTd(56, 1)) 150212ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 1503c2aa98e2SPeter Wemm 150412ed1c7cSGregory Neil Shapiro ret = rmdir(pathname); 150512ed1c7cSGregory Neil Shapiro if (ret < 0) 1506c2aa98e2SPeter Wemm { 1507c2aa98e2SPeter Wemm if (tTd(56, 2)) 150812ed1c7cSGregory Neil Shapiro sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 150912ed1c7cSGregory Neil Shapiro pathname, sm_errstring(errno)); 151012ed1c7cSGregory Neil Shapiro return ret; 1511c2aa98e2SPeter Wemm } 1512c2aa98e2SPeter Wemm } 1513c2aa98e2SPeter Wemm 1514c2aa98e2SPeter Wemm return 0; 1515c2aa98e2SPeter Wemm } 151612ed1c7cSGregory Neil Shapiro /* 1517c2aa98e2SPeter Wemm ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 1518c2aa98e2SPeter Wemm ** 15197660b554SGregory Neil Shapiro ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 1520c2aa98e2SPeter Wemm ** putting the result into `path'. if `createflag' is set, intervening 1521c2aa98e2SPeter Wemm ** directories will be created as needed. 1522c2aa98e2SPeter Wemm ** 1523c2aa98e2SPeter Wemm ** Parameters: 1524c2aa98e2SPeter Wemm ** host -- host name to convert from. 1525c2aa98e2SPeter Wemm ** path -- place to store result. 1526c2aa98e2SPeter Wemm ** pathlen -- length of path buffer. 1527c2aa98e2SPeter Wemm ** createflag -- if set, create intervening directories as 1528c2aa98e2SPeter Wemm ** needed. 1529c2aa98e2SPeter Wemm ** 1530c2aa98e2SPeter Wemm ** Returns: 1531c2aa98e2SPeter Wemm ** 0 -- success 1532c2aa98e2SPeter Wemm ** -1 -- failure 1533c2aa98e2SPeter Wemm */ 1534c2aa98e2SPeter Wemm 15353299c2f1SGregory Neil Shapiro static int 1536c2aa98e2SPeter Wemm mci_generate_persistent_path(host, path, pathlen, createflag) 1537c2aa98e2SPeter Wemm const char *host; 1538c2aa98e2SPeter Wemm char *path; 1539c2aa98e2SPeter Wemm int pathlen; 1540c2aa98e2SPeter Wemm bool createflag; 1541c2aa98e2SPeter Wemm { 1542c2aa98e2SPeter Wemm char *elem, *p, *x, ch; 1543c2aa98e2SPeter Wemm int ret = 0; 1544c2aa98e2SPeter Wemm int len; 1545c2aa98e2SPeter Wemm char t_host[MAXHOSTNAMELEN]; 15463299c2f1SGregory Neil Shapiro #if NETINET6 15473299c2f1SGregory Neil Shapiro struct in6_addr in6_addr; 1548*5b0945b5SGregory Neil Shapiro #endif 1549c2aa98e2SPeter Wemm 1550c2aa98e2SPeter Wemm /* 1551c2aa98e2SPeter Wemm ** Rationality check the arguments. 1552c2aa98e2SPeter Wemm */ 1553c2aa98e2SPeter Wemm 1554c2aa98e2SPeter Wemm if (host == NULL) 1555c2aa98e2SPeter Wemm { 1556c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null host"); 1557c2aa98e2SPeter Wemm return -1; 1558c2aa98e2SPeter Wemm } 1559c2aa98e2SPeter Wemm if (path == NULL) 1560c2aa98e2SPeter Wemm { 1561c2aa98e2SPeter Wemm syserr("mci_generate_persistent_path: null path"); 1562c2aa98e2SPeter Wemm return -1; 1563c2aa98e2SPeter Wemm } 1564c2aa98e2SPeter Wemm 1565c2aa98e2SPeter Wemm if (tTd(56, 80)) 156612ed1c7cSGregory Neil Shapiro sm_dprintf("mci_generate_persistent_path(%s): ", host); 1567c2aa98e2SPeter Wemm 1568c2aa98e2SPeter Wemm if (*host == '\0' || *host == '.') 1569c2aa98e2SPeter Wemm return -1; 1570c2aa98e2SPeter Wemm 1571c2aa98e2SPeter Wemm /* make certain this is not a bracketed host number */ 1572951742c4SGregory Neil Shapiro if (strlen(host) > sizeof(t_host) - 1) 1573c2aa98e2SPeter Wemm return -1; 1574c2aa98e2SPeter Wemm if (host[0] == '[') 1575951742c4SGregory Neil Shapiro (void) sm_strlcpy(t_host, host + 1, sizeof(t_host)); 1576c2aa98e2SPeter Wemm else 1577951742c4SGregory Neil Shapiro (void) sm_strlcpy(t_host, host, sizeof(t_host)); 1578c2aa98e2SPeter Wemm 1579c2aa98e2SPeter Wemm /* 1580c2aa98e2SPeter Wemm ** Delete any trailing dots from the hostname. 1581c2aa98e2SPeter Wemm ** Leave 'elem' pointing at the \0. 1582c2aa98e2SPeter Wemm */ 1583c2aa98e2SPeter Wemm 1584c2aa98e2SPeter Wemm elem = t_host + strlen(t_host); 1585c2aa98e2SPeter Wemm while (elem > t_host && 1586c2aa98e2SPeter Wemm (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 1587c2aa98e2SPeter Wemm *--elem = '\0'; 1588c2aa98e2SPeter Wemm 1589c2aa98e2SPeter Wemm /* check for bogus bracketed address */ 159012ed1c7cSGregory Neil Shapiro if (host[0] == '[') 159112ed1c7cSGregory Neil Shapiro { 159212ed1c7cSGregory Neil Shapiro bool good = false; 15933299c2f1SGregory Neil Shapiro # if NETINET6 159412ed1c7cSGregory Neil Shapiro if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 159512ed1c7cSGregory Neil Shapiro good = true; 1596*5b0945b5SGregory Neil Shapiro # endif 15973299c2f1SGregory Neil Shapiro # if NETINET 159812ed1c7cSGregory Neil Shapiro if (inet_addr(t_host) != INADDR_NONE) 159912ed1c7cSGregory Neil Shapiro good = true; 1600*5b0945b5SGregory Neil Shapiro # endif 160112ed1c7cSGregory Neil Shapiro if (!good) 1602c2aa98e2SPeter Wemm return -1; 160312ed1c7cSGregory Neil Shapiro } 1604c2aa98e2SPeter Wemm 1605c2aa98e2SPeter Wemm /* check for what will be the final length of the path */ 1606c2aa98e2SPeter Wemm len = strlen(HostStatDir) + 2; 1607c2aa98e2SPeter Wemm for (p = (char *) t_host; *p != '\0'; p++) 1608c2aa98e2SPeter Wemm { 1609c2aa98e2SPeter Wemm if (*p == '.') 1610c2aa98e2SPeter Wemm len++; 1611c2aa98e2SPeter Wemm len++; 1612c2aa98e2SPeter Wemm if (p[0] == '.' && p[1] == '.') 1613c2aa98e2SPeter Wemm return -1; 1614c2aa98e2SPeter Wemm } 1615c2aa98e2SPeter Wemm if (len > pathlen || len < 1) 1616c2aa98e2SPeter Wemm return -1; 161712ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(path, HostStatDir, pathlen); 1618c2aa98e2SPeter Wemm p = path + strlen(path); 1619c2aa98e2SPeter Wemm while (elem > t_host) 1620c2aa98e2SPeter Wemm { 1621c2aa98e2SPeter Wemm if (!path_is_dir(path, createflag)) 1622c2aa98e2SPeter Wemm { 1623c2aa98e2SPeter Wemm ret = -1; 1624c2aa98e2SPeter Wemm break; 1625c2aa98e2SPeter Wemm } 1626c2aa98e2SPeter Wemm elem--; 1627c2aa98e2SPeter Wemm while (elem >= t_host && *elem != '.') 1628c2aa98e2SPeter Wemm elem--; 1629c2aa98e2SPeter Wemm *p++ = '/'; 1630c2aa98e2SPeter Wemm x = elem + 1; 1631c2aa98e2SPeter Wemm while ((ch = *x++) != '\0' && ch != '.') 1632c2aa98e2SPeter Wemm { 1633c2aa98e2SPeter Wemm if (isascii(ch) && isupper(ch)) 1634c2aa98e2SPeter Wemm ch = tolower(ch); 1635c2aa98e2SPeter Wemm if (ch == '/') 1636c2aa98e2SPeter Wemm ch = ':'; /* / -> : */ 1637c2aa98e2SPeter Wemm *p++ = ch; 1638c2aa98e2SPeter Wemm } 1639c2aa98e2SPeter Wemm if (elem >= t_host) 1640c2aa98e2SPeter Wemm *p++ = '.'; 1641c2aa98e2SPeter Wemm *p = '\0'; 1642c2aa98e2SPeter Wemm } 1643c2aa98e2SPeter Wemm if (tTd(56, 80)) 1644c2aa98e2SPeter Wemm { 1645c2aa98e2SPeter Wemm if (ret < 0) 164612ed1c7cSGregory Neil Shapiro sm_dprintf("FAILURE %d\n", ret); 1647c2aa98e2SPeter Wemm else 164812ed1c7cSGregory Neil Shapiro sm_dprintf("SUCCESS %s\n", path); 1649c2aa98e2SPeter Wemm } 16503299c2f1SGregory Neil Shapiro return ret; 1651c2aa98e2SPeter Wemm } 1652