xref: /illumos-gate/usr/src/cmd/sendmail/src/mci.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1995-1997 Eric P. Allman.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate  * the sendmail distribution.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
157c478bd9Sstevel@tonic-gate 
16*d4660949Sjbeck SM_RCSID("@(#)$Id: mci.c,v 8.221 2007/11/13 23:44:25 gshapiro Exp $")
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
197c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
207c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate #include <dirent.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate static int	mci_generate_persistent_path __P((const char *, char *,
257c478bd9Sstevel@tonic-gate 						  int, bool));
267c478bd9Sstevel@tonic-gate static bool	mci_load_persistent __P((MCI *));
277c478bd9Sstevel@tonic-gate static void	mci_uncache __P((MCI **, bool));
287c478bd9Sstevel@tonic-gate static int	mci_lock_host_statfile __P((MCI *));
297c478bd9Sstevel@tonic-gate static int	mci_read_persistent __P((SM_FILE_T *, MCI *));
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate **  Mail Connection Information (MCI) Caching Module.
337c478bd9Sstevel@tonic-gate **
347c478bd9Sstevel@tonic-gate **	There are actually two separate things cached.  The first is
357c478bd9Sstevel@tonic-gate **	the set of all open connections -- these are stored in a
367c478bd9Sstevel@tonic-gate **	(small) list.  The second is stored in the symbol table; it
377c478bd9Sstevel@tonic-gate **	has the overall status for all hosts, whether or not there
387c478bd9Sstevel@tonic-gate **	is a connection open currently.
397c478bd9Sstevel@tonic-gate **
407c478bd9Sstevel@tonic-gate **	There should never be too many connections open (since this
417c478bd9Sstevel@tonic-gate **	could flood the socket table), nor should a connection be
427c478bd9Sstevel@tonic-gate **	allowed to sit idly for too long.
437c478bd9Sstevel@tonic-gate **
447c478bd9Sstevel@tonic-gate **	MaxMciCache is the maximum number of open connections that
457c478bd9Sstevel@tonic-gate **	will be supported.
467c478bd9Sstevel@tonic-gate **
477c478bd9Sstevel@tonic-gate **	MciCacheTimeout is the time (in seconds) that a connection
487c478bd9Sstevel@tonic-gate **	is permitted to survive without activity.
497c478bd9Sstevel@tonic-gate **
5049218d4fSjbeck **	We actually try any cached connections by sending a RSET
5149218d4fSjbeck **	before we use them; if the RSET fails we close down the
5249218d4fSjbeck **	connection and reopen it (see smtpprobe()).
537c478bd9Sstevel@tonic-gate **
547c478bd9Sstevel@tonic-gate **	The persistent MCI code is donated by Mark Lovell and Paul
557c478bd9Sstevel@tonic-gate **	Vixie.  It is based on the long term host status code in KJS
567c478bd9Sstevel@tonic-gate **	written by Paul but has been adapted by Mark to fit into the
577c478bd9Sstevel@tonic-gate **	MCI structure.
587c478bd9Sstevel@tonic-gate */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static MCI	**MciCache;		/* the open connection cache */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate **  MCI_CACHE -- enter a connection structure into the open connection cache
647c478bd9Sstevel@tonic-gate **
657c478bd9Sstevel@tonic-gate **	This may cause something else to be flushed.
667c478bd9Sstevel@tonic-gate **
677c478bd9Sstevel@tonic-gate **	Parameters:
687c478bd9Sstevel@tonic-gate **		mci -- the connection to cache.
697c478bd9Sstevel@tonic-gate **
707c478bd9Sstevel@tonic-gate **	Returns:
717c478bd9Sstevel@tonic-gate **		none.
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate void
mci_cache(mci)757c478bd9Sstevel@tonic-gate mci_cache(mci)
767c478bd9Sstevel@tonic-gate 	register MCI *mci;
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	register MCI **mcislot;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	/*
817c478bd9Sstevel@tonic-gate 	**  Find the best slot.  This may cause expired connections
827c478bd9Sstevel@tonic-gate 	**  to be closed.
837c478bd9Sstevel@tonic-gate 	*/
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	mcislot = mci_scan(mci);
867c478bd9Sstevel@tonic-gate 	if (mcislot == NULL)
877c478bd9Sstevel@tonic-gate 	{
887c478bd9Sstevel@tonic-gate 		/* we don't support caching */
897c478bd9Sstevel@tonic-gate 		return;
907c478bd9Sstevel@tonic-gate 	}
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL)
937c478bd9Sstevel@tonic-gate 		return;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/* if this is already cached, we are done */
967c478bd9Sstevel@tonic-gate 	if (bitset(MCIF_CACHED, mci->mci_flags))
977c478bd9Sstevel@tonic-gate 		return;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	/* otherwise we may have to clear the slot */
1007c478bd9Sstevel@tonic-gate 	if (*mcislot != NULL)
1017c478bd9Sstevel@tonic-gate 		mci_uncache(mcislot, true);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (tTd(42, 5))
1047c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_cache: caching %p (%s) in slot %d\n",
1057c478bd9Sstevel@tonic-gate 			   mci, mci->mci_host, (int) (mcislot - MciCache));
1067c478bd9Sstevel@tonic-gate 	if (tTd(91, 100))
1077c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
1087c478bd9Sstevel@tonic-gate 			  "mci_cache: caching %lx (%.100s) in slot %d",
1097c478bd9Sstevel@tonic-gate 			  (unsigned long) mci, mci->mci_host,
1107c478bd9Sstevel@tonic-gate 			  (int) (mcislot - MciCache));
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	*mcislot = mci;
1137c478bd9Sstevel@tonic-gate 	mci->mci_flags |= MCIF_CACHED;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate **  MCI_SCAN -- scan the cache, flush junk, and return best slot
1177c478bd9Sstevel@tonic-gate **
1187c478bd9Sstevel@tonic-gate **	Parameters:
1197c478bd9Sstevel@tonic-gate **		savemci -- never flush this one.  Can be null.
1207c478bd9Sstevel@tonic-gate **
1217c478bd9Sstevel@tonic-gate **	Returns:
1227c478bd9Sstevel@tonic-gate **		The LRU (or empty) slot.
1237c478bd9Sstevel@tonic-gate */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate MCI **
mci_scan(savemci)1267c478bd9Sstevel@tonic-gate mci_scan(savemci)
1277c478bd9Sstevel@tonic-gate 	MCI *savemci;
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	time_t now;
1307c478bd9Sstevel@tonic-gate 	register MCI **bestmci;
1317c478bd9Sstevel@tonic-gate 	register MCI *mci;
1327c478bd9Sstevel@tonic-gate 	register int i;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (MaxMciCache <= 0)
1357c478bd9Sstevel@tonic-gate 	{
1367c478bd9Sstevel@tonic-gate 		/* we don't support caching */
1377c478bd9Sstevel@tonic-gate 		return NULL;
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
1417c478bd9Sstevel@tonic-gate 	{
1427c478bd9Sstevel@tonic-gate 		/* first call */
143058561cbSjbeck 		MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof(*MciCache));
144058561cbSjbeck 		memset((char *) MciCache, '\0', MaxMciCache * sizeof(*MciCache));
1457c478bd9Sstevel@tonic-gate 		return &MciCache[0];
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	now = curtime();
1497c478bd9Sstevel@tonic-gate 	bestmci = &MciCache[0];
1507c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
1517c478bd9Sstevel@tonic-gate 	{
1527c478bd9Sstevel@tonic-gate 		mci = MciCache[i];
1537c478bd9Sstevel@tonic-gate 		if (mci == NULL || mci->mci_state == MCIS_CLOSED)
1547c478bd9Sstevel@tonic-gate 		{
1557c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
1567c478bd9Sstevel@tonic-gate 			continue;
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 		if ((mci->mci_lastuse + MciCacheTimeout <= now ||
1597c478bd9Sstevel@tonic-gate 		     (mci->mci_mailer != NULL &&
1607c478bd9Sstevel@tonic-gate 		      mci->mci_mailer->m_maxdeliveries > 0 &&
1617c478bd9Sstevel@tonic-gate 		      mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&&
1627c478bd9Sstevel@tonic-gate 		    mci != savemci)
1637c478bd9Sstevel@tonic-gate 		{
1647c478bd9Sstevel@tonic-gate 			/* connection idle too long or too many deliveries */
1657c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 			/* close it */
1687c478bd9Sstevel@tonic-gate 			mci_uncache(bestmci, true);
1697c478bd9Sstevel@tonic-gate 			continue;
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		if (*bestmci == NULL)
1727c478bd9Sstevel@tonic-gate 			continue;
1737c478bd9Sstevel@tonic-gate 		if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
1747c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	return bestmci;
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate **  MCI_UNCACHE -- remove a connection from a slot.
1807c478bd9Sstevel@tonic-gate **
1817c478bd9Sstevel@tonic-gate **	May close a connection.
1827c478bd9Sstevel@tonic-gate **
1837c478bd9Sstevel@tonic-gate **	Parameters:
1847c478bd9Sstevel@tonic-gate **		mcislot -- the slot to empty.
1857c478bd9Sstevel@tonic-gate **		doquit -- if true, send QUIT protocol on this connection.
1867c478bd9Sstevel@tonic-gate **			  if false, we are assumed to be in a forked child;
1877c478bd9Sstevel@tonic-gate **				all we want to do is close the file(s).
1887c478bd9Sstevel@tonic-gate **
1897c478bd9Sstevel@tonic-gate **	Returns:
1907c478bd9Sstevel@tonic-gate **		none.
1917c478bd9Sstevel@tonic-gate */
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static void
mci_uncache(mcislot,doquit)1947c478bd9Sstevel@tonic-gate mci_uncache(mcislot, doquit)
1957c478bd9Sstevel@tonic-gate 	register MCI **mcislot;
1967c478bd9Sstevel@tonic-gate 	bool doquit;
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	register MCI *mci;
1997c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	mci = *mcislot;
2027c478bd9Sstevel@tonic-gate 	if (mci == NULL)
2037c478bd9Sstevel@tonic-gate 		return;
2047c478bd9Sstevel@tonic-gate 	*mcislot = NULL;
2057c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL)
2067c478bd9Sstevel@tonic-gate 		return;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	mci_unlock_host(mci);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (tTd(42, 5))
2117c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n",
2127c478bd9Sstevel@tonic-gate 			   mci, mci->mci_host, (int) (mcislot - MciCache),
2137c478bd9Sstevel@tonic-gate 			   doquit);
2147c478bd9Sstevel@tonic-gate 	if (tTd(91, 100))
2157c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
2167c478bd9Sstevel@tonic-gate 			  "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)",
2177c478bd9Sstevel@tonic-gate 			  (unsigned long) mci, mci->mci_host,
2187c478bd9Sstevel@tonic-gate 			  (int) (mcislot - MciCache), doquit);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	mci->mci_deliveries = 0;
2217c478bd9Sstevel@tonic-gate 	if (doquit)
2227c478bd9Sstevel@tonic-gate 	{
2237c478bd9Sstevel@tonic-gate 		message("Closing connection to %s", mci->mci_host);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		mci->mci_flags &= ~MCIF_CACHED;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		/* only uses the envelope to flush the transcript file */
2287c478bd9Sstevel@tonic-gate 		if (mci->mci_state != MCIS_CLOSED)
2297c478bd9Sstevel@tonic-gate 			smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
2307c478bd9Sstevel@tonic-gate #if XLA
2317c478bd9Sstevel@tonic-gate 		xla_host_end(mci->mci_host);
2327c478bd9Sstevel@tonic-gate #endif /* XLA */
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	else
2357c478bd9Sstevel@tonic-gate 	{
2367c478bd9Sstevel@tonic-gate 		if (mci->mci_in != NULL)
2377c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
2387c478bd9Sstevel@tonic-gate 		if (mci->mci_out != NULL)
2397c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2407c478bd9Sstevel@tonic-gate 		mci->mci_in = mci->mci_out = NULL;
2417c478bd9Sstevel@tonic-gate 		mci->mci_state = MCIS_CLOSED;
2427c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = EX_OK;
2437c478bd9Sstevel@tonic-gate 		mci->mci_errno = 0;
2447c478bd9Sstevel@tonic-gate 		mci->mci_flags = 0;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 		mci->mci_retryrcpt = false;
2477c478bd9Sstevel@tonic-gate 		mci->mci_tolist = NULL;
2487c478bd9Sstevel@tonic-gate #if PIPELINING
2497c478bd9Sstevel@tonic-gate 		mci->mci_okrcpts = 0;
2507c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
2547c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
2557c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_heloname);
2567c478bd9Sstevel@tonic-gate 	if (mci->mci_rpool != NULL)
2577c478bd9Sstevel@tonic-gate 	{
2587c478bd9Sstevel@tonic-gate 		sm_rpool_free(mci->mci_rpool);
2597c478bd9Sstevel@tonic-gate 		mci->mci_macro.mac_rpool = NULL;
2607c478bd9Sstevel@tonic-gate 		mci->mci_rpool = NULL;
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate **  MCI_FLUSH -- flush the entire cache
2657c478bd9Sstevel@tonic-gate **
2667c478bd9Sstevel@tonic-gate **	Parameters:
2677c478bd9Sstevel@tonic-gate **		doquit -- if true, send QUIT protocol.
2687c478bd9Sstevel@tonic-gate **			  if false, just close the connection.
2697c478bd9Sstevel@tonic-gate **		allbut -- but leave this one open.
2707c478bd9Sstevel@tonic-gate **
2717c478bd9Sstevel@tonic-gate **	Returns:
2727c478bd9Sstevel@tonic-gate **		none.
2737c478bd9Sstevel@tonic-gate */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate void
mci_flush(doquit,allbut)2767c478bd9Sstevel@tonic-gate mci_flush(doquit, allbut)
2777c478bd9Sstevel@tonic-gate 	bool doquit;
2787c478bd9Sstevel@tonic-gate 	MCI *allbut;
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	register int i;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
2837c478bd9Sstevel@tonic-gate 		return;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
2867c478bd9Sstevel@tonic-gate 	{
2877c478bd9Sstevel@tonic-gate 		if (allbut != MciCache[i])
2887c478bd9Sstevel@tonic-gate 			mci_uncache(&MciCache[i], doquit);
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate **  MCI_GET -- get information about a particular host
2937c478bd9Sstevel@tonic-gate **
2947c478bd9Sstevel@tonic-gate **	Parameters:
2957c478bd9Sstevel@tonic-gate **		host -- host to look for.
2967c478bd9Sstevel@tonic-gate **		m -- mailer.
2977c478bd9Sstevel@tonic-gate **
2987c478bd9Sstevel@tonic-gate **	Returns:
2997c478bd9Sstevel@tonic-gate **		mci for this host (might be new).
3007c478bd9Sstevel@tonic-gate */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate MCI *
mci_get(host,m)3037c478bd9Sstevel@tonic-gate mci_get(host, m)
3047c478bd9Sstevel@tonic-gate 	char *host;
3057c478bd9Sstevel@tonic-gate 	MAILER *m;
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	register MCI *mci;
3087c478bd9Sstevel@tonic-gate 	register STAB *s;
3097c478bd9Sstevel@tonic-gate 	extern SOCKADDR CurHostAddr;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/* clear CurHostAddr so we don't get a bogus address with this name */
312058561cbSjbeck 	memset(&CurHostAddr, '\0', sizeof(CurHostAddr));
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* clear out any expired connections */
3157c478bd9Sstevel@tonic-gate 	(void) mci_scan(NULL);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (m->m_mno < 0)
3187c478bd9Sstevel@tonic-gate 		syserr("!negative mno %d (%s)", m->m_mno, m->m_name);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
3217c478bd9Sstevel@tonic-gate 	mci = &s->s_mci;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	/* initialize per-message data */
3247c478bd9Sstevel@tonic-gate 	mci->mci_retryrcpt = false;
3257c478bd9Sstevel@tonic-gate 	mci->mci_tolist = NULL;
3267c478bd9Sstevel@tonic-gate #if PIPELINING
3277c478bd9Sstevel@tonic-gate 	mci->mci_okrcpts = 0;
3287c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (mci->mci_rpool == NULL)
3317c478bd9Sstevel@tonic-gate 		mci->mci_rpool = sm_rpool_new_x(NULL);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (mci->mci_macro.mac_rpool == NULL)
3347c478bd9Sstevel@tonic-gate 		mci->mci_macro.mac_rpool = mci->mci_rpool;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	**  We don't need to load the persistent data if we have data
3387c478bd9Sstevel@tonic-gate 	**  already loaded in the cache.
3397c478bd9Sstevel@tonic-gate 	*/
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL &&
3427c478bd9Sstevel@tonic-gate 	    (mci->mci_host = s->s_name) != NULL &&
3437c478bd9Sstevel@tonic-gate 	    !mci_load_persistent(mci))
3447c478bd9Sstevel@tonic-gate 	{
3457c478bd9Sstevel@tonic-gate 		if (tTd(42, 2))
3467c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_get(%s %s): lock failed\n",
3477c478bd9Sstevel@tonic-gate 				host, m->m_name);
3487c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = EX_TEMPFAIL;
3497c478bd9Sstevel@tonic-gate 		mci->mci_state = MCIS_CLOSED;
3507c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
3517c478bd9Sstevel@tonic-gate 		return mci;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (tTd(42, 2))
3557c478bd9Sstevel@tonic-gate 	{
3567c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n",
3577c478bd9Sstevel@tonic-gate 			host, m->m_name, mci->mci_state, mci->mci_flags,
3587c478bd9Sstevel@tonic-gate 			mci->mci_exitstat, mci->mci_errno);
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (mci->mci_state == MCIS_OPEN)
3627c478bd9Sstevel@tonic-gate 	{
3637c478bd9Sstevel@tonic-gate 		/* poke the connection to see if it's still alive */
3647c478bd9Sstevel@tonic-gate 		(void) smtpprobe(mci);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 		/* reset the stored state in the event of a timeout */
3677c478bd9Sstevel@tonic-gate 		if (mci->mci_state != MCIS_OPEN)
3687c478bd9Sstevel@tonic-gate 		{
3697c478bd9Sstevel@tonic-gate 			mci->mci_errno = 0;
3707c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = EX_OK;
3717c478bd9Sstevel@tonic-gate 			mci->mci_state = MCIS_CLOSED;
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 		else
3747c478bd9Sstevel@tonic-gate 		{
3757c478bd9Sstevel@tonic-gate 			/* get peer host address */
3767c478bd9Sstevel@tonic-gate 			/* (this should really be in the mci struct) */
377058561cbSjbeck 			SOCKADDR_LEN_T socklen = sizeof(CurHostAddr);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 			(void) getpeername(sm_io_getinfo(mci->mci_in,
3807c478bd9Sstevel@tonic-gate 							 SM_IO_WHAT_FD, NULL),
3817c478bd9Sstevel@tonic-gate 				(struct sockaddr *) &CurHostAddr, &socklen);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	if (mci->mci_state == MCIS_CLOSED)
3857c478bd9Sstevel@tonic-gate 	{
3867c478bd9Sstevel@tonic-gate 		time_t now = curtime();
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 		/* if this info is stale, ignore it */
3897c478bd9Sstevel@tonic-gate 		if (mci->mci_lastuse + MciInfoTimeout <= now)
3907c478bd9Sstevel@tonic-gate 		{
3917c478bd9Sstevel@tonic-gate 			mci->mci_lastuse = now;
3927c478bd9Sstevel@tonic-gate 			mci->mci_errno = 0;
3937c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = EX_OK;
3947c478bd9Sstevel@tonic-gate 		}
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return mci;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate **  MCI_CLOSE -- (forcefully) close files used for a connection.
4027c478bd9Sstevel@tonic-gate **	Note: this is a last resort, usually smtpquit() or endmailer()
4037c478bd9Sstevel@tonic-gate **		should be used to close a connection.
4047c478bd9Sstevel@tonic-gate **
4057c478bd9Sstevel@tonic-gate **	Parameters:
4067c478bd9Sstevel@tonic-gate **		mci -- the connection to close.
4077c478bd9Sstevel@tonic-gate **		where -- where has this been called?
4087c478bd9Sstevel@tonic-gate **
4097c478bd9Sstevel@tonic-gate **	Returns:
4107c478bd9Sstevel@tonic-gate **		none.
4117c478bd9Sstevel@tonic-gate */
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate void
mci_close(mci,where)4147c478bd9Sstevel@tonic-gate mci_close(mci, where)
4157c478bd9Sstevel@tonic-gate 	MCI *mci;
4167c478bd9Sstevel@tonic-gate 	char *where;
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	bool dumped;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (mci == NULL)
4217c478bd9Sstevel@tonic-gate 		return;
4227c478bd9Sstevel@tonic-gate 	dumped = false;
4237c478bd9Sstevel@tonic-gate 	if (mci->mci_out != NULL)
4247c478bd9Sstevel@tonic-gate 	{
4257c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
4267c478bd9Sstevel@tonic-gate 		{
4277c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_close: mci_out!=NULL, where=%s\n",
4287c478bd9Sstevel@tonic-gate 				where);
4297c478bd9Sstevel@tonic-gate 			mci_dump(sm_debug_file(), mci, false);
4307c478bd9Sstevel@tonic-gate 			dumped = true;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
4337c478bd9Sstevel@tonic-gate 		mci->mci_out = NULL;
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 	if (mci->mci_in != NULL)
4367c478bd9Sstevel@tonic-gate 	{
4377c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
4387c478bd9Sstevel@tonic-gate 		{
4397c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_close: mci_in!=NULL, where=%s\n",
4407c478bd9Sstevel@tonic-gate 				where);
4417c478bd9Sstevel@tonic-gate 			if (!dumped)
4427c478bd9Sstevel@tonic-gate 				mci_dump(sm_debug_file(), mci, false);
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
4457c478bd9Sstevel@tonic-gate 		mci->mci_in = NULL;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 	mci->mci_state = MCIS_CLOSED;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate **  MCI_NEW -- allocate new MCI structure
4527c478bd9Sstevel@tonic-gate **
4537c478bd9Sstevel@tonic-gate **	Parameters:
4547c478bd9Sstevel@tonic-gate **		rpool -- if non-NULL: allocate from that rpool.
4557c478bd9Sstevel@tonic-gate **
4567c478bd9Sstevel@tonic-gate **	Returns:
4577c478bd9Sstevel@tonic-gate **		mci (new).
4587c478bd9Sstevel@tonic-gate */
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate MCI *
mci_new(rpool)4617c478bd9Sstevel@tonic-gate mci_new(rpool)
4627c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	register MCI *mci;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (rpool == NULL)
467058561cbSjbeck 		mci = (MCI *) sm_malloc_x(sizeof(*mci));
4687c478bd9Sstevel@tonic-gate 	else
469058561cbSjbeck 		mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof(*mci));
470058561cbSjbeck 	memset((char *) mci, '\0', sizeof(*mci));
4717c478bd9Sstevel@tonic-gate 	mci->mci_rpool = sm_rpool_new_x(NULL);
4727c478bd9Sstevel@tonic-gate 	mci->mci_macro.mac_rpool = mci->mci_rpool;
4737c478bd9Sstevel@tonic-gate 	return mci;
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate **  MCI_MATCH -- check connection cache for a particular host
4777c478bd9Sstevel@tonic-gate **
4787c478bd9Sstevel@tonic-gate **	Parameters:
4797c478bd9Sstevel@tonic-gate **		host -- host to look for.
4807c478bd9Sstevel@tonic-gate **		m -- mailer.
4817c478bd9Sstevel@tonic-gate **
4827c478bd9Sstevel@tonic-gate **	Returns:
4837c478bd9Sstevel@tonic-gate **		true iff open connection exists.
4847c478bd9Sstevel@tonic-gate */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate bool
mci_match(host,m)4877c478bd9Sstevel@tonic-gate mci_match(host, m)
4887c478bd9Sstevel@tonic-gate 	char *host;
4897c478bd9Sstevel@tonic-gate 	MAILER *m;
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	register MCI *mci;
4927c478bd9Sstevel@tonic-gate 	register STAB *s;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (m->m_mno < 0 || m->m_mno > MAXMAILERS)
4957c478bd9Sstevel@tonic-gate 		return false;
4967c478bd9Sstevel@tonic-gate 	s = stab(host, ST_MCI + m->m_mno, ST_FIND);
4977c478bd9Sstevel@tonic-gate 	if (s == NULL)
4987c478bd9Sstevel@tonic-gate 		return false;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	mci = &s->s_mci;
5017c478bd9Sstevel@tonic-gate 	return mci->mci_state == MCIS_OPEN;
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate **  MCI_SETSTAT -- set status codes in MCI structure.
5057c478bd9Sstevel@tonic-gate **
5067c478bd9Sstevel@tonic-gate **	Parameters:
5077c478bd9Sstevel@tonic-gate **		mci -- the MCI structure to set.
5087c478bd9Sstevel@tonic-gate **		xstat -- the exit status code.
5097c478bd9Sstevel@tonic-gate **		dstat -- the DSN status code.
5107c478bd9Sstevel@tonic-gate **		rstat -- the SMTP status code.
5117c478bd9Sstevel@tonic-gate **
5127c478bd9Sstevel@tonic-gate **	Returns:
5137c478bd9Sstevel@tonic-gate **		none.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate void
mci_setstat(mci,xstat,dstat,rstat)5177c478bd9Sstevel@tonic-gate mci_setstat(mci, xstat, dstat, rstat)
5187c478bd9Sstevel@tonic-gate 	MCI *mci;
5197c478bd9Sstevel@tonic-gate 	int xstat;
5207c478bd9Sstevel@tonic-gate 	char *dstat;
5217c478bd9Sstevel@tonic-gate 	char *rstat;
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	/* protocol errors should never be interpreted as sticky */
5247c478bd9Sstevel@tonic-gate 	if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
5257c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = xstat;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
5287c478bd9Sstevel@tonic-gate 	if (dstat != NULL)
5297c478bd9Sstevel@tonic-gate 		mci->mci_status = sm_strdup_x(dstat);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
5327c478bd9Sstevel@tonic-gate 	if (rstat != NULL)
5337c478bd9Sstevel@tonic-gate 		mci->mci_rstatus = sm_strdup_x(rstat);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate **  MCI_DUMP -- dump the contents of an MCI structure.
5377c478bd9Sstevel@tonic-gate **
5387c478bd9Sstevel@tonic-gate **	Parameters:
5397c478bd9Sstevel@tonic-gate **		fp -- output file pointer
5407c478bd9Sstevel@tonic-gate **		mci -- the MCI structure to dump.
5417c478bd9Sstevel@tonic-gate **
5427c478bd9Sstevel@tonic-gate **	Returns:
5437c478bd9Sstevel@tonic-gate **		none.
5447c478bd9Sstevel@tonic-gate **
5457c478bd9Sstevel@tonic-gate **	Side Effects:
5467c478bd9Sstevel@tonic-gate **		none.
5477c478bd9Sstevel@tonic-gate */
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate struct mcifbits
5507c478bd9Sstevel@tonic-gate {
5517c478bd9Sstevel@tonic-gate 	int	mcif_bit;	/* flag bit */
5527c478bd9Sstevel@tonic-gate 	char	*mcif_name;	/* flag name */
5537c478bd9Sstevel@tonic-gate };
5547c478bd9Sstevel@tonic-gate static struct mcifbits	MciFlags[] =
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	{ MCIF_VALID,		"VALID"		},
5577c478bd9Sstevel@tonic-gate 	{ MCIF_CACHED,		"CACHED"	},
5587c478bd9Sstevel@tonic-gate 	{ MCIF_ESMTP,		"ESMTP"		},
5597c478bd9Sstevel@tonic-gate 	{ MCIF_EXPN,		"EXPN"		},
5607c478bd9Sstevel@tonic-gate 	{ MCIF_SIZE,		"SIZE"		},
5617c478bd9Sstevel@tonic-gate 	{ MCIF_8BITMIME,	"8BITMIME"	},
5627c478bd9Sstevel@tonic-gate 	{ MCIF_7BIT,		"7BIT"		},
5637c478bd9Sstevel@tonic-gate 	{ MCIF_INHEADER,	"INHEADER"	},
5647c478bd9Sstevel@tonic-gate 	{ MCIF_CVT8TO7,		"CVT8TO7"	},
5657c478bd9Sstevel@tonic-gate 	{ MCIF_DSN,		"DSN"		},
5667c478bd9Sstevel@tonic-gate 	{ MCIF_8BITOK,		"8BITOK"	},
5677c478bd9Sstevel@tonic-gate 	{ MCIF_CVT7TO8,		"CVT7TO8"	},
5687c478bd9Sstevel@tonic-gate 	{ MCIF_INMIME,		"INMIME"	},
5697c478bd9Sstevel@tonic-gate 	{ MCIF_AUTH,		"AUTH"		},
5707c478bd9Sstevel@tonic-gate 	{ MCIF_AUTHACT,		"AUTHACT"	},
5717c478bd9Sstevel@tonic-gate 	{ MCIF_ENHSTAT,		"ENHSTAT"	},
5727c478bd9Sstevel@tonic-gate 	{ MCIF_PIPELINED,	"PIPELINED"	},
5737c478bd9Sstevel@tonic-gate #if STARTTLS
5747c478bd9Sstevel@tonic-gate 	{ MCIF_TLS,		"TLS"		},
5757c478bd9Sstevel@tonic-gate 	{ MCIF_TLSACT,		"TLSACT"	},
5767c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
5777c478bd9Sstevel@tonic-gate 	{ MCIF_DLVR_BY,		"DLVR_BY"	},
5787c478bd9Sstevel@tonic-gate 	{ 0,			NULL		}
5797c478bd9Sstevel@tonic-gate };
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate void
mci_dump(fp,mci,logit)5827c478bd9Sstevel@tonic-gate mci_dump(fp, mci, logit)
5837c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
5847c478bd9Sstevel@tonic-gate 	register MCI *mci;
5857c478bd9Sstevel@tonic-gate 	bool logit;
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	register char *p;
5887c478bd9Sstevel@tonic-gate 	char *sep;
5897c478bd9Sstevel@tonic-gate 	char buf[4000];
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	sep = logit ? " " : "\n\t";
5927c478bd9Sstevel@tonic-gate 	p = buf;
5937c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci);
5947c478bd9Sstevel@tonic-gate 	p += strlen(p);
5957c478bd9Sstevel@tonic-gate 	if (mci == NULL)
5967c478bd9Sstevel@tonic-gate 	{
5977c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "NULL");
5987c478bd9Sstevel@tonic-gate 		goto printit;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
6017c478bd9Sstevel@tonic-gate 	p += strlen(p);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/*
6047c478bd9Sstevel@tonic-gate 	**  The following check is just for paranoia.  It protects the
6057c478bd9Sstevel@tonic-gate 	**  assignment in the if() clause. If there's not some minimum
6067c478bd9Sstevel@tonic-gate 	**  amount of space we can stop right now. The check will not
6077c478bd9Sstevel@tonic-gate 	**  trigger as long as sizeof(buf)=4000.
6087c478bd9Sstevel@tonic-gate 	*/
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if (p >= buf + sizeof(buf) - 4)
6117c478bd9Sstevel@tonic-gate 		goto printit;
6127c478bd9Sstevel@tonic-gate 	if (mci->mci_flags != 0)
6137c478bd9Sstevel@tonic-gate 	{
6147c478bd9Sstevel@tonic-gate 		struct mcifbits *f;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 		*p++ = '<';	/* protected above */
6177c478bd9Sstevel@tonic-gate 		for (f = MciFlags; f->mcif_bit != 0; f++)
6187c478bd9Sstevel@tonic-gate 		{
6197c478bd9Sstevel@tonic-gate 			if (!bitset(f->mcif_bit, mci->mci_flags))
6207c478bd9Sstevel@tonic-gate 				continue;
6217c478bd9Sstevel@tonic-gate 			(void) sm_strlcpyn(p, SPACELEFT(buf, p), 2,
6227c478bd9Sstevel@tonic-gate 					   f->mcif_name, ",");
6237c478bd9Sstevel@tonic-gate 			p += strlen(p);
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 		p[-1] = '>';
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/* Note: sm_snprintf() takes care of NULL arguments for %s */
6297c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
6307c478bd9Sstevel@tonic-gate 		",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
6317c478bd9Sstevel@tonic-gate 		sep, mci->mci_errno, mci->mci_herrno,
6327c478bd9Sstevel@tonic-gate 		mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep);
6337c478bd9Sstevel@tonic-gate 	p += strlen(p);
6347c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
6357c478bd9Sstevel@tonic-gate 		"maxsize=%ld, phase=%s, mailer=%s,%s",
6367c478bd9Sstevel@tonic-gate 		mci->mci_maxsize, mci->mci_phase,
6377c478bd9Sstevel@tonic-gate 		mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
6387c478bd9Sstevel@tonic-gate 		sep);
6397c478bd9Sstevel@tonic-gate 	p += strlen(p);
6407c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
6417c478bd9Sstevel@tonic-gate 		"status=%s, rstatus=%s,%s",
6427c478bd9Sstevel@tonic-gate 		mci->mci_status, mci->mci_rstatus, sep);
6437c478bd9Sstevel@tonic-gate 	p += strlen(p);
6447c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
6457c478bd9Sstevel@tonic-gate 		"host=%s, lastuse=%s",
6467c478bd9Sstevel@tonic-gate 		mci->mci_host, ctime(&mci->mci_lastuse));
6477c478bd9Sstevel@tonic-gate printit:
6487c478bd9Sstevel@tonic-gate 	if (logit)
6497c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
6507c478bd9Sstevel@tonic-gate 	else
6517c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate **  MCI_DUMP_ALL -- print the entire MCI cache
6557c478bd9Sstevel@tonic-gate **
6567c478bd9Sstevel@tonic-gate **	Parameters:
6577c478bd9Sstevel@tonic-gate **		fp -- output file pointer
6587c478bd9Sstevel@tonic-gate **		logit -- if set, log the result instead of printing
6597c478bd9Sstevel@tonic-gate **			to stdout.
6607c478bd9Sstevel@tonic-gate **
6617c478bd9Sstevel@tonic-gate **	Returns:
6627c478bd9Sstevel@tonic-gate **		none.
6637c478bd9Sstevel@tonic-gate */
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate void
mci_dump_all(fp,logit)6667c478bd9Sstevel@tonic-gate mci_dump_all(fp, logit)
6677c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
6687c478bd9Sstevel@tonic-gate 	bool logit;
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	register int i;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
6737c478bd9Sstevel@tonic-gate 		return;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
6767c478bd9Sstevel@tonic-gate 		mci_dump(fp, MciCache[i], logit);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate **  MCI_LOCK_HOST -- Lock host while sending.
6807c478bd9Sstevel@tonic-gate **
6817c478bd9Sstevel@tonic-gate **	If we are contacting a host, we'll need to
6827c478bd9Sstevel@tonic-gate **	update the status information in the host status
6837c478bd9Sstevel@tonic-gate **	file, and if we want to do that, we ought to have
6847c478bd9Sstevel@tonic-gate **	locked it. This has the (according to some)
6857c478bd9Sstevel@tonic-gate **	desirable effect of serializing connectivity with
6867c478bd9Sstevel@tonic-gate **	remote hosts -- i.e.: one connection to a given
6877c478bd9Sstevel@tonic-gate **	host at a time.
6887c478bd9Sstevel@tonic-gate **
6897c478bd9Sstevel@tonic-gate **	Parameters:
6907c478bd9Sstevel@tonic-gate **		mci -- containing the host we want to lock.
6917c478bd9Sstevel@tonic-gate **
6927c478bd9Sstevel@tonic-gate **	Returns:
6937c478bd9Sstevel@tonic-gate **		EX_OK	    -- got the lock.
6947c478bd9Sstevel@tonic-gate **		EX_TEMPFAIL -- didn't get the lock.
6957c478bd9Sstevel@tonic-gate */
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate int
mci_lock_host(mci)6987c478bd9Sstevel@tonic-gate mci_lock_host(mci)
6997c478bd9Sstevel@tonic-gate 	MCI *mci;
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	if (mci == NULL)
7027c478bd9Sstevel@tonic-gate 	{
7037c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
7047c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: NULL mci\n");
7057c478bd9Sstevel@tonic-gate 		return EX_OK;
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (!SingleThreadDelivery)
7097c478bd9Sstevel@tonic-gate 		return EX_OK;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	return mci_lock_host_statfile(mci);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate static int
mci_lock_host_statfile(mci)7157c478bd9Sstevel@tonic-gate mci_lock_host_statfile(mci)
7167c478bd9Sstevel@tonic-gate 	MCI *mci;
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	int save_errno = errno;
7197c478bd9Sstevel@tonic-gate 	int retVal = EX_OK;
7207c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
7237c478bd9Sstevel@tonic-gate 		return EX_OK;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (tTd(56, 2))
7267c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_lock_host: attempting to lock %s\n",
7277c478bd9Sstevel@tonic-gate 			   mci->mci_host);
7287c478bd9Sstevel@tonic-gate 
729058561cbSjbeck 	if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname),
7307c478bd9Sstevel@tonic-gate 					 true) < 0)
7317c478bd9Sstevel@tonic-gate 	{
7327c478bd9Sstevel@tonic-gate 		/* of course this should never happen */
7337c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
7347c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: Failed to generate host path for %s\n",
7357c478bd9Sstevel@tonic-gate 				   mci->mci_host);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		retVal = EX_TEMPFAIL;
7387c478bd9Sstevel@tonic-gate 		goto cleanup;
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	mci->mci_statfile = safefopen(fname, O_RDWR, FileMode,
7427c478bd9Sstevel@tonic-gate 				      SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile == NULL)
7457c478bd9Sstevel@tonic-gate 	{
7467c478bd9Sstevel@tonic-gate 		syserr("mci_lock_host: cannot create host lock file %s", fname);
7477c478bd9Sstevel@tonic-gate 		goto cleanup;
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
7517c478bd9Sstevel@tonic-gate 		      fname, "", LOCK_EX|LOCK_NB))
7527c478bd9Sstevel@tonic-gate 	{
7537c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
7547c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: couldn't get lock on %s\n",
7557c478bd9Sstevel@tonic-gate 				fname);
7567c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
7577c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
7587c478bd9Sstevel@tonic-gate 		retVal = EX_TEMPFAIL;
7597c478bd9Sstevel@tonic-gate 		goto cleanup;
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	if (tTd(56, 12) && mci->mci_statfile != NULL)
7637c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_lock_host: Sanity check -- lock is good\n");
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate cleanup:
7667c478bd9Sstevel@tonic-gate 	errno = save_errno;
7677c478bd9Sstevel@tonic-gate 	return retVal;
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate **  MCI_UNLOCK_HOST -- unlock host
7717c478bd9Sstevel@tonic-gate **
7727c478bd9Sstevel@tonic-gate **	Clean up the lock on a host, close the file, let
7737c478bd9Sstevel@tonic-gate **	someone else use it.
7747c478bd9Sstevel@tonic-gate **
7757c478bd9Sstevel@tonic-gate **	Parameters:
7767c478bd9Sstevel@tonic-gate **		mci -- us.
7777c478bd9Sstevel@tonic-gate **
7787c478bd9Sstevel@tonic-gate **	Returns:
7797c478bd9Sstevel@tonic-gate **		nothing.
7807c478bd9Sstevel@tonic-gate */
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate void
mci_unlock_host(mci)7837c478bd9Sstevel@tonic-gate mci_unlock_host(mci)
7847c478bd9Sstevel@tonic-gate 	MCI *mci;
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	int save_errno = errno;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (mci == NULL)
7897c478bd9Sstevel@tonic-gate 	{
7907c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
7917c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: NULL mci\n");
7927c478bd9Sstevel@tonic-gate 		return;
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
7967c478bd9Sstevel@tonic-gate 		return;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
7997c478bd9Sstevel@tonic-gate 	{
8007c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
8017c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: stat file already locked\n");
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	else
8047c478bd9Sstevel@tonic-gate 	{
8057c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
8067c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: store prior to unlock\n");
8077c478bd9Sstevel@tonic-gate 		mci_store_persistent(mci);
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile != NULL)
8117c478bd9Sstevel@tonic-gate 	{
8127c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
8137c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
8147c478bd9Sstevel@tonic-gate 	}
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	errno = save_errno;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate /*
8197c478bd9Sstevel@tonic-gate **  MCI_LOAD_PERSISTENT -- load persistent host info
8207c478bd9Sstevel@tonic-gate **
8217c478bd9Sstevel@tonic-gate **	Load information about host that is kept
8227c478bd9Sstevel@tonic-gate **	in common for all running sendmails.
8237c478bd9Sstevel@tonic-gate **
8247c478bd9Sstevel@tonic-gate **	Parameters:
8257c478bd9Sstevel@tonic-gate **		mci -- the host/connection to load persistent info for.
8267c478bd9Sstevel@tonic-gate **
8277c478bd9Sstevel@tonic-gate **	Returns:
8287c478bd9Sstevel@tonic-gate **		true -- lock was successful
8297c478bd9Sstevel@tonic-gate **		false -- lock failed
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate static bool
mci_load_persistent(mci)8337c478bd9Sstevel@tonic-gate mci_load_persistent(mci)
8347c478bd9Sstevel@tonic-gate 	MCI *mci;
8357c478bd9Sstevel@tonic-gate {
8367c478bd9Sstevel@tonic-gate 	int save_errno = errno;
8377c478bd9Sstevel@tonic-gate 	bool locked = true;
8387c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
8397c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	if (mci == NULL)
8427c478bd9Sstevel@tonic-gate 	{
8437c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
8447c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: NULL mci\n");
8457c478bd9Sstevel@tonic-gate 		return true;
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
8497c478bd9Sstevel@tonic-gate 		return true;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	/* Already have the persistent information in memory */
8527c478bd9Sstevel@tonic-gate 	if (SingleThreadDelivery && mci->mci_statfile != NULL)
8537c478bd9Sstevel@tonic-gate 		return true;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
8567c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
8577c478bd9Sstevel@tonic-gate 			   mci->mci_host);
8587c478bd9Sstevel@tonic-gate 
859058561cbSjbeck 	if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname),
8607c478bd9Sstevel@tonic-gate 					 false) < 0)
8617c478bd9Sstevel@tonic-gate 	{
8627c478bd9Sstevel@tonic-gate 		/* Not much we can do if the file isn't there... */
8637c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
8647c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: Couldn't generate host path\n");
8657c478bd9Sstevel@tonic-gate 		goto cleanup;
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	fp = safefopen(fname, O_RDONLY, FileMode,
8697c478bd9Sstevel@tonic-gate 		       SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
8707c478bd9Sstevel@tonic-gate 	if (fp == NULL)
8717c478bd9Sstevel@tonic-gate 	{
8727c478bd9Sstevel@tonic-gate 		/* I can't think of any reason this should ever happen */
8737c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
8747c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: open(%s): %s\n",
8757c478bd9Sstevel@tonic-gate 				fname, sm_errstring(errno));
8767c478bd9Sstevel@tonic-gate 		goto cleanup;
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	FileName = fname;
8807c478bd9Sstevel@tonic-gate 	locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "",
8817c478bd9Sstevel@tonic-gate 			  LOCK_SH|LOCK_NB);
8827c478bd9Sstevel@tonic-gate 	if (locked)
8837c478bd9Sstevel@tonic-gate 	{
8847c478bd9Sstevel@tonic-gate 		(void) mci_read_persistent(fp, mci);
8857c478bd9Sstevel@tonic-gate 		(void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname,
8867c478bd9Sstevel@tonic-gate 				"", LOCK_UN);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 	FileName = NULL;
8897c478bd9Sstevel@tonic-gate 	(void) sm_io_close(fp, SM_TIME_DEFAULT);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate cleanup:
8927c478bd9Sstevel@tonic-gate 	errno = save_errno;
8937c478bd9Sstevel@tonic-gate 	return locked;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate **  MCI_READ_PERSISTENT -- read persistent host status file
8977c478bd9Sstevel@tonic-gate **
8987c478bd9Sstevel@tonic-gate **	Parameters:
8997c478bd9Sstevel@tonic-gate **		fp -- the file pointer to read.
9007c478bd9Sstevel@tonic-gate **		mci -- the pointer to fill in.
9017c478bd9Sstevel@tonic-gate **
9027c478bd9Sstevel@tonic-gate **	Returns:
9037c478bd9Sstevel@tonic-gate **		-1 -- if the file was corrupt.
9047c478bd9Sstevel@tonic-gate **		0 -- otherwise.
9057c478bd9Sstevel@tonic-gate **
9067c478bd9Sstevel@tonic-gate **	Warning:
9077c478bd9Sstevel@tonic-gate **		This code makes the assumption that this data
9087c478bd9Sstevel@tonic-gate **		will be read in an atomic fashion, and that the data
9097c478bd9Sstevel@tonic-gate **		was written in an atomic fashion.  Any other functioning
9107c478bd9Sstevel@tonic-gate **		may lead to some form of insanity.  This should be
9117c478bd9Sstevel@tonic-gate **		perfectly safe due to underlying stdio buffering.
9127c478bd9Sstevel@tonic-gate */
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate static int
mci_read_persistent(fp,mci)9157c478bd9Sstevel@tonic-gate mci_read_persistent(fp, mci)
9167c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
9177c478bd9Sstevel@tonic-gate 	register MCI *mci;
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	int ver;
9207c478bd9Sstevel@tonic-gate 	register char *p;
9217c478bd9Sstevel@tonic-gate 	int saveLineNumber = LineNumber;
9227c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	if (fp == NULL)
9253ee0e492Sjbeck 	{
9267c478bd9Sstevel@tonic-gate 		syserr("mci_read_persistent: NULL fp");
9273ee0e492Sjbeck 		/* NOTREACHED */
9283ee0e492Sjbeck 		return -1;
9293ee0e492Sjbeck 	}
9307c478bd9Sstevel@tonic-gate 	if (mci == NULL)
9313ee0e492Sjbeck 	{
9327c478bd9Sstevel@tonic-gate 		syserr("mci_read_persistent: NULL mci");
9333ee0e492Sjbeck 		/* NOTREACHED */
9343ee0e492Sjbeck 		return -1;
9353ee0e492Sjbeck 	}
9367c478bd9Sstevel@tonic-gate 	if (tTd(56, 93))
9377c478bd9Sstevel@tonic-gate 	{
9387c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_read_persistent: fp=%lx, mci=",
9397c478bd9Sstevel@tonic-gate 			   (unsigned long) fp);
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
9437c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	sm_io_rewind(fp, SM_TIME_DEFAULT);
9467c478bd9Sstevel@tonic-gate 	ver = -1;
9477c478bd9Sstevel@tonic-gate 	LineNumber = 0;
948058561cbSjbeck 	while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
9497c478bd9Sstevel@tonic-gate 	{
9507c478bd9Sstevel@tonic-gate 		LineNumber++;
9517c478bd9Sstevel@tonic-gate 		p = strchr(buf, '\n');
9527c478bd9Sstevel@tonic-gate 		if (p != NULL)
9537c478bd9Sstevel@tonic-gate 			*p = '\0';
9547c478bd9Sstevel@tonic-gate 		switch (buf[0])
9557c478bd9Sstevel@tonic-gate 		{
9567c478bd9Sstevel@tonic-gate 		  case 'V':		/* version stamp */
9577c478bd9Sstevel@tonic-gate 			ver = atoi(&buf[1]);
9587c478bd9Sstevel@tonic-gate 			if (ver < 0 || ver > 0)
9597c478bd9Sstevel@tonic-gate 				syserr("Unknown host status version %d: %d max",
9607c478bd9Sstevel@tonic-gate 					ver, 0);
9617c478bd9Sstevel@tonic-gate 			break;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 		  case 'E':		/* UNIX error number */
9647c478bd9Sstevel@tonic-gate 			mci->mci_errno = atoi(&buf[1]);
9657c478bd9Sstevel@tonic-gate 			break;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		  case 'H':		/* DNS error number */
9687c478bd9Sstevel@tonic-gate 			mci->mci_herrno = atoi(&buf[1]);
9697c478bd9Sstevel@tonic-gate 			break;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		  case 'S':		/* UNIX exit status */
9727c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = atoi(&buf[1]);
9737c478bd9Sstevel@tonic-gate 			break;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		  case 'D':		/* DSN status */
9767c478bd9Sstevel@tonic-gate 			mci->mci_status = newstr(&buf[1]);
9777c478bd9Sstevel@tonic-gate 			break;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 		  case 'R':		/* SMTP status */
9807c478bd9Sstevel@tonic-gate 			mci->mci_rstatus = newstr(&buf[1]);
9817c478bd9Sstevel@tonic-gate 			break;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 		  case 'U':		/* last usage time */
9847c478bd9Sstevel@tonic-gate 			mci->mci_lastuse = atol(&buf[1]);
9857c478bd9Sstevel@tonic-gate 			break;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 		  case '.':		/* end of file */
9887c478bd9Sstevel@tonic-gate 			if (tTd(56, 93))
9897c478bd9Sstevel@tonic-gate 				mci_dump(sm_debug_file(), mci, false);
9907c478bd9Sstevel@tonic-gate 			return 0;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 		  default:
9937c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_CRIT, NOQID,
9947c478bd9Sstevel@tonic-gate 				  "%s: line %d: Unknown host status line \"%s\"",
9957c478bd9Sstevel@tonic-gate 				  FileName == NULL ? mci->mci_host : FileName,
9967c478bd9Sstevel@tonic-gate 				  LineNumber, buf);
9977c478bd9Sstevel@tonic-gate 			LineNumber = saveLineNumber;
9987c478bd9Sstevel@tonic-gate 			return -1;
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	LineNumber = saveLineNumber;
10027c478bd9Sstevel@tonic-gate 	if (tTd(56, 93))
10037c478bd9Sstevel@tonic-gate 		sm_dprintf("incomplete (missing dot for EOF)\n");
10047c478bd9Sstevel@tonic-gate 	if (ver < 0)
10057c478bd9Sstevel@tonic-gate 		return -1;
10067c478bd9Sstevel@tonic-gate 	return 0;
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate **  MCI_STORE_PERSISTENT -- Store persistent MCI information
10107c478bd9Sstevel@tonic-gate **
10117c478bd9Sstevel@tonic-gate **	Store information about host that is kept
10127c478bd9Sstevel@tonic-gate **	in common for all running sendmails.
10137c478bd9Sstevel@tonic-gate **
10147c478bd9Sstevel@tonic-gate **	Parameters:
10157c478bd9Sstevel@tonic-gate **		mci -- the host/connection to store persistent info for.
10167c478bd9Sstevel@tonic-gate **
10177c478bd9Sstevel@tonic-gate **	Returns:
10187c478bd9Sstevel@tonic-gate **		none.
10197c478bd9Sstevel@tonic-gate */
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate void
mci_store_persistent(mci)10227c478bd9Sstevel@tonic-gate mci_store_persistent(mci)
10237c478bd9Sstevel@tonic-gate 	MCI *mci;
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	int save_errno = errno;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if (mci == NULL)
10287c478bd9Sstevel@tonic-gate 	{
10297c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
10307c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_store_persistent: NULL mci\n");
10317c478bd9Sstevel@tonic-gate 		return;
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
10357c478bd9Sstevel@tonic-gate 		return;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
10387c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_store_persistent: Storing information for %s\n",
10397c478bd9Sstevel@tonic-gate 			   mci->mci_host);
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile == NULL)
10427c478bd9Sstevel@tonic-gate 	{
10437c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
10447c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_store_persistent: no statfile\n");
10457c478bd9Sstevel@tonic-gate 		return;
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT);
10497c478bd9Sstevel@tonic-gate #if !NOFTRUNCATE
10507c478bd9Sstevel@tonic-gate 	(void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
10517c478bd9Sstevel@tonic-gate 			 (off_t) 0);
10527c478bd9Sstevel@tonic-gate #endif /* !NOFTRUNCATE */
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n");
10557c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n",
10567c478bd9Sstevel@tonic-gate 			     mci->mci_errno);
10577c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n",
10587c478bd9Sstevel@tonic-gate 			     mci->mci_herrno);
10597c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n",
10607c478bd9Sstevel@tonic-gate 			     mci->mci_exitstat);
10617c478bd9Sstevel@tonic-gate 	if (mci->mci_status != NULL)
10627c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
10637c478bd9Sstevel@tonic-gate 				     "D%.80s\n",
10647c478bd9Sstevel@tonic-gate 				     denlstring(mci->mci_status, true, false));
10657c478bd9Sstevel@tonic-gate 	if (mci->mci_rstatus != NULL)
10667c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
10677c478bd9Sstevel@tonic-gate 				     "R%.80s\n",
10687c478bd9Sstevel@tonic-gate 				     denlstring(mci->mci_rstatus, true, false));
10697c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n",
10707c478bd9Sstevel@tonic-gate 			     (long)(mci->mci_lastuse));
10717c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n");
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	(void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	errno = save_errno;
10767c478bd9Sstevel@tonic-gate 	return;
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate /*
10797c478bd9Sstevel@tonic-gate **  MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
10807c478bd9Sstevel@tonic-gate **
10817c478bd9Sstevel@tonic-gate **	Recursively find all the mci host files in `pathname'.  Default to
10827c478bd9Sstevel@tonic-gate **		main host status directory if no path is provided.
10837c478bd9Sstevel@tonic-gate **	Call (*action)(pathname, host) for each file found.
10847c478bd9Sstevel@tonic-gate **
10857c478bd9Sstevel@tonic-gate **	Note: all information is collected in a list before it is processed.
10867c478bd9Sstevel@tonic-gate **	This may not be the best way to do it, but it seems safest, since
10877c478bd9Sstevel@tonic-gate **	the file system would be touched while we are attempting to traverse
10887c478bd9Sstevel@tonic-gate **	the directory tree otherwise (during purges).
10897c478bd9Sstevel@tonic-gate **
10907c478bd9Sstevel@tonic-gate **	Parameters:
10917c478bd9Sstevel@tonic-gate **		action -- function to call on each node.  If returns < 0,
10927c478bd9Sstevel@tonic-gate **			return immediately.
10937c478bd9Sstevel@tonic-gate **		pathname -- root of tree.  If null, use main host status
10947c478bd9Sstevel@tonic-gate **			directory.
10957c478bd9Sstevel@tonic-gate **
10967c478bd9Sstevel@tonic-gate **	Returns:
10977c478bd9Sstevel@tonic-gate **		< 0 -- if any action routine returns a negative value, that
10987c478bd9Sstevel@tonic-gate **			value is returned.
10997c478bd9Sstevel@tonic-gate **		0 -- if we successfully went to completion.
11007c478bd9Sstevel@tonic-gate **		> 0 -- return status from action()
11017c478bd9Sstevel@tonic-gate */
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate int
11047c478bd9Sstevel@tonic-gate mci_traverse_persistent(action, pathname)
11057c478bd9Sstevel@tonic-gate 	int (*action)__P((char *, char *));
11067c478bd9Sstevel@tonic-gate 	char *pathname;
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate 	struct stat statbuf;
11097c478bd9Sstevel@tonic-gate 	DIR *d;
11107c478bd9Sstevel@tonic-gate 	int ret;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
11137c478bd9Sstevel@tonic-gate 		pathname = HostStatDir;
11147c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
11157c478bd9Sstevel@tonic-gate 		return -1;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
11187c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_traverse: pathname is %s\n", pathname);
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	ret = stat(pathname, &statbuf);
11217c478bd9Sstevel@tonic-gate 	if (ret < 0)
11227c478bd9Sstevel@tonic-gate 	{
11237c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
11247c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_traverse: Failed to stat %s: %s\n",
11257c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
11267c478bd9Sstevel@tonic-gate 		return ret;
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 	if (S_ISDIR(statbuf.st_mode))
11297c478bd9Sstevel@tonic-gate 	{
11307c478bd9Sstevel@tonic-gate 		bool leftone, removedone;
11317c478bd9Sstevel@tonic-gate 		size_t len;
11327c478bd9Sstevel@tonic-gate 		char *newptr;
11337c478bd9Sstevel@tonic-gate 		struct dirent *e;
11347c478bd9Sstevel@tonic-gate 		char newpath[MAXPATHLEN];
113549218d4fSjbeck #if MAXPATHLEN <= MAXNAMLEN - 3
113649218d4fSjbeck  ERROR "MAXPATHLEN <= MAXNAMLEN - 3"
113749218d4fSjbeck #endif /* MAXPATHLEN  <= MAXNAMLEN - 3 */
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 		if ((d = opendir(pathname)) == NULL)
11407c478bd9Sstevel@tonic-gate 		{
11417c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
11427c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: opendir %s: %s\n",
11437c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
11447c478bd9Sstevel@tonic-gate 			return -1;
11457c478bd9Sstevel@tonic-gate 		}
1146*d4660949Sjbeck 
1147*d4660949Sjbeck 		/*
1148*d4660949Sjbeck 		**  Reserve space for trailing '/', at least one
1149*d4660949Sjbeck 		**  character, and '\0'
1150*d4660949Sjbeck 		*/
1151*d4660949Sjbeck 
1152*d4660949Sjbeck 		len = sizeof(newpath) - 3;
11537c478bd9Sstevel@tonic-gate 		if (sm_strlcpy(newpath, pathname, len) >= len)
11547c478bd9Sstevel@tonic-gate 		{
1155*d4660949Sjbeck 			int save_errno = errno;
1156*d4660949Sjbeck 
11577c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
11587c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: path \"%s\" too long",
11597c478bd9Sstevel@tonic-gate 					pathname);
1160*d4660949Sjbeck 			(void) closedir(d);
1161*d4660949Sjbeck 			errno = save_errno;
11627c478bd9Sstevel@tonic-gate 			return -1;
11637c478bd9Sstevel@tonic-gate 		}
11647c478bd9Sstevel@tonic-gate 		newptr = newpath + strlen(newpath);
11657c478bd9Sstevel@tonic-gate 		*newptr++ = '/';
1166*d4660949Sjbeck 		len = sizeof(newpath) - (newptr - newpath);
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 		/*
11697c478bd9Sstevel@tonic-gate 		**  repeat until no file has been removed
11707c478bd9Sstevel@tonic-gate 		**  this may become ugly when several files "expire"
11717c478bd9Sstevel@tonic-gate 		**  during these loops, but it's better than doing
11727c478bd9Sstevel@tonic-gate 		**  a rewinddir() inside the inner loop
11737c478bd9Sstevel@tonic-gate 		*/
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 		do
11767c478bd9Sstevel@tonic-gate 		{
11777c478bd9Sstevel@tonic-gate 			leftone = removedone = false;
11787c478bd9Sstevel@tonic-gate 			while ((e = readdir(d)) != NULL)
11797c478bd9Sstevel@tonic-gate 			{
11807c478bd9Sstevel@tonic-gate 				if (e->d_name[0] == '.')
11817c478bd9Sstevel@tonic-gate 					continue;
11827c478bd9Sstevel@tonic-gate 
1183*d4660949Sjbeck 				if (sm_strlcpy(newptr, e->d_name, len) >= len)
1184*d4660949Sjbeck 				{
1185*d4660949Sjbeck 					/* Skip truncated copies */
1186*d4660949Sjbeck 					if (tTd(56, 4))
1187*d4660949Sjbeck 					{
1188*d4660949Sjbeck 						*newptr = '\0';
1189*d4660949Sjbeck 						sm_dprintf("mci_traverse: path \"%s%s\" too long",
1190*d4660949Sjbeck 							   newpath, e->d_name);
1191*d4660949Sjbeck 					}
1192*d4660949Sjbeck 					continue;
1193*d4660949Sjbeck 				}
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 				if (StopRequest)
11967c478bd9Sstevel@tonic-gate 					stop_sendmail();
11977c478bd9Sstevel@tonic-gate 				ret = mci_traverse_persistent(action, newpath);
11987c478bd9Sstevel@tonic-gate 				if (ret < 0)
11997c478bd9Sstevel@tonic-gate 					break;
12007c478bd9Sstevel@tonic-gate 				if (ret == 1)
12017c478bd9Sstevel@tonic-gate 					leftone = true;
12027c478bd9Sstevel@tonic-gate 				if (!removedone && ret == 0 &&
12037c478bd9Sstevel@tonic-gate 				    action == mci_purge_persistent)
12047c478bd9Sstevel@tonic-gate 					removedone = true;
12057c478bd9Sstevel@tonic-gate 			}
12067c478bd9Sstevel@tonic-gate 			if (ret < 0)
12077c478bd9Sstevel@tonic-gate 				break;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 			/*
12107c478bd9Sstevel@tonic-gate 			**  The following appears to be
12117c478bd9Sstevel@tonic-gate 			**  necessary during purges, since
12127c478bd9Sstevel@tonic-gate 			**  we modify the directory structure
12137c478bd9Sstevel@tonic-gate 			*/
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 			if (removedone)
12167c478bd9Sstevel@tonic-gate 				rewinddir(d);
12177c478bd9Sstevel@tonic-gate 			if (tTd(56, 40))
12187c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
12197c478bd9Sstevel@tonic-gate 					pathname, ret, removedone, leftone);
12207c478bd9Sstevel@tonic-gate 		} while (removedone);
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 		/* purge (or whatever) the directory proper */
12237c478bd9Sstevel@tonic-gate 		if (!leftone)
12247c478bd9Sstevel@tonic-gate 		{
12257c478bd9Sstevel@tonic-gate 			*--newptr = '\0';
12267c478bd9Sstevel@tonic-gate 			ret = (*action)(newpath, NULL);
12277c478bd9Sstevel@tonic-gate 		}
12287c478bd9Sstevel@tonic-gate 		(void) closedir(d);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 	else if (S_ISREG(statbuf.st_mode))
12317c478bd9Sstevel@tonic-gate 	{
12327c478bd9Sstevel@tonic-gate 		char *end = pathname + strlen(pathname) - 1;
12337c478bd9Sstevel@tonic-gate 		char *start;
12347c478bd9Sstevel@tonic-gate 		char *scan;
12357c478bd9Sstevel@tonic-gate 		char host[MAXHOSTNAMELEN];
12367c478bd9Sstevel@tonic-gate 		char *hostptr = host;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 		/*
12397c478bd9Sstevel@tonic-gate 		**  Reconstruct the host name from the path to the
12407c478bd9Sstevel@tonic-gate 		**  persistent information.
12417c478bd9Sstevel@tonic-gate 		*/
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 		do
12447c478bd9Sstevel@tonic-gate 		{
12457c478bd9Sstevel@tonic-gate 			if (hostptr != host)
12467c478bd9Sstevel@tonic-gate 				*(hostptr++) = '.';
12477c478bd9Sstevel@tonic-gate 			start = end;
12487c478bd9Sstevel@tonic-gate 			while (start > pathname && *(start - 1) != '/')
12497c478bd9Sstevel@tonic-gate 				start--;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 			if (*end == '.')
12527c478bd9Sstevel@tonic-gate 				end--;
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 			for (scan = start; scan <= end; scan++)
12557c478bd9Sstevel@tonic-gate 				*(hostptr++) = *scan;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 			end = start - 2;
12587c478bd9Sstevel@tonic-gate 		} while (end > pathname && *end == '.');
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 		*hostptr = '\0';
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		/*
12637c478bd9Sstevel@tonic-gate 		**  Do something with the file containing the persistent
12647c478bd9Sstevel@tonic-gate 		**  information.
12657c478bd9Sstevel@tonic-gate 		*/
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 		ret = (*action)(pathname, host);
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	return ret;
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate /*
12737c478bd9Sstevel@tonic-gate **  MCI_PRINT_PERSISTENT -- print persistent info
12747c478bd9Sstevel@tonic-gate **
12757c478bd9Sstevel@tonic-gate **	Dump the persistent information in the file 'pathname'
12767c478bd9Sstevel@tonic-gate **
12777c478bd9Sstevel@tonic-gate **	Parameters:
12787c478bd9Sstevel@tonic-gate **		pathname -- the pathname to the status file.
12797c478bd9Sstevel@tonic-gate **		hostname -- the corresponding host name.
12807c478bd9Sstevel@tonic-gate **
12817c478bd9Sstevel@tonic-gate **	Returns:
12827c478bd9Sstevel@tonic-gate **		0
12837c478bd9Sstevel@tonic-gate */
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate int
mci_print_persistent(pathname,hostname)12867c478bd9Sstevel@tonic-gate mci_print_persistent(pathname, hostname)
12877c478bd9Sstevel@tonic-gate 	char *pathname;
12887c478bd9Sstevel@tonic-gate 	char *hostname;
12897c478bd9Sstevel@tonic-gate {
12907c478bd9Sstevel@tonic-gate 	static bool initflag = false;
12917c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
12927c478bd9Sstevel@tonic-gate 	int width = Verbose ? 78 : 25;
12937c478bd9Sstevel@tonic-gate 	bool locked;
12947c478bd9Sstevel@tonic-gate 	MCI mcib;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	/* skip directories */
12977c478bd9Sstevel@tonic-gate 	if (hostname == NULL)
12987c478bd9Sstevel@tonic-gate 		return 0;
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	if (StopRequest)
13017c478bd9Sstevel@tonic-gate 		stop_sendmail();
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	if (!initflag)
13047c478bd9Sstevel@tonic-gate 	{
13057c478bd9Sstevel@tonic-gate 		initflag = true;
13067c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
13077c478bd9Sstevel@tonic-gate 				     " -------------- Hostname --------------- How long ago ---------Results---------\n");
13087c478bd9Sstevel@tonic-gate 	}
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	fp = safefopen(pathname, O_RDONLY, FileMode,
13117c478bd9Sstevel@tonic-gate 		       SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	if (fp == NULL)
13147c478bd9Sstevel@tonic-gate 	{
13157c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
13167c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_print_persistent: cannot open %s: %s\n",
13177c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
13187c478bd9Sstevel@tonic-gate 		return 0;
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	FileName = pathname;
1322058561cbSjbeck 	memset(&mcib, '\0', sizeof(mcib));
13237c478bd9Sstevel@tonic-gate 	if (mci_read_persistent(fp, &mcib) < 0)
13247c478bd9Sstevel@tonic-gate 	{
13257c478bd9Sstevel@tonic-gate 		syserr("%s: could not read status file", pathname);
13267c478bd9Sstevel@tonic-gate 		(void) sm_io_close(fp, SM_TIME_DEFAULT);
13277c478bd9Sstevel@tonic-gate 		FileName = NULL;
13287c478bd9Sstevel@tonic-gate 		return 0;
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname,
13327c478bd9Sstevel@tonic-gate 			   "", LOCK_SH|LOCK_NB);
13337c478bd9Sstevel@tonic-gate 	(void) sm_io_close(fp, SM_TIME_DEFAULT);
13347c478bd9Sstevel@tonic-gate 	FileName = NULL;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ",
13377c478bd9Sstevel@tonic-gate 			     locked ? '*' : ' ', hostname,
13387c478bd9Sstevel@tonic-gate 			     pintvl(curtime() - mcib.mci_lastuse, true));
13397c478bd9Sstevel@tonic-gate 	if (mcib.mci_rstatus != NULL)
13407c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width,
13417c478bd9Sstevel@tonic-gate 				     mcib.mci_rstatus);
13427c478bd9Sstevel@tonic-gate 	else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
13437c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
13447c478bd9Sstevel@tonic-gate 				     "Deferred: %.*s\n", width - 10,
13457c478bd9Sstevel@tonic-gate 				     sm_errstring(mcib.mci_errno));
13467c478bd9Sstevel@tonic-gate 	else if (mcib.mci_exitstat != 0)
13477c478bd9Sstevel@tonic-gate 	{
13487c478bd9Sstevel@tonic-gate 		char *exmsg = sm_sysexmsg(mcib.mci_exitstat);
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 		if (exmsg == NULL)
13517c478bd9Sstevel@tonic-gate 		{
13527c478bd9Sstevel@tonic-gate 			char buf[80];
13537c478bd9Sstevel@tonic-gate 
1354058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
13557c478bd9Sstevel@tonic-gate 				"Unknown mailer error %d",
13567c478bd9Sstevel@tonic-gate 				mcib.mci_exitstat);
13577c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
13587c478bd9Sstevel@tonic-gate 					     width, buf);
13597c478bd9Sstevel@tonic-gate 		}
13607c478bd9Sstevel@tonic-gate 		else
13617c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
13627c478bd9Sstevel@tonic-gate 					     width, &exmsg[5]);
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 	else if (mcib.mci_errno == 0)
13657c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n");
13667c478bd9Sstevel@tonic-gate 	else
13677c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n",
13687c478bd9Sstevel@tonic-gate 				     width - 4, sm_errstring(mcib.mci_errno));
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	return 0;
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate /*
13737c478bd9Sstevel@tonic-gate **  MCI_PURGE_PERSISTENT -- Remove a persistence status file.
13747c478bd9Sstevel@tonic-gate **
13757c478bd9Sstevel@tonic-gate **	Parameters:
13767c478bd9Sstevel@tonic-gate **		pathname -- path to the status file.
13777c478bd9Sstevel@tonic-gate **		hostname -- name of host corresponding to that file.
13787c478bd9Sstevel@tonic-gate **			NULL if this is a directory (domain).
13797c478bd9Sstevel@tonic-gate **
13807c478bd9Sstevel@tonic-gate **	Returns:
13817c478bd9Sstevel@tonic-gate **		0 -- ok
13827c478bd9Sstevel@tonic-gate **		1 -- file not deleted (too young, incorrect format)
13837c478bd9Sstevel@tonic-gate **		< 0 -- some error occurred
13847c478bd9Sstevel@tonic-gate */
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate int
mci_purge_persistent(pathname,hostname)13877c478bd9Sstevel@tonic-gate mci_purge_persistent(pathname, hostname)
13887c478bd9Sstevel@tonic-gate 	char *pathname;
13897c478bd9Sstevel@tonic-gate 	char *hostname;
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate 	struct stat statbuf;
13927c478bd9Sstevel@tonic-gate 	char *end = pathname + strlen(pathname) - 1;
13937c478bd9Sstevel@tonic-gate 	int ret;
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
13967c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_purge_persistent: purging %s\n", pathname);
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	ret = stat(pathname, &statbuf);
13997c478bd9Sstevel@tonic-gate 	if (ret < 0)
14007c478bd9Sstevel@tonic-gate 	{
14017c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
14027c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
14037c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
14047c478bd9Sstevel@tonic-gate 		return ret;
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 	if (curtime() - statbuf.st_mtime <= MciInfoTimeout)
14077c478bd9Sstevel@tonic-gate 		return 1;
14087c478bd9Sstevel@tonic-gate 	if (hostname != NULL)
14097c478bd9Sstevel@tonic-gate 	{
14107c478bd9Sstevel@tonic-gate 		/* remove the file */
14117c478bd9Sstevel@tonic-gate 		ret = unlink(pathname);
14127c478bd9Sstevel@tonic-gate 		if (ret < 0)
14137c478bd9Sstevel@tonic-gate 		{
14147c478bd9Sstevel@tonic-gate 			if (LogLevel > 8)
14157c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, NOQID,
14167c478bd9Sstevel@tonic-gate 					  "mci_purge_persistent: failed to unlink %s: %s",
14177c478bd9Sstevel@tonic-gate 					  pathname, sm_errstring(errno));
14187c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
14197c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
14207c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
14217c478bd9Sstevel@tonic-gate 			return ret;
14227c478bd9Sstevel@tonic-gate 		}
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 	else
14257c478bd9Sstevel@tonic-gate 	{
14267c478bd9Sstevel@tonic-gate 		/* remove the directory */
14277c478bd9Sstevel@tonic-gate 		if (*end != '.')
14287c478bd9Sstevel@tonic-gate 			return 1;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
14317c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 		ret = rmdir(pathname);
14347c478bd9Sstevel@tonic-gate 		if (ret < 0)
14357c478bd9Sstevel@tonic-gate 		{
14367c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
14377c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_purge_persistent: rmdir %s: %s\n",
14387c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
14397c478bd9Sstevel@tonic-gate 			return ret;
14407c478bd9Sstevel@tonic-gate 		}
14417c478bd9Sstevel@tonic-gate 	}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	return 0;
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate /*
14467c478bd9Sstevel@tonic-gate **  MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
14477c478bd9Sstevel@tonic-gate **
14487c478bd9Sstevel@tonic-gate **	Given `host', convert from a.b.c to $HostStatDir/c./b./a,
14497c478bd9Sstevel@tonic-gate **	putting the result into `path'.  if `createflag' is set, intervening
14507c478bd9Sstevel@tonic-gate **	directories will be created as needed.
14517c478bd9Sstevel@tonic-gate **
14527c478bd9Sstevel@tonic-gate **	Parameters:
14537c478bd9Sstevel@tonic-gate **		host -- host name to convert from.
14547c478bd9Sstevel@tonic-gate **		path -- place to store result.
14557c478bd9Sstevel@tonic-gate **		pathlen -- length of path buffer.
14567c478bd9Sstevel@tonic-gate **		createflag -- if set, create intervening directories as
14577c478bd9Sstevel@tonic-gate **			needed.
14587c478bd9Sstevel@tonic-gate **
14597c478bd9Sstevel@tonic-gate **	Returns:
14607c478bd9Sstevel@tonic-gate **		0 -- success
14617c478bd9Sstevel@tonic-gate **		-1 -- failure
14627c478bd9Sstevel@tonic-gate */
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate static int
mci_generate_persistent_path(host,path,pathlen,createflag)14657c478bd9Sstevel@tonic-gate mci_generate_persistent_path(host, path, pathlen, createflag)
14667c478bd9Sstevel@tonic-gate 	const char *host;
14677c478bd9Sstevel@tonic-gate 	char *path;
14687c478bd9Sstevel@tonic-gate 	int pathlen;
14697c478bd9Sstevel@tonic-gate 	bool createflag;
14707c478bd9Sstevel@tonic-gate {
14717c478bd9Sstevel@tonic-gate 	char *elem, *p, *x, ch;
14727c478bd9Sstevel@tonic-gate 	int ret = 0;
14737c478bd9Sstevel@tonic-gate 	int len;
14747c478bd9Sstevel@tonic-gate 	char t_host[MAXHOSTNAMELEN];
14757c478bd9Sstevel@tonic-gate #if NETINET6
14767c478bd9Sstevel@tonic-gate 	struct in6_addr in6_addr;
14777c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	/*
14807c478bd9Sstevel@tonic-gate 	**  Rationality check the arguments.
14817c478bd9Sstevel@tonic-gate 	*/
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	if (host == NULL)
14847c478bd9Sstevel@tonic-gate 	{
14857c478bd9Sstevel@tonic-gate 		syserr("mci_generate_persistent_path: null host");
14867c478bd9Sstevel@tonic-gate 		return -1;
14877c478bd9Sstevel@tonic-gate 	}
14887c478bd9Sstevel@tonic-gate 	if (path == NULL)
14897c478bd9Sstevel@tonic-gate 	{
14907c478bd9Sstevel@tonic-gate 		syserr("mci_generate_persistent_path: null path");
14917c478bd9Sstevel@tonic-gate 		return -1;
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	if (tTd(56, 80))
14957c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_generate_persistent_path(%s): ", host);
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	if (*host == '\0' || *host == '.')
14987c478bd9Sstevel@tonic-gate 		return -1;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	/* make certain this is not a bracketed host number */
1501058561cbSjbeck 	if (strlen(host) > sizeof(t_host) - 1)
15027c478bd9Sstevel@tonic-gate 		return -1;
15037c478bd9Sstevel@tonic-gate 	if (host[0] == '[')
1504058561cbSjbeck 		(void) sm_strlcpy(t_host, host + 1, sizeof(t_host));
15057c478bd9Sstevel@tonic-gate 	else
1506058561cbSjbeck 		(void) sm_strlcpy(t_host, host, sizeof(t_host));
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	/*
15097c478bd9Sstevel@tonic-gate 	**  Delete any trailing dots from the hostname.
15107c478bd9Sstevel@tonic-gate 	**  Leave 'elem' pointing at the \0.
15117c478bd9Sstevel@tonic-gate 	*/
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	elem = t_host + strlen(t_host);
15147c478bd9Sstevel@tonic-gate 	while (elem > t_host &&
15157c478bd9Sstevel@tonic-gate 	       (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
15167c478bd9Sstevel@tonic-gate 		*--elem = '\0';
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	/* check for bogus bracketed address */
15197c478bd9Sstevel@tonic-gate 	if (host[0] == '[')
15207c478bd9Sstevel@tonic-gate 	{
15217c478bd9Sstevel@tonic-gate 		bool good = false;
15227c478bd9Sstevel@tonic-gate # if NETINET6
15237c478bd9Sstevel@tonic-gate 		if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1)
15247c478bd9Sstevel@tonic-gate 			good = true;
15257c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
15267c478bd9Sstevel@tonic-gate # if NETINET
15277c478bd9Sstevel@tonic-gate 		if (inet_addr(t_host) != INADDR_NONE)
15287c478bd9Sstevel@tonic-gate 			good = true;
15297c478bd9Sstevel@tonic-gate # endif /* NETINET */
15307c478bd9Sstevel@tonic-gate 		if (!good)
15317c478bd9Sstevel@tonic-gate 			return -1;
15327c478bd9Sstevel@tonic-gate 	}
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	/* check for what will be the final length of the path */
15357c478bd9Sstevel@tonic-gate 	len = strlen(HostStatDir) + 2;
15367c478bd9Sstevel@tonic-gate 	for (p = (char *) t_host; *p != '\0'; p++)
15377c478bd9Sstevel@tonic-gate 	{
15387c478bd9Sstevel@tonic-gate 		if (*p == '.')
15397c478bd9Sstevel@tonic-gate 			len++;
15407c478bd9Sstevel@tonic-gate 		len++;
15417c478bd9Sstevel@tonic-gate 		if (p[0] == '.' && p[1] == '.')
15427c478bd9Sstevel@tonic-gate 			return -1;
15437c478bd9Sstevel@tonic-gate 	}
15447c478bd9Sstevel@tonic-gate 	if (len > pathlen || len < 1)
15457c478bd9Sstevel@tonic-gate 		return -1;
15467c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(path, HostStatDir, pathlen);
15477c478bd9Sstevel@tonic-gate 	p = path + strlen(path);
15487c478bd9Sstevel@tonic-gate 	while (elem > t_host)
15497c478bd9Sstevel@tonic-gate 	{
15507c478bd9Sstevel@tonic-gate 		if (!path_is_dir(path, createflag))
15517c478bd9Sstevel@tonic-gate 		{
15527c478bd9Sstevel@tonic-gate 			ret = -1;
15537c478bd9Sstevel@tonic-gate 			break;
15547c478bd9Sstevel@tonic-gate 		}
15557c478bd9Sstevel@tonic-gate 		elem--;
15567c478bd9Sstevel@tonic-gate 		while (elem >= t_host && *elem != '.')
15577c478bd9Sstevel@tonic-gate 			elem--;
15587c478bd9Sstevel@tonic-gate 		*p++ = '/';
15597c478bd9Sstevel@tonic-gate 		x = elem + 1;
15607c478bd9Sstevel@tonic-gate 		while ((ch = *x++) != '\0' && ch != '.')
15617c478bd9Sstevel@tonic-gate 		{
15627c478bd9Sstevel@tonic-gate 			if (isascii(ch) && isupper(ch))
15637c478bd9Sstevel@tonic-gate 				ch = tolower(ch);
15647c478bd9Sstevel@tonic-gate 			if (ch == '/')
15657c478bd9Sstevel@tonic-gate 				ch = ':';	/* / -> : */
15667c478bd9Sstevel@tonic-gate 			*p++ = ch;
15677c478bd9Sstevel@tonic-gate 		}
15687c478bd9Sstevel@tonic-gate 		if (elem >= t_host)
15697c478bd9Sstevel@tonic-gate 			*p++ = '.';
15707c478bd9Sstevel@tonic-gate 		*p = '\0';
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 	if (tTd(56, 80))
15737c478bd9Sstevel@tonic-gate 	{
15747c478bd9Sstevel@tonic-gate 		if (ret < 0)
15757c478bd9Sstevel@tonic-gate 			sm_dprintf("FAILURE %d\n", ret);
15767c478bd9Sstevel@tonic-gate 		else
15777c478bd9Sstevel@tonic-gate 			sm_dprintf("SUCCESS %s\n", path);
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate 	return ret;
15807c478bd9Sstevel@tonic-gate }
1581