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