xref: /titanic_51/usr/src/lib/libinetsvc/common/inetsvc.c (revision e23de8e200dff2773d80ce69c9f2e745b544b9b1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
586b1a8baSrotondo  * Common Development and Distribution License (the "License").
686b1a8baSrotondo  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*e23de8e2SGary Mills  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This library contains a set of routines that are shared amongst inetd,
287c478bd9Sstevel@tonic-gate  * inetadm, inetconv and the formerly internal inetd services. Amongst the
297c478bd9Sstevel@tonic-gate  * routines are ones for reading and validating the configuration of an
307c478bd9Sstevel@tonic-gate  * inetd service, a routine for requesting inetd be refreshed, ones for
317c478bd9Sstevel@tonic-gate  * reading, calculating and writing the hash of an inetd.conf file, and
327c478bd9Sstevel@tonic-gate  * numerous utility routines shared amongst the formerly internal inetd
337c478bd9Sstevel@tonic-gate  * services.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
397c478bd9Sstevel@tonic-gate #include <netdb.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <inetsvc.h>
437c478bd9Sstevel@tonic-gate #include <stdlib.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
467c478bd9Sstevel@tonic-gate #include <stdio.h>
477c478bd9Sstevel@tonic-gate #include <fcntl.h>
487c478bd9Sstevel@tonic-gate #include <pwd.h>
497c478bd9Sstevel@tonic-gate #include <md5.h>
507c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
517c478bd9Sstevel@tonic-gate #include <netinet/in.h>
527c478bd9Sstevel@tonic-gate #include <signal.h>
537c478bd9Sstevel@tonic-gate #include <syslog.h>
547c478bd9Sstevel@tonic-gate #include <libintl.h>
557c478bd9Sstevel@tonic-gate #include <stdlib.h>
567c478bd9Sstevel@tonic-gate #include <assert.h>
577c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
587c478bd9Sstevel@tonic-gate #include <libuutil.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static inetd_prop_t inetd_properties[] = {
61ba1637f8Smh138676 	{PR_SVC_NAME_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING,
627c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
63ba1637f8Smh138676 	{PR_SOCK_TYPE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING,
647c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
65ba1637f8Smh138676 	{PR_PROTO_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING_LIST,
667c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
67ba1637f8Smh138676 	{PR_ISRPC_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
687c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
69ba1637f8Smh138676 	{PR_RPC_LW_VER_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
707c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
71ba1637f8Smh138676 	{PR_RPC_HI_VER_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
727c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
73ba1637f8Smh138676 	{PR_ISWAIT_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
747c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
75ba1637f8Smh138676 	{PR_EXEC_NAME, START_METHOD_NAME, INET_TYPE_STRING,
767c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
77ba1637f8Smh138676 	{PR_ARG0_NAME, START_METHOD_NAME, INET_TYPE_STRING,
787c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
79ba1637f8Smh138676 	{PR_USER_NAME, START_METHOD_NAME, INET_TYPE_STRING,
807c478bd9Sstevel@tonic-gate 	    B_FALSE, IVE_UNSET, NULL, B_FALSE},
81ba1637f8Smh138676 	{PR_BIND_ADDR_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING,
827c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
83ba1637f8Smh138676 	{PR_BIND_FAIL_MAX_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
847c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
85ba1637f8Smh138676 	{PR_BIND_FAIL_INTVL_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
867c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
87ba1637f8Smh138676 	{PR_CON_RATE_MAX_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
887c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
89ba1637f8Smh138676 	{PR_MAX_COPIES_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
907c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
91ba1637f8Smh138676 	{PR_CON_RATE_OFFLINE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
927c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
93ba1637f8Smh138676 	{PR_MAX_FAIL_RATE_CNT_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
947c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
95ba1637f8Smh138676 	{PR_MAX_FAIL_RATE_INTVL_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
967c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
97ba1637f8Smh138676 	{PR_INHERIT_ENV_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
987c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
99ba1637f8Smh138676 	{PR_DO_TCP_TRACE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
1007c478bd9Sstevel@tonic-gate 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
101ba1637f8Smh138676 	{PR_DO_TCP_WRAPPERS_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
102ba1637f8Smh138676 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
103fff9db26Svp157776 	{PR_CONNECTION_BACKLOG_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
104fff9db26Svp157776 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
105*e23de8e2SGary Mills 	{PR_DO_TCP_KEEPALIVE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN,
106*e23de8e2SGary Mills 	    B_TRUE, IVE_UNSET, NULL, B_FALSE},
107ba1637f8Smh138676 	{NULL},
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #define	INETSVC_SVC_BUF_MAX (NSS_BUFLEN_RPC + sizeof (struct rpcent))
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #define	DIGEST_LEN	16
1137c478bd9Sstevel@tonic-gate #define	READ_BUFSIZ	8192
1147c478bd9Sstevel@tonic-gate #define	HASH_PG		"hash"
1157c478bd9Sstevel@tonic-gate #define	HASH_PROP	"md5sum"
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * Inactivity timer used by dg_template(). After this many seconds of network
1197c478bd9Sstevel@tonic-gate  * inactivity dg_template will cease listening for new datagrams and return.
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate #define	DG_INACTIVITY_TIMEOUT	60
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static boolean_t v6_proto(const char *);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate boolean_t
1267c478bd9Sstevel@tonic-gate is_tlx_service(inetd_prop_t *props)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	return ((strcmp(SOCKTYPE_TLI_STR,
129ba1637f8Smh138676 	    props[PT_SOCK_TYPE_INDEX].ip_value.iv_string) == 0) ||
1307c478bd9Sstevel@tonic-gate 	    (strcmp(SOCKTYPE_XTI_STR,
131ba1637f8Smh138676 	    props[PT_SOCK_TYPE_INDEX].ip_value.iv_string) == 0));
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * Return a reference to the property table. Number of entries in table
1367c478bd9Sstevel@tonic-gate  * are returned in num_elements argument.
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate inetd_prop_t *
1397c478bd9Sstevel@tonic-gate get_prop_table(size_t *num_elements)
1407c478bd9Sstevel@tonic-gate {
141ba1637f8Smh138676 	*num_elements = sizeof (inetd_properties) / sizeof (inetd_prop_t);
1427c478bd9Sstevel@tonic-gate 	return (&inetd_properties[0]);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
146ba1637f8Smh138676  * find_prop takes an array of inetd_prop_t's, the name of an inetd
147ba1637f8Smh138676  * property, the type expected, and returns a pointer to the matching member,
148ba1637f8Smh138676  * or NULL.
1497c478bd9Sstevel@tonic-gate  */
150ba1637f8Smh138676 inetd_prop_t *
151ba1637f8Smh138676 find_prop(const inetd_prop_t *prop, const char *name, inet_type_t type)
1527c478bd9Sstevel@tonic-gate {
153ba1637f8Smh138676 	int		i = 0;
1547c478bd9Sstevel@tonic-gate 
155ba1637f8Smh138676 	while (prop[i].ip_name != NULL && strcmp(name, prop[i].ip_name) != 0)
156ba1637f8Smh138676 		i++;
1577c478bd9Sstevel@tonic-gate 
158ba1637f8Smh138676 	if (prop[i].ip_name == NULL)
1597c478bd9Sstevel@tonic-gate 		return (NULL);
160ba1637f8Smh138676 
161ba1637f8Smh138676 	if (prop[i].ip_type != type)
162ba1637f8Smh138676 		return (NULL);
163ba1637f8Smh138676 
164ba1637f8Smh138676 	return ((inetd_prop_t *)prop + i);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
168ba1637f8Smh138676  * get_prop_value_int takes an array of inetd_prop_t's together with the name of
169ba1637f8Smh138676  * an inetd property and returns the value of the property.  It's expected that
170ba1637f8Smh138676  * the property exists in the searched array.
1717c478bd9Sstevel@tonic-gate  */
172ba1637f8Smh138676 int64_t
173ba1637f8Smh138676 get_prop_value_int(const inetd_prop_t *prop, const char *name)
1747c478bd9Sstevel@tonic-gate {
175ba1637f8Smh138676 	inetd_prop_t	*p;
1767c478bd9Sstevel@tonic-gate 
177ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_INTEGER);
178ba1637f8Smh138676 	return (p->ip_value.iv_int);
179ba1637f8Smh138676 }
180ba1637f8Smh138676 
181ba1637f8Smh138676 /*
182ba1637f8Smh138676  * get_prop_value_count takes an array of inetd_prop_t's together with the name
183ba1637f8Smh138676  * of an inetd property and returns the value of the property.  It's expected
184ba1637f8Smh138676  * that the property exists in the searched array.
185ba1637f8Smh138676  */
186ba1637f8Smh138676 uint64_t
187ba1637f8Smh138676 get_prop_value_count(const inetd_prop_t *prop, const char *name)
188ba1637f8Smh138676 {
189ba1637f8Smh138676 	inetd_prop_t	*p;
190ba1637f8Smh138676 
191ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_COUNT);
192ba1637f8Smh138676 	return (p->ip_value.iv_cnt);
193ba1637f8Smh138676 }
194ba1637f8Smh138676 
195ba1637f8Smh138676 /*
196ba1637f8Smh138676  * get_prop_value_boolean takes an array of inetd_prop_t's together with the
197ba1637f8Smh138676  * name of an inetd property and returns the value of the property.  It's
198ba1637f8Smh138676  * expected that the property exists in the searched array.
199ba1637f8Smh138676  */
200ba1637f8Smh138676 boolean_t
201ba1637f8Smh138676 get_prop_value_boolean(const inetd_prop_t *prop, const char *name)
202ba1637f8Smh138676 {
203ba1637f8Smh138676 	inetd_prop_t	*p;
204ba1637f8Smh138676 
205ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_BOOLEAN);
206ba1637f8Smh138676 	return (p->ip_value.iv_boolean);
207ba1637f8Smh138676 }
208ba1637f8Smh138676 
209ba1637f8Smh138676 /*
210ba1637f8Smh138676  * get_prop_value_string takes an array of inetd_prop_t's together with
211ba1637f8Smh138676  * the name of an inetd property and returns the value of the property.
212ba1637f8Smh138676  * It's expected that the property exists in the searched array.
213ba1637f8Smh138676  */
214ba1637f8Smh138676 const char *
215ba1637f8Smh138676 get_prop_value_string(const inetd_prop_t *prop, const char *name)
216ba1637f8Smh138676 {
217ba1637f8Smh138676 	inetd_prop_t	*p;
218ba1637f8Smh138676 
219ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_STRING);
220ba1637f8Smh138676 	return (p->ip_value.iv_string);
221ba1637f8Smh138676 }
222ba1637f8Smh138676 
223ba1637f8Smh138676 /*
224ba1637f8Smh138676  * get_prop_value_string_list takes an array of inetd_prop_t's together
225ba1637f8Smh138676  * with the name of an inetd property and returns the value of the property.
226ba1637f8Smh138676  * It's expected that the property exists in the searched array.
227ba1637f8Smh138676  */
228ba1637f8Smh138676 const char **
229ba1637f8Smh138676 get_prop_value_string_list(const inetd_prop_t *prop, const char *name)
230ba1637f8Smh138676 {
231ba1637f8Smh138676 	inetd_prop_t	*p;
232ba1637f8Smh138676 
233ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_STRING_LIST);
234ba1637f8Smh138676 	return ((const char **)p->ip_value.iv_string_list);
235ba1637f8Smh138676 }
236ba1637f8Smh138676 
237ba1637f8Smh138676 /*
238ba1637f8Smh138676  * put_prop_value_int takes an array of inetd_prop_t's, a name of an inetd
239ba1637f8Smh138676  * property, and a value.  It copies the value into the property
240ba1637f8Smh138676  * in the array.  It's expected that the property exists in the searched array.
241ba1637f8Smh138676  */
242ba1637f8Smh138676 void
243ba1637f8Smh138676 put_prop_value_int(inetd_prop_t *prop, const char *name, int64_t value)
244ba1637f8Smh138676 {
245ba1637f8Smh138676 	inetd_prop_t	*p;
246ba1637f8Smh138676 
247ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_INTEGER);
248ba1637f8Smh138676 	p->ip_value.iv_int = value;
249ba1637f8Smh138676 	p->ip_error = IVE_VALID;
250ba1637f8Smh138676 }
251ba1637f8Smh138676 
252ba1637f8Smh138676 /*
253ba1637f8Smh138676  * put_prop_value_count takes an array of inetd_prop_t's, a name of an inetd
254ba1637f8Smh138676  * property, and a value.  It copies the value into the property
255ba1637f8Smh138676  * in the array.  It's expected that the property exists in the searched array.
256ba1637f8Smh138676  */
257ba1637f8Smh138676 void
258ba1637f8Smh138676 put_prop_value_count(inetd_prop_t *prop, const char *name, uint64_t value)
259ba1637f8Smh138676 {
260ba1637f8Smh138676 	inetd_prop_t	*p;
261ba1637f8Smh138676 
262ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_COUNT);
263ba1637f8Smh138676 	p->ip_value.iv_cnt = value;
264ba1637f8Smh138676 	p->ip_error = IVE_VALID;
265ba1637f8Smh138676 }
266ba1637f8Smh138676 
267ba1637f8Smh138676 /*
268ba1637f8Smh138676  * put_prop_value_boolean takes an array of inetd_prop_t's, a name of an inetd
269ba1637f8Smh138676  * property, and a value.  It copies the value into the property
270ba1637f8Smh138676  * in the array.  It's expected that the property exists in the searched array.
271ba1637f8Smh138676  */
272ba1637f8Smh138676 void
273ba1637f8Smh138676 put_prop_value_boolean(inetd_prop_t *prop, const char *name, boolean_t value)
274ba1637f8Smh138676 {
275ba1637f8Smh138676 	inetd_prop_t	*p;
276ba1637f8Smh138676 
277ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_BOOLEAN);
278ba1637f8Smh138676 	p->ip_value.iv_boolean = value;
279ba1637f8Smh138676 	p->ip_error = IVE_VALID;
280ba1637f8Smh138676 }
281ba1637f8Smh138676 
282ba1637f8Smh138676 /*
283ba1637f8Smh138676  * put_prop_value_string takes an array of inetd_prop_t's, a name of an inetd
284ba1637f8Smh138676  * property, and a value.  It duplicates the value into the property
285ba1637f8Smh138676  * in the array, and returns B_TRUE for success and B_FALSE for failure.  It's
286ba1637f8Smh138676  * expected that the property exists in the searched array.
287ba1637f8Smh138676  */
288ba1637f8Smh138676 boolean_t
289ba1637f8Smh138676 put_prop_value_string(inetd_prop_t *prop, const char *name, const char *value)
290ba1637f8Smh138676 {
291ba1637f8Smh138676 	inetd_prop_t	*p;
292ba1637f8Smh138676 
293ba1637f8Smh138676 	if (strlen(value) >= scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) {
2947c478bd9Sstevel@tonic-gate 		errno = E2BIG;
295ba1637f8Smh138676 		return (B_FALSE);
2967c478bd9Sstevel@tonic-gate 	}
297ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_STRING);
298ba1637f8Smh138676 	if ((p->ip_value.iv_string = strdup(value)) == NULL)
299ba1637f8Smh138676 		return (B_FALSE);
300ba1637f8Smh138676 	p->ip_error = IVE_VALID;
301ba1637f8Smh138676 	return (B_TRUE);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
304ba1637f8Smh138676 /*
305ba1637f8Smh138676  * put_prop_value_string_list takes an array of inetd_prop_t's, a name of an
306ba1637f8Smh138676  * inetd property, and a value.  It copies the value into the property
307ba1637f8Smh138676  * in the array.  It's expected that the property exists in the searched array.
308ba1637f8Smh138676  */
309ba1637f8Smh138676 void
310ba1637f8Smh138676 put_prop_value_string_list(inetd_prop_t *prop, const char *name, char **value)
311ba1637f8Smh138676 {
312ba1637f8Smh138676 	inetd_prop_t	*p;
313ba1637f8Smh138676 
314ba1637f8Smh138676 	p = find_prop(prop, name, INET_TYPE_STRING_LIST);
315ba1637f8Smh138676 	p->ip_value.iv_string_list = value;
316ba1637f8Smh138676 	p->ip_error = IVE_VALID;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static void
3207c478bd9Sstevel@tonic-gate destroy_rpc_info(rpc_info_t *rpc)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	if (rpc != NULL) {
3237c478bd9Sstevel@tonic-gate 		free(rpc->netbuf.buf);
3247c478bd9Sstevel@tonic-gate 		free(rpc->netid);
3257c478bd9Sstevel@tonic-gate 		free(rpc);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * If 'proto' is a valid netid,  and no memory allocations fail, returns a
3317c478bd9Sstevel@tonic-gate  * pointer to an allocated and initialized rpc_info_t, else NULL.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate static rpc_info_t *
3347c478bd9Sstevel@tonic-gate create_rpc_info(const char *proto, int pnum, int low_ver, int high_ver)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	struct netconfig	*nconf;
3377c478bd9Sstevel@tonic-gate 	rpc_info_t		*ret;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ((ret = calloc(1, sizeof (rpc_info_t))) == NULL)
3407c478bd9Sstevel@tonic-gate 		return (NULL);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	ret->netbuf.maxlen = sizeof (struct sockaddr_storage);
3437c478bd9Sstevel@tonic-gate 	if ((ret->netbuf.buf = malloc(ret->netbuf.maxlen)) == NULL) {
3447c478bd9Sstevel@tonic-gate 		free(ret);
3457c478bd9Sstevel@tonic-gate 		return (NULL);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	ret->prognum = pnum;
3497c478bd9Sstevel@tonic-gate 	ret->lowver = low_ver;
3507c478bd9Sstevel@tonic-gate 	ret->highver = high_ver;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	if ((ret->netid = strdup(proto)) == NULL) {
3537c478bd9Sstevel@tonic-gate 		destroy_rpc_info(ret);
3547c478bd9Sstevel@tonic-gate 		return (NULL);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * Determine whether this is a loopback transport. If getnetconfigent()
3597c478bd9Sstevel@tonic-gate 	 * fails, we check to see whether it was the result of a v6 proto
3607c478bd9Sstevel@tonic-gate 	 * being specified and no IPv6 interface was configured on the system;
3617c478bd9Sstevel@tonic-gate 	 * if this holds, we know it must not be a loopback transport, else
3627c478bd9Sstevel@tonic-gate 	 * getnetconfigent() must be miss-behaving, so return an error.
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 	if ((nconf = getnetconfigent(proto)) != NULL) {
3657c478bd9Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
3667c478bd9Sstevel@tonic-gate 			ret->is_loopback = B_TRUE;
3677c478bd9Sstevel@tonic-gate 		freenetconfigent(nconf);
3687c478bd9Sstevel@tonic-gate 	} else if (!v6_proto(proto)) {
3697c478bd9Sstevel@tonic-gate 		destroy_rpc_info(ret);
3707c478bd9Sstevel@tonic-gate 		return (NULL);
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	return (ret);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate void
3777c478bd9Sstevel@tonic-gate destroy_tlx_info(tlx_info_t *tlx)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	tlx_conn_ind_t  *ci;
3807c478bd9Sstevel@tonic-gate 	void		*cookie = NULL;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (tlx == NULL)
3837c478bd9Sstevel@tonic-gate 		return;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	free(tlx->dev_name);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (tlx->conn_ind_queue != NULL) {
3887c478bd9Sstevel@tonic-gate 		/* free up conn ind queue */
3897c478bd9Sstevel@tonic-gate 		while ((ci = uu_list_teardown(tlx->conn_ind_queue, &cookie)) !=
3907c478bd9Sstevel@tonic-gate 		    NULL) {
3917c478bd9Sstevel@tonic-gate 			(void) t_free((char *)ci->call, T_CALL);
3927c478bd9Sstevel@tonic-gate 			free(ci);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 		uu_list_destroy(tlx->conn_ind_queue);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	free(tlx->local_addr.buf);
3987c478bd9Sstevel@tonic-gate 	free(tlx);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * Allocate, initialize and return a pointer to a tlx_info_t structure.
4037c478bd9Sstevel@tonic-gate  * On memory allocation failure NULL is returned.
4047c478bd9Sstevel@tonic-gate  */
4057c478bd9Sstevel@tonic-gate static tlx_info_t *
4067c478bd9Sstevel@tonic-gate create_tlx_info(const char *proto, uu_list_pool_t *conn_ind_pool)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	size_t			sz;
4097c478bd9Sstevel@tonic-gate 	tlx_info_t		*ret;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if ((ret = calloc(1, sizeof (tlx_info_t))) == NULL)
4127c478bd9Sstevel@tonic-gate 		return (NULL);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	ret->local_addr.maxlen = sizeof (struct sockaddr_storage);
4157c478bd9Sstevel@tonic-gate 	if ((ret->local_addr.buf = calloc(1, ret->local_addr.maxlen)) == NULL)
4167c478bd9Sstevel@tonic-gate 		goto fail;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if ((ret->conn_ind_queue = uu_list_create(conn_ind_pool, NULL, 0)) ==
4197c478bd9Sstevel@tonic-gate 	    NULL)
4207c478bd9Sstevel@tonic-gate 		goto fail;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	ret->local_addr.len = sizeof (struct sockaddr_in);
4237c478bd9Sstevel@tonic-gate 	/* LINTED E_BAD_PTR_CAST_ALIGN */
4247c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)(ret->local_addr.buf))->sin_family = AF_INET;
4257c478bd9Sstevel@tonic-gate 	/* LINTED E_BAD_PTR_CAST_ALIGN */
4267c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)(ret->local_addr.buf))->sin_addr.s_addr =
4277c478bd9Sstevel@tonic-gate 	    htonl(INADDR_ANY);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/* store device name, constructing if necessary */
4307c478bd9Sstevel@tonic-gate 	if (proto[0] != '/') {
4317c478bd9Sstevel@tonic-gate 		sz = strlen("/dev/") + strlen(proto) + 1;
4327c478bd9Sstevel@tonic-gate 		if ((ret->dev_name = malloc(sz)) == NULL)
4337c478bd9Sstevel@tonic-gate 			goto fail;
4347c478bd9Sstevel@tonic-gate 		(void) snprintf(ret->dev_name, sz, "/dev/%s", proto);
4357c478bd9Sstevel@tonic-gate 	} else if ((ret->dev_name = strdup(proto)) == NULL) {
4367c478bd9Sstevel@tonic-gate 			goto fail;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	return (ret);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate fail:
4427c478bd9Sstevel@tonic-gate 	destroy_tlx_info(ret);
4437c478bd9Sstevel@tonic-gate 	return (NULL);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Returns B_TRUE if this is a v6 protocol valid for both TLI and socket
4487c478bd9Sstevel@tonic-gate  * based services, else B_FALSE.
4497c478bd9Sstevel@tonic-gate  */
4507c478bd9Sstevel@tonic-gate static boolean_t
4517c478bd9Sstevel@tonic-gate v6_proto(const char *proto)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	return ((strcmp(proto, SOCKET_PROTO_TCP6) == 0) ||
4547c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_UDP6) == 0));
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * Returns B_TRUE if this is a valid v6 protocol for a socket based service,
4597c478bd9Sstevel@tonic-gate  * else B_FALSE.
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate static boolean_t
4627c478bd9Sstevel@tonic-gate v6_socket_proto(const char *proto)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	return ((strcmp(proto, SOCKET_PROTO_SCTP6) == 0) ||
4657c478bd9Sstevel@tonic-gate 	    v6_proto(proto));
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate static boolean_t
4707c478bd9Sstevel@tonic-gate valid_socket_proto(const char *proto)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	return (v6_socket_proto(proto) ||
4737c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_SCTP) == 0) ||
4747c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_TCP) == 0) ||
4757c478bd9Sstevel@tonic-gate 	    (strcmp(proto, SOCKET_PROTO_UDP) == 0));
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * Free all the memory consumed by 'pi' associated with the instance
4807c478bd9Sstevel@tonic-gate  * with configuration 'cfg'.
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate static void
4837c478bd9Sstevel@tonic-gate destroy_proto_info(basic_cfg_t *cfg, proto_info_t *pi)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	if (pi == NULL)
4867c478bd9Sstevel@tonic-gate 		return;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	assert(pi->listen_fd == -1);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	free(pi->proto);
4917c478bd9Sstevel@tonic-gate 	if (pi->ri != NULL)
4927c478bd9Sstevel@tonic-gate 		destroy_rpc_info(pi->ri);
4937c478bd9Sstevel@tonic-gate 	if (cfg->istlx) {
4947c478bd9Sstevel@tonic-gate 		destroy_tlx_info((tlx_info_t *)pi);
4957c478bd9Sstevel@tonic-gate 	} else {
4967c478bd9Sstevel@tonic-gate 		free(pi);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate void
5017c478bd9Sstevel@tonic-gate destroy_proto_list(basic_cfg_t *cfg)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	void		*cookie = NULL;
5047c478bd9Sstevel@tonic-gate 	proto_info_t	*pi;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	if (cfg->proto_list == NULL)
5077c478bd9Sstevel@tonic-gate 		return;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	while ((pi = uu_list_teardown(cfg->proto_list, &cookie)) != NULL)
5107c478bd9Sstevel@tonic-gate 		destroy_proto_info(cfg, pi);
5117c478bd9Sstevel@tonic-gate 	uu_list_destroy(cfg->proto_list);
5127c478bd9Sstevel@tonic-gate 	cfg->proto_list = NULL;
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate void
5167c478bd9Sstevel@tonic-gate destroy_basic_cfg(basic_cfg_t *cfg)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	if (cfg == NULL)
5197c478bd9Sstevel@tonic-gate 		return;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	free(cfg->bind_addr);
5227c478bd9Sstevel@tonic-gate 	destroy_proto_list(cfg);
5237c478bd9Sstevel@tonic-gate 	free(cfg->svc_name);
5247c478bd9Sstevel@tonic-gate 	free(cfg);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /*
52886b1a8baSrotondo  * Overwrite the socket address with the address specified by the
52986b1a8baSrotondo  * bind_addr property.
53086b1a8baSrotondo  */
53186b1a8baSrotondo static int
53286b1a8baSrotondo set_bind_addr(struct sockaddr_storage *ss, char *bind_addr)
53386b1a8baSrotondo {
53486b1a8baSrotondo 	struct addrinfo hints, *res;
53586b1a8baSrotondo 
53686b1a8baSrotondo 	if (bind_addr == NULL || bind_addr[0] == '\0')
53786b1a8baSrotondo 		return (0);
53886b1a8baSrotondo 
53986b1a8baSrotondo 	(void) memset(&hints, 0, sizeof (hints));
54086b1a8baSrotondo 	hints.ai_flags = AI_DEFAULT;
54186b1a8baSrotondo 	hints.ai_socktype = SOCK_STREAM;
54286b1a8baSrotondo 	hints.ai_family = ss->ss_family;
54386b1a8baSrotondo 	if (getaddrinfo(bind_addr, "", &hints, &res) != 0) {
54486b1a8baSrotondo 		return (-1);
54586b1a8baSrotondo 	} else {
54686b1a8baSrotondo 		void *p = res->ai_addr;
54786b1a8baSrotondo 		struct sockaddr_storage *newss = p;
54886b1a8baSrotondo 
54986b1a8baSrotondo 		(void) memcpy(SS_SINADDR(*ss), SS_SINADDR(*newss),
55086b1a8baSrotondo 		    SS_ADDRLEN(*ss));
55186b1a8baSrotondo 		freeaddrinfo(res);
55286b1a8baSrotondo 		return (0);
55386b1a8baSrotondo 	}
55486b1a8baSrotondo }
55586b1a8baSrotondo 
55686b1a8baSrotondo /*
5577c478bd9Sstevel@tonic-gate  * valid_props validates all the properties in an array of inetd_prop_t's,
5587c478bd9Sstevel@tonic-gate  * marking each property as valid or invalid.  If any properties are invalid,
5597c478bd9Sstevel@tonic-gate  * it returns B_FALSE, otherwise it returns B_TRUE.  Note that some properties
5607c478bd9Sstevel@tonic-gate  * are interdependent, so if one is invalid, it leaves others in an
5617c478bd9Sstevel@tonic-gate  * indeterminate state (such as ISRPC and SVC_NAME).  In this case, the
5627c478bd9Sstevel@tonic-gate  * indeterminate property will be marked valid.  IE, the only properties
5637c478bd9Sstevel@tonic-gate  * marked invalid are those that are KNOWN to be invalid.
5647c478bd9Sstevel@tonic-gate  *
5657c478bd9Sstevel@tonic-gate  * Piggy-backed onto this validation if 'fmri' is non-NULL is the construction
5667c478bd9Sstevel@tonic-gate  * of a structured configuration, a basic_cfg_t,  which is used by inetd.
5677c478bd9Sstevel@tonic-gate  * If 'fmri' is set then the latter three parameters need to be set to
5687c478bd9Sstevel@tonic-gate  * non-NULL values, and if the configuration is valid, the storage referenced
5697c478bd9Sstevel@tonic-gate  * by cfgpp is set to point at an initialized basic_cfg_t.
5707c478bd9Sstevel@tonic-gate  */
5717c478bd9Sstevel@tonic-gate boolean_t
5727c478bd9Sstevel@tonic-gate valid_props(inetd_prop_t *prop, const char *fmri, basic_cfg_t **cfgpp,
5737c478bd9Sstevel@tonic-gate     uu_list_pool_t *proto_info_pool, uu_list_pool_t *tlx_ci_pool)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	char			*bufp, *cp;
5767c478bd9Sstevel@tonic-gate 	boolean_t		ret = B_TRUE;
5777c478bd9Sstevel@tonic-gate 	int			i;
5787c478bd9Sstevel@tonic-gate 	long			uidl;
5797c478bd9Sstevel@tonic-gate 	boolean_t		isrpc;
5807c478bd9Sstevel@tonic-gate 	int			sock_type_id;
5817c478bd9Sstevel@tonic-gate 	int			rpc_pnum;
5827c478bd9Sstevel@tonic-gate 	int			rpc_lv, rpc_hv;
5837c478bd9Sstevel@tonic-gate 	basic_cfg_t		*cfg;
5847c478bd9Sstevel@tonic-gate 	char			*proto = NULL;
5857c478bd9Sstevel@tonic-gate 	int			pi;
5867c478bd9Sstevel@tonic-gate 	char			**netids = NULL;
5877c478bd9Sstevel@tonic-gate 	int			ni = 0;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	if (fmri != NULL)
5907c478bd9Sstevel@tonic-gate 		assert((cfgpp != NULL) && (proto_info_pool != NULL) &&
5917c478bd9Sstevel@tonic-gate 		    (tlx_ci_pool != NULL));
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/*
5947c478bd9Sstevel@tonic-gate 	 * Set all checkable properties to valid as a baseline.  We'll be
5957c478bd9Sstevel@tonic-gate 	 * marking all invalid properties.
5967c478bd9Sstevel@tonic-gate 	 */
597ba1637f8Smh138676 	for (i = 0; prop[i].ip_name != NULL; i++) {
5987c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error != IVE_UNSET)
5997c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_VALID;
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	if (((cfg = calloc(1, sizeof (basic_cfg_t))) == NULL) ||
6037c478bd9Sstevel@tonic-gate 	    ((fmri != NULL) &&
6047c478bd9Sstevel@tonic-gate 	    ((cfg->proto_list = uu_list_create(proto_info_pool, NULL, 0)) ==
6057c478bd9Sstevel@tonic-gate 	    NULL))) {
6067c478bd9Sstevel@tonic-gate 		free(cfg);
6077c478bd9Sstevel@tonic-gate 		return (B_FALSE);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	/* Check a service name was supplied */
6117c478bd9Sstevel@tonic-gate 	if ((prop[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) ||
6127c478bd9Sstevel@tonic-gate 	    ((cfg->svc_name =
613ba1637f8Smh138676 	    strdup(prop[PT_SVC_NAME_INDEX].ip_value.iv_string)) == NULL))
6147c478bd9Sstevel@tonic-gate 		prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/* Check that iswait and isrpc have valid boolean values */
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_UNSET) ||
6197c478bd9Sstevel@tonic-gate 	    (((cfg->iswait = prop[PT_ISWAIT_INDEX].ip_value.iv_boolean) !=
6207c478bd9Sstevel@tonic-gate 	    B_TRUE) && (cfg->iswait != B_FALSE)))
6217c478bd9Sstevel@tonic-gate 		prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	if ((prop[PT_ISRPC_INDEX].ip_error == IVE_UNSET) ||
6247c478bd9Sstevel@tonic-gate 	    (((isrpc = prop[PT_ISRPC_INDEX].ip_value.iv_boolean) != B_TRUE) &&
6257c478bd9Sstevel@tonic-gate 	    (isrpc != B_FALSE))) {
6267c478bd9Sstevel@tonic-gate 		prop[PT_ISRPC_INDEX].ip_error = IVE_INVALID;
6277c478bd9Sstevel@tonic-gate 	} else if (isrpc) {
6287c478bd9Sstevel@tonic-gate 		/*
6297c478bd9Sstevel@tonic-gate 		 * This is an RPC service, so ensure that the RPC version
6307c478bd9Sstevel@tonic-gate 		 * numbers are zero or greater, that the low version isn't
6317c478bd9Sstevel@tonic-gate 		 * greater than the high version and a valid program name
6327c478bd9Sstevel@tonic-gate 		 * is supplied.
6337c478bd9Sstevel@tonic-gate 		 */
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_LW_VER_INDEX].ip_error == IVE_UNSET) ||
6367c478bd9Sstevel@tonic-gate 		    ((rpc_lv = prop[PT_RPC_LW_VER_INDEX].ip_value.iv_int) <
6377c478bd9Sstevel@tonic-gate 		    0))
6387c478bd9Sstevel@tonic-gate 			prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_HI_VER_INDEX].ip_error == IVE_UNSET) ||
6417c478bd9Sstevel@tonic-gate 		    ((rpc_hv = prop[PT_RPC_HI_VER_INDEX].ip_value.iv_int) <
6427c478bd9Sstevel@tonic-gate 		    0))
6437c478bd9Sstevel@tonic-gate 			prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		if ((prop[PT_RPC_LW_VER_INDEX].ip_error != IVE_INVALID) &&
6467c478bd9Sstevel@tonic-gate 		    (prop[PT_RPC_HI_VER_INDEX].ip_error != IVE_INVALID) &&
6477c478bd9Sstevel@tonic-gate 		    (rpc_lv > rpc_hv)) {
6487c478bd9Sstevel@tonic-gate 			prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID;
6497c478bd9Sstevel@tonic-gate 			prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID;
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		if ((cfg->svc_name != NULL) &&
6537c478bd9Sstevel@tonic-gate 		    ((rpc_pnum = get_rpc_prognum(cfg->svc_name)) == -1))
6547c478bd9Sstevel@tonic-gate 			prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/* Check that the socket type is one of the acceptable values. */
6587c478bd9Sstevel@tonic-gate 	cfg->istlx = B_FALSE;
6597c478bd9Sstevel@tonic-gate 	if ((prop[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET) ||
6607c478bd9Sstevel@tonic-gate 	    ((sock_type_id = get_sock_type_id(
661ba1637f8Smh138676 	    prop[PT_SOCK_TYPE_INDEX].ip_value.iv_string)) == -1) &&
6627c478bd9Sstevel@tonic-gate 	    !(cfg->istlx = is_tlx_service(prop)))
6637c478bd9Sstevel@tonic-gate 		prop[PT_SOCK_TYPE_INDEX].ip_error = IVE_INVALID;
6647c478bd9Sstevel@tonic-gate 
66586b1a8baSrotondo 	/* Get the bind address */
666f60ea415Srotondo 	if (!cfg->istlx && prop[PT_BIND_ADDR_INDEX].ip_error != IVE_UNSET &&
667f60ea415Srotondo 	    (cfg->bind_addr =
668f60ea415Srotondo 	    strdup(prop[PT_BIND_ADDR_INDEX].ip_value.iv_string)) == NULL)
66986b1a8baSrotondo 		prop[PT_BIND_ADDR_INDEX].ip_error = IVE_INVALID;
67086b1a8baSrotondo 
6717c478bd9Sstevel@tonic-gate 	/*
6727c478bd9Sstevel@tonic-gate 	 * Iterate through all the different protos/netids resulting from the
6737c478bd9Sstevel@tonic-gate 	 * proto property and check that they're valid and perform checks on
6747c478bd9Sstevel@tonic-gate 	 * other fields that are tied-in with the proto.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	pi = 0;
6787c478bd9Sstevel@tonic-gate 	do {
6797c478bd9Sstevel@tonic-gate 		socket_info_t		*si = NULL;
6807c478bd9Sstevel@tonic-gate 		tlx_info_t		*ti = NULL;
6817c478bd9Sstevel@tonic-gate 		proto_info_t		*p_inf = NULL;
6827c478bd9Sstevel@tonic-gate 		boolean_t		v6only = B_FALSE;
6837c478bd9Sstevel@tonic-gate 		char			*only;
6847c478bd9Sstevel@tonic-gate 		boolean_t		invalid_proto = B_FALSE;
6857c478bd9Sstevel@tonic-gate 		char			**protos;
6867c478bd9Sstevel@tonic-gate 		struct protoent		pe;
6877c478bd9Sstevel@tonic-gate 		char			gpbuf[1024];
6887c478bd9Sstevel@tonic-gate 		struct netconfig	*nconf = NULL;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * If we don't know whether it's an rpc service or its
6927c478bd9Sstevel@tonic-gate 		 * endpoint type, we can't do any of the proto checks as we
6937c478bd9Sstevel@tonic-gate 		 * have no context; break out.
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 		if ((prop[PT_ISRPC_INDEX].ip_error != IVE_VALID) ||
6967c478bd9Sstevel@tonic-gate 		    (prop[PT_SOCK_TYPE_INDEX].ip_error != IVE_VALID))
6977c478bd9Sstevel@tonic-gate 			break;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		/* skip proto specific processing if the proto isn't set. */
7007c478bd9Sstevel@tonic-gate 		if (prop[PT_PROTO_INDEX].ip_error == IVE_UNSET) {
7017c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
7027c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
7037c478bd9Sstevel@tonic-gate 		}
704ba1637f8Smh138676 		protos = prop[PT_PROTO_INDEX].ip_value.iv_string_list;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		/*
7077c478bd9Sstevel@tonic-gate 		 * Get the next netid/proto.
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		if (!cfg->istlx || !isrpc) {
7117c478bd9Sstevel@tonic-gate 			proto = protos[pi++];
7127c478bd9Sstevel@tonic-gate 		/*
7137c478bd9Sstevel@tonic-gate 		 * This is a TLI/RPC service, so get the next netid, expanding
7147c478bd9Sstevel@tonic-gate 		 * any supplied nettype.
7157c478bd9Sstevel@tonic-gate 		 */
7167c478bd9Sstevel@tonic-gate 		} else if ((netids == NULL) ||
7177c478bd9Sstevel@tonic-gate 		    ((proto = netids[ni++]) == NULL)) {
7187c478bd9Sstevel@tonic-gate 			/*
7197c478bd9Sstevel@tonic-gate 			 * Either this is the first time around or
7207c478bd9Sstevel@tonic-gate 			 * we've exhausted the last set of netids, so
7217c478bd9Sstevel@tonic-gate 			 * try and get the next set using the currently
7227c478bd9Sstevel@tonic-gate 			 * indexed proto entry.
7237c478bd9Sstevel@tonic-gate 			 */
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 			if (netids != NULL) {
7267c478bd9Sstevel@tonic-gate 				destroy_strings(netids);
7277c478bd9Sstevel@tonic-gate 				netids = NULL;
7287c478bd9Sstevel@tonic-gate 			}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 			if (protos[pi] != NULL) {
7317c478bd9Sstevel@tonic-gate 				if ((netids = get_netids(protos[pi++])) ==
7327c478bd9Sstevel@tonic-gate 				    NULL) {
7337c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
7347c478bd9Sstevel@tonic-gate 					proto = protos[pi - 1];
7357c478bd9Sstevel@tonic-gate 				} else {
7367c478bd9Sstevel@tonic-gate 					ni = 0;
7377c478bd9Sstevel@tonic-gate 					proto = netids[ni++];
7387c478bd9Sstevel@tonic-gate 				}
7397c478bd9Sstevel@tonic-gate 			} else {
7407c478bd9Sstevel@tonic-gate 				proto = NULL;
7417c478bd9Sstevel@tonic-gate 			}
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 
74419cf6549Sjonb 		if (proto == NULL)
74519cf6549Sjonb 			break;
74619cf6549Sjonb 
74719cf6549Sjonb 		if (invalid_proto)
7487c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		/* strip a trailing only to simplify further processing */
7517c478bd9Sstevel@tonic-gate 		only = proto + strlen(proto) - (sizeof ("6only") - 1);
7527c478bd9Sstevel@tonic-gate 		if ((only > proto) && (strcmp(only, "6only") == 0)) {
7537c478bd9Sstevel@tonic-gate 			*++only = '\0';
7547c478bd9Sstevel@tonic-gate 			v6only = B_TRUE;
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		/* validate the proto/netid */
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		if (!cfg->istlx) {
7607c478bd9Sstevel@tonic-gate 			if (!valid_socket_proto(proto))
7617c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
7627c478bd9Sstevel@tonic-gate 		} else {
7637c478bd9Sstevel@tonic-gate 			/*
7647c478bd9Sstevel@tonic-gate 			 * Check if we've got a valid netid. If
7657c478bd9Sstevel@tonic-gate 			 * getnetconfigent() fails, we check to see whether
7667c478bd9Sstevel@tonic-gate 			 * we've got a v6 netid that may have been rejected
7677c478bd9Sstevel@tonic-gate 			 * because no IPv6 interface was configured before
7687c478bd9Sstevel@tonic-gate 			 * flagging 'proto' as invalid. If the latter condition
7697c478bd9Sstevel@tonic-gate 			 * holds, we don't flag the proto as invalid, and
7707c478bd9Sstevel@tonic-gate 			 * leave inetd to handle the value appropriately
7717c478bd9Sstevel@tonic-gate 			 * when it tries to listen on behalf of the service.
7727c478bd9Sstevel@tonic-gate 			 */
7737c478bd9Sstevel@tonic-gate 			if (((nconf = getnetconfigent(proto)) == NULL) &&
7747c478bd9Sstevel@tonic-gate 			    !v6_proto(proto))
7757c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
7767c478bd9Sstevel@tonic-gate 		}
7777c478bd9Sstevel@tonic-gate 		if (invalid_proto)
7787c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		/*
7817c478bd9Sstevel@tonic-gate 		 * dissallow datagram type nowait services
7827c478bd9Sstevel@tonic-gate 		 */
7837c478bd9Sstevel@tonic-gate 		if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_VALID) &&
7847c478bd9Sstevel@tonic-gate 		    !cfg->iswait) {
7857c478bd9Sstevel@tonic-gate 			if (strncmp(proto, SOCKET_PROTO_UDP,
7867c478bd9Sstevel@tonic-gate 			    sizeof (SOCKET_PROTO_UDP) - 1) == 0) {
7877c478bd9Sstevel@tonic-gate 				invalid_proto = B_TRUE;
7887c478bd9Sstevel@tonic-gate 			} else if (cfg->istlx && (nconf != NULL) &&
7897c478bd9Sstevel@tonic-gate 			    (nconf->nc_semantics == NC_TPI_CLTS)) {
7907c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
7917c478bd9Sstevel@tonic-gate 			}
7927c478bd9Sstevel@tonic-gate 			if (invalid_proto) {
7937c478bd9Sstevel@tonic-gate 				prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID;
7947c478bd9Sstevel@tonic-gate 				goto past_proto_processing;
7957c478bd9Sstevel@tonic-gate 			}
7967c478bd9Sstevel@tonic-gate 		}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		/*
7997c478bd9Sstevel@tonic-gate 		 * We're running in validate only mode. Don't bother creating
8007c478bd9Sstevel@tonic-gate 		 * any proto structures (they don't do any further validation).
8017c478bd9Sstevel@tonic-gate 		 */
8027c478bd9Sstevel@tonic-gate 		if (fmri == NULL)
8037c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		/*
8067c478bd9Sstevel@tonic-gate 		 * Create the apropriate transport info structure.
8077c478bd9Sstevel@tonic-gate 		 */
8087c478bd9Sstevel@tonic-gate 		if (cfg->istlx) {
8097c478bd9Sstevel@tonic-gate 			if ((ti = create_tlx_info(proto, tlx_ci_pool)) != NULL)
8107c478bd9Sstevel@tonic-gate 				p_inf = (proto_info_t *)ti;
8117c478bd9Sstevel@tonic-gate 		} else {
8127c478bd9Sstevel@tonic-gate 			struct sockaddr_storage *ss;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 			if ((si = calloc(1, sizeof (socket_info_t))) != NULL) {
8157c478bd9Sstevel@tonic-gate 				p_inf = (proto_info_t *)si;
8167c478bd9Sstevel@tonic-gate 				si->type = sock_type_id;
8177c478bd9Sstevel@tonic-gate 				ss = &si->local_addr;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 				if (v6_socket_proto(proto)) {
8207c478bd9Sstevel@tonic-gate 					ss->ss_family = AF_INET6;
8217c478bd9Sstevel@tonic-gate 					/* already in network order */
8227c478bd9Sstevel@tonic-gate 					((struct sockaddr_in6 *)ss)->sin6_addr =
8237c478bd9Sstevel@tonic-gate 					    in6addr_any;
8247c478bd9Sstevel@tonic-gate 				} else {
8257c478bd9Sstevel@tonic-gate 					ss->ss_family = AF_INET;
8267c478bd9Sstevel@tonic-gate 					((struct sockaddr_in *)ss)->sin_addr.
8277c478bd9Sstevel@tonic-gate 					    s_addr = htonl(INADDR_ANY);
8287c478bd9Sstevel@tonic-gate 				}
82986b1a8baSrotondo 				if (set_bind_addr(ss, cfg->bind_addr) != 0) {
83086b1a8baSrotondo 					prop[PT_BIND_ADDR_INDEX].ip_error =
83186b1a8baSrotondo 					    IVE_INVALID;
83286b1a8baSrotondo 				}
8337c478bd9Sstevel@tonic-gate 			}
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 		if (p_inf == NULL) {
8367c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
8377c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
8387c478bd9Sstevel@tonic-gate 		}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 		p_inf->v6only = v6only;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 		/*
8437c478bd9Sstevel@tonic-gate 		 * Store the supplied proto string for error reporting,
8447c478bd9Sstevel@tonic-gate 		 * re-attaching the 'only' suffix if one was taken off.
8457c478bd9Sstevel@tonic-gate 		 */
8467c478bd9Sstevel@tonic-gate 		if ((p_inf->proto = malloc(strlen(proto) + 5)) == NULL) {
8477c478bd9Sstevel@tonic-gate 			invalid_proto = B_TRUE;
8487c478bd9Sstevel@tonic-gate 			goto past_proto_processing;
8497c478bd9Sstevel@tonic-gate 		} else {
8507c478bd9Sstevel@tonic-gate 			(void) strlcpy(p_inf->proto, proto, strlen(proto) + 5);
8517c478bd9Sstevel@tonic-gate 			if (v6only)
8527c478bd9Sstevel@tonic-gate 				(void) strlcat(p_inf->proto, "only",
8537c478bd9Sstevel@tonic-gate 				    strlen(proto) + 5);
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		/*
8577c478bd9Sstevel@tonic-gate 		 * Validate and setup RPC/non-RPC specifics.
8587c478bd9Sstevel@tonic-gate 		 */
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		if (isrpc) {
8617c478bd9Sstevel@tonic-gate 			rpc_info_t *ri;
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 			if ((rpc_pnum != -1) && (rpc_lv != -1) &&
8647c478bd9Sstevel@tonic-gate 			    (rpc_hv != -1)) {
8657c478bd9Sstevel@tonic-gate 				if ((ri = create_rpc_info(proto, rpc_pnum,
8667c478bd9Sstevel@tonic-gate 				    rpc_lv, rpc_hv)) == NULL) {
8677c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
8687c478bd9Sstevel@tonic-gate 				} else {
8697c478bd9Sstevel@tonic-gate 					p_inf->ri = ri;
8707c478bd9Sstevel@tonic-gate 				}
8717c478bd9Sstevel@tonic-gate 			}
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate past_proto_processing:
8757c478bd9Sstevel@tonic-gate 		/* validate non-RPC service name */
8767c478bd9Sstevel@tonic-gate 		if (!isrpc && (cfg->svc_name != NULL)) {
8777c478bd9Sstevel@tonic-gate 			struct servent	se;
8787c478bd9Sstevel@tonic-gate 			char		gsbuf[NSS_BUFLEN_SERVICES];
8797c478bd9Sstevel@tonic-gate 			char		*gsproto = proto;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 			if (invalid_proto) {
8827c478bd9Sstevel@tonic-gate 				/*
8837c478bd9Sstevel@tonic-gate 				 * Make getservbyname_r do its lookup without a
8847c478bd9Sstevel@tonic-gate 				 * proto.
8857c478bd9Sstevel@tonic-gate 				 */
8867c478bd9Sstevel@tonic-gate 				gsproto = NULL;
8877c478bd9Sstevel@tonic-gate 			} else if (gsproto != NULL) {
8887c478bd9Sstevel@tonic-gate 				/*
8897c478bd9Sstevel@tonic-gate 				 * Since getservbyname & getprotobyname don't
8907c478bd9Sstevel@tonic-gate 				 * support tcp6, udp6 or sctp6 take off the 6
8917c478bd9Sstevel@tonic-gate 				 * digit from protocol.
8927c478bd9Sstevel@tonic-gate 				 */
8937c478bd9Sstevel@tonic-gate 				if (v6_socket_proto(gsproto))
8947c478bd9Sstevel@tonic-gate 					gsproto[strlen(gsproto) - 1] = '\0';
8957c478bd9Sstevel@tonic-gate 			}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 			if (getservbyname_r(cfg->svc_name, gsproto, &se, gsbuf,
8987c478bd9Sstevel@tonic-gate 			    sizeof (gsbuf)) == NULL) {
8997c478bd9Sstevel@tonic-gate 				if (gsproto != NULL)
9007c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
9017c478bd9Sstevel@tonic-gate 				prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID;
9027c478bd9Sstevel@tonic-gate 			} else if (cfg->istlx && (ti != NULL)) {
9037c478bd9Sstevel@tonic-gate 				/* LINTED E_BAD_PTR_CAST_ALIGN */
9047c478bd9Sstevel@tonic-gate 				SS_SETPORT(*(struct sockaddr_storage *)
9057c478bd9Sstevel@tonic-gate 				    ti->local_addr.buf, se.s_port);
9067c478bd9Sstevel@tonic-gate 			} else if (!cfg->istlx && (si != NULL)) {
9077c478bd9Sstevel@tonic-gate 				if ((gsproto != NULL) &&
9087c478bd9Sstevel@tonic-gate 				    getprotobyname_r(gsproto, &pe, gpbuf,
9097c478bd9Sstevel@tonic-gate 				    sizeof (gpbuf)) == NULL) {
9107c478bd9Sstevel@tonic-gate 					invalid_proto = B_TRUE;
9117c478bd9Sstevel@tonic-gate 				} else {
9127c478bd9Sstevel@tonic-gate 					si->protocol = pe.p_proto;
9137c478bd9Sstevel@tonic-gate 				}
9147c478bd9Sstevel@tonic-gate 				SS_SETPORT(si->local_addr, se.s_port);
9157c478bd9Sstevel@tonic-gate 			}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 		if (p_inf != NULL) {
9207c478bd9Sstevel@tonic-gate 			p_inf->listen_fd = -1;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 			/* add new proto entry to proto_list */
9237c478bd9Sstevel@tonic-gate 			uu_list_node_init(p_inf, &p_inf->link, proto_info_pool);
9247c478bd9Sstevel@tonic-gate 			(void) uu_list_insert_after(cfg->proto_list, NULL,
9257c478bd9Sstevel@tonic-gate 			    p_inf);
9267c478bd9Sstevel@tonic-gate 		}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		if (nconf != NULL)
9297c478bd9Sstevel@tonic-gate 			freenetconfigent(nconf);
9307c478bd9Sstevel@tonic-gate 		if (invalid_proto)
9317c478bd9Sstevel@tonic-gate 			prop[PT_PROTO_INDEX].ip_error = IVE_INVALID;
9327c478bd9Sstevel@tonic-gate 	} while (proto != NULL);	/* while just processed a proto */
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	/*
9357c478bd9Sstevel@tonic-gate 	 * Check that the exec string for the start method actually exists and
9367c478bd9Sstevel@tonic-gate 	 * that the user is either a valid username or uid. Note we don't
9377c478bd9Sstevel@tonic-gate 	 * mandate the setting of these fields, and don't do any checks
9387c478bd9Sstevel@tonic-gate 	 * for arg0, hence its absence.
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	if (prop[PT_EXEC_INDEX].ip_error != IVE_UNSET) {
9427c478bd9Sstevel@tonic-gate 		/* Don't pass any arguments to access() */
9437c478bd9Sstevel@tonic-gate 		if ((bufp = strdup(
944ba1637f8Smh138676 		    prop[PT_EXEC_INDEX].ip_value.iv_string)) == NULL) {
9457c478bd9Sstevel@tonic-gate 			prop[PT_EXEC_INDEX].ip_error = IVE_INVALID;
9467c478bd9Sstevel@tonic-gate 		} else {
9477c478bd9Sstevel@tonic-gate 			if ((cp = strpbrk(bufp, " \t")) != NULL)
9487c478bd9Sstevel@tonic-gate 				*cp = '\0';
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 			if ((access(bufp, F_OK) == -1) && (errno == ENOENT))
9517c478bd9Sstevel@tonic-gate 				prop[PT_EXEC_INDEX].ip_error = IVE_INVALID;
9527c478bd9Sstevel@tonic-gate 			free(bufp);
9537c478bd9Sstevel@tonic-gate 		}
9547c478bd9Sstevel@tonic-gate 	}
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	if (prop[PT_USER_INDEX].ip_error != IVE_UNSET) {
9577c478bd9Sstevel@tonic-gate 		char		pw_buf[NSS_BUFLEN_PASSWD];
9587c478bd9Sstevel@tonic-gate 		struct passwd	pw;
9597c478bd9Sstevel@tonic-gate 
960ba1637f8Smh138676 		if (getpwnam_r(prop[PT_USER_INDEX].ip_value.iv_string, &pw,
9617c478bd9Sstevel@tonic-gate 		    pw_buf, NSS_BUFLEN_PASSWD) == NULL) {
9627c478bd9Sstevel@tonic-gate 			errno = 0;
963ba1637f8Smh138676 			uidl = strtol(prop[PT_USER_INDEX].ip_value.iv_string,
9647c478bd9Sstevel@tonic-gate 			    &bufp, 10);
9657c478bd9Sstevel@tonic-gate 			if ((errno != 0) || (*bufp != '\0') ||
9667c478bd9Sstevel@tonic-gate 			    (getpwuid_r(uidl, &pw, pw_buf,
9677c478bd9Sstevel@tonic-gate 			    NSS_BUFLEN_PASSWD) == NULL))
9687c478bd9Sstevel@tonic-gate 				prop[PT_USER_INDEX].ip_error = IVE_INVALID;
9697c478bd9Sstevel@tonic-gate 		}
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/*
9737c478bd9Sstevel@tonic-gate 	 * Iterate through the properties in the array verifying that any
9747c478bd9Sstevel@tonic-gate 	 * default properties are valid, and setting the return boolean
9757c478bd9Sstevel@tonic-gate 	 * according to whether any properties were marked invalid.
9767c478bd9Sstevel@tonic-gate 	 */
9777c478bd9Sstevel@tonic-gate 
978ba1637f8Smh138676 	for (i = 0; prop[i].ip_name != NULL; i++) {
9797c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error == IVE_UNSET)
9807c478bd9Sstevel@tonic-gate 			continue;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		if (prop[i].ip_default &&
9837c478bd9Sstevel@tonic-gate 		    !valid_default_prop(prop[i].ip_name, &prop[i].ip_value))
9847c478bd9Sstevel@tonic-gate 			prop[i].ip_error = IVE_INVALID;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		if (prop[i].ip_error == IVE_INVALID)
9877c478bd9Sstevel@tonic-gate 			ret = B_FALSE;
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	/* pass back the basic_cfg_t if requested and it's a valid config */
9917c478bd9Sstevel@tonic-gate 	if ((cfgpp != NULL) && ret) {
9927c478bd9Sstevel@tonic-gate 		*cfgpp = cfg;
9937c478bd9Sstevel@tonic-gate 	} else {
9947c478bd9Sstevel@tonic-gate 		destroy_basic_cfg(cfg);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	return (ret);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate /*
10017c478bd9Sstevel@tonic-gate  * validate_default_prop takes the name of an inetd property, and a value
10027c478bd9Sstevel@tonic-gate  * for that property.  It returns B_TRUE if the property is valid, and B_FALSE
10037c478bd9Sstevel@tonic-gate  * if the proposed value isn't valid for that property.
10047c478bd9Sstevel@tonic-gate  */
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate boolean_t
1007ba1637f8Smh138676 valid_default_prop(const char *name, const void *value)
10087c478bd9Sstevel@tonic-gate {
10097c478bd9Sstevel@tonic-gate 	int		i;
10107c478bd9Sstevel@tonic-gate 
1011ba1637f8Smh138676 	for (i = 0; inetd_properties[i].ip_name != NULL; i++) {
10127c478bd9Sstevel@tonic-gate 		if (strcmp(name, inetd_properties[i].ip_name) != 0)
10137c478bd9Sstevel@tonic-gate 			continue;
10147c478bd9Sstevel@tonic-gate 		if (!inetd_properties[i].ip_default)
10157c478bd9Sstevel@tonic-gate 			return (B_FALSE);
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 		switch (inetd_properties[i].ip_type) {
1018ba1637f8Smh138676 		case INET_TYPE_INTEGER:
10197c478bd9Sstevel@tonic-gate 			if (*((int64_t *)value) >= -1)
10207c478bd9Sstevel@tonic-gate 				return (B_TRUE);
10217c478bd9Sstevel@tonic-gate 			else
10227c478bd9Sstevel@tonic-gate 				return (B_FALSE);
1023ba1637f8Smh138676 		case INET_TYPE_BOOLEAN:
10247c478bd9Sstevel@tonic-gate 			if ((*((boolean_t *)value) == B_FALSE) ||
10257c478bd9Sstevel@tonic-gate 			    (*((boolean_t *)value) == B_TRUE))
10267c478bd9Sstevel@tonic-gate 				return (B_TRUE);
10277c478bd9Sstevel@tonic-gate 			else
10287c478bd9Sstevel@tonic-gate 				return (B_FALSE);
1029ba1637f8Smh138676 		case INET_TYPE_COUNT:
1030ba1637f8Smh138676 		case INET_TYPE_STRING_LIST:
1031ba1637f8Smh138676 		case INET_TYPE_STRING:
10327c478bd9Sstevel@tonic-gate 			return (B_TRUE);
10337c478bd9Sstevel@tonic-gate 		}
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	return (B_FALSE);
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
103986b1a8baSrotondo /*ARGSUSED*/
10407c478bd9Sstevel@tonic-gate scf_error_t
10417c478bd9Sstevel@tonic-gate read_prop(scf_handle_t *h, inetd_prop_t *iprop, int index, const char *inst,
10427c478bd9Sstevel@tonic-gate     const char *pg_name)
10437c478bd9Sstevel@tonic-gate {
10447c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*sprop;
10457c478bd9Sstevel@tonic-gate 	uint8_t			*tmp_bool;
10467c478bd9Sstevel@tonic-gate 	int64_t			*tmp_int;
10477c478bd9Sstevel@tonic-gate 	uint64_t		*tmp_cnt;
10487c478bd9Sstevel@tonic-gate 	char			*tmp_char;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	if ((sprop = scf_simple_prop_get(h, inst, pg_name, iprop->ip_name)) ==
10517c478bd9Sstevel@tonic-gate 	    NULL)
10527c478bd9Sstevel@tonic-gate 		return (scf_error());
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	switch (iprop->ip_type) {
1055ba1637f8Smh138676 	case INET_TYPE_STRING:
1056ba1637f8Smh138676 		if ((tmp_char = scf_simple_prop_next_astring(sprop)) == NULL)
1057ba1637f8Smh138676 			goto scf_error;
1058ba1637f8Smh138676 		if ((iprop->ip_value.iv_string = strdup(tmp_char)) == NULL) {
1059ba1637f8Smh138676 			scf_simple_prop_free(sprop);
1060ba1637f8Smh138676 			return (SCF_ERROR_NO_MEMORY);
1061ba1637f8Smh138676 		}
1062ba1637f8Smh138676 		break;
1063ba1637f8Smh138676 	case INET_TYPE_STRING_LIST:
1064ba1637f8Smh138676 		{
10657c478bd9Sstevel@tonic-gate 			int	j = 0;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 			while ((tmp_char =
10687c478bd9Sstevel@tonic-gate 			    scf_simple_prop_next_astring(sprop)) != NULL) {
10697c478bd9Sstevel@tonic-gate 				char	**cpp;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 				if ((cpp = realloc(
1072ba1637f8Smh138676 				    iprop->ip_value.iv_string_list,
10737c478bd9Sstevel@tonic-gate 				    (j + 2) * sizeof (char *))) == NULL) {
10747c478bd9Sstevel@tonic-gate 					scf_simple_prop_free(sprop);
10757c478bd9Sstevel@tonic-gate 					return (SCF_ERROR_NO_MEMORY);
10767c478bd9Sstevel@tonic-gate 				}
1077ba1637f8Smh138676 				iprop->ip_value.iv_string_list = cpp;
10787c478bd9Sstevel@tonic-gate 				if ((cpp[j] = strdup(tmp_char)) == NULL) {
10797c478bd9Sstevel@tonic-gate 					scf_simple_prop_free(sprop);
10807c478bd9Sstevel@tonic-gate 					return (SCF_ERROR_NO_MEMORY);
10817c478bd9Sstevel@tonic-gate 				}
10827c478bd9Sstevel@tonic-gate 				cpp[++j] = NULL;
10837c478bd9Sstevel@tonic-gate 			}
10847c478bd9Sstevel@tonic-gate 			if ((j == 0) || (scf_error() != SCF_ERROR_NONE))
10857c478bd9Sstevel@tonic-gate 				goto scf_error;
10867c478bd9Sstevel@tonic-gate 		}
10877c478bd9Sstevel@tonic-gate 		break;
1088ba1637f8Smh138676 	case INET_TYPE_BOOLEAN:
10897c478bd9Sstevel@tonic-gate 		if ((tmp_bool = scf_simple_prop_next_boolean(sprop)) == NULL)
10907c478bd9Sstevel@tonic-gate 			goto scf_error;
10917c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_boolean =
10927c478bd9Sstevel@tonic-gate 		    (*tmp_bool == 0) ? B_FALSE : B_TRUE;
10937c478bd9Sstevel@tonic-gate 		break;
1094ba1637f8Smh138676 	case INET_TYPE_COUNT:
10957c478bd9Sstevel@tonic-gate 		if ((tmp_cnt = scf_simple_prop_next_count(sprop)) == NULL)
10967c478bd9Sstevel@tonic-gate 			goto scf_error;
10977c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_cnt = *tmp_cnt;
10987c478bd9Sstevel@tonic-gate 		break;
1099ba1637f8Smh138676 	case INET_TYPE_INTEGER:
11007c478bd9Sstevel@tonic-gate 		if ((tmp_int = scf_simple_prop_next_integer(sprop)) == NULL)
11017c478bd9Sstevel@tonic-gate 			goto scf_error;
11027c478bd9Sstevel@tonic-gate 		iprop->ip_value.iv_int = *tmp_int;
11037c478bd9Sstevel@tonic-gate 		break;
11047c478bd9Sstevel@tonic-gate 	default:
11057c478bd9Sstevel@tonic-gate 		assert(0);
11067c478bd9Sstevel@tonic-gate 	}
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	iprop->ip_error = IVE_VALID;
11097c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sprop);
11107c478bd9Sstevel@tonic-gate 	return (0);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate scf_error:
11137c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sprop);
11147c478bd9Sstevel@tonic-gate 	if (scf_error() == SCF_ERROR_NONE)
11157c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
11167c478bd9Sstevel@tonic-gate 	return (scf_error());
11177c478bd9Sstevel@tonic-gate }
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate /*
11207c478bd9Sstevel@tonic-gate  * read_props reads either the full set of properties for instance 'instance'
11217c478bd9Sstevel@tonic-gate  * (including defaults - pulling them in from inetd where necessary) if
11227c478bd9Sstevel@tonic-gate  * 'instance' is non-null, else just the defaults from inetd. The properties
11237c478bd9Sstevel@tonic-gate  * are returned in an allocated inetd_prop_t array, which must be freed
11247c478bd9Sstevel@tonic-gate  * using free_instance_props(). If an error occurs NULL is returned and 'err'
11257c478bd9Sstevel@tonic-gate  * is set to indicate the cause, else a pointer to the read properties is
11267c478bd9Sstevel@tonic-gate  * returned.
11277c478bd9Sstevel@tonic-gate  */
11287c478bd9Sstevel@tonic-gate static inetd_prop_t *
11297c478bd9Sstevel@tonic-gate read_props(scf_handle_t *h, const char *instance, size_t *num_elements,
11307c478bd9Sstevel@tonic-gate     scf_error_t *err)
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate 	inetd_prop_t	*ret = NULL;
11337c478bd9Sstevel@tonic-gate 	int		i;
11347c478bd9Sstevel@tonic-gate 	boolean_t	defaults_only = (instance == NULL);
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	if ((ret = malloc(sizeof (inetd_properties))) == NULL) {
11377c478bd9Sstevel@tonic-gate 		*err = SCF_ERROR_NO_MEMORY;
11387c478bd9Sstevel@tonic-gate 		return (NULL);
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate 	(void) memcpy(ret, &inetd_properties, sizeof (inetd_properties));
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	if (defaults_only)
11437c478bd9Sstevel@tonic-gate 		instance = INETD_INSTANCE_FMRI;
1144ba1637f8Smh138676 	for (i = 0; ret[i].ip_name != NULL; i++) {
11457c478bd9Sstevel@tonic-gate 		if (defaults_only && !ret[i].ip_default)
11467c478bd9Sstevel@tonic-gate 			continue;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 		switch (*err = read_prop(h, &ret[i], i, instance,
11497c478bd9Sstevel@tonic-gate 		    defaults_only ? PG_NAME_SERVICE_DEFAULTS : ret[i].ip_pg)) {
11507c478bd9Sstevel@tonic-gate 		case 0:
11517c478bd9Sstevel@tonic-gate 			break;
11527c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
11537c478bd9Sstevel@tonic-gate 			goto failure_cleanup;
11547c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
11557c478bd9Sstevel@tonic-gate 			/*
11567c478bd9Sstevel@tonic-gate 			 * In non-default-only mode where we're reading a
11577c478bd9Sstevel@tonic-gate 			 * default property, since the property wasn't
11587c478bd9Sstevel@tonic-gate 			 * found in the instance, try and read inetd's default
11597c478bd9Sstevel@tonic-gate 			 * value.
11607c478bd9Sstevel@tonic-gate 			 */
11617c478bd9Sstevel@tonic-gate 			if (!ret[i].ip_default || defaults_only)
11627c478bd9Sstevel@tonic-gate 				continue;
11637c478bd9Sstevel@tonic-gate 			switch (*err = read_prop(h, &ret[i], i,
11647c478bd9Sstevel@tonic-gate 			    INETD_INSTANCE_FMRI, PG_NAME_SERVICE_DEFAULTS)) {
11657c478bd9Sstevel@tonic-gate 			case 0:
11667c478bd9Sstevel@tonic-gate 				ret[i].from_inetd = B_TRUE;
11677c478bd9Sstevel@tonic-gate 				continue;
11687c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
11697c478bd9Sstevel@tonic-gate 				continue;
11707c478bd9Sstevel@tonic-gate 			default:
11717c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
11727c478bd9Sstevel@tonic-gate 			}
11737c478bd9Sstevel@tonic-gate 		default:
11747c478bd9Sstevel@tonic-gate 			goto failure_cleanup;
11757c478bd9Sstevel@tonic-gate 		}
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
1178ba1637f8Smh138676 	*num_elements = i;
11797c478bd9Sstevel@tonic-gate 	return (ret);
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate failure_cleanup:
11827c478bd9Sstevel@tonic-gate 	free_instance_props(ret);
11837c478bd9Sstevel@tonic-gate 	return (NULL);
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * Read all properties applicable to 'instance' (including defaults).
11887c478bd9Sstevel@tonic-gate  */
11897c478bd9Sstevel@tonic-gate inetd_prop_t *
11907c478bd9Sstevel@tonic-gate read_instance_props(scf_handle_t *h, const char *instance, size_t *num_elements,
11917c478bd9Sstevel@tonic-gate     scf_error_t *err)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 	return (read_props(h, instance, num_elements, err));
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate /*
11977c478bd9Sstevel@tonic-gate  * Read the default properties from inetd's defaults property group.
11987c478bd9Sstevel@tonic-gate  */
11997c478bd9Sstevel@tonic-gate inetd_prop_t *
12007c478bd9Sstevel@tonic-gate read_default_props(scf_handle_t *h, size_t *num_elements, scf_error_t *err)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate 	return (read_props(h, NULL, num_elements, err));
12037c478bd9Sstevel@tonic-gate }
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate void
12067c478bd9Sstevel@tonic-gate free_instance_props(inetd_prop_t *prop)
12077c478bd9Sstevel@tonic-gate {
12087c478bd9Sstevel@tonic-gate 	int i;
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	if (prop == NULL)
12117c478bd9Sstevel@tonic-gate 		return;
12127c478bd9Sstevel@tonic-gate 
1213ba1637f8Smh138676 	for (i = 0; prop[i].ip_name != NULL; i++) {
1214ba1637f8Smh138676 		if (prop[i].ip_type == INET_TYPE_STRING) {
1215ba1637f8Smh138676 			free(prop[i].ip_value.iv_string);
1216ba1637f8Smh138676 		} else if (prop[i].ip_type == INET_TYPE_STRING_LIST) {
1217ba1637f8Smh138676 			destroy_strings(prop[i].ip_value.iv_string_list);
12187c478bd9Sstevel@tonic-gate 		}
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate 	free(prop);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate int
12247c478bd9Sstevel@tonic-gate connect_to_inetd(void)
12257c478bd9Sstevel@tonic-gate {
12267c478bd9Sstevel@tonic-gate 	struct sockaddr_un	addr;
12277c478bd9Sstevel@tonic-gate 	int			fd;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
12307c478bd9Sstevel@tonic-gate 	if (fd < 0)
12317c478bd9Sstevel@tonic-gate 		return (-1);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	(void) memset(&addr, 0, sizeof (addr));
12347c478bd9Sstevel@tonic-gate 	addr.sun_family = AF_UNIX;
12357c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
12367c478bd9Sstevel@tonic-gate 	assert(sizeof (INETD_UDS_PATH) <= sizeof (addr.sun_path));
12377c478bd9Sstevel@tonic-gate 	(void) strlcpy(addr.sun_path, INETD_UDS_PATH,
12387c478bd9Sstevel@tonic-gate 	    sizeof (addr.sun_path));
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
12417c478bd9Sstevel@tonic-gate 		(void) close(fd);
12427c478bd9Sstevel@tonic-gate 		return (-1);
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	return (fd);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate  * refresh_inetd requests that inetd re-read all of the information that it's
12507c478bd9Sstevel@tonic-gate  * monitoring.
12517c478bd9Sstevel@tonic-gate  */
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate int
12547c478bd9Sstevel@tonic-gate refresh_inetd(void)
12557c478bd9Sstevel@tonic-gate {
12567c478bd9Sstevel@tonic-gate 	uds_request_t   req;
12577c478bd9Sstevel@tonic-gate 	int		fd;
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	if ((fd = connect_to_inetd()) < 0)
12607c478bd9Sstevel@tonic-gate 		return (-1);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	req = UR_REFRESH_INETD;
12637c478bd9Sstevel@tonic-gate 	if (send(fd, &req, sizeof (req), 0) < 0) {
12647c478bd9Sstevel@tonic-gate 		(void) close(fd);
12657c478bd9Sstevel@tonic-gate 		return (-1);
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	(void) close(fd);
12697c478bd9Sstevel@tonic-gate 	return (0);
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate /*
12737c478bd9Sstevel@tonic-gate  * Returns the id of the socket type 'type_str' that can be used in a call
12747c478bd9Sstevel@tonic-gate  * to socket(). If an unknown type string is passed returns -1, else the id.
12757c478bd9Sstevel@tonic-gate  */
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate int
12787c478bd9Sstevel@tonic-gate get_sock_type_id(const char *type_str)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate 	int	ret;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	if (strcmp(SOCKTYPE_STREAM_STR, type_str) == 0) {
12837c478bd9Sstevel@tonic-gate 		ret = SOCK_STREAM;
12847c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_DGRAM_STR, type_str) == 0) {
12857c478bd9Sstevel@tonic-gate 		ret = SOCK_DGRAM;
12867c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_RAW_STR, type_str) == 0) {
12877c478bd9Sstevel@tonic-gate 		ret = SOCK_RAW;
12887c478bd9Sstevel@tonic-gate 	} else if (strcmp(SOCKTYPE_SEQPKT_STR, type_str) == 0) {
12897c478bd9Sstevel@tonic-gate 		ret = SOCK_SEQPACKET;
12907c478bd9Sstevel@tonic-gate 	} else {
12917c478bd9Sstevel@tonic-gate 		ret = -1;
12927c478bd9Sstevel@tonic-gate 	}
12937c478bd9Sstevel@tonic-gate 	return (ret);
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate /*
12977c478bd9Sstevel@tonic-gate  * Takes either an RPC service name or number in string form as 'svc_name', and
12987c478bd9Sstevel@tonic-gate  * returns an integer format program number for the service. If the name isn't
12997c478bd9Sstevel@tonic-gate  * recognized as a valid RPC service name or isn't a valid number, -1 is
13007c478bd9Sstevel@tonic-gate  * returned, else the services program number.
13017c478bd9Sstevel@tonic-gate  */
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate int
13047c478bd9Sstevel@tonic-gate get_rpc_prognum(const char *svc_name)
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate 	struct rpcent	rpc;
13077c478bd9Sstevel@tonic-gate 	char		buf[INETSVC_SVC_BUF_MAX];
13087c478bd9Sstevel@tonic-gate 	int		pnum;
13097c478bd9Sstevel@tonic-gate 	char		*endptr;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (getrpcbyname_r(svc_name, &rpc, buf, sizeof (buf)) != NULL)
13127c478bd9Sstevel@tonic-gate 		return (rpc.r_number);
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	pnum = strtol(svc_name, &endptr, 0);
13157c478bd9Sstevel@tonic-gate 	if ((pnum == 0 && errno == EINVAL) ||
13167c478bd9Sstevel@tonic-gate 	    (pnum == LONG_MAX && errno == ERANGE) ||
13177c478bd9Sstevel@tonic-gate 	    pnum < 0 || *endptr != '\0') {
13187c478bd9Sstevel@tonic-gate 		return (-1);
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	return (pnum);
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate /*
13257c478bd9Sstevel@tonic-gate  * calculate_hash calculates the MD5 message-digest of the file pathname.
13267c478bd9Sstevel@tonic-gate  * On success, hash is modified to point to the digest string and 0 is returned.
13277c478bd9Sstevel@tonic-gate  * Otherwise, -1 is returned and errno is set to indicate the error.
13287c478bd9Sstevel@tonic-gate  * The space for the digest string is obtained using malloc(3C) and should be
13297c478bd9Sstevel@tonic-gate  * freed by the caller.
13307c478bd9Sstevel@tonic-gate  */
13317c478bd9Sstevel@tonic-gate int
13327c478bd9Sstevel@tonic-gate calculate_hash(const char *pathname, char **hash)
13337c478bd9Sstevel@tonic-gate {
13347c478bd9Sstevel@tonic-gate 	int fd, i, serrno;
13357c478bd9Sstevel@tonic-gate 	size_t len;
13367c478bd9Sstevel@tonic-gate 	ssize_t n;
13377c478bd9Sstevel@tonic-gate 	char *digest;
13387c478bd9Sstevel@tonic-gate 	MD5_CTX md5_context;
13397c478bd9Sstevel@tonic-gate 	unsigned char md5_digest[DIGEST_LEN];
13407c478bd9Sstevel@tonic-gate 	unsigned char buf[READ_BUFSIZ];
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	do {
13437c478bd9Sstevel@tonic-gate 		fd = open(pathname, O_RDONLY);
13447c478bd9Sstevel@tonic-gate 	} while (fd == -1 && errno == EINTR);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	if (fd == -1)
13477c478bd9Sstevel@tonic-gate 		return (-1);
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	/* allocate space for a 16-byte MD5 digest as a string of hex digits */
13507c478bd9Sstevel@tonic-gate 	len = 2 * sizeof (md5_digest) + 1;
13517c478bd9Sstevel@tonic-gate 	if ((digest = malloc(len)) == NULL) {
13527c478bd9Sstevel@tonic-gate 		serrno = errno;
13537c478bd9Sstevel@tonic-gate 		(void) close(fd);
13547c478bd9Sstevel@tonic-gate 		errno = serrno;
13557c478bd9Sstevel@tonic-gate 		return (-1);
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	MD5Init(&md5_context);
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	do {
13617c478bd9Sstevel@tonic-gate 		if ((n = read(fd, buf, sizeof (buf))) > 0)
13627c478bd9Sstevel@tonic-gate 			MD5Update(&md5_context, buf, n);
13637c478bd9Sstevel@tonic-gate 	} while ((n > 0) || (n == -1 && errno == EINTR));
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	serrno = errno;
13667c478bd9Sstevel@tonic-gate 	MD5Final(md5_digest, &md5_context);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	(void) close(fd);
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	if (n == -1) {
13717c478bd9Sstevel@tonic-gate 		errno = serrno;
13727c478bd9Sstevel@tonic-gate 		return (-1);
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (md5_digest); i++) {
13767c478bd9Sstevel@tonic-gate 		(void) snprintf(&digest[2 * i], len - (2 * i), "%02x",
13777c478bd9Sstevel@tonic-gate 		    md5_digest[i]);
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 	*hash = digest;
13807c478bd9Sstevel@tonic-gate 	return (0);
13817c478bd9Sstevel@tonic-gate }
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate /*
13847c478bd9Sstevel@tonic-gate  * retrieve_inetd_hash retrieves inetd's configuration file hash from the
13857c478bd9Sstevel@tonic-gate  * repository. On success, hash is modified to point to the hash string and
13867c478bd9Sstevel@tonic-gate  * SCF_ERROR_NONE is returned. Otherwise, the scf_error value is returned.
13877c478bd9Sstevel@tonic-gate  * The space for the hash string is obtained using malloc(3C) and should be
13887c478bd9Sstevel@tonic-gate  * freed by the caller.
13897c478bd9Sstevel@tonic-gate  */
13907c478bd9Sstevel@tonic-gate scf_error_t
13917c478bd9Sstevel@tonic-gate retrieve_inetd_hash(char **hash)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	scf_simple_prop_t *sp;
13947c478bd9Sstevel@tonic-gate 	char *hashstr, *s;
13957c478bd9Sstevel@tonic-gate 	scf_error_t scf_err;
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, HASH_PG,
13987c478bd9Sstevel@tonic-gate 	    HASH_PROP)) == NULL)
13997c478bd9Sstevel@tonic-gate 		return (scf_error());
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	if ((hashstr = scf_simple_prop_next_astring(sp)) == NULL) {
14027c478bd9Sstevel@tonic-gate 		scf_err = scf_error();
14037c478bd9Sstevel@tonic-gate 		scf_simple_prop_free(sp);
14047c478bd9Sstevel@tonic-gate 		return (scf_err);
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	if ((s = strdup(hashstr)) == NULL) {
14087c478bd9Sstevel@tonic-gate 		scf_simple_prop_free(sp);
14097c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
14107c478bd9Sstevel@tonic-gate 	}
14117c478bd9Sstevel@tonic-gate 	*hash = s;
14127c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sp);
14137c478bd9Sstevel@tonic-gate 	return (SCF_ERROR_NONE);
14147c478bd9Sstevel@tonic-gate }
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate /*
14177c478bd9Sstevel@tonic-gate  * store_inetd_hash stores the string hash in inetd's configuration file hash
14187c478bd9Sstevel@tonic-gate  * in the repository. On success, SCF_ERROR_NONE is returned. Otherwise, the
14197c478bd9Sstevel@tonic-gate  * scf_error value is returned.
14207c478bd9Sstevel@tonic-gate  */
14217c478bd9Sstevel@tonic-gate scf_error_t
14227c478bd9Sstevel@tonic-gate store_inetd_hash(const char *hash)
14237c478bd9Sstevel@tonic-gate {
14247c478bd9Sstevel@tonic-gate 	int ret;
14257c478bd9Sstevel@tonic-gate 	scf_error_t rval = SCF_ERROR_NONE;
14267c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
14277c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
14287c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
14297c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx = NULL;
14307c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *txent = NULL;
14317c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
14327c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
14357c478bd9Sstevel@tonic-gate 	    scf_handle_bind(h) == -1)
14367c478bd9Sstevel@tonic-gate 		goto error;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
14397c478bd9Sstevel@tonic-gate 	    (inst = scf_instance_create(h)) == NULL ||
14407c478bd9Sstevel@tonic-gate 	    scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL, inst,
14417c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1)
14427c478bd9Sstevel@tonic-gate 		goto error;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, HASH_PG, pg) == -1) {
14457c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND ||
14467c478bd9Sstevel@tonic-gate 		    scf_instance_add_pg(inst, HASH_PG, SCF_GROUP_APPLICATION,
14477c478bd9Sstevel@tonic-gate 		    0, pg) == -1)
14487c478bd9Sstevel@tonic-gate 			goto error;
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
14527c478bd9Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL ||
14537c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
14547c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
14557c478bd9Sstevel@tonic-gate 		goto error;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	do {
14587c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1)
14597c478bd9Sstevel@tonic-gate 			goto error;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_new(tx, txent, HASH_PROP,
14627c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) == -1 &&
14637c478bd9Sstevel@tonic-gate 		    scf_transaction_property_change_type(tx, txent, HASH_PROP,
14647c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) == -1)
14657c478bd9Sstevel@tonic-gate 			goto error;
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(val, hash) == -1 ||
14687c478bd9Sstevel@tonic-gate 		    scf_entry_add_value(txent, val) == -1)
14697c478bd9Sstevel@tonic-gate 			goto error;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 		if ((ret = scf_transaction_commit(tx)) == -1)
14727c478bd9Sstevel@tonic-gate 			goto error;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 		if (ret == 0) {
14757c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
14767c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
14777c478bd9Sstevel@tonic-gate 				goto error;
14787c478bd9Sstevel@tonic-gate 		}
14797c478bd9Sstevel@tonic-gate 	} while (ret == 0);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	goto success;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate error:
14847c478bd9Sstevel@tonic-gate 	rval = scf_error();
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate success:
14877c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
14887c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
14897c478bd9Sstevel@tonic-gate 	scf_entry_destroy(txent);
14907c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
14917c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
14927c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
14937c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
14947c478bd9Sstevel@tonic-gate 	return (rval);
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate /*
14987c478bd9Sstevel@tonic-gate  * This is a wrapper function for inet_ntop(). In case the af is AF_INET6
14997c478bd9Sstevel@tonic-gate  * and the address pointed by src is a IPv4-mapped IPv6 address, it returns
15007c478bd9Sstevel@tonic-gate  * a printable IPv4 address, not an IPv4-mapped IPv6 address. In other cases it
15017c478bd9Sstevel@tonic-gate  * behaves just like inet_ntop().
15027c478bd9Sstevel@tonic-gate  */
15037c478bd9Sstevel@tonic-gate const char *
15047c478bd9Sstevel@tonic-gate inet_ntop_native(int af, const void *addr, char *dst, size_t size)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate 	struct in_addr	v4addr;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	if ((af == AF_INET6) && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) {
15097c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr);
15107c478bd9Sstevel@tonic-gate 		return (inet_ntop(AF_INET, &v4addr, dst, size));
15117c478bd9Sstevel@tonic-gate 	} else {
15127c478bd9Sstevel@tonic-gate 		return (inet_ntop(af, addr, dst, size));
15137c478bd9Sstevel@tonic-gate 	}
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate  * inetd specific setproctitle. It sets the title so that it contains
15187c478bd9Sstevel@tonic-gate  * 'svc_name' followed by, if obtainable, the address of the remote end of
15197c478bd9Sstevel@tonic-gate  * socket 's'.
15207c478bd9Sstevel@tonic-gate  * NOTE: The argv manipulation in this function should be replaced when a
15217c478bd9Sstevel@tonic-gate  * common version of setproctitle is made available.
15227c478bd9Sstevel@tonic-gate  */
15237c478bd9Sstevel@tonic-gate void
15247c478bd9Sstevel@tonic-gate setproctitle(const char *svc_name, int s, char *argv[])
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	socklen_t		size;
15277c478bd9Sstevel@tonic-gate 	struct sockaddr_storage	ss;
15287c478bd9Sstevel@tonic-gate 	char			abuf[INET6_ADDRSTRLEN];
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	static char		buf[80];
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	size = (socklen_t)sizeof (ss);
15337c478bd9Sstevel@tonic-gate 	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
15347c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "-%s [%s]", svc_name,
15357c478bd9Sstevel@tonic-gate 		    inet_ntop_native(ss.ss_family, (ss.ss_family == AF_INET6 ?
15367c478bd9Sstevel@tonic-gate 		    (void *)&((struct sockaddr_in6 *)(&ss))->sin6_addr :
15377c478bd9Sstevel@tonic-gate 		    (void *)&((struct sockaddr_in *)(&ss))->sin_addr), abuf,
15387c478bd9Sstevel@tonic-gate 		    sizeof (abuf)));
15397c478bd9Sstevel@tonic-gate 	} else {
15407c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "-%s", svc_name);
15417c478bd9Sstevel@tonic-gate 	}
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	/* we set argv[0] to point at our static storage. */
15447c478bd9Sstevel@tonic-gate 	argv[0] = buf;
15457c478bd9Sstevel@tonic-gate 	argv[1] = NULL;
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate static boolean_t
15497c478bd9Sstevel@tonic-gate inetd_builtin_srcport(in_port_t p)
15507c478bd9Sstevel@tonic-gate {
15517c478bd9Sstevel@tonic-gate 	p = ntohs(p);
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if ((p == IPPORT_ECHO) ||
15547c478bd9Sstevel@tonic-gate 	    (p == IPPORT_DISCARD) ||
15557c478bd9Sstevel@tonic-gate 	    (p == IPPORT_DAYTIME) ||
15567c478bd9Sstevel@tonic-gate 	    (p == IPPORT_CHARGEN) ||
15577c478bd9Sstevel@tonic-gate 	    (p == IPPORT_TIMESERVER)) {
15587c478bd9Sstevel@tonic-gate 		return (B_TRUE);
15597c478bd9Sstevel@tonic-gate 	} else {
15607c478bd9Sstevel@tonic-gate 		return (B_FALSE);
15617c478bd9Sstevel@tonic-gate 	}
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
15657c478bd9Sstevel@tonic-gate static void
15667c478bd9Sstevel@tonic-gate alarm_handler(int sig)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	exit(0);
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate /*
15727c478bd9Sstevel@tonic-gate  * This function is a datagram service template. It acts as a datagram wait
15737c478bd9Sstevel@tonic-gate  * type server, waiting for datagrams to come in, and when they do passing
15747c478bd9Sstevel@tonic-gate  * their contents, as-well as the socket they came in on and the remote
15757c478bd9Sstevel@tonic-gate  * address, in a call to the callback function 'cb'. If no datagrams are
15767c478bd9Sstevel@tonic-gate  * received for DG_INACTIVITY_TIMEOUT seconds the function exits with code 0.
15777c478bd9Sstevel@tonic-gate  */
15787c478bd9Sstevel@tonic-gate void
15797c478bd9Sstevel@tonic-gate dg_template(void (*cb)(int, const struct sockaddr *, int, const void *, size_t),
15807c478bd9Sstevel@tonic-gate     int s, void *buf, size_t buflen)
15817c478bd9Sstevel@tonic-gate {
15827c478bd9Sstevel@tonic-gate 	struct sockaddr_storage	sa;
15837c478bd9Sstevel@tonic-gate 	socklen_t		sa_size;
15847c478bd9Sstevel@tonic-gate 	ssize_t			i;
15857c478bd9Sstevel@tonic-gate 	char			tmp[BUFSIZ];
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	(void) sigset(SIGALRM, alarm_handler);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
15907c478bd9Sstevel@tonic-gate 		buf = tmp;
15917c478bd9Sstevel@tonic-gate 		buflen = sizeof (tmp);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 	for (;;) {
15947c478bd9Sstevel@tonic-gate 		(void) alarm(DG_INACTIVITY_TIMEOUT);
15957c478bd9Sstevel@tonic-gate 		sa_size = sizeof (sa);
15967c478bd9Sstevel@tonic-gate 		if ((i = recvfrom(s, buf, buflen, 0, (struct sockaddr *)&sa,
15977c478bd9Sstevel@tonic-gate 		    &sa_size)) < 0) {
15987c478bd9Sstevel@tonic-gate 			continue;
15997c478bd9Sstevel@tonic-gate 		} else if (inetd_builtin_srcport(
16007c478bd9Sstevel@tonic-gate 		    ((struct sockaddr_in *)(&sa))->sin_port)) {
16017c478bd9Sstevel@tonic-gate 			/* denial-of-service attack possibility - ignore it */
16027c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
16037c478bd9Sstevel@tonic-gate 	"Incoming datagram from internal inetd service received; ignoring.");
16047c478bd9Sstevel@tonic-gate 			continue;
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		(void) alarm(0);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 		cb(s, (struct sockaddr *)&sa, sa_size, buf, i);
16097c478bd9Sstevel@tonic-gate 	}
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate /*
16137c478bd9Sstevel@tonic-gate  * An extension of write() or sendto() that keeps trying until either the full
16147c478bd9Sstevel@tonic-gate  * request has completed or a non-EINTR error occurs. If 'to' is set to a
16157c478bd9Sstevel@tonic-gate  * non-NULL value, sendto() is extended, else write(). Returns 0 on success
16167c478bd9Sstevel@tonic-gate  * else -1.
16177c478bd9Sstevel@tonic-gate  */
16187c478bd9Sstevel@tonic-gate int
16197c478bd9Sstevel@tonic-gate safe_sendto_write(int fd, const void *buf, size_t sz, int flags,
16207c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen) {
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	size_t		cnt = 0;
16237c478bd9Sstevel@tonic-gate 	ssize_t		ret;
16247c478bd9Sstevel@tonic-gate 	const char	*cp = buf;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	do {
16277c478bd9Sstevel@tonic-gate 		if (to == NULL) {
16287c478bd9Sstevel@tonic-gate 			ret = write(fd, cp + cnt, sz - cnt);
16297c478bd9Sstevel@tonic-gate 		} else {
16307c478bd9Sstevel@tonic-gate 			ret = sendto(fd, cp + cnt, sz - cnt, flags, to, tolen);
16317c478bd9Sstevel@tonic-gate 		}
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 		if (ret > 0)
16347c478bd9Sstevel@tonic-gate 			cnt += ret;
16357c478bd9Sstevel@tonic-gate 	} while ((cnt != sz) && (errno == EINTR));
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	return ((cnt == sz) ? 0 : -1);
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate int
16417c478bd9Sstevel@tonic-gate safe_sendto(int fd, const void *buf, size_t sz, int flags,
16427c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen) {
16437c478bd9Sstevel@tonic-gate 	return (safe_sendto_write(fd, buf, sz, flags, to, tolen));
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate int
16477c478bd9Sstevel@tonic-gate safe_write(int fd, const void *buf, size_t sz)
16487c478bd9Sstevel@tonic-gate {
16497c478bd9Sstevel@tonic-gate 	return (safe_sendto_write(fd, buf, sz, 0, NULL, 0));
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate /*
16537c478bd9Sstevel@tonic-gate  * Free up the memory occupied by string array 'strs'.
16547c478bd9Sstevel@tonic-gate  */
16557c478bd9Sstevel@tonic-gate void
16567c478bd9Sstevel@tonic-gate destroy_strings(char **strs)
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate 	int i = 0;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	if (strs != NULL) {
16617c478bd9Sstevel@tonic-gate 		while (strs[i] != NULL)
16627c478bd9Sstevel@tonic-gate 			free(strs[i++]);
16637c478bd9Sstevel@tonic-gate 		free(strs);
16647c478bd9Sstevel@tonic-gate 	}
16657c478bd9Sstevel@tonic-gate }
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate /*
16687c478bd9Sstevel@tonic-gate  * Parse the proto list string into an allocated array of proto strings,
16697c478bd9Sstevel@tonic-gate  * returning a pointer to this array. If one of the protos is too big
16707c478bd9Sstevel@tonic-gate  * errno is set to E2BIG and NULL is returned; if memory allocation failure
16717c478bd9Sstevel@tonic-gate  * occurs errno is set to ENOMEM and NULL is returned; else on success
16727c478bd9Sstevel@tonic-gate  * a pointer the string array is returned.
16737c478bd9Sstevel@tonic-gate  */
16747c478bd9Sstevel@tonic-gate char **
16757c478bd9Sstevel@tonic-gate get_protos(const char *pstr)
16767c478bd9Sstevel@tonic-gate {
16777c478bd9Sstevel@tonic-gate 	char	*cp;
16787c478bd9Sstevel@tonic-gate 	int	i = 0;
16797c478bd9Sstevel@tonic-gate 	char	**ret = NULL;
16807c478bd9Sstevel@tonic-gate 	size_t	max_proto_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
16817c478bd9Sstevel@tonic-gate 	char	*str;
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	/* copy the parameter as strtok modifies its parameters */
16847c478bd9Sstevel@tonic-gate 	if ((str = strdup(pstr)) == NULL)
16857c478bd9Sstevel@tonic-gate 		goto malloc_failure;
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	for (cp = strtok(str, PROTO_DELIMITERS); cp != NULL;
16887c478bd9Sstevel@tonic-gate 	    cp = strtok(NULL, PROTO_DELIMITERS)) {
16897c478bd9Sstevel@tonic-gate 		char **cpp;
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 		if (strlen(cp) >= max_proto_len) {
16927c478bd9Sstevel@tonic-gate 			destroy_strings(ret);
16937c478bd9Sstevel@tonic-gate 			free(str);
16947c478bd9Sstevel@tonic-gate 			errno = E2BIG;
16957c478bd9Sstevel@tonic-gate 			return (NULL);
16967c478bd9Sstevel@tonic-gate 		}
16977c478bd9Sstevel@tonic-gate 		if ((cpp = realloc(ret, (i + 2) * sizeof (char *))) == NULL)
16987c478bd9Sstevel@tonic-gate 			goto malloc_failure;
16997c478bd9Sstevel@tonic-gate 		ret = cpp;
17007c478bd9Sstevel@tonic-gate 		if ((cpp[i] = strdup(cp)) == NULL)
17017c478bd9Sstevel@tonic-gate 			goto malloc_failure;
17027c478bd9Sstevel@tonic-gate 		cpp[++i] = NULL;
17037c478bd9Sstevel@tonic-gate 	}
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	free(str);
17067c478bd9Sstevel@tonic-gate 	return (ret);
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate malloc_failure:
17097c478bd9Sstevel@tonic-gate 	destroy_strings(ret);
17107c478bd9Sstevel@tonic-gate 	free(str);
17117c478bd9Sstevel@tonic-gate 	errno = ENOMEM;
17127c478bd9Sstevel@tonic-gate 	return (NULL);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate /*
17167c478bd9Sstevel@tonic-gate  * Returns an allocated string array of netids corresponding with 'proto'. The
17177c478bd9Sstevel@tonic-gate  * function first tries to interpret 'proto' as a nettype to get its netids.
17187c478bd9Sstevel@tonic-gate  * If this fails it tries to interpret it as a netid. If 'proto' is neither
17197c478bd9Sstevel@tonic-gate  * a nettype or a netid or a memory allocation failures occurs NULL is
17207c478bd9Sstevel@tonic-gate  * returned, else a pointer to an array of netids associated with 'proto' is
17217c478bd9Sstevel@tonic-gate  * returned.
17227c478bd9Sstevel@tonic-gate  */
17237c478bd9Sstevel@tonic-gate char **
17247c478bd9Sstevel@tonic-gate get_netids(char *proto)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	void			*handle;
17277c478bd9Sstevel@tonic-gate 	struct netconfig	*nconf;
17287c478bd9Sstevel@tonic-gate 	char			**netids = NULL;
17297c478bd9Sstevel@tonic-gate 	char			**cpp;
17307c478bd9Sstevel@tonic-gate 	int			i = 0;
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	if (strcmp(proto, "*") == 0)
17337c478bd9Sstevel@tonic-gate 		proto = "visible";
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	if ((handle = __rpc_setconf(proto)) != NULL) {
17367c478bd9Sstevel@tonic-gate 		/* expand nettype */
17377c478bd9Sstevel@tonic-gate 		while ((nconf = __rpc_getconf(handle)) != NULL) {
17387c478bd9Sstevel@tonic-gate 			if ((cpp = realloc(netids,
17397c478bd9Sstevel@tonic-gate 			    (i + 2) * sizeof (char *))) == NULL)
17407c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
17417c478bd9Sstevel@tonic-gate 			netids = cpp;
17427c478bd9Sstevel@tonic-gate 			if ((cpp[i] = strdup(nconf->nc_netid)) == NULL)
17437c478bd9Sstevel@tonic-gate 				goto failure_cleanup;
17447c478bd9Sstevel@tonic-gate 			cpp[++i] = NULL;
17457c478bd9Sstevel@tonic-gate 		}
17467c478bd9Sstevel@tonic-gate 		__rpc_endconf(handle);
17477c478bd9Sstevel@tonic-gate 	} else {
17487c478bd9Sstevel@tonic-gate 		if ((netids = malloc(2 * sizeof (char *))) == NULL)
17497c478bd9Sstevel@tonic-gate 			return (NULL);
17507c478bd9Sstevel@tonic-gate 		if ((netids[0] = strdup(proto)) == NULL) {
17517c478bd9Sstevel@tonic-gate 			free(netids);
17527c478bd9Sstevel@tonic-gate 			return (NULL);
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 		netids[1] = NULL;
17557c478bd9Sstevel@tonic-gate 	}
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	return (netids);
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate failure_cleanup:
17607c478bd9Sstevel@tonic-gate 	destroy_strings(netids);
17617c478bd9Sstevel@tonic-gate 	__rpc_endconf(handle);
17627c478bd9Sstevel@tonic-gate 	return (NULL);
17637c478bd9Sstevel@tonic-gate }
1764