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