17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 586b1a8baSrotondo * Common Development and Distribution License (the "License"). 686b1a8baSrotondo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*e23de8e2SGary Mills * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This library contains a set of routines that are shared amongst inetd, 287c478bd9Sstevel@tonic-gate * inetadm, inetconv and the formerly internal inetd services. Amongst the 297c478bd9Sstevel@tonic-gate * routines are ones for reading and validating the configuration of an 307c478bd9Sstevel@tonic-gate * inetd service, a routine for requesting inetd be refreshed, ones for 317c478bd9Sstevel@tonic-gate * reading, calculating and writing the hash of an inetd.conf file, and 327c478bd9Sstevel@tonic-gate * numerous utility routines shared amongst the formerly internal inetd 337c478bd9Sstevel@tonic-gate * services. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h> 397c478bd9Sstevel@tonic-gate #include <netdb.h> 407c478bd9Sstevel@tonic-gate #include <limits.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <inetsvc.h> 437c478bd9Sstevel@tonic-gate #include <stdlib.h> 447c478bd9Sstevel@tonic-gate #include <unistd.h> 457c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h> 467c478bd9Sstevel@tonic-gate #include <stdio.h> 477c478bd9Sstevel@tonic-gate #include <fcntl.h> 487c478bd9Sstevel@tonic-gate #include <pwd.h> 497c478bd9Sstevel@tonic-gate #include <md5.h> 507c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 517c478bd9Sstevel@tonic-gate #include <netinet/in.h> 527c478bd9Sstevel@tonic-gate #include <signal.h> 537c478bd9Sstevel@tonic-gate #include <syslog.h> 547c478bd9Sstevel@tonic-gate #include <libintl.h> 557c478bd9Sstevel@tonic-gate #include <stdlib.h> 567c478bd9Sstevel@tonic-gate #include <assert.h> 577c478bd9Sstevel@tonic-gate #include <rpc/nettype.h> 587c478bd9Sstevel@tonic-gate #include <libuutil.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static inetd_prop_t inetd_properties[] = { 61ba1637f8Smh138676 {PR_SVC_NAME_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING, 627c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 63ba1637f8Smh138676 {PR_SOCK_TYPE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING, 647c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 65ba1637f8Smh138676 {PR_PROTO_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING_LIST, 667c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 67ba1637f8Smh138676 {PR_ISRPC_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 687c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 69ba1637f8Smh138676 {PR_RPC_LW_VER_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 707c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 71ba1637f8Smh138676 {PR_RPC_HI_VER_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 727c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 73ba1637f8Smh138676 {PR_ISWAIT_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 747c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 75ba1637f8Smh138676 {PR_EXEC_NAME, START_METHOD_NAME, INET_TYPE_STRING, 767c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 77ba1637f8Smh138676 {PR_ARG0_NAME, START_METHOD_NAME, INET_TYPE_STRING, 787c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 79ba1637f8Smh138676 {PR_USER_NAME, START_METHOD_NAME, INET_TYPE_STRING, 807c478bd9Sstevel@tonic-gate B_FALSE, IVE_UNSET, NULL, B_FALSE}, 81ba1637f8Smh138676 {PR_BIND_ADDR_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_STRING, 827c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 83ba1637f8Smh138676 {PR_BIND_FAIL_MAX_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 847c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 85ba1637f8Smh138676 {PR_BIND_FAIL_INTVL_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 867c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 87ba1637f8Smh138676 {PR_CON_RATE_MAX_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 887c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 89ba1637f8Smh138676 {PR_MAX_COPIES_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 907c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 91ba1637f8Smh138676 {PR_CON_RATE_OFFLINE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 927c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 93ba1637f8Smh138676 {PR_MAX_FAIL_RATE_CNT_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 947c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 95ba1637f8Smh138676 {PR_MAX_FAIL_RATE_INTVL_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 967c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 97ba1637f8Smh138676 {PR_INHERIT_ENV_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 987c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 99ba1637f8Smh138676 {PR_DO_TCP_TRACE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 1007c478bd9Sstevel@tonic-gate B_TRUE, IVE_UNSET, NULL, B_FALSE}, 101ba1637f8Smh138676 {PR_DO_TCP_WRAPPERS_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 102ba1637f8Smh138676 B_TRUE, IVE_UNSET, NULL, B_FALSE}, 103fff9db26Svp157776 {PR_CONNECTION_BACKLOG_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_INTEGER, 104fff9db26Svp157776 B_TRUE, IVE_UNSET, NULL, B_FALSE}, 105*e23de8e2SGary Mills {PR_DO_TCP_KEEPALIVE_NAME, PG_NAME_SERVICE_CONFIG, INET_TYPE_BOOLEAN, 106*e23de8e2SGary Mills B_TRUE, IVE_UNSET, NULL, B_FALSE}, 107ba1637f8Smh138676 {NULL}, 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate #define INETSVC_SVC_BUF_MAX (NSS_BUFLEN_RPC + sizeof (struct rpcent)) 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate #define DIGEST_LEN 16 1137c478bd9Sstevel@tonic-gate #define READ_BUFSIZ 8192 1147c478bd9Sstevel@tonic-gate #define HASH_PG "hash" 1157c478bd9Sstevel@tonic-gate #define HASH_PROP "md5sum" 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * Inactivity timer used by dg_template(). After this many seconds of network 1197c478bd9Sstevel@tonic-gate * inactivity dg_template will cease listening for new datagrams and return. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate #define DG_INACTIVITY_TIMEOUT 60 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static boolean_t v6_proto(const char *); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate boolean_t 1267c478bd9Sstevel@tonic-gate is_tlx_service(inetd_prop_t *props) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate return ((strcmp(SOCKTYPE_TLI_STR, 129ba1637f8Smh138676 props[PT_SOCK_TYPE_INDEX].ip_value.iv_string) == 0) || 1307c478bd9Sstevel@tonic-gate (strcmp(SOCKTYPE_XTI_STR, 131ba1637f8Smh138676 props[PT_SOCK_TYPE_INDEX].ip_value.iv_string) == 0)); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * Return a reference to the property table. Number of entries in table 1367c478bd9Sstevel@tonic-gate * are returned in num_elements argument. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate inetd_prop_t * 1397c478bd9Sstevel@tonic-gate get_prop_table(size_t *num_elements) 1407c478bd9Sstevel@tonic-gate { 141ba1637f8Smh138676 *num_elements = sizeof (inetd_properties) / sizeof (inetd_prop_t); 1427c478bd9Sstevel@tonic-gate return (&inetd_properties[0]); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 146ba1637f8Smh138676 * find_prop takes an array of inetd_prop_t's, the name of an inetd 147ba1637f8Smh138676 * property, the type expected, and returns a pointer to the matching member, 148ba1637f8Smh138676 * or NULL. 1497c478bd9Sstevel@tonic-gate */ 150ba1637f8Smh138676 inetd_prop_t * 151ba1637f8Smh138676 find_prop(const inetd_prop_t *prop, const char *name, inet_type_t type) 1527c478bd9Sstevel@tonic-gate { 153ba1637f8Smh138676 int i = 0; 1547c478bd9Sstevel@tonic-gate 155ba1637f8Smh138676 while (prop[i].ip_name != NULL && strcmp(name, prop[i].ip_name) != 0) 156ba1637f8Smh138676 i++; 1577c478bd9Sstevel@tonic-gate 158ba1637f8Smh138676 if (prop[i].ip_name == NULL) 1597c478bd9Sstevel@tonic-gate return (NULL); 160ba1637f8Smh138676 161ba1637f8Smh138676 if (prop[i].ip_type != type) 162ba1637f8Smh138676 return (NULL); 163ba1637f8Smh138676 164ba1637f8Smh138676 return ((inetd_prop_t *)prop + i); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 168ba1637f8Smh138676 * get_prop_value_int takes an array of inetd_prop_t's together with the name of 169ba1637f8Smh138676 * an inetd property and returns the value of the property. It's expected that 170ba1637f8Smh138676 * the property exists in the searched array. 1717c478bd9Sstevel@tonic-gate */ 172ba1637f8Smh138676 int64_t 173ba1637f8Smh138676 get_prop_value_int(const inetd_prop_t *prop, const char *name) 1747c478bd9Sstevel@tonic-gate { 175ba1637f8Smh138676 inetd_prop_t *p; 1767c478bd9Sstevel@tonic-gate 177ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_INTEGER); 178ba1637f8Smh138676 return (p->ip_value.iv_int); 179ba1637f8Smh138676 } 180ba1637f8Smh138676 181ba1637f8Smh138676 /* 182ba1637f8Smh138676 * get_prop_value_count takes an array of inetd_prop_t's together with the name 183ba1637f8Smh138676 * of an inetd property and returns the value of the property. It's expected 184ba1637f8Smh138676 * that the property exists in the searched array. 185ba1637f8Smh138676 */ 186ba1637f8Smh138676 uint64_t 187ba1637f8Smh138676 get_prop_value_count(const inetd_prop_t *prop, const char *name) 188ba1637f8Smh138676 { 189ba1637f8Smh138676 inetd_prop_t *p; 190ba1637f8Smh138676 191ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_COUNT); 192ba1637f8Smh138676 return (p->ip_value.iv_cnt); 193ba1637f8Smh138676 } 194ba1637f8Smh138676 195ba1637f8Smh138676 /* 196ba1637f8Smh138676 * get_prop_value_boolean takes an array of inetd_prop_t's together with the 197ba1637f8Smh138676 * name of an inetd property and returns the value of the property. It's 198ba1637f8Smh138676 * expected that the property exists in the searched array. 199ba1637f8Smh138676 */ 200ba1637f8Smh138676 boolean_t 201ba1637f8Smh138676 get_prop_value_boolean(const inetd_prop_t *prop, const char *name) 202ba1637f8Smh138676 { 203ba1637f8Smh138676 inetd_prop_t *p; 204ba1637f8Smh138676 205ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_BOOLEAN); 206ba1637f8Smh138676 return (p->ip_value.iv_boolean); 207ba1637f8Smh138676 } 208ba1637f8Smh138676 209ba1637f8Smh138676 /* 210ba1637f8Smh138676 * get_prop_value_string takes an array of inetd_prop_t's together with 211ba1637f8Smh138676 * the name of an inetd property and returns the value of the property. 212ba1637f8Smh138676 * It's expected that the property exists in the searched array. 213ba1637f8Smh138676 */ 214ba1637f8Smh138676 const char * 215ba1637f8Smh138676 get_prop_value_string(const inetd_prop_t *prop, const char *name) 216ba1637f8Smh138676 { 217ba1637f8Smh138676 inetd_prop_t *p; 218ba1637f8Smh138676 219ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_STRING); 220ba1637f8Smh138676 return (p->ip_value.iv_string); 221ba1637f8Smh138676 } 222ba1637f8Smh138676 223ba1637f8Smh138676 /* 224ba1637f8Smh138676 * get_prop_value_string_list takes an array of inetd_prop_t's together 225ba1637f8Smh138676 * with the name of an inetd property and returns the value of the property. 226ba1637f8Smh138676 * It's expected that the property exists in the searched array. 227ba1637f8Smh138676 */ 228ba1637f8Smh138676 const char ** 229ba1637f8Smh138676 get_prop_value_string_list(const inetd_prop_t *prop, const char *name) 230ba1637f8Smh138676 { 231ba1637f8Smh138676 inetd_prop_t *p; 232ba1637f8Smh138676 233ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_STRING_LIST); 234ba1637f8Smh138676 return ((const char **)p->ip_value.iv_string_list); 235ba1637f8Smh138676 } 236ba1637f8Smh138676 237ba1637f8Smh138676 /* 238ba1637f8Smh138676 * put_prop_value_int takes an array of inetd_prop_t's, a name of an inetd 239ba1637f8Smh138676 * property, and a value. It copies the value into the property 240ba1637f8Smh138676 * in the array. It's expected that the property exists in the searched array. 241ba1637f8Smh138676 */ 242ba1637f8Smh138676 void 243ba1637f8Smh138676 put_prop_value_int(inetd_prop_t *prop, const char *name, int64_t value) 244ba1637f8Smh138676 { 245ba1637f8Smh138676 inetd_prop_t *p; 246ba1637f8Smh138676 247ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_INTEGER); 248ba1637f8Smh138676 p->ip_value.iv_int = value; 249ba1637f8Smh138676 p->ip_error = IVE_VALID; 250ba1637f8Smh138676 } 251ba1637f8Smh138676 252ba1637f8Smh138676 /* 253ba1637f8Smh138676 * put_prop_value_count takes an array of inetd_prop_t's, a name of an inetd 254ba1637f8Smh138676 * property, and a value. It copies the value into the property 255ba1637f8Smh138676 * in the array. It's expected that the property exists in the searched array. 256ba1637f8Smh138676 */ 257ba1637f8Smh138676 void 258ba1637f8Smh138676 put_prop_value_count(inetd_prop_t *prop, const char *name, uint64_t value) 259ba1637f8Smh138676 { 260ba1637f8Smh138676 inetd_prop_t *p; 261ba1637f8Smh138676 262ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_COUNT); 263ba1637f8Smh138676 p->ip_value.iv_cnt = value; 264ba1637f8Smh138676 p->ip_error = IVE_VALID; 265ba1637f8Smh138676 } 266ba1637f8Smh138676 267ba1637f8Smh138676 /* 268ba1637f8Smh138676 * put_prop_value_boolean takes an array of inetd_prop_t's, a name of an inetd 269ba1637f8Smh138676 * property, and a value. It copies the value into the property 270ba1637f8Smh138676 * in the array. It's expected that the property exists in the searched array. 271ba1637f8Smh138676 */ 272ba1637f8Smh138676 void 273ba1637f8Smh138676 put_prop_value_boolean(inetd_prop_t *prop, const char *name, boolean_t value) 274ba1637f8Smh138676 { 275ba1637f8Smh138676 inetd_prop_t *p; 276ba1637f8Smh138676 277ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_BOOLEAN); 278ba1637f8Smh138676 p->ip_value.iv_boolean = value; 279ba1637f8Smh138676 p->ip_error = IVE_VALID; 280ba1637f8Smh138676 } 281ba1637f8Smh138676 282ba1637f8Smh138676 /* 283ba1637f8Smh138676 * put_prop_value_string takes an array of inetd_prop_t's, a name of an inetd 284ba1637f8Smh138676 * property, and a value. It duplicates the value into the property 285ba1637f8Smh138676 * in the array, and returns B_TRUE for success and B_FALSE for failure. It's 286ba1637f8Smh138676 * expected that the property exists in the searched array. 287ba1637f8Smh138676 */ 288ba1637f8Smh138676 boolean_t 289ba1637f8Smh138676 put_prop_value_string(inetd_prop_t *prop, const char *name, const char *value) 290ba1637f8Smh138676 { 291ba1637f8Smh138676 inetd_prop_t *p; 292ba1637f8Smh138676 293ba1637f8Smh138676 if (strlen(value) >= scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) { 2947c478bd9Sstevel@tonic-gate errno = E2BIG; 295ba1637f8Smh138676 return (B_FALSE); 2967c478bd9Sstevel@tonic-gate } 297ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_STRING); 298ba1637f8Smh138676 if ((p->ip_value.iv_string = strdup(value)) == NULL) 299ba1637f8Smh138676 return (B_FALSE); 300ba1637f8Smh138676 p->ip_error = IVE_VALID; 301ba1637f8Smh138676 return (B_TRUE); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 304ba1637f8Smh138676 /* 305ba1637f8Smh138676 * put_prop_value_string_list takes an array of inetd_prop_t's, a name of an 306ba1637f8Smh138676 * inetd property, and a value. It copies the value into the property 307ba1637f8Smh138676 * in the array. It's expected that the property exists in the searched array. 308ba1637f8Smh138676 */ 309ba1637f8Smh138676 void 310ba1637f8Smh138676 put_prop_value_string_list(inetd_prop_t *prop, const char *name, char **value) 311ba1637f8Smh138676 { 312ba1637f8Smh138676 inetd_prop_t *p; 313ba1637f8Smh138676 314ba1637f8Smh138676 p = find_prop(prop, name, INET_TYPE_STRING_LIST); 315ba1637f8Smh138676 p->ip_value.iv_string_list = value; 316ba1637f8Smh138676 p->ip_error = IVE_VALID; 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate static void 3207c478bd9Sstevel@tonic-gate destroy_rpc_info(rpc_info_t *rpc) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate if (rpc != NULL) { 3237c478bd9Sstevel@tonic-gate free(rpc->netbuf.buf); 3247c478bd9Sstevel@tonic-gate free(rpc->netid); 3257c478bd9Sstevel@tonic-gate free(rpc); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * If 'proto' is a valid netid, and no memory allocations fail, returns a 3317c478bd9Sstevel@tonic-gate * pointer to an allocated and initialized rpc_info_t, else NULL. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate static rpc_info_t * 3347c478bd9Sstevel@tonic-gate create_rpc_info(const char *proto, int pnum, int low_ver, int high_ver) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate struct netconfig *nconf; 3377c478bd9Sstevel@tonic-gate rpc_info_t *ret; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if ((ret = calloc(1, sizeof (rpc_info_t))) == NULL) 3407c478bd9Sstevel@tonic-gate return (NULL); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate ret->netbuf.maxlen = sizeof (struct sockaddr_storage); 3437c478bd9Sstevel@tonic-gate if ((ret->netbuf.buf = malloc(ret->netbuf.maxlen)) == NULL) { 3447c478bd9Sstevel@tonic-gate free(ret); 3457c478bd9Sstevel@tonic-gate return (NULL); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate ret->prognum = pnum; 3497c478bd9Sstevel@tonic-gate ret->lowver = low_ver; 3507c478bd9Sstevel@tonic-gate ret->highver = high_ver; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if ((ret->netid = strdup(proto)) == NULL) { 3537c478bd9Sstevel@tonic-gate destroy_rpc_info(ret); 3547c478bd9Sstevel@tonic-gate return (NULL); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Determine whether this is a loopback transport. If getnetconfigent() 3597c478bd9Sstevel@tonic-gate * fails, we check to see whether it was the result of a v6 proto 3607c478bd9Sstevel@tonic-gate * being specified and no IPv6 interface was configured on the system; 3617c478bd9Sstevel@tonic-gate * if this holds, we know it must not be a loopback transport, else 3627c478bd9Sstevel@tonic-gate * getnetconfigent() must be miss-behaving, so return an error. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate if ((nconf = getnetconfigent(proto)) != NULL) { 3657c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) 3667c478bd9Sstevel@tonic-gate ret->is_loopback = B_TRUE; 3677c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 3687c478bd9Sstevel@tonic-gate } else if (!v6_proto(proto)) { 3697c478bd9Sstevel@tonic-gate destroy_rpc_info(ret); 3707c478bd9Sstevel@tonic-gate return (NULL); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate return (ret); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate void 3777c478bd9Sstevel@tonic-gate destroy_tlx_info(tlx_info_t *tlx) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate tlx_conn_ind_t *ci; 3807c478bd9Sstevel@tonic-gate void *cookie = NULL; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (tlx == NULL) 3837c478bd9Sstevel@tonic-gate return; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate free(tlx->dev_name); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (tlx->conn_ind_queue != NULL) { 3887c478bd9Sstevel@tonic-gate /* free up conn ind queue */ 3897c478bd9Sstevel@tonic-gate while ((ci = uu_list_teardown(tlx->conn_ind_queue, &cookie)) != 3907c478bd9Sstevel@tonic-gate NULL) { 3917c478bd9Sstevel@tonic-gate (void) t_free((char *)ci->call, T_CALL); 3927c478bd9Sstevel@tonic-gate free(ci); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate uu_list_destroy(tlx->conn_ind_queue); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate free(tlx->local_addr.buf); 3987c478bd9Sstevel@tonic-gate free(tlx); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Allocate, initialize and return a pointer to a tlx_info_t structure. 4037c478bd9Sstevel@tonic-gate * On memory allocation failure NULL is returned. 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate static tlx_info_t * 4067c478bd9Sstevel@tonic-gate create_tlx_info(const char *proto, uu_list_pool_t *conn_ind_pool) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate size_t sz; 4097c478bd9Sstevel@tonic-gate tlx_info_t *ret; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if ((ret = calloc(1, sizeof (tlx_info_t))) == NULL) 4127c478bd9Sstevel@tonic-gate return (NULL); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate ret->local_addr.maxlen = sizeof (struct sockaddr_storage); 4157c478bd9Sstevel@tonic-gate if ((ret->local_addr.buf = calloc(1, ret->local_addr.maxlen)) == NULL) 4167c478bd9Sstevel@tonic-gate goto fail; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if ((ret->conn_ind_queue = uu_list_create(conn_ind_pool, NULL, 0)) == 4197c478bd9Sstevel@tonic-gate NULL) 4207c478bd9Sstevel@tonic-gate goto fail; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate ret->local_addr.len = sizeof (struct sockaddr_in); 4237c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 4247c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)(ret->local_addr.buf))->sin_family = AF_INET; 4257c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 4267c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)(ret->local_addr.buf))->sin_addr.s_addr = 4277c478bd9Sstevel@tonic-gate htonl(INADDR_ANY); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* store device name, constructing if necessary */ 4307c478bd9Sstevel@tonic-gate if (proto[0] != '/') { 4317c478bd9Sstevel@tonic-gate sz = strlen("/dev/") + strlen(proto) + 1; 4327c478bd9Sstevel@tonic-gate if ((ret->dev_name = malloc(sz)) == NULL) 4337c478bd9Sstevel@tonic-gate goto fail; 4347c478bd9Sstevel@tonic-gate (void) snprintf(ret->dev_name, sz, "/dev/%s", proto); 4357c478bd9Sstevel@tonic-gate } else if ((ret->dev_name = strdup(proto)) == NULL) { 4367c478bd9Sstevel@tonic-gate goto fail; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate return (ret); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate fail: 4427c478bd9Sstevel@tonic-gate destroy_tlx_info(ret); 4437c478bd9Sstevel@tonic-gate return (NULL); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Returns B_TRUE if this is a v6 protocol valid for both TLI and socket 4487c478bd9Sstevel@tonic-gate * based services, else B_FALSE. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate static boolean_t 4517c478bd9Sstevel@tonic-gate v6_proto(const char *proto) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate return ((strcmp(proto, SOCKET_PROTO_TCP6) == 0) || 4547c478bd9Sstevel@tonic-gate (strcmp(proto, SOCKET_PROTO_UDP6) == 0)); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * Returns B_TRUE if this is a valid v6 protocol for a socket based service, 4597c478bd9Sstevel@tonic-gate * else B_FALSE. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate static boolean_t 4627c478bd9Sstevel@tonic-gate v6_socket_proto(const char *proto) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate return ((strcmp(proto, SOCKET_PROTO_SCTP6) == 0) || 4657c478bd9Sstevel@tonic-gate v6_proto(proto)); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate static boolean_t 4707c478bd9Sstevel@tonic-gate valid_socket_proto(const char *proto) 4717c478bd9Sstevel@tonic-gate { 4727c478bd9Sstevel@tonic-gate return (v6_socket_proto(proto) || 4737c478bd9Sstevel@tonic-gate (strcmp(proto, SOCKET_PROTO_SCTP) == 0) || 4747c478bd9Sstevel@tonic-gate (strcmp(proto, SOCKET_PROTO_TCP) == 0) || 4757c478bd9Sstevel@tonic-gate (strcmp(proto, SOCKET_PROTO_UDP) == 0)); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * Free all the memory consumed by 'pi' associated with the instance 4807c478bd9Sstevel@tonic-gate * with configuration 'cfg'. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate static void 4837c478bd9Sstevel@tonic-gate destroy_proto_info(basic_cfg_t *cfg, proto_info_t *pi) 4847c478bd9Sstevel@tonic-gate { 4857c478bd9Sstevel@tonic-gate if (pi == NULL) 4867c478bd9Sstevel@tonic-gate return; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate assert(pi->listen_fd == -1); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate free(pi->proto); 4917c478bd9Sstevel@tonic-gate if (pi->ri != NULL) 4927c478bd9Sstevel@tonic-gate destroy_rpc_info(pi->ri); 4937c478bd9Sstevel@tonic-gate if (cfg->istlx) { 4947c478bd9Sstevel@tonic-gate destroy_tlx_info((tlx_info_t *)pi); 4957c478bd9Sstevel@tonic-gate } else { 4967c478bd9Sstevel@tonic-gate free(pi); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate void 5017c478bd9Sstevel@tonic-gate destroy_proto_list(basic_cfg_t *cfg) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate void *cookie = NULL; 5047c478bd9Sstevel@tonic-gate proto_info_t *pi; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (cfg->proto_list == NULL) 5077c478bd9Sstevel@tonic-gate return; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate while ((pi = uu_list_teardown(cfg->proto_list, &cookie)) != NULL) 5107c478bd9Sstevel@tonic-gate destroy_proto_info(cfg, pi); 5117c478bd9Sstevel@tonic-gate uu_list_destroy(cfg->proto_list); 5127c478bd9Sstevel@tonic-gate cfg->proto_list = NULL; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate void 5167c478bd9Sstevel@tonic-gate destroy_basic_cfg(basic_cfg_t *cfg) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate if (cfg == NULL) 5197c478bd9Sstevel@tonic-gate return; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate free(cfg->bind_addr); 5227c478bd9Sstevel@tonic-gate destroy_proto_list(cfg); 5237c478bd9Sstevel@tonic-gate free(cfg->svc_name); 5247c478bd9Sstevel@tonic-gate free(cfg); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* 52886b1a8baSrotondo * Overwrite the socket address with the address specified by the 52986b1a8baSrotondo * bind_addr property. 53086b1a8baSrotondo */ 53186b1a8baSrotondo static int 53286b1a8baSrotondo set_bind_addr(struct sockaddr_storage *ss, char *bind_addr) 53386b1a8baSrotondo { 53486b1a8baSrotondo struct addrinfo hints, *res; 53586b1a8baSrotondo 53686b1a8baSrotondo if (bind_addr == NULL || bind_addr[0] == '\0') 53786b1a8baSrotondo return (0); 53886b1a8baSrotondo 53986b1a8baSrotondo (void) memset(&hints, 0, sizeof (hints)); 54086b1a8baSrotondo hints.ai_flags = AI_DEFAULT; 54186b1a8baSrotondo hints.ai_socktype = SOCK_STREAM; 54286b1a8baSrotondo hints.ai_family = ss->ss_family; 54386b1a8baSrotondo if (getaddrinfo(bind_addr, "", &hints, &res) != 0) { 54486b1a8baSrotondo return (-1); 54586b1a8baSrotondo } else { 54686b1a8baSrotondo void *p = res->ai_addr; 54786b1a8baSrotondo struct sockaddr_storage *newss = p; 54886b1a8baSrotondo 54986b1a8baSrotondo (void) memcpy(SS_SINADDR(*ss), SS_SINADDR(*newss), 55086b1a8baSrotondo SS_ADDRLEN(*ss)); 55186b1a8baSrotondo freeaddrinfo(res); 55286b1a8baSrotondo return (0); 55386b1a8baSrotondo } 55486b1a8baSrotondo } 55586b1a8baSrotondo 55686b1a8baSrotondo /* 5577c478bd9Sstevel@tonic-gate * valid_props validates all the properties in an array of inetd_prop_t's, 5587c478bd9Sstevel@tonic-gate * marking each property as valid or invalid. If any properties are invalid, 5597c478bd9Sstevel@tonic-gate * it returns B_FALSE, otherwise it returns B_TRUE. Note that some properties 5607c478bd9Sstevel@tonic-gate * are interdependent, so if one is invalid, it leaves others in an 5617c478bd9Sstevel@tonic-gate * indeterminate state (such as ISRPC and SVC_NAME). In this case, the 5627c478bd9Sstevel@tonic-gate * indeterminate property will be marked valid. IE, the only properties 5637c478bd9Sstevel@tonic-gate * marked invalid are those that are KNOWN to be invalid. 5647c478bd9Sstevel@tonic-gate * 5657c478bd9Sstevel@tonic-gate * Piggy-backed onto this validation if 'fmri' is non-NULL is the construction 5667c478bd9Sstevel@tonic-gate * of a structured configuration, a basic_cfg_t, which is used by inetd. 5677c478bd9Sstevel@tonic-gate * If 'fmri' is set then the latter three parameters need to be set to 5687c478bd9Sstevel@tonic-gate * non-NULL values, and if the configuration is valid, the storage referenced 5697c478bd9Sstevel@tonic-gate * by cfgpp is set to point at an initialized basic_cfg_t. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate boolean_t 5727c478bd9Sstevel@tonic-gate valid_props(inetd_prop_t *prop, const char *fmri, basic_cfg_t **cfgpp, 5737c478bd9Sstevel@tonic-gate uu_list_pool_t *proto_info_pool, uu_list_pool_t *tlx_ci_pool) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate char *bufp, *cp; 5767c478bd9Sstevel@tonic-gate boolean_t ret = B_TRUE; 5777c478bd9Sstevel@tonic-gate int i; 5787c478bd9Sstevel@tonic-gate long uidl; 5797c478bd9Sstevel@tonic-gate boolean_t isrpc; 5807c478bd9Sstevel@tonic-gate int sock_type_id; 5817c478bd9Sstevel@tonic-gate int rpc_pnum; 5827c478bd9Sstevel@tonic-gate int rpc_lv, rpc_hv; 5837c478bd9Sstevel@tonic-gate basic_cfg_t *cfg; 5847c478bd9Sstevel@tonic-gate char *proto = NULL; 5857c478bd9Sstevel@tonic-gate int pi; 5867c478bd9Sstevel@tonic-gate char **netids = NULL; 5877c478bd9Sstevel@tonic-gate int ni = 0; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (fmri != NULL) 5907c478bd9Sstevel@tonic-gate assert((cfgpp != NULL) && (proto_info_pool != NULL) && 5917c478bd9Sstevel@tonic-gate (tlx_ci_pool != NULL)); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Set all checkable properties to valid as a baseline. We'll be 5957c478bd9Sstevel@tonic-gate * marking all invalid properties. 5967c478bd9Sstevel@tonic-gate */ 597ba1637f8Smh138676 for (i = 0; prop[i].ip_name != NULL; i++) { 5987c478bd9Sstevel@tonic-gate if (prop[i].ip_error != IVE_UNSET) 5997c478bd9Sstevel@tonic-gate prop[i].ip_error = IVE_VALID; 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (((cfg = calloc(1, sizeof (basic_cfg_t))) == NULL) || 6037c478bd9Sstevel@tonic-gate ((fmri != NULL) && 6047c478bd9Sstevel@tonic-gate ((cfg->proto_list = uu_list_create(proto_info_pool, NULL, 0)) == 6057c478bd9Sstevel@tonic-gate NULL))) { 6067c478bd9Sstevel@tonic-gate free(cfg); 6077c478bd9Sstevel@tonic-gate return (B_FALSE); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* Check a service name was supplied */ 6117c478bd9Sstevel@tonic-gate if ((prop[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) || 6127c478bd9Sstevel@tonic-gate ((cfg->svc_name = 613ba1637f8Smh138676 strdup(prop[PT_SVC_NAME_INDEX].ip_value.iv_string)) == NULL)) 6147c478bd9Sstevel@tonic-gate prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* Check that iswait and isrpc have valid boolean values */ 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_UNSET) || 6197c478bd9Sstevel@tonic-gate (((cfg->iswait = prop[PT_ISWAIT_INDEX].ip_value.iv_boolean) != 6207c478bd9Sstevel@tonic-gate B_TRUE) && (cfg->iswait != B_FALSE))) 6217c478bd9Sstevel@tonic-gate prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate if ((prop[PT_ISRPC_INDEX].ip_error == IVE_UNSET) || 6247c478bd9Sstevel@tonic-gate (((isrpc = prop[PT_ISRPC_INDEX].ip_value.iv_boolean) != B_TRUE) && 6257c478bd9Sstevel@tonic-gate (isrpc != B_FALSE))) { 6267c478bd9Sstevel@tonic-gate prop[PT_ISRPC_INDEX].ip_error = IVE_INVALID; 6277c478bd9Sstevel@tonic-gate } else if (isrpc) { 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * This is an RPC service, so ensure that the RPC version 6307c478bd9Sstevel@tonic-gate * numbers are zero or greater, that the low version isn't 6317c478bd9Sstevel@tonic-gate * greater than the high version and a valid program name 6327c478bd9Sstevel@tonic-gate * is supplied. 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate if ((prop[PT_RPC_LW_VER_INDEX].ip_error == IVE_UNSET) || 6367c478bd9Sstevel@tonic-gate ((rpc_lv = prop[PT_RPC_LW_VER_INDEX].ip_value.iv_int) < 6377c478bd9Sstevel@tonic-gate 0)) 6387c478bd9Sstevel@tonic-gate prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if ((prop[PT_RPC_HI_VER_INDEX].ip_error == IVE_UNSET) || 6417c478bd9Sstevel@tonic-gate ((rpc_hv = prop[PT_RPC_HI_VER_INDEX].ip_value.iv_int) < 6427c478bd9Sstevel@tonic-gate 0)) 6437c478bd9Sstevel@tonic-gate prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if ((prop[PT_RPC_LW_VER_INDEX].ip_error != IVE_INVALID) && 6467c478bd9Sstevel@tonic-gate (prop[PT_RPC_HI_VER_INDEX].ip_error != IVE_INVALID) && 6477c478bd9Sstevel@tonic-gate (rpc_lv > rpc_hv)) { 6487c478bd9Sstevel@tonic-gate prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID; 6497c478bd9Sstevel@tonic-gate prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID; 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate if ((cfg->svc_name != NULL) && 6537c478bd9Sstevel@tonic-gate ((rpc_pnum = get_rpc_prognum(cfg->svc_name)) == -1)) 6547c478bd9Sstevel@tonic-gate prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* Check that the socket type is one of the acceptable values. */ 6587c478bd9Sstevel@tonic-gate cfg->istlx = B_FALSE; 6597c478bd9Sstevel@tonic-gate if ((prop[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET) || 6607c478bd9Sstevel@tonic-gate ((sock_type_id = get_sock_type_id( 661ba1637f8Smh138676 prop[PT_SOCK_TYPE_INDEX].ip_value.iv_string)) == -1) && 6627c478bd9Sstevel@tonic-gate !(cfg->istlx = is_tlx_service(prop))) 6637c478bd9Sstevel@tonic-gate prop[PT_SOCK_TYPE_INDEX].ip_error = IVE_INVALID; 6647c478bd9Sstevel@tonic-gate 66586b1a8baSrotondo /* Get the bind address */ 666f60ea415Srotondo if (!cfg->istlx && prop[PT_BIND_ADDR_INDEX].ip_error != IVE_UNSET && 667f60ea415Srotondo (cfg->bind_addr = 668f60ea415Srotondo strdup(prop[PT_BIND_ADDR_INDEX].ip_value.iv_string)) == NULL) 66986b1a8baSrotondo prop[PT_BIND_ADDR_INDEX].ip_error = IVE_INVALID; 67086b1a8baSrotondo 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * Iterate through all the different protos/netids resulting from the 6737c478bd9Sstevel@tonic-gate * proto property and check that they're valid and perform checks on 6747c478bd9Sstevel@tonic-gate * other fields that are tied-in with the proto. 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate pi = 0; 6787c478bd9Sstevel@tonic-gate do { 6797c478bd9Sstevel@tonic-gate socket_info_t *si = NULL; 6807c478bd9Sstevel@tonic-gate tlx_info_t *ti = NULL; 6817c478bd9Sstevel@tonic-gate proto_info_t *p_inf = NULL; 6827c478bd9Sstevel@tonic-gate boolean_t v6only = B_FALSE; 6837c478bd9Sstevel@tonic-gate char *only; 6847c478bd9Sstevel@tonic-gate boolean_t invalid_proto = B_FALSE; 6857c478bd9Sstevel@tonic-gate char **protos; 6867c478bd9Sstevel@tonic-gate struct protoent pe; 6877c478bd9Sstevel@tonic-gate char gpbuf[1024]; 6887c478bd9Sstevel@tonic-gate struct netconfig *nconf = NULL; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * If we don't know whether it's an rpc service or its 6927c478bd9Sstevel@tonic-gate * endpoint type, we can't do any of the proto checks as we 6937c478bd9Sstevel@tonic-gate * have no context; break out. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if ((prop[PT_ISRPC_INDEX].ip_error != IVE_VALID) || 6967c478bd9Sstevel@tonic-gate (prop[PT_SOCK_TYPE_INDEX].ip_error != IVE_VALID)) 6977c478bd9Sstevel@tonic-gate break; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* skip proto specific processing if the proto isn't set. */ 7007c478bd9Sstevel@tonic-gate if (prop[PT_PROTO_INDEX].ip_error == IVE_UNSET) { 7017c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7027c478bd9Sstevel@tonic-gate goto past_proto_processing; 7037c478bd9Sstevel@tonic-gate } 704ba1637f8Smh138676 protos = prop[PT_PROTO_INDEX].ip_value.iv_string_list; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * Get the next netid/proto. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (!cfg->istlx || !isrpc) { 7117c478bd9Sstevel@tonic-gate proto = protos[pi++]; 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * This is a TLI/RPC service, so get the next netid, expanding 7147c478bd9Sstevel@tonic-gate * any supplied nettype. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate } else if ((netids == NULL) || 7177c478bd9Sstevel@tonic-gate ((proto = netids[ni++]) == NULL)) { 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * Either this is the first time around or 7207c478bd9Sstevel@tonic-gate * we've exhausted the last set of netids, so 7217c478bd9Sstevel@tonic-gate * try and get the next set using the currently 7227c478bd9Sstevel@tonic-gate * indexed proto entry. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate if (netids != NULL) { 7267c478bd9Sstevel@tonic-gate destroy_strings(netids); 7277c478bd9Sstevel@tonic-gate netids = NULL; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if (protos[pi] != NULL) { 7317c478bd9Sstevel@tonic-gate if ((netids = get_netids(protos[pi++])) == 7327c478bd9Sstevel@tonic-gate NULL) { 7337c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7347c478bd9Sstevel@tonic-gate proto = protos[pi - 1]; 7357c478bd9Sstevel@tonic-gate } else { 7367c478bd9Sstevel@tonic-gate ni = 0; 7377c478bd9Sstevel@tonic-gate proto = netids[ni++]; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate } else { 7407c478bd9Sstevel@tonic-gate proto = NULL; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 74419cf6549Sjonb if (proto == NULL) 74519cf6549Sjonb break; 74619cf6549Sjonb 74719cf6549Sjonb if (invalid_proto) 7487c478bd9Sstevel@tonic-gate goto past_proto_processing; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* strip a trailing only to simplify further processing */ 7517c478bd9Sstevel@tonic-gate only = proto + strlen(proto) - (sizeof ("6only") - 1); 7527c478bd9Sstevel@tonic-gate if ((only > proto) && (strcmp(only, "6only") == 0)) { 7537c478bd9Sstevel@tonic-gate *++only = '\0'; 7547c478bd9Sstevel@tonic-gate v6only = B_TRUE; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* validate the proto/netid */ 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate if (!cfg->istlx) { 7607c478bd9Sstevel@tonic-gate if (!valid_socket_proto(proto)) 7617c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7627c478bd9Sstevel@tonic-gate } else { 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * Check if we've got a valid netid. If 7657c478bd9Sstevel@tonic-gate * getnetconfigent() fails, we check to see whether 7667c478bd9Sstevel@tonic-gate * we've got a v6 netid that may have been rejected 7677c478bd9Sstevel@tonic-gate * because no IPv6 interface was configured before 7687c478bd9Sstevel@tonic-gate * flagging 'proto' as invalid. If the latter condition 7697c478bd9Sstevel@tonic-gate * holds, we don't flag the proto as invalid, and 7707c478bd9Sstevel@tonic-gate * leave inetd to handle the value appropriately 7717c478bd9Sstevel@tonic-gate * when it tries to listen on behalf of the service. 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate if (((nconf = getnetconfigent(proto)) == NULL) && 7747c478bd9Sstevel@tonic-gate !v6_proto(proto)) 7757c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate if (invalid_proto) 7787c478bd9Sstevel@tonic-gate goto past_proto_processing; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate /* 7817c478bd9Sstevel@tonic-gate * dissallow datagram type nowait services 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_VALID) && 7847c478bd9Sstevel@tonic-gate !cfg->iswait) { 7857c478bd9Sstevel@tonic-gate if (strncmp(proto, SOCKET_PROTO_UDP, 7867c478bd9Sstevel@tonic-gate sizeof (SOCKET_PROTO_UDP) - 1) == 0) { 7877c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7887c478bd9Sstevel@tonic-gate } else if (cfg->istlx && (nconf != NULL) && 7897c478bd9Sstevel@tonic-gate (nconf->nc_semantics == NC_TPI_CLTS)) { 7907c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate if (invalid_proto) { 7937c478bd9Sstevel@tonic-gate prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID; 7947c478bd9Sstevel@tonic-gate goto past_proto_processing; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* 7997c478bd9Sstevel@tonic-gate * We're running in validate only mode. Don't bother creating 8007c478bd9Sstevel@tonic-gate * any proto structures (they don't do any further validation). 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate if (fmri == NULL) 8037c478bd9Sstevel@tonic-gate goto past_proto_processing; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * Create the apropriate transport info structure. 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate if (cfg->istlx) { 8097c478bd9Sstevel@tonic-gate if ((ti = create_tlx_info(proto, tlx_ci_pool)) != NULL) 8107c478bd9Sstevel@tonic-gate p_inf = (proto_info_t *)ti; 8117c478bd9Sstevel@tonic-gate } else { 8127c478bd9Sstevel@tonic-gate struct sockaddr_storage *ss; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if ((si = calloc(1, sizeof (socket_info_t))) != NULL) { 8157c478bd9Sstevel@tonic-gate p_inf = (proto_info_t *)si; 8167c478bd9Sstevel@tonic-gate si->type = sock_type_id; 8177c478bd9Sstevel@tonic-gate ss = &si->local_addr; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate if (v6_socket_proto(proto)) { 8207c478bd9Sstevel@tonic-gate ss->ss_family = AF_INET6; 8217c478bd9Sstevel@tonic-gate /* already in network order */ 8227c478bd9Sstevel@tonic-gate ((struct sockaddr_in6 *)ss)->sin6_addr = 8237c478bd9Sstevel@tonic-gate in6addr_any; 8247c478bd9Sstevel@tonic-gate } else { 8257c478bd9Sstevel@tonic-gate ss->ss_family = AF_INET; 8267c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)ss)->sin_addr. 8277c478bd9Sstevel@tonic-gate s_addr = htonl(INADDR_ANY); 8287c478bd9Sstevel@tonic-gate } 82986b1a8baSrotondo if (set_bind_addr(ss, cfg->bind_addr) != 0) { 83086b1a8baSrotondo prop[PT_BIND_ADDR_INDEX].ip_error = 83186b1a8baSrotondo IVE_INVALID; 83286b1a8baSrotondo } 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate if (p_inf == NULL) { 8367c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 8377c478bd9Sstevel@tonic-gate goto past_proto_processing; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate p_inf->v6only = v6only; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * Store the supplied proto string for error reporting, 8447c478bd9Sstevel@tonic-gate * re-attaching the 'only' suffix if one was taken off. 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate if ((p_inf->proto = malloc(strlen(proto) + 5)) == NULL) { 8477c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 8487c478bd9Sstevel@tonic-gate goto past_proto_processing; 8497c478bd9Sstevel@tonic-gate } else { 8507c478bd9Sstevel@tonic-gate (void) strlcpy(p_inf->proto, proto, strlen(proto) + 5); 8517c478bd9Sstevel@tonic-gate if (v6only) 8527c478bd9Sstevel@tonic-gate (void) strlcat(p_inf->proto, "only", 8537c478bd9Sstevel@tonic-gate strlen(proto) + 5); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * Validate and setup RPC/non-RPC specifics. 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate if (isrpc) { 8617c478bd9Sstevel@tonic-gate rpc_info_t *ri; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate if ((rpc_pnum != -1) && (rpc_lv != -1) && 8647c478bd9Sstevel@tonic-gate (rpc_hv != -1)) { 8657c478bd9Sstevel@tonic-gate if ((ri = create_rpc_info(proto, rpc_pnum, 8667c478bd9Sstevel@tonic-gate rpc_lv, rpc_hv)) == NULL) { 8677c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 8687c478bd9Sstevel@tonic-gate } else { 8697c478bd9Sstevel@tonic-gate p_inf->ri = ri; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate past_proto_processing: 8757c478bd9Sstevel@tonic-gate /* validate non-RPC service name */ 8767c478bd9Sstevel@tonic-gate if (!isrpc && (cfg->svc_name != NULL)) { 8777c478bd9Sstevel@tonic-gate struct servent se; 8787c478bd9Sstevel@tonic-gate char gsbuf[NSS_BUFLEN_SERVICES]; 8797c478bd9Sstevel@tonic-gate char *gsproto = proto; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate if (invalid_proto) { 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * Make getservbyname_r do its lookup without a 8847c478bd9Sstevel@tonic-gate * proto. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate gsproto = NULL; 8877c478bd9Sstevel@tonic-gate } else if (gsproto != NULL) { 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * Since getservbyname & getprotobyname don't 8907c478bd9Sstevel@tonic-gate * support tcp6, udp6 or sctp6 take off the 6 8917c478bd9Sstevel@tonic-gate * digit from protocol. 8927c478bd9Sstevel@tonic-gate */ 8937c478bd9Sstevel@tonic-gate if (v6_socket_proto(gsproto)) 8947c478bd9Sstevel@tonic-gate gsproto[strlen(gsproto) - 1] = '\0'; 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate if (getservbyname_r(cfg->svc_name, gsproto, &se, gsbuf, 8987c478bd9Sstevel@tonic-gate sizeof (gsbuf)) == NULL) { 8997c478bd9Sstevel@tonic-gate if (gsproto != NULL) 9007c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 9017c478bd9Sstevel@tonic-gate prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; 9027c478bd9Sstevel@tonic-gate } else if (cfg->istlx && (ti != NULL)) { 9037c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 9047c478bd9Sstevel@tonic-gate SS_SETPORT(*(struct sockaddr_storage *) 9057c478bd9Sstevel@tonic-gate ti->local_addr.buf, se.s_port); 9067c478bd9Sstevel@tonic-gate } else if (!cfg->istlx && (si != NULL)) { 9077c478bd9Sstevel@tonic-gate if ((gsproto != NULL) && 9087c478bd9Sstevel@tonic-gate getprotobyname_r(gsproto, &pe, gpbuf, 9097c478bd9Sstevel@tonic-gate sizeof (gpbuf)) == NULL) { 9107c478bd9Sstevel@tonic-gate invalid_proto = B_TRUE; 9117c478bd9Sstevel@tonic-gate } else { 9127c478bd9Sstevel@tonic-gate si->protocol = pe.p_proto; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate SS_SETPORT(si->local_addr, se.s_port); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if (p_inf != NULL) { 9207c478bd9Sstevel@tonic-gate p_inf->listen_fd = -1; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate /* add new proto entry to proto_list */ 9237c478bd9Sstevel@tonic-gate uu_list_node_init(p_inf, &p_inf->link, proto_info_pool); 9247c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(cfg->proto_list, NULL, 9257c478bd9Sstevel@tonic-gate p_inf); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (nconf != NULL) 9297c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 9307c478bd9Sstevel@tonic-gate if (invalid_proto) 9317c478bd9Sstevel@tonic-gate prop[PT_PROTO_INDEX].ip_error = IVE_INVALID; 9327c478bd9Sstevel@tonic-gate } while (proto != NULL); /* while just processed a proto */ 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * Check that the exec string for the start method actually exists and 9367c478bd9Sstevel@tonic-gate * that the user is either a valid username or uid. Note we don't 9377c478bd9Sstevel@tonic-gate * mandate the setting of these fields, and don't do any checks 9387c478bd9Sstevel@tonic-gate * for arg0, hence its absence. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate if (prop[PT_EXEC_INDEX].ip_error != IVE_UNSET) { 9427c478bd9Sstevel@tonic-gate /* Don't pass any arguments to access() */ 9437c478bd9Sstevel@tonic-gate if ((bufp = strdup( 944ba1637f8Smh138676 prop[PT_EXEC_INDEX].ip_value.iv_string)) == NULL) { 9457c478bd9Sstevel@tonic-gate prop[PT_EXEC_INDEX].ip_error = IVE_INVALID; 9467c478bd9Sstevel@tonic-gate } else { 9477c478bd9Sstevel@tonic-gate if ((cp = strpbrk(bufp, " \t")) != NULL) 9487c478bd9Sstevel@tonic-gate *cp = '\0'; 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate if ((access(bufp, F_OK) == -1) && (errno == ENOENT)) 9517c478bd9Sstevel@tonic-gate prop[PT_EXEC_INDEX].ip_error = IVE_INVALID; 9527c478bd9Sstevel@tonic-gate free(bufp); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate if (prop[PT_USER_INDEX].ip_error != IVE_UNSET) { 9577c478bd9Sstevel@tonic-gate char pw_buf[NSS_BUFLEN_PASSWD]; 9587c478bd9Sstevel@tonic-gate struct passwd pw; 9597c478bd9Sstevel@tonic-gate 960ba1637f8Smh138676 if (getpwnam_r(prop[PT_USER_INDEX].ip_value.iv_string, &pw, 9617c478bd9Sstevel@tonic-gate pw_buf, NSS_BUFLEN_PASSWD) == NULL) { 9627c478bd9Sstevel@tonic-gate errno = 0; 963ba1637f8Smh138676 uidl = strtol(prop[PT_USER_INDEX].ip_value.iv_string, 9647c478bd9Sstevel@tonic-gate &bufp, 10); 9657c478bd9Sstevel@tonic-gate if ((errno != 0) || (*bufp != '\0') || 9667c478bd9Sstevel@tonic-gate (getpwuid_r(uidl, &pw, pw_buf, 9677c478bd9Sstevel@tonic-gate NSS_BUFLEN_PASSWD) == NULL)) 9687c478bd9Sstevel@tonic-gate prop[PT_USER_INDEX].ip_error = IVE_INVALID; 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Iterate through the properties in the array verifying that any 9747c478bd9Sstevel@tonic-gate * default properties are valid, and setting the return boolean 9757c478bd9Sstevel@tonic-gate * according to whether any properties were marked invalid. 9767c478bd9Sstevel@tonic-gate */ 9777c478bd9Sstevel@tonic-gate 978ba1637f8Smh138676 for (i = 0; prop[i].ip_name != NULL; i++) { 9797c478bd9Sstevel@tonic-gate if (prop[i].ip_error == IVE_UNSET) 9807c478bd9Sstevel@tonic-gate continue; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate if (prop[i].ip_default && 9837c478bd9Sstevel@tonic-gate !valid_default_prop(prop[i].ip_name, &prop[i].ip_value)) 9847c478bd9Sstevel@tonic-gate prop[i].ip_error = IVE_INVALID; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (prop[i].ip_error == IVE_INVALID) 9877c478bd9Sstevel@tonic-gate ret = B_FALSE; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* pass back the basic_cfg_t if requested and it's a valid config */ 9917c478bd9Sstevel@tonic-gate if ((cfgpp != NULL) && ret) { 9927c478bd9Sstevel@tonic-gate *cfgpp = cfg; 9937c478bd9Sstevel@tonic-gate } else { 9947c478bd9Sstevel@tonic-gate destroy_basic_cfg(cfg); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate return (ret); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * validate_default_prop takes the name of an inetd property, and a value 10027c478bd9Sstevel@tonic-gate * for that property. It returns B_TRUE if the property is valid, and B_FALSE 10037c478bd9Sstevel@tonic-gate * if the proposed value isn't valid for that property. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate boolean_t 1007ba1637f8Smh138676 valid_default_prop(const char *name, const void *value) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate int i; 10107c478bd9Sstevel@tonic-gate 1011ba1637f8Smh138676 for (i = 0; inetd_properties[i].ip_name != NULL; i++) { 10127c478bd9Sstevel@tonic-gate if (strcmp(name, inetd_properties[i].ip_name) != 0) 10137c478bd9Sstevel@tonic-gate continue; 10147c478bd9Sstevel@tonic-gate if (!inetd_properties[i].ip_default) 10157c478bd9Sstevel@tonic-gate return (B_FALSE); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate switch (inetd_properties[i].ip_type) { 1018ba1637f8Smh138676 case INET_TYPE_INTEGER: 10197c478bd9Sstevel@tonic-gate if (*((int64_t *)value) >= -1) 10207c478bd9Sstevel@tonic-gate return (B_TRUE); 10217c478bd9Sstevel@tonic-gate else 10227c478bd9Sstevel@tonic-gate return (B_FALSE); 1023ba1637f8Smh138676 case INET_TYPE_BOOLEAN: 10247c478bd9Sstevel@tonic-gate if ((*((boolean_t *)value) == B_FALSE) || 10257c478bd9Sstevel@tonic-gate (*((boolean_t *)value) == B_TRUE)) 10267c478bd9Sstevel@tonic-gate return (B_TRUE); 10277c478bd9Sstevel@tonic-gate else 10287c478bd9Sstevel@tonic-gate return (B_FALSE); 1029ba1637f8Smh138676 case INET_TYPE_COUNT: 1030ba1637f8Smh138676 case INET_TYPE_STRING_LIST: 1031ba1637f8Smh138676 case INET_TYPE_STRING: 10327c478bd9Sstevel@tonic-gate return (B_TRUE); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate return (B_FALSE); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 103986b1a8baSrotondo /*ARGSUSED*/ 10407c478bd9Sstevel@tonic-gate scf_error_t 10417c478bd9Sstevel@tonic-gate read_prop(scf_handle_t *h, inetd_prop_t *iprop, int index, const char *inst, 10427c478bd9Sstevel@tonic-gate const char *pg_name) 10437c478bd9Sstevel@tonic-gate { 10447c478bd9Sstevel@tonic-gate scf_simple_prop_t *sprop; 10457c478bd9Sstevel@tonic-gate uint8_t *tmp_bool; 10467c478bd9Sstevel@tonic-gate int64_t *tmp_int; 10477c478bd9Sstevel@tonic-gate uint64_t *tmp_cnt; 10487c478bd9Sstevel@tonic-gate char *tmp_char; 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate if ((sprop = scf_simple_prop_get(h, inst, pg_name, iprop->ip_name)) == 10517c478bd9Sstevel@tonic-gate NULL) 10527c478bd9Sstevel@tonic-gate return (scf_error()); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate switch (iprop->ip_type) { 1055ba1637f8Smh138676 case INET_TYPE_STRING: 1056ba1637f8Smh138676 if ((tmp_char = scf_simple_prop_next_astring(sprop)) == NULL) 1057ba1637f8Smh138676 goto scf_error; 1058ba1637f8Smh138676 if ((iprop->ip_value.iv_string = strdup(tmp_char)) == NULL) { 1059ba1637f8Smh138676 scf_simple_prop_free(sprop); 1060ba1637f8Smh138676 return (SCF_ERROR_NO_MEMORY); 1061ba1637f8Smh138676 } 1062ba1637f8Smh138676 break; 1063ba1637f8Smh138676 case INET_TYPE_STRING_LIST: 1064ba1637f8Smh138676 { 10657c478bd9Sstevel@tonic-gate int j = 0; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate while ((tmp_char = 10687c478bd9Sstevel@tonic-gate scf_simple_prop_next_astring(sprop)) != NULL) { 10697c478bd9Sstevel@tonic-gate char **cpp; 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if ((cpp = realloc( 1072ba1637f8Smh138676 iprop->ip_value.iv_string_list, 10737c478bd9Sstevel@tonic-gate (j + 2) * sizeof (char *))) == NULL) { 10747c478bd9Sstevel@tonic-gate scf_simple_prop_free(sprop); 10757c478bd9Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 10767c478bd9Sstevel@tonic-gate } 1077ba1637f8Smh138676 iprop->ip_value.iv_string_list = cpp; 10787c478bd9Sstevel@tonic-gate if ((cpp[j] = strdup(tmp_char)) == NULL) { 10797c478bd9Sstevel@tonic-gate scf_simple_prop_free(sprop); 10807c478bd9Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate cpp[++j] = NULL; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate if ((j == 0) || (scf_error() != SCF_ERROR_NONE)) 10857c478bd9Sstevel@tonic-gate goto scf_error; 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate break; 1088ba1637f8Smh138676 case INET_TYPE_BOOLEAN: 10897c478bd9Sstevel@tonic-gate if ((tmp_bool = scf_simple_prop_next_boolean(sprop)) == NULL) 10907c478bd9Sstevel@tonic-gate goto scf_error; 10917c478bd9Sstevel@tonic-gate iprop->ip_value.iv_boolean = 10927c478bd9Sstevel@tonic-gate (*tmp_bool == 0) ? B_FALSE : B_TRUE; 10937c478bd9Sstevel@tonic-gate break; 1094ba1637f8Smh138676 case INET_TYPE_COUNT: 10957c478bd9Sstevel@tonic-gate if ((tmp_cnt = scf_simple_prop_next_count(sprop)) == NULL) 10967c478bd9Sstevel@tonic-gate goto scf_error; 10977c478bd9Sstevel@tonic-gate iprop->ip_value.iv_cnt = *tmp_cnt; 10987c478bd9Sstevel@tonic-gate break; 1099ba1637f8Smh138676 case INET_TYPE_INTEGER: 11007c478bd9Sstevel@tonic-gate if ((tmp_int = scf_simple_prop_next_integer(sprop)) == NULL) 11017c478bd9Sstevel@tonic-gate goto scf_error; 11027c478bd9Sstevel@tonic-gate iprop->ip_value.iv_int = *tmp_int; 11037c478bd9Sstevel@tonic-gate break; 11047c478bd9Sstevel@tonic-gate default: 11057c478bd9Sstevel@tonic-gate assert(0); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate iprop->ip_error = IVE_VALID; 11097c478bd9Sstevel@tonic-gate scf_simple_prop_free(sprop); 11107c478bd9Sstevel@tonic-gate return (0); 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate scf_error: 11137c478bd9Sstevel@tonic-gate scf_simple_prop_free(sprop); 11147c478bd9Sstevel@tonic-gate if (scf_error() == SCF_ERROR_NONE) 11157c478bd9Sstevel@tonic-gate return (SCF_ERROR_NOT_FOUND); 11167c478bd9Sstevel@tonic-gate return (scf_error()); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * read_props reads either the full set of properties for instance 'instance' 11217c478bd9Sstevel@tonic-gate * (including defaults - pulling them in from inetd where necessary) if 11227c478bd9Sstevel@tonic-gate * 'instance' is non-null, else just the defaults from inetd. The properties 11237c478bd9Sstevel@tonic-gate * are returned in an allocated inetd_prop_t array, which must be freed 11247c478bd9Sstevel@tonic-gate * using free_instance_props(). If an error occurs NULL is returned and 'err' 11257c478bd9Sstevel@tonic-gate * is set to indicate the cause, else a pointer to the read properties is 11267c478bd9Sstevel@tonic-gate * returned. 11277c478bd9Sstevel@tonic-gate */ 11287c478bd9Sstevel@tonic-gate static inetd_prop_t * 11297c478bd9Sstevel@tonic-gate read_props(scf_handle_t *h, const char *instance, size_t *num_elements, 11307c478bd9Sstevel@tonic-gate scf_error_t *err) 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate inetd_prop_t *ret = NULL; 11337c478bd9Sstevel@tonic-gate int i; 11347c478bd9Sstevel@tonic-gate boolean_t defaults_only = (instance == NULL); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate if ((ret = malloc(sizeof (inetd_properties))) == NULL) { 11377c478bd9Sstevel@tonic-gate *err = SCF_ERROR_NO_MEMORY; 11387c478bd9Sstevel@tonic-gate return (NULL); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate (void) memcpy(ret, &inetd_properties, sizeof (inetd_properties)); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate if (defaults_only) 11437c478bd9Sstevel@tonic-gate instance = INETD_INSTANCE_FMRI; 1144ba1637f8Smh138676 for (i = 0; ret[i].ip_name != NULL; i++) { 11457c478bd9Sstevel@tonic-gate if (defaults_only && !ret[i].ip_default) 11467c478bd9Sstevel@tonic-gate continue; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate switch (*err = read_prop(h, &ret[i], i, instance, 11497c478bd9Sstevel@tonic-gate defaults_only ? PG_NAME_SERVICE_DEFAULTS : ret[i].ip_pg)) { 11507c478bd9Sstevel@tonic-gate case 0: 11517c478bd9Sstevel@tonic-gate break; 11527c478bd9Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 11537c478bd9Sstevel@tonic-gate goto failure_cleanup; 11547c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * In non-default-only mode where we're reading a 11577c478bd9Sstevel@tonic-gate * default property, since the property wasn't 11587c478bd9Sstevel@tonic-gate * found in the instance, try and read inetd's default 11597c478bd9Sstevel@tonic-gate * value. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate if (!ret[i].ip_default || defaults_only) 11627c478bd9Sstevel@tonic-gate continue; 11637c478bd9Sstevel@tonic-gate switch (*err = read_prop(h, &ret[i], i, 11647c478bd9Sstevel@tonic-gate INETD_INSTANCE_FMRI, PG_NAME_SERVICE_DEFAULTS)) { 11657c478bd9Sstevel@tonic-gate case 0: 11667c478bd9Sstevel@tonic-gate ret[i].from_inetd = B_TRUE; 11677c478bd9Sstevel@tonic-gate continue; 11687c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 11697c478bd9Sstevel@tonic-gate continue; 11707c478bd9Sstevel@tonic-gate default: 11717c478bd9Sstevel@tonic-gate goto failure_cleanup; 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate default: 11747c478bd9Sstevel@tonic-gate goto failure_cleanup; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 1178ba1637f8Smh138676 *num_elements = i; 11797c478bd9Sstevel@tonic-gate return (ret); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate failure_cleanup: 11827c478bd9Sstevel@tonic-gate free_instance_props(ret); 11837c478bd9Sstevel@tonic-gate return (NULL); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 11877c478bd9Sstevel@tonic-gate * Read all properties applicable to 'instance' (including defaults). 11887c478bd9Sstevel@tonic-gate */ 11897c478bd9Sstevel@tonic-gate inetd_prop_t * 11907c478bd9Sstevel@tonic-gate read_instance_props(scf_handle_t *h, const char *instance, size_t *num_elements, 11917c478bd9Sstevel@tonic-gate scf_error_t *err) 11927c478bd9Sstevel@tonic-gate { 11937c478bd9Sstevel@tonic-gate return (read_props(h, instance, num_elements, err)); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * Read the default properties from inetd's defaults property group. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate inetd_prop_t * 12007c478bd9Sstevel@tonic-gate read_default_props(scf_handle_t *h, size_t *num_elements, scf_error_t *err) 12017c478bd9Sstevel@tonic-gate { 12027c478bd9Sstevel@tonic-gate return (read_props(h, NULL, num_elements, err)); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate void 12067c478bd9Sstevel@tonic-gate free_instance_props(inetd_prop_t *prop) 12077c478bd9Sstevel@tonic-gate { 12087c478bd9Sstevel@tonic-gate int i; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate if (prop == NULL) 12117c478bd9Sstevel@tonic-gate return; 12127c478bd9Sstevel@tonic-gate 1213ba1637f8Smh138676 for (i = 0; prop[i].ip_name != NULL; i++) { 1214ba1637f8Smh138676 if (prop[i].ip_type == INET_TYPE_STRING) { 1215ba1637f8Smh138676 free(prop[i].ip_value.iv_string); 1216ba1637f8Smh138676 } else if (prop[i].ip_type == INET_TYPE_STRING_LIST) { 1217ba1637f8Smh138676 destroy_strings(prop[i].ip_value.iv_string_list); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate free(prop); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate int 12247c478bd9Sstevel@tonic-gate connect_to_inetd(void) 12257c478bd9Sstevel@tonic-gate { 12267c478bd9Sstevel@tonic-gate struct sockaddr_un addr; 12277c478bd9Sstevel@tonic-gate int fd; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate fd = socket(AF_UNIX, SOCK_STREAM, 0); 12307c478bd9Sstevel@tonic-gate if (fd < 0) 12317c478bd9Sstevel@tonic-gate return (-1); 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate (void) memset(&addr, 0, sizeof (addr)); 12347c478bd9Sstevel@tonic-gate addr.sun_family = AF_UNIX; 12357c478bd9Sstevel@tonic-gate /* CONSTCOND */ 12367c478bd9Sstevel@tonic-gate assert(sizeof (INETD_UDS_PATH) <= sizeof (addr.sun_path)); 12377c478bd9Sstevel@tonic-gate (void) strlcpy(addr.sun_path, INETD_UDS_PATH, 12387c478bd9Sstevel@tonic-gate sizeof (addr.sun_path)); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 12417c478bd9Sstevel@tonic-gate (void) close(fd); 12427c478bd9Sstevel@tonic-gate return (-1); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate return (fd); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* 12497c478bd9Sstevel@tonic-gate * refresh_inetd requests that inetd re-read all of the information that it's 12507c478bd9Sstevel@tonic-gate * monitoring. 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate int 12547c478bd9Sstevel@tonic-gate refresh_inetd(void) 12557c478bd9Sstevel@tonic-gate { 12567c478bd9Sstevel@tonic-gate uds_request_t req; 12577c478bd9Sstevel@tonic-gate int fd; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if ((fd = connect_to_inetd()) < 0) 12607c478bd9Sstevel@tonic-gate return (-1); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate req = UR_REFRESH_INETD; 12637c478bd9Sstevel@tonic-gate if (send(fd, &req, sizeof (req), 0) < 0) { 12647c478bd9Sstevel@tonic-gate (void) close(fd); 12657c478bd9Sstevel@tonic-gate return (-1); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate (void) close(fd); 12697c478bd9Sstevel@tonic-gate return (0); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate /* 12737c478bd9Sstevel@tonic-gate * Returns the id of the socket type 'type_str' that can be used in a call 12747c478bd9Sstevel@tonic-gate * to socket(). If an unknown type string is passed returns -1, else the id. 12757c478bd9Sstevel@tonic-gate */ 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate int 12787c478bd9Sstevel@tonic-gate get_sock_type_id(const char *type_str) 12797c478bd9Sstevel@tonic-gate { 12807c478bd9Sstevel@tonic-gate int ret; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate if (strcmp(SOCKTYPE_STREAM_STR, type_str) == 0) { 12837c478bd9Sstevel@tonic-gate ret = SOCK_STREAM; 12847c478bd9Sstevel@tonic-gate } else if (strcmp(SOCKTYPE_DGRAM_STR, type_str) == 0) { 12857c478bd9Sstevel@tonic-gate ret = SOCK_DGRAM; 12867c478bd9Sstevel@tonic-gate } else if (strcmp(SOCKTYPE_RAW_STR, type_str) == 0) { 12877c478bd9Sstevel@tonic-gate ret = SOCK_RAW; 12887c478bd9Sstevel@tonic-gate } else if (strcmp(SOCKTYPE_SEQPKT_STR, type_str) == 0) { 12897c478bd9Sstevel@tonic-gate ret = SOCK_SEQPACKET; 12907c478bd9Sstevel@tonic-gate } else { 12917c478bd9Sstevel@tonic-gate ret = -1; 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate return (ret); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * Takes either an RPC service name or number in string form as 'svc_name', and 12987c478bd9Sstevel@tonic-gate * returns an integer format program number for the service. If the name isn't 12997c478bd9Sstevel@tonic-gate * recognized as a valid RPC service name or isn't a valid number, -1 is 13007c478bd9Sstevel@tonic-gate * returned, else the services program number. 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate int 13047c478bd9Sstevel@tonic-gate get_rpc_prognum(const char *svc_name) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate struct rpcent rpc; 13077c478bd9Sstevel@tonic-gate char buf[INETSVC_SVC_BUF_MAX]; 13087c478bd9Sstevel@tonic-gate int pnum; 13097c478bd9Sstevel@tonic-gate char *endptr; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if (getrpcbyname_r(svc_name, &rpc, buf, sizeof (buf)) != NULL) 13127c478bd9Sstevel@tonic-gate return (rpc.r_number); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate pnum = strtol(svc_name, &endptr, 0); 13157c478bd9Sstevel@tonic-gate if ((pnum == 0 && errno == EINVAL) || 13167c478bd9Sstevel@tonic-gate (pnum == LONG_MAX && errno == ERANGE) || 13177c478bd9Sstevel@tonic-gate pnum < 0 || *endptr != '\0') { 13187c478bd9Sstevel@tonic-gate return (-1); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate return (pnum); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 13257c478bd9Sstevel@tonic-gate * calculate_hash calculates the MD5 message-digest of the file pathname. 13267c478bd9Sstevel@tonic-gate * On success, hash is modified to point to the digest string and 0 is returned. 13277c478bd9Sstevel@tonic-gate * Otherwise, -1 is returned and errno is set to indicate the error. 13287c478bd9Sstevel@tonic-gate * The space for the digest string is obtained using malloc(3C) and should be 13297c478bd9Sstevel@tonic-gate * freed by the caller. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate int 13327c478bd9Sstevel@tonic-gate calculate_hash(const char *pathname, char **hash) 13337c478bd9Sstevel@tonic-gate { 13347c478bd9Sstevel@tonic-gate int fd, i, serrno; 13357c478bd9Sstevel@tonic-gate size_t len; 13367c478bd9Sstevel@tonic-gate ssize_t n; 13377c478bd9Sstevel@tonic-gate char *digest; 13387c478bd9Sstevel@tonic-gate MD5_CTX md5_context; 13397c478bd9Sstevel@tonic-gate unsigned char md5_digest[DIGEST_LEN]; 13407c478bd9Sstevel@tonic-gate unsigned char buf[READ_BUFSIZ]; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate do { 13437c478bd9Sstevel@tonic-gate fd = open(pathname, O_RDONLY); 13447c478bd9Sstevel@tonic-gate } while (fd == -1 && errno == EINTR); 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (fd == -1) 13477c478bd9Sstevel@tonic-gate return (-1); 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* allocate space for a 16-byte MD5 digest as a string of hex digits */ 13507c478bd9Sstevel@tonic-gate len = 2 * sizeof (md5_digest) + 1; 13517c478bd9Sstevel@tonic-gate if ((digest = malloc(len)) == NULL) { 13527c478bd9Sstevel@tonic-gate serrno = errno; 13537c478bd9Sstevel@tonic-gate (void) close(fd); 13547c478bd9Sstevel@tonic-gate errno = serrno; 13557c478bd9Sstevel@tonic-gate return (-1); 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate MD5Init(&md5_context); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate do { 13617c478bd9Sstevel@tonic-gate if ((n = read(fd, buf, sizeof (buf))) > 0) 13627c478bd9Sstevel@tonic-gate MD5Update(&md5_context, buf, n); 13637c478bd9Sstevel@tonic-gate } while ((n > 0) || (n == -1 && errno == EINTR)); 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate serrno = errno; 13667c478bd9Sstevel@tonic-gate MD5Final(md5_digest, &md5_context); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate (void) close(fd); 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate if (n == -1) { 13717c478bd9Sstevel@tonic-gate errno = serrno; 13727c478bd9Sstevel@tonic-gate return (-1); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (md5_digest); i++) { 13767c478bd9Sstevel@tonic-gate (void) snprintf(&digest[2 * i], len - (2 * i), "%02x", 13777c478bd9Sstevel@tonic-gate md5_digest[i]); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate *hash = digest; 13807c478bd9Sstevel@tonic-gate return (0); 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate /* 13847c478bd9Sstevel@tonic-gate * retrieve_inetd_hash retrieves inetd's configuration file hash from the 13857c478bd9Sstevel@tonic-gate * repository. On success, hash is modified to point to the hash string and 13867c478bd9Sstevel@tonic-gate * SCF_ERROR_NONE is returned. Otherwise, the scf_error value is returned. 13877c478bd9Sstevel@tonic-gate * The space for the hash string is obtained using malloc(3C) and should be 13887c478bd9Sstevel@tonic-gate * freed by the caller. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate scf_error_t 13917c478bd9Sstevel@tonic-gate retrieve_inetd_hash(char **hash) 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate scf_simple_prop_t *sp; 13947c478bd9Sstevel@tonic-gate char *hashstr, *s; 13957c478bd9Sstevel@tonic-gate scf_error_t scf_err; 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, HASH_PG, 13987c478bd9Sstevel@tonic-gate HASH_PROP)) == NULL) 13997c478bd9Sstevel@tonic-gate return (scf_error()); 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate if ((hashstr = scf_simple_prop_next_astring(sp)) == NULL) { 14027c478bd9Sstevel@tonic-gate scf_err = scf_error(); 14037c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 14047c478bd9Sstevel@tonic-gate return (scf_err); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate if ((s = strdup(hashstr)) == NULL) { 14087c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 14097c478bd9Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate *hash = s; 14127c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 14137c478bd9Sstevel@tonic-gate return (SCF_ERROR_NONE); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * store_inetd_hash stores the string hash in inetd's configuration file hash 14187c478bd9Sstevel@tonic-gate * in the repository. On success, SCF_ERROR_NONE is returned. Otherwise, the 14197c478bd9Sstevel@tonic-gate * scf_error value is returned. 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate scf_error_t 14227c478bd9Sstevel@tonic-gate store_inetd_hash(const char *hash) 14237c478bd9Sstevel@tonic-gate { 14247c478bd9Sstevel@tonic-gate int ret; 14257c478bd9Sstevel@tonic-gate scf_error_t rval = SCF_ERROR_NONE; 14267c478bd9Sstevel@tonic-gate scf_handle_t *h; 14277c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 14287c478bd9Sstevel@tonic-gate scf_instance_t *inst = NULL; 14297c478bd9Sstevel@tonic-gate scf_transaction_t *tx = NULL; 14307c478bd9Sstevel@tonic-gate scf_transaction_entry_t *txent = NULL; 14317c478bd9Sstevel@tonic-gate scf_property_t *prop = NULL; 14327c478bd9Sstevel@tonic-gate scf_value_t *val = NULL; 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate if ((h = scf_handle_create(SCF_VERSION)) == NULL || 14357c478bd9Sstevel@tonic-gate scf_handle_bind(h) == -1) 14367c478bd9Sstevel@tonic-gate goto error; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL || 14397c478bd9Sstevel@tonic-gate (inst = scf_instance_create(h)) == NULL || 14407c478bd9Sstevel@tonic-gate scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL, inst, 14417c478bd9Sstevel@tonic-gate NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 14427c478bd9Sstevel@tonic-gate goto error; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate if (scf_instance_get_pg(inst, HASH_PG, pg) == -1) { 14457c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND || 14467c478bd9Sstevel@tonic-gate scf_instance_add_pg(inst, HASH_PG, SCF_GROUP_APPLICATION, 14477c478bd9Sstevel@tonic-gate 0, pg) == -1) 14487c478bd9Sstevel@tonic-gate goto error; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate if ((tx = scf_transaction_create(h)) == NULL || 14527c478bd9Sstevel@tonic-gate (txent = scf_entry_create(h)) == NULL || 14537c478bd9Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL || 14547c478bd9Sstevel@tonic-gate (val = scf_value_create(h)) == NULL) 14557c478bd9Sstevel@tonic-gate goto error; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate do { 14587c478bd9Sstevel@tonic-gate if (scf_transaction_start(tx, pg) == -1) 14597c478bd9Sstevel@tonic-gate goto error; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate if (scf_transaction_property_new(tx, txent, HASH_PROP, 14627c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING) == -1 && 14637c478bd9Sstevel@tonic-gate scf_transaction_property_change_type(tx, txent, HASH_PROP, 14647c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING) == -1) 14657c478bd9Sstevel@tonic-gate goto error; 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate if (scf_value_set_astring(val, hash) == -1 || 14687c478bd9Sstevel@tonic-gate scf_entry_add_value(txent, val) == -1) 14697c478bd9Sstevel@tonic-gate goto error; 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate if ((ret = scf_transaction_commit(tx)) == -1) 14727c478bd9Sstevel@tonic-gate goto error; 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (ret == 0) { 14757c478bd9Sstevel@tonic-gate scf_transaction_reset(tx); 14767c478bd9Sstevel@tonic-gate if (scf_pg_update(pg) == -1) 14777c478bd9Sstevel@tonic-gate goto error; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate } while (ret == 0); 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate goto success; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate error: 14847c478bd9Sstevel@tonic-gate rval = scf_error(); 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate success: 14877c478bd9Sstevel@tonic-gate scf_value_destroy(val); 14887c478bd9Sstevel@tonic-gate scf_property_destroy(prop); 14897c478bd9Sstevel@tonic-gate scf_entry_destroy(txent); 14907c478bd9Sstevel@tonic-gate scf_transaction_destroy(tx); 14917c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 14927c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 14937c478bd9Sstevel@tonic-gate scf_handle_destroy(h); 14947c478bd9Sstevel@tonic-gate return (rval); 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* 14987c478bd9Sstevel@tonic-gate * This is a wrapper function for inet_ntop(). In case the af is AF_INET6 14997c478bd9Sstevel@tonic-gate * and the address pointed by src is a IPv4-mapped IPv6 address, it returns 15007c478bd9Sstevel@tonic-gate * a printable IPv4 address, not an IPv4-mapped IPv6 address. In other cases it 15017c478bd9Sstevel@tonic-gate * behaves just like inet_ntop(). 15027c478bd9Sstevel@tonic-gate */ 15037c478bd9Sstevel@tonic-gate const char * 15047c478bd9Sstevel@tonic-gate inet_ntop_native(int af, const void *addr, char *dst, size_t size) 15057c478bd9Sstevel@tonic-gate { 15067c478bd9Sstevel@tonic-gate struct in_addr v4addr; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if ((af == AF_INET6) && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { 15097c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); 15107c478bd9Sstevel@tonic-gate return (inet_ntop(AF_INET, &v4addr, dst, size)); 15117c478bd9Sstevel@tonic-gate } else { 15127c478bd9Sstevel@tonic-gate return (inet_ntop(af, addr, dst, size)); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate /* 15177c478bd9Sstevel@tonic-gate * inetd specific setproctitle. It sets the title so that it contains 15187c478bd9Sstevel@tonic-gate * 'svc_name' followed by, if obtainable, the address of the remote end of 15197c478bd9Sstevel@tonic-gate * socket 's'. 15207c478bd9Sstevel@tonic-gate * NOTE: The argv manipulation in this function should be replaced when a 15217c478bd9Sstevel@tonic-gate * common version of setproctitle is made available. 15227c478bd9Sstevel@tonic-gate */ 15237c478bd9Sstevel@tonic-gate void 15247c478bd9Sstevel@tonic-gate setproctitle(const char *svc_name, int s, char *argv[]) 15257c478bd9Sstevel@tonic-gate { 15267c478bd9Sstevel@tonic-gate socklen_t size; 15277c478bd9Sstevel@tonic-gate struct sockaddr_storage ss; 15287c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate static char buf[80]; 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate size = (socklen_t)sizeof (ss); 15337c478bd9Sstevel@tonic-gate if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 15347c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "-%s [%s]", svc_name, 15357c478bd9Sstevel@tonic-gate inet_ntop_native(ss.ss_family, (ss.ss_family == AF_INET6 ? 15367c478bd9Sstevel@tonic-gate (void *)&((struct sockaddr_in6 *)(&ss))->sin6_addr : 15377c478bd9Sstevel@tonic-gate (void *)&((struct sockaddr_in *)(&ss))->sin_addr), abuf, 15387c478bd9Sstevel@tonic-gate sizeof (abuf))); 15397c478bd9Sstevel@tonic-gate } else { 15407c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "-%s", svc_name); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate /* we set argv[0] to point at our static storage. */ 15447c478bd9Sstevel@tonic-gate argv[0] = buf; 15457c478bd9Sstevel@tonic-gate argv[1] = NULL; 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate static boolean_t 15497c478bd9Sstevel@tonic-gate inetd_builtin_srcport(in_port_t p) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate p = ntohs(p); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if ((p == IPPORT_ECHO) || 15547c478bd9Sstevel@tonic-gate (p == IPPORT_DISCARD) || 15557c478bd9Sstevel@tonic-gate (p == IPPORT_DAYTIME) || 15567c478bd9Sstevel@tonic-gate (p == IPPORT_CHARGEN) || 15577c478bd9Sstevel@tonic-gate (p == IPPORT_TIMESERVER)) { 15587c478bd9Sstevel@tonic-gate return (B_TRUE); 15597c478bd9Sstevel@tonic-gate } else { 15607c478bd9Sstevel@tonic-gate return (B_FALSE); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 15657c478bd9Sstevel@tonic-gate static void 15667c478bd9Sstevel@tonic-gate alarm_handler(int sig) 15677c478bd9Sstevel@tonic-gate { 15687c478bd9Sstevel@tonic-gate exit(0); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * This function is a datagram service template. It acts as a datagram wait 15737c478bd9Sstevel@tonic-gate * type server, waiting for datagrams to come in, and when they do passing 15747c478bd9Sstevel@tonic-gate * their contents, as-well as the socket they came in on and the remote 15757c478bd9Sstevel@tonic-gate * address, in a call to the callback function 'cb'. If no datagrams are 15767c478bd9Sstevel@tonic-gate * received for DG_INACTIVITY_TIMEOUT seconds the function exits with code 0. 15777c478bd9Sstevel@tonic-gate */ 15787c478bd9Sstevel@tonic-gate void 15797c478bd9Sstevel@tonic-gate dg_template(void (*cb)(int, const struct sockaddr *, int, const void *, size_t), 15807c478bd9Sstevel@tonic-gate int s, void *buf, size_t buflen) 15817c478bd9Sstevel@tonic-gate { 15827c478bd9Sstevel@tonic-gate struct sockaddr_storage sa; 15837c478bd9Sstevel@tonic-gate socklen_t sa_size; 15847c478bd9Sstevel@tonic-gate ssize_t i; 15857c478bd9Sstevel@tonic-gate char tmp[BUFSIZ]; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate (void) sigset(SIGALRM, alarm_handler); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate if (buf == NULL) { 15907c478bd9Sstevel@tonic-gate buf = tmp; 15917c478bd9Sstevel@tonic-gate buflen = sizeof (tmp); 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate for (;;) { 15947c478bd9Sstevel@tonic-gate (void) alarm(DG_INACTIVITY_TIMEOUT); 15957c478bd9Sstevel@tonic-gate sa_size = sizeof (sa); 15967c478bd9Sstevel@tonic-gate if ((i = recvfrom(s, buf, buflen, 0, (struct sockaddr *)&sa, 15977c478bd9Sstevel@tonic-gate &sa_size)) < 0) { 15987c478bd9Sstevel@tonic-gate continue; 15997c478bd9Sstevel@tonic-gate } else if (inetd_builtin_srcport( 16007c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)(&sa))->sin_port)) { 16017c478bd9Sstevel@tonic-gate /* denial-of-service attack possibility - ignore it */ 16027c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 16037c478bd9Sstevel@tonic-gate "Incoming datagram from internal inetd service received; ignoring."); 16047c478bd9Sstevel@tonic-gate continue; 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate (void) alarm(0); 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate cb(s, (struct sockaddr *)&sa, sa_size, buf, i); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate /* 16137c478bd9Sstevel@tonic-gate * An extension of write() or sendto() that keeps trying until either the full 16147c478bd9Sstevel@tonic-gate * request has completed or a non-EINTR error occurs. If 'to' is set to a 16157c478bd9Sstevel@tonic-gate * non-NULL value, sendto() is extended, else write(). Returns 0 on success 16167c478bd9Sstevel@tonic-gate * else -1. 16177c478bd9Sstevel@tonic-gate */ 16187c478bd9Sstevel@tonic-gate int 16197c478bd9Sstevel@tonic-gate safe_sendto_write(int fd, const void *buf, size_t sz, int flags, 16207c478bd9Sstevel@tonic-gate const struct sockaddr *to, int tolen) { 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate size_t cnt = 0; 16237c478bd9Sstevel@tonic-gate ssize_t ret; 16247c478bd9Sstevel@tonic-gate const char *cp = buf; 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate do { 16277c478bd9Sstevel@tonic-gate if (to == NULL) { 16287c478bd9Sstevel@tonic-gate ret = write(fd, cp + cnt, sz - cnt); 16297c478bd9Sstevel@tonic-gate } else { 16307c478bd9Sstevel@tonic-gate ret = sendto(fd, cp + cnt, sz - cnt, flags, to, tolen); 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate if (ret > 0) 16347c478bd9Sstevel@tonic-gate cnt += ret; 16357c478bd9Sstevel@tonic-gate } while ((cnt != sz) && (errno == EINTR)); 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate return ((cnt == sz) ? 0 : -1); 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate int 16417c478bd9Sstevel@tonic-gate safe_sendto(int fd, const void *buf, size_t sz, int flags, 16427c478bd9Sstevel@tonic-gate const struct sockaddr *to, int tolen) { 16437c478bd9Sstevel@tonic-gate return (safe_sendto_write(fd, buf, sz, flags, to, tolen)); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate int 16477c478bd9Sstevel@tonic-gate safe_write(int fd, const void *buf, size_t sz) 16487c478bd9Sstevel@tonic-gate { 16497c478bd9Sstevel@tonic-gate return (safe_sendto_write(fd, buf, sz, 0, NULL, 0)); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * Free up the memory occupied by string array 'strs'. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate void 16567c478bd9Sstevel@tonic-gate destroy_strings(char **strs) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate int i = 0; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate if (strs != NULL) { 16617c478bd9Sstevel@tonic-gate while (strs[i] != NULL) 16627c478bd9Sstevel@tonic-gate free(strs[i++]); 16637c478bd9Sstevel@tonic-gate free(strs); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 16687c478bd9Sstevel@tonic-gate * Parse the proto list string into an allocated array of proto strings, 16697c478bd9Sstevel@tonic-gate * returning a pointer to this array. If one of the protos is too big 16707c478bd9Sstevel@tonic-gate * errno is set to E2BIG and NULL is returned; if memory allocation failure 16717c478bd9Sstevel@tonic-gate * occurs errno is set to ENOMEM and NULL is returned; else on success 16727c478bd9Sstevel@tonic-gate * a pointer the string array is returned. 16737c478bd9Sstevel@tonic-gate */ 16747c478bd9Sstevel@tonic-gate char ** 16757c478bd9Sstevel@tonic-gate get_protos(const char *pstr) 16767c478bd9Sstevel@tonic-gate { 16777c478bd9Sstevel@tonic-gate char *cp; 16787c478bd9Sstevel@tonic-gate int i = 0; 16797c478bd9Sstevel@tonic-gate char **ret = NULL; 16807c478bd9Sstevel@tonic-gate size_t max_proto_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 16817c478bd9Sstevel@tonic-gate char *str; 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate /* copy the parameter as strtok modifies its parameters */ 16847c478bd9Sstevel@tonic-gate if ((str = strdup(pstr)) == NULL) 16857c478bd9Sstevel@tonic-gate goto malloc_failure; 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate for (cp = strtok(str, PROTO_DELIMITERS); cp != NULL; 16887c478bd9Sstevel@tonic-gate cp = strtok(NULL, PROTO_DELIMITERS)) { 16897c478bd9Sstevel@tonic-gate char **cpp; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate if (strlen(cp) >= max_proto_len) { 16927c478bd9Sstevel@tonic-gate destroy_strings(ret); 16937c478bd9Sstevel@tonic-gate free(str); 16947c478bd9Sstevel@tonic-gate errno = E2BIG; 16957c478bd9Sstevel@tonic-gate return (NULL); 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate if ((cpp = realloc(ret, (i + 2) * sizeof (char *))) == NULL) 16987c478bd9Sstevel@tonic-gate goto malloc_failure; 16997c478bd9Sstevel@tonic-gate ret = cpp; 17007c478bd9Sstevel@tonic-gate if ((cpp[i] = strdup(cp)) == NULL) 17017c478bd9Sstevel@tonic-gate goto malloc_failure; 17027c478bd9Sstevel@tonic-gate cpp[++i] = NULL; 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate free(str); 17067c478bd9Sstevel@tonic-gate return (ret); 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate malloc_failure: 17097c478bd9Sstevel@tonic-gate destroy_strings(ret); 17107c478bd9Sstevel@tonic-gate free(str); 17117c478bd9Sstevel@tonic-gate errno = ENOMEM; 17127c478bd9Sstevel@tonic-gate return (NULL); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Returns an allocated string array of netids corresponding with 'proto'. The 17177c478bd9Sstevel@tonic-gate * function first tries to interpret 'proto' as a nettype to get its netids. 17187c478bd9Sstevel@tonic-gate * If this fails it tries to interpret it as a netid. If 'proto' is neither 17197c478bd9Sstevel@tonic-gate * a nettype or a netid or a memory allocation failures occurs NULL is 17207c478bd9Sstevel@tonic-gate * returned, else a pointer to an array of netids associated with 'proto' is 17217c478bd9Sstevel@tonic-gate * returned. 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate char ** 17247c478bd9Sstevel@tonic-gate get_netids(char *proto) 17257c478bd9Sstevel@tonic-gate { 17267c478bd9Sstevel@tonic-gate void *handle; 17277c478bd9Sstevel@tonic-gate struct netconfig *nconf; 17287c478bd9Sstevel@tonic-gate char **netids = NULL; 17297c478bd9Sstevel@tonic-gate char **cpp; 17307c478bd9Sstevel@tonic-gate int i = 0; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (strcmp(proto, "*") == 0) 17337c478bd9Sstevel@tonic-gate proto = "visible"; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if ((handle = __rpc_setconf(proto)) != NULL) { 17367c478bd9Sstevel@tonic-gate /* expand nettype */ 17377c478bd9Sstevel@tonic-gate while ((nconf = __rpc_getconf(handle)) != NULL) { 17387c478bd9Sstevel@tonic-gate if ((cpp = realloc(netids, 17397c478bd9Sstevel@tonic-gate (i + 2) * sizeof (char *))) == NULL) 17407c478bd9Sstevel@tonic-gate goto failure_cleanup; 17417c478bd9Sstevel@tonic-gate netids = cpp; 17427c478bd9Sstevel@tonic-gate if ((cpp[i] = strdup(nconf->nc_netid)) == NULL) 17437c478bd9Sstevel@tonic-gate goto failure_cleanup; 17447c478bd9Sstevel@tonic-gate cpp[++i] = NULL; 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate __rpc_endconf(handle); 17477c478bd9Sstevel@tonic-gate } else { 17487c478bd9Sstevel@tonic-gate if ((netids = malloc(2 * sizeof (char *))) == NULL) 17497c478bd9Sstevel@tonic-gate return (NULL); 17507c478bd9Sstevel@tonic-gate if ((netids[0] = strdup(proto)) == NULL) { 17517c478bd9Sstevel@tonic-gate free(netids); 17527c478bd9Sstevel@tonic-gate return (NULL); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate netids[1] = NULL; 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate return (netids); 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate failure_cleanup: 17607c478bd9Sstevel@tonic-gate destroy_strings(netids); 17617c478bd9Sstevel@tonic-gate __rpc_endconf(handle); 17627c478bd9Sstevel@tonic-gate return (NULL); 17637c478bd9Sstevel@tonic-gate } 1764