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