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