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