xref: /illumos-gate/usr/src/cmd/sendmail/src/daemon.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
6*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
7*7c478bd9Sstevel@tonic-gate  *
8*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
9*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
10*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  */
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate #include <sendmail.h>
17*7c478bd9Sstevel@tonic-gate 
18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: daemon.c,v 8.658 2005/02/02 18:19:28 ca Exp $")
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
21*7c478bd9Sstevel@tonic-gate # define USE_SOCK_STREAM	1
22*7c478bd9Sstevel@tonic-gate #endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #if defined(USE_SOCK_STREAM)
25*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
26*7c478bd9Sstevel@tonic-gate #  include <arpa/inet.h>
27*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
28*7c478bd9Sstevel@tonic-gate # if NAMED_BIND
29*7c478bd9Sstevel@tonic-gate #  ifndef NO_DATA
30*7c478bd9Sstevel@tonic-gate #   define NO_DATA	NO_ADDRESS
31*7c478bd9Sstevel@tonic-gate #  endif /* ! NO_DATA */
32*7c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */
33*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_SOCK_STREAM) */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #if STARTTLS
36*7c478bd9Sstevel@tonic-gate #  include <openssl/rand.h>
37*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #if IP_SRCROUTE && NETINET
42*7c478bd9Sstevel@tonic-gate # include <netinet/in_systm.h>
43*7c478bd9Sstevel@tonic-gate # include <netinet/ip.h>
44*7c478bd9Sstevel@tonic-gate # if HAS_IN_H
45*7c478bd9Sstevel@tonic-gate #  include <netinet/in.h>
46*7c478bd9Sstevel@tonic-gate #  ifndef IPOPTION
47*7c478bd9Sstevel@tonic-gate #   define IPOPTION	ip_opts
48*7c478bd9Sstevel@tonic-gate #   define IP_LIST	ip_opts
49*7c478bd9Sstevel@tonic-gate #   define IP_DST	ip_dst
50*7c478bd9Sstevel@tonic-gate #  endif /* ! IPOPTION */
51*7c478bd9Sstevel@tonic-gate # else /* HAS_IN_H */
52*7c478bd9Sstevel@tonic-gate #  include <netinet/ip_var.h>
53*7c478bd9Sstevel@tonic-gate #  ifndef IPOPTION
54*7c478bd9Sstevel@tonic-gate #   define IPOPTION	ipoption
55*7c478bd9Sstevel@tonic-gate #   define IP_LIST	ipopt_list
56*7c478bd9Sstevel@tonic-gate #   define IP_DST	ipopt_dst
57*7c478bd9Sstevel@tonic-gate #  endif /* ! IPOPTION */
58*7c478bd9Sstevel@tonic-gate # endif /* HAS_IN_H */
59*7c478bd9Sstevel@tonic-gate #endif /* IP_SRCROUTE && NETINET */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <sm/fdset.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* structure to describe a daemon or a client */
64*7c478bd9Sstevel@tonic-gate struct daemon
65*7c478bd9Sstevel@tonic-gate {
66*7c478bd9Sstevel@tonic-gate 	int		d_socket;	/* fd for socket */
67*7c478bd9Sstevel@tonic-gate 	SOCKADDR	d_addr;		/* socket for incoming */
68*7c478bd9Sstevel@tonic-gate 	unsigned short	d_port;		/* port number */
69*7c478bd9Sstevel@tonic-gate 	int		d_listenqueue;	/* size of listen queue */
70*7c478bd9Sstevel@tonic-gate 	int		d_tcprcvbufsize;	/* size of TCP receive buffer */
71*7c478bd9Sstevel@tonic-gate 	int		d_tcpsndbufsize;	/* size of TCP send buffer */
72*7c478bd9Sstevel@tonic-gate 	time_t		d_refuse_connections_until;
73*7c478bd9Sstevel@tonic-gate 	bool		d_firsttime;
74*7c478bd9Sstevel@tonic-gate 	int		d_socksize;
75*7c478bd9Sstevel@tonic-gate 	BITMAP256	d_flags;	/* flags; see sendmail.h */
76*7c478bd9Sstevel@tonic-gate 	char		*d_mflags;	/* flags for use in macro */
77*7c478bd9Sstevel@tonic-gate 	char		*d_name;	/* user-supplied name */
78*7c478bd9Sstevel@tonic-gate #if MILTER
79*7c478bd9Sstevel@tonic-gate 	char		*d_inputfilterlist;
80*7c478bd9Sstevel@tonic-gate 	struct milter	*d_inputfilters[MAXFILTERS];
81*7c478bd9Sstevel@tonic-gate #endif /* MILTER */
82*7c478bd9Sstevel@tonic-gate #if _FFR_SS_PER_DAEMON
83*7c478bd9Sstevel@tonic-gate 	int		d_supersafe;
84*7c478bd9Sstevel@tonic-gate #endif /* _FFR_SS_PER_DAEMON */
85*7c478bd9Sstevel@tonic-gate #if _FFR_DM_PER_DAEMON
86*7c478bd9Sstevel@tonic-gate 	int		d_dm;	/* DeliveryMode */
87*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DM_PER_DAEMON */
88*7c478bd9Sstevel@tonic-gate };
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate typedef struct daemon DAEMON_T;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #define SAFE_NOTSET	(-1)	/* SuperSafe (per daemon) option not set */
93*7c478bd9Sstevel@tonic-gate /* see also sendmail.h: SuperSafe values */
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate #define DM_NOTSET	(-1)	/* DeliveryMode (per daemon) option not set */
96*7c478bd9Sstevel@tonic-gate /* see also sendmail.h: values for e_sendmode -- send modes */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate static void		connecttimeout __P((int));
99*7c478bd9Sstevel@tonic-gate static int		opendaemonsocket __P((DAEMON_T *, bool));
100*7c478bd9Sstevel@tonic-gate static unsigned short	setupdaemon __P((SOCKADDR *));
101*7c478bd9Sstevel@tonic-gate static void		getrequests_checkdiskspace __P((ENVELOPE *e));
102*7c478bd9Sstevel@tonic-gate static void		setsockaddroptions __P((char *, DAEMON_T *));
103*7c478bd9Sstevel@tonic-gate static void		printdaemonflags __P((DAEMON_T *));
104*7c478bd9Sstevel@tonic-gate static int		addr_family __P((char *));
105*7c478bd9Sstevel@tonic-gate static int		addrcmp __P((struct hostent *, char *, SOCKADDR *));
106*7c478bd9Sstevel@tonic-gate static void		authtimeout __P((int));
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate **  DAEMON.C -- routines to use when running as a daemon.
110*7c478bd9Sstevel@tonic-gate **
111*7c478bd9Sstevel@tonic-gate **	This entire file is highly dependent on the 4.2 BSD
112*7c478bd9Sstevel@tonic-gate **	interprocess communication primitives.  No attempt has
113*7c478bd9Sstevel@tonic-gate **	been made to make this file portable to Version 7,
114*7c478bd9Sstevel@tonic-gate **	Version 6, MPX files, etc.  If you should try such a
115*7c478bd9Sstevel@tonic-gate **	thing yourself, I recommend chucking the entire file
116*7c478bd9Sstevel@tonic-gate **	and starting from scratch.  Basic semantics are:
117*7c478bd9Sstevel@tonic-gate **
118*7c478bd9Sstevel@tonic-gate **	getrequests(e)
119*7c478bd9Sstevel@tonic-gate **		Opens a port and initiates a connection.
120*7c478bd9Sstevel@tonic-gate **		Returns in a child.  Must set InChannel and
121*7c478bd9Sstevel@tonic-gate **		OutChannel appropriately.
122*7c478bd9Sstevel@tonic-gate **	clrdaemon()
123*7c478bd9Sstevel@tonic-gate **		Close any open files associated with getting
124*7c478bd9Sstevel@tonic-gate **		the connection; this is used when running the queue,
125*7c478bd9Sstevel@tonic-gate **		etc., to avoid having extra file descriptors during
126*7c478bd9Sstevel@tonic-gate **		the queue run and to avoid confusing the network
127*7c478bd9Sstevel@tonic-gate **		code (if it cares).
128*7c478bd9Sstevel@tonic-gate **	makeconnection(host, port, mci, e, enough)
129*7c478bd9Sstevel@tonic-gate **		Make a connection to the named host on the given
130*7c478bd9Sstevel@tonic-gate **		port. Returns zero on success, else an exit status
131*7c478bd9Sstevel@tonic-gate **		describing the error.
132*7c478bd9Sstevel@tonic-gate **	host_map_lookup(map, hbuf, avp, pstat)
133*7c478bd9Sstevel@tonic-gate **		Convert the entry in hbuf into a canonical form.
134*7c478bd9Sstevel@tonic-gate */
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate static DAEMON_T	Daemons[MAXDAEMONS];
137*7c478bd9Sstevel@tonic-gate static int	NDaemons = 0;			/* actual number of daemons */
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static time_t	NextDiskSpaceCheck = 0;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate /*
142*7c478bd9Sstevel@tonic-gate **  GETREQUESTS -- open mail IPC port and get requests.
143*7c478bd9Sstevel@tonic-gate **
144*7c478bd9Sstevel@tonic-gate **	Parameters:
145*7c478bd9Sstevel@tonic-gate **		e -- the current envelope.
146*7c478bd9Sstevel@tonic-gate **
147*7c478bd9Sstevel@tonic-gate **	Returns:
148*7c478bd9Sstevel@tonic-gate **		pointer to flags.
149*7c478bd9Sstevel@tonic-gate **
150*7c478bd9Sstevel@tonic-gate **	Side Effects:
151*7c478bd9Sstevel@tonic-gate **		Waits until some interesting activity occurs.  When
152*7c478bd9Sstevel@tonic-gate **		it does, a child is created to process it, and the
153*7c478bd9Sstevel@tonic-gate **		parent waits for completion.  Return from this
154*7c478bd9Sstevel@tonic-gate **		routine is always in the child.  The file pointers
155*7c478bd9Sstevel@tonic-gate **		"InChannel" and "OutChannel" should be set to point
156*7c478bd9Sstevel@tonic-gate **		to the communication channel.
157*7c478bd9Sstevel@tonic-gate **		May restart persistent queue runners if they have ended
158*7c478bd9Sstevel@tonic-gate **		for some reason.
159*7c478bd9Sstevel@tonic-gate */
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate BITMAP256 *
162*7c478bd9Sstevel@tonic-gate getrequests(e)
163*7c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	int t;
166*7c478bd9Sstevel@tonic-gate 	int idx, curdaemon = -1;
167*7c478bd9Sstevel@tonic-gate 	int i, olddaemon = 0;
168*7c478bd9Sstevel@tonic-gate #if XDEBUG
169*7c478bd9Sstevel@tonic-gate 	bool j_has_dot;
170*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
171*7c478bd9Sstevel@tonic-gate 	char status[MAXLINE];
172*7c478bd9Sstevel@tonic-gate 	SOCKADDR sa;
173*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T len = sizeof sa;
174*7c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA
175*7c478bd9Sstevel@tonic-gate 	time_t lastrun;
176*7c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */
177*7c478bd9Sstevel@tonic-gate # if NETUNIX
178*7c478bd9Sstevel@tonic-gate 	extern int ControlSocket;
179*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
180*7c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
181*7c478bd9Sstevel@tonic-gate 	extern bool refuseconnections __P((char *, ENVELOPE *, int, bool));
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	/* initialize data for function that generates queue ids */
185*7c478bd9Sstevel@tonic-gate 	init_qid_alg();
186*7c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < NDaemons; idx++)
187*7c478bd9Sstevel@tonic-gate 	{
188*7c478bd9Sstevel@tonic-gate 		Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
189*7c478bd9Sstevel@tonic-gate 		Daemons[idx].d_firsttime = true;
190*7c478bd9Sstevel@tonic-gate 		Daemons[idx].d_refuse_connections_until = (time_t) 0;
191*7c478bd9Sstevel@tonic-gate 	}
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	/*
194*7c478bd9Sstevel@tonic-gate 	**  Try to actually open the connection.
195*7c478bd9Sstevel@tonic-gate 	*/
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	if (tTd(15, 1))
198*7c478bd9Sstevel@tonic-gate 	{
199*7c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < NDaemons; idx++)
200*7c478bd9Sstevel@tonic-gate 		{
201*7c478bd9Sstevel@tonic-gate 			sm_dprintf("getrequests: daemon %s: port %d\n",
202*7c478bd9Sstevel@tonic-gate 				   Daemons[idx].d_name,
203*7c478bd9Sstevel@tonic-gate 				   ntohs(Daemons[idx].d_port));
204*7c478bd9Sstevel@tonic-gate 		}
205*7c478bd9Sstevel@tonic-gate 	}
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	/* get a socket for the SMTP connection */
208*7c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < NDaemons; idx++)
209*7c478bd9Sstevel@tonic-gate 		Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true);
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	if (opencontrolsocket() < 0)
212*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_WARNING, NOQID,
213*7c478bd9Sstevel@tonic-gate 			  "daemon could not open control socket %s: %s",
214*7c478bd9Sstevel@tonic-gate 			  ControlSocketName, sm_errstring(errno));
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	/* If there are any queue runners released reapchild() co-ord's */
217*7c478bd9Sstevel@tonic-gate 	(void) sm_signal(SIGCHLD, reapchild);
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	/* write the pid to file, command line args to syslog */
220*7c478bd9Sstevel@tonic-gate 	log_sendmail_pid(e);
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate #if XDEBUG
223*7c478bd9Sstevel@tonic-gate 	{
224*7c478bd9Sstevel@tonic-gate 		char jbuf[MAXHOSTNAMELEN];
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 		expand("\201j", jbuf, sizeof jbuf, e);
227*7c478bd9Sstevel@tonic-gate 		j_has_dot = strchr(jbuf, '.') != NULL;
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/* Add parent process as first item */
232*7c478bd9Sstevel@tonic-gate 	proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL);
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if (tTd(15, 1))
235*7c478bd9Sstevel@tonic-gate 	{
236*7c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < NDaemons; idx++)
237*7c478bd9Sstevel@tonic-gate 			sm_dprintf("getrequests: daemon %s: %d\n",
238*7c478bd9Sstevel@tonic-gate 				Daemons[idx].d_name,
239*7c478bd9Sstevel@tonic-gate 				Daemons[idx].d_socket);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	for (;;)
243*7c478bd9Sstevel@tonic-gate 	{
244*7c478bd9Sstevel@tonic-gate 		register pid_t pid;
245*7c478bd9Sstevel@tonic-gate 		auto SOCKADDR_LEN_T lotherend;
246*7c478bd9Sstevel@tonic-gate 		bool timedout = false;
247*7c478bd9Sstevel@tonic-gate 		bool control = false;
248*7c478bd9Sstevel@tonic-gate 		int save_errno;
249*7c478bd9Sstevel@tonic-gate 		int pipefd[2];
250*7c478bd9Sstevel@tonic-gate 		time_t now;
251*7c478bd9Sstevel@tonic-gate #if STARTTLS
252*7c478bd9Sstevel@tonic-gate 		long seed;
253*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 		/* see if we are rejecting connections */
256*7c478bd9Sstevel@tonic-gate 		(void) sm_blocksignal(SIGALRM);
257*7c478bd9Sstevel@tonic-gate 		CHECK_RESTART;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < NDaemons; idx++)
260*7c478bd9Sstevel@tonic-gate 		{
261*7c478bd9Sstevel@tonic-gate 			/*
262*7c478bd9Sstevel@tonic-gate 			**  XXX do this call outside the loop?
263*7c478bd9Sstevel@tonic-gate 			**	no: refuse_connections may sleep().
264*7c478bd9Sstevel@tonic-gate 			*/
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 			now = curtime();
267*7c478bd9Sstevel@tonic-gate 			if (now < Daemons[idx].d_refuse_connections_until)
268*7c478bd9Sstevel@tonic-gate 				continue;
269*7c478bd9Sstevel@tonic-gate 			if (bitnset(D_DISABLE, Daemons[idx].d_flags))
270*7c478bd9Sstevel@tonic-gate 				continue;
271*7c478bd9Sstevel@tonic-gate 			if (refuseconnections(Daemons[idx].d_name, e, idx,
272*7c478bd9Sstevel@tonic-gate 					      curdaemon == idx))
273*7c478bd9Sstevel@tonic-gate 			{
274*7c478bd9Sstevel@tonic-gate 				if (Daemons[idx].d_socket >= 0)
275*7c478bd9Sstevel@tonic-gate 				{
276*7c478bd9Sstevel@tonic-gate 					/* close socket so peer fails quickly */
277*7c478bd9Sstevel@tonic-gate 					(void) close(Daemons[idx].d_socket);
278*7c478bd9Sstevel@tonic-gate 					Daemons[idx].d_socket = -1;
279*7c478bd9Sstevel@tonic-gate 				}
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 				/* refuse connections for next 15 seconds */
282*7c478bd9Sstevel@tonic-gate 				Daemons[idx].d_refuse_connections_until = now + 15;
283*7c478bd9Sstevel@tonic-gate 			}
284*7c478bd9Sstevel@tonic-gate 			else if (Daemons[idx].d_socket < 0 ||
285*7c478bd9Sstevel@tonic-gate 				 Daemons[idx].d_firsttime)
286*7c478bd9Sstevel@tonic-gate 			{
287*7c478bd9Sstevel@tonic-gate 				if (!Daemons[idx].d_firsttime && LogLevel > 8)
288*7c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, NOQID,
289*7c478bd9Sstevel@tonic-gate 						"accepting connections again for daemon %s",
290*7c478bd9Sstevel@tonic-gate 						Daemons[idx].d_name);
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 				/* arrange to (re)open the socket if needed */
293*7c478bd9Sstevel@tonic-gate 				(void) opendaemonsocket(&Daemons[idx], false);
294*7c478bd9Sstevel@tonic-gate 				Daemons[idx].d_firsttime = false;
295*7c478bd9Sstevel@tonic-gate 			}
296*7c478bd9Sstevel@tonic-gate 		}
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 		/* May have been sleeping above, check again */
299*7c478bd9Sstevel@tonic-gate 		CHECK_RESTART;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		getrequests_checkdiskspace(e);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate #if XDEBUG
304*7c478bd9Sstevel@tonic-gate 		/* check for disaster */
305*7c478bd9Sstevel@tonic-gate 		{
306*7c478bd9Sstevel@tonic-gate 			char jbuf[MAXHOSTNAMELEN];
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 			expand("\201j", jbuf, sizeof jbuf, e);
309*7c478bd9Sstevel@tonic-gate 			if (!wordinclass(jbuf, 'w'))
310*7c478bd9Sstevel@tonic-gate 			{
311*7c478bd9Sstevel@tonic-gate 				dumpstate("daemon lost $j");
312*7c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ALERT, NOQID,
313*7c478bd9Sstevel@tonic-gate 					  "daemon process doesn't have $j in $=w; see syslog");
314*7c478bd9Sstevel@tonic-gate 				abort();
315*7c478bd9Sstevel@tonic-gate 			}
316*7c478bd9Sstevel@tonic-gate 			else if (j_has_dot && strchr(jbuf, '.') == NULL)
317*7c478bd9Sstevel@tonic-gate 			{
318*7c478bd9Sstevel@tonic-gate 				dumpstate("daemon $j lost dot");
319*7c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ALERT, NOQID,
320*7c478bd9Sstevel@tonic-gate 					  "daemon process $j lost dot; see syslog");
321*7c478bd9Sstevel@tonic-gate 				abort();
322*7c478bd9Sstevel@tonic-gate 			}
323*7c478bd9Sstevel@tonic-gate 		}
324*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate #if 0
327*7c478bd9Sstevel@tonic-gate 		/*
328*7c478bd9Sstevel@tonic-gate 		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
329*7c478bd9Sstevel@tonic-gate 		**  fix the SVr4 problem.  But it seems to have gone away,
330*7c478bd9Sstevel@tonic-gate 		**  so is it worth doing this?
331*7c478bd9Sstevel@tonic-gate 		*/
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 		if (DaemonSocket >= 0 &&
334*7c478bd9Sstevel@tonic-gate 		    SetNonBlocking(DaemonSocket, false) < 0)
335*7c478bd9Sstevel@tonic-gate 			log an error here;
336*7c478bd9Sstevel@tonic-gate #endif /* 0 */
337*7c478bd9Sstevel@tonic-gate 		(void) sm_releasesignal(SIGALRM);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		for (;;)
340*7c478bd9Sstevel@tonic-gate 		{
341*7c478bd9Sstevel@tonic-gate 			bool setproc = false;
342*7c478bd9Sstevel@tonic-gate 			int highest = -1;
343*7c478bd9Sstevel@tonic-gate 			fd_set readfds;
344*7c478bd9Sstevel@tonic-gate 			struct timeval timeout;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 			CHECK_RESTART;
347*7c478bd9Sstevel@tonic-gate 			FD_ZERO(&readfds);
348*7c478bd9Sstevel@tonic-gate 			for (idx = 0; idx < NDaemons; idx++)
349*7c478bd9Sstevel@tonic-gate 			{
350*7c478bd9Sstevel@tonic-gate 				/* wait for a connection */
351*7c478bd9Sstevel@tonic-gate 				if (Daemons[idx].d_socket >= 0)
352*7c478bd9Sstevel@tonic-gate 				{
353*7c478bd9Sstevel@tonic-gate 					if (!setproc &&
354*7c478bd9Sstevel@tonic-gate 					    !bitnset(D_ETRNONLY,
355*7c478bd9Sstevel@tonic-gate 						     Daemons[idx].d_flags))
356*7c478bd9Sstevel@tonic-gate 					{
357*7c478bd9Sstevel@tonic-gate 						sm_setproctitle(true, e,
358*7c478bd9Sstevel@tonic-gate 								"accepting connections");
359*7c478bd9Sstevel@tonic-gate 						setproc = true;
360*7c478bd9Sstevel@tonic-gate 					}
361*7c478bd9Sstevel@tonic-gate 					if (Daemons[idx].d_socket > highest)
362*7c478bd9Sstevel@tonic-gate 						highest = Daemons[idx].d_socket;
363*7c478bd9Sstevel@tonic-gate 					SM_FD_SET(Daemons[idx].d_socket,
364*7c478bd9Sstevel@tonic-gate 						  &readfds);
365*7c478bd9Sstevel@tonic-gate 				}
366*7c478bd9Sstevel@tonic-gate 			}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate #if NETUNIX
369*7c478bd9Sstevel@tonic-gate 			if (ControlSocket >= 0)
370*7c478bd9Sstevel@tonic-gate 			{
371*7c478bd9Sstevel@tonic-gate 				if (ControlSocket > highest)
372*7c478bd9Sstevel@tonic-gate 					highest = ControlSocket;
373*7c478bd9Sstevel@tonic-gate 				SM_FD_SET(ControlSocket, &readfds);
374*7c478bd9Sstevel@tonic-gate 			}
375*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 			timeout.tv_sec = 5;
378*7c478bd9Sstevel@tonic-gate 			timeout.tv_usec = 0;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 			t = select(highest + 1, FDSET_CAST &readfds,
381*7c478bd9Sstevel@tonic-gate 				   NULL, NULL, &timeout);
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 			/* Did someone signal while waiting? */
384*7c478bd9Sstevel@tonic-gate 			CHECK_RESTART;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 			curdaemon = -1;
387*7c478bd9Sstevel@tonic-gate 			if (doqueuerun())
388*7c478bd9Sstevel@tonic-gate 			{
389*7c478bd9Sstevel@tonic-gate 				(void) runqueue(true, false, false, false);
390*7c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA
391*7c478bd9Sstevel@tonic-gate 				lastrun = now;
392*7c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA
395*7c478bd9Sstevel@tonic-gate 			else if (QueueIntvl > 0 &&
396*7c478bd9Sstevel@tonic-gate 				 lastrun + QueueIntvl + 60 < now)
397*7c478bd9Sstevel@tonic-gate 			{
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 				/*
400*7c478bd9Sstevel@tonic-gate 				**  set lastrun unconditionally to avoid
401*7c478bd9Sstevel@tonic-gate 				**  calling checkqueuerunner() all the time.
402*7c478bd9Sstevel@tonic-gate 				**  That's also why we currently ignore the
403*7c478bd9Sstevel@tonic-gate 				**  result of the function call.
404*7c478bd9Sstevel@tonic-gate 				*/
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 				(void) checkqueuerunner();
407*7c478bd9Sstevel@tonic-gate 				lastrun = now;
408*7c478bd9Sstevel@tonic-gate 			}
409*7c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 			if (t <= 0)
412*7c478bd9Sstevel@tonic-gate 			{
413*7c478bd9Sstevel@tonic-gate 				timedout = true;
414*7c478bd9Sstevel@tonic-gate 				break;
415*7c478bd9Sstevel@tonic-gate 			}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 			control = false;
418*7c478bd9Sstevel@tonic-gate 			errno = 0;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 			/* look "round-robin" for an active socket */
421*7c478bd9Sstevel@tonic-gate 			if ((idx = olddaemon + 1) >= NDaemons)
422*7c478bd9Sstevel@tonic-gate 				idx = 0;
423*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < NDaemons; i++)
424*7c478bd9Sstevel@tonic-gate 			{
425*7c478bd9Sstevel@tonic-gate 				if (Daemons[idx].d_socket >= 0 &&
426*7c478bd9Sstevel@tonic-gate 				    SM_FD_ISSET(Daemons[idx].d_socket,
427*7c478bd9Sstevel@tonic-gate 						&readfds))
428*7c478bd9Sstevel@tonic-gate 				{
429*7c478bd9Sstevel@tonic-gate 					lotherend = Daemons[idx].d_socksize;
430*7c478bd9Sstevel@tonic-gate 					memset(&RealHostAddr, '\0',
431*7c478bd9Sstevel@tonic-gate 					       sizeof RealHostAddr);
432*7c478bd9Sstevel@tonic-gate 					t = accept(Daemons[idx].d_socket,
433*7c478bd9Sstevel@tonic-gate 						   (struct sockaddr *)&RealHostAddr,
434*7c478bd9Sstevel@tonic-gate 						   &lotherend);
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 					/*
437*7c478bd9Sstevel@tonic-gate 					**  If remote side closes before
438*7c478bd9Sstevel@tonic-gate 					**  accept() finishes, sockaddr
439*7c478bd9Sstevel@tonic-gate 					**  might not be fully filled in.
440*7c478bd9Sstevel@tonic-gate 					*/
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 					if (t >= 0 &&
443*7c478bd9Sstevel@tonic-gate 					    (lotherend == 0 ||
444*7c478bd9Sstevel@tonic-gate # ifdef BSD4_4_SOCKADDR
445*7c478bd9Sstevel@tonic-gate 					     RealHostAddr.sa.sa_len == 0 ||
446*7c478bd9Sstevel@tonic-gate # endif /* BSD4_4_SOCKADDR */
447*7c478bd9Sstevel@tonic-gate 					     RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
448*7c478bd9Sstevel@tonic-gate 					{
449*7c478bd9Sstevel@tonic-gate 						(void) close(t);
450*7c478bd9Sstevel@tonic-gate 						t = -1;
451*7c478bd9Sstevel@tonic-gate 						errno = EINVAL;
452*7c478bd9Sstevel@tonic-gate 					}
453*7c478bd9Sstevel@tonic-gate 					olddaemon = curdaemon = idx;
454*7c478bd9Sstevel@tonic-gate 					break;
455*7c478bd9Sstevel@tonic-gate 				}
456*7c478bd9Sstevel@tonic-gate 				if (++idx >= NDaemons)
457*7c478bd9Sstevel@tonic-gate 					idx = 0;
458*7c478bd9Sstevel@tonic-gate 			}
459*7c478bd9Sstevel@tonic-gate #if NETUNIX
460*7c478bd9Sstevel@tonic-gate 			if (curdaemon == -1 && ControlSocket >= 0 &&
461*7c478bd9Sstevel@tonic-gate 			    SM_FD_ISSET(ControlSocket, &readfds))
462*7c478bd9Sstevel@tonic-gate 			{
463*7c478bd9Sstevel@tonic-gate 				struct sockaddr_un sa_un;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 				lotherend = sizeof sa_un;
466*7c478bd9Sstevel@tonic-gate 				memset(&sa_un, '\0', sizeof sa_un);
467*7c478bd9Sstevel@tonic-gate 				t = accept(ControlSocket,
468*7c478bd9Sstevel@tonic-gate 					   (struct sockaddr *)&sa_un,
469*7c478bd9Sstevel@tonic-gate 					   &lotherend);
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 				/*
472*7c478bd9Sstevel@tonic-gate 				**  If remote side closes before
473*7c478bd9Sstevel@tonic-gate 				**  accept() finishes, sockaddr
474*7c478bd9Sstevel@tonic-gate 				**  might not be fully filled in.
475*7c478bd9Sstevel@tonic-gate 				*/
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 				if (t >= 0 &&
478*7c478bd9Sstevel@tonic-gate 				    (lotherend == 0 ||
479*7c478bd9Sstevel@tonic-gate # ifdef BSD4_4_SOCKADDR
480*7c478bd9Sstevel@tonic-gate 				     sa_un.sun_len == 0 ||
481*7c478bd9Sstevel@tonic-gate # endif /* BSD4_4_SOCKADDR */
482*7c478bd9Sstevel@tonic-gate 				     sa_un.sun_family != AF_UNIX))
483*7c478bd9Sstevel@tonic-gate 				{
484*7c478bd9Sstevel@tonic-gate 					(void) close(t);
485*7c478bd9Sstevel@tonic-gate 					t = -1;
486*7c478bd9Sstevel@tonic-gate 					errno = EINVAL;
487*7c478bd9Sstevel@tonic-gate 				}
488*7c478bd9Sstevel@tonic-gate 				if (t >= 0)
489*7c478bd9Sstevel@tonic-gate 					control = true;
490*7c478bd9Sstevel@tonic-gate 			}
491*7c478bd9Sstevel@tonic-gate #else /* NETUNIX */
492*7c478bd9Sstevel@tonic-gate 			if (curdaemon == -1)
493*7c478bd9Sstevel@tonic-gate 			{
494*7c478bd9Sstevel@tonic-gate 				/* No daemon to service */
495*7c478bd9Sstevel@tonic-gate 				continue;
496*7c478bd9Sstevel@tonic-gate 			}
497*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
498*7c478bd9Sstevel@tonic-gate 			if (t >= 0 || errno != EINTR)
499*7c478bd9Sstevel@tonic-gate 				break;
500*7c478bd9Sstevel@tonic-gate 		}
501*7c478bd9Sstevel@tonic-gate 		if (timedout)
502*7c478bd9Sstevel@tonic-gate 		{
503*7c478bd9Sstevel@tonic-gate 			timedout = false;
504*7c478bd9Sstevel@tonic-gate 			continue;
505*7c478bd9Sstevel@tonic-gate 		}
506*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
507*7c478bd9Sstevel@tonic-gate 		(void) sm_blocksignal(SIGALRM);
508*7c478bd9Sstevel@tonic-gate 		if (t < 0)
509*7c478bd9Sstevel@tonic-gate 		{
510*7c478bd9Sstevel@tonic-gate 			errno = save_errno;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 			/* let's ignore these temporary errors */
513*7c478bd9Sstevel@tonic-gate 			if (save_errno == EINTR
514*7c478bd9Sstevel@tonic-gate #ifdef EAGAIN
515*7c478bd9Sstevel@tonic-gate 			    || save_errno == EAGAIN
516*7c478bd9Sstevel@tonic-gate #endif /* EAGAIN */
517*7c478bd9Sstevel@tonic-gate #ifdef ECONNABORTED
518*7c478bd9Sstevel@tonic-gate 			    || save_errno == ECONNABORTED
519*7c478bd9Sstevel@tonic-gate #endif /* ECONNABORTED */
520*7c478bd9Sstevel@tonic-gate #ifdef EWOULDBLOCK
521*7c478bd9Sstevel@tonic-gate 			    || save_errno == EWOULDBLOCK
522*7c478bd9Sstevel@tonic-gate #endif /* EWOULDBLOCK */
523*7c478bd9Sstevel@tonic-gate 			   )
524*7c478bd9Sstevel@tonic-gate 				continue;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 			syserr("getrequests: accept");
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 			/* arrange to re-open the socket next time around */
529*7c478bd9Sstevel@tonic-gate 			(void) close(Daemons[curdaemon].d_socket);
530*7c478bd9Sstevel@tonic-gate 			Daemons[curdaemon].d_socket = -1;
531*7c478bd9Sstevel@tonic-gate #if SO_REUSEADDR_IS_BROKEN
532*7c478bd9Sstevel@tonic-gate 			/*
533*7c478bd9Sstevel@tonic-gate 			**  Give time for bound socket to be released.
534*7c478bd9Sstevel@tonic-gate 			**  This creates a denial-of-service if you can
535*7c478bd9Sstevel@tonic-gate 			**  force accept() to fail on affected systems.
536*7c478bd9Sstevel@tonic-gate 			*/
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 			Daemons[curdaemon].d_refuse_connections_until = curtime() + 15;
539*7c478bd9Sstevel@tonic-gate #endif /* SO_REUSEADDR_IS_BROKEN */
540*7c478bd9Sstevel@tonic-gate 			continue;
541*7c478bd9Sstevel@tonic-gate 		}
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 		if (!control)
544*7c478bd9Sstevel@tonic-gate 		{
545*7c478bd9Sstevel@tonic-gate 			/* set some daemon related macros */
546*7c478bd9Sstevel@tonic-gate 			switch (Daemons[curdaemon].d_addr.sa.sa_family)
547*7c478bd9Sstevel@tonic-gate 			{
548*7c478bd9Sstevel@tonic-gate 			  case AF_UNSPEC:
549*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
550*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "unspec");
551*7c478bd9Sstevel@tonic-gate 				break;
552*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
553*7c478bd9Sstevel@tonic-gate # if NETUNIX
554*7c478bd9Sstevel@tonic-gate 			  case AF_UNIX:
555*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
556*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "local");
557*7c478bd9Sstevel@tonic-gate 				break;
558*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
559*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DAEMON_NETUNIX */
560*7c478bd9Sstevel@tonic-gate #if NETINET
561*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
562*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
563*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "inet");
564*7c478bd9Sstevel@tonic-gate 				break;
565*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
566*7c478bd9Sstevel@tonic-gate #if NETINET6
567*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
568*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
569*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "inet6");
570*7c478bd9Sstevel@tonic-gate 				break;
571*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
572*7c478bd9Sstevel@tonic-gate #if NETISO
573*7c478bd9Sstevel@tonic-gate 			  case AF_ISO:
574*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
575*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "iso");
576*7c478bd9Sstevel@tonic-gate 				break;
577*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
578*7c478bd9Sstevel@tonic-gate #if NETNS
579*7c478bd9Sstevel@tonic-gate 			  case AF_NS:
580*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
581*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "ns");
582*7c478bd9Sstevel@tonic-gate 				break;
583*7c478bd9Sstevel@tonic-gate #endif /* NETNS */
584*7c478bd9Sstevel@tonic-gate #if NETX25
585*7c478bd9Sstevel@tonic-gate 			  case AF_CCITT:
586*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
587*7c478bd9Sstevel@tonic-gate 					macid("{daemon_family}"), "x.25");
588*7c478bd9Sstevel@tonic-gate 				break;
589*7c478bd9Sstevel@tonic-gate #endif /* NETX25 */
590*7c478bd9Sstevel@tonic-gate 			}
591*7c478bd9Sstevel@tonic-gate 			macdefine(&BlankEnvelope.e_macro, A_PERM,
592*7c478bd9Sstevel@tonic-gate 				macid("{daemon_name}"),
593*7c478bd9Sstevel@tonic-gate 				Daemons[curdaemon].d_name);
594*7c478bd9Sstevel@tonic-gate 			if (Daemons[curdaemon].d_mflags != NULL)
595*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
596*7c478bd9Sstevel@tonic-gate 					macid("{daemon_flags}"),
597*7c478bd9Sstevel@tonic-gate 					Daemons[curdaemon].d_mflags);
598*7c478bd9Sstevel@tonic-gate 			else
599*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
600*7c478bd9Sstevel@tonic-gate 					macid("{daemon_flags}"), "");
601*7c478bd9Sstevel@tonic-gate 		}
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 		/*
604*7c478bd9Sstevel@tonic-gate 		**  If connection rate is exceeded here, connection shall be
605*7c478bd9Sstevel@tonic-gate 		**  refused later by a new call after fork() by the
606*7c478bd9Sstevel@tonic-gate 		**  validate_connection() function. Closing the connection
607*7c478bd9Sstevel@tonic-gate 		**  at this point violates RFC 2821.
608*7c478bd9Sstevel@tonic-gate 		**  Do NOT remove this call, its side effects are needed.
609*7c478bd9Sstevel@tonic-gate 		*/
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		connection_rate_check(&RealHostAddr, NULL);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 		/*
614*7c478bd9Sstevel@tonic-gate 		**  Create a subprocess to process the mail.
615*7c478bd9Sstevel@tonic-gate 		*/
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 		if (tTd(15, 2))
618*7c478bd9Sstevel@tonic-gate 			sm_dprintf("getrequests: forking (fd = %d)\n", t);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 		/*
621*7c478bd9Sstevel@tonic-gate 		**  Advance state of PRNG.
622*7c478bd9Sstevel@tonic-gate 		**  This is necessary because otherwise all child processes
623*7c478bd9Sstevel@tonic-gate 		**  will produce the same PRN sequence and hence the selection
624*7c478bd9Sstevel@tonic-gate 		**  of a queue directory (and other things, e.g., MX selection)
625*7c478bd9Sstevel@tonic-gate 		**  are not "really" random.
626*7c478bd9Sstevel@tonic-gate 		*/
627*7c478bd9Sstevel@tonic-gate #if STARTTLS
628*7c478bd9Sstevel@tonic-gate 		/* XXX get some better "random" data? */
629*7c478bd9Sstevel@tonic-gate 		seed = get_random();
630*7c478bd9Sstevel@tonic-gate 		RAND_seed((void *) &NextDiskSpaceCheck,
631*7c478bd9Sstevel@tonic-gate 			  sizeof NextDiskSpaceCheck);
632*7c478bd9Sstevel@tonic-gate 		RAND_seed((void *) &now, sizeof now);
633*7c478bd9Sstevel@tonic-gate 		RAND_seed((void *) &seed, sizeof seed);
634*7c478bd9Sstevel@tonic-gate #else /* STARTTLS */
635*7c478bd9Sstevel@tonic-gate 		(void) get_random();
636*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
639*7c478bd9Sstevel@tonic-gate 		/*
640*7c478bd9Sstevel@tonic-gate 		**  Update MX records for FallbackMX.
641*7c478bd9Sstevel@tonic-gate 		**  Let's hope this is fast otherwise we screw up the
642*7c478bd9Sstevel@tonic-gate 		**  response time.
643*7c478bd9Sstevel@tonic-gate 		*/
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 		if (FallbackMX != NULL)
646*7c478bd9Sstevel@tonic-gate 			(void) getfallbackmxrr(FallbackMX);
647*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 		if (tTd(93, 100))
650*7c478bd9Sstevel@tonic-gate 		{
651*7c478bd9Sstevel@tonic-gate 			/* don't fork, handle connection in this process */
652*7c478bd9Sstevel@tonic-gate 			pid = 0;
653*7c478bd9Sstevel@tonic-gate 			pipefd[0] = pipefd[1] = -1;
654*7c478bd9Sstevel@tonic-gate 		}
655*7c478bd9Sstevel@tonic-gate 		else
656*7c478bd9Sstevel@tonic-gate 		{
657*7c478bd9Sstevel@tonic-gate 			/*
658*7c478bd9Sstevel@tonic-gate 			**  Create a pipe to keep the child from writing to
659*7c478bd9Sstevel@tonic-gate 			**  the socket until after the parent has closed
660*7c478bd9Sstevel@tonic-gate 			**  it.  Otherwise the parent may hang if the child
661*7c478bd9Sstevel@tonic-gate 			**  has closed it first.
662*7c478bd9Sstevel@tonic-gate 			*/
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 			if (pipe(pipefd) < 0)
665*7c478bd9Sstevel@tonic-gate 				pipefd[0] = pipefd[1] = -1;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 			(void) sm_blocksignal(SIGCHLD);
668*7c478bd9Sstevel@tonic-gate 			pid = fork();
669*7c478bd9Sstevel@tonic-gate 			if (pid < 0)
670*7c478bd9Sstevel@tonic-gate 			{
671*7c478bd9Sstevel@tonic-gate 				syserr("daemon: cannot fork");
672*7c478bd9Sstevel@tonic-gate 				if (pipefd[0] != -1)
673*7c478bd9Sstevel@tonic-gate 				{
674*7c478bd9Sstevel@tonic-gate 					(void) close(pipefd[0]);
675*7c478bd9Sstevel@tonic-gate 					(void) close(pipefd[1]);
676*7c478bd9Sstevel@tonic-gate 				}
677*7c478bd9Sstevel@tonic-gate 				(void) sm_releasesignal(SIGCHLD);
678*7c478bd9Sstevel@tonic-gate 				(void) sleep(10);
679*7c478bd9Sstevel@tonic-gate 				(void) close(t);
680*7c478bd9Sstevel@tonic-gate 				continue;
681*7c478bd9Sstevel@tonic-gate 			}
682*7c478bd9Sstevel@tonic-gate 		}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		if (pid == 0)
685*7c478bd9Sstevel@tonic-gate 		{
686*7c478bd9Sstevel@tonic-gate 			char *p;
687*7c478bd9Sstevel@tonic-gate 			SM_FILE_T *inchannel, *outchannel = NULL;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 			/*
690*7c478bd9Sstevel@tonic-gate 			**  CHILD -- return to caller.
691*7c478bd9Sstevel@tonic-gate 			**	Collect verified idea of sending host.
692*7c478bd9Sstevel@tonic-gate 			**	Verify calling user id if possible here.
693*7c478bd9Sstevel@tonic-gate 			*/
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 			/* Reset global flags */
696*7c478bd9Sstevel@tonic-gate 			RestartRequest = NULL;
697*7c478bd9Sstevel@tonic-gate 			RestartWorkGroup = false;
698*7c478bd9Sstevel@tonic-gate 			ShutdownRequest = NULL;
699*7c478bd9Sstevel@tonic-gate 			PendingSignal = 0;
700*7c478bd9Sstevel@tonic-gate 			CurrentPid = getpid();
701*7c478bd9Sstevel@tonic-gate 			close_sendmail_pid();
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 			(void) sm_releasesignal(SIGALRM);
704*7c478bd9Sstevel@tonic-gate 			(void) sm_releasesignal(SIGCHLD);
705*7c478bd9Sstevel@tonic-gate 			(void) sm_signal(SIGCHLD, SIG_DFL);
706*7c478bd9Sstevel@tonic-gate 			(void) sm_signal(SIGHUP, SIG_DFL);
707*7c478bd9Sstevel@tonic-gate 			(void) sm_signal(SIGTERM, intsig);
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 			/* turn on profiling */
710*7c478bd9Sstevel@tonic-gate 			/* SM_PROF(0); */
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 			/*
713*7c478bd9Sstevel@tonic-gate 			**  Initialize exception stack and default exception
714*7c478bd9Sstevel@tonic-gate 			**  handler for child process.
715*7c478bd9Sstevel@tonic-gate 			*/
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 			sm_exc_newthread(fatal_error);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 			if (!control)
720*7c478bd9Sstevel@tonic-gate 			{
721*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
722*7c478bd9Sstevel@tonic-gate 					macid("{daemon_addr}"),
723*7c478bd9Sstevel@tonic-gate 					anynet_ntoa(&Daemons[curdaemon].d_addr));
724*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(status, sizeof status, "%d",
725*7c478bd9Sstevel@tonic-gate 						ntohs(Daemons[curdaemon].d_port));
726*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
727*7c478bd9Sstevel@tonic-gate 					macid("{daemon_port}"), status);
728*7c478bd9Sstevel@tonic-gate 			}
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 			for (idx = 0; idx < NDaemons; idx++)
731*7c478bd9Sstevel@tonic-gate 			{
732*7c478bd9Sstevel@tonic-gate 				if (Daemons[idx].d_socket >= 0)
733*7c478bd9Sstevel@tonic-gate 					(void) close(Daemons[idx].d_socket);
734*7c478bd9Sstevel@tonic-gate 				Daemons[idx].d_socket = -1;
735*7c478bd9Sstevel@tonic-gate 			}
736*7c478bd9Sstevel@tonic-gate 			clrcontrol();
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 			/* Avoid SMTP daemon actions if control command */
739*7c478bd9Sstevel@tonic-gate 			if (control)
740*7c478bd9Sstevel@tonic-gate 			{
741*7c478bd9Sstevel@tonic-gate 				/* Add control socket process */
742*7c478bd9Sstevel@tonic-gate 				proc_list_add(CurrentPid,
743*7c478bd9Sstevel@tonic-gate 					      "console socket child",
744*7c478bd9Sstevel@tonic-gate 					      PROC_CONTROL_CHILD, 0, -1, NULL);
745*7c478bd9Sstevel@tonic-gate 			}
746*7c478bd9Sstevel@tonic-gate 			else
747*7c478bd9Sstevel@tonic-gate 			{
748*7c478bd9Sstevel@tonic-gate 				proc_list_clear();
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 				/* clean up background delivery children */
751*7c478bd9Sstevel@tonic-gate 				(void) sm_signal(SIGCHLD, reapchild);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 				/* Add parent process as first child item */
754*7c478bd9Sstevel@tonic-gate 				proc_list_add(CurrentPid, "daemon child",
755*7c478bd9Sstevel@tonic-gate 					      PROC_DAEMON_CHILD, 0, -1, NULL);
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 				/* don't schedule queue runs if ETRN */
758*7c478bd9Sstevel@tonic-gate 				QueueIntvl = 0;
759*7c478bd9Sstevel@tonic-gate #if _FFR_SS_PER_DAEMON
760*7c478bd9Sstevel@tonic-gate 				if (Daemons[curdaemon].d_supersafe !=
761*7c478bd9Sstevel@tonic-gate 				    SAFE_NOTSET)
762*7c478bd9Sstevel@tonic-gate 					SuperSafe = Daemons[curdaemon].d_supersafe;
763*7c478bd9Sstevel@tonic-gate #endif /* _FFR_SS_PER_DAEMON */
764*7c478bd9Sstevel@tonic-gate #if _FFR_DM_PER_DAEMON
765*7c478bd9Sstevel@tonic-gate 				if (Daemons[curdaemon].d_dm != DM_NOTSET)
766*7c478bd9Sstevel@tonic-gate 					set_delivery_mode(
767*7c478bd9Sstevel@tonic-gate 						Daemons[curdaemon].d_dm, e);
768*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DM_PER_DAEMON */
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 				sm_setproctitle(true, e, "startup with %s",
772*7c478bd9Sstevel@tonic-gate 						anynet_ntoa(&RealHostAddr));
773*7c478bd9Sstevel@tonic-gate 			}
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 			if (pipefd[0] != -1)
776*7c478bd9Sstevel@tonic-gate 			{
777*7c478bd9Sstevel@tonic-gate 				auto char c;
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 				/*
780*7c478bd9Sstevel@tonic-gate 				**  Wait for the parent to close the write end
781*7c478bd9Sstevel@tonic-gate 				**  of the pipe, which we will see as an EOF.
782*7c478bd9Sstevel@tonic-gate 				**  This guarantees that we won't write to the
783*7c478bd9Sstevel@tonic-gate 				**  socket until after the parent has closed
784*7c478bd9Sstevel@tonic-gate 				**  the pipe.
785*7c478bd9Sstevel@tonic-gate 				*/
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 				/* close the write end of the pipe */
788*7c478bd9Sstevel@tonic-gate 				(void) close(pipefd[1]);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 				/* we shouldn't be interrupted, but ... */
791*7c478bd9Sstevel@tonic-gate 				while (read(pipefd[0], &c, 1) < 0 &&
792*7c478bd9Sstevel@tonic-gate 				       errno == EINTR)
793*7c478bd9Sstevel@tonic-gate 					continue;
794*7c478bd9Sstevel@tonic-gate 				(void) close(pipefd[0]);
795*7c478bd9Sstevel@tonic-gate 			}
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 			/* control socket processing */
798*7c478bd9Sstevel@tonic-gate 			if (control)
799*7c478bd9Sstevel@tonic-gate 			{
800*7c478bd9Sstevel@tonic-gate 				control_command(t, e);
801*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
802*7c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
803*7c478bd9Sstevel@tonic-gate 			}
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 			/* determine host name */
806*7c478bd9Sstevel@tonic-gate 			p = hostnamebyanyaddr(&RealHostAddr);
807*7c478bd9Sstevel@tonic-gate 			if (strlen(p) > MAXNAME) /* XXX  - 1 ? */
808*7c478bd9Sstevel@tonic-gate 				p[MAXNAME] = '\0';
809*7c478bd9Sstevel@tonic-gate 			RealHostName = newstr(p);
810*7c478bd9Sstevel@tonic-gate 			if (RealHostName[0] == '[')
811*7c478bd9Sstevel@tonic-gate 			{
812*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
813*7c478bd9Sstevel@tonic-gate 					macid("{client_resolve}"),
814*7c478bd9Sstevel@tonic-gate 					h_errno == TRY_AGAIN ? "TEMP" : "FAIL");
815*7c478bd9Sstevel@tonic-gate 			}
816*7c478bd9Sstevel@tonic-gate 			else
817*7c478bd9Sstevel@tonic-gate 			{
818*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
819*7c478bd9Sstevel@tonic-gate 					  macid("{client_resolve}"), "OK");
820*7c478bd9Sstevel@tonic-gate 			}
821*7c478bd9Sstevel@tonic-gate 			sm_setproctitle(true, e, "startup with %s", p);
822*7c478bd9Sstevel@tonic-gate 			markstats(e, NULL, STATS_CONNECT);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 			if ((inchannel = sm_io_open(SmFtStdiofd,
825*7c478bd9Sstevel@tonic-gate 						    SM_TIME_DEFAULT,
826*7c478bd9Sstevel@tonic-gate 						    (void *) &t,
827*7c478bd9Sstevel@tonic-gate 						    SM_IO_RDONLY_B,
828*7c478bd9Sstevel@tonic-gate 						    NULL)) == NULL ||
829*7c478bd9Sstevel@tonic-gate 			    (t = dup(t)) < 0 ||
830*7c478bd9Sstevel@tonic-gate 			    (outchannel = sm_io_open(SmFtStdiofd,
831*7c478bd9Sstevel@tonic-gate 						     SM_TIME_DEFAULT,
832*7c478bd9Sstevel@tonic-gate 						     (void *) &t,
833*7c478bd9Sstevel@tonic-gate 						     SM_IO_WRONLY_B,
834*7c478bd9Sstevel@tonic-gate 						     NULL)) == NULL)
835*7c478bd9Sstevel@tonic-gate 			{
836*7c478bd9Sstevel@tonic-gate 				syserr("cannot open SMTP server channel, fd=%d",
837*7c478bd9Sstevel@tonic-gate 					t);
838*7c478bd9Sstevel@tonic-gate 				finis(false, true, EX_OK);
839*7c478bd9Sstevel@tonic-gate 			}
840*7c478bd9Sstevel@tonic-gate 			sm_io_automode(inchannel, outchannel);
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 			InChannel = inchannel;
843*7c478bd9Sstevel@tonic-gate 			OutChannel = outchannel;
844*7c478bd9Sstevel@tonic-gate 			DisConnected = false;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate #if XLA
847*7c478bd9Sstevel@tonic-gate 			if (!xla_host_ok(RealHostName))
848*7c478bd9Sstevel@tonic-gate 			{
849*7c478bd9Sstevel@tonic-gate 				message("421 4.4.5 Too many SMTP sessions for this host");
850*7c478bd9Sstevel@tonic-gate 				finis(false, true, EX_OK);
851*7c478bd9Sstevel@tonic-gate 			}
852*7c478bd9Sstevel@tonic-gate #endif /* XLA */
853*7c478bd9Sstevel@tonic-gate 			/* find out name for interface of connection */
854*7c478bd9Sstevel@tonic-gate 			if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
855*7c478bd9Sstevel@tonic-gate 						      NULL), &sa.sa, &len) == 0)
856*7c478bd9Sstevel@tonic-gate 			{
857*7c478bd9Sstevel@tonic-gate 				p = hostnamebyanyaddr(&sa);
858*7c478bd9Sstevel@tonic-gate 				if (tTd(15, 9))
859*7c478bd9Sstevel@tonic-gate 					sm_dprintf("getreq: got name %s\n", p);
860*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
861*7c478bd9Sstevel@tonic-gate 					macid("{if_name}"), p);
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 				/*
864*7c478bd9Sstevel@tonic-gate 				**  Do this only if it is not the loopback
865*7c478bd9Sstevel@tonic-gate 				**  interface.
866*7c478bd9Sstevel@tonic-gate 				*/
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 				if (!isloopback(sa))
869*7c478bd9Sstevel@tonic-gate 				{
870*7c478bd9Sstevel@tonic-gate 					char *addr;
871*7c478bd9Sstevel@tonic-gate 					char family[5];
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 					addr = anynet_ntoa(&sa);
874*7c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(family,
875*7c478bd9Sstevel@tonic-gate 						sizeof(family),
876*7c478bd9Sstevel@tonic-gate 						"%d", sa.sa.sa_family);
877*7c478bd9Sstevel@tonic-gate 					macdefine(&BlankEnvelope.e_macro,
878*7c478bd9Sstevel@tonic-gate 						A_TEMP,
879*7c478bd9Sstevel@tonic-gate 						macid("{if_addr}"), addr);
880*7c478bd9Sstevel@tonic-gate 					macdefine(&BlankEnvelope.e_macro,
881*7c478bd9Sstevel@tonic-gate 						A_TEMP,
882*7c478bd9Sstevel@tonic-gate 						macid("{if_family}"), family);
883*7c478bd9Sstevel@tonic-gate 					if (tTd(15, 7))
884*7c478bd9Sstevel@tonic-gate 						sm_dprintf("getreq: got addr %s and family %s\n",
885*7c478bd9Sstevel@tonic-gate 							addr, family);
886*7c478bd9Sstevel@tonic-gate 				}
887*7c478bd9Sstevel@tonic-gate 				else
888*7c478bd9Sstevel@tonic-gate 				{
889*7c478bd9Sstevel@tonic-gate 					macdefine(&BlankEnvelope.e_macro,
890*7c478bd9Sstevel@tonic-gate 						A_PERM,
891*7c478bd9Sstevel@tonic-gate 						macid("{if_addr}"), NULL);
892*7c478bd9Sstevel@tonic-gate 					macdefine(&BlankEnvelope.e_macro,
893*7c478bd9Sstevel@tonic-gate 						A_PERM,
894*7c478bd9Sstevel@tonic-gate 						macid("{if_family}"), NULL);
895*7c478bd9Sstevel@tonic-gate 				}
896*7c478bd9Sstevel@tonic-gate 			}
897*7c478bd9Sstevel@tonic-gate 			else
898*7c478bd9Sstevel@tonic-gate 			{
899*7c478bd9Sstevel@tonic-gate 				if (tTd(15, 7))
900*7c478bd9Sstevel@tonic-gate 					sm_dprintf("getreq: getsockname failed\n");
901*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
902*7c478bd9Sstevel@tonic-gate 					macid("{if_name}"), NULL);
903*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
904*7c478bd9Sstevel@tonic-gate 					macid("{if_addr}"), NULL);
905*7c478bd9Sstevel@tonic-gate 				macdefine(&BlankEnvelope.e_macro, A_PERM,
906*7c478bd9Sstevel@tonic-gate 					macid("{if_family}"), NULL);
907*7c478bd9Sstevel@tonic-gate 			}
908*7c478bd9Sstevel@tonic-gate 			break;
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		/* parent -- keep track of children */
912*7c478bd9Sstevel@tonic-gate 		if (control)
913*7c478bd9Sstevel@tonic-gate 		{
914*7c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(status, sizeof status,
915*7c478bd9Sstevel@tonic-gate 					   "control socket server child");
916*7c478bd9Sstevel@tonic-gate 			proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL);
917*7c478bd9Sstevel@tonic-gate 		}
918*7c478bd9Sstevel@tonic-gate 		else
919*7c478bd9Sstevel@tonic-gate 		{
920*7c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(status, sizeof status,
921*7c478bd9Sstevel@tonic-gate 					   "SMTP server child for %s",
922*7c478bd9Sstevel@tonic-gate 					   anynet_ntoa(&RealHostAddr));
923*7c478bd9Sstevel@tonic-gate 			proc_list_add(pid, status, PROC_DAEMON, 0, -1,
924*7c478bd9Sstevel@tonic-gate 					&RealHostAddr);
925*7c478bd9Sstevel@tonic-gate 		}
926*7c478bd9Sstevel@tonic-gate 		(void) sm_releasesignal(SIGCHLD);
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 		/* close the read end of the synchronization pipe */
929*7c478bd9Sstevel@tonic-gate 		if (pipefd[0] != -1)
930*7c478bd9Sstevel@tonic-gate 		{
931*7c478bd9Sstevel@tonic-gate 			(void) close(pipefd[0]);
932*7c478bd9Sstevel@tonic-gate 			pipefd[0] = -1;
933*7c478bd9Sstevel@tonic-gate 		}
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 		/* close the port so that others will hang (for a while) */
936*7c478bd9Sstevel@tonic-gate 		(void) close(t);
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 		/* release the child by closing the read end of the sync pipe */
939*7c478bd9Sstevel@tonic-gate 		if (pipefd[1] != -1)
940*7c478bd9Sstevel@tonic-gate 		{
941*7c478bd9Sstevel@tonic-gate 			(void) close(pipefd[1]);
942*7c478bd9Sstevel@tonic-gate 			pipefd[1] = -1;
943*7c478bd9Sstevel@tonic-gate 		}
944*7c478bd9Sstevel@tonic-gate 	}
945*7c478bd9Sstevel@tonic-gate 	if (tTd(15, 2))
946*7c478bd9Sstevel@tonic-gate 		sm_dprintf("getreq: returning\n");
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate #if MILTER
949*7c478bd9Sstevel@tonic-gate 	/* set the filters for this daemon */
950*7c478bd9Sstevel@tonic-gate 	if (Daemons[curdaemon].d_inputfilterlist != NULL)
951*7c478bd9Sstevel@tonic-gate 	{
952*7c478bd9Sstevel@tonic-gate 		for (i = 0;
953*7c478bd9Sstevel@tonic-gate 		     (i < MAXFILTERS &&
954*7c478bd9Sstevel@tonic-gate 		      Daemons[curdaemon].d_inputfilters[i] != NULL);
955*7c478bd9Sstevel@tonic-gate 		     i++)
956*7c478bd9Sstevel@tonic-gate 		{
957*7c478bd9Sstevel@tonic-gate 			InputFilters[i] = Daemons[curdaemon].d_inputfilters[i];
958*7c478bd9Sstevel@tonic-gate 		}
959*7c478bd9Sstevel@tonic-gate 		if (i < MAXFILTERS)
960*7c478bd9Sstevel@tonic-gate 			InputFilters[i] = NULL;
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate #endif /* MILTER */
963*7c478bd9Sstevel@tonic-gate 	return &Daemons[curdaemon].d_flags;
964*7c478bd9Sstevel@tonic-gate }
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate /*
967*7c478bd9Sstevel@tonic-gate **  GETREQUESTS_CHECKDISKSPACE -- check available diskspace.
968*7c478bd9Sstevel@tonic-gate **
969*7c478bd9Sstevel@tonic-gate **	Parameters:
970*7c478bd9Sstevel@tonic-gate **		e -- envelope.
971*7c478bd9Sstevel@tonic-gate **
972*7c478bd9Sstevel@tonic-gate **	Returns:
973*7c478bd9Sstevel@tonic-gate **		none.
974*7c478bd9Sstevel@tonic-gate **
975*7c478bd9Sstevel@tonic-gate **	Side Effects:
976*7c478bd9Sstevel@tonic-gate **		Modifies Daemon flags (D_ETRNONLY) if not enough disk space.
977*7c478bd9Sstevel@tonic-gate */
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate static void
980*7c478bd9Sstevel@tonic-gate getrequests_checkdiskspace(e)
981*7c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
982*7c478bd9Sstevel@tonic-gate {
983*7c478bd9Sstevel@tonic-gate 	bool logged = false;
984*7c478bd9Sstevel@tonic-gate 	int idx;
985*7c478bd9Sstevel@tonic-gate 	time_t now;
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	now = curtime();
988*7c478bd9Sstevel@tonic-gate 	if (now < NextDiskSpaceCheck)
989*7c478bd9Sstevel@tonic-gate 		return;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	/* Check if there is available disk space in all queue groups. */
992*7c478bd9Sstevel@tonic-gate 	if (!enoughdiskspace(0, NULL))
993*7c478bd9Sstevel@tonic-gate 	{
994*7c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < NDaemons; ++idx)
995*7c478bd9Sstevel@tonic-gate 		{
996*7c478bd9Sstevel@tonic-gate 			if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
997*7c478bd9Sstevel@tonic-gate 				continue;
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 			/* log only if not logged before */
1000*7c478bd9Sstevel@tonic-gate 			if (!logged)
1001*7c478bd9Sstevel@tonic-gate 			{
1002*7c478bd9Sstevel@tonic-gate 				if (LogLevel > 8)
1003*7c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, NOQID,
1004*7c478bd9Sstevel@tonic-gate 						  "rejecting new messages: min free: %ld",
1005*7c478bd9Sstevel@tonic-gate 						  MinBlocksFree);
1006*7c478bd9Sstevel@tonic-gate 				sm_setproctitle(true, e,
1007*7c478bd9Sstevel@tonic-gate 						"rejecting new messages: min free: %ld",
1008*7c478bd9Sstevel@tonic-gate 						MinBlocksFree);
1009*7c478bd9Sstevel@tonic-gate 				logged = true;
1010*7c478bd9Sstevel@tonic-gate 			}
1011*7c478bd9Sstevel@tonic-gate 			setbitn(D_ETRNONLY, Daemons[idx].d_flags);
1012*7c478bd9Sstevel@tonic-gate 		}
1013*7c478bd9Sstevel@tonic-gate 	}
1014*7c478bd9Sstevel@tonic-gate 	else
1015*7c478bd9Sstevel@tonic-gate 	{
1016*7c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < NDaemons; ++idx)
1017*7c478bd9Sstevel@tonic-gate 		{
1018*7c478bd9Sstevel@tonic-gate 			if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
1019*7c478bd9Sstevel@tonic-gate 				continue;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 			/* log only if not logged before */
1022*7c478bd9Sstevel@tonic-gate 			if (!logged)
1023*7c478bd9Sstevel@tonic-gate 			{
1024*7c478bd9Sstevel@tonic-gate 				if (LogLevel > 8)
1025*7c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, NOQID,
1026*7c478bd9Sstevel@tonic-gate 						  "accepting new messages (again)");
1027*7c478bd9Sstevel@tonic-gate 				logged = true;
1028*7c478bd9Sstevel@tonic-gate 			}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 			/* title will be set later */
1031*7c478bd9Sstevel@tonic-gate 			clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
1032*7c478bd9Sstevel@tonic-gate 		}
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	/* only check disk space once a minute */
1036*7c478bd9Sstevel@tonic-gate 	NextDiskSpaceCheck = now + 60;
1037*7c478bd9Sstevel@tonic-gate }
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate /*
1040*7c478bd9Sstevel@tonic-gate **  OPENDAEMONSOCKET -- open SMTP socket
1041*7c478bd9Sstevel@tonic-gate **
1042*7c478bd9Sstevel@tonic-gate **	Deals with setting all appropriate options.
1043*7c478bd9Sstevel@tonic-gate **
1044*7c478bd9Sstevel@tonic-gate **	Parameters:
1045*7c478bd9Sstevel@tonic-gate **		d -- the structure for the daemon to open.
1046*7c478bd9Sstevel@tonic-gate **		firsttime -- set if this is the initial open.
1047*7c478bd9Sstevel@tonic-gate **
1048*7c478bd9Sstevel@tonic-gate **	Returns:
1049*7c478bd9Sstevel@tonic-gate **		Size in bytes of the daemon socket addr.
1050*7c478bd9Sstevel@tonic-gate **
1051*7c478bd9Sstevel@tonic-gate **	Side Effects:
1052*7c478bd9Sstevel@tonic-gate **		Leaves DaemonSocket set to the open socket.
1053*7c478bd9Sstevel@tonic-gate **		Exits if the socket cannot be created.
1054*7c478bd9Sstevel@tonic-gate */
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate #define MAXOPENTRIES	10	/* maximum number of tries to open connection */
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate static int
1059*7c478bd9Sstevel@tonic-gate opendaemonsocket(d, firsttime)
1060*7c478bd9Sstevel@tonic-gate 	DAEMON_T *d;
1061*7c478bd9Sstevel@tonic-gate 	bool firsttime;
1062*7c478bd9Sstevel@tonic-gate {
1063*7c478bd9Sstevel@tonic-gate 	int on = 1;
1064*7c478bd9Sstevel@tonic-gate 	int fdflags;
1065*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T socksize = 0;
1066*7c478bd9Sstevel@tonic-gate 	int ntries = 0;
1067*7c478bd9Sstevel@tonic-gate 	int save_errno;
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	if (tTd(15, 2))
1070*7c478bd9Sstevel@tonic-gate 		sm_dprintf("opendaemonsocket(%s)\n", d->d_name);
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	do
1073*7c478bd9Sstevel@tonic-gate 	{
1074*7c478bd9Sstevel@tonic-gate 		if (ntries > 0)
1075*7c478bd9Sstevel@tonic-gate 			(void) sleep(5);
1076*7c478bd9Sstevel@tonic-gate 		if (firsttime || d->d_socket < 0)
1077*7c478bd9Sstevel@tonic-gate 		{
1078*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
1079*7c478bd9Sstevel@tonic-gate # if NETUNIX
1080*7c478bd9Sstevel@tonic-gate 			if (d->d_addr.sa.sa_family == AF_UNIX)
1081*7c478bd9Sstevel@tonic-gate 			{
1082*7c478bd9Sstevel@tonic-gate 				int rval;
1083*7c478bd9Sstevel@tonic-gate 				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT;
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 				/* if not safe, don't use it */
1086*7c478bd9Sstevel@tonic-gate 				rval = safefile(d->d_addr.sunix.sun_path,
1087*7c478bd9Sstevel@tonic-gate 						RunAsUid, RunAsGid,
1088*7c478bd9Sstevel@tonic-gate 						RunAsUserName, sff,
1089*7c478bd9Sstevel@tonic-gate 						S_IRUSR|S_IWUSR, NULL);
1090*7c478bd9Sstevel@tonic-gate 				if (rval != 0)
1091*7c478bd9Sstevel@tonic-gate 				{
1092*7c478bd9Sstevel@tonic-gate 					save_errno = errno;
1093*7c478bd9Sstevel@tonic-gate 					syserr("opendaemonsocket: daemon %s: unsafe domain socket %s",
1094*7c478bd9Sstevel@tonic-gate 					       d->d_name,
1095*7c478bd9Sstevel@tonic-gate 					       d->d_addr.sunix.sun_path);
1096*7c478bd9Sstevel@tonic-gate 					goto fail;
1097*7c478bd9Sstevel@tonic-gate 				}
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 				/* Don't try to overtake an existing socket */
1100*7c478bd9Sstevel@tonic-gate 				(void) unlink(d->d_addr.sunix.sun_path);
1101*7c478bd9Sstevel@tonic-gate 			}
1102*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
1103*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DOMAIN_NETUNIX */
1104*7c478bd9Sstevel@tonic-gate 			d->d_socket = socket(d->d_addr.sa.sa_family,
1105*7c478bd9Sstevel@tonic-gate 					     SOCK_STREAM, 0);
1106*7c478bd9Sstevel@tonic-gate 			if (d->d_socket < 0)
1107*7c478bd9Sstevel@tonic-gate 			{
1108*7c478bd9Sstevel@tonic-gate 				save_errno = errno;
1109*7c478bd9Sstevel@tonic-gate 				syserr("opendaemonsocket: daemon %s: can't create server SMTP socket",
1110*7c478bd9Sstevel@tonic-gate 				       d->d_name);
1111*7c478bd9Sstevel@tonic-gate 			  fail:
1112*7c478bd9Sstevel@tonic-gate 				if (bitnset(D_OPTIONAL, d->d_flags) &&
1113*7c478bd9Sstevel@tonic-gate 				    (!transienterror(save_errno) ||
1114*7c478bd9Sstevel@tonic-gate 				     ntries >= MAXOPENTRIES - 1))
1115*7c478bd9Sstevel@tonic-gate 				{
1116*7c478bd9Sstevel@tonic-gate 					syserr("opendaemonsocket: daemon %s: optional socket disabled",
1117*7c478bd9Sstevel@tonic-gate 					       d->d_name);
1118*7c478bd9Sstevel@tonic-gate 					setbitn(D_DISABLE, d->d_flags);
1119*7c478bd9Sstevel@tonic-gate 					d->d_socket = -1;
1120*7c478bd9Sstevel@tonic-gate 					return -1;
1121*7c478bd9Sstevel@tonic-gate 				}
1122*7c478bd9Sstevel@tonic-gate 			  severe:
1123*7c478bd9Sstevel@tonic-gate 				if (LogLevel > 0)
1124*7c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ALERT, NOQID,
1125*7c478bd9Sstevel@tonic-gate 						  "daemon %s: problem creating SMTP socket",
1126*7c478bd9Sstevel@tonic-gate 						  d->d_name);
1127*7c478bd9Sstevel@tonic-gate 				d->d_socket = -1;
1128*7c478bd9Sstevel@tonic-gate 				continue;
1129*7c478bd9Sstevel@tonic-gate 			}
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 			if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE)
1132*7c478bd9Sstevel@tonic-gate 			{
1133*7c478bd9Sstevel@tonic-gate 				save_errno = EINVAL;
1134*7c478bd9Sstevel@tonic-gate 				syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large",
1135*7c478bd9Sstevel@tonic-gate 				       d->d_name, d->d_socket);
1136*7c478bd9Sstevel@tonic-gate 				goto fail;
1137*7c478bd9Sstevel@tonic-gate 			}
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 			/* turn on network debugging? */
1140*7c478bd9Sstevel@tonic-gate 			if (tTd(15, 101))
1141*7c478bd9Sstevel@tonic-gate 				(void) setsockopt(d->d_socket, SOL_SOCKET,
1142*7c478bd9Sstevel@tonic-gate 						  SO_DEBUG, (char *)&on,
1143*7c478bd9Sstevel@tonic-gate 						  sizeof on);
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 			(void) setsockopt(d->d_socket, SOL_SOCKET,
1146*7c478bd9Sstevel@tonic-gate 					  SO_REUSEADDR, (char *)&on, sizeof on);
1147*7c478bd9Sstevel@tonic-gate 			(void) setsockopt(d->d_socket, SOL_SOCKET,
1148*7c478bd9Sstevel@tonic-gate 					  SO_KEEPALIVE, (char *)&on, sizeof on);
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate #ifdef SO_RCVBUF
1151*7c478bd9Sstevel@tonic-gate 			if (d->d_tcprcvbufsize > 0)
1152*7c478bd9Sstevel@tonic-gate 			{
1153*7c478bd9Sstevel@tonic-gate 				if (setsockopt(d->d_socket, SOL_SOCKET,
1154*7c478bd9Sstevel@tonic-gate 					       SO_RCVBUF,
1155*7c478bd9Sstevel@tonic-gate 					       (char *) &d->d_tcprcvbufsize,
1156*7c478bd9Sstevel@tonic-gate 					       sizeof(d->d_tcprcvbufsize)) < 0)
1157*7c478bd9Sstevel@tonic-gate 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
1158*7c478bd9Sstevel@tonic-gate 			}
1159*7c478bd9Sstevel@tonic-gate #endif /* SO_RCVBUF */
1160*7c478bd9Sstevel@tonic-gate #ifdef SO_SNDBUF
1161*7c478bd9Sstevel@tonic-gate 			if (d->d_tcpsndbufsize > 0)
1162*7c478bd9Sstevel@tonic-gate 			{
1163*7c478bd9Sstevel@tonic-gate 				if (setsockopt(d->d_socket, SOL_SOCKET,
1164*7c478bd9Sstevel@tonic-gate 					       SO_SNDBUF,
1165*7c478bd9Sstevel@tonic-gate 					       (char *) &d->d_tcpsndbufsize,
1166*7c478bd9Sstevel@tonic-gate 					       sizeof(d->d_tcpsndbufsize)) < 0)
1167*7c478bd9Sstevel@tonic-gate 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
1168*7c478bd9Sstevel@tonic-gate 			}
1169*7c478bd9Sstevel@tonic-gate #endif /* SO_SNDBUF */
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 			if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
1172*7c478bd9Sstevel@tonic-gate 			    fcntl(d->d_socket, F_SETFD,
1173*7c478bd9Sstevel@tonic-gate 				  fdflags | FD_CLOEXEC) == -1)
1174*7c478bd9Sstevel@tonic-gate 			{
1175*7c478bd9Sstevel@tonic-gate 				save_errno = errno;
1176*7c478bd9Sstevel@tonic-gate 				syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
1177*7c478bd9Sstevel@tonic-gate 				       d->d_name,
1178*7c478bd9Sstevel@tonic-gate 				       fdflags == -1 ? "get" : "set",
1179*7c478bd9Sstevel@tonic-gate 				       sm_errstring(save_errno));
1180*7c478bd9Sstevel@tonic-gate 				(void) close(d->d_socket);
1181*7c478bd9Sstevel@tonic-gate 				goto severe;
1182*7c478bd9Sstevel@tonic-gate 			}
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 			switch (d->d_addr.sa.sa_family)
1185*7c478bd9Sstevel@tonic-gate 			{
1186*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
1187*7c478bd9Sstevel@tonic-gate # ifdef NETUNIX
1188*7c478bd9Sstevel@tonic-gate 			  case AF_UNIX:
1189*7c478bd9Sstevel@tonic-gate 				socksize = sizeof d->d_addr.sunix;
1190*7c478bd9Sstevel@tonic-gate 				break;
1191*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
1192*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DAEMON_NETUNIX */
1193*7c478bd9Sstevel@tonic-gate #if NETINET
1194*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
1195*7c478bd9Sstevel@tonic-gate 				socksize = sizeof d->d_addr.sin;
1196*7c478bd9Sstevel@tonic-gate 				break;
1197*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate #if NETINET6
1200*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
1201*7c478bd9Sstevel@tonic-gate 				socksize = sizeof d->d_addr.sin6;
1202*7c478bd9Sstevel@tonic-gate 				break;
1203*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate #if NETISO
1206*7c478bd9Sstevel@tonic-gate 			  case AF_ISO:
1207*7c478bd9Sstevel@tonic-gate 				socksize = sizeof d->d_addr.siso;
1208*7c478bd9Sstevel@tonic-gate 				break;
1209*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 			  default:
1212*7c478bd9Sstevel@tonic-gate 				socksize = sizeof d->d_addr;
1213*7c478bd9Sstevel@tonic-gate 				break;
1214*7c478bd9Sstevel@tonic-gate 			}
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 			if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
1217*7c478bd9Sstevel@tonic-gate 			{
1218*7c478bd9Sstevel@tonic-gate 				/* probably another daemon already */
1219*7c478bd9Sstevel@tonic-gate 				save_errno = errno;
1220*7c478bd9Sstevel@tonic-gate 				syserr("opendaemonsocket: daemon %s: cannot bind",
1221*7c478bd9Sstevel@tonic-gate 				       d->d_name);
1222*7c478bd9Sstevel@tonic-gate 				(void) close(d->d_socket);
1223*7c478bd9Sstevel@tonic-gate 				goto fail;
1224*7c478bd9Sstevel@tonic-gate 			}
1225*7c478bd9Sstevel@tonic-gate 		}
1226*7c478bd9Sstevel@tonic-gate 		if (!firsttime &&
1227*7c478bd9Sstevel@tonic-gate 		    listen(d->d_socket, d->d_listenqueue) < 0)
1228*7c478bd9Sstevel@tonic-gate 		{
1229*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
1230*7c478bd9Sstevel@tonic-gate 			syserr("opendaemonsocket: daemon %s: cannot listen",
1231*7c478bd9Sstevel@tonic-gate 			       d->d_name);
1232*7c478bd9Sstevel@tonic-gate 			(void) close(d->d_socket);
1233*7c478bd9Sstevel@tonic-gate 			goto severe;
1234*7c478bd9Sstevel@tonic-gate 		}
1235*7c478bd9Sstevel@tonic-gate 		return socksize;
1236*7c478bd9Sstevel@tonic-gate 	} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
1237*7c478bd9Sstevel@tonic-gate 	syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
1238*7c478bd9Sstevel@tonic-gate 	       d->d_name);
1239*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1240*7c478bd9Sstevel@tonic-gate 	return -1;  /* avoid compiler warning on IRIX */
1241*7c478bd9Sstevel@tonic-gate }
1242*7c478bd9Sstevel@tonic-gate /*
1243*7c478bd9Sstevel@tonic-gate **  SETUPDAEMON -- setup socket for daemon
1244*7c478bd9Sstevel@tonic-gate **
1245*7c478bd9Sstevel@tonic-gate **	Parameters:
1246*7c478bd9Sstevel@tonic-gate **		daemonaddr -- socket for daemon
1247*7c478bd9Sstevel@tonic-gate **
1248*7c478bd9Sstevel@tonic-gate **	Returns:
1249*7c478bd9Sstevel@tonic-gate **		port number on which daemon should run
1250*7c478bd9Sstevel@tonic-gate **
1251*7c478bd9Sstevel@tonic-gate */
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate static unsigned short
1254*7c478bd9Sstevel@tonic-gate setupdaemon(daemonaddr)
1255*7c478bd9Sstevel@tonic-gate 	SOCKADDR *daemonaddr;
1256*7c478bd9Sstevel@tonic-gate {
1257*7c478bd9Sstevel@tonic-gate 	unsigned short port;
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 	/*
1260*7c478bd9Sstevel@tonic-gate 	**  Set up the address for the mailer.
1261*7c478bd9Sstevel@tonic-gate 	*/
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	if (daemonaddr->sa.sa_family == AF_UNSPEC)
1264*7c478bd9Sstevel@tonic-gate 	{
1265*7c478bd9Sstevel@tonic-gate 		memset(daemonaddr, '\0', sizeof *daemonaddr);
1266*7c478bd9Sstevel@tonic-gate #if NETINET
1267*7c478bd9Sstevel@tonic-gate 		daemonaddr->sa.sa_family = AF_INET;
1268*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1269*7c478bd9Sstevel@tonic-gate 	}
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	switch (daemonaddr->sa.sa_family)
1272*7c478bd9Sstevel@tonic-gate 	{
1273*7c478bd9Sstevel@tonic-gate #if NETINET
1274*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
1275*7c478bd9Sstevel@tonic-gate 		if (daemonaddr->sin.sin_addr.s_addr == 0)
1276*7c478bd9Sstevel@tonic-gate 			daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
1277*7c478bd9Sstevel@tonic-gate 		port = daemonaddr->sin.sin_port;
1278*7c478bd9Sstevel@tonic-gate 		break;
1279*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate #if NETINET6
1282*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
1283*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
1284*7c478bd9Sstevel@tonic-gate 			daemonaddr->sin6.sin6_addr = in6addr_any;
1285*7c478bd9Sstevel@tonic-gate 		port = daemonaddr->sin6.sin6_port;
1286*7c478bd9Sstevel@tonic-gate 		break;
1287*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	  default:
1290*7c478bd9Sstevel@tonic-gate 		/* unknown protocol */
1291*7c478bd9Sstevel@tonic-gate 		port = 0;
1292*7c478bd9Sstevel@tonic-gate 		break;
1293*7c478bd9Sstevel@tonic-gate 	}
1294*7c478bd9Sstevel@tonic-gate 	if (port == 0)
1295*7c478bd9Sstevel@tonic-gate 	{
1296*7c478bd9Sstevel@tonic-gate #ifdef NO_GETSERVBYNAME
1297*7c478bd9Sstevel@tonic-gate 		port = htons(25);
1298*7c478bd9Sstevel@tonic-gate #else /* NO_GETSERVBYNAME */
1299*7c478bd9Sstevel@tonic-gate 		{
1300*7c478bd9Sstevel@tonic-gate 			register struct servent *sp;
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 			sp = getservbyname("smtp", "tcp");
1303*7c478bd9Sstevel@tonic-gate 			if (sp == NULL)
1304*7c478bd9Sstevel@tonic-gate 			{
1305*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 service \"smtp\" unknown");
1306*7c478bd9Sstevel@tonic-gate 				port = htons(25);
1307*7c478bd9Sstevel@tonic-gate 			}
1308*7c478bd9Sstevel@tonic-gate 			else
1309*7c478bd9Sstevel@tonic-gate 				port = sp->s_port;
1310*7c478bd9Sstevel@tonic-gate 		}
1311*7c478bd9Sstevel@tonic-gate #endif /* NO_GETSERVBYNAME */
1312*7c478bd9Sstevel@tonic-gate 	}
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	switch (daemonaddr->sa.sa_family)
1315*7c478bd9Sstevel@tonic-gate 	{
1316*7c478bd9Sstevel@tonic-gate #if NETINET
1317*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
1318*7c478bd9Sstevel@tonic-gate 		daemonaddr->sin.sin_port = port;
1319*7c478bd9Sstevel@tonic-gate 		break;
1320*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate #if NETINET6
1323*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
1324*7c478bd9Sstevel@tonic-gate 		daemonaddr->sin6.sin6_port = port;
1325*7c478bd9Sstevel@tonic-gate 		break;
1326*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	  default:
1329*7c478bd9Sstevel@tonic-gate 		/* unknown protocol */
1330*7c478bd9Sstevel@tonic-gate 		break;
1331*7c478bd9Sstevel@tonic-gate 	}
1332*7c478bd9Sstevel@tonic-gate 	return port;
1333*7c478bd9Sstevel@tonic-gate }
1334*7c478bd9Sstevel@tonic-gate /*
1335*7c478bd9Sstevel@tonic-gate **  CLRDAEMON -- reset the daemon connection
1336*7c478bd9Sstevel@tonic-gate **
1337*7c478bd9Sstevel@tonic-gate **	Parameters:
1338*7c478bd9Sstevel@tonic-gate **		none.
1339*7c478bd9Sstevel@tonic-gate **
1340*7c478bd9Sstevel@tonic-gate **	Returns:
1341*7c478bd9Sstevel@tonic-gate **		none.
1342*7c478bd9Sstevel@tonic-gate **
1343*7c478bd9Sstevel@tonic-gate **	Side Effects:
1344*7c478bd9Sstevel@tonic-gate **		releases any resources used by the passive daemon.
1345*7c478bd9Sstevel@tonic-gate */
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate void
1348*7c478bd9Sstevel@tonic-gate clrdaemon()
1349*7c478bd9Sstevel@tonic-gate {
1350*7c478bd9Sstevel@tonic-gate 	int i;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDaemons; i++)
1353*7c478bd9Sstevel@tonic-gate 	{
1354*7c478bd9Sstevel@tonic-gate 		if (Daemons[i].d_socket >= 0)
1355*7c478bd9Sstevel@tonic-gate 			(void) close(Daemons[i].d_socket);
1356*7c478bd9Sstevel@tonic-gate 		Daemons[i].d_socket = -1;
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate }
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate /*
1361*7c478bd9Sstevel@tonic-gate **  GETMODIFIERS -- get modifier flags
1362*7c478bd9Sstevel@tonic-gate **
1363*7c478bd9Sstevel@tonic-gate **	Parameters:
1364*7c478bd9Sstevel@tonic-gate **		v -- the modifiers (input text line).
1365*7c478bd9Sstevel@tonic-gate **		modifiers -- pointer to flag field to represent modifiers.
1366*7c478bd9Sstevel@tonic-gate **
1367*7c478bd9Sstevel@tonic-gate **	Returns:
1368*7c478bd9Sstevel@tonic-gate **		(xallocat()ed) string representation of modifiers.
1369*7c478bd9Sstevel@tonic-gate **
1370*7c478bd9Sstevel@tonic-gate **	Side Effects:
1371*7c478bd9Sstevel@tonic-gate **		fills in modifiers.
1372*7c478bd9Sstevel@tonic-gate */
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate char *
1375*7c478bd9Sstevel@tonic-gate getmodifiers(v, modifiers)
1376*7c478bd9Sstevel@tonic-gate 	char *v;
1377*7c478bd9Sstevel@tonic-gate 	BITMAP256 modifiers;
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	int l;
1380*7c478bd9Sstevel@tonic-gate 	char *h, *f, *flags;
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 	/* maximum length of flags: upper case Option -> "OO " */
1383*7c478bd9Sstevel@tonic-gate 	l = 3 * strlen(v) + 3;
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	/* is someone joking? */
1386*7c478bd9Sstevel@tonic-gate 	if (l < 0 || l > 256)
1387*7c478bd9Sstevel@tonic-gate 	{
1388*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 2)
1389*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, NOQID,
1390*7c478bd9Sstevel@tonic-gate 				  "getmodifiers too long, ignored");
1391*7c478bd9Sstevel@tonic-gate 		return NULL;
1392*7c478bd9Sstevel@tonic-gate 	}
1393*7c478bd9Sstevel@tonic-gate 	flags = xalloc(l);
1394*7c478bd9Sstevel@tonic-gate 	f = flags;
1395*7c478bd9Sstevel@tonic-gate 	clrbitmap(modifiers);
1396*7c478bd9Sstevel@tonic-gate 	for (h = v; *h != '\0'; h++)
1397*7c478bd9Sstevel@tonic-gate 	{
1398*7c478bd9Sstevel@tonic-gate 		if (isascii(*h) && !isspace(*h) && isprint(*h))
1399*7c478bd9Sstevel@tonic-gate 		{
1400*7c478bd9Sstevel@tonic-gate 			setbitn(*h, modifiers);
1401*7c478bd9Sstevel@tonic-gate 			if (flags != f)
1402*7c478bd9Sstevel@tonic-gate 				*flags++ = ' ';
1403*7c478bd9Sstevel@tonic-gate 			*flags++ = *h;
1404*7c478bd9Sstevel@tonic-gate 			if (isupper(*h))
1405*7c478bd9Sstevel@tonic-gate 				*flags++ = *h;
1406*7c478bd9Sstevel@tonic-gate 		}
1407*7c478bd9Sstevel@tonic-gate 	}
1408*7c478bd9Sstevel@tonic-gate 	*flags++ = '\0';
1409*7c478bd9Sstevel@tonic-gate 	return f;
1410*7c478bd9Sstevel@tonic-gate }
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate /*
1413*7c478bd9Sstevel@tonic-gate **  CHKDAEMONMODIFIERS -- check whether all daemons have set a flag.
1414*7c478bd9Sstevel@tonic-gate **
1415*7c478bd9Sstevel@tonic-gate **	Parameters:
1416*7c478bd9Sstevel@tonic-gate **		flag -- the flag to test.
1417*7c478bd9Sstevel@tonic-gate **
1418*7c478bd9Sstevel@tonic-gate **	Returns:
1419*7c478bd9Sstevel@tonic-gate **		true iff all daemons have set flag.
1420*7c478bd9Sstevel@tonic-gate */
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate bool
1423*7c478bd9Sstevel@tonic-gate chkdaemonmodifiers(flag)
1424*7c478bd9Sstevel@tonic-gate 	int flag;
1425*7c478bd9Sstevel@tonic-gate {
1426*7c478bd9Sstevel@tonic-gate 	int i;
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDaemons; i++)
1429*7c478bd9Sstevel@tonic-gate 		if (!bitnset((char) flag, Daemons[i].d_flags))
1430*7c478bd9Sstevel@tonic-gate 			return false;
1431*7c478bd9Sstevel@tonic-gate 	return true;
1432*7c478bd9Sstevel@tonic-gate }
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate /*
1435*7c478bd9Sstevel@tonic-gate **  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
1436*7c478bd9Sstevel@tonic-gate **
1437*7c478bd9Sstevel@tonic-gate **	Parameters:
1438*7c478bd9Sstevel@tonic-gate **		p -- the options line.
1439*7c478bd9Sstevel@tonic-gate **		d -- the daemon structure to fill in.
1440*7c478bd9Sstevel@tonic-gate **
1441*7c478bd9Sstevel@tonic-gate **	Returns:
1442*7c478bd9Sstevel@tonic-gate **		none.
1443*7c478bd9Sstevel@tonic-gate */
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate static void
1446*7c478bd9Sstevel@tonic-gate setsockaddroptions(p, d)
1447*7c478bd9Sstevel@tonic-gate 	char *p;
1448*7c478bd9Sstevel@tonic-gate 	DAEMON_T *d;
1449*7c478bd9Sstevel@tonic-gate {
1450*7c478bd9Sstevel@tonic-gate #if NETISO
1451*7c478bd9Sstevel@tonic-gate 	short portno;
1452*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
1453*7c478bd9Sstevel@tonic-gate 	char *port = NULL;
1454*7c478bd9Sstevel@tonic-gate 	char *addr = NULL;
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate #if NETINET
1457*7c478bd9Sstevel@tonic-gate 	if (d->d_addr.sa.sa_family == AF_UNSPEC)
1458*7c478bd9Sstevel@tonic-gate 		d->d_addr.sa.sa_family = AF_INET;
1459*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	while (p != NULL)
1462*7c478bd9Sstevel@tonic-gate 	{
1463*7c478bd9Sstevel@tonic-gate 		register char *f;
1464*7c478bd9Sstevel@tonic-gate 		register char *v;
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 		while (isascii(*p) && isspace(*p))
1467*7c478bd9Sstevel@tonic-gate 			p++;
1468*7c478bd9Sstevel@tonic-gate 		if (*p == '\0')
1469*7c478bd9Sstevel@tonic-gate 			break;
1470*7c478bd9Sstevel@tonic-gate 		f = p;
1471*7c478bd9Sstevel@tonic-gate 		p = strchr(p, ',');
1472*7c478bd9Sstevel@tonic-gate 		if (p != NULL)
1473*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
1474*7c478bd9Sstevel@tonic-gate 		v = strchr(f, '=');
1475*7c478bd9Sstevel@tonic-gate 		if (v == NULL)
1476*7c478bd9Sstevel@tonic-gate 			continue;
1477*7c478bd9Sstevel@tonic-gate 		while (isascii(*++v) && isspace(*v))
1478*7c478bd9Sstevel@tonic-gate 			continue;
1479*7c478bd9Sstevel@tonic-gate 		if (isascii(*f) && islower(*f))
1480*7c478bd9Sstevel@tonic-gate 			*f = toupper(*f);
1481*7c478bd9Sstevel@tonic-gate #if _FFR_SS_PER_DAEMON
1482*7c478bd9Sstevel@tonic-gate 		d->d_supersafe = SAFE_NOTSET;
1483*7c478bd9Sstevel@tonic-gate #endif /* _FFR_SS_PER_DAEMON */
1484*7c478bd9Sstevel@tonic-gate #if _FFR_DM_PER_DAEMON
1485*7c478bd9Sstevel@tonic-gate 		d->d_dm = DM_NOTSET;
1486*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DM_PER_DAEMON */
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 		switch (*f)
1489*7c478bd9Sstevel@tonic-gate 		{
1490*7c478bd9Sstevel@tonic-gate 		  case 'A':		/* address */
1491*7c478bd9Sstevel@tonic-gate 			addr = v;
1492*7c478bd9Sstevel@tonic-gate 			break;
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate #if _FFR_DM_PER_DAEMON
1495*7c478bd9Sstevel@tonic-gate 		  case 'D':		/* DeliveryMode */
1496*7c478bd9Sstevel@tonic-gate 			switch (*v)
1497*7c478bd9Sstevel@tonic-gate 			{
1498*7c478bd9Sstevel@tonic-gate 			  case SM_QUEUE:
1499*7c478bd9Sstevel@tonic-gate 			  case SM_DEFER:
1500*7c478bd9Sstevel@tonic-gate 			  case SM_DELIVER:
1501*7c478bd9Sstevel@tonic-gate 			  case SM_FORK:
1502*7c478bd9Sstevel@tonic-gate 				d->d_dm = *v;
1503*7c478bd9Sstevel@tonic-gate 				break;
1504*7c478bd9Sstevel@tonic-gate 			  default:
1505*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 Unknown delivery mode %c",
1506*7c478bd9Sstevel@tonic-gate 					*v);
1507*7c478bd9Sstevel@tonic-gate 				break;
1508*7c478bd9Sstevel@tonic-gate 			}
1509*7c478bd9Sstevel@tonic-gate 			break;
1510*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DM_PER_DAEMON */
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate 		  case 'F':		/* address family */
1513*7c478bd9Sstevel@tonic-gate 			if (isascii(*v) && isdigit(*v))
1514*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = atoi(v);
1515*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
1516*7c478bd9Sstevel@tonic-gate # ifdef NETUNIX
1517*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "unix") == 0 ||
1518*7c478bd9Sstevel@tonic-gate 				 sm_strcasecmp(v, "local") == 0)
1519*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_UNIX;
1520*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
1521*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DAEMON_NETUNIX */
1522*7c478bd9Sstevel@tonic-gate #if NETINET
1523*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "inet") == 0)
1524*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_INET;
1525*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1526*7c478bd9Sstevel@tonic-gate #if NETINET6
1527*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "inet6") == 0)
1528*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_INET6;
1529*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1530*7c478bd9Sstevel@tonic-gate #if NETISO
1531*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "iso") == 0)
1532*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_ISO;
1533*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
1534*7c478bd9Sstevel@tonic-gate #if NETNS
1535*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "ns") == 0)
1536*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_NS;
1537*7c478bd9Sstevel@tonic-gate #endif /* NETNS */
1538*7c478bd9Sstevel@tonic-gate #if NETX25
1539*7c478bd9Sstevel@tonic-gate 			else if (sm_strcasecmp(v, "x.25") == 0)
1540*7c478bd9Sstevel@tonic-gate 				d->d_addr.sa.sa_family = AF_CCITT;
1541*7c478bd9Sstevel@tonic-gate #endif /* NETX25 */
1542*7c478bd9Sstevel@tonic-gate 			else
1543*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 Unknown address family %s in Family=option",
1544*7c478bd9Sstevel@tonic-gate 				       v);
1545*7c478bd9Sstevel@tonic-gate 			break;
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate #if MILTER
1548*7c478bd9Sstevel@tonic-gate 		  case 'I':
1549*7c478bd9Sstevel@tonic-gate 			d->d_inputfilterlist = v;
1550*7c478bd9Sstevel@tonic-gate 			break;
1551*7c478bd9Sstevel@tonic-gate #endif /* MILTER */
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate 		  case 'L':		/* listen queue size */
1554*7c478bd9Sstevel@tonic-gate 			d->d_listenqueue = atoi(v);
1555*7c478bd9Sstevel@tonic-gate 			break;
1556*7c478bd9Sstevel@tonic-gate 
1557*7c478bd9Sstevel@tonic-gate 		  case 'M':		/* modifiers (flags) */
1558*7c478bd9Sstevel@tonic-gate 			d->d_mflags = getmodifiers(v, d->d_flags);
1559*7c478bd9Sstevel@tonic-gate 			break;
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate 		  case 'N':		/* name */
1562*7c478bd9Sstevel@tonic-gate 			d->d_name = v;
1563*7c478bd9Sstevel@tonic-gate 			break;
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 		  case 'P':		/* port */
1566*7c478bd9Sstevel@tonic-gate 			port = v;
1567*7c478bd9Sstevel@tonic-gate 			break;
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 		  case 'R':		/* receive buffer size */
1570*7c478bd9Sstevel@tonic-gate 			d->d_tcprcvbufsize = atoi(v);
1571*7c478bd9Sstevel@tonic-gate 			break;
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 		  case 'S':		/* send buffer size */
1574*7c478bd9Sstevel@tonic-gate 			d->d_tcpsndbufsize = atoi(v);
1575*7c478bd9Sstevel@tonic-gate 			break;
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate #if _FFR_SS_PER_DAEMON
1578*7c478bd9Sstevel@tonic-gate 		  case 'T':		/* SuperSafe */
1579*7c478bd9Sstevel@tonic-gate 			if (tolower(*v) == 'i')
1580*7c478bd9Sstevel@tonic-gate 				d->d_supersafe = SAFE_INTERACTIVE;
1581*7c478bd9Sstevel@tonic-gate 			else if (tolower(*v) == 'p')
1582*7c478bd9Sstevel@tonic-gate # if MILTER
1583*7c478bd9Sstevel@tonic-gate 				d->d_supersafe = SAFE_REALLY_POSTMILTER;
1584*7c478bd9Sstevel@tonic-gate # else /* MILTER */
1585*7c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1586*7c478bd9Sstevel@tonic-gate 					"Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
1587*7c478bd9Sstevel@tonic-gate # endif /* MILTER */
1588*7c478bd9Sstevel@tonic-gate 			else
1589*7c478bd9Sstevel@tonic-gate 				d->d_supersafe = atobool(v) ? SAFE_REALLY
1590*7c478bd9Sstevel@tonic-gate 							: SAFE_NO;
1591*7c478bd9Sstevel@tonic-gate 			break;
1592*7c478bd9Sstevel@tonic-gate #endif /* _FFR_SS_PER_DAEMON */
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 		  default:
1595*7c478bd9Sstevel@tonic-gate 			syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
1596*7c478bd9Sstevel@tonic-gate 			       f);
1597*7c478bd9Sstevel@tonic-gate 		}
1598*7c478bd9Sstevel@tonic-gate 	}
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	/* Check addr and port after finding family */
1601*7c478bd9Sstevel@tonic-gate 	if (addr != NULL)
1602*7c478bd9Sstevel@tonic-gate 	{
1603*7c478bd9Sstevel@tonic-gate 		switch (d->d_addr.sa.sa_family)
1604*7c478bd9Sstevel@tonic-gate 		{
1605*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
1606*7c478bd9Sstevel@tonic-gate # if NETUNIX
1607*7c478bd9Sstevel@tonic-gate 		  case AF_UNIX:
1608*7c478bd9Sstevel@tonic-gate 			if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path))
1609*7c478bd9Sstevel@tonic-gate 			{
1610*7c478bd9Sstevel@tonic-gate 				errno = ENAMETOOLONG;
1611*7c478bd9Sstevel@tonic-gate 				syserr("setsockaddroptions: domain socket name too long: %s > %d",
1612*7c478bd9Sstevel@tonic-gate 				       addr, sizeof(d->d_addr.sunix.sun_path));
1613*7c478bd9Sstevel@tonic-gate 				break;
1614*7c478bd9Sstevel@tonic-gate 			}
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 			/* file safety check done in opendaemonsocket() */
1617*7c478bd9Sstevel@tonic-gate 			(void) memset(&d->d_addr.sunix.sun_path, '\0',
1618*7c478bd9Sstevel@tonic-gate 				      sizeof(d->d_addr.sunix.sun_path));
1619*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path,
1620*7c478bd9Sstevel@tonic-gate 					  addr,
1621*7c478bd9Sstevel@tonic-gate 					  sizeof(d->d_addr.sunix.sun_path));
1622*7c478bd9Sstevel@tonic-gate 			break;
1623*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
1624*7c478bd9Sstevel@tonic-gate #endif	/* _FFR_DAEMON_NETUNIX */
1625*7c478bd9Sstevel@tonic-gate #if NETINET
1626*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
1627*7c478bd9Sstevel@tonic-gate 			if (!isascii(*addr) || !isdigit(*addr) ||
1628*7c478bd9Sstevel@tonic-gate 			    ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr))
1629*7c478bd9Sstevel@tonic-gate 			     == INADDR_NONE))
1630*7c478bd9Sstevel@tonic-gate 			{
1631*7c478bd9Sstevel@tonic-gate 				register struct hostent *hp;
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 				hp = sm_gethostbyname(addr, AF_INET);
1634*7c478bd9Sstevel@tonic-gate 				if (hp == NULL)
1635*7c478bd9Sstevel@tonic-gate 					syserr("554 5.3.0 host \"%s\" unknown",
1636*7c478bd9Sstevel@tonic-gate 					       addr);
1637*7c478bd9Sstevel@tonic-gate 				else
1638*7c478bd9Sstevel@tonic-gate 				{
1639*7c478bd9Sstevel@tonic-gate 					while (*(hp->h_addr_list) != NULL &&
1640*7c478bd9Sstevel@tonic-gate 					       hp->h_addrtype != AF_INET)
1641*7c478bd9Sstevel@tonic-gate 						hp->h_addr_list++;
1642*7c478bd9Sstevel@tonic-gate 					if (*(hp->h_addr_list) == NULL)
1643*7c478bd9Sstevel@tonic-gate 						syserr("554 5.3.0 host \"%s\" unknown",
1644*7c478bd9Sstevel@tonic-gate 						       addr);
1645*7c478bd9Sstevel@tonic-gate 					else
1646*7c478bd9Sstevel@tonic-gate 						memmove(&d->d_addr.sin.sin_addr,
1647*7c478bd9Sstevel@tonic-gate 							*(hp->h_addr_list),
1648*7c478bd9Sstevel@tonic-gate 							INADDRSZ);
1649*7c478bd9Sstevel@tonic-gate # if NETINET6
1650*7c478bd9Sstevel@tonic-gate 					freehostent(hp);
1651*7c478bd9Sstevel@tonic-gate 					hp = NULL;
1652*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1653*7c478bd9Sstevel@tonic-gate 				}
1654*7c478bd9Sstevel@tonic-gate 			}
1655*7c478bd9Sstevel@tonic-gate 			break;
1656*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate #if NETINET6
1659*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
1660*7c478bd9Sstevel@tonic-gate 			if (anynet_pton(AF_INET6, addr,
1661*7c478bd9Sstevel@tonic-gate 					&d->d_addr.sin6.sin6_addr) != 1)
1662*7c478bd9Sstevel@tonic-gate 			{
1663*7c478bd9Sstevel@tonic-gate 				register struct hostent *hp;
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate 				hp = sm_gethostbyname(addr, AF_INET6);
1666*7c478bd9Sstevel@tonic-gate 				if (hp == NULL)
1667*7c478bd9Sstevel@tonic-gate 					syserr("554 5.3.0 host \"%s\" unknown",
1668*7c478bd9Sstevel@tonic-gate 					       addr);
1669*7c478bd9Sstevel@tonic-gate 				else
1670*7c478bd9Sstevel@tonic-gate 				{
1671*7c478bd9Sstevel@tonic-gate 					while (*(hp->h_addr_list) != NULL &&
1672*7c478bd9Sstevel@tonic-gate 					       hp->h_addrtype != AF_INET6)
1673*7c478bd9Sstevel@tonic-gate 						hp->h_addr_list++;
1674*7c478bd9Sstevel@tonic-gate 					if (*(hp->h_addr_list) == NULL)
1675*7c478bd9Sstevel@tonic-gate 						syserr("554 5.3.0 host \"%s\" unknown",
1676*7c478bd9Sstevel@tonic-gate 						       addr);
1677*7c478bd9Sstevel@tonic-gate 					else
1678*7c478bd9Sstevel@tonic-gate 						memmove(&d->d_addr.sin6.sin6_addr,
1679*7c478bd9Sstevel@tonic-gate 							*(hp->h_addr_list),
1680*7c478bd9Sstevel@tonic-gate 							IN6ADDRSZ);
1681*7c478bd9Sstevel@tonic-gate 					freehostent(hp);
1682*7c478bd9Sstevel@tonic-gate 					hp = NULL;
1683*7c478bd9Sstevel@tonic-gate 				}
1684*7c478bd9Sstevel@tonic-gate 			}
1685*7c478bd9Sstevel@tonic-gate 			break;
1686*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 		  default:
1689*7c478bd9Sstevel@tonic-gate 			syserr("554 5.3.5 address= option unsupported for family %d",
1690*7c478bd9Sstevel@tonic-gate 			       d->d_addr.sa.sa_family);
1691*7c478bd9Sstevel@tonic-gate 			break;
1692*7c478bd9Sstevel@tonic-gate 		}
1693*7c478bd9Sstevel@tonic-gate 	}
1694*7c478bd9Sstevel@tonic-gate 
1695*7c478bd9Sstevel@tonic-gate 	if (port != NULL)
1696*7c478bd9Sstevel@tonic-gate 	{
1697*7c478bd9Sstevel@tonic-gate 		switch (d->d_addr.sa.sa_family)
1698*7c478bd9Sstevel@tonic-gate 		{
1699*7c478bd9Sstevel@tonic-gate #if NETINET
1700*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
1701*7c478bd9Sstevel@tonic-gate 			if (isascii(*port) && isdigit(*port))
1702*7c478bd9Sstevel@tonic-gate 				d->d_addr.sin.sin_port = htons((unsigned short)
1703*7c478bd9Sstevel@tonic-gate 						     atoi((const char *) port));
1704*7c478bd9Sstevel@tonic-gate 			else
1705*7c478bd9Sstevel@tonic-gate 			{
1706*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
1707*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 invalid port number: %s",
1708*7c478bd9Sstevel@tonic-gate 				       port);
1709*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
1710*7c478bd9Sstevel@tonic-gate 				register struct servent *sp;
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 				sp = getservbyname(port, "tcp");
1713*7c478bd9Sstevel@tonic-gate 				if (sp == NULL)
1714*7c478bd9Sstevel@tonic-gate 					syserr("554 5.3.5 service \"%s\" unknown",
1715*7c478bd9Sstevel@tonic-gate 					       port);
1716*7c478bd9Sstevel@tonic-gate 				else
1717*7c478bd9Sstevel@tonic-gate 					d->d_addr.sin.sin_port = sp->s_port;
1718*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
1719*7c478bd9Sstevel@tonic-gate 			}
1720*7c478bd9Sstevel@tonic-gate 			break;
1721*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1722*7c478bd9Sstevel@tonic-gate 
1723*7c478bd9Sstevel@tonic-gate #if NETINET6
1724*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
1725*7c478bd9Sstevel@tonic-gate 			if (isascii(*port) && isdigit(*port))
1726*7c478bd9Sstevel@tonic-gate 				d->d_addr.sin6.sin6_port = htons((unsigned short)
1727*7c478bd9Sstevel@tonic-gate 								  atoi(port));
1728*7c478bd9Sstevel@tonic-gate 			else
1729*7c478bd9Sstevel@tonic-gate 			{
1730*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
1731*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 invalid port number: %s",
1732*7c478bd9Sstevel@tonic-gate 				       port);
1733*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
1734*7c478bd9Sstevel@tonic-gate 				register struct servent *sp;
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 				sp = getservbyname(port, "tcp");
1737*7c478bd9Sstevel@tonic-gate 				if (sp == NULL)
1738*7c478bd9Sstevel@tonic-gate 					syserr("554 5.3.5 service \"%s\" unknown",
1739*7c478bd9Sstevel@tonic-gate 					       port);
1740*7c478bd9Sstevel@tonic-gate 				else
1741*7c478bd9Sstevel@tonic-gate 					d->d_addr.sin6.sin6_port = sp->s_port;
1742*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
1743*7c478bd9Sstevel@tonic-gate 			}
1744*7c478bd9Sstevel@tonic-gate 			break;
1745*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate #if NETISO
1748*7c478bd9Sstevel@tonic-gate 		  case AF_ISO:
1749*7c478bd9Sstevel@tonic-gate 			/* assume two byte transport selector */
1750*7c478bd9Sstevel@tonic-gate 			if (isascii(*port) && isdigit(*port))
1751*7c478bd9Sstevel@tonic-gate 				portno = htons((unsigned short) atoi(port));
1752*7c478bd9Sstevel@tonic-gate 			else
1753*7c478bd9Sstevel@tonic-gate 			{
1754*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
1755*7c478bd9Sstevel@tonic-gate 				syserr("554 5.3.5 invalid port number: %s",
1756*7c478bd9Sstevel@tonic-gate 				       port);
1757*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
1758*7c478bd9Sstevel@tonic-gate 				register struct servent *sp;
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 				sp = getservbyname(port, "tcp");
1761*7c478bd9Sstevel@tonic-gate 				if (sp == NULL)
1762*7c478bd9Sstevel@tonic-gate 					syserr("554 5.3.5 service \"%s\" unknown",
1763*7c478bd9Sstevel@tonic-gate 					       port);
1764*7c478bd9Sstevel@tonic-gate 				else
1765*7c478bd9Sstevel@tonic-gate 					portno = sp->s_port;
1766*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
1767*7c478bd9Sstevel@tonic-gate 			}
1768*7c478bd9Sstevel@tonic-gate 			memmove(TSEL(&d->d_addr.siso),
1769*7c478bd9Sstevel@tonic-gate 				(char *) &portno, 2);
1770*7c478bd9Sstevel@tonic-gate 			break;
1771*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
1772*7c478bd9Sstevel@tonic-gate 
1773*7c478bd9Sstevel@tonic-gate 		  default:
1774*7c478bd9Sstevel@tonic-gate 			syserr("554 5.3.5 Port= option unsupported for family %d",
1775*7c478bd9Sstevel@tonic-gate 			       d->d_addr.sa.sa_family);
1776*7c478bd9Sstevel@tonic-gate 			break;
1777*7c478bd9Sstevel@tonic-gate 		}
1778*7c478bd9Sstevel@tonic-gate 	}
1779*7c478bd9Sstevel@tonic-gate }
1780*7c478bd9Sstevel@tonic-gate /*
1781*7c478bd9Sstevel@tonic-gate **  SETDAEMONOPTIONS -- set options for running the MTA daemon
1782*7c478bd9Sstevel@tonic-gate **
1783*7c478bd9Sstevel@tonic-gate **	Parameters:
1784*7c478bd9Sstevel@tonic-gate **		p -- the options line.
1785*7c478bd9Sstevel@tonic-gate **
1786*7c478bd9Sstevel@tonic-gate **	Returns:
1787*7c478bd9Sstevel@tonic-gate **		true if successful, false otherwise.
1788*7c478bd9Sstevel@tonic-gate **
1789*7c478bd9Sstevel@tonic-gate **	Side Effects:
1790*7c478bd9Sstevel@tonic-gate **		increments number of daemons.
1791*7c478bd9Sstevel@tonic-gate */
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate #define DEF_LISTENQUEUE	10
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate struct dflags
1796*7c478bd9Sstevel@tonic-gate {
1797*7c478bd9Sstevel@tonic-gate 	char	*d_name;
1798*7c478bd9Sstevel@tonic-gate 	int	d_flag;
1799*7c478bd9Sstevel@tonic-gate };
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate static struct dflags	DaemonFlags[] =
1802*7c478bd9Sstevel@tonic-gate {
1803*7c478bd9Sstevel@tonic-gate 	{ "AUTHREQ",		D_AUTHREQ	},
1804*7c478bd9Sstevel@tonic-gate 	{ "BINDIF",		D_BINDIF	},
1805*7c478bd9Sstevel@tonic-gate 	{ "CANONREQ",		D_CANONREQ	},
1806*7c478bd9Sstevel@tonic-gate 	{ "IFNHELO",		D_IFNHELO	},
1807*7c478bd9Sstevel@tonic-gate 	{ "FQMAIL",		D_FQMAIL	},
1808*7c478bd9Sstevel@tonic-gate 	{ "FQRCPT",		D_FQRCPT	},
1809*7c478bd9Sstevel@tonic-gate 	{ "SMTPS",		D_SMTPS		},
1810*7c478bd9Sstevel@tonic-gate 	{ "UNQUALOK",		D_UNQUALOK	},
1811*7c478bd9Sstevel@tonic-gate 	{ "NOAUTH",		D_NOAUTH	},
1812*7c478bd9Sstevel@tonic-gate 	{ "NOCANON",		D_NOCANON	},
1813*7c478bd9Sstevel@tonic-gate 	{ "NOETRN",		D_NOETRN	},
1814*7c478bd9Sstevel@tonic-gate 	{ "NOTLS",		D_NOTLS		},
1815*7c478bd9Sstevel@tonic-gate 	{ "ETRNONLY",		D_ETRNONLY	},
1816*7c478bd9Sstevel@tonic-gate 	{ "OPTIONAL",		D_OPTIONAL	},
1817*7c478bd9Sstevel@tonic-gate 	{ "DISABLE",		D_DISABLE	},
1818*7c478bd9Sstevel@tonic-gate 	{ "ISSET",		D_ISSET		},
1819*7c478bd9Sstevel@tonic-gate 	{ NULL,			0		}
1820*7c478bd9Sstevel@tonic-gate };
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate static void
1823*7c478bd9Sstevel@tonic-gate printdaemonflags(d)
1824*7c478bd9Sstevel@tonic-gate 	DAEMON_T *d;
1825*7c478bd9Sstevel@tonic-gate {
1826*7c478bd9Sstevel@tonic-gate 	register struct dflags *df;
1827*7c478bd9Sstevel@tonic-gate 	bool first = true;
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	for (df = DaemonFlags; df->d_name != NULL; df++)
1830*7c478bd9Sstevel@tonic-gate 	{
1831*7c478bd9Sstevel@tonic-gate 		if (!bitnset(df->d_flag, d->d_flags))
1832*7c478bd9Sstevel@tonic-gate 			continue;
1833*7c478bd9Sstevel@tonic-gate 		if (first)
1834*7c478bd9Sstevel@tonic-gate 			sm_dprintf("<%s", df->d_name);
1835*7c478bd9Sstevel@tonic-gate 		else
1836*7c478bd9Sstevel@tonic-gate 			sm_dprintf(",%s", df->d_name);
1837*7c478bd9Sstevel@tonic-gate 		first = false;
1838*7c478bd9Sstevel@tonic-gate 	}
1839*7c478bd9Sstevel@tonic-gate 	if (!first)
1840*7c478bd9Sstevel@tonic-gate 		sm_dprintf(">");
1841*7c478bd9Sstevel@tonic-gate }
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate bool
1844*7c478bd9Sstevel@tonic-gate setdaemonoptions(p)
1845*7c478bd9Sstevel@tonic-gate 	register char *p;
1846*7c478bd9Sstevel@tonic-gate {
1847*7c478bd9Sstevel@tonic-gate 	if (NDaemons >= MAXDAEMONS)
1848*7c478bd9Sstevel@tonic-gate 		return false;
1849*7c478bd9Sstevel@tonic-gate 	Daemons[NDaemons].d_socket = -1;
1850*7c478bd9Sstevel@tonic-gate 	Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1851*7c478bd9Sstevel@tonic-gate 	clrbitmap(Daemons[NDaemons].d_flags);
1852*7c478bd9Sstevel@tonic-gate 	setsockaddroptions(p, &Daemons[NDaemons]);
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate #if MILTER
1855*7c478bd9Sstevel@tonic-gate 	if (Daemons[NDaemons].d_inputfilterlist != NULL)
1856*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
1857*7c478bd9Sstevel@tonic-gate #endif /* MILTER */
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	if (Daemons[NDaemons].d_name != NULL)
1860*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
1861*7c478bd9Sstevel@tonic-gate 	else
1862*7c478bd9Sstevel@tonic-gate 	{
1863*7c478bd9Sstevel@tonic-gate 		char num[30];
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons);
1866*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_name = newstr(num);
1867*7c478bd9Sstevel@tonic-gate 	}
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 	if (tTd(37, 1))
1870*7c478bd9Sstevel@tonic-gate 	{
1871*7c478bd9Sstevel@tonic-gate 		sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name);
1872*7c478bd9Sstevel@tonic-gate 		printdaemonflags(&Daemons[NDaemons]);
1873*7c478bd9Sstevel@tonic-gate 		sm_dprintf("\n");
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 	++NDaemons;
1876*7c478bd9Sstevel@tonic-gate 	return true;
1877*7c478bd9Sstevel@tonic-gate }
1878*7c478bd9Sstevel@tonic-gate /*
1879*7c478bd9Sstevel@tonic-gate **  INITDAEMON -- initialize daemon if not yet done.
1880*7c478bd9Sstevel@tonic-gate **
1881*7c478bd9Sstevel@tonic-gate **	Parameters:
1882*7c478bd9Sstevel@tonic-gate **		none
1883*7c478bd9Sstevel@tonic-gate **
1884*7c478bd9Sstevel@tonic-gate **	Returns:
1885*7c478bd9Sstevel@tonic-gate **		none
1886*7c478bd9Sstevel@tonic-gate **
1887*7c478bd9Sstevel@tonic-gate **	Side Effects:
1888*7c478bd9Sstevel@tonic-gate **		initializes structure for one daemon.
1889*7c478bd9Sstevel@tonic-gate */
1890*7c478bd9Sstevel@tonic-gate 
1891*7c478bd9Sstevel@tonic-gate void
1892*7c478bd9Sstevel@tonic-gate initdaemon()
1893*7c478bd9Sstevel@tonic-gate {
1894*7c478bd9Sstevel@tonic-gate 	if (NDaemons == 0)
1895*7c478bd9Sstevel@tonic-gate 	{
1896*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_socket = -1;
1897*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1898*7c478bd9Sstevel@tonic-gate 		Daemons[NDaemons].d_name = "Daemon0";
1899*7c478bd9Sstevel@tonic-gate 		NDaemons = 1;
1900*7c478bd9Sstevel@tonic-gate 	}
1901*7c478bd9Sstevel@tonic-gate }
1902*7c478bd9Sstevel@tonic-gate /*
1903*7c478bd9Sstevel@tonic-gate **  SETCLIENTOPTIONS -- set options for running the client
1904*7c478bd9Sstevel@tonic-gate **
1905*7c478bd9Sstevel@tonic-gate **	Parameters:
1906*7c478bd9Sstevel@tonic-gate **		p -- the options line.
1907*7c478bd9Sstevel@tonic-gate **
1908*7c478bd9Sstevel@tonic-gate **	Returns:
1909*7c478bd9Sstevel@tonic-gate **		none.
1910*7c478bd9Sstevel@tonic-gate */
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate static DAEMON_T	ClientSettings[AF_MAX + 1];
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate void
1915*7c478bd9Sstevel@tonic-gate setclientoptions(p)
1916*7c478bd9Sstevel@tonic-gate 	register char *p;
1917*7c478bd9Sstevel@tonic-gate {
1918*7c478bd9Sstevel@tonic-gate 	int family;
1919*7c478bd9Sstevel@tonic-gate 	DAEMON_T d;
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate 	memset(&d, '\0', sizeof d);
1922*7c478bd9Sstevel@tonic-gate 	setsockaddroptions(p, &d);
1923*7c478bd9Sstevel@tonic-gate 
1924*7c478bd9Sstevel@tonic-gate 	/* grab what we need */
1925*7c478bd9Sstevel@tonic-gate 	family = d.d_addr.sa.sa_family;
1926*7c478bd9Sstevel@tonic-gate 	STRUCTCOPY(d, ClientSettings[family]);
1927*7c478bd9Sstevel@tonic-gate 	setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */
1928*7c478bd9Sstevel@tonic-gate 	if (d.d_name != NULL)
1929*7c478bd9Sstevel@tonic-gate 		ClientSettings[family].d_name = newstr(d.d_name);
1930*7c478bd9Sstevel@tonic-gate 	else
1931*7c478bd9Sstevel@tonic-gate 	{
1932*7c478bd9Sstevel@tonic-gate 		char num[30];
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(num, sizeof num, "Client%d", family);
1935*7c478bd9Sstevel@tonic-gate 		ClientSettings[family].d_name = newstr(num);
1936*7c478bd9Sstevel@tonic-gate 	}
1937*7c478bd9Sstevel@tonic-gate }
1938*7c478bd9Sstevel@tonic-gate /*
1939*7c478bd9Sstevel@tonic-gate **  ADDR_FAMILY -- determine address family from address
1940*7c478bd9Sstevel@tonic-gate **
1941*7c478bd9Sstevel@tonic-gate **	Parameters:
1942*7c478bd9Sstevel@tonic-gate **		addr -- the string representation of the address
1943*7c478bd9Sstevel@tonic-gate **
1944*7c478bd9Sstevel@tonic-gate **	Returns:
1945*7c478bd9Sstevel@tonic-gate **		AF_INET, AF_INET6 or AF_UNSPEC
1946*7c478bd9Sstevel@tonic-gate **
1947*7c478bd9Sstevel@tonic-gate **	Side Effects:
1948*7c478bd9Sstevel@tonic-gate **		none.
1949*7c478bd9Sstevel@tonic-gate */
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate static int
1952*7c478bd9Sstevel@tonic-gate addr_family(addr)
1953*7c478bd9Sstevel@tonic-gate 	char *addr;
1954*7c478bd9Sstevel@tonic-gate {
1955*7c478bd9Sstevel@tonic-gate #if NETINET6
1956*7c478bd9Sstevel@tonic-gate 	SOCKADDR clt_addr;
1957*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1958*7c478bd9Sstevel@tonic-gate 
1959*7c478bd9Sstevel@tonic-gate #if NETINET
1960*7c478bd9Sstevel@tonic-gate 	if (inet_addr(addr) != INADDR_NONE)
1961*7c478bd9Sstevel@tonic-gate 	{
1962*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 9))
1963*7c478bd9Sstevel@tonic-gate 			sm_dprintf("addr_family(%s): INET\n", addr);
1964*7c478bd9Sstevel@tonic-gate 		return AF_INET;
1965*7c478bd9Sstevel@tonic-gate 	}
1966*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
1967*7c478bd9Sstevel@tonic-gate #if NETINET6
1968*7c478bd9Sstevel@tonic-gate 	if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
1969*7c478bd9Sstevel@tonic-gate 	{
1970*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 9))
1971*7c478bd9Sstevel@tonic-gate 			sm_dprintf("addr_family(%s): INET6\n", addr);
1972*7c478bd9Sstevel@tonic-gate 		return AF_INET6;
1973*7c478bd9Sstevel@tonic-gate 	}
1974*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1975*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
1976*7c478bd9Sstevel@tonic-gate # if NETUNIX
1977*7c478bd9Sstevel@tonic-gate 	if (*addr == '/')
1978*7c478bd9Sstevel@tonic-gate 	{
1979*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 9))
1980*7c478bd9Sstevel@tonic-gate 			sm_dprintf("addr_family(%s): LOCAL\n", addr);
1981*7c478bd9Sstevel@tonic-gate 		return AF_UNIX;
1982*7c478bd9Sstevel@tonic-gate 	}
1983*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
1984*7c478bd9Sstevel@tonic-gate #endif	/* _FFR_DAEMON_NETUNIX */
1985*7c478bd9Sstevel@tonic-gate 	if (tTd(16, 9))
1986*7c478bd9Sstevel@tonic-gate 		sm_dprintf("addr_family(%s): UNSPEC\n", addr);
1987*7c478bd9Sstevel@tonic-gate 	return AF_UNSPEC;
1988*7c478bd9Sstevel@tonic-gate }
1989*7c478bd9Sstevel@tonic-gate 
1990*7c478bd9Sstevel@tonic-gate /*
1991*7c478bd9Sstevel@tonic-gate **  CHKCLIENTMODIFIERS -- check whether all clients have set a flag.
1992*7c478bd9Sstevel@tonic-gate **
1993*7c478bd9Sstevel@tonic-gate **	Parameters:
1994*7c478bd9Sstevel@tonic-gate **		flag -- the flag to test.
1995*7c478bd9Sstevel@tonic-gate **
1996*7c478bd9Sstevel@tonic-gate **	Returns:
1997*7c478bd9Sstevel@tonic-gate **		true iff all configured clients have set the flag.
1998*7c478bd9Sstevel@tonic-gate */
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate bool
2001*7c478bd9Sstevel@tonic-gate chkclientmodifiers(flag)
2002*7c478bd9Sstevel@tonic-gate 	int flag;
2003*7c478bd9Sstevel@tonic-gate {
2004*7c478bd9Sstevel@tonic-gate 	int i;
2005*7c478bd9Sstevel@tonic-gate 	bool flagisset;
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	flagisset = false;
2008*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < AF_MAX; i++)
2009*7c478bd9Sstevel@tonic-gate 	{
2010*7c478bd9Sstevel@tonic-gate 		if (bitnset(D_ISSET, ClientSettings[i].d_flags))
2011*7c478bd9Sstevel@tonic-gate 		{
2012*7c478bd9Sstevel@tonic-gate 			if (!bitnset((char) flag, ClientSettings[i].d_flags))
2013*7c478bd9Sstevel@tonic-gate 				return false;
2014*7c478bd9Sstevel@tonic-gate 			flagisset = true;
2015*7c478bd9Sstevel@tonic-gate 		}
2016*7c478bd9Sstevel@tonic-gate 	}
2017*7c478bd9Sstevel@tonic-gate 	return flagisset;
2018*7c478bd9Sstevel@tonic-gate }
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate #if MILTER
2021*7c478bd9Sstevel@tonic-gate /*
2022*7c478bd9Sstevel@tonic-gate **  SETUP_DAEMON_FILTERS -- Parse per-socket filters
2023*7c478bd9Sstevel@tonic-gate **
2024*7c478bd9Sstevel@tonic-gate **	Parameters:
2025*7c478bd9Sstevel@tonic-gate **		none
2026*7c478bd9Sstevel@tonic-gate **
2027*7c478bd9Sstevel@tonic-gate **	Returns:
2028*7c478bd9Sstevel@tonic-gate **		none
2029*7c478bd9Sstevel@tonic-gate */
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate void
2032*7c478bd9Sstevel@tonic-gate setup_daemon_milters()
2033*7c478bd9Sstevel@tonic-gate {
2034*7c478bd9Sstevel@tonic-gate 	int idx;
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	if (OpMode == MD_SMTP)
2037*7c478bd9Sstevel@tonic-gate 	{
2038*7c478bd9Sstevel@tonic-gate 		/* no need to configure the daemons */
2039*7c478bd9Sstevel@tonic-gate 		return;
2040*7c478bd9Sstevel@tonic-gate 	}
2041*7c478bd9Sstevel@tonic-gate 
2042*7c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < NDaemons; idx++)
2043*7c478bd9Sstevel@tonic-gate 	{
2044*7c478bd9Sstevel@tonic-gate 		if (Daemons[idx].d_inputfilterlist != NULL)
2045*7c478bd9Sstevel@tonic-gate 		{
2046*7c478bd9Sstevel@tonic-gate 			milter_config(Daemons[idx].d_inputfilterlist,
2047*7c478bd9Sstevel@tonic-gate 				      Daemons[idx].d_inputfilters,
2048*7c478bd9Sstevel@tonic-gate 				      MAXFILTERS);
2049*7c478bd9Sstevel@tonic-gate 		}
2050*7c478bd9Sstevel@tonic-gate 	}
2051*7c478bd9Sstevel@tonic-gate }
2052*7c478bd9Sstevel@tonic-gate #endif /* MILTER */
2053*7c478bd9Sstevel@tonic-gate /*
2054*7c478bd9Sstevel@tonic-gate **  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
2055*7c478bd9Sstevel@tonic-gate **
2056*7c478bd9Sstevel@tonic-gate **	Parameters:
2057*7c478bd9Sstevel@tonic-gate **		host -- the name of the host.
2058*7c478bd9Sstevel@tonic-gate **		port -- the port number to connect to.
2059*7c478bd9Sstevel@tonic-gate **		mci -- a pointer to the mail connection information
2060*7c478bd9Sstevel@tonic-gate **			structure to be filled in.
2061*7c478bd9Sstevel@tonic-gate **		e -- the current envelope.
2062*7c478bd9Sstevel@tonic-gate **		enough -- time at which to stop further connection attempts.
2063*7c478bd9Sstevel@tonic-gate **			(0 means no limit)
2064*7c478bd9Sstevel@tonic-gate **
2065*7c478bd9Sstevel@tonic-gate **	Returns:
2066*7c478bd9Sstevel@tonic-gate **		An exit code telling whether the connection could be
2067*7c478bd9Sstevel@tonic-gate **			made and if not why not.
2068*7c478bd9Sstevel@tonic-gate **
2069*7c478bd9Sstevel@tonic-gate **	Side Effects:
2070*7c478bd9Sstevel@tonic-gate **		none.
2071*7c478bd9Sstevel@tonic-gate */
2072*7c478bd9Sstevel@tonic-gate 
2073*7c478bd9Sstevel@tonic-gate static jmp_buf	CtxConnectTimeout;
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate SOCKADDR	CurHostAddr;		/* address of current host */
2076*7c478bd9Sstevel@tonic-gate 
2077*7c478bd9Sstevel@tonic-gate int
2078*7c478bd9Sstevel@tonic-gate makeconnection(host, port, mci, e, enough)
2079*7c478bd9Sstevel@tonic-gate 	char *host;
2080*7c478bd9Sstevel@tonic-gate 	volatile unsigned int port;
2081*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
2082*7c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
2083*7c478bd9Sstevel@tonic-gate 	time_t enough;
2084*7c478bd9Sstevel@tonic-gate {
2085*7c478bd9Sstevel@tonic-gate 	register volatile int addrno = 0;
2086*7c478bd9Sstevel@tonic-gate 	volatile int s;
2087*7c478bd9Sstevel@tonic-gate 	register struct hostent *volatile hp = (struct hostent *) NULL;
2088*7c478bd9Sstevel@tonic-gate 	SOCKADDR addr;
2089*7c478bd9Sstevel@tonic-gate 	SOCKADDR clt_addr;
2090*7c478bd9Sstevel@tonic-gate 	int save_errno = 0;
2091*7c478bd9Sstevel@tonic-gate 	volatile SOCKADDR_LEN_T addrlen;
2092*7c478bd9Sstevel@tonic-gate 	volatile bool firstconnect;
2093*7c478bd9Sstevel@tonic-gate 	SM_EVENT *volatile ev = NULL;
2094*7c478bd9Sstevel@tonic-gate #if NETINET6
2095*7c478bd9Sstevel@tonic-gate 	volatile bool v6found = false;
2096*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2097*7c478bd9Sstevel@tonic-gate 	volatile int family = InetMode;
2098*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T len;
2099*7c478bd9Sstevel@tonic-gate 	volatile SOCKADDR_LEN_T socksize = 0;
2100*7c478bd9Sstevel@tonic-gate 	volatile bool clt_bind;
2101*7c478bd9Sstevel@tonic-gate 	BITMAP256 d_flags;
2102*7c478bd9Sstevel@tonic-gate 	char *p;
2103*7c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	/* retranslate {daemon_flags} into bitmap */
2106*7c478bd9Sstevel@tonic-gate 	clrbitmap(d_flags);
2107*7c478bd9Sstevel@tonic-gate 	if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL)
2108*7c478bd9Sstevel@tonic-gate 	{
2109*7c478bd9Sstevel@tonic-gate 		for (; *p != '\0'; p++)
2110*7c478bd9Sstevel@tonic-gate 		{
2111*7c478bd9Sstevel@tonic-gate 			if (!(isascii(*p) && isspace(*p)))
2112*7c478bd9Sstevel@tonic-gate 				setbitn(bitidx(*p), d_flags);
2113*7c478bd9Sstevel@tonic-gate 		}
2114*7c478bd9Sstevel@tonic-gate 	}
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate #if NETINET6
2117*7c478bd9Sstevel@tonic-gate  v4retry:
2118*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2119*7c478bd9Sstevel@tonic-gate 	clt_bind = false;
2120*7c478bd9Sstevel@tonic-gate 
2121*7c478bd9Sstevel@tonic-gate 	/* Set up the address for outgoing connection. */
2122*7c478bd9Sstevel@tonic-gate 	if (bitnset(D_BINDIF, d_flags) &&
2123*7c478bd9Sstevel@tonic-gate 	    (p = macvalue(macid("{if_addr}"), e)) != NULL &&
2124*7c478bd9Sstevel@tonic-gate 	    *p != '\0')
2125*7c478bd9Sstevel@tonic-gate 	{
2126*7c478bd9Sstevel@tonic-gate #if NETINET6
2127*7c478bd9Sstevel@tonic-gate 		char p6[INET6_ADDRSTRLEN];
2128*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 		memset(&clt_addr, '\0', sizeof clt_addr);
2131*7c478bd9Sstevel@tonic-gate 
2132*7c478bd9Sstevel@tonic-gate 		/* infer the address family from the address itself */
2133*7c478bd9Sstevel@tonic-gate 		clt_addr.sa.sa_family = addr_family(p);
2134*7c478bd9Sstevel@tonic-gate 		switch (clt_addr.sa.sa_family)
2135*7c478bd9Sstevel@tonic-gate 		{
2136*7c478bd9Sstevel@tonic-gate #if NETINET
2137*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
2138*7c478bd9Sstevel@tonic-gate 			clt_addr.sin.sin_addr.s_addr = inet_addr(p);
2139*7c478bd9Sstevel@tonic-gate 			if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
2140*7c478bd9Sstevel@tonic-gate 			    clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
2141*7c478bd9Sstevel@tonic-gate 			{
2142*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2143*7c478bd9Sstevel@tonic-gate 				socksize = sizeof (struct sockaddr_in);
2144*7c478bd9Sstevel@tonic-gate 			}
2145*7c478bd9Sstevel@tonic-gate 			break;
2146*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate #if NETINET6
2149*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
2150*7c478bd9Sstevel@tonic-gate 			if (inet_addr(p) != INADDR_NONE)
2151*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p6, sizeof p6,
2152*7c478bd9Sstevel@tonic-gate 						   "IPv6:::ffff:%s", p);
2153*7c478bd9Sstevel@tonic-gate 			else
2154*7c478bd9Sstevel@tonic-gate 				(void) sm_strlcpy(p6, p, sizeof p6);
2155*7c478bd9Sstevel@tonic-gate 			if (anynet_pton(AF_INET6, p6,
2156*7c478bd9Sstevel@tonic-gate 					&clt_addr.sin6.sin6_addr) == 1 &&
2157*7c478bd9Sstevel@tonic-gate 			    !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
2158*7c478bd9Sstevel@tonic-gate 			{
2159*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2160*7c478bd9Sstevel@tonic-gate 				socksize = sizeof (struct sockaddr_in6);
2161*7c478bd9Sstevel@tonic-gate 			}
2162*7c478bd9Sstevel@tonic-gate 			break;
2163*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate #if 0
2166*7c478bd9Sstevel@tonic-gate 		  default:
2167*7c478bd9Sstevel@tonic-gate 			syserr("554 5.3.5 Address= option unsupported for family %d",
2168*7c478bd9Sstevel@tonic-gate 			       clt_addr.sa.sa_family);
2169*7c478bd9Sstevel@tonic-gate 			break;
2170*7c478bd9Sstevel@tonic-gate #endif /* 0 */
2171*7c478bd9Sstevel@tonic-gate 		}
2172*7c478bd9Sstevel@tonic-gate 		if (clt_bind)
2173*7c478bd9Sstevel@tonic-gate 			family = clt_addr.sa.sa_family;
2174*7c478bd9Sstevel@tonic-gate 	}
2175*7c478bd9Sstevel@tonic-gate 
2176*7c478bd9Sstevel@tonic-gate 	/* D_BINDIF not set or not available, fallback to ClientPortOptions */
2177*7c478bd9Sstevel@tonic-gate 	if (!clt_bind)
2178*7c478bd9Sstevel@tonic-gate 	{
2179*7c478bd9Sstevel@tonic-gate 		STRUCTCOPY(ClientSettings[family].d_addr, clt_addr);
2180*7c478bd9Sstevel@tonic-gate 		switch (clt_addr.sa.sa_family)
2181*7c478bd9Sstevel@tonic-gate 		{
2182*7c478bd9Sstevel@tonic-gate #if NETINET
2183*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
2184*7c478bd9Sstevel@tonic-gate 			if (clt_addr.sin.sin_addr.s_addr == 0)
2185*7c478bd9Sstevel@tonic-gate 				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
2186*7c478bd9Sstevel@tonic-gate 			else
2187*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2188*7c478bd9Sstevel@tonic-gate 			if (clt_addr.sin.sin_port != 0)
2189*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2190*7c478bd9Sstevel@tonic-gate 			socksize = sizeof (struct sockaddr_in);
2191*7c478bd9Sstevel@tonic-gate 			break;
2192*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2193*7c478bd9Sstevel@tonic-gate #if NETINET6
2194*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
2195*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
2196*7c478bd9Sstevel@tonic-gate 				clt_addr.sin6.sin6_addr = in6addr_any;
2197*7c478bd9Sstevel@tonic-gate 			else
2198*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2199*7c478bd9Sstevel@tonic-gate 			socksize = sizeof (struct sockaddr_in6);
2200*7c478bd9Sstevel@tonic-gate 			if (clt_addr.sin6.sin6_port != 0)
2201*7c478bd9Sstevel@tonic-gate 				clt_bind = true;
2202*7c478bd9Sstevel@tonic-gate 			break;
2203*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2204*7c478bd9Sstevel@tonic-gate #if NETISO
2205*7c478bd9Sstevel@tonic-gate 		  case AF_ISO:
2206*7c478bd9Sstevel@tonic-gate 			socksize = sizeof clt_addr.siso;
2207*7c478bd9Sstevel@tonic-gate 			clt_bind = true;
2208*7c478bd9Sstevel@tonic-gate 			break;
2209*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
2210*7c478bd9Sstevel@tonic-gate 		  default:
2211*7c478bd9Sstevel@tonic-gate 			break;
2212*7c478bd9Sstevel@tonic-gate 		}
2213*7c478bd9Sstevel@tonic-gate 	}
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 	/*
2216*7c478bd9Sstevel@tonic-gate 	**  Set up the address for the mailer.
2217*7c478bd9Sstevel@tonic-gate 	**	Accept "[a.b.c.d]" syntax for host name.
2218*7c478bd9Sstevel@tonic-gate 	*/
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	SM_SET_H_ERRNO(0);
2221*7c478bd9Sstevel@tonic-gate 	errno = 0;
2222*7c478bd9Sstevel@tonic-gate 	memset(&CurHostAddr, '\0', sizeof CurHostAddr);
2223*7c478bd9Sstevel@tonic-gate 	memset(&addr, '\0', sizeof addr);
2224*7c478bd9Sstevel@tonic-gate 	SmtpPhase = mci->mci_phase = "initial connection";
2225*7c478bd9Sstevel@tonic-gate 	CurHostName = host;
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 	if (host[0] == '[')
2228*7c478bd9Sstevel@tonic-gate 	{
2229*7c478bd9Sstevel@tonic-gate 		p = strchr(host, ']');
2230*7c478bd9Sstevel@tonic-gate 		if (p != NULL)
2231*7c478bd9Sstevel@tonic-gate 		{
2232*7c478bd9Sstevel@tonic-gate #if NETINET
2233*7c478bd9Sstevel@tonic-gate 			unsigned long hid = INADDR_NONE;
2234*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2235*7c478bd9Sstevel@tonic-gate #if NETINET6
2236*7c478bd9Sstevel@tonic-gate 			struct sockaddr_in6 hid6;
2237*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2238*7c478bd9Sstevel@tonic-gate 
2239*7c478bd9Sstevel@tonic-gate 			*p = '\0';
2240*7c478bd9Sstevel@tonic-gate #if NETINET6
2241*7c478bd9Sstevel@tonic-gate 			memset(&hid6, '\0', sizeof hid6);
2242*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2243*7c478bd9Sstevel@tonic-gate #if NETINET
2244*7c478bd9Sstevel@tonic-gate 			if (family == AF_INET &&
2245*7c478bd9Sstevel@tonic-gate 			    (hid = inet_addr(&host[1])) != INADDR_NONE)
2246*7c478bd9Sstevel@tonic-gate 			{
2247*7c478bd9Sstevel@tonic-gate 				addr.sin.sin_family = AF_INET;
2248*7c478bd9Sstevel@tonic-gate 				addr.sin.sin_addr.s_addr = hid;
2249*7c478bd9Sstevel@tonic-gate 			}
2250*7c478bd9Sstevel@tonic-gate 			else
2251*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2252*7c478bd9Sstevel@tonic-gate #if NETINET6
2253*7c478bd9Sstevel@tonic-gate 			if (family == AF_INET6 &&
2254*7c478bd9Sstevel@tonic-gate 			    anynet_pton(AF_INET6, &host[1],
2255*7c478bd9Sstevel@tonic-gate 					&hid6.sin6_addr) == 1)
2256*7c478bd9Sstevel@tonic-gate 			{
2257*7c478bd9Sstevel@tonic-gate 				addr.sin6.sin6_family = AF_INET6;
2258*7c478bd9Sstevel@tonic-gate 				addr.sin6.sin6_addr = hid6.sin6_addr;
2259*7c478bd9Sstevel@tonic-gate 			}
2260*7c478bd9Sstevel@tonic-gate 			else
2261*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2262*7c478bd9Sstevel@tonic-gate 			{
2263*7c478bd9Sstevel@tonic-gate 				/* try it as a host name (avoid MX lookup) */
2264*7c478bd9Sstevel@tonic-gate 				hp = sm_gethostbyname(&host[1], family);
2265*7c478bd9Sstevel@tonic-gate 				if (hp == NULL && p[-1] == '.')
2266*7c478bd9Sstevel@tonic-gate 				{
2267*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
2268*7c478bd9Sstevel@tonic-gate 					int oldopts = _res.options;
2269*7c478bd9Sstevel@tonic-gate 
2270*7c478bd9Sstevel@tonic-gate 					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2271*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
2272*7c478bd9Sstevel@tonic-gate 					p[-1] = '\0';
2273*7c478bd9Sstevel@tonic-gate 					hp = sm_gethostbyname(&host[1],
2274*7c478bd9Sstevel@tonic-gate 							      family);
2275*7c478bd9Sstevel@tonic-gate 					p[-1] = '.';
2276*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
2277*7c478bd9Sstevel@tonic-gate 					_res.options = oldopts;
2278*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
2279*7c478bd9Sstevel@tonic-gate 				}
2280*7c478bd9Sstevel@tonic-gate 				*p = ']';
2281*7c478bd9Sstevel@tonic-gate 				goto gothostent;
2282*7c478bd9Sstevel@tonic-gate 			}
2283*7c478bd9Sstevel@tonic-gate 			*p = ']';
2284*7c478bd9Sstevel@tonic-gate 		}
2285*7c478bd9Sstevel@tonic-gate 		if (p == NULL)
2286*7c478bd9Sstevel@tonic-gate 		{
2287*7c478bd9Sstevel@tonic-gate 			extern char MsgBuf[];
2288*7c478bd9Sstevel@tonic-gate 
2289*7c478bd9Sstevel@tonic-gate 			usrerrenh("5.1.2",
2290*7c478bd9Sstevel@tonic-gate 				  "553 Invalid numeric domain spec \"%s\"",
2291*7c478bd9Sstevel@tonic-gate 				  host);
2292*7c478bd9Sstevel@tonic-gate 			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
2293*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
2294*7c478bd9Sstevel@tonic-gate 			return EX_NOHOST;
2295*7c478bd9Sstevel@tonic-gate 		}
2296*7c478bd9Sstevel@tonic-gate 	}
2297*7c478bd9Sstevel@tonic-gate 	else
2298*7c478bd9Sstevel@tonic-gate 	{
2299*7c478bd9Sstevel@tonic-gate 		/* contortion to get around SGI cc complaints */
2300*7c478bd9Sstevel@tonic-gate 		{
2301*7c478bd9Sstevel@tonic-gate 			p = &host[strlen(host) - 1];
2302*7c478bd9Sstevel@tonic-gate 			hp = sm_gethostbyname(host, family);
2303*7c478bd9Sstevel@tonic-gate 			if (hp == NULL && *p == '.')
2304*7c478bd9Sstevel@tonic-gate 			{
2305*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
2306*7c478bd9Sstevel@tonic-gate 				int oldopts = _res.options;
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2309*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
2310*7c478bd9Sstevel@tonic-gate 				*p = '\0';
2311*7c478bd9Sstevel@tonic-gate 				hp = sm_gethostbyname(host, family);
2312*7c478bd9Sstevel@tonic-gate 				*p = '.';
2313*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
2314*7c478bd9Sstevel@tonic-gate 				_res.options = oldopts;
2315*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
2316*7c478bd9Sstevel@tonic-gate 			}
2317*7c478bd9Sstevel@tonic-gate 		}
2318*7c478bd9Sstevel@tonic-gate gothostent:
2319*7c478bd9Sstevel@tonic-gate 		if (hp == NULL)
2320*7c478bd9Sstevel@tonic-gate 		{
2321*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
2322*7c478bd9Sstevel@tonic-gate 			/* check for name server timeouts */
2323*7c478bd9Sstevel@tonic-gate # if NETINET6
2324*7c478bd9Sstevel@tonic-gate 			if (WorkAroundBrokenAAAA && family == AF_INET6 &&
2325*7c478bd9Sstevel@tonic-gate 			    errno == ETIMEDOUT)
2326*7c478bd9Sstevel@tonic-gate 			{
2327*7c478bd9Sstevel@tonic-gate 				/*
2328*7c478bd9Sstevel@tonic-gate 				**  An attempt with family AF_INET may
2329*7c478bd9Sstevel@tonic-gate 				**  succeed By skipping the next section
2330*7c478bd9Sstevel@tonic-gate 				**  of code, we will try AF_INET before
2331*7c478bd9Sstevel@tonic-gate 				**  failing.
2332*7c478bd9Sstevel@tonic-gate 				*/
2333*7c478bd9Sstevel@tonic-gate 
2334*7c478bd9Sstevel@tonic-gate 				if (tTd(16, 10))
2335*7c478bd9Sstevel@tonic-gate 					sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n");
2336*7c478bd9Sstevel@tonic-gate 			}
2337*7c478bd9Sstevel@tonic-gate 			else
2338*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
2339*7c478bd9Sstevel@tonic-gate 			{
2340*7c478bd9Sstevel@tonic-gate 				if (errno == ETIMEDOUT ||
2341*7c478bd9Sstevel@tonic-gate 				    h_errno == TRY_AGAIN ||
2342*7c478bd9Sstevel@tonic-gate 				    (errno == ECONNREFUSED && UseNameServer))
2343*7c478bd9Sstevel@tonic-gate 				{
2344*7c478bd9Sstevel@tonic-gate 					save_errno = errno;
2345*7c478bd9Sstevel@tonic-gate 					mci_setstat(mci, EX_TEMPFAIL,
2346*7c478bd9Sstevel@tonic-gate 						    "4.4.3", NULL);
2347*7c478bd9Sstevel@tonic-gate 					errno = save_errno;
2348*7c478bd9Sstevel@tonic-gate 					return EX_TEMPFAIL;
2349*7c478bd9Sstevel@tonic-gate 				}
2350*7c478bd9Sstevel@tonic-gate 			}
2351*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
2352*7c478bd9Sstevel@tonic-gate #if NETINET6
2353*7c478bd9Sstevel@tonic-gate 			/*
2354*7c478bd9Sstevel@tonic-gate 			**  Try v6 first, then fall back to v4.
2355*7c478bd9Sstevel@tonic-gate 			**  If we found a v6 address, but no v4
2356*7c478bd9Sstevel@tonic-gate 			**  addresses, then TEMPFAIL.
2357*7c478bd9Sstevel@tonic-gate 			*/
2358*7c478bd9Sstevel@tonic-gate 
2359*7c478bd9Sstevel@tonic-gate 			if (family == AF_INET6)
2360*7c478bd9Sstevel@tonic-gate 			{
2361*7c478bd9Sstevel@tonic-gate 				family = AF_INET;
2362*7c478bd9Sstevel@tonic-gate 				goto v4retry;
2363*7c478bd9Sstevel@tonic-gate 			}
2364*7c478bd9Sstevel@tonic-gate 			if (v6found)
2365*7c478bd9Sstevel@tonic-gate 				goto v6tempfail;
2366*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2367*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
2368*7c478bd9Sstevel@tonic-gate 			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2369*7c478bd9Sstevel@tonic-gate 			errno = save_errno;
2370*7c478bd9Sstevel@tonic-gate 			return EX_NOHOST;
2371*7c478bd9Sstevel@tonic-gate 		}
2372*7c478bd9Sstevel@tonic-gate 		addr.sa.sa_family = hp->h_addrtype;
2373*7c478bd9Sstevel@tonic-gate 		switch (hp->h_addrtype)
2374*7c478bd9Sstevel@tonic-gate 		{
2375*7c478bd9Sstevel@tonic-gate #if NETINET
2376*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
2377*7c478bd9Sstevel@tonic-gate 			memmove(&addr.sin.sin_addr,
2378*7c478bd9Sstevel@tonic-gate 				hp->h_addr,
2379*7c478bd9Sstevel@tonic-gate 				INADDRSZ);
2380*7c478bd9Sstevel@tonic-gate 			break;
2381*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate #if NETINET6
2384*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
2385*7c478bd9Sstevel@tonic-gate 			memmove(&addr.sin6.sin6_addr,
2386*7c478bd9Sstevel@tonic-gate 				hp->h_addr,
2387*7c478bd9Sstevel@tonic-gate 				IN6ADDRSZ);
2388*7c478bd9Sstevel@tonic-gate 			break;
2389*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2390*7c478bd9Sstevel@tonic-gate 
2391*7c478bd9Sstevel@tonic-gate 		  default:
2392*7c478bd9Sstevel@tonic-gate 			if (hp->h_length > sizeof addr.sa.sa_data)
2393*7c478bd9Sstevel@tonic-gate 			{
2394*7c478bd9Sstevel@tonic-gate 				syserr("makeconnection: long sa_data: family %d len %d",
2395*7c478bd9Sstevel@tonic-gate 					hp->h_addrtype, hp->h_length);
2396*7c478bd9Sstevel@tonic-gate 				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2397*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2398*7c478bd9Sstevel@tonic-gate 				return EX_NOHOST;
2399*7c478bd9Sstevel@tonic-gate 			}
2400*7c478bd9Sstevel@tonic-gate 			memmove(addr.sa.sa_data, hp->h_addr, hp->h_length);
2401*7c478bd9Sstevel@tonic-gate 			break;
2402*7c478bd9Sstevel@tonic-gate 		}
2403*7c478bd9Sstevel@tonic-gate 		addrno = 1;
2404*7c478bd9Sstevel@tonic-gate 	}
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 	/*
2407*7c478bd9Sstevel@tonic-gate 	**  Determine the port number.
2408*7c478bd9Sstevel@tonic-gate 	*/
2409*7c478bd9Sstevel@tonic-gate 
2410*7c478bd9Sstevel@tonic-gate 	if (port == 0)
2411*7c478bd9Sstevel@tonic-gate 	{
2412*7c478bd9Sstevel@tonic-gate #ifdef NO_GETSERVBYNAME
2413*7c478bd9Sstevel@tonic-gate 		port = htons(25);
2414*7c478bd9Sstevel@tonic-gate #else /* NO_GETSERVBYNAME */
2415*7c478bd9Sstevel@tonic-gate 		register struct servent *sp = getservbyname("smtp", "tcp");
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 		if (sp == NULL)
2418*7c478bd9Sstevel@tonic-gate 		{
2419*7c478bd9Sstevel@tonic-gate 			if (LogLevel > 2)
2420*7c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, NOQID,
2421*7c478bd9Sstevel@tonic-gate 					  "makeconnection: service \"smtp\" unknown");
2422*7c478bd9Sstevel@tonic-gate 			port = htons(25);
2423*7c478bd9Sstevel@tonic-gate 		}
2424*7c478bd9Sstevel@tonic-gate 		else
2425*7c478bd9Sstevel@tonic-gate 			port = sp->s_port;
2426*7c478bd9Sstevel@tonic-gate #endif /* NO_GETSERVBYNAME */
2427*7c478bd9Sstevel@tonic-gate 	}
2428*7c478bd9Sstevel@tonic-gate 
2429*7c478bd9Sstevel@tonic-gate #if NETINET6
2430*7c478bd9Sstevel@tonic-gate 	if (addr.sa.sa_family == AF_INET6 &&
2431*7c478bd9Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) &&
2432*7c478bd9Sstevel@tonic-gate 	    ClientSettings[AF_INET].d_addr.sa.sa_family != 0)
2433*7c478bd9Sstevel@tonic-gate 	{
2434*7c478bd9Sstevel@tonic-gate 		/*
2435*7c478bd9Sstevel@tonic-gate 		**  Ignore mapped IPv4 address since
2436*7c478bd9Sstevel@tonic-gate 		**  there is a ClientPortOptions setting
2437*7c478bd9Sstevel@tonic-gate 		**  for IPv4.
2438*7c478bd9Sstevel@tonic-gate 		*/
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 		goto nextaddr;
2441*7c478bd9Sstevel@tonic-gate 	}
2442*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 	switch (addr.sa.sa_family)
2445*7c478bd9Sstevel@tonic-gate 	{
2446*7c478bd9Sstevel@tonic-gate #if NETINET
2447*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
2448*7c478bd9Sstevel@tonic-gate 		addr.sin.sin_port = port;
2449*7c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in);
2450*7c478bd9Sstevel@tonic-gate 		break;
2451*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate #if NETINET6
2454*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
2455*7c478bd9Sstevel@tonic-gate 		addr.sin6.sin6_port = port;
2456*7c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in6);
2457*7c478bd9Sstevel@tonic-gate 		break;
2458*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2459*7c478bd9Sstevel@tonic-gate 
2460*7c478bd9Sstevel@tonic-gate #if NETISO
2461*7c478bd9Sstevel@tonic-gate 	  case AF_ISO:
2462*7c478bd9Sstevel@tonic-gate 		/* assume two byte transport selector */
2463*7c478bd9Sstevel@tonic-gate 		memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
2464*7c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_iso);
2465*7c478bd9Sstevel@tonic-gate 		break;
2466*7c478bd9Sstevel@tonic-gate #endif /* NETISO */
2467*7c478bd9Sstevel@tonic-gate 
2468*7c478bd9Sstevel@tonic-gate 	  default:
2469*7c478bd9Sstevel@tonic-gate 		syserr("Can't connect to address family %d", addr.sa.sa_family);
2470*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2471*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2472*7c478bd9Sstevel@tonic-gate #if NETINET6
2473*7c478bd9Sstevel@tonic-gate 		if (hp != NULL)
2474*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
2475*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2476*7c478bd9Sstevel@tonic-gate 		return EX_NOHOST;
2477*7c478bd9Sstevel@tonic-gate 	}
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate 	/*
2480*7c478bd9Sstevel@tonic-gate 	**  Try to actually open the connection.
2481*7c478bd9Sstevel@tonic-gate 	*/
2482*7c478bd9Sstevel@tonic-gate 
2483*7c478bd9Sstevel@tonic-gate #if XLA
2484*7c478bd9Sstevel@tonic-gate 	/* if too many connections, don't bother trying */
2485*7c478bd9Sstevel@tonic-gate 	if (!xla_noqueue_ok(host))
2486*7c478bd9Sstevel@tonic-gate 	{
2487*7c478bd9Sstevel@tonic-gate # if NETINET6
2488*7c478bd9Sstevel@tonic-gate 		if (hp != NULL)
2489*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
2490*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
2491*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2492*7c478bd9Sstevel@tonic-gate 	}
2493*7c478bd9Sstevel@tonic-gate #endif /* XLA */
2494*7c478bd9Sstevel@tonic-gate 
2495*7c478bd9Sstevel@tonic-gate 	firstconnect = true;
2496*7c478bd9Sstevel@tonic-gate 	for (;;)
2497*7c478bd9Sstevel@tonic-gate 	{
2498*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 1))
2499*7c478bd9Sstevel@tonic-gate 			sm_dprintf("makeconnection (%s [%s].%d (%d))\n",
2500*7c478bd9Sstevel@tonic-gate 				   host, anynet_ntoa(&addr), ntohs(port),
2501*7c478bd9Sstevel@tonic-gate 				   (int) addr.sa.sa_family);
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate 		/* save for logging */
2504*7c478bd9Sstevel@tonic-gate 		CurHostAddr = addr;
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate #if HASRRESVPORT
2507*7c478bd9Sstevel@tonic-gate 		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
2508*7c478bd9Sstevel@tonic-gate 		{
2509*7c478bd9Sstevel@tonic-gate 			int rport = IPPORT_RESERVED - 1;
2510*7c478bd9Sstevel@tonic-gate 
2511*7c478bd9Sstevel@tonic-gate 			s = rresvport(&rport);
2512*7c478bd9Sstevel@tonic-gate 		}
2513*7c478bd9Sstevel@tonic-gate 		else
2514*7c478bd9Sstevel@tonic-gate #endif /* HASRRESVPORT */
2515*7c478bd9Sstevel@tonic-gate 		{
2516*7c478bd9Sstevel@tonic-gate 			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
2517*7c478bd9Sstevel@tonic-gate 		}
2518*7c478bd9Sstevel@tonic-gate 		if (s < 0)
2519*7c478bd9Sstevel@tonic-gate 		{
2520*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
2521*7c478bd9Sstevel@tonic-gate 			syserr("makeconnection: cannot create socket");
2522*7c478bd9Sstevel@tonic-gate #if XLA
2523*7c478bd9Sstevel@tonic-gate 			xla_host_end(host);
2524*7c478bd9Sstevel@tonic-gate #endif /* XLA */
2525*7c478bd9Sstevel@tonic-gate 			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2526*7c478bd9Sstevel@tonic-gate #if NETINET6
2527*7c478bd9Sstevel@tonic-gate 			if (hp != NULL)
2528*7c478bd9Sstevel@tonic-gate 				freehostent(hp);
2529*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2530*7c478bd9Sstevel@tonic-gate 			errno = save_errno;
2531*7c478bd9Sstevel@tonic-gate 			return EX_TEMPFAIL;
2532*7c478bd9Sstevel@tonic-gate 		}
2533*7c478bd9Sstevel@tonic-gate 
2534*7c478bd9Sstevel@tonic-gate #ifdef SO_SNDBUF
2535*7c478bd9Sstevel@tonic-gate 		if (ClientSettings[family].d_tcpsndbufsize > 0)
2536*7c478bd9Sstevel@tonic-gate 		{
2537*7c478bd9Sstevel@tonic-gate 			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
2538*7c478bd9Sstevel@tonic-gate 				       (char *) &ClientSettings[family].d_tcpsndbufsize,
2539*7c478bd9Sstevel@tonic-gate 				       sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0)
2540*7c478bd9Sstevel@tonic-gate 				syserr("makeconnection: setsockopt(SO_SNDBUF)");
2541*7c478bd9Sstevel@tonic-gate 		}
2542*7c478bd9Sstevel@tonic-gate #endif /* SO_SNDBUF */
2543*7c478bd9Sstevel@tonic-gate #ifdef SO_RCVBUF
2544*7c478bd9Sstevel@tonic-gate 		if (ClientSettings[family].d_tcprcvbufsize > 0)
2545*7c478bd9Sstevel@tonic-gate 		{
2546*7c478bd9Sstevel@tonic-gate 			if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
2547*7c478bd9Sstevel@tonic-gate 				       (char *) &ClientSettings[family].d_tcprcvbufsize,
2548*7c478bd9Sstevel@tonic-gate 				       sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0)
2549*7c478bd9Sstevel@tonic-gate 				syserr("makeconnection: setsockopt(SO_RCVBUF)");
2550*7c478bd9Sstevel@tonic-gate 		}
2551*7c478bd9Sstevel@tonic-gate #endif /* SO_RCVBUF */
2552*7c478bd9Sstevel@tonic-gate 
2553*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 1))
2554*7c478bd9Sstevel@tonic-gate 			sm_dprintf("makeconnection: fd=%d\n", s);
2555*7c478bd9Sstevel@tonic-gate 
2556*7c478bd9Sstevel@tonic-gate 		/* turn on network debugging? */
2557*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 101))
2558*7c478bd9Sstevel@tonic-gate 		{
2559*7c478bd9Sstevel@tonic-gate 			int on = 1;
2560*7c478bd9Sstevel@tonic-gate 
2561*7c478bd9Sstevel@tonic-gate 			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
2562*7c478bd9Sstevel@tonic-gate 					  (char *)&on, sizeof on);
2563*7c478bd9Sstevel@tonic-gate 		}
2564*7c478bd9Sstevel@tonic-gate 		if (e->e_xfp != NULL)	/* for debugging */
2565*7c478bd9Sstevel@tonic-gate 			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
2566*7c478bd9Sstevel@tonic-gate 		errno = 0;		/* for debugging */
2567*7c478bd9Sstevel@tonic-gate 
2568*7c478bd9Sstevel@tonic-gate 		if (clt_bind)
2569*7c478bd9Sstevel@tonic-gate 		{
2570*7c478bd9Sstevel@tonic-gate 			int on = 1;
2571*7c478bd9Sstevel@tonic-gate 
2572*7c478bd9Sstevel@tonic-gate 			switch (clt_addr.sa.sa_family)
2573*7c478bd9Sstevel@tonic-gate 			{
2574*7c478bd9Sstevel@tonic-gate #if NETINET
2575*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
2576*7c478bd9Sstevel@tonic-gate 				if (clt_addr.sin.sin_port != 0)
2577*7c478bd9Sstevel@tonic-gate 					(void) setsockopt(s, SOL_SOCKET,
2578*7c478bd9Sstevel@tonic-gate 							  SO_REUSEADDR,
2579*7c478bd9Sstevel@tonic-gate 							  (char *) &on,
2580*7c478bd9Sstevel@tonic-gate 							  sizeof on);
2581*7c478bd9Sstevel@tonic-gate 				break;
2582*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2583*7c478bd9Sstevel@tonic-gate 
2584*7c478bd9Sstevel@tonic-gate #if NETINET6
2585*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
2586*7c478bd9Sstevel@tonic-gate 				if (clt_addr.sin6.sin6_port != 0)
2587*7c478bd9Sstevel@tonic-gate 					(void) setsockopt(s, SOL_SOCKET,
2588*7c478bd9Sstevel@tonic-gate 							  SO_REUSEADDR,
2589*7c478bd9Sstevel@tonic-gate 							  (char *) &on,
2590*7c478bd9Sstevel@tonic-gate 							  sizeof on);
2591*7c478bd9Sstevel@tonic-gate 				break;
2592*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2593*7c478bd9Sstevel@tonic-gate 			}
2594*7c478bd9Sstevel@tonic-gate 
2595*7c478bd9Sstevel@tonic-gate 			if (bind(s, &clt_addr.sa, socksize) < 0)
2596*7c478bd9Sstevel@tonic-gate 			{
2597*7c478bd9Sstevel@tonic-gate 				save_errno = errno;
2598*7c478bd9Sstevel@tonic-gate 				(void) close(s);
2599*7c478bd9Sstevel@tonic-gate 				errno = save_errno;
2600*7c478bd9Sstevel@tonic-gate 				syserr("makeconnection: cannot bind socket [%s]",
2601*7c478bd9Sstevel@tonic-gate 				       anynet_ntoa(&clt_addr));
2602*7c478bd9Sstevel@tonic-gate #if NETINET6
2603*7c478bd9Sstevel@tonic-gate 				if (hp != NULL)
2604*7c478bd9Sstevel@tonic-gate 					freehostent(hp);
2605*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2606*7c478bd9Sstevel@tonic-gate 				errno = save_errno;
2607*7c478bd9Sstevel@tonic-gate 				return EX_TEMPFAIL;
2608*7c478bd9Sstevel@tonic-gate 			}
2609*7c478bd9Sstevel@tonic-gate 		}
2610*7c478bd9Sstevel@tonic-gate 
2611*7c478bd9Sstevel@tonic-gate 		/*
2612*7c478bd9Sstevel@tonic-gate 		**  Linux seems to hang in connect for 90 minutes (!!!).
2613*7c478bd9Sstevel@tonic-gate 		**  Time out the connect to avoid this problem.
2614*7c478bd9Sstevel@tonic-gate 		*/
2615*7c478bd9Sstevel@tonic-gate 
2616*7c478bd9Sstevel@tonic-gate 		if (setjmp(CtxConnectTimeout) == 0)
2617*7c478bd9Sstevel@tonic-gate 		{
2618*7c478bd9Sstevel@tonic-gate 			int i;
2619*7c478bd9Sstevel@tonic-gate 
2620*7c478bd9Sstevel@tonic-gate 			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
2621*7c478bd9Sstevel@tonic-gate 				ev = sm_setevent(TimeOuts.to_iconnect,
2622*7c478bd9Sstevel@tonic-gate 						 connecttimeout, 0);
2623*7c478bd9Sstevel@tonic-gate 			else if (TimeOuts.to_connect != 0)
2624*7c478bd9Sstevel@tonic-gate 				ev = sm_setevent(TimeOuts.to_connect,
2625*7c478bd9Sstevel@tonic-gate 						 connecttimeout, 0);
2626*7c478bd9Sstevel@tonic-gate 			else
2627*7c478bd9Sstevel@tonic-gate 				ev = NULL;
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 			switch (ConnectOnlyTo.sa.sa_family)
2630*7c478bd9Sstevel@tonic-gate 			{
2631*7c478bd9Sstevel@tonic-gate #if NETINET
2632*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
2633*7c478bd9Sstevel@tonic-gate 				addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
2634*7c478bd9Sstevel@tonic-gate 				break;
2635*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2636*7c478bd9Sstevel@tonic-gate 
2637*7c478bd9Sstevel@tonic-gate #if NETINET6
2638*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
2639*7c478bd9Sstevel@tonic-gate 				memmove(&addr.sin6.sin6_addr,
2640*7c478bd9Sstevel@tonic-gate 					&ConnectOnlyTo.sin6.sin6_addr,
2641*7c478bd9Sstevel@tonic-gate 					IN6ADDRSZ);
2642*7c478bd9Sstevel@tonic-gate 				break;
2643*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2644*7c478bd9Sstevel@tonic-gate 			}
2645*7c478bd9Sstevel@tonic-gate 			if (tTd(16, 1))
2646*7c478bd9Sstevel@tonic-gate 				sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr));
2647*7c478bd9Sstevel@tonic-gate 			i = connect(s, (struct sockaddr *) &addr, addrlen);
2648*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
2649*7c478bd9Sstevel@tonic-gate 			if (ev != NULL)
2650*7c478bd9Sstevel@tonic-gate 				sm_clrevent(ev);
2651*7c478bd9Sstevel@tonic-gate 			if (i >= 0)
2652*7c478bd9Sstevel@tonic-gate 				break;
2653*7c478bd9Sstevel@tonic-gate 		}
2654*7c478bd9Sstevel@tonic-gate 		else
2655*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
2656*7c478bd9Sstevel@tonic-gate 
2657*7c478bd9Sstevel@tonic-gate 		/* couldn't connect.... figure out why */
2658*7c478bd9Sstevel@tonic-gate 		(void) close(s);
2659*7c478bd9Sstevel@tonic-gate 
2660*7c478bd9Sstevel@tonic-gate 		/* if running demand-dialed connection, try again */
2661*7c478bd9Sstevel@tonic-gate 		if (DialDelay > 0 && firstconnect &&
2662*7c478bd9Sstevel@tonic-gate 		    bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
2663*7c478bd9Sstevel@tonic-gate 		{
2664*7c478bd9Sstevel@tonic-gate 			if (tTd(16, 1))
2665*7c478bd9Sstevel@tonic-gate 				sm_dprintf("Connect failed (%s); trying again...\n",
2666*7c478bd9Sstevel@tonic-gate 					   sm_errstring(save_errno));
2667*7c478bd9Sstevel@tonic-gate 			firstconnect = false;
2668*7c478bd9Sstevel@tonic-gate 			(void) sleep(DialDelay);
2669*7c478bd9Sstevel@tonic-gate 			continue;
2670*7c478bd9Sstevel@tonic-gate 		}
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 13)
2673*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
2674*7c478bd9Sstevel@tonic-gate 				  "makeconnection (%s [%s]) failed: %s",
2675*7c478bd9Sstevel@tonic-gate 				  host, anynet_ntoa(&addr),
2676*7c478bd9Sstevel@tonic-gate 				  sm_errstring(save_errno));
2677*7c478bd9Sstevel@tonic-gate 
2678*7c478bd9Sstevel@tonic-gate #if NETINET6
2679*7c478bd9Sstevel@tonic-gate nextaddr:
2680*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2681*7c478bd9Sstevel@tonic-gate 		if (hp != NULL && hp->h_addr_list[addrno] != NULL &&
2682*7c478bd9Sstevel@tonic-gate 		    (enough == 0 || curtime() < enough))
2683*7c478bd9Sstevel@tonic-gate 		{
2684*7c478bd9Sstevel@tonic-gate 			if (tTd(16, 1))
2685*7c478bd9Sstevel@tonic-gate 				sm_dprintf("Connect failed (%s); trying new address....\n",
2686*7c478bd9Sstevel@tonic-gate 					   sm_errstring(save_errno));
2687*7c478bd9Sstevel@tonic-gate 			switch (addr.sa.sa_family)
2688*7c478bd9Sstevel@tonic-gate 			{
2689*7c478bd9Sstevel@tonic-gate #if NETINET
2690*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
2691*7c478bd9Sstevel@tonic-gate 				memmove(&addr.sin.sin_addr,
2692*7c478bd9Sstevel@tonic-gate 					hp->h_addr_list[addrno++],
2693*7c478bd9Sstevel@tonic-gate 					INADDRSZ);
2694*7c478bd9Sstevel@tonic-gate 				break;
2695*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
2696*7c478bd9Sstevel@tonic-gate 
2697*7c478bd9Sstevel@tonic-gate #if NETINET6
2698*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
2699*7c478bd9Sstevel@tonic-gate 				memmove(&addr.sin6.sin6_addr,
2700*7c478bd9Sstevel@tonic-gate 					hp->h_addr_list[addrno++],
2701*7c478bd9Sstevel@tonic-gate 					IN6ADDRSZ);
2702*7c478bd9Sstevel@tonic-gate 				break;
2703*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2704*7c478bd9Sstevel@tonic-gate 
2705*7c478bd9Sstevel@tonic-gate 			  default:
2706*7c478bd9Sstevel@tonic-gate 				memmove(addr.sa.sa_data,
2707*7c478bd9Sstevel@tonic-gate 					hp->h_addr_list[addrno++],
2708*7c478bd9Sstevel@tonic-gate 					hp->h_length);
2709*7c478bd9Sstevel@tonic-gate 				break;
2710*7c478bd9Sstevel@tonic-gate 			}
2711*7c478bd9Sstevel@tonic-gate 			continue;
2712*7c478bd9Sstevel@tonic-gate 		}
2713*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2714*7c478bd9Sstevel@tonic-gate 
2715*7c478bd9Sstevel@tonic-gate #if NETINET6
2716*7c478bd9Sstevel@tonic-gate 		if (family == AF_INET6)
2717*7c478bd9Sstevel@tonic-gate 		{
2718*7c478bd9Sstevel@tonic-gate 			if (tTd(16, 1))
2719*7c478bd9Sstevel@tonic-gate 				sm_dprintf("Connect failed (%s); retrying with AF_INET....\n",
2720*7c478bd9Sstevel@tonic-gate 					   sm_errstring(save_errno));
2721*7c478bd9Sstevel@tonic-gate 			v6found = true;
2722*7c478bd9Sstevel@tonic-gate 			family = AF_INET;
2723*7c478bd9Sstevel@tonic-gate 			if (hp != NULL)
2724*7c478bd9Sstevel@tonic-gate 			{
2725*7c478bd9Sstevel@tonic-gate 				freehostent(hp);
2726*7c478bd9Sstevel@tonic-gate 				hp = NULL;
2727*7c478bd9Sstevel@tonic-gate 			}
2728*7c478bd9Sstevel@tonic-gate 			goto v4retry;
2729*7c478bd9Sstevel@tonic-gate 		}
2730*7c478bd9Sstevel@tonic-gate 	v6tempfail:
2731*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2732*7c478bd9Sstevel@tonic-gate 		/* couldn't open connection */
2733*7c478bd9Sstevel@tonic-gate #if NETINET6
2734*7c478bd9Sstevel@tonic-gate 		/* Don't clobber an already saved errno from v4retry */
2735*7c478bd9Sstevel@tonic-gate 		if (errno > 0)
2736*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2737*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
2738*7c478bd9Sstevel@tonic-gate 		if (tTd(16, 1))
2739*7c478bd9Sstevel@tonic-gate 			sm_dprintf("Connect failed (%s)\n",
2740*7c478bd9Sstevel@tonic-gate 				   sm_errstring(save_errno));
2741*7c478bd9Sstevel@tonic-gate #if XLA
2742*7c478bd9Sstevel@tonic-gate 		xla_host_end(host);
2743*7c478bd9Sstevel@tonic-gate #endif /* XLA */
2744*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2745*7c478bd9Sstevel@tonic-gate #if NETINET6
2746*7c478bd9Sstevel@tonic-gate 		if (hp != NULL)
2747*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
2748*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2749*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2750*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2751*7c478bd9Sstevel@tonic-gate 	}
2752*7c478bd9Sstevel@tonic-gate 
2753*7c478bd9Sstevel@tonic-gate #if NETINET6
2754*7c478bd9Sstevel@tonic-gate 	if (hp != NULL)
2755*7c478bd9Sstevel@tonic-gate 	{
2756*7c478bd9Sstevel@tonic-gate 		freehostent(hp);
2757*7c478bd9Sstevel@tonic-gate 		hp = NULL;
2758*7c478bd9Sstevel@tonic-gate 	}
2759*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2760*7c478bd9Sstevel@tonic-gate 
2761*7c478bd9Sstevel@tonic-gate 	/* connection ok, put it into canonical form */
2762*7c478bd9Sstevel@tonic-gate 	mci->mci_out = NULL;
2763*7c478bd9Sstevel@tonic-gate 	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2764*7c478bd9Sstevel@tonic-gate 				       (void *) &s,
2765*7c478bd9Sstevel@tonic-gate 				       SM_IO_WRONLY_B, NULL)) == NULL ||
2766*7c478bd9Sstevel@tonic-gate 	    (s = dup(s)) < 0 ||
2767*7c478bd9Sstevel@tonic-gate 	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2768*7c478bd9Sstevel@tonic-gate 				      (void *) &s,
2769*7c478bd9Sstevel@tonic-gate 				      SM_IO_RDONLY_B, NULL)) == NULL)
2770*7c478bd9Sstevel@tonic-gate 	{
2771*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
2772*7c478bd9Sstevel@tonic-gate 		syserr("cannot open SMTP client channel, fd=%d", s);
2773*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2774*7c478bd9Sstevel@tonic-gate 		if (mci->mci_out != NULL)
2775*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2776*7c478bd9Sstevel@tonic-gate 		(void) close(s);
2777*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2778*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2779*7c478bd9Sstevel@tonic-gate 	}
2780*7c478bd9Sstevel@tonic-gate 	sm_io_automode(mci->mci_out, mci->mci_in);
2781*7c478bd9Sstevel@tonic-gate 
2782*7c478bd9Sstevel@tonic-gate 	/* set {client_flags} */
2783*7c478bd9Sstevel@tonic-gate 	if (ClientSettings[addr.sa.sa_family].d_mflags != NULL)
2784*7c478bd9Sstevel@tonic-gate 	{
2785*7c478bd9Sstevel@tonic-gate 		macdefine(&mci->mci_macro, A_PERM,
2786*7c478bd9Sstevel@tonic-gate 			  macid("{client_flags}"),
2787*7c478bd9Sstevel@tonic-gate 			  ClientSettings[addr.sa.sa_family].d_mflags);
2788*7c478bd9Sstevel@tonic-gate 	}
2789*7c478bd9Sstevel@tonic-gate 	else
2790*7c478bd9Sstevel@tonic-gate 		macdefine(&mci->mci_macro, A_PERM,
2791*7c478bd9Sstevel@tonic-gate 			  macid("{client_flags}"), "");
2792*7c478bd9Sstevel@tonic-gate 
2793*7c478bd9Sstevel@tonic-gate 	/* "add" {client_flags} to bitmap */
2794*7c478bd9Sstevel@tonic-gate 	if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags))
2795*7c478bd9Sstevel@tonic-gate 	{
2796*7c478bd9Sstevel@tonic-gate 		/* look for just this one flag */
2797*7c478bd9Sstevel@tonic-gate 		setbitn(D_IFNHELO, d_flags);
2798*7c478bd9Sstevel@tonic-gate 	}
2799*7c478bd9Sstevel@tonic-gate 
2800*7c478bd9Sstevel@tonic-gate 	/* find out name for Interface through which we connect */
2801*7c478bd9Sstevel@tonic-gate 	len = sizeof addr;
2802*7c478bd9Sstevel@tonic-gate 	if (getsockname(s, &addr.sa, &len) == 0)
2803*7c478bd9Sstevel@tonic-gate 	{
2804*7c478bd9Sstevel@tonic-gate 		char *name;
2805*7c478bd9Sstevel@tonic-gate 		char family[5];
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2808*7c478bd9Sstevel@tonic-gate 			macid("{if_addr_out}"), anynet_ntoa(&addr));
2809*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(family, sizeof(family), "%d",
2810*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family);
2811*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2812*7c478bd9Sstevel@tonic-gate 			macid("{if_family_out}"), family);
2813*7c478bd9Sstevel@tonic-gate 
2814*7c478bd9Sstevel@tonic-gate 		name = hostnamebyanyaddr(&addr);
2815*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2816*7c478bd9Sstevel@tonic-gate 			macid("{if_name_out}"), name);
2817*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 11)
2818*7c478bd9Sstevel@tonic-gate 		{
2819*7c478bd9Sstevel@tonic-gate 			/* log connection information */
2820*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
2821*7c478bd9Sstevel@tonic-gate 				  "SMTP outgoing connect on %.40s", name);
2822*7c478bd9Sstevel@tonic-gate 		}
2823*7c478bd9Sstevel@tonic-gate 		if (bitnset(D_IFNHELO, d_flags))
2824*7c478bd9Sstevel@tonic-gate 		{
2825*7c478bd9Sstevel@tonic-gate 			if (name[0] != '[' && strchr(name, '.') != NULL)
2826*7c478bd9Sstevel@tonic-gate 				mci->mci_heloname = newstr(name);
2827*7c478bd9Sstevel@tonic-gate 		}
2828*7c478bd9Sstevel@tonic-gate 	}
2829*7c478bd9Sstevel@tonic-gate 	else
2830*7c478bd9Sstevel@tonic-gate 	{
2831*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2832*7c478bd9Sstevel@tonic-gate 			macid("{if_name_out}"), NULL);
2833*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2834*7c478bd9Sstevel@tonic-gate 			macid("{if_addr_out}"), NULL);
2835*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2836*7c478bd9Sstevel@tonic-gate 			macid("{if_family_out}"), NULL);
2837*7c478bd9Sstevel@tonic-gate 	}
2838*7c478bd9Sstevel@tonic-gate 
2839*7c478bd9Sstevel@tonic-gate #if _FFR_HELONAME
2840*7c478bd9Sstevel@tonic-gate 	/* Use the configured HeloName as appropriate */
2841*7c478bd9Sstevel@tonic-gate 	if (HeloName != NULL && HeloName[0] != '\0')
2842*7c478bd9Sstevel@tonic-gate 		mci->mci_heloname = newstr(HeloName);
2843*7c478bd9Sstevel@tonic-gate #endif /* _FFR_HELONAME */
2844*7c478bd9Sstevel@tonic-gate 
2845*7c478bd9Sstevel@tonic-gate 	mci_setstat(mci, EX_OK, NULL, NULL);
2846*7c478bd9Sstevel@tonic-gate 	return EX_OK;
2847*7c478bd9Sstevel@tonic-gate }
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate static void
2850*7c478bd9Sstevel@tonic-gate connecttimeout(ignore)
2851*7c478bd9Sstevel@tonic-gate 	int ignore;
2852*7c478bd9Sstevel@tonic-gate {
2853*7c478bd9Sstevel@tonic-gate 	/*
2854*7c478bd9Sstevel@tonic-gate 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2855*7c478bd9Sstevel@tonic-gate 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2856*7c478bd9Sstevel@tonic-gate 	**	DOING.
2857*7c478bd9Sstevel@tonic-gate 	*/
2858*7c478bd9Sstevel@tonic-gate 
2859*7c478bd9Sstevel@tonic-gate 	errno = ETIMEDOUT;
2860*7c478bd9Sstevel@tonic-gate 	longjmp(CtxConnectTimeout, 1);
2861*7c478bd9Sstevel@tonic-gate }
2862*7c478bd9Sstevel@tonic-gate /*
2863*7c478bd9Sstevel@tonic-gate **  MAKECONNECTION_DS -- make a connection to a domain socket.
2864*7c478bd9Sstevel@tonic-gate **
2865*7c478bd9Sstevel@tonic-gate **	Parameters:
2866*7c478bd9Sstevel@tonic-gate **		mux_path -- the path of the socket to connect to.
2867*7c478bd9Sstevel@tonic-gate **		mci -- a pointer to the mail connection information
2868*7c478bd9Sstevel@tonic-gate **			structure to be filled in.
2869*7c478bd9Sstevel@tonic-gate **
2870*7c478bd9Sstevel@tonic-gate **	Returns:
2871*7c478bd9Sstevel@tonic-gate **		An exit code telling whether the connection could be
2872*7c478bd9Sstevel@tonic-gate **			made and if not why not.
2873*7c478bd9Sstevel@tonic-gate **
2874*7c478bd9Sstevel@tonic-gate **	Side Effects:
2875*7c478bd9Sstevel@tonic-gate **		none.
2876*7c478bd9Sstevel@tonic-gate */
2877*7c478bd9Sstevel@tonic-gate 
2878*7c478bd9Sstevel@tonic-gate #if NETUNIX
2879*7c478bd9Sstevel@tonic-gate int
2880*7c478bd9Sstevel@tonic-gate makeconnection_ds(mux_path, mci)
2881*7c478bd9Sstevel@tonic-gate 	char *mux_path;
2882*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
2883*7c478bd9Sstevel@tonic-gate {
2884*7c478bd9Sstevel@tonic-gate 	int sock;
2885*7c478bd9Sstevel@tonic-gate 	int rval, save_errno;
2886*7c478bd9Sstevel@tonic-gate 	long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
2887*7c478bd9Sstevel@tonic-gate 	struct sockaddr_un unix_addr;
2888*7c478bd9Sstevel@tonic-gate 
2889*7c478bd9Sstevel@tonic-gate 	/* if not safe, don't connect */
2890*7c478bd9Sstevel@tonic-gate 	rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
2891*7c478bd9Sstevel@tonic-gate 			sff, S_IRUSR|S_IWUSR, NULL);
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	if (rval != 0)
2894*7c478bd9Sstevel@tonic-gate 	{
2895*7c478bd9Sstevel@tonic-gate 		syserr("makeconnection_ds: unsafe domain socket %s",
2896*7c478bd9Sstevel@tonic-gate 			mux_path);
2897*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
2898*7c478bd9Sstevel@tonic-gate 		errno = rval;
2899*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2900*7c478bd9Sstevel@tonic-gate 	}
2901*7c478bd9Sstevel@tonic-gate 
2902*7c478bd9Sstevel@tonic-gate 	/* prepare address structure */
2903*7c478bd9Sstevel@tonic-gate 	memset(&unix_addr, '\0', sizeof unix_addr);
2904*7c478bd9Sstevel@tonic-gate 	unix_addr.sun_family = AF_UNIX;
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate 	if (strlen(mux_path) >= sizeof unix_addr.sun_path)
2907*7c478bd9Sstevel@tonic-gate 	{
2908*7c478bd9Sstevel@tonic-gate 		syserr("makeconnection_ds: domain socket name %s too long",
2909*7c478bd9Sstevel@tonic-gate 			mux_path);
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate 		/* XXX why TEMPFAIL but 5.x.y ? */
2912*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
2913*7c478bd9Sstevel@tonic-gate 		errno = ENAMETOOLONG;
2914*7c478bd9Sstevel@tonic-gate 		return EX_UNAVAILABLE;
2915*7c478bd9Sstevel@tonic-gate 	}
2916*7c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(unix_addr.sun_path, mux_path,
2917*7c478bd9Sstevel@tonic-gate 			  sizeof unix_addr.sun_path);
2918*7c478bd9Sstevel@tonic-gate 
2919*7c478bd9Sstevel@tonic-gate 	/* initialize domain socket */
2920*7c478bd9Sstevel@tonic-gate 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
2921*7c478bd9Sstevel@tonic-gate 	if (sock == -1)
2922*7c478bd9Sstevel@tonic-gate 	{
2923*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
2924*7c478bd9Sstevel@tonic-gate 		syserr("makeconnection_ds: could not create domain socket %s",
2925*7c478bd9Sstevel@tonic-gate 			mux_path);
2926*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2927*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2928*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2929*7c478bd9Sstevel@tonic-gate 	}
2930*7c478bd9Sstevel@tonic-gate 
2931*7c478bd9Sstevel@tonic-gate 	/* connect to server */
2932*7c478bd9Sstevel@tonic-gate 	if (connect(sock, (struct sockaddr *) &unix_addr,
2933*7c478bd9Sstevel@tonic-gate 		    sizeof(unix_addr)) == -1)
2934*7c478bd9Sstevel@tonic-gate 	{
2935*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
2936*7c478bd9Sstevel@tonic-gate 		syserr("Could not connect to socket %s", mux_path);
2937*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2938*7c478bd9Sstevel@tonic-gate 		(void) close(sock);
2939*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2940*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2941*7c478bd9Sstevel@tonic-gate 	}
2942*7c478bd9Sstevel@tonic-gate 
2943*7c478bd9Sstevel@tonic-gate 	/* connection ok, put it into canonical form */
2944*7c478bd9Sstevel@tonic-gate 	mci->mci_out = NULL;
2945*7c478bd9Sstevel@tonic-gate 	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2946*7c478bd9Sstevel@tonic-gate 				       (void *) &sock, SM_IO_WRONLY_B, NULL))
2947*7c478bd9Sstevel@tonic-gate 					== NULL
2948*7c478bd9Sstevel@tonic-gate 	    || (sock = dup(sock)) < 0 ||
2949*7c478bd9Sstevel@tonic-gate 	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2950*7c478bd9Sstevel@tonic-gate 				      (void *) &sock, SM_IO_RDONLY_B, NULL))
2951*7c478bd9Sstevel@tonic-gate 					== NULL)
2952*7c478bd9Sstevel@tonic-gate 	{
2953*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
2954*7c478bd9Sstevel@tonic-gate 		syserr("cannot open SMTP client channel, fd=%d", sock);
2955*7c478bd9Sstevel@tonic-gate 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2956*7c478bd9Sstevel@tonic-gate 		if (mci->mci_out != NULL)
2957*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2958*7c478bd9Sstevel@tonic-gate 		(void) close(sock);
2959*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
2960*7c478bd9Sstevel@tonic-gate 		return EX_TEMPFAIL;
2961*7c478bd9Sstevel@tonic-gate 	}
2962*7c478bd9Sstevel@tonic-gate 	sm_io_automode(mci->mci_out, mci->mci_in);
2963*7c478bd9Sstevel@tonic-gate 
2964*7c478bd9Sstevel@tonic-gate 	mci_setstat(mci, EX_OK, NULL, NULL);
2965*7c478bd9Sstevel@tonic-gate 	errno = 0;
2966*7c478bd9Sstevel@tonic-gate 	return EX_OK;
2967*7c478bd9Sstevel@tonic-gate }
2968*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
2969*7c478bd9Sstevel@tonic-gate /*
2970*7c478bd9Sstevel@tonic-gate **  SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
2971*7c478bd9Sstevel@tonic-gate **
2972*7c478bd9Sstevel@tonic-gate **	Parameters:
2973*7c478bd9Sstevel@tonic-gate **		none.
2974*7c478bd9Sstevel@tonic-gate **
2975*7c478bd9Sstevel@tonic-gate **	Returns:
2976*7c478bd9Sstevel@tonic-gate **		none.
2977*7c478bd9Sstevel@tonic-gate **
2978*7c478bd9Sstevel@tonic-gate **	Side Effects:
2979*7c478bd9Sstevel@tonic-gate **		closes control socket, exits.
2980*7c478bd9Sstevel@tonic-gate */
2981*7c478bd9Sstevel@tonic-gate 
2982*7c478bd9Sstevel@tonic-gate void
2983*7c478bd9Sstevel@tonic-gate shutdown_daemon()
2984*7c478bd9Sstevel@tonic-gate {
2985*7c478bd9Sstevel@tonic-gate 	int i;
2986*7c478bd9Sstevel@tonic-gate 	char *reason;
2987*7c478bd9Sstevel@tonic-gate 
2988*7c478bd9Sstevel@tonic-gate 	sm_allsignals(true);
2989*7c478bd9Sstevel@tonic-gate 
2990*7c478bd9Sstevel@tonic-gate 	reason = ShutdownRequest;
2991*7c478bd9Sstevel@tonic-gate 	ShutdownRequest = NULL;
2992*7c478bd9Sstevel@tonic-gate 	PendingSignal = 0;
2993*7c478bd9Sstevel@tonic-gate 
2994*7c478bd9Sstevel@tonic-gate 	if (LogLevel > 9)
2995*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s",
2996*7c478bd9Sstevel@tonic-gate 			  reason == NULL ? "implicit call" : reason);
2997*7c478bd9Sstevel@tonic-gate 
2998*7c478bd9Sstevel@tonic-gate 	FileName = NULL;
2999*7c478bd9Sstevel@tonic-gate 	closecontrolsocket(true);
3000*7c478bd9Sstevel@tonic-gate #if XLA
3001*7c478bd9Sstevel@tonic-gate 	xla_all_end();
3002*7c478bd9Sstevel@tonic-gate #endif /* XLA */
3003*7c478bd9Sstevel@tonic-gate 
3004*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDaemons; i++)
3005*7c478bd9Sstevel@tonic-gate 	{
3006*7c478bd9Sstevel@tonic-gate 		if (Daemons[i].d_socket >= 0)
3007*7c478bd9Sstevel@tonic-gate 		{
3008*7c478bd9Sstevel@tonic-gate 			(void) close(Daemons[i].d_socket);
3009*7c478bd9Sstevel@tonic-gate 			Daemons[i].d_socket = -1;
3010*7c478bd9Sstevel@tonic-gate 
3011*7c478bd9Sstevel@tonic-gate #if _FFR_DAEMON_NETUNIX
3012*7c478bd9Sstevel@tonic-gate # if NETUNIX
3013*7c478bd9Sstevel@tonic-gate 			/* Remove named sockets */
3014*7c478bd9Sstevel@tonic-gate 			if (Daemons[i].d_addr.sa.sa_family == AF_UNIX)
3015*7c478bd9Sstevel@tonic-gate 			{
3016*7c478bd9Sstevel@tonic-gate 				int rval;
3017*7c478bd9Sstevel@tonic-gate 				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT;
3018*7c478bd9Sstevel@tonic-gate 
3019*7c478bd9Sstevel@tonic-gate 				/* if not safe, don't use it */
3020*7c478bd9Sstevel@tonic-gate 				rval = safefile(Daemons[i].d_addr.sunix.sun_path,
3021*7c478bd9Sstevel@tonic-gate 						RunAsUid, RunAsGid,
3022*7c478bd9Sstevel@tonic-gate 						RunAsUserName, sff,
3023*7c478bd9Sstevel@tonic-gate 						S_IRUSR|S_IWUSR, NULL);
3024*7c478bd9Sstevel@tonic-gate 				if (rval == 0 &&
3025*7c478bd9Sstevel@tonic-gate 				    unlink(Daemons[i].d_addr.sunix.sun_path) < 0)
3026*7c478bd9Sstevel@tonic-gate 				{
3027*7c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_WARNING, NOQID,
3028*7c478bd9Sstevel@tonic-gate 						  "Could not remove daemon %s socket: %s: %s",
3029*7c478bd9Sstevel@tonic-gate 						  Daemons[i].d_name,
3030*7c478bd9Sstevel@tonic-gate 						  Daemons[i].d_addr.sunix.sun_path,
3031*7c478bd9Sstevel@tonic-gate 						  sm_errstring(errno));
3032*7c478bd9Sstevel@tonic-gate 				}
3033*7c478bd9Sstevel@tonic-gate 			}
3034*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
3035*7c478bd9Sstevel@tonic-gate #endif	/* _FFR_DAEMON_NETUNIX */
3036*7c478bd9Sstevel@tonic-gate 		}
3037*7c478bd9Sstevel@tonic-gate 	}
3038*7c478bd9Sstevel@tonic-gate 
3039*7c478bd9Sstevel@tonic-gate 	finis(false, true, EX_OK);
3040*7c478bd9Sstevel@tonic-gate }
3041*7c478bd9Sstevel@tonic-gate /*
3042*7c478bd9Sstevel@tonic-gate **  RESTART_DAEMON -- Performs a clean restart of the daemon
3043*7c478bd9Sstevel@tonic-gate **
3044*7c478bd9Sstevel@tonic-gate **	Parameters:
3045*7c478bd9Sstevel@tonic-gate **		none.
3046*7c478bd9Sstevel@tonic-gate **
3047*7c478bd9Sstevel@tonic-gate **	Returns:
3048*7c478bd9Sstevel@tonic-gate **		none.
3049*7c478bd9Sstevel@tonic-gate **
3050*7c478bd9Sstevel@tonic-gate **	Side Effects:
3051*7c478bd9Sstevel@tonic-gate **		restarts the daemon or exits if restart fails.
3052*7c478bd9Sstevel@tonic-gate */
3053*7c478bd9Sstevel@tonic-gate 
3054*7c478bd9Sstevel@tonic-gate /* Make a non-DFL/IGN signal a noop */
3055*7c478bd9Sstevel@tonic-gate #define SM_NOOP_SIGNAL(sig, old)				\
3056*7c478bd9Sstevel@tonic-gate do								\
3057*7c478bd9Sstevel@tonic-gate {								\
3058*7c478bd9Sstevel@tonic-gate 	(old) = sm_signal((sig), sm_signal_noop);		\
3059*7c478bd9Sstevel@tonic-gate 	if ((old) == SIG_IGN || (old) == SIG_DFL)		\
3060*7c478bd9Sstevel@tonic-gate 		(void) sm_signal((sig), (old));			\
3061*7c478bd9Sstevel@tonic-gate } while (0)
3062*7c478bd9Sstevel@tonic-gate 
3063*7c478bd9Sstevel@tonic-gate void
3064*7c478bd9Sstevel@tonic-gate restart_daemon()
3065*7c478bd9Sstevel@tonic-gate {
3066*7c478bd9Sstevel@tonic-gate 	bool drop;
3067*7c478bd9Sstevel@tonic-gate 	int save_errno;
3068*7c478bd9Sstevel@tonic-gate 	char *reason;
3069*7c478bd9Sstevel@tonic-gate 	sigfunc_t ignore, oalrm, ousr1;
3070*7c478bd9Sstevel@tonic-gate 	extern int DtableSize;
3071*7c478bd9Sstevel@tonic-gate 
3072*7c478bd9Sstevel@tonic-gate 	/* clear the events to turn off SIGALRMs */
3073*7c478bd9Sstevel@tonic-gate 	sm_clear_events();
3074*7c478bd9Sstevel@tonic-gate 	sm_allsignals(true);
3075*7c478bd9Sstevel@tonic-gate 
3076*7c478bd9Sstevel@tonic-gate 	reason = RestartRequest;
3077*7c478bd9Sstevel@tonic-gate 	RestartRequest = NULL;
3078*7c478bd9Sstevel@tonic-gate 	PendingSignal = 0;
3079*7c478bd9Sstevel@tonic-gate 
3080*7c478bd9Sstevel@tonic-gate 	if (SaveArgv[0][0] != '/')
3081*7c478bd9Sstevel@tonic-gate 	{
3082*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 3)
3083*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, NOQID,
3084*7c478bd9Sstevel@tonic-gate 				  "could not restart: need full path");
3085*7c478bd9Sstevel@tonic-gate 		finis(false, true, EX_OSFILE);
3086*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3087*7c478bd9Sstevel@tonic-gate 	}
3088*7c478bd9Sstevel@tonic-gate 	if (LogLevel > 3)
3089*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
3090*7c478bd9Sstevel@tonic-gate 			  SaveArgv[0],
3091*7c478bd9Sstevel@tonic-gate 			  reason == NULL ? "implicit call" : reason);
3092*7c478bd9Sstevel@tonic-gate 
3093*7c478bd9Sstevel@tonic-gate 	closecontrolsocket(true);
3094*7c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
3095*7c478bd9Sstevel@tonic-gate 	cleanup_shm(DaemonPid == getpid());
3096*7c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
3097*7c478bd9Sstevel@tonic-gate 
3098*7c478bd9Sstevel@tonic-gate 	/* close locked pid file */
3099*7c478bd9Sstevel@tonic-gate 	close_sendmail_pid();
3100*7c478bd9Sstevel@tonic-gate 
3101*7c478bd9Sstevel@tonic-gate 	/*
3102*7c478bd9Sstevel@tonic-gate 	**  Want to drop to the user who started the process in all cases
3103*7c478bd9Sstevel@tonic-gate 	**  *but* when running as "smmsp" for the clientmqueue queue run
3104*7c478bd9Sstevel@tonic-gate 	**  daemon.  In that case, UseMSP will be true, RunAsUid should not
3105*7c478bd9Sstevel@tonic-gate 	**  be root, and RealUid should be either 0 or RunAsUid.
3106*7c478bd9Sstevel@tonic-gate 	*/
3107*7c478bd9Sstevel@tonic-gate 
3108*7c478bd9Sstevel@tonic-gate 	drop = !(UseMSP && RunAsUid != 0 &&
3109*7c478bd9Sstevel@tonic-gate 		 (RealUid == 0 || RealUid == RunAsUid));
3110*7c478bd9Sstevel@tonic-gate 
3111*7c478bd9Sstevel@tonic-gate 	if (drop_privileges(drop) != EX_OK)
3112*7c478bd9Sstevel@tonic-gate 	{
3113*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 0)
3114*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ALERT, NOQID,
3115*7c478bd9Sstevel@tonic-gate 				  "could not drop privileges: %s",
3116*7c478bd9Sstevel@tonic-gate 				  sm_errstring(errno));
3117*7c478bd9Sstevel@tonic-gate 		finis(false, true, EX_OSERR);
3118*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3119*7c478bd9Sstevel@tonic-gate 	}
3120*7c478bd9Sstevel@tonic-gate 
3121*7c478bd9Sstevel@tonic-gate 	sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
3122*7c478bd9Sstevel@tonic-gate 
3123*7c478bd9Sstevel@tonic-gate 	/*
3124*7c478bd9Sstevel@tonic-gate 	**  Need to allow signals before execve() to make them "harmless".
3125*7c478bd9Sstevel@tonic-gate 	**  However, the default action can be "terminate", so it isn't
3126*7c478bd9Sstevel@tonic-gate 	**  really harmless.  Setting signals to IGN will cause them to be
3127*7c478bd9Sstevel@tonic-gate 	**  ignored in the new process to, so that isn't a good alternative.
3128*7c478bd9Sstevel@tonic-gate 	*/
3129*7c478bd9Sstevel@tonic-gate 
3130*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGALRM, oalrm);
3131*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGCHLD, ignore);
3132*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGHUP, ignore);
3133*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGINT, ignore);
3134*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGPIPE, ignore);
3135*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGTERM, ignore);
3136*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1
3137*7c478bd9Sstevel@tonic-gate 	SM_NOOP_SIGNAL(SIGUSR1, ousr1);
3138*7c478bd9Sstevel@tonic-gate #endif /* SIGUSR1 */
3139*7c478bd9Sstevel@tonic-gate 
3140*7c478bd9Sstevel@tonic-gate 	/* Turn back on signals */
3141*7c478bd9Sstevel@tonic-gate 	sm_allsignals(false);
3142*7c478bd9Sstevel@tonic-gate 
3143*7c478bd9Sstevel@tonic-gate 	(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
3144*7c478bd9Sstevel@tonic-gate 	save_errno = errno;
3145*7c478bd9Sstevel@tonic-gate 
3146*7c478bd9Sstevel@tonic-gate 	/* block signals again and restore needed signals */
3147*7c478bd9Sstevel@tonic-gate 	sm_allsignals(true);
3148*7c478bd9Sstevel@tonic-gate 
3149*7c478bd9Sstevel@tonic-gate 	/* For finis() events */
3150*7c478bd9Sstevel@tonic-gate 	(void) sm_signal(SIGALRM, oalrm);
3151*7c478bd9Sstevel@tonic-gate 
3152*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1
3153*7c478bd9Sstevel@tonic-gate 	/* For debugging finis() */
3154*7c478bd9Sstevel@tonic-gate 	(void) sm_signal(SIGUSR1, ousr1);
3155*7c478bd9Sstevel@tonic-gate #endif /* SIGUSR1 */
3156*7c478bd9Sstevel@tonic-gate 
3157*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
3158*7c478bd9Sstevel@tonic-gate 	if (LogLevel > 0)
3159*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s",
3160*7c478bd9Sstevel@tonic-gate 			  SaveArgv[0], sm_errstring(errno));
3161*7c478bd9Sstevel@tonic-gate 	finis(false, true, EX_OSFILE);
3162*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
3163*7c478bd9Sstevel@tonic-gate }
3164*7c478bd9Sstevel@tonic-gate /*
3165*7c478bd9Sstevel@tonic-gate **  MYHOSTNAME -- return the name of this host.
3166*7c478bd9Sstevel@tonic-gate **
3167*7c478bd9Sstevel@tonic-gate **	Parameters:
3168*7c478bd9Sstevel@tonic-gate **		hostbuf -- a place to return the name of this host.
3169*7c478bd9Sstevel@tonic-gate **		size -- the size of hostbuf.
3170*7c478bd9Sstevel@tonic-gate **
3171*7c478bd9Sstevel@tonic-gate **	Returns:
3172*7c478bd9Sstevel@tonic-gate **		A list of aliases for this host.
3173*7c478bd9Sstevel@tonic-gate **
3174*7c478bd9Sstevel@tonic-gate **	Side Effects:
3175*7c478bd9Sstevel@tonic-gate **		Adds numeric codes to $=w.
3176*7c478bd9Sstevel@tonic-gate */
3177*7c478bd9Sstevel@tonic-gate 
3178*7c478bd9Sstevel@tonic-gate struct hostent *
3179*7c478bd9Sstevel@tonic-gate myhostname(hostbuf, size)
3180*7c478bd9Sstevel@tonic-gate 	char hostbuf[];
3181*7c478bd9Sstevel@tonic-gate 	int size;
3182*7c478bd9Sstevel@tonic-gate {
3183*7c478bd9Sstevel@tonic-gate 	register struct hostent *hp;
3184*7c478bd9Sstevel@tonic-gate 
3185*7c478bd9Sstevel@tonic-gate 	if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
3186*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(hostbuf, "localhost", size);
3187*7c478bd9Sstevel@tonic-gate 	hp = sm_gethostbyname(hostbuf, InetMode);
3188*7c478bd9Sstevel@tonic-gate #if NETINET && NETINET6
3189*7c478bd9Sstevel@tonic-gate 	if (hp == NULL && InetMode == AF_INET6)
3190*7c478bd9Sstevel@tonic-gate 	{
3191*7c478bd9Sstevel@tonic-gate 		/*
3192*7c478bd9Sstevel@tonic-gate 		**  It's possible that this IPv6 enabled machine doesn't
3193*7c478bd9Sstevel@tonic-gate 		**  actually have any IPv6 interfaces and, therefore, no
3194*7c478bd9Sstevel@tonic-gate 		**  IPv6 addresses.  Fall back to AF_INET.
3195*7c478bd9Sstevel@tonic-gate 		*/
3196*7c478bd9Sstevel@tonic-gate 
3197*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyname(hostbuf, AF_INET);
3198*7c478bd9Sstevel@tonic-gate 	}
3199*7c478bd9Sstevel@tonic-gate #endif /* NETINET && NETINET6 */
3200*7c478bd9Sstevel@tonic-gate 	if (hp == NULL)
3201*7c478bd9Sstevel@tonic-gate 		return NULL;
3202*7c478bd9Sstevel@tonic-gate 	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
3203*7c478bd9Sstevel@tonic-gate 		(void) cleanstrcpy(hostbuf, hp->h_name, size);
3204*7c478bd9Sstevel@tonic-gate 
3205*7c478bd9Sstevel@tonic-gate #if NETINFO
3206*7c478bd9Sstevel@tonic-gate 	if (strchr(hostbuf, '.') == NULL)
3207*7c478bd9Sstevel@tonic-gate 	{
3208*7c478bd9Sstevel@tonic-gate 		char *domainname;
3209*7c478bd9Sstevel@tonic-gate 
3210*7c478bd9Sstevel@tonic-gate 		domainname = ni_propval("/locations", NULL, "resolver",
3211*7c478bd9Sstevel@tonic-gate 					"domain", '\0');
3212*7c478bd9Sstevel@tonic-gate 		if (domainname != NULL &&
3213*7c478bd9Sstevel@tonic-gate 		    strlen(domainname) + strlen(hostbuf) + 1 < size)
3214*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcat2(hostbuf, ".", domainname, size);
3215*7c478bd9Sstevel@tonic-gate 	}
3216*7c478bd9Sstevel@tonic-gate #endif /* NETINFO */
3217*7c478bd9Sstevel@tonic-gate 
3218*7c478bd9Sstevel@tonic-gate 	/*
3219*7c478bd9Sstevel@tonic-gate 	**  If there is still no dot in the name, try looking for a
3220*7c478bd9Sstevel@tonic-gate 	**  dotted alias.
3221*7c478bd9Sstevel@tonic-gate 	*/
3222*7c478bd9Sstevel@tonic-gate 
3223*7c478bd9Sstevel@tonic-gate 	if (strchr(hostbuf, '.') == NULL)
3224*7c478bd9Sstevel@tonic-gate 	{
3225*7c478bd9Sstevel@tonic-gate 		char **ha;
3226*7c478bd9Sstevel@tonic-gate 
3227*7c478bd9Sstevel@tonic-gate 		for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
3228*7c478bd9Sstevel@tonic-gate 		{
3229*7c478bd9Sstevel@tonic-gate 			if (strchr(*ha, '.') != NULL)
3230*7c478bd9Sstevel@tonic-gate 			{
3231*7c478bd9Sstevel@tonic-gate 				(void) cleanstrcpy(hostbuf, *ha, size - 1);
3232*7c478bd9Sstevel@tonic-gate 				hostbuf[size - 1] = '\0';
3233*7c478bd9Sstevel@tonic-gate 				break;
3234*7c478bd9Sstevel@tonic-gate 			}
3235*7c478bd9Sstevel@tonic-gate 		}
3236*7c478bd9Sstevel@tonic-gate 	}
3237*7c478bd9Sstevel@tonic-gate 
3238*7c478bd9Sstevel@tonic-gate 	/*
3239*7c478bd9Sstevel@tonic-gate 	**  If _still_ no dot, wait for a while and try again -- it is
3240*7c478bd9Sstevel@tonic-gate 	**  possible that some service is starting up.  This can result
3241*7c478bd9Sstevel@tonic-gate 	**  in excessive delays if the system is badly configured, but
3242*7c478bd9Sstevel@tonic-gate 	**  there really isn't a way around that, particularly given that
3243*7c478bd9Sstevel@tonic-gate 	**  the config file hasn't been read at this point.
3244*7c478bd9Sstevel@tonic-gate 	**  All in all, a bit of a mess.
3245*7c478bd9Sstevel@tonic-gate 	*/
3246*7c478bd9Sstevel@tonic-gate 
3247*7c478bd9Sstevel@tonic-gate 	if (strchr(hostbuf, '.') == NULL &&
3248*7c478bd9Sstevel@tonic-gate 	    !getcanonname(hostbuf, size, true, NULL))
3249*7c478bd9Sstevel@tonic-gate 	{
3250*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_CRIT, NOQID,
3251*7c478bd9Sstevel@tonic-gate 			  "My unqualified host name (%s) unknown; sleeping for retry",
3252*7c478bd9Sstevel@tonic-gate 			  hostbuf);
3253*7c478bd9Sstevel@tonic-gate 		message("My unqualified host name (%s) unknown; sleeping for retry",
3254*7c478bd9Sstevel@tonic-gate 			hostbuf);
3255*7c478bd9Sstevel@tonic-gate 		(void) sleep(60);
3256*7c478bd9Sstevel@tonic-gate 		if (!getcanonname(hostbuf, size, true, NULL))
3257*7c478bd9Sstevel@tonic-gate 		{
3258*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ALERT, NOQID,
3259*7c478bd9Sstevel@tonic-gate 				  "unable to qualify my own domain name (%s) -- using short name",
3260*7c478bd9Sstevel@tonic-gate 				  hostbuf);
3261*7c478bd9Sstevel@tonic-gate 			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
3262*7c478bd9Sstevel@tonic-gate 				hostbuf);
3263*7c478bd9Sstevel@tonic-gate 		}
3264*7c478bd9Sstevel@tonic-gate 	}
3265*7c478bd9Sstevel@tonic-gate 	return hp;
3266*7c478bd9Sstevel@tonic-gate }
3267*7c478bd9Sstevel@tonic-gate /*
3268*7c478bd9Sstevel@tonic-gate **  ADDRCMP -- compare two host addresses
3269*7c478bd9Sstevel@tonic-gate **
3270*7c478bd9Sstevel@tonic-gate **	Parameters:
3271*7c478bd9Sstevel@tonic-gate **		hp -- hostent structure for the first address
3272*7c478bd9Sstevel@tonic-gate **		ha -- actual first address
3273*7c478bd9Sstevel@tonic-gate **		sa -- second address
3274*7c478bd9Sstevel@tonic-gate **
3275*7c478bd9Sstevel@tonic-gate **	Returns:
3276*7c478bd9Sstevel@tonic-gate **		0 -- if ha and sa match
3277*7c478bd9Sstevel@tonic-gate **		else -- they don't match
3278*7c478bd9Sstevel@tonic-gate */
3279*7c478bd9Sstevel@tonic-gate 
3280*7c478bd9Sstevel@tonic-gate static int
3281*7c478bd9Sstevel@tonic-gate addrcmp(hp, ha, sa)
3282*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
3283*7c478bd9Sstevel@tonic-gate 	char *ha;
3284*7c478bd9Sstevel@tonic-gate 	SOCKADDR *sa;
3285*7c478bd9Sstevel@tonic-gate {
3286*7c478bd9Sstevel@tonic-gate #if NETINET6
3287*7c478bd9Sstevel@tonic-gate 	unsigned char *a;
3288*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3289*7c478bd9Sstevel@tonic-gate 
3290*7c478bd9Sstevel@tonic-gate 	switch (sa->sa.sa_family)
3291*7c478bd9Sstevel@tonic-gate 	{
3292*7c478bd9Sstevel@tonic-gate #if NETINET
3293*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
3294*7c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET)
3295*7c478bd9Sstevel@tonic-gate 			return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
3296*7c478bd9Sstevel@tonic-gate 		break;
3297*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
3298*7c478bd9Sstevel@tonic-gate 
3299*7c478bd9Sstevel@tonic-gate #if NETINET6
3300*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
3301*7c478bd9Sstevel@tonic-gate 		a = (unsigned char *) &sa->sin6.sin6_addr;
3302*7c478bd9Sstevel@tonic-gate 
3303*7c478bd9Sstevel@tonic-gate 		/* Straight binary comparison */
3304*7c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET6)
3305*7c478bd9Sstevel@tonic-gate 			return memcmp(ha, a, IN6ADDRSZ);
3306*7c478bd9Sstevel@tonic-gate 
3307*7c478bd9Sstevel@tonic-gate 		/* If IPv4-mapped IPv6 address, compare the IPv4 section */
3308*7c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET &&
3309*7c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
3310*7c478bd9Sstevel@tonic-gate 			return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
3311*7c478bd9Sstevel@tonic-gate 		break;
3312*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3313*7c478bd9Sstevel@tonic-gate 	}
3314*7c478bd9Sstevel@tonic-gate 	return -1;
3315*7c478bd9Sstevel@tonic-gate }
3316*7c478bd9Sstevel@tonic-gate /*
3317*7c478bd9Sstevel@tonic-gate **  GETAUTHINFO -- get the real host name associated with a file descriptor
3318*7c478bd9Sstevel@tonic-gate **
3319*7c478bd9Sstevel@tonic-gate **	Uses RFC1413 protocol to try to get info from the other end.
3320*7c478bd9Sstevel@tonic-gate **
3321*7c478bd9Sstevel@tonic-gate **	Parameters:
3322*7c478bd9Sstevel@tonic-gate **		fd -- the descriptor
3323*7c478bd9Sstevel@tonic-gate **		may_be_forged -- an outage that is set to true if the
3324*7c478bd9Sstevel@tonic-gate **			forward lookup of RealHostName does not match
3325*7c478bd9Sstevel@tonic-gate **			RealHostAddr; set to false if they do match.
3326*7c478bd9Sstevel@tonic-gate **
3327*7c478bd9Sstevel@tonic-gate **	Returns:
3328*7c478bd9Sstevel@tonic-gate **		The user@host information associated with this descriptor.
3329*7c478bd9Sstevel@tonic-gate */
3330*7c478bd9Sstevel@tonic-gate 
3331*7c478bd9Sstevel@tonic-gate static jmp_buf	CtxAuthTimeout;
3332*7c478bd9Sstevel@tonic-gate 
3333*7c478bd9Sstevel@tonic-gate static void
3334*7c478bd9Sstevel@tonic-gate authtimeout(ignore)
3335*7c478bd9Sstevel@tonic-gate 	int ignore;
3336*7c478bd9Sstevel@tonic-gate {
3337*7c478bd9Sstevel@tonic-gate 	/*
3338*7c478bd9Sstevel@tonic-gate 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3339*7c478bd9Sstevel@tonic-gate 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3340*7c478bd9Sstevel@tonic-gate 	**	DOING.
3341*7c478bd9Sstevel@tonic-gate 	*/
3342*7c478bd9Sstevel@tonic-gate 
3343*7c478bd9Sstevel@tonic-gate 	errno = ETIMEDOUT;
3344*7c478bd9Sstevel@tonic-gate 	longjmp(CtxAuthTimeout, 1);
3345*7c478bd9Sstevel@tonic-gate }
3346*7c478bd9Sstevel@tonic-gate 
3347*7c478bd9Sstevel@tonic-gate char *
3348*7c478bd9Sstevel@tonic-gate getauthinfo(fd, may_be_forged)
3349*7c478bd9Sstevel@tonic-gate 	int fd;
3350*7c478bd9Sstevel@tonic-gate 	bool *may_be_forged;
3351*7c478bd9Sstevel@tonic-gate {
3352*7c478bd9Sstevel@tonic-gate 	unsigned short SM_NONVOLATILE port = 0;
3353*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T falen;
3354*7c478bd9Sstevel@tonic-gate 	register char *volatile p = NULL;
3355*7c478bd9Sstevel@tonic-gate 	SOCKADDR la;
3356*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T lalen;
3357*7c478bd9Sstevel@tonic-gate #ifndef NO_GETSERVBYNAME
3358*7c478bd9Sstevel@tonic-gate 	register struct servent *sp;
3359*7c478bd9Sstevel@tonic-gate # if NETINET
3360*7c478bd9Sstevel@tonic-gate 	static unsigned short port4 = 0;
3361*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
3362*7c478bd9Sstevel@tonic-gate # if NETINET6
3363*7c478bd9Sstevel@tonic-gate 	static unsigned short port6 = 0;
3364*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
3365*7c478bd9Sstevel@tonic-gate #endif /* ! NO_GETSERVBYNAME */
3366*7c478bd9Sstevel@tonic-gate 	volatile int s;
3367*7c478bd9Sstevel@tonic-gate 	int i = 0;
3368*7c478bd9Sstevel@tonic-gate 	size_t len;
3369*7c478bd9Sstevel@tonic-gate 	SM_EVENT *ev;
3370*7c478bd9Sstevel@tonic-gate 	int nleft;
3371*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
3372*7c478bd9Sstevel@tonic-gate 	char *ostype = NULL;
3373*7c478bd9Sstevel@tonic-gate 	char **ha;
3374*7c478bd9Sstevel@tonic-gate 	char ibuf[MAXNAME + 1];
3375*7c478bd9Sstevel@tonic-gate 	static char hbuf[MAXNAME + MAXAUTHINFO + 11];
3376*7c478bd9Sstevel@tonic-gate 
3377*7c478bd9Sstevel@tonic-gate 	*may_be_forged = false;
3378*7c478bd9Sstevel@tonic-gate 	falen = sizeof RealHostAddr;
3379*7c478bd9Sstevel@tonic-gate 	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
3380*7c478bd9Sstevel@tonic-gate 	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
3381*7c478bd9Sstevel@tonic-gate 	{
3382*7c478bd9Sstevel@tonic-gate 		if (i < 0)
3383*7c478bd9Sstevel@tonic-gate 		{
3384*7c478bd9Sstevel@tonic-gate 			/*
3385*7c478bd9Sstevel@tonic-gate 			**  ENOTSOCK is OK: bail on anything else, but reset
3386*7c478bd9Sstevel@tonic-gate 			**  errno in this case, so a mis-report doesn't
3387*7c478bd9Sstevel@tonic-gate 			**  happen later.
3388*7c478bd9Sstevel@tonic-gate 			*/
3389*7c478bd9Sstevel@tonic-gate 
3390*7c478bd9Sstevel@tonic-gate 			if (errno != ENOTSOCK)
3391*7c478bd9Sstevel@tonic-gate 				return NULL;
3392*7c478bd9Sstevel@tonic-gate 			errno = 0;
3393*7c478bd9Sstevel@tonic-gate 		}
3394*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName,
3395*7c478bd9Sstevel@tonic-gate 				   "@localhost");
3396*7c478bd9Sstevel@tonic-gate 		if (tTd(9, 1))
3397*7c478bd9Sstevel@tonic-gate 			sm_dprintf("getauthinfo: %s\n", hbuf);
3398*7c478bd9Sstevel@tonic-gate 		return hbuf;
3399*7c478bd9Sstevel@tonic-gate 	}
3400*7c478bd9Sstevel@tonic-gate 
3401*7c478bd9Sstevel@tonic-gate 	if (RealHostName == NULL)
3402*7c478bd9Sstevel@tonic-gate 	{
3403*7c478bd9Sstevel@tonic-gate 		/* translate that to a host name */
3404*7c478bd9Sstevel@tonic-gate 		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
3405*7c478bd9Sstevel@tonic-gate 		if (strlen(RealHostName) > MAXNAME)
3406*7c478bd9Sstevel@tonic-gate 			RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
3407*7c478bd9Sstevel@tonic-gate 	}
3408*7c478bd9Sstevel@tonic-gate 
3409*7c478bd9Sstevel@tonic-gate 	/* cross check RealHostName with forward DNS lookup */
3410*7c478bd9Sstevel@tonic-gate 	if (anynet_ntoa(&RealHostAddr)[0] != '[' &&
3411*7c478bd9Sstevel@tonic-gate 	    RealHostName[0] != '[')
3412*7c478bd9Sstevel@tonic-gate 	{
3413*7c478bd9Sstevel@tonic-gate 		int family;
3414*7c478bd9Sstevel@tonic-gate 
3415*7c478bd9Sstevel@tonic-gate 		family = RealHostAddr.sa.sa_family;
3416*7c478bd9Sstevel@tonic-gate #if NETINET6 && NEEDSGETIPNODE
3417*7c478bd9Sstevel@tonic-gate 		/*
3418*7c478bd9Sstevel@tonic-gate 		**  If RealHostAddr is an IPv6 connection with an
3419*7c478bd9Sstevel@tonic-gate 		**  IPv4-mapped address, we need RealHostName's IPv4
3420*7c478bd9Sstevel@tonic-gate 		**  address(es) for addrcmp() to compare against
3421*7c478bd9Sstevel@tonic-gate 		**  RealHostAddr.
3422*7c478bd9Sstevel@tonic-gate 		**
3423*7c478bd9Sstevel@tonic-gate 		**  Actually, we only need to do this for systems
3424*7c478bd9Sstevel@tonic-gate 		**  which NEEDSGETIPNODE since the real getipnodebyname()
3425*7c478bd9Sstevel@tonic-gate 		**  already does V4MAPPED address via the AI_V4MAPPEDCFG
3426*7c478bd9Sstevel@tonic-gate 		**  flag.  A better fix to this problem is to add this
3427*7c478bd9Sstevel@tonic-gate 		**  functionality to our stub getipnodebyname().
3428*7c478bd9Sstevel@tonic-gate 		*/
3429*7c478bd9Sstevel@tonic-gate 
3430*7c478bd9Sstevel@tonic-gate 		if (family == AF_INET6 &&
3431*7c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
3432*7c478bd9Sstevel@tonic-gate 			family = AF_INET;
3433*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 && NEEDSGETIPNODE */
3434*7c478bd9Sstevel@tonic-gate 
3435*7c478bd9Sstevel@tonic-gate 		/* try to match the reverse against the forward lookup */
3436*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyname(RealHostName, family);
3437*7c478bd9Sstevel@tonic-gate 		if (hp == NULL)
3438*7c478bd9Sstevel@tonic-gate 		{
3439*7c478bd9Sstevel@tonic-gate 			/* XXX: Could be a temporary error on forward lookup */
3440*7c478bd9Sstevel@tonic-gate 			*may_be_forged = true;
3441*7c478bd9Sstevel@tonic-gate 		}
3442*7c478bd9Sstevel@tonic-gate 		else
3443*7c478bd9Sstevel@tonic-gate 		{
3444*7c478bd9Sstevel@tonic-gate 			for (ha = hp->h_addr_list; *ha != NULL; ha++)
3445*7c478bd9Sstevel@tonic-gate 			{
3446*7c478bd9Sstevel@tonic-gate 				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
3447*7c478bd9Sstevel@tonic-gate 					break;
3448*7c478bd9Sstevel@tonic-gate 			}
3449*7c478bd9Sstevel@tonic-gate 			*may_be_forged = *ha == NULL;
3450*7c478bd9Sstevel@tonic-gate #if NETINET6
3451*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
3452*7c478bd9Sstevel@tonic-gate 			hp = NULL;
3453*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3454*7c478bd9Sstevel@tonic-gate 		}
3455*7c478bd9Sstevel@tonic-gate 	}
3456*7c478bd9Sstevel@tonic-gate 
3457*7c478bd9Sstevel@tonic-gate 	if (TimeOuts.to_ident == 0)
3458*7c478bd9Sstevel@tonic-gate 		goto noident;
3459*7c478bd9Sstevel@tonic-gate 
3460*7c478bd9Sstevel@tonic-gate 	lalen = sizeof la;
3461*7c478bd9Sstevel@tonic-gate 	switch (RealHostAddr.sa.sa_family)
3462*7c478bd9Sstevel@tonic-gate 	{
3463*7c478bd9Sstevel@tonic-gate #if NETINET
3464*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
3465*7c478bd9Sstevel@tonic-gate 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
3466*7c478bd9Sstevel@tonic-gate 		    lalen <= 0 ||
3467*7c478bd9Sstevel@tonic-gate 		    la.sa.sa_family != AF_INET)
3468*7c478bd9Sstevel@tonic-gate 		{
3469*7c478bd9Sstevel@tonic-gate 			/* no ident info */
3470*7c478bd9Sstevel@tonic-gate 			goto noident;
3471*7c478bd9Sstevel@tonic-gate 		}
3472*7c478bd9Sstevel@tonic-gate 		port = RealHostAddr.sin.sin_port;
3473*7c478bd9Sstevel@tonic-gate 
3474*7c478bd9Sstevel@tonic-gate 		/* create ident query */
3475*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
3476*7c478bd9Sstevel@tonic-gate 				ntohs(RealHostAddr.sin.sin_port),
3477*7c478bd9Sstevel@tonic-gate 				ntohs(la.sin.sin_port));
3478*7c478bd9Sstevel@tonic-gate 
3479*7c478bd9Sstevel@tonic-gate 		/* create local address */
3480*7c478bd9Sstevel@tonic-gate 		la.sin.sin_port = 0;
3481*7c478bd9Sstevel@tonic-gate 
3482*7c478bd9Sstevel@tonic-gate 		/* create foreign address */
3483*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
3484*7c478bd9Sstevel@tonic-gate 		RealHostAddr.sin.sin_port = htons(113);
3485*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
3486*7c478bd9Sstevel@tonic-gate 
3487*7c478bd9Sstevel@tonic-gate 		/*
3488*7c478bd9Sstevel@tonic-gate 		**  getservbyname() consumes about 5% of the time
3489*7c478bd9Sstevel@tonic-gate 		**  when receiving a small message (almost all of the time
3490*7c478bd9Sstevel@tonic-gate 		**  spent in this routine).
3491*7c478bd9Sstevel@tonic-gate 		**  Hence we store the port in a static variable
3492*7c478bd9Sstevel@tonic-gate 		**  to save this time.
3493*7c478bd9Sstevel@tonic-gate 		**  The portnumber shouldn't change very often...
3494*7c478bd9Sstevel@tonic-gate 		**  This code makes the assumption that the port number
3495*7c478bd9Sstevel@tonic-gate 		**  is not 0.
3496*7c478bd9Sstevel@tonic-gate 		*/
3497*7c478bd9Sstevel@tonic-gate 
3498*7c478bd9Sstevel@tonic-gate 		if (port4 == 0)
3499*7c478bd9Sstevel@tonic-gate 		{
3500*7c478bd9Sstevel@tonic-gate 			sp = getservbyname("auth", "tcp");
3501*7c478bd9Sstevel@tonic-gate 			if (sp != NULL)
3502*7c478bd9Sstevel@tonic-gate 				port4 = sp->s_port;
3503*7c478bd9Sstevel@tonic-gate 			else
3504*7c478bd9Sstevel@tonic-gate 				port4 = htons(113);
3505*7c478bd9Sstevel@tonic-gate 		}
3506*7c478bd9Sstevel@tonic-gate 		RealHostAddr.sin.sin_port = port4;
3507*7c478bd9Sstevel@tonic-gate 		break;
3508*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
3509*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
3510*7c478bd9Sstevel@tonic-gate 
3511*7c478bd9Sstevel@tonic-gate #if NETINET6
3512*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
3513*7c478bd9Sstevel@tonic-gate 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
3514*7c478bd9Sstevel@tonic-gate 		    lalen <= 0 ||
3515*7c478bd9Sstevel@tonic-gate 		    la.sa.sa_family != AF_INET6)
3516*7c478bd9Sstevel@tonic-gate 		{
3517*7c478bd9Sstevel@tonic-gate 			/* no ident info */
3518*7c478bd9Sstevel@tonic-gate 			goto noident;
3519*7c478bd9Sstevel@tonic-gate 		}
3520*7c478bd9Sstevel@tonic-gate 		port = RealHostAddr.sin6.sin6_port;
3521*7c478bd9Sstevel@tonic-gate 
3522*7c478bd9Sstevel@tonic-gate 		/* create ident query */
3523*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
3524*7c478bd9Sstevel@tonic-gate 				ntohs(RealHostAddr.sin6.sin6_port),
3525*7c478bd9Sstevel@tonic-gate 				ntohs(la.sin6.sin6_port));
3526*7c478bd9Sstevel@tonic-gate 
3527*7c478bd9Sstevel@tonic-gate 		/* create local address */
3528*7c478bd9Sstevel@tonic-gate 		la.sin6.sin6_port = 0;
3529*7c478bd9Sstevel@tonic-gate 
3530*7c478bd9Sstevel@tonic-gate 		/* create foreign address */
3531*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
3532*7c478bd9Sstevel@tonic-gate 		RealHostAddr.sin6.sin6_port = htons(113);
3533*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
3534*7c478bd9Sstevel@tonic-gate 		if (port6 == 0)
3535*7c478bd9Sstevel@tonic-gate 		{
3536*7c478bd9Sstevel@tonic-gate 			sp = getservbyname("auth", "tcp");
3537*7c478bd9Sstevel@tonic-gate 			if (sp != NULL)
3538*7c478bd9Sstevel@tonic-gate 				port6 = sp->s_port;
3539*7c478bd9Sstevel@tonic-gate 			else
3540*7c478bd9Sstevel@tonic-gate 				port6 = htons(113);
3541*7c478bd9Sstevel@tonic-gate 		}
3542*7c478bd9Sstevel@tonic-gate 		RealHostAddr.sin6.sin6_port = port6;
3543*7c478bd9Sstevel@tonic-gate 		break;
3544*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
3545*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3546*7c478bd9Sstevel@tonic-gate 	  default:
3547*7c478bd9Sstevel@tonic-gate 		/* no ident info */
3548*7c478bd9Sstevel@tonic-gate 		goto noident;
3549*7c478bd9Sstevel@tonic-gate 	}
3550*7c478bd9Sstevel@tonic-gate 
3551*7c478bd9Sstevel@tonic-gate 	s = -1;
3552*7c478bd9Sstevel@tonic-gate 	if (setjmp(CtxAuthTimeout) != 0)
3553*7c478bd9Sstevel@tonic-gate 	{
3554*7c478bd9Sstevel@tonic-gate 		if (s >= 0)
3555*7c478bd9Sstevel@tonic-gate 			(void) close(s);
3556*7c478bd9Sstevel@tonic-gate 		goto noident;
3557*7c478bd9Sstevel@tonic-gate 	}
3558*7c478bd9Sstevel@tonic-gate 
3559*7c478bd9Sstevel@tonic-gate 	/* put a timeout around the whole thing */
3560*7c478bd9Sstevel@tonic-gate 	ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0);
3561*7c478bd9Sstevel@tonic-gate 
3562*7c478bd9Sstevel@tonic-gate 	/* connect to foreign IDENT server using same address as SMTP socket */
3563*7c478bd9Sstevel@tonic-gate 	s = socket(la.sa.sa_family, SOCK_STREAM, 0);
3564*7c478bd9Sstevel@tonic-gate 	if (s < 0)
3565*7c478bd9Sstevel@tonic-gate 	{
3566*7c478bd9Sstevel@tonic-gate 		sm_clrevent(ev);
3567*7c478bd9Sstevel@tonic-gate 		goto noident;
3568*7c478bd9Sstevel@tonic-gate 	}
3569*7c478bd9Sstevel@tonic-gate 	if (bind(s, &la.sa, lalen) < 0 ||
3570*7c478bd9Sstevel@tonic-gate 	    connect(s, &RealHostAddr.sa, lalen) < 0)
3571*7c478bd9Sstevel@tonic-gate 		goto closeident;
3572*7c478bd9Sstevel@tonic-gate 
3573*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 10))
3574*7c478bd9Sstevel@tonic-gate 		sm_dprintf("getauthinfo: sent %s", ibuf);
3575*7c478bd9Sstevel@tonic-gate 
3576*7c478bd9Sstevel@tonic-gate 	/* send query */
3577*7c478bd9Sstevel@tonic-gate 	if (write(s, ibuf, strlen(ibuf)) < 0)
3578*7c478bd9Sstevel@tonic-gate 		goto closeident;
3579*7c478bd9Sstevel@tonic-gate 
3580*7c478bd9Sstevel@tonic-gate 	/* get result */
3581*7c478bd9Sstevel@tonic-gate 	p = &ibuf[0];
3582*7c478bd9Sstevel@tonic-gate 	nleft = sizeof ibuf - 1;
3583*7c478bd9Sstevel@tonic-gate 	while ((i = read(s, p, nleft)) > 0)
3584*7c478bd9Sstevel@tonic-gate 	{
3585*7c478bd9Sstevel@tonic-gate 		char *s;
3586*7c478bd9Sstevel@tonic-gate 
3587*7c478bd9Sstevel@tonic-gate 		p += i;
3588*7c478bd9Sstevel@tonic-gate 		nleft -= i;
3589*7c478bd9Sstevel@tonic-gate 		*p = '\0';
3590*7c478bd9Sstevel@tonic-gate 		if ((s = strchr(ibuf, '\n')) != NULL)
3591*7c478bd9Sstevel@tonic-gate 		{
3592*7c478bd9Sstevel@tonic-gate 			if (p > s + 1)
3593*7c478bd9Sstevel@tonic-gate 			{
3594*7c478bd9Sstevel@tonic-gate 				p = s + 1;
3595*7c478bd9Sstevel@tonic-gate 				*p = '\0';
3596*7c478bd9Sstevel@tonic-gate 			}
3597*7c478bd9Sstevel@tonic-gate 			break;
3598*7c478bd9Sstevel@tonic-gate 		}
3599*7c478bd9Sstevel@tonic-gate 		if (nleft <= 0)
3600*7c478bd9Sstevel@tonic-gate 			break;
3601*7c478bd9Sstevel@tonic-gate 	}
3602*7c478bd9Sstevel@tonic-gate 	(void) close(s);
3603*7c478bd9Sstevel@tonic-gate 	sm_clrevent(ev);
3604*7c478bd9Sstevel@tonic-gate 	if (i < 0 || p == &ibuf[0])
3605*7c478bd9Sstevel@tonic-gate 		goto noident;
3606*7c478bd9Sstevel@tonic-gate 
3607*7c478bd9Sstevel@tonic-gate 	if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r')
3608*7c478bd9Sstevel@tonic-gate 		p--;
3609*7c478bd9Sstevel@tonic-gate 	*++p = '\0';
3610*7c478bd9Sstevel@tonic-gate 
3611*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 3))
3612*7c478bd9Sstevel@tonic-gate 		sm_dprintf("getauthinfo:  got %s\n", ibuf);
3613*7c478bd9Sstevel@tonic-gate 
3614*7c478bd9Sstevel@tonic-gate 	/* parse result */
3615*7c478bd9Sstevel@tonic-gate 	p = strchr(ibuf, ':');
3616*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
3617*7c478bd9Sstevel@tonic-gate 	{
3618*7c478bd9Sstevel@tonic-gate 		/* malformed response */
3619*7c478bd9Sstevel@tonic-gate 		goto noident;
3620*7c478bd9Sstevel@tonic-gate 	}
3621*7c478bd9Sstevel@tonic-gate 	while (isascii(*++p) && isspace(*p))
3622*7c478bd9Sstevel@tonic-gate 		continue;
3623*7c478bd9Sstevel@tonic-gate 	if (sm_strncasecmp(p, "userid", 6) != 0)
3624*7c478bd9Sstevel@tonic-gate 	{
3625*7c478bd9Sstevel@tonic-gate 		/* presumably an error string */
3626*7c478bd9Sstevel@tonic-gate 		goto noident;
3627*7c478bd9Sstevel@tonic-gate 	}
3628*7c478bd9Sstevel@tonic-gate 	p += 6;
3629*7c478bd9Sstevel@tonic-gate 	while (isascii(*p) && isspace(*p))
3630*7c478bd9Sstevel@tonic-gate 		p++;
3631*7c478bd9Sstevel@tonic-gate 	if (*p++ != ':')
3632*7c478bd9Sstevel@tonic-gate 	{
3633*7c478bd9Sstevel@tonic-gate 		/* either useridxx or malformed response */
3634*7c478bd9Sstevel@tonic-gate 		goto noident;
3635*7c478bd9Sstevel@tonic-gate 	}
3636*7c478bd9Sstevel@tonic-gate 
3637*7c478bd9Sstevel@tonic-gate 	/* p now points to the OSTYPE field */
3638*7c478bd9Sstevel@tonic-gate 	while (isascii(*p) && isspace(*p))
3639*7c478bd9Sstevel@tonic-gate 		p++;
3640*7c478bd9Sstevel@tonic-gate 	ostype = p;
3641*7c478bd9Sstevel@tonic-gate 	p = strchr(p, ':');
3642*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
3643*7c478bd9Sstevel@tonic-gate 	{
3644*7c478bd9Sstevel@tonic-gate 		/* malformed response */
3645*7c478bd9Sstevel@tonic-gate 		goto noident;
3646*7c478bd9Sstevel@tonic-gate 	}
3647*7c478bd9Sstevel@tonic-gate 	else
3648*7c478bd9Sstevel@tonic-gate 	{
3649*7c478bd9Sstevel@tonic-gate 		char *charset;
3650*7c478bd9Sstevel@tonic-gate 
3651*7c478bd9Sstevel@tonic-gate 		*p = '\0';
3652*7c478bd9Sstevel@tonic-gate 		charset = strchr(ostype, ',');
3653*7c478bd9Sstevel@tonic-gate 		if (charset != NULL)
3654*7c478bd9Sstevel@tonic-gate 			*charset = '\0';
3655*7c478bd9Sstevel@tonic-gate 	}
3656*7c478bd9Sstevel@tonic-gate 
3657*7c478bd9Sstevel@tonic-gate 	/* 1413 says don't do this -- but it's broken otherwise */
3658*7c478bd9Sstevel@tonic-gate 	while (isascii(*++p) && isspace(*p))
3659*7c478bd9Sstevel@tonic-gate 		continue;
3660*7c478bd9Sstevel@tonic-gate 
3661*7c478bd9Sstevel@tonic-gate 	/* p now points to the authenticated name -- copy carefully */
3662*7c478bd9Sstevel@tonic-gate 	if (sm_strncasecmp(ostype, "other", 5) == 0 &&
3663*7c478bd9Sstevel@tonic-gate 	    (ostype[5] == ' ' || ostype[5] == '\0'))
3664*7c478bd9Sstevel@tonic-gate 	{
3665*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf);
3666*7c478bd9Sstevel@tonic-gate 		cleanstrcpy(&hbuf[6], p, MAXAUTHINFO);
3667*7c478bd9Sstevel@tonic-gate 	}
3668*7c478bd9Sstevel@tonic-gate 	else
3669*7c478bd9Sstevel@tonic-gate 		cleanstrcpy(hbuf, p, MAXAUTHINFO);
3670*7c478bd9Sstevel@tonic-gate 	len = strlen(hbuf);
3671*7c478bd9Sstevel@tonic-gate 	(void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@",
3672*7c478bd9Sstevel@tonic-gate 			   RealHostName == NULL ? "localhost" : RealHostName);
3673*7c478bd9Sstevel@tonic-gate 	goto postident;
3674*7c478bd9Sstevel@tonic-gate 
3675*7c478bd9Sstevel@tonic-gate closeident:
3676*7c478bd9Sstevel@tonic-gate 	(void) close(s);
3677*7c478bd9Sstevel@tonic-gate 	sm_clrevent(ev);
3678*7c478bd9Sstevel@tonic-gate 
3679*7c478bd9Sstevel@tonic-gate noident:
3680*7c478bd9Sstevel@tonic-gate 	/* put back the original incoming port */
3681*7c478bd9Sstevel@tonic-gate 	switch (RealHostAddr.sa.sa_family)
3682*7c478bd9Sstevel@tonic-gate 	{
3683*7c478bd9Sstevel@tonic-gate #if NETINET
3684*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
3685*7c478bd9Sstevel@tonic-gate 		if (port > 0)
3686*7c478bd9Sstevel@tonic-gate 			RealHostAddr.sin.sin_port = port;
3687*7c478bd9Sstevel@tonic-gate 		break;
3688*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
3689*7c478bd9Sstevel@tonic-gate 
3690*7c478bd9Sstevel@tonic-gate #if NETINET6
3691*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
3692*7c478bd9Sstevel@tonic-gate 		if (port > 0)
3693*7c478bd9Sstevel@tonic-gate 			RealHostAddr.sin6.sin6_port = port;
3694*7c478bd9Sstevel@tonic-gate 		break;
3695*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3696*7c478bd9Sstevel@tonic-gate 	}
3697*7c478bd9Sstevel@tonic-gate 
3698*7c478bd9Sstevel@tonic-gate 	if (RealHostName == NULL)
3699*7c478bd9Sstevel@tonic-gate 	{
3700*7c478bd9Sstevel@tonic-gate 		if (tTd(9, 1))
3701*7c478bd9Sstevel@tonic-gate 			sm_dprintf("getauthinfo: NULL\n");
3702*7c478bd9Sstevel@tonic-gate 		return NULL;
3703*7c478bd9Sstevel@tonic-gate 	}
3704*7c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf);
3705*7c478bd9Sstevel@tonic-gate 
3706*7c478bd9Sstevel@tonic-gate postident:
3707*7c478bd9Sstevel@tonic-gate #if IP_SRCROUTE
3708*7c478bd9Sstevel@tonic-gate # ifndef GET_IPOPT_DST
3709*7c478bd9Sstevel@tonic-gate #  define GET_IPOPT_DST(dst)	(dst)
3710*7c478bd9Sstevel@tonic-gate # endif /* ! GET_IPOPT_DST */
3711*7c478bd9Sstevel@tonic-gate 	/*
3712*7c478bd9Sstevel@tonic-gate 	**  Extract IP source routing information.
3713*7c478bd9Sstevel@tonic-gate 	**
3714*7c478bd9Sstevel@tonic-gate 	**	Format of output for a connection from site a through b
3715*7c478bd9Sstevel@tonic-gate 	**	through c to d:
3716*7c478bd9Sstevel@tonic-gate 	**		loose:      @site-c@site-b:site-a
3717*7c478bd9Sstevel@tonic-gate 	**		strict:	   !@site-c@site-b:site-a
3718*7c478bd9Sstevel@tonic-gate 	**
3719*7c478bd9Sstevel@tonic-gate 	**	o - pointer within ipopt_list structure.
3720*7c478bd9Sstevel@tonic-gate 	**	q - pointer within ls/ss rr route data
3721*7c478bd9Sstevel@tonic-gate 	**	p - pointer to hbuf
3722*7c478bd9Sstevel@tonic-gate 	*/
3723*7c478bd9Sstevel@tonic-gate 
3724*7c478bd9Sstevel@tonic-gate 	if (RealHostAddr.sa.sa_family == AF_INET)
3725*7c478bd9Sstevel@tonic-gate 	{
3726*7c478bd9Sstevel@tonic-gate 		SOCKOPT_LEN_T ipoptlen;
3727*7c478bd9Sstevel@tonic-gate 		int j;
3728*7c478bd9Sstevel@tonic-gate 		unsigned char *q;
3729*7c478bd9Sstevel@tonic-gate 		unsigned char *o;
3730*7c478bd9Sstevel@tonic-gate 		int l;
3731*7c478bd9Sstevel@tonic-gate 		struct IPOPTION ipopt;
3732*7c478bd9Sstevel@tonic-gate 
3733*7c478bd9Sstevel@tonic-gate 		ipoptlen = sizeof ipopt;
3734*7c478bd9Sstevel@tonic-gate 		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
3735*7c478bd9Sstevel@tonic-gate 			       (char *) &ipopt, &ipoptlen) < 0)
3736*7c478bd9Sstevel@tonic-gate 			goto noipsr;
3737*7c478bd9Sstevel@tonic-gate 		if (ipoptlen == 0)
3738*7c478bd9Sstevel@tonic-gate 			goto noipsr;
3739*7c478bd9Sstevel@tonic-gate 		o = (unsigned char *) ipopt.IP_LIST;
3740*7c478bd9Sstevel@tonic-gate 		while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen)
3741*7c478bd9Sstevel@tonic-gate 		{
3742*7c478bd9Sstevel@tonic-gate 			switch (*o)
3743*7c478bd9Sstevel@tonic-gate 			{
3744*7c478bd9Sstevel@tonic-gate 			  case IPOPT_EOL:
3745*7c478bd9Sstevel@tonic-gate 				o = NULL;
3746*7c478bd9Sstevel@tonic-gate 				break;
3747*7c478bd9Sstevel@tonic-gate 
3748*7c478bd9Sstevel@tonic-gate 			  case IPOPT_NOP:
3749*7c478bd9Sstevel@tonic-gate 				o++;
3750*7c478bd9Sstevel@tonic-gate 				break;
3751*7c478bd9Sstevel@tonic-gate 
3752*7c478bd9Sstevel@tonic-gate 			  case IPOPT_SSRR:
3753*7c478bd9Sstevel@tonic-gate 			  case IPOPT_LSRR:
3754*7c478bd9Sstevel@tonic-gate 				/*
3755*7c478bd9Sstevel@tonic-gate 				**  Source routing.
3756*7c478bd9Sstevel@tonic-gate 				**	o[0] is the option type (loose/strict).
3757*7c478bd9Sstevel@tonic-gate 				**	o[1] is the length of this option,
3758*7c478bd9Sstevel@tonic-gate 				**		including option type and
3759*7c478bd9Sstevel@tonic-gate 				**		length.
3760*7c478bd9Sstevel@tonic-gate 				**	o[2] is the pointer into the route
3761*7c478bd9Sstevel@tonic-gate 				**		data.
3762*7c478bd9Sstevel@tonic-gate 				**	o[3] begins the route data.
3763*7c478bd9Sstevel@tonic-gate 				*/
3764*7c478bd9Sstevel@tonic-gate 
3765*7c478bd9Sstevel@tonic-gate 				p = &hbuf[strlen(hbuf)];
3766*7c478bd9Sstevel@tonic-gate 				l = sizeof hbuf - (hbuf - p) - 6;
3767*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(hbuf, p),
3768*7c478bd9Sstevel@tonic-gate 					" [%s@%.*s",
3769*7c478bd9Sstevel@tonic-gate 					*o == IPOPT_SSRR ? "!" : "",
3770*7c478bd9Sstevel@tonic-gate 					l > 240 ? 120 : l / 2,
3771*7c478bd9Sstevel@tonic-gate 					inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
3772*7c478bd9Sstevel@tonic-gate 				i = strlen(p);
3773*7c478bd9Sstevel@tonic-gate 				p += i;
3774*7c478bd9Sstevel@tonic-gate 				l -= strlen(p);
3775*7c478bd9Sstevel@tonic-gate 
3776*7c478bd9Sstevel@tonic-gate 				j = o[1] / sizeof(struct in_addr) - 1;
3777*7c478bd9Sstevel@tonic-gate 
3778*7c478bd9Sstevel@tonic-gate 				/* q skips length and router pointer to data */
3779*7c478bd9Sstevel@tonic-gate 				q = &o[3];
3780*7c478bd9Sstevel@tonic-gate 				for ( ; j >= 0; j--)
3781*7c478bd9Sstevel@tonic-gate 				{
3782*7c478bd9Sstevel@tonic-gate 					struct in_addr addr;
3783*7c478bd9Sstevel@tonic-gate 
3784*7c478bd9Sstevel@tonic-gate 					memcpy(&addr, q, sizeof(addr));
3785*7c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(p,
3786*7c478bd9Sstevel@tonic-gate 						SPACELEFT(hbuf, p),
3787*7c478bd9Sstevel@tonic-gate 						"%c%.*s",
3788*7c478bd9Sstevel@tonic-gate 						j != 0 ? '@' : ':',
3789*7c478bd9Sstevel@tonic-gate 						l > 240 ? 120 :
3790*7c478bd9Sstevel@tonic-gate 							j == 0 ? l : l / 2,
3791*7c478bd9Sstevel@tonic-gate 						inet_ntoa(addr));
3792*7c478bd9Sstevel@tonic-gate 					i = strlen(p);
3793*7c478bd9Sstevel@tonic-gate 					p += i;
3794*7c478bd9Sstevel@tonic-gate 					l -= i + 1;
3795*7c478bd9Sstevel@tonic-gate 					q += sizeof(struct in_addr);
3796*7c478bd9Sstevel@tonic-gate 				}
3797*7c478bd9Sstevel@tonic-gate 				o += o[1];
3798*7c478bd9Sstevel@tonic-gate 				break;
3799*7c478bd9Sstevel@tonic-gate 
3800*7c478bd9Sstevel@tonic-gate 			  default:
3801*7c478bd9Sstevel@tonic-gate 				/* Skip over option */
3802*7c478bd9Sstevel@tonic-gate 				o += o[1];
3803*7c478bd9Sstevel@tonic-gate 				break;
3804*7c478bd9Sstevel@tonic-gate 			}
3805*7c478bd9Sstevel@tonic-gate 		}
3806*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(hbuf, p), "]");
3807*7c478bd9Sstevel@tonic-gate 		goto postipsr;
3808*7c478bd9Sstevel@tonic-gate 	}
3809*7c478bd9Sstevel@tonic-gate 
3810*7c478bd9Sstevel@tonic-gate noipsr:
3811*7c478bd9Sstevel@tonic-gate #endif /* IP_SRCROUTE */
3812*7c478bd9Sstevel@tonic-gate 	if (RealHostName != NULL && RealHostName[0] != '[')
3813*7c478bd9Sstevel@tonic-gate 	{
3814*7c478bd9Sstevel@tonic-gate 		p = &hbuf[strlen(hbuf)];
3815*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
3816*7c478bd9Sstevel@tonic-gate 				   anynet_ntoa(&RealHostAddr));
3817*7c478bd9Sstevel@tonic-gate 	}
3818*7c478bd9Sstevel@tonic-gate 	if (*may_be_forged)
3819*7c478bd9Sstevel@tonic-gate 	{
3820*7c478bd9Sstevel@tonic-gate 		p = &hbuf[strlen(hbuf)];
3821*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p));
3822*7c478bd9Sstevel@tonic-gate 		macdefine(&BlankEnvelope.e_macro, A_PERM,
3823*7c478bd9Sstevel@tonic-gate 			  macid("{client_resolve}"), "FORGED");
3824*7c478bd9Sstevel@tonic-gate 	}
3825*7c478bd9Sstevel@tonic-gate 
3826*7c478bd9Sstevel@tonic-gate #if IP_SRCROUTE
3827*7c478bd9Sstevel@tonic-gate postipsr:
3828*7c478bd9Sstevel@tonic-gate #endif /* IP_SRCROUTE */
3829*7c478bd9Sstevel@tonic-gate 
3830*7c478bd9Sstevel@tonic-gate 	/* put back the original incoming port */
3831*7c478bd9Sstevel@tonic-gate 	switch (RealHostAddr.sa.sa_family)
3832*7c478bd9Sstevel@tonic-gate 	{
3833*7c478bd9Sstevel@tonic-gate #if NETINET
3834*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
3835*7c478bd9Sstevel@tonic-gate 		if (port > 0)
3836*7c478bd9Sstevel@tonic-gate 			RealHostAddr.sin.sin_port = port;
3837*7c478bd9Sstevel@tonic-gate 		break;
3838*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
3839*7c478bd9Sstevel@tonic-gate 
3840*7c478bd9Sstevel@tonic-gate #if NETINET6
3841*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
3842*7c478bd9Sstevel@tonic-gate 		if (port > 0)
3843*7c478bd9Sstevel@tonic-gate 			RealHostAddr.sin6.sin6_port = port;
3844*7c478bd9Sstevel@tonic-gate 		break;
3845*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3846*7c478bd9Sstevel@tonic-gate 	}
3847*7c478bd9Sstevel@tonic-gate 
3848*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 1))
3849*7c478bd9Sstevel@tonic-gate 		sm_dprintf("getauthinfo: %s\n", hbuf);
3850*7c478bd9Sstevel@tonic-gate 	return hbuf;
3851*7c478bd9Sstevel@tonic-gate }
3852*7c478bd9Sstevel@tonic-gate /*
3853*7c478bd9Sstevel@tonic-gate **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
3854*7c478bd9Sstevel@tonic-gate **
3855*7c478bd9Sstevel@tonic-gate **	Parameters:
3856*7c478bd9Sstevel@tonic-gate **		map -- a pointer to this map.
3857*7c478bd9Sstevel@tonic-gate **		name -- the (presumably unqualified) hostname.
3858*7c478bd9Sstevel@tonic-gate **		av -- unused -- for compatibility with other mapping
3859*7c478bd9Sstevel@tonic-gate **			functions.
3860*7c478bd9Sstevel@tonic-gate **		statp -- an exit status (out parameter) -- set to
3861*7c478bd9Sstevel@tonic-gate **			EX_TEMPFAIL if the name server is unavailable.
3862*7c478bd9Sstevel@tonic-gate **
3863*7c478bd9Sstevel@tonic-gate **	Returns:
3864*7c478bd9Sstevel@tonic-gate **		The mapping, if found.
3865*7c478bd9Sstevel@tonic-gate **		NULL if no mapping found.
3866*7c478bd9Sstevel@tonic-gate **
3867*7c478bd9Sstevel@tonic-gate **	Side Effects:
3868*7c478bd9Sstevel@tonic-gate **		Looks up the host specified in hbuf.  If it is not
3869*7c478bd9Sstevel@tonic-gate **		the canonical name for that host, return the canonical
3870*7c478bd9Sstevel@tonic-gate **		name (unless MF_MATCHONLY is set, which will cause the
3871*7c478bd9Sstevel@tonic-gate **		status only to be returned).
3872*7c478bd9Sstevel@tonic-gate */
3873*7c478bd9Sstevel@tonic-gate 
3874*7c478bd9Sstevel@tonic-gate char *
3875*7c478bd9Sstevel@tonic-gate host_map_lookup(map, name, av, statp)
3876*7c478bd9Sstevel@tonic-gate 	MAP *map;
3877*7c478bd9Sstevel@tonic-gate 	char *name;
3878*7c478bd9Sstevel@tonic-gate 	char **av;
3879*7c478bd9Sstevel@tonic-gate 	int *statp;
3880*7c478bd9Sstevel@tonic-gate {
3881*7c478bd9Sstevel@tonic-gate 	register struct hostent *hp;
3882*7c478bd9Sstevel@tonic-gate #if NETINET
3883*7c478bd9Sstevel@tonic-gate 	struct in_addr in_addr;
3884*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
3885*7c478bd9Sstevel@tonic-gate #if NETINET6
3886*7c478bd9Sstevel@tonic-gate 	struct in6_addr in6_addr;
3887*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3888*7c478bd9Sstevel@tonic-gate 	char *cp, *ans = NULL;
3889*7c478bd9Sstevel@tonic-gate 	register STAB *s;
3890*7c478bd9Sstevel@tonic-gate 	time_t now;
3891*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
3892*7c478bd9Sstevel@tonic-gate 	time_t SM_NONVOLATILE retrans = 0;
3893*7c478bd9Sstevel@tonic-gate 	int SM_NONVOLATILE retry = 0;
3894*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
3895*7c478bd9Sstevel@tonic-gate 	char hbuf[MAXNAME + 1];
3896*7c478bd9Sstevel@tonic-gate 
3897*7c478bd9Sstevel@tonic-gate 	/*
3898*7c478bd9Sstevel@tonic-gate 	**  See if we have already looked up this name.  If so, just
3899*7c478bd9Sstevel@tonic-gate 	**  return it (unless expired).
3900*7c478bd9Sstevel@tonic-gate 	*/
3901*7c478bd9Sstevel@tonic-gate 
3902*7c478bd9Sstevel@tonic-gate 	now = curtime();
3903*7c478bd9Sstevel@tonic-gate 	s = stab(name, ST_NAMECANON, ST_ENTER);
3904*7c478bd9Sstevel@tonic-gate 	if (bitset(NCF_VALID, s->s_namecanon.nc_flags) &&
3905*7c478bd9Sstevel@tonic-gate 	    s->s_namecanon.nc_exp >= now)
3906*7c478bd9Sstevel@tonic-gate 	{
3907*7c478bd9Sstevel@tonic-gate 		if (tTd(9, 1))
3908*7c478bd9Sstevel@tonic-gate 			sm_dprintf("host_map_lookup(%s) => CACHE %s\n",
3909*7c478bd9Sstevel@tonic-gate 				    name,
3910*7c478bd9Sstevel@tonic-gate 				    s->s_namecanon.nc_cname == NULL
3911*7c478bd9Sstevel@tonic-gate 					? "NULL"
3912*7c478bd9Sstevel@tonic-gate 					: s->s_namecanon.nc_cname);
3913*7c478bd9Sstevel@tonic-gate 		errno = s->s_namecanon.nc_errno;
3914*7c478bd9Sstevel@tonic-gate 		SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
3915*7c478bd9Sstevel@tonic-gate 		*statp = s->s_namecanon.nc_stat;
3916*7c478bd9Sstevel@tonic-gate 		if (*statp == EX_TEMPFAIL)
3917*7c478bd9Sstevel@tonic-gate 		{
3918*7c478bd9Sstevel@tonic-gate 			CurEnv->e_status = "4.4.3";
3919*7c478bd9Sstevel@tonic-gate 			message("851 %s: Name server timeout",
3920*7c478bd9Sstevel@tonic-gate 				shortenstring(name, 33));
3921*7c478bd9Sstevel@tonic-gate 		}
3922*7c478bd9Sstevel@tonic-gate 		if (*statp != EX_OK)
3923*7c478bd9Sstevel@tonic-gate 			return NULL;
3924*7c478bd9Sstevel@tonic-gate 		if (s->s_namecanon.nc_cname == NULL)
3925*7c478bd9Sstevel@tonic-gate 		{
3926*7c478bd9Sstevel@tonic-gate 			syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d",
3927*7c478bd9Sstevel@tonic-gate 			       name,
3928*7c478bd9Sstevel@tonic-gate 			       s->s_namecanon.nc_errno,
3929*7c478bd9Sstevel@tonic-gate 			       s->s_namecanon.nc_herrno);
3930*7c478bd9Sstevel@tonic-gate 			return NULL;
3931*7c478bd9Sstevel@tonic-gate 		}
3932*7c478bd9Sstevel@tonic-gate 		if (bitset(MF_MATCHONLY, map->map_mflags))
3933*7c478bd9Sstevel@tonic-gate 			cp = map_rewrite(map, name, strlen(name), NULL);
3934*7c478bd9Sstevel@tonic-gate 		else
3935*7c478bd9Sstevel@tonic-gate 			cp = map_rewrite(map,
3936*7c478bd9Sstevel@tonic-gate 					 s->s_namecanon.nc_cname,
3937*7c478bd9Sstevel@tonic-gate 					 strlen(s->s_namecanon.nc_cname),
3938*7c478bd9Sstevel@tonic-gate 					 av);
3939*7c478bd9Sstevel@tonic-gate 		return cp;
3940*7c478bd9Sstevel@tonic-gate 	}
3941*7c478bd9Sstevel@tonic-gate 
3942*7c478bd9Sstevel@tonic-gate 	/*
3943*7c478bd9Sstevel@tonic-gate 	**  If we are running without a regular network connection (usually
3944*7c478bd9Sstevel@tonic-gate 	**  dial-on-demand) and we are just queueing, we want to avoid DNS
3945*7c478bd9Sstevel@tonic-gate 	**  lookups because those could try to connect to a server.
3946*7c478bd9Sstevel@tonic-gate 	*/
3947*7c478bd9Sstevel@tonic-gate 
3948*7c478bd9Sstevel@tonic-gate 	if (CurEnv->e_sendmode == SM_DEFER &&
3949*7c478bd9Sstevel@tonic-gate 	    bitset(MF_DEFER, map->map_mflags))
3950*7c478bd9Sstevel@tonic-gate 	{
3951*7c478bd9Sstevel@tonic-gate 		if (tTd(9, 1))
3952*7c478bd9Sstevel@tonic-gate 			sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name);
3953*7c478bd9Sstevel@tonic-gate 		*statp = EX_TEMPFAIL;
3954*7c478bd9Sstevel@tonic-gate 		return NULL;
3955*7c478bd9Sstevel@tonic-gate 	}
3956*7c478bd9Sstevel@tonic-gate 
3957*7c478bd9Sstevel@tonic-gate 	/*
3958*7c478bd9Sstevel@tonic-gate 	**  If first character is a bracket, then it is an address
3959*7c478bd9Sstevel@tonic-gate 	**  lookup.  Address is copied into a temporary buffer to
3960*7c478bd9Sstevel@tonic-gate 	**  strip the brackets and to preserve name if address is
3961*7c478bd9Sstevel@tonic-gate 	**  unknown.
3962*7c478bd9Sstevel@tonic-gate 	*/
3963*7c478bd9Sstevel@tonic-gate 
3964*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 1))
3965*7c478bd9Sstevel@tonic-gate 		sm_dprintf("host_map_lookup(%s) => ", name);
3966*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
3967*7c478bd9Sstevel@tonic-gate 	if (map->map_timeout > 0)
3968*7c478bd9Sstevel@tonic-gate 	{
3969*7c478bd9Sstevel@tonic-gate 		retrans = _res.retrans;
3970*7c478bd9Sstevel@tonic-gate 		_res.retrans = map->map_timeout;
3971*7c478bd9Sstevel@tonic-gate 	}
3972*7c478bd9Sstevel@tonic-gate 	if (map->map_retry > 0)
3973*7c478bd9Sstevel@tonic-gate 	{
3974*7c478bd9Sstevel@tonic-gate 		retry = _res.retry;
3975*7c478bd9Sstevel@tonic-gate 		_res.retry = map->map_retry;
3976*7c478bd9Sstevel@tonic-gate 	}
3977*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
3978*7c478bd9Sstevel@tonic-gate 
3979*7c478bd9Sstevel@tonic-gate 	/* set default TTL */
3980*7c478bd9Sstevel@tonic-gate 	s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
3981*7c478bd9Sstevel@tonic-gate 	if (*name != '[')
3982*7c478bd9Sstevel@tonic-gate 	{
3983*7c478bd9Sstevel@tonic-gate 		int ttl;
3984*7c478bd9Sstevel@tonic-gate 
3985*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(hbuf, name, sizeof hbuf);
3986*7c478bd9Sstevel@tonic-gate 		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl))
3987*7c478bd9Sstevel@tonic-gate 		{
3988*7c478bd9Sstevel@tonic-gate 			ans = hbuf;
3989*7c478bd9Sstevel@tonic-gate 			if (ttl > 0)
3990*7c478bd9Sstevel@tonic-gate 				s->s_namecanon.nc_exp = now + SM_MIN(ttl,
3991*7c478bd9Sstevel@tonic-gate 								SM_DEFAULT_TTL);
3992*7c478bd9Sstevel@tonic-gate 		}
3993*7c478bd9Sstevel@tonic-gate 	}
3994*7c478bd9Sstevel@tonic-gate 	else
3995*7c478bd9Sstevel@tonic-gate 	{
3996*7c478bd9Sstevel@tonic-gate 		if ((cp = strchr(name, ']')) == NULL)
3997*7c478bd9Sstevel@tonic-gate 		{
3998*7c478bd9Sstevel@tonic-gate 			if (tTd(9, 1))
3999*7c478bd9Sstevel@tonic-gate 				sm_dprintf("FAILED\n");
4000*7c478bd9Sstevel@tonic-gate 			return NULL;
4001*7c478bd9Sstevel@tonic-gate 		}
4002*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
4003*7c478bd9Sstevel@tonic-gate 
4004*7c478bd9Sstevel@tonic-gate 		hp = NULL;
4005*7c478bd9Sstevel@tonic-gate #if NETINET
4006*7c478bd9Sstevel@tonic-gate 		if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
4007*7c478bd9Sstevel@tonic-gate 			hp = sm_gethostbyaddr((char *)&in_addr,
4008*7c478bd9Sstevel@tonic-gate 					      INADDRSZ, AF_INET);
4009*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
4010*7c478bd9Sstevel@tonic-gate #if NETINET6
4011*7c478bd9Sstevel@tonic-gate 		if (hp == NULL &&
4012*7c478bd9Sstevel@tonic-gate 		    anynet_pton(AF_INET6, &name[1], &in6_addr) == 1)
4013*7c478bd9Sstevel@tonic-gate 			hp = sm_gethostbyaddr((char *)&in6_addr,
4014*7c478bd9Sstevel@tonic-gate 					      IN6ADDRSZ, AF_INET6);
4015*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
4016*7c478bd9Sstevel@tonic-gate 		*cp = ']';
4017*7c478bd9Sstevel@tonic-gate 
4018*7c478bd9Sstevel@tonic-gate 		if (hp != NULL)
4019*7c478bd9Sstevel@tonic-gate 		{
4020*7c478bd9Sstevel@tonic-gate 			/* found a match -- copy out */
4021*7c478bd9Sstevel@tonic-gate 			ans = denlstring((char *) hp->h_name, true, true);
4022*7c478bd9Sstevel@tonic-gate #if NETINET6
4023*7c478bd9Sstevel@tonic-gate 			if (ans == hp->h_name)
4024*7c478bd9Sstevel@tonic-gate 			{
4025*7c478bd9Sstevel@tonic-gate 				static char n[MAXNAME + 1];
4026*7c478bd9Sstevel@tonic-gate 
4027*7c478bd9Sstevel@tonic-gate 				/* hp->h_name is about to disappear */
4028*7c478bd9Sstevel@tonic-gate 				(void) sm_strlcpy(n, ans, sizeof n);
4029*7c478bd9Sstevel@tonic-gate 				ans = n;
4030*7c478bd9Sstevel@tonic-gate 			}
4031*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
4032*7c478bd9Sstevel@tonic-gate 			hp = NULL;
4033*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
4034*7c478bd9Sstevel@tonic-gate 		}
4035*7c478bd9Sstevel@tonic-gate 	}
4036*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
4037*7c478bd9Sstevel@tonic-gate 	if (map->map_timeout > 0)
4038*7c478bd9Sstevel@tonic-gate 		_res.retrans = retrans;
4039*7c478bd9Sstevel@tonic-gate 	if (map->map_retry > 0)
4040*7c478bd9Sstevel@tonic-gate 		_res.retry = retry;
4041*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
4042*7c478bd9Sstevel@tonic-gate 
4043*7c478bd9Sstevel@tonic-gate 	s->s_namecanon.nc_flags |= NCF_VALID;	/* will be soon */
4044*7c478bd9Sstevel@tonic-gate 
4045*7c478bd9Sstevel@tonic-gate 	/* Found an answer */
4046*7c478bd9Sstevel@tonic-gate 	if (ans != NULL)
4047*7c478bd9Sstevel@tonic-gate 	{
4048*7c478bd9Sstevel@tonic-gate 		s->s_namecanon.nc_stat = *statp = EX_OK;
4049*7c478bd9Sstevel@tonic-gate 		if (s->s_namecanon.nc_cname != NULL)
4050*7c478bd9Sstevel@tonic-gate 			sm_free(s->s_namecanon.nc_cname);
4051*7c478bd9Sstevel@tonic-gate 		s->s_namecanon.nc_cname = sm_strdup_x(ans);
4052*7c478bd9Sstevel@tonic-gate 		if (bitset(MF_MATCHONLY, map->map_mflags))
4053*7c478bd9Sstevel@tonic-gate 			cp = map_rewrite(map, name, strlen(name), NULL);
4054*7c478bd9Sstevel@tonic-gate 		else
4055*7c478bd9Sstevel@tonic-gate 			cp = map_rewrite(map, ans, strlen(ans), av);
4056*7c478bd9Sstevel@tonic-gate 		if (tTd(9, 1))
4057*7c478bd9Sstevel@tonic-gate 			sm_dprintf("FOUND %s\n", ans);
4058*7c478bd9Sstevel@tonic-gate 		return cp;
4059*7c478bd9Sstevel@tonic-gate 	}
4060*7c478bd9Sstevel@tonic-gate 
4061*7c478bd9Sstevel@tonic-gate 
4062*7c478bd9Sstevel@tonic-gate 	/* No match found */
4063*7c478bd9Sstevel@tonic-gate 	s->s_namecanon.nc_errno = errno;
4064*7c478bd9Sstevel@tonic-gate #if NAMED_BIND
4065*7c478bd9Sstevel@tonic-gate 	s->s_namecanon.nc_herrno = h_errno;
4066*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 1))
4067*7c478bd9Sstevel@tonic-gate 		sm_dprintf("FAIL (%d)\n", h_errno);
4068*7c478bd9Sstevel@tonic-gate 	switch (h_errno)
4069*7c478bd9Sstevel@tonic-gate 	{
4070*7c478bd9Sstevel@tonic-gate 	  case TRY_AGAIN:
4071*7c478bd9Sstevel@tonic-gate 		if (UseNameServer)
4072*7c478bd9Sstevel@tonic-gate 		{
4073*7c478bd9Sstevel@tonic-gate 			CurEnv->e_status = "4.4.3";
4074*7c478bd9Sstevel@tonic-gate 			message("851 %s: Name server timeout",
4075*7c478bd9Sstevel@tonic-gate 				shortenstring(name, 33));
4076*7c478bd9Sstevel@tonic-gate 		}
4077*7c478bd9Sstevel@tonic-gate 		*statp = EX_TEMPFAIL;
4078*7c478bd9Sstevel@tonic-gate 		break;
4079*7c478bd9Sstevel@tonic-gate 
4080*7c478bd9Sstevel@tonic-gate 	  case HOST_NOT_FOUND:
4081*7c478bd9Sstevel@tonic-gate 	  case NO_DATA:
4082*7c478bd9Sstevel@tonic-gate 		*statp = EX_NOHOST;
4083*7c478bd9Sstevel@tonic-gate 		break;
4084*7c478bd9Sstevel@tonic-gate 
4085*7c478bd9Sstevel@tonic-gate 	  case NO_RECOVERY:
4086*7c478bd9Sstevel@tonic-gate 		*statp = EX_SOFTWARE;
4087*7c478bd9Sstevel@tonic-gate 		break;
4088*7c478bd9Sstevel@tonic-gate 
4089*7c478bd9Sstevel@tonic-gate 	  default:
4090*7c478bd9Sstevel@tonic-gate 		*statp = EX_UNAVAILABLE;
4091*7c478bd9Sstevel@tonic-gate 		break;
4092*7c478bd9Sstevel@tonic-gate 	}
4093*7c478bd9Sstevel@tonic-gate #else /* NAMED_BIND */
4094*7c478bd9Sstevel@tonic-gate 	if (tTd(9, 1))
4095*7c478bd9Sstevel@tonic-gate 		sm_dprintf("FAIL\n");
4096*7c478bd9Sstevel@tonic-gate 	*statp = EX_NOHOST;
4097*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
4098*7c478bd9Sstevel@tonic-gate 	s->s_namecanon.nc_stat = *statp;
4099*7c478bd9Sstevel@tonic-gate 	return NULL;
4100*7c478bd9Sstevel@tonic-gate }
4101*7c478bd9Sstevel@tonic-gate /*
4102*7c478bd9Sstevel@tonic-gate **  HOST_MAP_INIT -- initialize host class structures
4103*7c478bd9Sstevel@tonic-gate **
4104*7c478bd9Sstevel@tonic-gate **	Parameters:
4105*7c478bd9Sstevel@tonic-gate **		map -- a pointer to this map.
4106*7c478bd9Sstevel@tonic-gate **		args -- argument string.
4107*7c478bd9Sstevel@tonic-gate **
4108*7c478bd9Sstevel@tonic-gate **	Returns:
4109*7c478bd9Sstevel@tonic-gate **		true.
4110*7c478bd9Sstevel@tonic-gate */
4111*7c478bd9Sstevel@tonic-gate 
4112*7c478bd9Sstevel@tonic-gate bool
4113*7c478bd9Sstevel@tonic-gate host_map_init(map, args)
4114*7c478bd9Sstevel@tonic-gate 	MAP *map;
4115*7c478bd9Sstevel@tonic-gate 	char *args;
4116*7c478bd9Sstevel@tonic-gate {
4117*7c478bd9Sstevel@tonic-gate 	register char *p = args;
4118*7c478bd9Sstevel@tonic-gate 
4119*7c478bd9Sstevel@tonic-gate 	for (;;)
4120*7c478bd9Sstevel@tonic-gate 	{
4121*7c478bd9Sstevel@tonic-gate 		while (isascii(*p) && isspace(*p))
4122*7c478bd9Sstevel@tonic-gate 			p++;
4123*7c478bd9Sstevel@tonic-gate 		if (*p != '-')
4124*7c478bd9Sstevel@tonic-gate 			break;
4125*7c478bd9Sstevel@tonic-gate 		switch (*++p)
4126*7c478bd9Sstevel@tonic-gate 		{
4127*7c478bd9Sstevel@tonic-gate 		  case 'a':
4128*7c478bd9Sstevel@tonic-gate 			map->map_app = ++p;
4129*7c478bd9Sstevel@tonic-gate 			break;
4130*7c478bd9Sstevel@tonic-gate 
4131*7c478bd9Sstevel@tonic-gate 		  case 'T':
4132*7c478bd9Sstevel@tonic-gate 			map->map_tapp = ++p;
4133*7c478bd9Sstevel@tonic-gate 			break;
4134*7c478bd9Sstevel@tonic-gate 
4135*7c478bd9Sstevel@tonic-gate 		  case 'm':
4136*7c478bd9Sstevel@tonic-gate 			map->map_mflags |= MF_MATCHONLY;
4137*7c478bd9Sstevel@tonic-gate 			break;
4138*7c478bd9Sstevel@tonic-gate 
4139*7c478bd9Sstevel@tonic-gate 		  case 't':
4140*7c478bd9Sstevel@tonic-gate 			map->map_mflags |= MF_NODEFER;
4141*7c478bd9Sstevel@tonic-gate 			break;
4142*7c478bd9Sstevel@tonic-gate 
4143*7c478bd9Sstevel@tonic-gate 		  case 'S':	/* only for consistency */
4144*7c478bd9Sstevel@tonic-gate 			map->map_spacesub = *++p;
4145*7c478bd9Sstevel@tonic-gate 			break;
4146*7c478bd9Sstevel@tonic-gate 
4147*7c478bd9Sstevel@tonic-gate 		  case 'D':
4148*7c478bd9Sstevel@tonic-gate 			map->map_mflags |= MF_DEFER;
4149*7c478bd9Sstevel@tonic-gate 			break;
4150*7c478bd9Sstevel@tonic-gate 
4151*7c478bd9Sstevel@tonic-gate 		  case 'd':
4152*7c478bd9Sstevel@tonic-gate 			{
4153*7c478bd9Sstevel@tonic-gate 				char *h;
4154*7c478bd9Sstevel@tonic-gate 
4155*7c478bd9Sstevel@tonic-gate 				while (isascii(*++p) && isspace(*p))
4156*7c478bd9Sstevel@tonic-gate 					continue;
4157*7c478bd9Sstevel@tonic-gate 				h = strchr(p, ' ');
4158*7c478bd9Sstevel@tonic-gate 				if (h != NULL)
4159*7c478bd9Sstevel@tonic-gate 					*h = '\0';
4160*7c478bd9Sstevel@tonic-gate 				map->map_timeout = convtime(p, 's');
4161*7c478bd9Sstevel@tonic-gate 				if (h != NULL)
4162*7c478bd9Sstevel@tonic-gate 					*h = ' ';
4163*7c478bd9Sstevel@tonic-gate 			}
4164*7c478bd9Sstevel@tonic-gate 			break;
4165*7c478bd9Sstevel@tonic-gate 
4166*7c478bd9Sstevel@tonic-gate 		  case 'r':
4167*7c478bd9Sstevel@tonic-gate 			while (isascii(*++p) && isspace(*p))
4168*7c478bd9Sstevel@tonic-gate 				continue;
4169*7c478bd9Sstevel@tonic-gate 			map->map_retry = atoi(p);
4170*7c478bd9Sstevel@tonic-gate 			break;
4171*7c478bd9Sstevel@tonic-gate 		}
4172*7c478bd9Sstevel@tonic-gate 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4173*7c478bd9Sstevel@tonic-gate 			p++;
4174*7c478bd9Sstevel@tonic-gate 		if (*p != '\0')
4175*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
4176*7c478bd9Sstevel@tonic-gate 	}
4177*7c478bd9Sstevel@tonic-gate 	if (map->map_app != NULL)
4178*7c478bd9Sstevel@tonic-gate 		map->map_app = newstr(map->map_app);
4179*7c478bd9Sstevel@tonic-gate 	if (map->map_tapp != NULL)
4180*7c478bd9Sstevel@tonic-gate 		map->map_tapp = newstr(map->map_tapp);
4181*7c478bd9Sstevel@tonic-gate 	return true;
4182*7c478bd9Sstevel@tonic-gate }
4183*7c478bd9Sstevel@tonic-gate 
4184*7c478bd9Sstevel@tonic-gate #if NETINET6
4185*7c478bd9Sstevel@tonic-gate /*
4186*7c478bd9Sstevel@tonic-gate **  ANYNET_NTOP -- convert an IPv6 network address to printable form.
4187*7c478bd9Sstevel@tonic-gate **
4188*7c478bd9Sstevel@tonic-gate **	Parameters:
4189*7c478bd9Sstevel@tonic-gate **		s6a -- a pointer to an in6_addr structure.
4190*7c478bd9Sstevel@tonic-gate **		dst -- buffer to store result in
4191*7c478bd9Sstevel@tonic-gate **		dst_len -- size of dst buffer
4192*7c478bd9Sstevel@tonic-gate **
4193*7c478bd9Sstevel@tonic-gate **	Returns:
4194*7c478bd9Sstevel@tonic-gate **		A printable version of that structure.
4195*7c478bd9Sstevel@tonic-gate */
4196*7c478bd9Sstevel@tonic-gate 
4197*7c478bd9Sstevel@tonic-gate char *
4198*7c478bd9Sstevel@tonic-gate anynet_ntop(s6a, dst, dst_len)
4199*7c478bd9Sstevel@tonic-gate 	struct in6_addr *s6a;
4200*7c478bd9Sstevel@tonic-gate 	char *dst;
4201*7c478bd9Sstevel@tonic-gate 	size_t dst_len;
4202*7c478bd9Sstevel@tonic-gate {
4203*7c478bd9Sstevel@tonic-gate 	register char *ap;
4204*7c478bd9Sstevel@tonic-gate 
4205*7c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_V4MAPPED(s6a))
4206*7c478bd9Sstevel@tonic-gate 		ap = (char *) inet_ntop(AF_INET,
4207*7c478bd9Sstevel@tonic-gate 					&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
4208*7c478bd9Sstevel@tonic-gate 					dst, dst_len);
4209*7c478bd9Sstevel@tonic-gate 	else
4210*7c478bd9Sstevel@tonic-gate 	{
4211*7c478bd9Sstevel@tonic-gate 		char *d;
4212*7c478bd9Sstevel@tonic-gate 		size_t sz;
4213*7c478bd9Sstevel@tonic-gate 
4214*7c478bd9Sstevel@tonic-gate 		/* Save pointer to beginning of string */
4215*7c478bd9Sstevel@tonic-gate 		d = dst;
4216*7c478bd9Sstevel@tonic-gate 
4217*7c478bd9Sstevel@tonic-gate 		/* Add IPv6: protocol tag */
4218*7c478bd9Sstevel@tonic-gate 		sz = sm_strlcpy(dst, "IPv6:", dst_len);
4219*7c478bd9Sstevel@tonic-gate 		if (sz >= dst_len)
4220*7c478bd9Sstevel@tonic-gate 			return NULL;
4221*7c478bd9Sstevel@tonic-gate 		dst += sz;
4222*7c478bd9Sstevel@tonic-gate 		dst_len -= sz;
4223*7c478bd9Sstevel@tonic-gate 		ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
4224*7c478bd9Sstevel@tonic-gate 
4225*7c478bd9Sstevel@tonic-gate 		/* Restore pointer to beginning of string */
4226*7c478bd9Sstevel@tonic-gate 		if (ap != NULL)
4227*7c478bd9Sstevel@tonic-gate 			ap = d;
4228*7c478bd9Sstevel@tonic-gate 	}
4229*7c478bd9Sstevel@tonic-gate 	return ap;
4230*7c478bd9Sstevel@tonic-gate }
4231*7c478bd9Sstevel@tonic-gate 
4232*7c478bd9Sstevel@tonic-gate /*
4233*7c478bd9Sstevel@tonic-gate **  ANYNET_PTON -- convert printed form to network address.
4234*7c478bd9Sstevel@tonic-gate **
4235*7c478bd9Sstevel@tonic-gate **	Wrapper for inet_pton() which handles IPv6: labels.
4236*7c478bd9Sstevel@tonic-gate **
4237*7c478bd9Sstevel@tonic-gate **	Parameters:
4238*7c478bd9Sstevel@tonic-gate **		family -- address family
4239*7c478bd9Sstevel@tonic-gate **		src -- string
4240*7c478bd9Sstevel@tonic-gate **		dst -- destination address structure
4241*7c478bd9Sstevel@tonic-gate **
4242*7c478bd9Sstevel@tonic-gate **	Returns:
4243*7c478bd9Sstevel@tonic-gate **		1 if the address was valid
4244*7c478bd9Sstevel@tonic-gate **		0 if the address wasn't parseable
4245*7c478bd9Sstevel@tonic-gate **		-1 if error
4246*7c478bd9Sstevel@tonic-gate */
4247*7c478bd9Sstevel@tonic-gate 
4248*7c478bd9Sstevel@tonic-gate int
4249*7c478bd9Sstevel@tonic-gate anynet_pton(family, src, dst)
4250*7c478bd9Sstevel@tonic-gate 	int family;
4251*7c478bd9Sstevel@tonic-gate 	const char *src;
4252*7c478bd9Sstevel@tonic-gate 	void *dst;
4253*7c478bd9Sstevel@tonic-gate {
4254*7c478bd9Sstevel@tonic-gate 	if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0)
4255*7c478bd9Sstevel@tonic-gate 		src += 5;
4256*7c478bd9Sstevel@tonic-gate 	return inet_pton(family, src, dst);
4257*7c478bd9Sstevel@tonic-gate }
4258*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
4259*7c478bd9Sstevel@tonic-gate /*
4260*7c478bd9Sstevel@tonic-gate **  ANYNET_NTOA -- convert a network address to printable form.
4261*7c478bd9Sstevel@tonic-gate **
4262*7c478bd9Sstevel@tonic-gate **	Parameters:
4263*7c478bd9Sstevel@tonic-gate **		sap -- a pointer to a sockaddr structure.
4264*7c478bd9Sstevel@tonic-gate **
4265*7c478bd9Sstevel@tonic-gate **	Returns:
4266*7c478bd9Sstevel@tonic-gate **		A printable version of that sockaddr.
4267*7c478bd9Sstevel@tonic-gate */
4268*7c478bd9Sstevel@tonic-gate 
4269*7c478bd9Sstevel@tonic-gate #ifdef USE_SOCK_STREAM
4270*7c478bd9Sstevel@tonic-gate 
4271*7c478bd9Sstevel@tonic-gate # if NETLINK
4272*7c478bd9Sstevel@tonic-gate #  include <net/if_dl.h>
4273*7c478bd9Sstevel@tonic-gate # endif /* NETLINK */
4274*7c478bd9Sstevel@tonic-gate 
4275*7c478bd9Sstevel@tonic-gate char *
4276*7c478bd9Sstevel@tonic-gate anynet_ntoa(sap)
4277*7c478bd9Sstevel@tonic-gate 	register SOCKADDR *sap;
4278*7c478bd9Sstevel@tonic-gate {
4279*7c478bd9Sstevel@tonic-gate 	register char *bp;
4280*7c478bd9Sstevel@tonic-gate 	register char *ap;
4281*7c478bd9Sstevel@tonic-gate 	int l;
4282*7c478bd9Sstevel@tonic-gate 	static char buf[100];
4283*7c478bd9Sstevel@tonic-gate 
4284*7c478bd9Sstevel@tonic-gate 	/* check for null/zero family */
4285*7c478bd9Sstevel@tonic-gate 	if (sap == NULL)
4286*7c478bd9Sstevel@tonic-gate 		return "NULLADDR";
4287*7c478bd9Sstevel@tonic-gate 	if (sap->sa.sa_family == 0)
4288*7c478bd9Sstevel@tonic-gate 		return "0";
4289*7c478bd9Sstevel@tonic-gate 
4290*7c478bd9Sstevel@tonic-gate 	switch (sap->sa.sa_family)
4291*7c478bd9Sstevel@tonic-gate 	{
4292*7c478bd9Sstevel@tonic-gate # if NETUNIX
4293*7c478bd9Sstevel@tonic-gate 	  case AF_UNIX:
4294*7c478bd9Sstevel@tonic-gate 		if (sap->sunix.sun_path[0] != '\0')
4295*7c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]",
4296*7c478bd9Sstevel@tonic-gate 					   sap->sunix.sun_path);
4297*7c478bd9Sstevel@tonic-gate 		else
4298*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf);
4299*7c478bd9Sstevel@tonic-gate 		return buf;
4300*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
4301*7c478bd9Sstevel@tonic-gate 
4302*7c478bd9Sstevel@tonic-gate # if NETINET
4303*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
4304*7c478bd9Sstevel@tonic-gate 		return (char *) inet_ntoa(sap->sin.sin_addr);
4305*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
4306*7c478bd9Sstevel@tonic-gate 
4307*7c478bd9Sstevel@tonic-gate # if NETINET6
4308*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
4309*7c478bd9Sstevel@tonic-gate 		ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf);
4310*7c478bd9Sstevel@tonic-gate 		if (ap != NULL)
4311*7c478bd9Sstevel@tonic-gate 			return ap;
4312*7c478bd9Sstevel@tonic-gate 		break;
4313*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
4314*7c478bd9Sstevel@tonic-gate 
4315*7c478bd9Sstevel@tonic-gate # if NETLINK
4316*7c478bd9Sstevel@tonic-gate 	  case AF_LINK:
4317*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(buf, sizeof buf, "[LINK: %s]",
4318*7c478bd9Sstevel@tonic-gate 				   link_ntoa((struct sockaddr_dl *) &sap->sa));
4319*7c478bd9Sstevel@tonic-gate 		return buf;
4320*7c478bd9Sstevel@tonic-gate # endif /* NETLINK */
4321*7c478bd9Sstevel@tonic-gate 	  default:
4322*7c478bd9Sstevel@tonic-gate 		/* this case is needed when nothing is #defined */
4323*7c478bd9Sstevel@tonic-gate 		/* in order to keep the switch syntactically correct */
4324*7c478bd9Sstevel@tonic-gate 		break;
4325*7c478bd9Sstevel@tonic-gate 	}
4326*7c478bd9Sstevel@tonic-gate 
4327*7c478bd9Sstevel@tonic-gate 	/* unknown family -- just dump bytes */
4328*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
4329*7c478bd9Sstevel@tonic-gate 	bp = &buf[strlen(buf)];
4330*7c478bd9Sstevel@tonic-gate 	ap = sap->sa.sa_data;
4331*7c478bd9Sstevel@tonic-gate 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
4332*7c478bd9Sstevel@tonic-gate 	{
4333*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
4334*7c478bd9Sstevel@tonic-gate 				   *ap++ & 0377);
4335*7c478bd9Sstevel@tonic-gate 		bp += 3;
4336*7c478bd9Sstevel@tonic-gate 	}
4337*7c478bd9Sstevel@tonic-gate 	*--bp = '\0';
4338*7c478bd9Sstevel@tonic-gate 	return buf;
4339*7c478bd9Sstevel@tonic-gate }
4340*7c478bd9Sstevel@tonic-gate /*
4341*7c478bd9Sstevel@tonic-gate **  HOSTNAMEBYANYADDR -- return name of host based on address
4342*7c478bd9Sstevel@tonic-gate **
4343*7c478bd9Sstevel@tonic-gate **	Parameters:
4344*7c478bd9Sstevel@tonic-gate **		sap -- SOCKADDR pointer
4345*7c478bd9Sstevel@tonic-gate **
4346*7c478bd9Sstevel@tonic-gate **	Returns:
4347*7c478bd9Sstevel@tonic-gate **		text representation of host name.
4348*7c478bd9Sstevel@tonic-gate **
4349*7c478bd9Sstevel@tonic-gate **	Side Effects:
4350*7c478bd9Sstevel@tonic-gate **		none.
4351*7c478bd9Sstevel@tonic-gate */
4352*7c478bd9Sstevel@tonic-gate 
4353*7c478bd9Sstevel@tonic-gate char *
4354*7c478bd9Sstevel@tonic-gate hostnamebyanyaddr(sap)
4355*7c478bd9Sstevel@tonic-gate 	register SOCKADDR *sap;
4356*7c478bd9Sstevel@tonic-gate {
4357*7c478bd9Sstevel@tonic-gate 	register struct hostent *hp;
4358*7c478bd9Sstevel@tonic-gate # if NAMED_BIND
4359*7c478bd9Sstevel@tonic-gate 	int saveretry;
4360*7c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */
4361*7c478bd9Sstevel@tonic-gate # if NETINET6
4362*7c478bd9Sstevel@tonic-gate 	struct in6_addr in6_addr;
4363*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
4364*7c478bd9Sstevel@tonic-gate 
4365*7c478bd9Sstevel@tonic-gate # if NAMED_BIND
4366*7c478bd9Sstevel@tonic-gate 	/* shorten name server timeout to avoid higher level timeouts */
4367*7c478bd9Sstevel@tonic-gate 	saveretry = _res.retry;
4368*7c478bd9Sstevel@tonic-gate 	if (_res.retry * _res.retrans > 20)
4369*7c478bd9Sstevel@tonic-gate 		_res.retry = 20 / _res.retrans;
4370*7c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */
4371*7c478bd9Sstevel@tonic-gate 
4372*7c478bd9Sstevel@tonic-gate 	switch (sap->sa.sa_family)
4373*7c478bd9Sstevel@tonic-gate 	{
4374*7c478bd9Sstevel@tonic-gate # if NETINET
4375*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
4376*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
4377*7c478bd9Sstevel@tonic-gate 				      INADDRSZ, AF_INET);
4378*7c478bd9Sstevel@tonic-gate 		break;
4379*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
4380*7c478bd9Sstevel@tonic-gate 
4381*7c478bd9Sstevel@tonic-gate # if NETINET6
4382*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
4383*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
4384*7c478bd9Sstevel@tonic-gate 				      IN6ADDRSZ, AF_INET6);
4385*7c478bd9Sstevel@tonic-gate 		break;
4386*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
4387*7c478bd9Sstevel@tonic-gate 
4388*7c478bd9Sstevel@tonic-gate # if NETISO
4389*7c478bd9Sstevel@tonic-gate 	  case AF_ISO:
4390*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
4391*7c478bd9Sstevel@tonic-gate 				      sizeof sap->siso.siso_addr, AF_ISO);
4392*7c478bd9Sstevel@tonic-gate 		break;
4393*7c478bd9Sstevel@tonic-gate # endif /* NETISO */
4394*7c478bd9Sstevel@tonic-gate 
4395*7c478bd9Sstevel@tonic-gate # if NETUNIX
4396*7c478bd9Sstevel@tonic-gate 	  case AF_UNIX:
4397*7c478bd9Sstevel@tonic-gate 		hp = NULL;
4398*7c478bd9Sstevel@tonic-gate 		break;
4399*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
4400*7c478bd9Sstevel@tonic-gate 
4401*7c478bd9Sstevel@tonic-gate 	  default:
4402*7c478bd9Sstevel@tonic-gate 		hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data,
4403*7c478bd9Sstevel@tonic-gate 				      sap->sa.sa_family);
4404*7c478bd9Sstevel@tonic-gate 		break;
4405*7c478bd9Sstevel@tonic-gate 	}
4406*7c478bd9Sstevel@tonic-gate 
4407*7c478bd9Sstevel@tonic-gate # if NAMED_BIND
4408*7c478bd9Sstevel@tonic-gate 	_res.retry = saveretry;
4409*7c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */
4410*7c478bd9Sstevel@tonic-gate 
4411*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
4412*7c478bd9Sstevel@tonic-gate 	if (hp != NULL && hp->h_name[0] != '['
4413*7c478bd9Sstevel@tonic-gate #  if NETINET6
4414*7c478bd9Sstevel@tonic-gate 	    && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
4415*7c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
4416*7c478bd9Sstevel@tonic-gate #  if NETINET
4417*7c478bd9Sstevel@tonic-gate 	    && inet_addr(hp->h_name) == INADDR_NONE
4418*7c478bd9Sstevel@tonic-gate #  endif /* NETINET */
4419*7c478bd9Sstevel@tonic-gate 	    )
4420*7c478bd9Sstevel@tonic-gate 	{
4421*7c478bd9Sstevel@tonic-gate 		char *name;
4422*7c478bd9Sstevel@tonic-gate 
4423*7c478bd9Sstevel@tonic-gate 		name = denlstring((char *) hp->h_name, true, true);
4424*7c478bd9Sstevel@tonic-gate #  if NETINET6
4425*7c478bd9Sstevel@tonic-gate 		if (name == hp->h_name)
4426*7c478bd9Sstevel@tonic-gate 		{
4427*7c478bd9Sstevel@tonic-gate 			static char n[MAXNAME + 1];
4428*7c478bd9Sstevel@tonic-gate 
4429*7c478bd9Sstevel@tonic-gate 			/* Copy the string, hp->h_name is about to disappear */
4430*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(n, name, sizeof n);
4431*7c478bd9Sstevel@tonic-gate 			name = n;
4432*7c478bd9Sstevel@tonic-gate 		}
4433*7c478bd9Sstevel@tonic-gate 		freehostent(hp);
4434*7c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
4435*7c478bd9Sstevel@tonic-gate 		return name;
4436*7c478bd9Sstevel@tonic-gate 	}
4437*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
4438*7c478bd9Sstevel@tonic-gate 
4439*7c478bd9Sstevel@tonic-gate # if NETINET6
4440*7c478bd9Sstevel@tonic-gate 	if (hp != NULL)
4441*7c478bd9Sstevel@tonic-gate 	{
4442*7c478bd9Sstevel@tonic-gate 		freehostent(hp);
4443*7c478bd9Sstevel@tonic-gate 		hp = NULL;
4444*7c478bd9Sstevel@tonic-gate 	}
4445*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
4446*7c478bd9Sstevel@tonic-gate 
4447*7c478bd9Sstevel@tonic-gate # if NETUNIX
4448*7c478bd9Sstevel@tonic-gate 	if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
4449*7c478bd9Sstevel@tonic-gate 		return "localhost";
4450*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
4451*7c478bd9Sstevel@tonic-gate 	{
4452*7c478bd9Sstevel@tonic-gate 		static char buf[203];
4453*7c478bd9Sstevel@tonic-gate 
4454*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(buf, sizeof buf, "[%.200s]",
4455*7c478bd9Sstevel@tonic-gate 				   anynet_ntoa(sap));
4456*7c478bd9Sstevel@tonic-gate 		return buf;
4457*7c478bd9Sstevel@tonic-gate 	}
4458*7c478bd9Sstevel@tonic-gate }
4459*7c478bd9Sstevel@tonic-gate #endif /* USE_SOCK_STREAM */
4460