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