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