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