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