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