Home | History | Annotate | Download | only in common
      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 2007 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 	{PR_CONNECTION_BACKLOG_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER,
    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