xref: /titanic_51/usr/src/lib/libinetsvc/common/inetsvc.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This library contains a set of routines that are shared amongst inetd,
31*7c478bd9Sstevel@tonic-gate  * inetadm, inetconv and the formerly internal inetd services. Amongst the
32*7c478bd9Sstevel@tonic-gate  * routines are ones for reading and validating the configuration of an
33*7c478bd9Sstevel@tonic-gate  * inetd service, a routine for requesting inetd be refreshed, ones for
34*7c478bd9Sstevel@tonic-gate  * reading, calculating and writing the hash of an inetd.conf file, and
35*7c478bd9Sstevel@tonic-gate  * numerous utility routines shared amongst the formerly internal inetd
36*7c478bd9Sstevel@tonic-gate  * services.
37*7c478bd9Sstevel@tonic-gate  */
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
42*7c478bd9Sstevel@tonic-gate #include <netdb.h>
43*7c478bd9Sstevel@tonic-gate #include <limits.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <inetsvc.h>
46*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
47*7c478bd9Sstevel@tonic-gate #include <unistd.h>
48*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
49*7c478bd9Sstevel@tonic-gate #include <stdio.h>
50*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
51*7c478bd9Sstevel@tonic-gate #include <pwd.h>
52*7c478bd9Sstevel@tonic-gate #include <md5.h>
53*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
54*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
55*7c478bd9Sstevel@tonic-gate #include <signal.h>
56*7c478bd9Sstevel@tonic-gate #include <syslog.h>
57*7c478bd9Sstevel@tonic-gate #include <libintl.h>
58*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
59*7c478bd9Sstevel@tonic-gate #include <assert.h>
60*7c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
61*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate static inetd_prop_t inetd_properties[] = {
64*7c478bd9Sstevel@tonic-gate 	{PR_SVC_NAME_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_ASTRING,
65*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
66*7c478bd9Sstevel@tonic-gate 	{PR_SOCK_TYPE_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_ASTRING,
67*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
68*7c478bd9Sstevel@tonic-gate 	{PR_PROTO_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_ASTRING,
69*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
70*7c478bd9Sstevel@tonic-gate 	{PR_ISRPC_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_BOOLEAN,
71*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
72*7c478bd9Sstevel@tonic-gate 	{PR_RPC_LW_VER_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
73*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
74*7c478bd9Sstevel@tonic-gate 	{PR_RPC_HI_VER_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
75*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
76*7c478bd9Sstevel@tonic-gate 	{PR_ISWAIT_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_BOOLEAN,
77*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
78*7c478bd9Sstevel@tonic-gate 	{PR_EXEC_NAME, START_METHOD_NAME, SCF_TYPE_ASTRING,
79*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
80*7c478bd9Sstevel@tonic-gate 	{PR_ARG0_NAME, START_METHOD_NAME, SCF_TYPE_ASTRING,
81*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
82*7c478bd9Sstevel@tonic-gate 	{PR_USER_NAME, START_METHOD_NAME, SCF_TYPE_ASTRING,
83*7c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
84*7c478bd9Sstevel@tonic-gate 	{PR_BIND_ADDR_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_ASTRING,
85*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
86*7c478bd9Sstevel@tonic-gate 	{PR_BIND_FAIL_MAX_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
87*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
88*7c478bd9Sstevel@tonic-gate 	{PR_BIND_FAIL_INTVL_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
89*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
90*7c478bd9Sstevel@tonic-gate 	{PR_CON_RATE_MAX_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
91*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
92*7c478bd9Sstevel@tonic-gate 	{PR_MAX_COPIES_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
93*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
94*7c478bd9Sstevel@tonic-gate 	{PR_CON_RATE_OFFLINE_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
95*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
96*7c478bd9Sstevel@tonic-gate 	{PR_MAX_FAIL_RATE_CNT_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
97*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
98*7c478bd9Sstevel@tonic-gate 	{PR_MAX_FAIL_RATE_INTVL_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_INTEGER,
99*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
100*7c478bd9Sstevel@tonic-gate 	{PR_INHERIT_ENV_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_BOOLEAN,
101*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
102*7c478bd9Sstevel@tonic-gate 	{PR_DO_TCP_TRACE_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_BOOLEAN,
103*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
104*7c478bd9Sstevel@tonic-gate 	{PR_DO_TCP_WRAPPERS_NAME, PG_NAME_SERVICE_CONFIG, SCF_TYPE_BOOLEAN,
105*7c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE}
106*7c478bd9Sstevel@tonic-gate };
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate #define	INETD_NUMPROPS (sizeof (inetd_properties) / sizeof (inetd_prop_t))
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate #define	INETSVC_SVC_BUF_MAX (NSS_BUFLEN_RPC + sizeof (struct rpcent))
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate #define	DIGEST_LEN	16
113*7c478bd9Sstevel@tonic-gate #define	READ_BUFSIZ	8192
114*7c478bd9Sstevel@tonic-gate #define	HASH_PG		"hash"
115*7c478bd9Sstevel@tonic-gate #define	HASH_PROP	"md5sum"
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  * Inactivity timer used by dg_template(). After this many seconds of network
119*7c478bd9Sstevel@tonic-gate  * inactivity dg_template will cease listening for new datagrams and return.
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate #define	DG_INACTIVITY_TIMEOUT	60
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate static boolean_t v6_proto(const char *);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate boolean_t
126*7c478bd9Sstevel@tonic-gate is_tlx_service(inetd_prop_t *props)
127*7c478bd9Sstevel@tonic-gate {
128*7c478bd9Sstevel@tonic-gate 	return ((strcmp(SOCKTYPE_TLI_STR,
129*7c478bd9Sstevel@tonic-gate 	    props[PT_SOCK_TYPE_INDEX].ip_value.iv_astring) == 0) ||
130*7c478bd9Sstevel@tonic-gate 	    (strcmp(SOCKTYPE_XTI_STR,
131*7c478bd9Sstevel@tonic-gate 	    props[PT_SOCK_TYPE_INDEX].ip_value.iv_astring) == 0));
132*7c478bd9Sstevel@tonic-gate }
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate /*
135*7c478bd9Sstevel@tonic-gate  * Return a reference to the property table. Number of entries in table
136*7c478bd9Sstevel@tonic-gate  * are returned in num_elements argument.
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate inetd_prop_t *
139*7c478bd9Sstevel@tonic-gate get_prop_table(size_t *num_elements)
140*7c478bd9Sstevel@tonic-gate {
141*7c478bd9Sstevel@tonic-gate 	*num_elements = INETD_NUMPROPS;
142*7c478bd9Sstevel@tonic-gate 	return (&inetd_properties[0]);
143*7c478bd9Sstevel@tonic-gate }
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate /*
146*7c478bd9Sstevel@tonic-gate  * get_prop_value takes an array of inetd_prop_t's and a name of an inetd
147*7c478bd9Sstevel@tonic-gate  * property, and returns a pointer to the value of the requested property.
148*7c478bd9Sstevel@tonic-gate  */
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate void *
151*7c478bd9Sstevel@tonic-gate get_prop_value(const inetd_prop_t *prop, char *name)
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate 	int		i;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
156*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, prop[i].ip_name) != 0)
157*7c478bd9Sstevel@tonic-gate 			continue;
158*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_type == SCF_TYPE_ASTRING) {
159*7c478bd9Sstevel@tonic-gate 			if (i == PT_PROTO_INDEX) {
160*7c478bd9Sstevel@tonic-gate 				return ((void *)
161*7c478bd9Sstevel@tonic-gate 				    prop[i].ip_value.iv_proto_list);
162*7c478bd9Sstevel@tonic-gate 			} else {
163*7c478bd9Sstevel@tonic-gate 				return ((void *) prop[i].ip_value.iv_astring);
164*7c478bd9Sstevel@tonic-gate 			}
165*7c478bd9Sstevel@tonic-gate 		} else {
166*7c478bd9Sstevel@tonic-gate 			return ((void *) &prop[i].ip_value);
167*7c478bd9Sstevel@tonic-gate 		}
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	return (NULL);
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate /*
174*7c478bd9Sstevel@tonic-gate  * put_prop_value takes an array of inetd_prop_t's, a name of an inetd
175*7c478bd9Sstevel@tonic-gate  * property, and a pointer to a value.  It copies the value into the property
176*7c478bd9Sstevel@tonic-gate  * in the array, and returns 0 for success and -1 for failure.
177*7c478bd9Sstevel@tonic-gate  */
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate int
180*7c478bd9Sstevel@tonic-gate put_prop_value(inetd_prop_t *prop, char *name, void *value)
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	int		i;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
185*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, prop[i].ip_name) != 0)
186*7c478bd9Sstevel@tonic-gate 			continue;
187*7c478bd9Sstevel@tonic-gate 		switch (prop[i].ip_type) {
188*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
189*7c478bd9Sstevel@tonic-gate 			prop[i].ip_value.iv_int = *((int64_t *)value);
190*7c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_VALID;
191*7c478bd9Sstevel@tonic-gate 			return (0);
192*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
193*7c478bd9Sstevel@tonic-gate 			prop[i].ip_value.iv_boolean =
194*7c478bd9Sstevel@tonic-gate 			    *((boolean_t *)value);
195*7c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_VALID;
196*7c478bd9Sstevel@tonic-gate 			return (0);
197*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
198*7c478bd9Sstevel@tonic-gate 			if (i == PT_PROTO_INDEX) {
199*7c478bd9Sstevel@tonic-gate 				if ((prop[i].ip_value.iv_proto_list =
200*7c478bd9Sstevel@tonic-gate 				    get_protos((char *)value)) == NULL)
201*7c478bd9Sstevel@tonic-gate 					return (-1);
202*7c478bd9Sstevel@tonic-gate 			} else {
203*7c478bd9Sstevel@tonic-gate 				if (strlen((char *)value) >=
204*7c478bd9Sstevel@tonic-gate 				    scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) {
205*7c478bd9Sstevel@tonic-gate 					errno = E2BIG;
206*7c478bd9Sstevel@tonic-gate 					return (-1);
207*7c478bd9Sstevel@tonic-gate 				}
208*7c478bd9Sstevel@tonic-gate 				if ((prop[i].ip_value.iv_astring =
209*7c478bd9Sstevel@tonic-gate 				    strdup((char *)value)) == NULL)
210*7c478bd9Sstevel@tonic-gate 					return (-1);
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_VALID;
213*7c478bd9Sstevel@tonic-gate 			return (0);
214*7c478bd9Sstevel@tonic-gate 		}
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	return (-1);
218*7c478bd9Sstevel@tonic-gate }
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate static void
221*7c478bd9Sstevel@tonic-gate destroy_rpc_info(rpc_info_t *rpc)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	if (rpc != NULL) {
224*7c478bd9Sstevel@tonic-gate 		free(rpc->netbuf.buf);
225*7c478bd9Sstevel@tonic-gate 		free(rpc->netid);
226*7c478bd9Sstevel@tonic-gate 		free(rpc);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate /*
231*7c478bd9Sstevel@tonic-gate  * If 'proto' is a valid netid,  and no memory allocations fail, returns a
232*7c478bd9Sstevel@tonic-gate  * pointer to an allocated and initialized rpc_info_t, else NULL.
233*7c478bd9Sstevel@tonic-gate  */
234*7c478bd9Sstevel@tonic-gate static rpc_info_t *
235*7c478bd9Sstevel@tonic-gate create_rpc_info(const char *proto, int pnum, int low_ver, int high_ver)
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	struct netconfig	*nconf;
238*7c478bd9Sstevel@tonic-gate 	rpc_info_t		*ret;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	if ((ret = calloc(1, sizeof (rpc_info_t))) == NULL)
241*7c478bd9Sstevel@tonic-gate 		return (NULL);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	ret->netbuf.maxlen = sizeof (struct sockaddr_storage);
244*7c478bd9Sstevel@tonic-gate 	if ((ret->netbuf.buf = malloc(ret->netbuf.maxlen)) == NULL) {
245*7c478bd9Sstevel@tonic-gate 		free(ret);
246*7c478bd9Sstevel@tonic-gate 		return (NULL);
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	ret->prognum = pnum;
250*7c478bd9Sstevel@tonic-gate 	ret->lowver = low_ver;
251*7c478bd9Sstevel@tonic-gate 	ret->highver = high_ver;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if ((ret->netid = strdup(proto)) == NULL) {
254*7c478bd9Sstevel@tonic-gate 		destroy_rpc_info(ret);
255*7c478bd9Sstevel@tonic-gate 		return (NULL);
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	/*
259*7c478bd9Sstevel@tonic-gate 	 * Determine whether this is a loopback transport. If getnetconfigent()
260*7c478bd9Sstevel@tonic-gate 	 * fails, we check to see whether it was the result of a v6 proto
261*7c478bd9Sstevel@tonic-gate 	 * being specified and no IPv6 interface was configured on the system;
262*7c478bd9Sstevel@tonic-gate 	 * if this holds, we know it must not be a loopback transport, else
263*7c478bd9Sstevel@tonic-gate 	 * getnetconfigent() must be miss-behaving, so return an error.
264*7c478bd9Sstevel@tonic-gate 	 */
265*7c478bd9Sstevel@tonic-gate 	if ((nconf = getnetconfigent(proto)) != NULL) {
266*7c478bd9Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
267*7c478bd9Sstevel@tonic-gate 			ret->is_loopback = B_TRUE;
268*7c478bd9Sstevel@tonic-gate 		freenetconfigent(nconf);
269*7c478bd9Sstevel@tonic-gate 	} else if (!v6_proto(proto)) {
270*7c478bd9Sstevel@tonic-gate 		destroy_rpc_info(ret);
271*7c478bd9Sstevel@tonic-gate 		return (NULL);
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	return (ret);
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate void
278*7c478bd9Sstevel@tonic-gate destroy_tlx_info(tlx_info_t *tlx)
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate 	tlx_conn_ind_t  *ci;
281*7c478bd9Sstevel@tonic-gate 	void		*cookie = NULL;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	if (tlx == NULL)
284*7c478bd9Sstevel@tonic-gate 		return;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	free(tlx->dev_name);
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	if (tlx->conn_ind_queue != NULL) {
289*7c478bd9Sstevel@tonic-gate 		/* free up conn ind queue */
290*7c478bd9Sstevel@tonic-gate 		while ((ci = uu_list_teardown(tlx->conn_ind_queue, &cookie)) !=
291*7c478bd9Sstevel@tonic-gate 		    NULL) {
292*7c478bd9Sstevel@tonic-gate 			(void) t_free((char *)ci->call, T_CALL);
293*7c478bd9Sstevel@tonic-gate 			free(ci);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 		uu_list_destroy(tlx->conn_ind_queue);
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	free(tlx->local_addr.buf);
299*7c478bd9Sstevel@tonic-gate 	free(tlx);
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate /*
303*7c478bd9Sstevel@tonic-gate  * Allocate, initialize and return a pointer to a tlx_info_t structure.
304*7c478bd9Sstevel@tonic-gate  * On memory allocation failure NULL is returned.
305*7c478bd9Sstevel@tonic-gate  */
306*7c478bd9Sstevel@tonic-gate static tlx_info_t *
307*7c478bd9Sstevel@tonic-gate create_tlx_info(const char *proto, uu_list_pool_t *conn_ind_pool)
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate 	size_t			sz;
310*7c478bd9Sstevel@tonic-gate 	tlx_info_t		*ret;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if ((ret = calloc(1, sizeof (tlx_info_t))) == NULL)
313*7c478bd9Sstevel@tonic-gate 		return (NULL);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	ret->local_addr.maxlen = sizeof (struct sockaddr_storage);
316*7c478bd9Sstevel@tonic-gate 	if ((ret->local_addr.buf = calloc(1, ret->local_addr.maxlen)) == NULL)
317*7c478bd9Sstevel@tonic-gate 		goto fail;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	if ((ret->conn_ind_queue = uu_list_create(conn_ind_pool, NULL, 0)) ==
320*7c478bd9Sstevel@tonic-gate 	    NULL)
321*7c478bd9Sstevel@tonic-gate 		goto fail;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	ret->local_addr.len = sizeof (struct sockaddr_in);
324*7c478bd9Sstevel@tonic-gate 	/* LINTED E_BAD_PTR_CAST_ALIGN */
325*7c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)(ret->local_addr.buf))->sin_family = AF_INET;
326*7c478bd9Sstevel@tonic-gate 	/* LINTED E_BAD_PTR_CAST_ALIGN */
327*7c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)(ret->local_addr.buf))->sin_addr.s_addr =
328*7c478bd9Sstevel@tonic-gate 	    htonl(INADDR_ANY);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	/* store device name, constructing if necessary */
331*7c478bd9Sstevel@tonic-gate 	if (proto[0] != '/') {
332*7c478bd9Sstevel@tonic-gate 		sz = strlen("/dev/") + strlen(proto) + 1;
333*7c478bd9Sstevel@tonic-gate 		if ((ret->dev_name = malloc(sz)) == NULL)
334*7c478bd9Sstevel@tonic-gate 			goto fail;
335*7c478bd9Sstevel@tonic-gate 		(void) snprintf(ret->dev_name, sz, "/dev/%s", proto);
336*7c478bd9Sstevel@tonic-gate 	} else if ((ret->dev_name = strdup(proto)) == NULL) {
337*7c478bd9Sstevel@tonic-gate 			goto fail;
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	return (ret);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate fail:
343*7c478bd9Sstevel@tonic-gate 	destroy_tlx_info(ret);
344*7c478bd9Sstevel@tonic-gate 	return (NULL);
345*7c478bd9Sstevel@tonic-gate }
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate /*
348*7c478bd9Sstevel@tonic-gate  * Returns B_TRUE if this is a v6 protocol valid for both TLI and socket
349*7c478bd9Sstevel@tonic-gate  * based services, else B_FALSE.
350*7c478bd9Sstevel@tonic-gate  */
351*7c478bd9Sstevel@tonic-gate static boolean_t
352*7c478bd9Sstevel@tonic-gate v6_proto(const char *proto)
353*7c478bd9Sstevel@tonic-gate {
354*7c478bd9Sstevel@tonic-gate 	return ((strcmp(proto, SOCKET_PROTO_TCP6) == 0) ||
355*7c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_UDP6) == 0));
356*7c478bd9Sstevel@tonic-gate }
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate /*
359*7c478bd9Sstevel@tonic-gate  * Returns B_TRUE if this is a valid v6 protocol for a socket based service,
360*7c478bd9Sstevel@tonic-gate  * else B_FALSE.
361*7c478bd9Sstevel@tonic-gate  */
362*7c478bd9Sstevel@tonic-gate static boolean_t
363*7c478bd9Sstevel@tonic-gate v6_socket_proto(const char *proto)
364*7c478bd9Sstevel@tonic-gate {
365*7c478bd9Sstevel@tonic-gate 	return ((strcmp(proto, SOCKET_PROTO_SCTP6) == 0) ||
366*7c478bd9Sstevel@tonic-gate 	    v6_proto(proto));
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate static boolean_t
371*7c478bd9Sstevel@tonic-gate valid_socket_proto(const char *proto)
372*7c478bd9Sstevel@tonic-gate {
373*7c478bd9Sstevel@tonic-gate 	return (v6_socket_proto(proto) ||
374*7c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_SCTP) == 0) ||
375*7c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_TCP) == 0) ||
376*7c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_UDP) == 0));
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate /*
380*7c478bd9Sstevel@tonic-gate  * Free all the memory consumed by 'pi' associated with the instance
381*7c478bd9Sstevel@tonic-gate  * with configuration 'cfg'.
382*7c478bd9Sstevel@tonic-gate  */
383*7c478bd9Sstevel@tonic-gate static void
384*7c478bd9Sstevel@tonic-gate destroy_proto_info(basic_cfg_t *cfg, proto_info_t *pi)
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate 	if (pi == NULL)
387*7c478bd9Sstevel@tonic-gate 		return;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	assert(pi->listen_fd == -1);
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	free(pi->proto);
392*7c478bd9Sstevel@tonic-gate 	if (pi->ri != NULL)
393*7c478bd9Sstevel@tonic-gate 		destroy_rpc_info(pi->ri);
394*7c478bd9Sstevel@tonic-gate 	if (cfg->istlx) {
395*7c478bd9Sstevel@tonic-gate 		destroy_tlx_info((tlx_info_t *)pi);
396*7c478bd9Sstevel@tonic-gate 	} else {
397*7c478bd9Sstevel@tonic-gate 		free(pi);
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate }
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate void
402*7c478bd9Sstevel@tonic-gate destroy_proto_list(basic_cfg_t *cfg)
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 	void		*cookie = NULL;
405*7c478bd9Sstevel@tonic-gate 	proto_info_t	*pi;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	if (cfg->proto_list == NULL)
408*7c478bd9Sstevel@tonic-gate 		return;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	while ((pi = uu_list_teardown(cfg->proto_list, &cookie)) != NULL)
411*7c478bd9Sstevel@tonic-gate 		destroy_proto_info(cfg, pi);
412*7c478bd9Sstevel@tonic-gate 	uu_list_destroy(cfg->proto_list);
413*7c478bd9Sstevel@tonic-gate 	cfg->proto_list = NULL;
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate void
417*7c478bd9Sstevel@tonic-gate destroy_basic_cfg(basic_cfg_t *cfg)
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	if (cfg == NULL)
420*7c478bd9Sstevel@tonic-gate 		return;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	free(cfg->bind_addr);
423*7c478bd9Sstevel@tonic-gate 	destroy_proto_list(cfg);
424*7c478bd9Sstevel@tonic-gate 	free(cfg->svc_name);
425*7c478bd9Sstevel@tonic-gate 	free(cfg);
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate /*
429*7c478bd9Sstevel@tonic-gate  * valid_props validates all the properties in an array of inetd_prop_t's,
430*7c478bd9Sstevel@tonic-gate  * marking each property as valid or invalid.  If any properties are invalid,
431*7c478bd9Sstevel@tonic-gate  * it returns B_FALSE, otherwise it returns B_TRUE.  Note that some properties
432*7c478bd9Sstevel@tonic-gate  * are interdependent, so if one is invalid, it leaves others in an
433*7c478bd9Sstevel@tonic-gate  * indeterminate state (such as ISRPC and SVC_NAME).  In this case, the
434*7c478bd9Sstevel@tonic-gate  * indeterminate property will be marked valid.  IE, the only properties
435*7c478bd9Sstevel@tonic-gate  * marked invalid are those that are KNOWN to be invalid.
436*7c478bd9Sstevel@tonic-gate  *
437*7c478bd9Sstevel@tonic-gate  * Piggy-backed onto this validation if 'fmri' is non-NULL is the construction
438*7c478bd9Sstevel@tonic-gate  * of a structured configuration, a basic_cfg_t,  which is used by inetd.
439*7c478bd9Sstevel@tonic-gate  * If 'fmri' is set then the latter three parameters need to be set to
440*7c478bd9Sstevel@tonic-gate  * non-NULL values, and if the configuration is valid, the storage referenced
441*7c478bd9Sstevel@tonic-gate  * by cfgpp is set to point at an initialized basic_cfg_t.
442*7c478bd9Sstevel@tonic-gate  */
443*7c478bd9Sstevel@tonic-gate boolean_t
444*7c478bd9Sstevel@tonic-gate valid_props(inetd_prop_t *prop, const char *fmri, basic_cfg_t **cfgpp,
445*7c478bd9Sstevel@tonic-gate     uu_list_pool_t *proto_info_pool, uu_list_pool_t *tlx_ci_pool)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	char			*bufp, *cp;
448*7c478bd9Sstevel@tonic-gate 	boolean_t		ret = B_TRUE;
449*7c478bd9Sstevel@tonic-gate 	int			i;
450*7c478bd9Sstevel@tonic-gate 	long			uidl;
451*7c478bd9Sstevel@tonic-gate 	boolean_t		isrpc;
452*7c478bd9Sstevel@tonic-gate 	int			sock_type_id;
453*7c478bd9Sstevel@tonic-gate 	int			rpc_pnum;
454*7c478bd9Sstevel@tonic-gate 	int			rpc_lv, rpc_hv;
455*7c478bd9Sstevel@tonic-gate 	basic_cfg_t		*cfg;
456*7c478bd9Sstevel@tonic-gate 	char			*proto = NULL;
457*7c478bd9Sstevel@tonic-gate 	int			pi;
458*7c478bd9Sstevel@tonic-gate 	char			**netids = NULL;
459*7c478bd9Sstevel@tonic-gate 	int			ni = 0;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (fmri != NULL)
462*7c478bd9Sstevel@tonic-gate 		assert((cfgpp != NULL) && (proto_info_pool != NULL) &&
463*7c478bd9Sstevel@tonic-gate 		    (tlx_ci_pool != NULL));
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	/*
466*7c478bd9Sstevel@tonic-gate 	 * Set all checkable properties to valid as a baseline.  We'll be
467*7c478bd9Sstevel@tonic-gate 	 * marking all invalid properties.
468*7c478bd9Sstevel@tonic-gate 	 */
469*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
470*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error != IVE_UNSET)
471*7c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_VALID;
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if (((cfg = calloc(1, sizeof (basic_cfg_t))) == NULL) ||
475*7c478bd9Sstevel@tonic-gate 	    ((fmri != NULL) &&
476*7c478bd9Sstevel@tonic-gate 	    ((cfg->proto_list = uu_list_create(proto_info_pool, NULL, 0)) ==
477*7c478bd9Sstevel@tonic-gate 	    NULL))) {
478*7c478bd9Sstevel@tonic-gate 		free(cfg);
479*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	/* Check a service name was supplied */
483*7c478bd9Sstevel@tonic-gate 	if ((prop[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) ||
484*7c478bd9Sstevel@tonic-gate 	    ((cfg->svc_name =
485*7c478bd9Sstevel@tonic-gate 	    strdup(prop[PT_SVC_NAME_INDEX].ip_value.iv_astring)) == NULL))
486*7c478bd9Sstevel@tonic-gate 		prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	/* Check that iswait and isrpc have valid boolean values */
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_UNSET) ||
491*7c478bd9Sstevel@tonic-gate 	    (((cfg->iswait = prop[PT_ISWAIT_INDEX].ip_value.iv_boolean) !=
492*7c478bd9Sstevel@tonic-gate 	    B_TRUE) && (cfg->iswait != B_FALSE)))
493*7c478bd9Sstevel@tonic-gate 		prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if ((prop[PT_ISRPC_INDEX].ip_error == IVE_UNSET) ||
496*7c478bd9Sstevel@tonic-gate 	    (((isrpc = prop[PT_ISRPC_INDEX].ip_value.iv_boolean) != B_TRUE) &&
497*7c478bd9Sstevel@tonic-gate 	    (isrpc != B_FALSE))) {
498*7c478bd9Sstevel@tonic-gate 		prop[PT_ISRPC_INDEX].ip_error = IVE_INVALID;
499*7c478bd9Sstevel@tonic-gate 	} else if (isrpc) {
500*7c478bd9Sstevel@tonic-gate 		/*
501*7c478bd9Sstevel@tonic-gate 		 * This is an RPC service, so ensure that the RPC version
502*7c478bd9Sstevel@tonic-gate 		 * numbers are zero or greater, that the low version isn't
503*7c478bd9Sstevel@tonic-gate 		 * greater than the high version and a valid program name
504*7c478bd9Sstevel@tonic-gate 		 * is supplied.
505*7c478bd9Sstevel@tonic-gate 		 */
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_LW_VER_INDEX].ip_error == IVE_UNSET) ||
508*7c478bd9Sstevel@tonic-gate 		    ((rpc_lv = prop[PT_RPC_LW_VER_INDEX].ip_value.iv_int) <
509*7c478bd9Sstevel@tonic-gate 		    0))
510*7c478bd9Sstevel@tonic-gate 			prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_HI_VER_INDEX].ip_error == IVE_UNSET) ||
513*7c478bd9Sstevel@tonic-gate 		    ((rpc_hv = prop[PT_RPC_HI_VER_INDEX].ip_value.iv_int) <
514*7c478bd9Sstevel@tonic-gate 		    0))
515*7c478bd9Sstevel@tonic-gate 			prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_LW_VER_INDEX].ip_error != IVE_INVALID) &&
518*7c478bd9Sstevel@tonic-gate 		    (prop[PT_RPC_HI_VER_INDEX].ip_error != IVE_INVALID) &&
519*7c478bd9Sstevel@tonic-gate 		    (rpc_lv > rpc_hv)) {
520*7c478bd9Sstevel@tonic-gate 			prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID;
521*7c478bd9Sstevel@tonic-gate 			prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID;
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 		if ((cfg->svc_name != NULL) &&
525*7c478bd9Sstevel@tonic-gate 		    ((rpc_pnum = get_rpc_prognum(cfg->svc_name)) == -1))
526*7c478bd9Sstevel@tonic-gate 			prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	/* Check that the socket type is one of the acceptable values. */
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	cfg->istlx = B_FALSE;
532*7c478bd9Sstevel@tonic-gate 	if ((prop[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET) ||
533*7c478bd9Sstevel@tonic-gate 	    ((sock_type_id = get_sock_type_id(
534*7c478bd9Sstevel@tonic-gate 	    prop[PT_SOCK_TYPE_INDEX].ip_value.iv_astring)) == -1) &&
535*7c478bd9Sstevel@tonic-gate 	    !(cfg->istlx = is_tlx_service(prop)))
536*7c478bd9Sstevel@tonic-gate 		prop[PT_SOCK_TYPE_INDEX].ip_error = IVE_INVALID;
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	/*
539*7c478bd9Sstevel@tonic-gate 	 * Iterate through all the different protos/netids resulting from the
540*7c478bd9Sstevel@tonic-gate 	 * proto property and check that they're valid and perform checks on
541*7c478bd9Sstevel@tonic-gate 	 * other fields that are tied-in with the proto.
542*7c478bd9Sstevel@tonic-gate 	 */
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	pi = 0;
545*7c478bd9Sstevel@tonic-gate 	do {
546*7c478bd9Sstevel@tonic-gate 		socket_info_t		*si = NULL;
547*7c478bd9Sstevel@tonic-gate 		tlx_info_t		*ti = NULL;
548*7c478bd9Sstevel@tonic-gate 		proto_info_t		*p_inf = NULL;
549*7c478bd9Sstevel@tonic-gate 		boolean_t		v6only = B_FALSE;
550*7c478bd9Sstevel@tonic-gate 		char			*only;
551*7c478bd9Sstevel@tonic-gate 		boolean_t		invalid_proto = B_FALSE;
552*7c478bd9Sstevel@tonic-gate 		char			**protos;
553*7c478bd9Sstevel@tonic-gate 		struct protoent		pe;
554*7c478bd9Sstevel@tonic-gate 		char			gpbuf[1024];
555*7c478bd9Sstevel@tonic-gate 		struct netconfig	*nconf = NULL;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 		/*
558*7c478bd9Sstevel@tonic-gate 		 * If we don't know whether it's an rpc service or its
559*7c478bd9Sstevel@tonic-gate 		 * endpoint type, we can't do any of the proto checks as we
560*7c478bd9Sstevel@tonic-gate 		 * have no context; break out.
561*7c478bd9Sstevel@tonic-gate 		 */
562*7c478bd9Sstevel@tonic-gate 		if ((prop[PT_ISRPC_INDEX].ip_error != IVE_VALID) ||
563*7c478bd9Sstevel@tonic-gate 		    (prop[PT_SOCK_TYPE_INDEX].ip_error != IVE_VALID))
564*7c478bd9Sstevel@tonic-gate 			break;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		/* skip proto specific processing if the proto isn't set. */
567*7c478bd9Sstevel@tonic-gate 		if (prop[PT_PROTO_INDEX].ip_error == IVE_UNSET) {
568*7c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
569*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		protos = prop[PT_PROTO_INDEX].ip_value.iv_proto_list;
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		/*
574*7c478bd9Sstevel@tonic-gate 		 * Get the next netid/proto.
575*7c478bd9Sstevel@tonic-gate 		 */
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 		if (!cfg->istlx || !isrpc) {
578*7c478bd9Sstevel@tonic-gate 			proto = protos[pi++];
579*7c478bd9Sstevel@tonic-gate 		/*
580*7c478bd9Sstevel@tonic-gate 		 * This is a TLI/RPC service, so get the next netid, expanding
581*7c478bd9Sstevel@tonic-gate 		 * any supplied nettype.
582*7c478bd9Sstevel@tonic-gate 		 */
583*7c478bd9Sstevel@tonic-gate 		} else if ((netids == NULL) ||
584*7c478bd9Sstevel@tonic-gate 		    ((proto = netids[ni++]) == NULL)) {
585*7c478bd9Sstevel@tonic-gate 			/*
586*7c478bd9Sstevel@tonic-gate 			 * Either this is the first time around or
587*7c478bd9Sstevel@tonic-gate 			 * we've exhausted the last set of netids, so
588*7c478bd9Sstevel@tonic-gate 			 * try and get the next set using the currently
589*7c478bd9Sstevel@tonic-gate 			 * indexed proto entry.
590*7c478bd9Sstevel@tonic-gate 			 */
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 			if (netids != NULL) {
593*7c478bd9Sstevel@tonic-gate 				destroy_strings(netids);
594*7c478bd9Sstevel@tonic-gate 				netids = NULL;
595*7c478bd9Sstevel@tonic-gate 			}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 			if (protos[pi] != NULL) {
598*7c478bd9Sstevel@tonic-gate 				if ((netids = get_netids(protos[pi++])) ==
599*7c478bd9Sstevel@tonic-gate 				    NULL) {
600*7c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
601*7c478bd9Sstevel@tonic-gate 					proto = protos[pi - 1];
602*7c478bd9Sstevel@tonic-gate 				} else {
603*7c478bd9Sstevel@tonic-gate 					ni = 0;
604*7c478bd9Sstevel@tonic-gate 					proto = netids[ni++];
605*7c478bd9Sstevel@tonic-gate 				}
606*7c478bd9Sstevel@tonic-gate 			} else {
607*7c478bd9Sstevel@tonic-gate 				proto = NULL;
608*7c478bd9Sstevel@tonic-gate 			}
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		if (invalid_proto || (proto == NULL))
612*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 		/* strip a trailing only to simplify further processing */
615*7c478bd9Sstevel@tonic-gate 		only = proto + strlen(proto) - (sizeof ("6only") - 1);
616*7c478bd9Sstevel@tonic-gate 		if ((only > proto) && (strcmp(only, "6only") == 0)) {
617*7c478bd9Sstevel@tonic-gate 			*++only = '\0';
618*7c478bd9Sstevel@tonic-gate 			v6only = B_TRUE;
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		/* validate the proto/netid */
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 		if (!cfg->istlx) {
624*7c478bd9Sstevel@tonic-gate 			if (!valid_socket_proto(proto))
625*7c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
626*7c478bd9Sstevel@tonic-gate 		} else {
627*7c478bd9Sstevel@tonic-gate 			/*
628*7c478bd9Sstevel@tonic-gate 			 * Check if we've got a valid netid. If
629*7c478bd9Sstevel@tonic-gate 			 * getnetconfigent() fails, we check to see whether
630*7c478bd9Sstevel@tonic-gate 			 * we've got a v6 netid that may have been rejected
631*7c478bd9Sstevel@tonic-gate 			 * because no IPv6 interface was configured before
632*7c478bd9Sstevel@tonic-gate 			 * flagging 'proto' as invalid. If the latter condition
633*7c478bd9Sstevel@tonic-gate 			 * holds, we don't flag the proto as invalid, and
634*7c478bd9Sstevel@tonic-gate 			 * leave inetd to handle the value appropriately
635*7c478bd9Sstevel@tonic-gate 			 * when it tries to listen on behalf of the service.
636*7c478bd9Sstevel@tonic-gate 			 */
637*7c478bd9Sstevel@tonic-gate 			if (((nconf = getnetconfigent(proto)) == NULL) &&
638*7c478bd9Sstevel@tonic-gate 			    !v6_proto(proto))
639*7c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
640*7c478bd9Sstevel@tonic-gate 		}
641*7c478bd9Sstevel@tonic-gate 		if (invalid_proto)
642*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		/*
645*7c478bd9Sstevel@tonic-gate 		 * dissallow datagram type nowait services
646*7c478bd9Sstevel@tonic-gate 		 */
647*7c478bd9Sstevel@tonic-gate 		if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_VALID) &&
648*7c478bd9Sstevel@tonic-gate 		    !cfg->iswait) {
649*7c478bd9Sstevel@tonic-gate 			if (strncmp(proto, SOCKET_PROTO_UDP,
650*7c478bd9Sstevel@tonic-gate 			    sizeof (SOCKET_PROTO_UDP) - 1) == 0) {
651*7c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
652*7c478bd9Sstevel@tonic-gate 			} else if (cfg->istlx && (nconf != NULL) &&
653*7c478bd9Sstevel@tonic-gate 				(nconf->nc_semantics == NC_TPI_CLTS)) {
654*7c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
655*7c478bd9Sstevel@tonic-gate 			}
656*7c478bd9Sstevel@tonic-gate 			if (invalid_proto) {
657*7c478bd9Sstevel@tonic-gate 				prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID;
658*7c478bd9Sstevel@tonic-gate 				goto past_proto_processing;
659*7c478bd9Sstevel@tonic-gate 			}
660*7c478bd9Sstevel@tonic-gate 		}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 		/*
663*7c478bd9Sstevel@tonic-gate 		 * We're running in validate only mode. Don't bother creating
664*7c478bd9Sstevel@tonic-gate 		 * any proto structures (they don't do any further validation).
665*7c478bd9Sstevel@tonic-gate 		 */
666*7c478bd9Sstevel@tonic-gate 		if (fmri == NULL)
667*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 		/*
670*7c478bd9Sstevel@tonic-gate 		 * Create the apropriate transport info structure.
671*7c478bd9Sstevel@tonic-gate 		 */
672*7c478bd9Sstevel@tonic-gate 		if (cfg->istlx) {
673*7c478bd9Sstevel@tonic-gate 			if ((ti = create_tlx_info(proto, tlx_ci_pool)) != NULL)
674*7c478bd9Sstevel@tonic-gate 				p_inf = (proto_info_t *)ti;
675*7c478bd9Sstevel@tonic-gate 		} else {
676*7c478bd9Sstevel@tonic-gate 			struct sockaddr_storage *ss;
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 			if ((si = calloc(1, sizeof (socket_info_t))) != NULL) {
679*7c478bd9Sstevel@tonic-gate 				p_inf = (proto_info_t *)si;
680*7c478bd9Sstevel@tonic-gate 				si->type = sock_type_id;
681*7c478bd9Sstevel@tonic-gate 				ss = &si->local_addr;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 				if (v6_socket_proto(proto)) {
684*7c478bd9Sstevel@tonic-gate 					ss->ss_family = AF_INET6;
685*7c478bd9Sstevel@tonic-gate 					/* already in network order */
686*7c478bd9Sstevel@tonic-gate 					((struct sockaddr_in6 *)ss)->sin6_addr =
687*7c478bd9Sstevel@tonic-gate 					    in6addr_any;
688*7c478bd9Sstevel@tonic-gate 				} else {
689*7c478bd9Sstevel@tonic-gate 					ss->ss_family = AF_INET;
690*7c478bd9Sstevel@tonic-gate 					((struct sockaddr_in *)ss)->sin_addr.
691*7c478bd9Sstevel@tonic-gate 					    s_addr = htonl(INADDR_ANY);
692*7c478bd9Sstevel@tonic-gate 				}
693*7c478bd9Sstevel@tonic-gate 			}
694*7c478bd9Sstevel@tonic-gate 		}
695*7c478bd9Sstevel@tonic-gate 		if (p_inf == NULL) {
696*7c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
697*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
698*7c478bd9Sstevel@tonic-gate 		}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 		p_inf->v6only = v6only;
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 		/*
703*7c478bd9Sstevel@tonic-gate 		 * Store the supplied proto string for error reporting,
704*7c478bd9Sstevel@tonic-gate 		 * re-attaching the 'only' suffix if one was taken off.
705*7c478bd9Sstevel@tonic-gate 		 */
706*7c478bd9Sstevel@tonic-gate 		if ((p_inf->proto = malloc(strlen(proto) + 5)) == NULL) {
707*7c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
708*7c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
709*7c478bd9Sstevel@tonic-gate 		} else {
710*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(p_inf->proto, proto, strlen(proto) + 5);
711*7c478bd9Sstevel@tonic-gate 			if (v6only)
712*7c478bd9Sstevel@tonic-gate 				(void) strlcat(p_inf->proto, "only",
713*7c478bd9Sstevel@tonic-gate 				    strlen(proto) + 5);
714*7c478bd9Sstevel@tonic-gate 		}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 		/*
717*7c478bd9Sstevel@tonic-gate 		 * Validate and setup RPC/non-RPC specifics.
718*7c478bd9Sstevel@tonic-gate 		 */
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 		if (isrpc) {
721*7c478bd9Sstevel@tonic-gate 			rpc_info_t *ri;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 			if ((rpc_pnum != -1) && (rpc_lv != -1) &&
724*7c478bd9Sstevel@tonic-gate 			    (rpc_hv != -1)) {
725*7c478bd9Sstevel@tonic-gate 				if ((ri = create_rpc_info(proto, rpc_pnum,
726*7c478bd9Sstevel@tonic-gate 				    rpc_lv, rpc_hv)) == NULL) {
727*7c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
728*7c478bd9Sstevel@tonic-gate 				} else {
729*7c478bd9Sstevel@tonic-gate 					p_inf->ri = ri;
730*7c478bd9Sstevel@tonic-gate 				}
731*7c478bd9Sstevel@tonic-gate 			}
732*7c478bd9Sstevel@tonic-gate 		}
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate past_proto_processing:
735*7c478bd9Sstevel@tonic-gate 		/* validate non-RPC service name */
736*7c478bd9Sstevel@tonic-gate 		if (!isrpc && (cfg->svc_name != NULL)) {
737*7c478bd9Sstevel@tonic-gate 			struct servent	se;
738*7c478bd9Sstevel@tonic-gate 			char		gsbuf[NSS_BUFLEN_SERVICES];
739*7c478bd9Sstevel@tonic-gate 			char		*gsproto = proto;
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 			if (invalid_proto) {
742*7c478bd9Sstevel@tonic-gate 				/*
743*7c478bd9Sstevel@tonic-gate 				 * Make getservbyname_r do its lookup without a
744*7c478bd9Sstevel@tonic-gate 				 * proto.
745*7c478bd9Sstevel@tonic-gate 				 */
746*7c478bd9Sstevel@tonic-gate 				gsproto = NULL;
747*7c478bd9Sstevel@tonic-gate 			} else if (gsproto != NULL) {
748*7c478bd9Sstevel@tonic-gate 				/*
749*7c478bd9Sstevel@tonic-gate 				 * Since getservbyname & getprotobyname don't
750*7c478bd9Sstevel@tonic-gate 				 * support tcp6, udp6 or sctp6 take off the 6
751*7c478bd9Sstevel@tonic-gate 				 * digit from protocol.
752*7c478bd9Sstevel@tonic-gate 				 */
753*7c478bd9Sstevel@tonic-gate 				if (v6_socket_proto(gsproto))
754*7c478bd9Sstevel@tonic-gate 					gsproto[strlen(gsproto) - 1] = '\0';
755*7c478bd9Sstevel@tonic-gate 			}
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 			if (getservbyname_r(cfg->svc_name, gsproto, &se, gsbuf,
758*7c478bd9Sstevel@tonic-gate 			    sizeof (gsbuf)) == NULL) {
759*7c478bd9Sstevel@tonic-gate 				if (gsproto != NULL)
760*7c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
761*7c478bd9Sstevel@tonic-gate 				prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
762*7c478bd9Sstevel@tonic-gate 			} else if (cfg->istlx && (ti != NULL)) {
763*7c478bd9Sstevel@tonic-gate 				/* LINTED E_BAD_PTR_CAST_ALIGN */
764*7c478bd9Sstevel@tonic-gate 				SS_SETPORT(*(struct sockaddr_storage *)
765*7c478bd9Sstevel@tonic-gate 				    ti->local_addr.buf, se.s_port);
766*7c478bd9Sstevel@tonic-gate 			} else if (!cfg->istlx && (si != NULL)) {
767*7c478bd9Sstevel@tonic-gate 				if ((gsproto != NULL) &&
768*7c478bd9Sstevel@tonic-gate 				    getprotobyname_r(gsproto, &pe, gpbuf,
769*7c478bd9Sstevel@tonic-gate 				    sizeof (gpbuf)) == NULL) {
770*7c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
771*7c478bd9Sstevel@tonic-gate 				} else {
772*7c478bd9Sstevel@tonic-gate 					si->protocol = pe.p_proto;
773*7c478bd9Sstevel@tonic-gate 				}
774*7c478bd9Sstevel@tonic-gate 				SS_SETPORT(si->local_addr, se.s_port);
775*7c478bd9Sstevel@tonic-gate 			}
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 		}
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 		if (p_inf != NULL) {
780*7c478bd9Sstevel@tonic-gate 			p_inf->listen_fd = -1;
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 			/* add new proto entry to proto_list */
783*7c478bd9Sstevel@tonic-gate 			uu_list_node_init(p_inf, &p_inf->link, proto_info_pool);
784*7c478bd9Sstevel@tonic-gate 			(void) uu_list_insert_after(cfg->proto_list, NULL,
785*7c478bd9Sstevel@tonic-gate 			    p_inf);
786*7c478bd9Sstevel@tonic-gate 		}
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 		if (nconf != NULL)
789*7c478bd9Sstevel@tonic-gate 			freenetconfigent(nconf);
790*7c478bd9Sstevel@tonic-gate 		if (invalid_proto)
791*7c478bd9Sstevel@tonic-gate 			prop[PT_PROTO_INDEX].ip_error = IVE_INVALID;
792*7c478bd9Sstevel@tonic-gate 	} while (proto != NULL);	/* while just processed a proto */
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	/*
795*7c478bd9Sstevel@tonic-gate 	 * Check that the exec string for the start method actually exists and
796*7c478bd9Sstevel@tonic-gate 	 * that the user is either a valid username or uid. Note we don't
797*7c478bd9Sstevel@tonic-gate 	 * mandate the setting of these fields, and don't do any checks
798*7c478bd9Sstevel@tonic-gate 	 * for arg0, hence its absence.
799*7c478bd9Sstevel@tonic-gate 	 */
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	if (prop[PT_EXEC_INDEX].ip_error != IVE_UNSET) {
802*7c478bd9Sstevel@tonic-gate 		/* Don't pass any arguments to access() */
803*7c478bd9Sstevel@tonic-gate 		if ((bufp = strdup(
804*7c478bd9Sstevel@tonic-gate 		    prop[PT_EXEC_INDEX].ip_value.iv_astring)) == NULL) {
805*7c478bd9Sstevel@tonic-gate 			prop[PT_EXEC_INDEX].ip_error = IVE_INVALID;
806*7c478bd9Sstevel@tonic-gate 		} else {
807*7c478bd9Sstevel@tonic-gate 			if ((cp = strpbrk(bufp, " \t")) != NULL)
808*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 			if ((access(bufp, F_OK) == -1) && (errno == ENOENT))
811*7c478bd9Sstevel@tonic-gate 				prop[PT_EXEC_INDEX].ip_error = IVE_INVALID;
812*7c478bd9Sstevel@tonic-gate 			free(bufp);
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if (prop[PT_USER_INDEX].ip_error != IVE_UNSET) {
817*7c478bd9Sstevel@tonic-gate 		char		pw_buf[NSS_BUFLEN_PASSWD];
818*7c478bd9Sstevel@tonic-gate 		struct passwd	pw;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 		if (getpwnam_r(prop[PT_USER_INDEX].ip_value.iv_astring, &pw,
821*7c478bd9Sstevel@tonic-gate 		    pw_buf, NSS_BUFLEN_PASSWD) == NULL) {
822*7c478bd9Sstevel@tonic-gate 			errno = 0;
823*7c478bd9Sstevel@tonic-gate 			uidl = strtol(prop[PT_USER_INDEX].ip_value.iv_astring,
824*7c478bd9Sstevel@tonic-gate 			    &bufp, 10);
825*7c478bd9Sstevel@tonic-gate 			if ((errno != 0) || (*bufp != '\0') ||
826*7c478bd9Sstevel@tonic-gate 			    (getpwuid_r(uidl, &pw, pw_buf,
827*7c478bd9Sstevel@tonic-gate 			    NSS_BUFLEN_PASSWD) == NULL))
828*7c478bd9Sstevel@tonic-gate 				prop[PT_USER_INDEX].ip_error = IVE_INVALID;
829*7c478bd9Sstevel@tonic-gate 		}
830*7c478bd9Sstevel@tonic-gate 	}
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	/*
833*7c478bd9Sstevel@tonic-gate 	 * Iterate through the properties in the array verifying that any
834*7c478bd9Sstevel@tonic-gate 	 * default properties are valid, and setting the return boolean
835*7c478bd9Sstevel@tonic-gate 	 * according to whether any properties were marked invalid.
836*7c478bd9Sstevel@tonic-gate 	 */
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
839*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error == IVE_UNSET)
840*7c478bd9Sstevel@tonic-gate 			continue;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_default &&
843*7c478bd9Sstevel@tonic-gate 		    !valid_default_prop(prop[i].ip_name, &prop[i].ip_value))
844*7c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_INVALID;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error == IVE_INVALID)
847*7c478bd9Sstevel@tonic-gate 			ret = B_FALSE;
848*7c478bd9Sstevel@tonic-gate 	}
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/* pass back the basic_cfg_t if requested and it's a valid config */
851*7c478bd9Sstevel@tonic-gate 	if ((cfgpp != NULL) && ret) {
852*7c478bd9Sstevel@tonic-gate 		*cfgpp = cfg;
853*7c478bd9Sstevel@tonic-gate 	} else {
854*7c478bd9Sstevel@tonic-gate 		destroy_basic_cfg(cfg);
855*7c478bd9Sstevel@tonic-gate 	}
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	return (ret);
858*7c478bd9Sstevel@tonic-gate }
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate /*
861*7c478bd9Sstevel@tonic-gate  * validate_default_prop takes the name of an inetd property, and a value
862*7c478bd9Sstevel@tonic-gate  * for that property.  It returns B_TRUE if the property is valid, and B_FALSE
863*7c478bd9Sstevel@tonic-gate  * if the proposed value isn't valid for that property.
864*7c478bd9Sstevel@tonic-gate  */
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate boolean_t
867*7c478bd9Sstevel@tonic-gate valid_default_prop(char *name, void *value)
868*7c478bd9Sstevel@tonic-gate {
869*7c478bd9Sstevel@tonic-gate 	int		i;
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
872*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, inetd_properties[i].ip_name) != 0)
873*7c478bd9Sstevel@tonic-gate 			continue;
874*7c478bd9Sstevel@tonic-gate 		if (!inetd_properties[i].ip_default)
875*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 		switch (inetd_properties[i].ip_type) {
878*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
879*7c478bd9Sstevel@tonic-gate 			if (*((int64_t *)value) >= -1)
880*7c478bd9Sstevel@tonic-gate 				return (B_TRUE);
881*7c478bd9Sstevel@tonic-gate 			else
882*7c478bd9Sstevel@tonic-gate 				return (B_FALSE);
883*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
884*7c478bd9Sstevel@tonic-gate 			if ((*((boolean_t *)value) == B_FALSE) ||
885*7c478bd9Sstevel@tonic-gate 			    (*((boolean_t *)value) == B_TRUE))
886*7c478bd9Sstevel@tonic-gate 				return (B_TRUE);
887*7c478bd9Sstevel@tonic-gate 			else
888*7c478bd9Sstevel@tonic-gate 				return (B_FALSE);
889*7c478bd9Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
890*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
891*7c478bd9Sstevel@tonic-gate 		}
892*7c478bd9Sstevel@tonic-gate 	}
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
895*7c478bd9Sstevel@tonic-gate }
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate scf_error_t
898*7c478bd9Sstevel@tonic-gate read_prop(scf_handle_t *h, inetd_prop_t *iprop, int index, const char *inst,
899*7c478bd9Sstevel@tonic-gate     const char *pg_name)
900*7c478bd9Sstevel@tonic-gate {
901*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*sprop;
902*7c478bd9Sstevel@tonic-gate 	uint8_t			*tmp_bool;
903*7c478bd9Sstevel@tonic-gate 	int64_t			*tmp_int;
904*7c478bd9Sstevel@tonic-gate 	uint64_t		*tmp_cnt;
905*7c478bd9Sstevel@tonic-gate 	char			*tmp_char;
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	if ((sprop = scf_simple_prop_get(h, inst, pg_name, iprop->ip_name)) ==
908*7c478bd9Sstevel@tonic-gate 	    NULL)
909*7c478bd9Sstevel@tonic-gate 		return (scf_error());
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	switch (iprop->ip_type) {
912*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
913*7c478bd9Sstevel@tonic-gate 		if (index == PT_PROTO_INDEX) {
914*7c478bd9Sstevel@tonic-gate 			int	j = 0;
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 			while ((tmp_char =
917*7c478bd9Sstevel@tonic-gate 			    scf_simple_prop_next_astring(sprop)) != NULL) {
918*7c478bd9Sstevel@tonic-gate 				char	**cpp;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 				if ((cpp = realloc(
921*7c478bd9Sstevel@tonic-gate 				    iprop->ip_value.iv_proto_list,
922*7c478bd9Sstevel@tonic-gate 				    (j + 2) * sizeof (char *))) == NULL) {
923*7c478bd9Sstevel@tonic-gate 					scf_simple_prop_free(sprop);
924*7c478bd9Sstevel@tonic-gate 					return (SCF_ERROR_NO_MEMORY);
925*7c478bd9Sstevel@tonic-gate 				}
926*7c478bd9Sstevel@tonic-gate 				iprop->ip_value.iv_proto_list = cpp;
927*7c478bd9Sstevel@tonic-gate 				if ((cpp[j] = strdup(tmp_char)) == NULL) {
928*7c478bd9Sstevel@tonic-gate 					scf_simple_prop_free(sprop);
929*7c478bd9Sstevel@tonic-gate 					return (SCF_ERROR_NO_MEMORY);
930*7c478bd9Sstevel@tonic-gate 				}
931*7c478bd9Sstevel@tonic-gate 				cpp[++j] = NULL;
932*7c478bd9Sstevel@tonic-gate 			}
933*7c478bd9Sstevel@tonic-gate 			if ((j == 0) || (scf_error() != SCF_ERROR_NONE))
934*7c478bd9Sstevel@tonic-gate 				goto scf_error;
935*7c478bd9Sstevel@tonic-gate 		} else {
936*7c478bd9Sstevel@tonic-gate 			if ((tmp_char = scf_simple_prop_next_astring(sprop)) ==
937*7c478bd9Sstevel@tonic-gate 			    NULL)
938*7c478bd9Sstevel@tonic-gate 				goto scf_error;
939*7c478bd9Sstevel@tonic-gate 			if ((iprop->ip_value.iv_astring = strdup(tmp_char)) ==
940*7c478bd9Sstevel@tonic-gate 			    NULL) {
941*7c478bd9Sstevel@tonic-gate 				scf_simple_prop_free(sprop);
942*7c478bd9Sstevel@tonic-gate 				return (SCF_ERROR_NO_MEMORY);
943*7c478bd9Sstevel@tonic-gate 			}
944*7c478bd9Sstevel@tonic-gate 		}
945*7c478bd9Sstevel@tonic-gate 		break;
946*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
947*7c478bd9Sstevel@tonic-gate 		if ((tmp_bool = scf_simple_prop_next_boolean(sprop)) == NULL)
948*7c478bd9Sstevel@tonic-gate 			goto scf_error;
949*7c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_boolean =
950*7c478bd9Sstevel@tonic-gate 		    (*tmp_bool == 0) ? B_FALSE : B_TRUE;
951*7c478bd9Sstevel@tonic-gate 		break;
952*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
953*7c478bd9Sstevel@tonic-gate 		if ((tmp_cnt = scf_simple_prop_next_count(sprop)) == NULL)
954*7c478bd9Sstevel@tonic-gate 			goto scf_error;
955*7c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_cnt = *tmp_cnt;
956*7c478bd9Sstevel@tonic-gate 		break;
957*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
958*7c478bd9Sstevel@tonic-gate 		if ((tmp_int = scf_simple_prop_next_integer(sprop)) == NULL)
959*7c478bd9Sstevel@tonic-gate 			goto scf_error;
960*7c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_int = *tmp_int;
961*7c478bd9Sstevel@tonic-gate 		break;
962*7c478bd9Sstevel@tonic-gate 	default:
963*7c478bd9Sstevel@tonic-gate 		assert(0);
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	iprop->ip_error = IVE_VALID;
967*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sprop);
968*7c478bd9Sstevel@tonic-gate 	return (0);
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate scf_error:
971*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sprop);
972*7c478bd9Sstevel@tonic-gate 	if (scf_error() == SCF_ERROR_NONE)
973*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
974*7c478bd9Sstevel@tonic-gate 	return (scf_error());
975*7c478bd9Sstevel@tonic-gate }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate /*
978*7c478bd9Sstevel@tonic-gate  * read_props reads either the full set of properties for instance 'instance'
979*7c478bd9Sstevel@tonic-gate  * (including defaults - pulling them in from inetd where necessary) if
980*7c478bd9Sstevel@tonic-gate  * 'instance' is non-null, else just the defaults from inetd. The properties
981*7c478bd9Sstevel@tonic-gate  * are returned in an allocated inetd_prop_t array, which must be freed
982*7c478bd9Sstevel@tonic-gate  * using free_instance_props(). If an error occurs NULL is returned and 'err'
983*7c478bd9Sstevel@tonic-gate  * is set to indicate the cause, else a pointer to the read properties is
984*7c478bd9Sstevel@tonic-gate  * returned.
985*7c478bd9Sstevel@tonic-gate  */
986*7c478bd9Sstevel@tonic-gate static inetd_prop_t *
987*7c478bd9Sstevel@tonic-gate read_props(scf_handle_t *h, const char *instance, size_t *num_elements,
988*7c478bd9Sstevel@tonic-gate     scf_error_t *err)
989*7c478bd9Sstevel@tonic-gate {
990*7c478bd9Sstevel@tonic-gate 	inetd_prop_t	*ret = NULL;
991*7c478bd9Sstevel@tonic-gate 	int		i;
992*7c478bd9Sstevel@tonic-gate 	boolean_t	defaults_only = (instance == NULL);
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	if ((ret = malloc(sizeof (inetd_properties))) == NULL) {
995*7c478bd9Sstevel@tonic-gate 		*err = SCF_ERROR_NO_MEMORY;
996*7c478bd9Sstevel@tonic-gate 		return (NULL);
997*7c478bd9Sstevel@tonic-gate 	}
998*7c478bd9Sstevel@tonic-gate 	(void) memcpy(ret, &inetd_properties, sizeof (inetd_properties));
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	if (defaults_only)
1001*7c478bd9Sstevel@tonic-gate 		instance = INETD_INSTANCE_FMRI;
1002*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
1003*7c478bd9Sstevel@tonic-gate 		if (defaults_only && !ret[i].ip_default)
1004*7c478bd9Sstevel@tonic-gate 			continue;
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 		switch (*err = read_prop(h, &ret[i], i, instance,
1007*7c478bd9Sstevel@tonic-gate 		    defaults_only ? PG_NAME_SERVICE_DEFAULTS : ret[i].ip_pg)) {
1008*7c478bd9Sstevel@tonic-gate 		case 0:
1009*7c478bd9Sstevel@tonic-gate 			break;
1010*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
1011*7c478bd9Sstevel@tonic-gate 			goto failure_cleanup;
1012*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1013*7c478bd9Sstevel@tonic-gate 			/*
1014*7c478bd9Sstevel@tonic-gate 			 * In non-default-only mode where we're reading a
1015*7c478bd9Sstevel@tonic-gate 			 * default property, since the property wasn't
1016*7c478bd9Sstevel@tonic-gate 			 * found in the instance, try and read inetd's default
1017*7c478bd9Sstevel@tonic-gate 			 * value.
1018*7c478bd9Sstevel@tonic-gate 			 */
1019*7c478bd9Sstevel@tonic-gate 			if (!ret[i].ip_default || defaults_only)
1020*7c478bd9Sstevel@tonic-gate 				continue;
1021*7c478bd9Sstevel@tonic-gate 			switch (*err = read_prop(h, &ret[i], i,
1022*7c478bd9Sstevel@tonic-gate 			    INETD_INSTANCE_FMRI, PG_NAME_SERVICE_DEFAULTS)) {
1023*7c478bd9Sstevel@tonic-gate 			case 0:
1024*7c478bd9Sstevel@tonic-gate 				ret[i].from_inetd = B_TRUE;
1025*7c478bd9Sstevel@tonic-gate 				continue;
1026*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
1027*7c478bd9Sstevel@tonic-gate 				continue;
1028*7c478bd9Sstevel@tonic-gate 			default:
1029*7c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
1030*7c478bd9Sstevel@tonic-gate 			}
1031*7c478bd9Sstevel@tonic-gate 		default:
1032*7c478bd9Sstevel@tonic-gate 			goto failure_cleanup;
1033*7c478bd9Sstevel@tonic-gate 		}
1034*7c478bd9Sstevel@tonic-gate 	}
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	*num_elements = INETD_NUMPROPS;
1037*7c478bd9Sstevel@tonic-gate 	return (ret);
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate failure_cleanup:
1040*7c478bd9Sstevel@tonic-gate 	free_instance_props(ret);
1041*7c478bd9Sstevel@tonic-gate 	return (NULL);
1042*7c478bd9Sstevel@tonic-gate }
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate /*
1045*7c478bd9Sstevel@tonic-gate  * Read all properties applicable to 'instance' (including defaults).
1046*7c478bd9Sstevel@tonic-gate  */
1047*7c478bd9Sstevel@tonic-gate inetd_prop_t *
1048*7c478bd9Sstevel@tonic-gate read_instance_props(scf_handle_t *h, const char *instance, size_t *num_elements,
1049*7c478bd9Sstevel@tonic-gate     scf_error_t *err)
1050*7c478bd9Sstevel@tonic-gate {
1051*7c478bd9Sstevel@tonic-gate 	return (read_props(h, instance, num_elements, err));
1052*7c478bd9Sstevel@tonic-gate }
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate /*
1055*7c478bd9Sstevel@tonic-gate  * Read the default properties from inetd's defaults property group.
1056*7c478bd9Sstevel@tonic-gate  */
1057*7c478bd9Sstevel@tonic-gate inetd_prop_t *
1058*7c478bd9Sstevel@tonic-gate read_default_props(scf_handle_t *h, size_t *num_elements, scf_error_t *err)
1059*7c478bd9Sstevel@tonic-gate {
1060*7c478bd9Sstevel@tonic-gate 	return (read_props(h, NULL, num_elements, err));
1061*7c478bd9Sstevel@tonic-gate }
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate void
1064*7c478bd9Sstevel@tonic-gate free_instance_props(inetd_prop_t *prop)
1065*7c478bd9Sstevel@tonic-gate {
1066*7c478bd9Sstevel@tonic-gate 	int i;
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	if (prop == NULL)
1069*7c478bd9Sstevel@tonic-gate 		return;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < INETD_NUMPROPS; i++) {
1072*7c478bd9Sstevel@tonic-gate 		if (prop[i].ip_type == SCF_TYPE_ASTRING) {
1073*7c478bd9Sstevel@tonic-gate 			if (i == PT_PROTO_INDEX) {
1074*7c478bd9Sstevel@tonic-gate 				destroy_strings(prop[i].ip_value.iv_proto_list);
1075*7c478bd9Sstevel@tonic-gate 			} else {
1076*7c478bd9Sstevel@tonic-gate 				free(prop[i].ip_value.iv_astring);
1077*7c478bd9Sstevel@tonic-gate 			}
1078*7c478bd9Sstevel@tonic-gate 		}
1079*7c478bd9Sstevel@tonic-gate 	}
1080*7c478bd9Sstevel@tonic-gate 	free(prop);
1081*7c478bd9Sstevel@tonic-gate }
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate int
1084*7c478bd9Sstevel@tonic-gate connect_to_inetd(void)
1085*7c478bd9Sstevel@tonic-gate {
1086*7c478bd9Sstevel@tonic-gate 	struct sockaddr_un	addr;
1087*7c478bd9Sstevel@tonic-gate 	int			fd;
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
1090*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
1091*7c478bd9Sstevel@tonic-gate 		return (-1);
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	(void) memset(&addr, 0, sizeof (addr));
1094*7c478bd9Sstevel@tonic-gate 	addr.sun_family = AF_UNIX;
1095*7c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
1096*7c478bd9Sstevel@tonic-gate 	assert(sizeof (INETD_UDS_PATH) <= sizeof (addr.sun_path));
1097*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(addr.sun_path, INETD_UDS_PATH,
1098*7c478bd9Sstevel@tonic-gate 	    sizeof (addr.sun_path));
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
1101*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1102*7c478bd9Sstevel@tonic-gate 		return (-1);
1103*7c478bd9Sstevel@tonic-gate 	}
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	return (fd);
1106*7c478bd9Sstevel@tonic-gate }
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate /*
1109*7c478bd9Sstevel@tonic-gate  * refresh_inetd requests that inetd re-read all of the information that it's
1110*7c478bd9Sstevel@tonic-gate  * monitoring.
1111*7c478bd9Sstevel@tonic-gate  */
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate int
1114*7c478bd9Sstevel@tonic-gate refresh_inetd(void)
1115*7c478bd9Sstevel@tonic-gate {
1116*7c478bd9Sstevel@tonic-gate 	uds_request_t   req;
1117*7c478bd9Sstevel@tonic-gate 	int		fd;
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	if ((fd = connect_to_inetd()) < 0)
1120*7c478bd9Sstevel@tonic-gate 		return (-1);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	req = UR_REFRESH_INETD;
1123*7c478bd9Sstevel@tonic-gate 	if (send(fd, &req, sizeof (req), 0) < 0) {
1124*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1125*7c478bd9Sstevel@tonic-gate 		return (-1);
1126*7c478bd9Sstevel@tonic-gate 	}
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1129*7c478bd9Sstevel@tonic-gate 	return (0);
1130*7c478bd9Sstevel@tonic-gate }
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate /*
1133*7c478bd9Sstevel@tonic-gate  * Returns the id of the socket type 'type_str' that can be used in a call
1134*7c478bd9Sstevel@tonic-gate  * to socket(). If an unknown type string is passed returns -1, else the id.
1135*7c478bd9Sstevel@tonic-gate  */
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate int
1138*7c478bd9Sstevel@tonic-gate get_sock_type_id(const char *type_str)
1139*7c478bd9Sstevel@tonic-gate {
1140*7c478bd9Sstevel@tonic-gate 	int	ret;
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	if (strcmp(SOCKTYPE_STREAM_STR, type_str) == 0) {
1143*7c478bd9Sstevel@tonic-gate 		ret = SOCK_STREAM;
1144*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_DGRAM_STR, type_str) == 0) {
1145*7c478bd9Sstevel@tonic-gate 		ret = SOCK_DGRAM;
1146*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_RAW_STR, type_str) == 0) {
1147*7c478bd9Sstevel@tonic-gate 		ret = SOCK_RAW;
1148*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_SEQPKT_STR, type_str) == 0) {
1149*7c478bd9Sstevel@tonic-gate 		ret = SOCK_SEQPACKET;
1150*7c478bd9Sstevel@tonic-gate 	} else {
1151*7c478bd9Sstevel@tonic-gate 		ret = -1;
1152*7c478bd9Sstevel@tonic-gate 	}
1153*7c478bd9Sstevel@tonic-gate 	return (ret);
1154*7c478bd9Sstevel@tonic-gate }
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate /*
1157*7c478bd9Sstevel@tonic-gate  * Takes either an RPC service name or number in string form as 'svc_name', and
1158*7c478bd9Sstevel@tonic-gate  * returns an integer format program number for the service. If the name isn't
1159*7c478bd9Sstevel@tonic-gate  * recognized as a valid RPC service name or isn't a valid number, -1 is
1160*7c478bd9Sstevel@tonic-gate  * returned, else the services program number.
1161*7c478bd9Sstevel@tonic-gate  */
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate int
1164*7c478bd9Sstevel@tonic-gate get_rpc_prognum(const char *svc_name)
1165*7c478bd9Sstevel@tonic-gate {
1166*7c478bd9Sstevel@tonic-gate 	struct rpcent	rpc;
1167*7c478bd9Sstevel@tonic-gate 	char		buf[INETSVC_SVC_BUF_MAX];
1168*7c478bd9Sstevel@tonic-gate 	int		pnum;
1169*7c478bd9Sstevel@tonic-gate 	char		*endptr;
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 	if (getrpcbyname_r(svc_name, &rpc, buf, sizeof (buf)) != NULL)
1172*7c478bd9Sstevel@tonic-gate 		return (rpc.r_number);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	pnum = strtol(svc_name, &endptr, 0);
1175*7c478bd9Sstevel@tonic-gate 	if ((pnum == 0 && errno == EINVAL) ||
1176*7c478bd9Sstevel@tonic-gate 	    (pnum == LONG_MAX && errno == ERANGE) ||
1177*7c478bd9Sstevel@tonic-gate 	    pnum < 0 || *endptr != '\0') {
1178*7c478bd9Sstevel@tonic-gate 		return (-1);
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	return (pnum);
1182*7c478bd9Sstevel@tonic-gate }
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate /*
1185*7c478bd9Sstevel@tonic-gate  * calculate_hash calculates the MD5 message-digest of the file pathname.
1186*7c478bd9Sstevel@tonic-gate  * On success, hash is modified to point to the digest string and 0 is returned.
1187*7c478bd9Sstevel@tonic-gate  * Otherwise, -1 is returned and errno is set to indicate the error.
1188*7c478bd9Sstevel@tonic-gate  * The space for the digest string is obtained using malloc(3C) and should be
1189*7c478bd9Sstevel@tonic-gate  * freed by the caller.
1190*7c478bd9Sstevel@tonic-gate  */
1191*7c478bd9Sstevel@tonic-gate int
1192*7c478bd9Sstevel@tonic-gate calculate_hash(const char *pathname, char **hash)
1193*7c478bd9Sstevel@tonic-gate {
1194*7c478bd9Sstevel@tonic-gate 	int fd, i, serrno;
1195*7c478bd9Sstevel@tonic-gate 	size_t len;
1196*7c478bd9Sstevel@tonic-gate 	ssize_t n;
1197*7c478bd9Sstevel@tonic-gate 	char *digest;
1198*7c478bd9Sstevel@tonic-gate 	MD5_CTX md5_context;
1199*7c478bd9Sstevel@tonic-gate 	unsigned char md5_digest[DIGEST_LEN];
1200*7c478bd9Sstevel@tonic-gate 	unsigned char buf[READ_BUFSIZ];
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	do {
1203*7c478bd9Sstevel@tonic-gate 		fd = open(pathname, O_RDONLY);
1204*7c478bd9Sstevel@tonic-gate 	} while (fd == -1 && errno == EINTR);
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
1207*7c478bd9Sstevel@tonic-gate 		return (-1);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	/* allocate space for a 16-byte MD5 digest as a string of hex digits */
1210*7c478bd9Sstevel@tonic-gate 	len = 2 * sizeof (md5_digest) + 1;
1211*7c478bd9Sstevel@tonic-gate 	if ((digest = malloc(len)) == NULL) {
1212*7c478bd9Sstevel@tonic-gate 		serrno = errno;
1213*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1214*7c478bd9Sstevel@tonic-gate 		errno = serrno;
1215*7c478bd9Sstevel@tonic-gate 		return (-1);
1216*7c478bd9Sstevel@tonic-gate 	}
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	MD5Init(&md5_context);
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 	do {
1221*7c478bd9Sstevel@tonic-gate 		if ((n = read(fd, buf, sizeof (buf))) > 0)
1222*7c478bd9Sstevel@tonic-gate 			MD5Update(&md5_context, buf, n);
1223*7c478bd9Sstevel@tonic-gate 	} while ((n > 0) || (n == -1 && errno == EINTR));
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	serrno = errno;
1226*7c478bd9Sstevel@tonic-gate 	MD5Final(md5_digest, &md5_context);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (n == -1) {
1231*7c478bd9Sstevel@tonic-gate 		errno = serrno;
1232*7c478bd9Sstevel@tonic-gate 		return (-1);
1233*7c478bd9Sstevel@tonic-gate 	}
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (md5_digest); i++) {
1236*7c478bd9Sstevel@tonic-gate 		(void) snprintf(&digest[2 * i], len - (2 * i), "%02x",
1237*7c478bd9Sstevel@tonic-gate 		    md5_digest[i]);
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 	*hash = digest;
1240*7c478bd9Sstevel@tonic-gate 	return (0);
1241*7c478bd9Sstevel@tonic-gate }
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate /*
1244*7c478bd9Sstevel@tonic-gate  * retrieve_inetd_hash retrieves inetd's configuration file hash from the
1245*7c478bd9Sstevel@tonic-gate  * repository. On success, hash is modified to point to the hash string and
1246*7c478bd9Sstevel@tonic-gate  * SCF_ERROR_NONE is returned. Otherwise, the scf_error value is returned.
1247*7c478bd9Sstevel@tonic-gate  * The space for the hash string is obtained using malloc(3C) and should be
1248*7c478bd9Sstevel@tonic-gate  * freed by the caller.
1249*7c478bd9Sstevel@tonic-gate  */
1250*7c478bd9Sstevel@tonic-gate scf_error_t
1251*7c478bd9Sstevel@tonic-gate retrieve_inetd_hash(char **hash)
1252*7c478bd9Sstevel@tonic-gate {
1253*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_t *sp;
1254*7c478bd9Sstevel@tonic-gate 	char *hashstr, *s;
1255*7c478bd9Sstevel@tonic-gate 	scf_error_t scf_err;
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, HASH_PG,
1258*7c478bd9Sstevel@tonic-gate 	    HASH_PROP)) == NULL)
1259*7c478bd9Sstevel@tonic-gate 		return (scf_error());
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 	if ((hashstr = scf_simple_prop_next_astring(sp)) == NULL) {
1262*7c478bd9Sstevel@tonic-gate 		scf_err = scf_error();
1263*7c478bd9Sstevel@tonic-gate 		scf_simple_prop_free(sp);
1264*7c478bd9Sstevel@tonic-gate 		return (scf_err);
1265*7c478bd9Sstevel@tonic-gate 	}
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	if ((s = strdup(hashstr)) == NULL) {
1268*7c478bd9Sstevel@tonic-gate 		scf_simple_prop_free(sp);
1269*7c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
1270*7c478bd9Sstevel@tonic-gate 	}
1271*7c478bd9Sstevel@tonic-gate 	*hash = s;
1272*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sp);
1273*7c478bd9Sstevel@tonic-gate 	return (SCF_ERROR_NONE);
1274*7c478bd9Sstevel@tonic-gate }
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate /*
1277*7c478bd9Sstevel@tonic-gate  * store_inetd_hash stores the string hash in inetd's configuration file hash
1278*7c478bd9Sstevel@tonic-gate  * in the repository. On success, SCF_ERROR_NONE is returned. Otherwise, the
1279*7c478bd9Sstevel@tonic-gate  * scf_error value is returned.
1280*7c478bd9Sstevel@tonic-gate  */
1281*7c478bd9Sstevel@tonic-gate scf_error_t
1282*7c478bd9Sstevel@tonic-gate store_inetd_hash(const char *hash)
1283*7c478bd9Sstevel@tonic-gate {
1284*7c478bd9Sstevel@tonic-gate 	int ret;
1285*7c478bd9Sstevel@tonic-gate 	scf_error_t rval = SCF_ERROR_NONE;
1286*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
1287*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1288*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
1289*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx = NULL;
1290*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *txent = NULL;
1291*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
1292*7c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
1295*7c478bd9Sstevel@tonic-gate 	    scf_handle_bind(h) == -1)
1296*7c478bd9Sstevel@tonic-gate 		goto error;
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
1299*7c478bd9Sstevel@tonic-gate 	    (inst = scf_instance_create(h)) == NULL ||
1300*7c478bd9Sstevel@tonic-gate 	    scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL, inst,
1301*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1)
1302*7c478bd9Sstevel@tonic-gate 		goto error;
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, HASH_PG, pg) == -1) {
1305*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND ||
1306*7c478bd9Sstevel@tonic-gate 		    scf_instance_add_pg(inst, HASH_PG, SCF_GROUP_APPLICATION,
1307*7c478bd9Sstevel@tonic-gate 		    0, pg) == -1)
1308*7c478bd9Sstevel@tonic-gate 			goto error;
1309*7c478bd9Sstevel@tonic-gate 	}
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
1312*7c478bd9Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL ||
1313*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
1314*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
1315*7c478bd9Sstevel@tonic-gate 		goto error;
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	do {
1318*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1)
1319*7c478bd9Sstevel@tonic-gate 			goto error;
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_new(tx, txent, HASH_PROP,
1322*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) == -1 &&
1323*7c478bd9Sstevel@tonic-gate 		    scf_transaction_property_change_type(tx, txent, HASH_PROP,
1324*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) == -1)
1325*7c478bd9Sstevel@tonic-gate 			goto error;
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(val, hash) == -1 ||
1328*7c478bd9Sstevel@tonic-gate 		    scf_entry_add_value(txent, val) == -1)
1329*7c478bd9Sstevel@tonic-gate 			goto error;
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 		if ((ret = scf_transaction_commit(tx)) == -1)
1332*7c478bd9Sstevel@tonic-gate 			goto error;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		if (ret == 0) {
1335*7c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
1336*7c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
1337*7c478bd9Sstevel@tonic-gate 				goto error;
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 	} while (ret == 0);
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	goto success;
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate error:
1344*7c478bd9Sstevel@tonic-gate 	rval = scf_error();
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate success:
1347*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
1348*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1349*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(txent);
1350*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
1351*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
1352*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1353*7c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
1354*7c478bd9Sstevel@tonic-gate 	return (rval);
1355*7c478bd9Sstevel@tonic-gate }
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate /*
1358*7c478bd9Sstevel@tonic-gate  * This is a wrapper function for inet_ntop(). In case the af is AF_INET6
1359*7c478bd9Sstevel@tonic-gate  * and the address pointed by src is a IPv4-mapped IPv6 address, it returns
1360*7c478bd9Sstevel@tonic-gate  * a printable IPv4 address, not an IPv4-mapped IPv6 address. In other cases it
1361*7c478bd9Sstevel@tonic-gate  * behaves just like inet_ntop().
1362*7c478bd9Sstevel@tonic-gate  */
1363*7c478bd9Sstevel@tonic-gate const char *
1364*7c478bd9Sstevel@tonic-gate inet_ntop_native(int af, const void *addr, char *dst, size_t size)
1365*7c478bd9Sstevel@tonic-gate {
1366*7c478bd9Sstevel@tonic-gate 	struct in_addr	v4addr;
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 	if ((af == AF_INET6) && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) {
1369*7c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr);
1370*7c478bd9Sstevel@tonic-gate 		return (inet_ntop(AF_INET, &v4addr, dst, size));
1371*7c478bd9Sstevel@tonic-gate 	} else {
1372*7c478bd9Sstevel@tonic-gate 		return (inet_ntop(af, addr, dst, size));
1373*7c478bd9Sstevel@tonic-gate 	}
1374*7c478bd9Sstevel@tonic-gate }
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate /*
1377*7c478bd9Sstevel@tonic-gate  * inetd specific setproctitle. It sets the title so that it contains
1378*7c478bd9Sstevel@tonic-gate  * 'svc_name' followed by, if obtainable, the address of the remote end of
1379*7c478bd9Sstevel@tonic-gate  * socket 's'.
1380*7c478bd9Sstevel@tonic-gate  * NOTE: The argv manipulation in this function should be replaced when a
1381*7c478bd9Sstevel@tonic-gate  * common version of setproctitle is made available.
1382*7c478bd9Sstevel@tonic-gate  */
1383*7c478bd9Sstevel@tonic-gate void
1384*7c478bd9Sstevel@tonic-gate setproctitle(const char *svc_name, int s, char *argv[])
1385*7c478bd9Sstevel@tonic-gate {
1386*7c478bd9Sstevel@tonic-gate 	socklen_t		size;
1387*7c478bd9Sstevel@tonic-gate 	struct sockaddr_storage	ss;
1388*7c478bd9Sstevel@tonic-gate 	char			abuf[INET6_ADDRSTRLEN];
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	static char		buf[80];
1391*7c478bd9Sstevel@tonic-gate 
1392*7c478bd9Sstevel@tonic-gate 	size = (socklen_t)sizeof (ss);
1393*7c478bd9Sstevel@tonic-gate 	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1394*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "-%s [%s]", svc_name,
1395*7c478bd9Sstevel@tonic-gate 		    inet_ntop_native(ss.ss_family, (ss.ss_family == AF_INET6 ?
1396*7c478bd9Sstevel@tonic-gate 		    (void *)&((struct sockaddr_in6 *)(&ss))->sin6_addr :
1397*7c478bd9Sstevel@tonic-gate 		    (void *)&((struct sockaddr_in *)(&ss))->sin_addr), abuf,
1398*7c478bd9Sstevel@tonic-gate 		    sizeof (abuf)));
1399*7c478bd9Sstevel@tonic-gate 	} else {
1400*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "-%s", svc_name);
1401*7c478bd9Sstevel@tonic-gate 	}
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate 	/* we set argv[0] to point at our static storage. */
1404*7c478bd9Sstevel@tonic-gate 	argv[0] = buf;
1405*7c478bd9Sstevel@tonic-gate 	argv[1] = NULL;
1406*7c478bd9Sstevel@tonic-gate }
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate static boolean_t
1409*7c478bd9Sstevel@tonic-gate inetd_builtin_srcport(in_port_t p)
1410*7c478bd9Sstevel@tonic-gate {
1411*7c478bd9Sstevel@tonic-gate 	p = ntohs(p);
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate 	if ((p == IPPORT_ECHO) ||
1414*7c478bd9Sstevel@tonic-gate 	    (p == IPPORT_DISCARD) ||
1415*7c478bd9Sstevel@tonic-gate 	    (p == IPPORT_DAYTIME) ||
1416*7c478bd9Sstevel@tonic-gate 	    (p == IPPORT_CHARGEN) ||
1417*7c478bd9Sstevel@tonic-gate 	    (p == IPPORT_TIMESERVER)) {
1418*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1419*7c478bd9Sstevel@tonic-gate 	} else {
1420*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1421*7c478bd9Sstevel@tonic-gate 	}
1422*7c478bd9Sstevel@tonic-gate }
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
1425*7c478bd9Sstevel@tonic-gate static void
1426*7c478bd9Sstevel@tonic-gate alarm_handler(int sig)
1427*7c478bd9Sstevel@tonic-gate {
1428*7c478bd9Sstevel@tonic-gate 	exit(0);
1429*7c478bd9Sstevel@tonic-gate }
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate /*
1432*7c478bd9Sstevel@tonic-gate  * This function is a datagram service template. It acts as a datagram wait
1433*7c478bd9Sstevel@tonic-gate  * type server, waiting for datagrams to come in, and when they do passing
1434*7c478bd9Sstevel@tonic-gate  * their contents, as-well as the socket they came in on and the remote
1435*7c478bd9Sstevel@tonic-gate  * address, in a call to the callback function 'cb'. If no datagrams are
1436*7c478bd9Sstevel@tonic-gate  * received for DG_INACTIVITY_TIMEOUT seconds the function exits with code 0.
1437*7c478bd9Sstevel@tonic-gate  */
1438*7c478bd9Sstevel@tonic-gate void
1439*7c478bd9Sstevel@tonic-gate dg_template(void (*cb)(int, const struct sockaddr *, int, const void *, size_t),
1440*7c478bd9Sstevel@tonic-gate     int s, void *buf, size_t buflen)
1441*7c478bd9Sstevel@tonic-gate {
1442*7c478bd9Sstevel@tonic-gate 	struct sockaddr_storage	sa;
1443*7c478bd9Sstevel@tonic-gate 	socklen_t		sa_size;
1444*7c478bd9Sstevel@tonic-gate 	ssize_t			i;
1445*7c478bd9Sstevel@tonic-gate 	char			tmp[BUFSIZ];
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGALRM, alarm_handler);
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
1450*7c478bd9Sstevel@tonic-gate 		buf = tmp;
1451*7c478bd9Sstevel@tonic-gate 		buflen = sizeof (tmp);
1452*7c478bd9Sstevel@tonic-gate 	}
1453*7c478bd9Sstevel@tonic-gate 	for (;;) {
1454*7c478bd9Sstevel@tonic-gate 		(void) alarm(DG_INACTIVITY_TIMEOUT);
1455*7c478bd9Sstevel@tonic-gate 		sa_size = sizeof (sa);
1456*7c478bd9Sstevel@tonic-gate 		if ((i = recvfrom(s, buf, buflen, 0, (struct sockaddr *)&sa,
1457*7c478bd9Sstevel@tonic-gate 		    &sa_size)) < 0) {
1458*7c478bd9Sstevel@tonic-gate 			continue;
1459*7c478bd9Sstevel@tonic-gate 		} else if (inetd_builtin_srcport(
1460*7c478bd9Sstevel@tonic-gate 		    ((struct sockaddr_in *)(&sa))->sin_port)) {
1461*7c478bd9Sstevel@tonic-gate 			/* denial-of-service attack possibility - ignore it */
1462*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
1463*7c478bd9Sstevel@tonic-gate 	"Incoming datagram from internal inetd service received; ignoring.");
1464*7c478bd9Sstevel@tonic-gate 			continue;
1465*7c478bd9Sstevel@tonic-gate 		}
1466*7c478bd9Sstevel@tonic-gate 		(void) alarm(0);
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 		cb(s, (struct sockaddr *)&sa, sa_size, buf, i);
1469*7c478bd9Sstevel@tonic-gate 	}
1470*7c478bd9Sstevel@tonic-gate }
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate /*
1473*7c478bd9Sstevel@tonic-gate  * An extension of write() or sendto() that keeps trying until either the full
1474*7c478bd9Sstevel@tonic-gate  * request has completed or a non-EINTR error occurs. If 'to' is set to a
1475*7c478bd9Sstevel@tonic-gate  * non-NULL value, sendto() is extended, else write(). Returns 0 on success
1476*7c478bd9Sstevel@tonic-gate  * else -1.
1477*7c478bd9Sstevel@tonic-gate  */
1478*7c478bd9Sstevel@tonic-gate int
1479*7c478bd9Sstevel@tonic-gate safe_sendto_write(int fd, const void *buf, size_t sz, int flags,
1480*7c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen) {
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	size_t		cnt = 0;
1483*7c478bd9Sstevel@tonic-gate 	ssize_t		ret;
1484*7c478bd9Sstevel@tonic-gate 	const char	*cp = buf;
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate 	do {
1487*7c478bd9Sstevel@tonic-gate 		if (to == NULL) {
1488*7c478bd9Sstevel@tonic-gate 			ret = write(fd, cp + cnt, sz - cnt);
1489*7c478bd9Sstevel@tonic-gate 		} else {
1490*7c478bd9Sstevel@tonic-gate 			ret = sendto(fd, cp + cnt, sz - cnt, flags, to, tolen);
1491*7c478bd9Sstevel@tonic-gate 		}
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate 		if (ret > 0)
1494*7c478bd9Sstevel@tonic-gate 			cnt += ret;
1495*7c478bd9Sstevel@tonic-gate 	} while ((cnt != sz) && (errno == EINTR));
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 	return ((cnt == sz) ? 0 : -1);
1498*7c478bd9Sstevel@tonic-gate }
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate int
1501*7c478bd9Sstevel@tonic-gate safe_sendto(int fd, const void *buf, size_t sz, int flags,
1502*7c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen) {
1503*7c478bd9Sstevel@tonic-gate 	return (safe_sendto_write(fd, buf, sz, flags, to, tolen));
1504*7c478bd9Sstevel@tonic-gate }
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate int
1507*7c478bd9Sstevel@tonic-gate safe_write(int fd, const void *buf, size_t sz)
1508*7c478bd9Sstevel@tonic-gate {
1509*7c478bd9Sstevel@tonic-gate 	return (safe_sendto_write(fd, buf, sz, 0, NULL, 0));
1510*7c478bd9Sstevel@tonic-gate }
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate /*
1513*7c478bd9Sstevel@tonic-gate  * Free up the memory occupied by string array 'strs'.
1514*7c478bd9Sstevel@tonic-gate  */
1515*7c478bd9Sstevel@tonic-gate void
1516*7c478bd9Sstevel@tonic-gate destroy_strings(char **strs)
1517*7c478bd9Sstevel@tonic-gate {
1518*7c478bd9Sstevel@tonic-gate 	int i = 0;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	if (strs != NULL) {
1521*7c478bd9Sstevel@tonic-gate 		while (strs[i] != NULL)
1522*7c478bd9Sstevel@tonic-gate 			free(strs[i++]);
1523*7c478bd9Sstevel@tonic-gate 		free(strs);
1524*7c478bd9Sstevel@tonic-gate 	}
1525*7c478bd9Sstevel@tonic-gate }
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate /*
1528*7c478bd9Sstevel@tonic-gate  * Parse the proto list string into an allocated array of proto strings,
1529*7c478bd9Sstevel@tonic-gate  * returning a pointer to this array. If one of the protos is too big
1530*7c478bd9Sstevel@tonic-gate  * errno is set to E2BIG and NULL is returned; if memory allocation failure
1531*7c478bd9Sstevel@tonic-gate  * occurs errno is set to ENOMEM and NULL is returned; else on success
1532*7c478bd9Sstevel@tonic-gate  * a pointer the string array is returned.
1533*7c478bd9Sstevel@tonic-gate  */
1534*7c478bd9Sstevel@tonic-gate char **
1535*7c478bd9Sstevel@tonic-gate get_protos(const char *pstr)
1536*7c478bd9Sstevel@tonic-gate {
1537*7c478bd9Sstevel@tonic-gate 	char	*cp;
1538*7c478bd9Sstevel@tonic-gate 	int	i = 0;
1539*7c478bd9Sstevel@tonic-gate 	char	**ret = NULL;
1540*7c478bd9Sstevel@tonic-gate 	size_t	max_proto_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1541*7c478bd9Sstevel@tonic-gate 	char	*str;
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	/* copy the parameter as strtok modifies its parameters */
1544*7c478bd9Sstevel@tonic-gate 	if ((str = strdup(pstr)) == NULL)
1545*7c478bd9Sstevel@tonic-gate 		goto malloc_failure;
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate 	for (cp = strtok(str, PROTO_DELIMITERS); cp != NULL;
1548*7c478bd9Sstevel@tonic-gate 	    cp = strtok(NULL, PROTO_DELIMITERS)) {
1549*7c478bd9Sstevel@tonic-gate 		char **cpp;
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 		if (strlen(cp) >= max_proto_len) {
1552*7c478bd9Sstevel@tonic-gate 			destroy_strings(ret);
1553*7c478bd9Sstevel@tonic-gate 			free(str);
1554*7c478bd9Sstevel@tonic-gate 			errno = E2BIG;
1555*7c478bd9Sstevel@tonic-gate 			return (NULL);
1556*7c478bd9Sstevel@tonic-gate 		}
1557*7c478bd9Sstevel@tonic-gate 		if ((cpp = realloc(ret, (i + 2) * sizeof (char *))) == NULL)
1558*7c478bd9Sstevel@tonic-gate 			goto malloc_failure;
1559*7c478bd9Sstevel@tonic-gate 		ret = cpp;
1560*7c478bd9Sstevel@tonic-gate 		if ((cpp[i] = strdup(cp)) == NULL)
1561*7c478bd9Sstevel@tonic-gate 			goto malloc_failure;
1562*7c478bd9Sstevel@tonic-gate 		cpp[++i] = NULL;
1563*7c478bd9Sstevel@tonic-gate 	}
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 	free(str);
1566*7c478bd9Sstevel@tonic-gate 	return (ret);
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate malloc_failure:
1569*7c478bd9Sstevel@tonic-gate 	destroy_strings(ret);
1570*7c478bd9Sstevel@tonic-gate 	free(str);
1571*7c478bd9Sstevel@tonic-gate 	errno = ENOMEM;
1572*7c478bd9Sstevel@tonic-gate 	return (NULL);
1573*7c478bd9Sstevel@tonic-gate }
1574*7c478bd9Sstevel@tonic-gate 
1575*7c478bd9Sstevel@tonic-gate /*
1576*7c478bd9Sstevel@tonic-gate  * Returns an allocated string array of netids corresponding with 'proto'. The
1577*7c478bd9Sstevel@tonic-gate  * function first tries to interpret 'proto' as a nettype to get its netids.
1578*7c478bd9Sstevel@tonic-gate  * If this fails it tries to interpret it as a netid. If 'proto' is neither
1579*7c478bd9Sstevel@tonic-gate  * a nettype or a netid or a memory allocation failures occurs NULL is
1580*7c478bd9Sstevel@tonic-gate  * returned, else a pointer to an array of netids associated with 'proto' is
1581*7c478bd9Sstevel@tonic-gate  * returned.
1582*7c478bd9Sstevel@tonic-gate  */
1583*7c478bd9Sstevel@tonic-gate char **
1584*7c478bd9Sstevel@tonic-gate get_netids(char *proto)
1585*7c478bd9Sstevel@tonic-gate {
1586*7c478bd9Sstevel@tonic-gate 	void			*handle;
1587*7c478bd9Sstevel@tonic-gate 	struct netconfig	*nconf;
1588*7c478bd9Sstevel@tonic-gate 	char			**netids = NULL;
1589*7c478bd9Sstevel@tonic-gate 	char			**cpp;
1590*7c478bd9Sstevel@tonic-gate 	int			i = 0;
1591*7c478bd9Sstevel@tonic-gate 
1592*7c478bd9Sstevel@tonic-gate 	if (strcmp(proto, "*") == 0)
1593*7c478bd9Sstevel@tonic-gate 		proto = "visible";
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate 	if ((handle = __rpc_setconf(proto)) != NULL) {
1596*7c478bd9Sstevel@tonic-gate 		/* expand nettype */
1597*7c478bd9Sstevel@tonic-gate 		while ((nconf = __rpc_getconf(handle)) != NULL) {
1598*7c478bd9Sstevel@tonic-gate 			if ((cpp = realloc(netids,
1599*7c478bd9Sstevel@tonic-gate 			    (i + 2) * sizeof (char *))) == NULL)
1600*7c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
1601*7c478bd9Sstevel@tonic-gate 			netids = cpp;
1602*7c478bd9Sstevel@tonic-gate 			if ((cpp[i] = strdup(nconf->nc_netid)) == NULL)
1603*7c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
1604*7c478bd9Sstevel@tonic-gate 			cpp[++i] = NULL;
1605*7c478bd9Sstevel@tonic-gate 		}
1606*7c478bd9Sstevel@tonic-gate 		__rpc_endconf(handle);
1607*7c478bd9Sstevel@tonic-gate 	} else {
1608*7c478bd9Sstevel@tonic-gate 		if ((netids = malloc(2 * sizeof (char *))) == NULL)
1609*7c478bd9Sstevel@tonic-gate 			return (NULL);
1610*7c478bd9Sstevel@tonic-gate 		if ((netids[0] = strdup(proto)) == NULL) {
1611*7c478bd9Sstevel@tonic-gate 			free(netids);
1612*7c478bd9Sstevel@tonic-gate 			return (NULL);
1613*7c478bd9Sstevel@tonic-gate 		}
1614*7c478bd9Sstevel@tonic-gate 		netids[1] = NULL;
1615*7c478bd9Sstevel@tonic-gate 	}
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate 	return (netids);
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate failure_cleanup:
1620*7c478bd9Sstevel@tonic-gate 	destroy_strings(netids);
1621*7c478bd9Sstevel@tonic-gate 	__rpc_endconf(handle);
1622*7c478bd9Sstevel@tonic-gate 	return (NULL);
1623*7c478bd9Sstevel@tonic-gate }
1624