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