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