10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*5404Stn143363 * Common Development and Distribution License (the "License"). 6*5404Stn143363 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5404Stn143363 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * inetconv - convert inetd.conf entries into smf(5) service manifests, 300Sstevel@tonic-gate * import them into smf(5) repository 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/stat.h> 360Sstevel@tonic-gate #include <sys/wait.h> 370Sstevel@tonic-gate #include <stdio.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate #include <unistd.h> 410Sstevel@tonic-gate #include <fcntl.h> 420Sstevel@tonic-gate #include <pwd.h> 430Sstevel@tonic-gate #include <grp.h> 440Sstevel@tonic-gate #include <errno.h> 450Sstevel@tonic-gate #include <limits.h> 460Sstevel@tonic-gate #include <locale.h> 470Sstevel@tonic-gate #include <libintl.h> 480Sstevel@tonic-gate #include <libscf.h> 490Sstevel@tonic-gate #include <inetsvc.h> 500Sstevel@tonic-gate #include <rpc/nettype.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* exit codes */ 530Sstevel@tonic-gate #define EXIT_SUCCESS 0 /* succeeded */ 540Sstevel@tonic-gate #define EXIT_USAGE 1 /* bad options */ 550Sstevel@tonic-gate #define EXIT_ERROR_CONV 2 /* error(s) coverting inetd.conf entries */ 560Sstevel@tonic-gate #define EXIT_ERROR_IMP 3 /* error(s) importing manifests */ 570Sstevel@tonic-gate #define EXIT_ERROR_SYS 4 /* system error */ 580Sstevel@tonic-gate #define EXIT_ERROR_ENBL 5 /* error(s) enabling services */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate #ifndef TEXT_DOMAIN 610Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD" 620Sstevel@tonic-gate #endif 630Sstevel@tonic-gate 640Sstevel@tonic-gate #define MAIN_CONFIG "/etc/inet/inetd.conf" 650Sstevel@tonic-gate #define ALT_CONFIG "/etc/inetd.conf" 660Sstevel@tonic-gate 670Sstevel@tonic-gate #define MANIFEST_DIR "/var/svc/manifest/network" 68290Sdstaff #define MANIFEST_RPC_DIR MANIFEST_DIR "/rpc" 690Sstevel@tonic-gate #define SVCCFG_PATH "/usr/sbin/svccfg" 700Sstevel@tonic-gate 71290Sdstaff #define RPCBIND_FMRI "svc:/network/rpc/bind" 72290Sdstaff 730Sstevel@tonic-gate /* maximum allowed length of an inetd.conf format line */ 740Sstevel@tonic-gate #define MAX_SRC_LINELEN 32768 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* Version of inetconv, used as a marker in services we generate */ 770Sstevel@tonic-gate #define INETCONV_VERSION 1 780Sstevel@tonic-gate 790Sstevel@tonic-gate struct inetconfent { 800Sstevel@tonic-gate /* fields as read from inetd.conf format line */ 810Sstevel@tonic-gate char *service; 820Sstevel@tonic-gate char *endpoint; 830Sstevel@tonic-gate char *protocol; 840Sstevel@tonic-gate char *wait_status; 850Sstevel@tonic-gate char *username; 860Sstevel@tonic-gate char *server_program; 870Sstevel@tonic-gate char *server_args; 880Sstevel@tonic-gate /* information derived from above fields */ 890Sstevel@tonic-gate boolean_t wait; 900Sstevel@tonic-gate boolean_t isrpc; 910Sstevel@tonic-gate int rpc_low_version; 920Sstevel@tonic-gate int rpc_high_version; 930Sstevel@tonic-gate char *rpc_prog; 940Sstevel@tonic-gate char *groupname; 950Sstevel@tonic-gate char *exec; 960Sstevel@tonic-gate char *arg0; 970Sstevel@tonic-gate }; 980Sstevel@tonic-gate 990Sstevel@tonic-gate struct fileinfo { 1000Sstevel@tonic-gate FILE *fp; 1010Sstevel@tonic-gate char *filename; 1020Sstevel@tonic-gate int lineno; 1030Sstevel@tonic-gate int failcnt; 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate static char *progname; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static boolean_t import = B_TRUE; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* start of manifest XML template strings */ 1110Sstevel@tonic-gate static const char xml_header[] = 1120Sstevel@tonic-gate "<?xml version='1.0'?>\n" 1130Sstevel@tonic-gate "<!DOCTYPE service_bundle SYSTEM " 1140Sstevel@tonic-gate "'/usr/share/lib/xml/dtd/service_bundle.dtd.1'>\n"; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate static const char xml_comment[] = 1170Sstevel@tonic-gate "<!--\n" 1180Sstevel@tonic-gate " Service manifest for the %s service.\n" 1190Sstevel@tonic-gate "\n" 1200Sstevel@tonic-gate " Generated by inetconv(1M) from inetd.conf(4).\n" 1210Sstevel@tonic-gate "-->\n\n"; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate static const char xml_service_bundle[] = 1240Sstevel@tonic-gate "<service_bundle type='manifest' name='inetconv:%s'>\n\n"; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate static const char xml_service_name[] = 1270Sstevel@tonic-gate "<service\n" 1280Sstevel@tonic-gate " name='network/%s'\n" 1290Sstevel@tonic-gate " type='service'\n" 1300Sstevel@tonic-gate " version='1'>\n\n"; 1310Sstevel@tonic-gate 132290Sdstaff static const char xml_dependency[] = 133290Sdstaff " <dependency\n" 134290Sdstaff " name='%s'\n" 135290Sdstaff " grouping='require_all'\n" 136290Sdstaff " restart_on='restart'\n" 137290Sdstaff " type='service'>\n" 138290Sdstaff " <service_fmri value='%s' />\n" 139290Sdstaff " </dependency>\n\n"; 140290Sdstaff 1410Sstevel@tonic-gate static const char xml_instance[] = 1420Sstevel@tonic-gate " <create_default_instance enabled='true'/>\n\n"; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate static const char xml_restarter[] = 1450Sstevel@tonic-gate " <restarter>\n" 1460Sstevel@tonic-gate " <service_fmri value='%s' />\n" 1470Sstevel@tonic-gate " </restarter>\n\n"; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static const char xml_exec_method_start[] = 1500Sstevel@tonic-gate " <!--\n" 1510Sstevel@tonic-gate " Set a timeout of 0 to signify to inetd that we don't want to\n" 1520Sstevel@tonic-gate " timeout this service, since the forked process is the one that\n" 1530Sstevel@tonic-gate " does the service's work. This is the case for most/all legacy\n" 1540Sstevel@tonic-gate " inetd services; for services written to take advantage of SMF\n" 1550Sstevel@tonic-gate " capabilities, the start method should fork off a process to\n" 1560Sstevel@tonic-gate " handle the request and return a success code.\n" 1570Sstevel@tonic-gate " -->\n" 1580Sstevel@tonic-gate " <exec_method\n" 1590Sstevel@tonic-gate " type='method'\n" 1600Sstevel@tonic-gate " name='%s'\n" 1610Sstevel@tonic-gate " %s='%s'\n" 1620Sstevel@tonic-gate " timeout_seconds='0'>\n" 1630Sstevel@tonic-gate " <method_context>\n" 1640Sstevel@tonic-gate " <method_credential %s='%s' group='%s' />\n" 1650Sstevel@tonic-gate " </method_context>\n"; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate static const char xml_arg0[] = 1680Sstevel@tonic-gate " <propval name='%s' type='astring'\n" 1690Sstevel@tonic-gate " value='%s' />\n"; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static const char xml_exec_method_end[] = 1720Sstevel@tonic-gate " </exec_method>\n\n"; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static const char xml_exec_method_disable[] = 1750Sstevel@tonic-gate " <!--\n" 1760Sstevel@tonic-gate " Use inetd's built-in kill support to disable services.\n" 1770Sstevel@tonic-gate " -->\n" 1780Sstevel@tonic-gate " <exec_method\n" 1790Sstevel@tonic-gate " type='method'\n" 1800Sstevel@tonic-gate " name='%s'\n" 1810Sstevel@tonic-gate " %s=':kill'\n" 1820Sstevel@tonic-gate " timeout_seconds='0'>\n"; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate static const char xml_exec_method_offline[] = 1850Sstevel@tonic-gate " <!--\n" 1860Sstevel@tonic-gate " Use inetd's built-in process kill support to offline wait type\n" 1870Sstevel@tonic-gate " services.\n" 1880Sstevel@tonic-gate " -->\n" 1890Sstevel@tonic-gate " <exec_method\n" 1900Sstevel@tonic-gate " type='method'\n" 1910Sstevel@tonic-gate " name='%s'\n" 1920Sstevel@tonic-gate " %s=':kill_process'\n" 1930Sstevel@tonic-gate " timeout_seconds='0'>\n"; 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate static const char xml_inetconv_group_start[] = 1960Sstevel@tonic-gate " <!--\n" 1970Sstevel@tonic-gate " This property group is used to record information about\n" 1980Sstevel@tonic-gate " how this manifest was created. It is an implementation\n" 1990Sstevel@tonic-gate " detail which should not be modified or deleted.\n" 2000Sstevel@tonic-gate " -->\n" 2010Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n" 2020Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n" 2030Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n" 2040Sstevel@tonic-gate " <propval name='%s' type='astring' value=\n" 2050Sstevel@tonic-gate "'%s %s %s %s %s %s%s%s'\n" 2060Sstevel@tonic-gate " />\n"; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate static const char xml_property_group_start[] = 2090Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n" 2100Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 2110Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 2120Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 2130Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n" 2140Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n"; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate static const char xml_property_group_rpc[] = 2170Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n" 2180Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />" 2190Sstevel@tonic-gate "\n"; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static const char xml_property_group_end[] = 2220Sstevel@tonic-gate " </property_group>\n\n"; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate static const char xml_stability[] = 2250Sstevel@tonic-gate " <stability value='External' />\n\n"; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate static const char xml_template[] = 2280Sstevel@tonic-gate " <template>\n" 2290Sstevel@tonic-gate " <common_name>\n" 2300Sstevel@tonic-gate " <loctext xml:lang='C'>\n" 2310Sstevel@tonic-gate "%s\n" 2320Sstevel@tonic-gate " </loctext>\n" 2330Sstevel@tonic-gate " </common_name>\n" 2340Sstevel@tonic-gate " </template>\n"; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate static const char xml_footer[] = 2370Sstevel@tonic-gate "</service>\n" 2380Sstevel@tonic-gate "\n" 2390Sstevel@tonic-gate "</service_bundle>\n"; 2400Sstevel@tonic-gate /* end of manifest XML template strings */ 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate static void * 2430Sstevel@tonic-gate safe_malloc(size_t size) 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate void *cp; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate if ((cp = malloc(size)) == NULL) { 2480Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 2490Sstevel@tonic-gate progname, strerror(errno)); 2500Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate return (cp); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate static char * 2560Sstevel@tonic-gate safe_strdup(char *s) 2570Sstevel@tonic-gate { 2580Sstevel@tonic-gate char *cp; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if ((cp = strdup(s)) == NULL) { 2610Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: strdup failed: %s\n"), 2620Sstevel@tonic-gate progname, strerror(errno)); 2630Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate return (cp); 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate static char * 2690Sstevel@tonic-gate propertyname(char *name, char *prefix) 2700Sstevel@tonic-gate { 2710Sstevel@tonic-gate static char *buf; 2720Sstevel@tonic-gate size_t len; 2730Sstevel@tonic-gate int c; 2740Sstevel@tonic-gate char *cp; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* free any memory allocated by a previous call */ 2770Sstevel@tonic-gate free(buf); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate len = strlen(name) + strlen(prefix) + 1; 2800Sstevel@tonic-gate buf = safe_malloc(len); 2810Sstevel@tonic-gate buf[0] = '\0'; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate /* 2840Sstevel@tonic-gate * Property names must match the regular expression: 2850Sstevel@tonic-gate * ([A-Za-z][_A-Za-z0-9.-]*,)?[A-Za-z][_A-Za-z0-9-]* 2860Sstevel@tonic-gate */ 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* 2890Sstevel@tonic-gate * Make sure the first character is alphabetic, if not insert prefix. 290*5404Stn143363 * Can't use isalpha() here as it's locale dependent but the property 2910Sstevel@tonic-gate * name regular expression isn't. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate c = name[0]; 2940Sstevel@tonic-gate if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { 2950Sstevel@tonic-gate (void) strlcat(buf, prefix, len); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate (void) strlcat(buf, name, len); 2980Sstevel@tonic-gate 299*5404Stn143363 /* convert any disallowed characters into '_' */ 3000Sstevel@tonic-gate for (cp = buf; *cp != '\0'; cp++) { 3010Sstevel@tonic-gate if ((*cp < 'A' || *cp > 'Z') && (*cp < 'a' || *cp > 'z') && 3020Sstevel@tonic-gate (*cp < '0' || *cp > '9') && (*cp != '.') && (*cp != '-')) 3030Sstevel@tonic-gate *cp = '_'; 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate return (buf); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate static char * 3090Sstevel@tonic-gate servicename(struct inetconfent *iconf) 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate static char *buf; 3120Sstevel@tonic-gate size_t len; 313*5404Stn143363 char *cp, *proto; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* free any memory allocated by a previous call */ 3160Sstevel@tonic-gate free(buf); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate len = strlen(iconf->service) + strlen(iconf->protocol) + 3190Sstevel@tonic-gate sizeof ("rpc-/visible"); 3200Sstevel@tonic-gate buf = safe_malloc(len); 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Combine the service and protocol fields to produce a unique 3240Sstevel@tonic-gate * manifest service name. The syntax of a service name is: 3250Sstevel@tonic-gate * prop(/prop)* 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate (void) strlcpy(buf, propertyname(iconf->service, 3280Sstevel@tonic-gate iconf->isrpc ? "rpc-": "s-"), len); 3290Sstevel@tonic-gate (void) strlcat(buf, "/", len); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate proto = iconf->protocol; 3320Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0)) 3330Sstevel@tonic-gate proto = "rpc/visible"; 334*5404Stn143363 335*5404Stn143363 /* 336*5404Stn143363 * SMF service names may not contain '.', but IANA services do 337*5404Stn143363 * allow its use, and property names can contain '.' as returned 338*5404Stn143363 * by propertyname(). So if the resultant SMF service name 339*5404Stn143363 * would contain a '.' we fix it here. 340*5404Stn143363 */ 341*5404Stn143363 for (cp = buf; *cp != '\0'; cp++) { 342*5404Stn143363 if (*cp == '.') 343*5404Stn143363 *cp = '_'; 344*5404Stn143363 } 3450Sstevel@tonic-gate (void) strlcat(buf, propertyname(proto, "p-"), len); 3460Sstevel@tonic-gate return (buf); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate static boolean_t 3500Sstevel@tonic-gate is_v6only(char *protocol) 3510Sstevel@tonic-gate { 3520Sstevel@tonic-gate /* returns true if protocol is an IPv6 only protocol */ 3530Sstevel@tonic-gate if ((strcmp(protocol, SOCKET_PROTO_TCP6_ONLY) == 0) || 3540Sstevel@tonic-gate (strcmp(protocol, SOCKET_PROTO_UDP6_ONLY) == 0)) 3550Sstevel@tonic-gate return (B_TRUE); 3560Sstevel@tonic-gate return (B_FALSE); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate static char * 3600Sstevel@tonic-gate invalid_props(inetd_prop_t *p) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate static char 3630Sstevel@tonic-gate buf[sizeof (" service-name endpoint-type protocol wait-status")]; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate buf[0] = '\0'; 3660Sstevel@tonic-gate if ((p[PT_SVC_NAME_INDEX].ip_error == IVE_INVALID) || 3670Sstevel@tonic-gate (p[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) || 3680Sstevel@tonic-gate (p[PT_RPC_LW_VER_INDEX].ip_error == IVE_INVALID) || 3690Sstevel@tonic-gate (p[PT_RPC_HI_VER_INDEX].ip_error == IVE_INVALID)) 3700Sstevel@tonic-gate (void) strlcat(buf, " service-name", sizeof (buf)); 3710Sstevel@tonic-gate if ((p[PT_SOCK_TYPE_INDEX].ip_error == IVE_INVALID) || 3720Sstevel@tonic-gate (p[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET)) 3730Sstevel@tonic-gate (void) strlcat(buf, " endpoint-type", sizeof (buf)); 3740Sstevel@tonic-gate if ((p[PT_PROTO_INDEX].ip_error == IVE_INVALID) || 3750Sstevel@tonic-gate (p[PT_PROTO_INDEX].ip_error == IVE_UNSET) || 3760Sstevel@tonic-gate (p[PT_ISRPC_INDEX].ip_error == IVE_INVALID)) 3770Sstevel@tonic-gate (void) strlcat(buf, " protocol", sizeof (buf)); 3780Sstevel@tonic-gate if (p[PT_ISWAIT_INDEX].ip_error == IVE_INVALID) 3790Sstevel@tonic-gate (void) strlcat(buf, " wait-status", sizeof (buf)); 3800Sstevel@tonic-gate return (buf); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate static boolean_t 3840Sstevel@tonic-gate valid_basic_properties(struct inetconfent *iconf, struct fileinfo *finfo) 3850Sstevel@tonic-gate { 3860Sstevel@tonic-gate size_t prop_size; 3870Sstevel@tonic-gate inetd_prop_t *prop, *inetd_properties; 3880Sstevel@tonic-gate boolean_t valid = B_TRUE; 3890Sstevel@tonic-gate char *proto = iconf->protocol; 3900Sstevel@tonic-gate char *svc_name = iconf->service; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate inetd_properties = get_prop_table(&prop_size); 3930Sstevel@tonic-gate prop = safe_malloc(prop_size * sizeof (inetd_prop_t)); 3940Sstevel@tonic-gate (void) memcpy(prop, inetd_properties, 3950Sstevel@tonic-gate prop_size * sizeof (inetd_prop_t)); 3960Sstevel@tonic-gate 3971293Smh138676 put_prop_value_boolean(prop, PR_ISRPC_NAME, iconf->isrpc); 3981293Smh138676 put_prop_value_boolean(prop, PR_ISWAIT_NAME, iconf->wait); 3990Sstevel@tonic-gate if (iconf->isrpc) { 4001293Smh138676 put_prop_value_int(prop, PR_RPC_LW_VER_NAME, 4011293Smh138676 iconf->rpc_low_version); 4021293Smh138676 put_prop_value_int(prop, PR_RPC_HI_VER_NAME, 4031293Smh138676 iconf->rpc_high_version); 4040Sstevel@tonic-gate svc_name = iconf->rpc_prog; 4050Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */ 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4081293Smh138676 if (!put_prop_value_string(prop, PR_SOCK_TYPE_NAME, iconf->endpoint) || 4091293Smh138676 !put_prop_value_string(prop, PR_SVC_NAME_NAME, svc_name)) { 4100Sstevel@tonic-gate valid = B_FALSE; 4110Sstevel@tonic-gate 4121293Smh138676 if (errno == ENOMEM) { 4131293Smh138676 (void) fprintf(stderr, 4141293Smh138676 gettext("%s: failed to allocate memory: %s\n"), 4151293Smh138676 progname, strerror(errno)); 4161293Smh138676 exit(EXIT_ERROR_SYS); 4171293Smh138676 } 4181293Smh138676 } 4191293Smh138676 4201293Smh138676 put_prop_value_string_list(prop, PR_PROTO_NAME, get_protos(proto)); 4211293Smh138676 4220Sstevel@tonic-gate if (!valid_props(prop, NULL, NULL, NULL, NULL) || !valid) { 4230Sstevel@tonic-gate valid = B_FALSE; 4240Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 4250Sstevel@tonic-gate "invalid or inconsistent fields:%s\n"), progname, 4260Sstevel@tonic-gate finfo->filename, finfo->lineno, 4270Sstevel@tonic-gate invalid_props(prop)); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate free_instance_props(prop); 4310Sstevel@tonic-gate return (valid); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate static boolean_t 4350Sstevel@tonic-gate valid_inetconfent(struct inetconfent *iconf, struct fileinfo *finfo) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate boolean_t valid = B_TRUE; 4380Sstevel@tonic-gate size_t len; 4390Sstevel@tonic-gate char *cp, *endp; 4400Sstevel@tonic-gate struct passwd *pwd; 4410Sstevel@tonic-gate struct group *grp; 4420Sstevel@tonic-gate struct stat statb; 4430Sstevel@tonic-gate char *proto = iconf->protocol; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate iconf->isrpc = B_FALSE; 4460Sstevel@tonic-gate if (strncmp(iconf->protocol, "rpc/", 4) == 0) { 4470Sstevel@tonic-gate iconf->isrpc = B_TRUE; 4480Sstevel@tonic-gate iconf->rpc_prog = safe_strdup(iconf->service); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* set RPC version numbers */ 4510Sstevel@tonic-gate iconf->rpc_low_version = 1; 4520Sstevel@tonic-gate iconf->rpc_high_version = 1; 4530Sstevel@tonic-gate if ((cp = strrchr(iconf->rpc_prog, '/')) != NULL) { 4540Sstevel@tonic-gate *cp = '\0'; 4550Sstevel@tonic-gate if (*++cp != '\0') { 4560Sstevel@tonic-gate errno = 0; 4570Sstevel@tonic-gate iconf->rpc_low_version = strtol(cp, &endp, 10); 4580Sstevel@tonic-gate if (errno != 0) 4590Sstevel@tonic-gate goto vererr; 4600Sstevel@tonic-gate cp = endp; 4610Sstevel@tonic-gate if (*cp == '-') { 4620Sstevel@tonic-gate if (*++cp == '\0') 4630Sstevel@tonic-gate goto vererr; 4640Sstevel@tonic-gate errno = 0; 4650Sstevel@tonic-gate iconf->rpc_high_version = strtol(cp, 4660Sstevel@tonic-gate &endp, 10); 4670Sstevel@tonic-gate if ((errno != 0) || (*endp != '\0')) 4680Sstevel@tonic-gate goto vererr; 4690Sstevel@tonic-gate } else if (*cp == '\0') { 4700Sstevel@tonic-gate iconf->rpc_high_version = 4710Sstevel@tonic-gate iconf->rpc_low_version; 4720Sstevel@tonic-gate } else { 4730Sstevel@tonic-gate vererr: 4740Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4750Sstevel@tonic-gate "%s: Error %s line %d invalid RPC " 4760Sstevel@tonic-gate "version in service: %s\n"), 4770Sstevel@tonic-gate progname, finfo->filename, 4780Sstevel@tonic-gate finfo->lineno, iconf->service); 4790Sstevel@tonic-gate valid = B_FALSE; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */ 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate /* tcp6only and udp6only are not valid in inetd.conf */ 4860Sstevel@tonic-gate if (is_v6only(proto)) { 4870Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 4880Sstevel@tonic-gate "invalid protocol: %s\n"), progname, 4890Sstevel@tonic-gate finfo->filename, finfo->lineno, proto); 4900Sstevel@tonic-gate valid = B_FALSE; 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate if (strcmp(iconf->wait_status, "wait") == 0) { 4940Sstevel@tonic-gate iconf->wait = B_TRUE; 4950Sstevel@tonic-gate } else if (strcmp(iconf->wait_status, "nowait") == 0) { 4960Sstevel@tonic-gate iconf->wait = B_FALSE; 4970Sstevel@tonic-gate } else { 4980Sstevel@tonic-gate (void) fprintf(stderr, 4990Sstevel@tonic-gate gettext("%s: Error %s line %d invalid wait-status: %s\n"), 5000Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 5010Sstevel@tonic-gate iconf->wait_status); 5020Sstevel@tonic-gate valid = B_FALSE; 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate /* look up the username to set the groupname */ 5060Sstevel@tonic-gate if ((pwd = getpwnam(iconf->username)) == NULL) { 5070Sstevel@tonic-gate (void) fprintf(stderr, 5080Sstevel@tonic-gate gettext("%s: Error %s line %d unknown user: %s\n"), 5090Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 5100Sstevel@tonic-gate iconf->username); 5110Sstevel@tonic-gate valid = B_FALSE; 5120Sstevel@tonic-gate } else { 5130Sstevel@tonic-gate if ((grp = getgrgid(pwd->pw_gid)) != NULL) { 5140Sstevel@tonic-gate iconf->groupname = safe_strdup(grp->gr_name); 5150Sstevel@tonic-gate } else { 5160Sstevel@tonic-gate /* use the group ID if no groupname */ 5170Sstevel@tonic-gate char s[1]; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate len = snprintf(s, 1, "%d", pwd->pw_gid) + 1; 5200Sstevel@tonic-gate iconf->groupname = safe_malloc(len); 5210Sstevel@tonic-gate (void) snprintf(iconf->groupname, len, "%d", 5220Sstevel@tonic-gate pwd->pw_gid); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* check for internal services */ 5270Sstevel@tonic-gate if (strcmp(iconf->server_program, "internal") == 0) { 5280Sstevel@tonic-gate valid = B_FALSE; 5290Sstevel@tonic-gate if ((strcmp(iconf->service, "echo") == 0) || 5300Sstevel@tonic-gate (strcmp(iconf->service, "discard") == 0) || 5310Sstevel@tonic-gate (strcmp(iconf->service, "time") == 0) || 5320Sstevel@tonic-gate (strcmp(iconf->service, "daytime") == 0) || 5330Sstevel@tonic-gate (strcmp(iconf->service, "chargen") == 0)) { 5340Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5350Sstevel@tonic-gate "%s: Error %s line %d the SUNWcnsr and SUNWcnsu" 5360Sstevel@tonic-gate " packages contain the internal services\n"), 5370Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 5380Sstevel@tonic-gate } else { 5390Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 5400Sstevel@tonic-gate "unknown internal service: %s\n"), progname, 5410Sstevel@tonic-gate finfo->filename, finfo->lineno, iconf->service); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate } else if ((stat(iconf->server_program, &statb) == -1) && 5440Sstevel@tonic-gate (errno == ENOENT)) { 5450Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5460Sstevel@tonic-gate "%s: Error %s line %d server-program not found: %s\n"), 5470Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 5480Sstevel@tonic-gate iconf->server_program); 5490Sstevel@tonic-gate valid = B_FALSE; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate return (valid && valid_basic_properties(iconf, finfo)); 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate static void 5560Sstevel@tonic-gate free_inetconfent(struct inetconfent *iconf) 5570Sstevel@tonic-gate { 5580Sstevel@tonic-gate if (iconf == NULL) 5590Sstevel@tonic-gate return; 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate free(iconf->service); 5620Sstevel@tonic-gate free(iconf->endpoint); 5630Sstevel@tonic-gate free(iconf->protocol); 5640Sstevel@tonic-gate free(iconf->wait_status); 5650Sstevel@tonic-gate free(iconf->username); 5660Sstevel@tonic-gate free(iconf->server_program); 5670Sstevel@tonic-gate free(iconf->server_args); 5680Sstevel@tonic-gate free(iconf->rpc_prog); 5690Sstevel@tonic-gate free(iconf->groupname); 5700Sstevel@tonic-gate free(iconf->exec); 5710Sstevel@tonic-gate free(iconf->arg0); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate free(iconf); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate static struct inetconfent * 5770Sstevel@tonic-gate line_to_inetconfent(char *line) 5780Sstevel@tonic-gate { 5790Sstevel@tonic-gate char *cp; 5800Sstevel@tonic-gate struct inetconfent *iconf; 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate iconf = safe_malloc(sizeof (struct inetconfent)); 5830Sstevel@tonic-gate (void) memset(iconf, 0, sizeof (struct inetconfent)); 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate if ((cp = strtok(line, " \t\n")) == NULL) 5860Sstevel@tonic-gate goto fail; 5870Sstevel@tonic-gate iconf->service = safe_strdup(cp); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 5900Sstevel@tonic-gate goto fail; 5910Sstevel@tonic-gate iconf->endpoint = safe_strdup(cp); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 5940Sstevel@tonic-gate goto fail; 5950Sstevel@tonic-gate iconf->protocol = safe_strdup(cp); 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 5980Sstevel@tonic-gate goto fail; 5990Sstevel@tonic-gate iconf->wait_status = safe_strdup(cp); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 6020Sstevel@tonic-gate goto fail; 6030Sstevel@tonic-gate iconf->username = safe_strdup(cp); 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 6060Sstevel@tonic-gate goto fail; 6070Sstevel@tonic-gate iconf->server_program = safe_strdup(cp); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* last field is optional */ 6100Sstevel@tonic-gate if ((cp = strtok(NULL, "\n")) != NULL) 6110Sstevel@tonic-gate iconf->server_args = safe_strdup(cp); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate /* Combine args and server name to construct exec and args fields */ 6140Sstevel@tonic-gate if (iconf->server_args == NULL) { 6150Sstevel@tonic-gate iconf->exec = safe_strdup(iconf->server_program); 6160Sstevel@tonic-gate } else { 6170Sstevel@tonic-gate int len; 6180Sstevel@tonic-gate char *args, *endp; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate len = strlen(iconf->server_program) + 6210Sstevel@tonic-gate strlen(iconf->server_args) + 1; 6220Sstevel@tonic-gate iconf->exec = safe_malloc(len); 6230Sstevel@tonic-gate (void) strlcpy(iconf->exec, iconf->server_program, len); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate args = safe_strdup(iconf->server_args); 6260Sstevel@tonic-gate if ((cp = strtok(args, " \t")) != NULL) { 6270Sstevel@tonic-gate if ((endp = strrchr(iconf->exec, '/')) == NULL) 6280Sstevel@tonic-gate endp = iconf->exec; 6290Sstevel@tonic-gate else 6300Sstevel@tonic-gate endp++; 6310Sstevel@tonic-gate /* only set arg0 property value if needed */ 6320Sstevel@tonic-gate if (strcmp(endp, cp) != 0) 6330Sstevel@tonic-gate iconf->arg0 = safe_strdup(cp); 6340Sstevel@tonic-gate while ((cp = strtok(NULL, " \t")) != NULL) { 6350Sstevel@tonic-gate (void) strlcat(iconf->exec, " ", len); 6360Sstevel@tonic-gate (void) strlcat(iconf->exec, cp, len); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate free(args); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate return (iconf); 6430Sstevel@tonic-gate fail: 6440Sstevel@tonic-gate free_inetconfent(iconf); 6450Sstevel@tonic-gate return (NULL); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate static void 6490Sstevel@tonic-gate skipline(FILE *fp) 6500Sstevel@tonic-gate { 6510Sstevel@tonic-gate int c; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* skip remainder of a line */ 6540Sstevel@tonic-gate while (((c = getc(fp)) != EOF) && (c != '\n')) 6550Sstevel@tonic-gate ; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate static struct inetconfent * 6590Sstevel@tonic-gate fgetinetconfent(struct fileinfo *finfo, boolean_t validate) 6600Sstevel@tonic-gate { 6610Sstevel@tonic-gate char *cp; 6620Sstevel@tonic-gate struct inetconfent *iconf; 6630Sstevel@tonic-gate char line[MAX_SRC_LINELEN]; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate while (fgets(line, sizeof (line), finfo->fp) != NULL) { 6660Sstevel@tonic-gate finfo->lineno++; 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* skip empty or commented out lines */ 6690Sstevel@tonic-gate if (*line == '\n') 6700Sstevel@tonic-gate continue; 6710Sstevel@tonic-gate if (*line == '#') { 6720Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') 6730Sstevel@tonic-gate skipline(finfo->fp); 6740Sstevel@tonic-gate continue; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate /* check for lines which are too long */ 6770Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') { 6780Sstevel@tonic-gate (void) fprintf(stderr, 6790Sstevel@tonic-gate gettext("%s: Error %s line %d too long, skipped\n"), 6800Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 6810Sstevel@tonic-gate skipline(finfo->fp); 6820Sstevel@tonic-gate finfo->failcnt++; 6830Sstevel@tonic-gate continue; 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate /* remove in line comments and newline character */ 6860Sstevel@tonic-gate if ((cp = strchr(line, '#')) == NULL) 6870Sstevel@tonic-gate cp = strchr(line, '\n'); 6880Sstevel@tonic-gate if (cp) 6890Sstevel@tonic-gate *cp = '\0'; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if ((iconf = line_to_inetconfent(line)) == NULL) { 6920Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6930Sstevel@tonic-gate "%s: Error %s line %d too few fields, skipped\n"), 6940Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 6950Sstevel@tonic-gate finfo->failcnt++; 6960Sstevel@tonic-gate continue; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (!validate || valid_inetconfent(iconf, finfo)) 7000Sstevel@tonic-gate return (iconf); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate finfo->failcnt++; 7030Sstevel@tonic-gate free_inetconfent(iconf); 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate return (NULL); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate static char * 7090Sstevel@tonic-gate boolstr(boolean_t val) 7100Sstevel@tonic-gate { 7110Sstevel@tonic-gate if (val) 7120Sstevel@tonic-gate return ("true"); 7130Sstevel@tonic-gate return ("false"); 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate static int 7170Sstevel@tonic-gate print_manifest(FILE *f, char *filename, struct inetconfent *iconf) 7180Sstevel@tonic-gate { 7190Sstevel@tonic-gate if (fprintf(f, xml_header) < 0) 7200Sstevel@tonic-gate goto print_err; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate if (fprintf(f, xml_comment, 7230Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0) 7240Sstevel@tonic-gate goto print_err; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (fprintf(f, xml_service_bundle, iconf->service) < 0) 7270Sstevel@tonic-gate goto print_err; 7280Sstevel@tonic-gate if (fprintf(f, xml_service_name, servicename(iconf)) < 0) 7290Sstevel@tonic-gate goto print_err; 7300Sstevel@tonic-gate if (fprintf(f, xml_instance) < 0) 7310Sstevel@tonic-gate goto print_err; 7320Sstevel@tonic-gate if (fprintf(f, xml_restarter, INETD_INSTANCE_FMRI) < 0) 7330Sstevel@tonic-gate goto print_err; 734290Sdstaff if (iconf->isrpc) { 735290Sdstaff if (fprintf(f, xml_dependency, "rpcbind", RPCBIND_FMRI) < 0) 736290Sdstaff goto print_err; 737290Sdstaff } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if (fprintf(f, xml_exec_method_start, START_METHOD_NAME, PR_EXEC_NAME, 7400Sstevel@tonic-gate iconf->exec, PR_USER_NAME, iconf->username, iconf->groupname) < 0) 7410Sstevel@tonic-gate goto print_err; 7420Sstevel@tonic-gate if (iconf->arg0 != NULL) { 7430Sstevel@tonic-gate if (fprintf(f, xml_arg0, PR_ARG0_NAME, iconf->arg0) < 0) 7440Sstevel@tonic-gate goto print_err; 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 7470Sstevel@tonic-gate goto print_err; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (fprintf(f, xml_exec_method_disable, DISABLE_METHOD_NAME, 7500Sstevel@tonic-gate PR_EXEC_NAME) < 0) 7510Sstevel@tonic-gate goto print_err; 7520Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 7530Sstevel@tonic-gate goto print_err; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (iconf->wait) { 7560Sstevel@tonic-gate if (fprintf(f, xml_exec_method_offline, OFFLINE_METHOD_NAME, 7570Sstevel@tonic-gate PR_EXEC_NAME) < 0) 7580Sstevel@tonic-gate goto print_err; 7590Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 7600Sstevel@tonic-gate goto print_err; 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if (fprintf(f, xml_inetconv_group_start, PG_NAME_INETCONV, 7640Sstevel@tonic-gate PR_AUTO_CONVERTED_NAME, boolstr(B_TRUE), 7650Sstevel@tonic-gate PR_VERSION_NAME, INETCONV_VERSION, 7660Sstevel@tonic-gate PR_SOURCE_LINE_NAME, iconf->service, 7670Sstevel@tonic-gate iconf->endpoint, iconf->protocol, iconf->wait_status, 7680Sstevel@tonic-gate iconf->username, iconf->server_program, 7690Sstevel@tonic-gate iconf->server_args == NULL ? "" : " ", 7700Sstevel@tonic-gate iconf->server_args == NULL ? "" : iconf->server_args) < 0) 7710Sstevel@tonic-gate goto print_err; 7720Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0) 7730Sstevel@tonic-gate goto print_err; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate if (fprintf(f, xml_property_group_start, PG_NAME_SERVICE_CONFIG, 7760Sstevel@tonic-gate PR_SVC_NAME_NAME, iconf->isrpc ? iconf->rpc_prog : iconf->service, 7770Sstevel@tonic-gate PR_SOCK_TYPE_NAME, iconf->endpoint, 7780Sstevel@tonic-gate PR_PROTO_NAME, iconf->isrpc ? iconf->protocol + 4 : 7790Sstevel@tonic-gate iconf->protocol, 7800Sstevel@tonic-gate PR_ISWAIT_NAME, boolstr(iconf->wait), 7810Sstevel@tonic-gate PR_ISRPC_NAME, boolstr(iconf->isrpc)) < 0) 7820Sstevel@tonic-gate goto print_err; 7830Sstevel@tonic-gate if (iconf->isrpc) { 7840Sstevel@tonic-gate if (fprintf(f, xml_property_group_rpc, 7850Sstevel@tonic-gate PR_RPC_LW_VER_NAME, iconf->rpc_low_version, 7860Sstevel@tonic-gate PR_RPC_HI_VER_NAME, iconf->rpc_high_version) < 0) 7870Sstevel@tonic-gate goto print_err; 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0) 7900Sstevel@tonic-gate goto print_err; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate if (fprintf(f, xml_stability) < 0) 7930Sstevel@tonic-gate goto print_err; 7940Sstevel@tonic-gate if (fprintf(f, xml_template, 7950Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0) 7960Sstevel@tonic-gate goto print_err; 7970Sstevel@tonic-gate if (fprintf(f, xml_footer) < 0) 7980Sstevel@tonic-gate goto print_err; 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate (void) printf("%s -> %s\n", iconf->service, filename); 8010Sstevel@tonic-gate return (0); 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate print_err: 8040Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error writing manifest %s: %s\n"), 8050Sstevel@tonic-gate progname, filename, strerror(errno)); 8060Sstevel@tonic-gate return (-1); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate static struct fileinfo * 8100Sstevel@tonic-gate open_srcfile(char *filename) 8110Sstevel@tonic-gate { 8120Sstevel@tonic-gate struct fileinfo *finfo = NULL; 8130Sstevel@tonic-gate FILE *fp; 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate if (filename != NULL) { 8160Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 8170Sstevel@tonic-gate (void) fprintf(stderr, 8180Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 8190Sstevel@tonic-gate progname, filename, strerror(errno)); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate } else { 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * If no source file specified, do the same as inetd and first 8240Sstevel@tonic-gate * try /etc/inet/inetd.conf, followed by /etc/inetd.conf. 8250Sstevel@tonic-gate */ 8260Sstevel@tonic-gate filename = MAIN_CONFIG; 8270Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 8280Sstevel@tonic-gate (void) fprintf(stderr, 8290Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 8300Sstevel@tonic-gate progname, filename, strerror(errno)); 8310Sstevel@tonic-gate filename = ALT_CONFIG; 8320Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 8330Sstevel@tonic-gate (void) fprintf(stderr, gettext( 8340Sstevel@tonic-gate "%s: Error opening %s: %s\n"), progname, 8350Sstevel@tonic-gate filename, strerror(errno)); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate if (fp != NULL) { 8400Sstevel@tonic-gate finfo = safe_malloc(sizeof (struct fileinfo)); 8410Sstevel@tonic-gate finfo->fp = fp; 8420Sstevel@tonic-gate finfo->filename = filename; 8430Sstevel@tonic-gate finfo->lineno = 0; 8440Sstevel@tonic-gate finfo->failcnt = 0; 8450Sstevel@tonic-gate (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate return (finfo); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * Opens manifest output file. Returns 0 on success, -1 if the file 8520Sstevel@tonic-gate * exists, -2 on other errors. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate static int 8550Sstevel@tonic-gate open_dstfile( 8560Sstevel@tonic-gate char *destdir, 8570Sstevel@tonic-gate boolean_t overwrite, 8580Sstevel@tonic-gate struct inetconfent *iconf, 8590Sstevel@tonic-gate struct fileinfo **finfo) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate int fd; 8620Sstevel@tonic-gate size_t len; 8630Sstevel@tonic-gate char *dstfile, *cp, *proto; 8640Sstevel@tonic-gate FILE *fp; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* if no destdir specified, use appropriate default */ 8670Sstevel@tonic-gate if (destdir == NULL) { 8680Sstevel@tonic-gate if (iconf->isrpc) 8690Sstevel@tonic-gate destdir = MANIFEST_RPC_DIR; 8700Sstevel@tonic-gate else 8710Sstevel@tonic-gate destdir = MANIFEST_DIR; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate len = strlen(destdir) + strlen(iconf->service) + 8750Sstevel@tonic-gate strlen(iconf->protocol) + sizeof ("/-visible.xml"); 8760Sstevel@tonic-gate dstfile = safe_malloc(len); 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate (void) strlcpy(dstfile, destdir, len); 8790Sstevel@tonic-gate if (dstfile[strlen(dstfile) - 1] != '/') 8800Sstevel@tonic-gate (void) strlcat(dstfile, "/", len); 8810Sstevel@tonic-gate cp = dstfile + strlen(dstfile); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate (void) strlcat(dstfile, iconf->service, len); 8840Sstevel@tonic-gate (void) strlcat(dstfile, "-", len); 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate proto = iconf->protocol; 8870Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0)) 8880Sstevel@tonic-gate proto = "rpc/visible"; 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate (void) strlcat(dstfile, proto, len); 8910Sstevel@tonic-gate (void) strlcat(dstfile, ".xml", len); 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate /* convert any '/' chars in service or protocol to '_' chars */ 8940Sstevel@tonic-gate while ((cp = strchr(cp, '/')) != NULL) 8950Sstevel@tonic-gate *cp = '_'; 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate fd = open(dstfile, O_WRONLY|O_CREAT|(overwrite ? O_TRUNC : O_EXCL), 8980Sstevel@tonic-gate 0644); 8990Sstevel@tonic-gate if (fd == -1) { 9000Sstevel@tonic-gate if (!overwrite && (errno == EEXIST)) { 9010Sstevel@tonic-gate (void) fprintf(stderr, 9020Sstevel@tonic-gate gettext("%s: Notice: Service manifest for " 9030Sstevel@tonic-gate "%s already generated as %s, skipped\n"), 9040Sstevel@tonic-gate progname, iconf->service, dstfile); 9050Sstevel@tonic-gate free(dstfile); 9060Sstevel@tonic-gate return (-1); 9070Sstevel@tonic-gate } else { 9080Sstevel@tonic-gate (void) fprintf(stderr, 9090Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 9100Sstevel@tonic-gate progname, dstfile, strerror(errno)); 9110Sstevel@tonic-gate free(dstfile); 9120Sstevel@tonic-gate return (-2); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate /* Clear errno to catch the "no stdio streams" case */ 9160Sstevel@tonic-gate errno = 0; 9170Sstevel@tonic-gate if ((fp = fdopen(fd, "w")) == NULL) { 9180Sstevel@tonic-gate char *s = strerror(errno); 9190Sstevel@tonic-gate if (errno == 0) 9200Sstevel@tonic-gate s = gettext("No stdio streams available"); 9210Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error fdopen failed: %s\n"), 9220Sstevel@tonic-gate progname, s); 9230Sstevel@tonic-gate (void) close(fd); 9240Sstevel@tonic-gate free(dstfile); 9250Sstevel@tonic-gate return (-2); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate *finfo = safe_malloc(sizeof (struct fileinfo)); 9280Sstevel@tonic-gate (*finfo)->fp = fp; 9290Sstevel@tonic-gate (*finfo)->filename = dstfile; 9300Sstevel@tonic-gate (*finfo)->lineno = 0; 9310Sstevel@tonic-gate (*finfo)->failcnt = 0; 9320Sstevel@tonic-gate return (0); 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate static int 9360Sstevel@tonic-gate import_manifest(char *filename) 9370Sstevel@tonic-gate { 9380Sstevel@tonic-gate int status; 9390Sstevel@tonic-gate pid_t pid, wpid; 9400Sstevel@tonic-gate char *cp; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate if ((cp = strrchr(filename, '/')) == NULL) 9430Sstevel@tonic-gate cp = filename; 9440Sstevel@tonic-gate else 9450Sstevel@tonic-gate cp++; 9460Sstevel@tonic-gate (void) printf(gettext("Importing %s ..."), cp); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if ((pid = fork()) == -1) { 9490Sstevel@tonic-gate (void) fprintf(stderr, 9500Sstevel@tonic-gate gettext("\n%s: fork failed, %s not imported: %s\n"), 9510Sstevel@tonic-gate progname, filename, strerror(errno)); 9520Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate if (pid == 0) { 9550Sstevel@tonic-gate /* child */ 9560Sstevel@tonic-gate (void) fclose(stdin); 9570Sstevel@tonic-gate (void) setenv("SVCCFG_CHECKHASH", "1", 1); 9580Sstevel@tonic-gate (void) execl(SVCCFG_PATH, "svccfg", "import", filename, NULL); 9590Sstevel@tonic-gate (void) fprintf(stderr, gettext("\n%s: exec of %s failed: %s"), 9600Sstevel@tonic-gate progname, SVCCFG_PATH, strerror(errno)); 9610Sstevel@tonic-gate _exit(EXIT_ERROR_SYS); 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate /* parent */ 9640Sstevel@tonic-gate if ((wpid = waitpid(pid, &status, 0)) != pid) { 9650Sstevel@tonic-gate (void) fprintf(stderr, gettext( 9660Sstevel@tonic-gate "\n%s: unexpected wait (%d) from import of %s: %s\n"), 9670Sstevel@tonic-gate progname, wpid, filename, strerror(errno)); 9680Sstevel@tonic-gate return (-1); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) { 9710Sstevel@tonic-gate (void) fprintf(stderr, 9720Sstevel@tonic-gate gettext("\n%s: import failure (%d) for %s\n"), 9730Sstevel@tonic-gate progname, WEXITSTATUS(status), filename); 9740Sstevel@tonic-gate return (-1); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate (void) printf(gettext("Done\n")); 9770Sstevel@tonic-gate return (0); 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate static int 9810Sstevel@tonic-gate inetd_config_path(char **path) 9820Sstevel@tonic-gate { 9830Sstevel@tonic-gate int fd; 9840Sstevel@tonic-gate char *arg1, *configfile, *configstr; 9850Sstevel@tonic-gate scf_simple_prop_t *sp; 9860Sstevel@tonic-gate char cpath[PATH_MAX]; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, "start", 9890Sstevel@tonic-gate SCF_PROPERTY_EXEC)) == NULL) 9900Sstevel@tonic-gate return (-1); 9910Sstevel@tonic-gate if ((configstr = scf_simple_prop_next_astring(sp)) == NULL) { 9920Sstevel@tonic-gate scf_simple_prop_free(sp); 9930Sstevel@tonic-gate return (-1); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate configstr = safe_strdup(configstr); 9960Sstevel@tonic-gate scf_simple_prop_free(sp); 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * Look for the optional configuration file, the syntax is: 10000Sstevel@tonic-gate * /usr/lib/inet/inetd [config-file] start|stop|refresh|disable|%m 10010Sstevel@tonic-gate */ 10020Sstevel@tonic-gate if (strtok(configstr, " \t") == NULL) { 10030Sstevel@tonic-gate free(configstr); 10040Sstevel@tonic-gate return (-1); 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate if ((arg1 = strtok(NULL, " \t")) == NULL) { 10070Sstevel@tonic-gate free(configstr); 10080Sstevel@tonic-gate return (-1); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate if (strtok(NULL, " \t") == NULL) { 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * No configuration file specified, do the same as inetd and 10130Sstevel@tonic-gate * first try /etc/inet/inetd.conf, followed by /etc/inetd.conf. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate configfile = MAIN_CONFIG; 10160Sstevel@tonic-gate if ((fd = open(configfile, O_RDONLY)) >= 0) 10170Sstevel@tonic-gate (void) close(fd); 10180Sstevel@tonic-gate else 10190Sstevel@tonic-gate configfile = ALT_CONFIG; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate } else { 10220Sstevel@tonic-gate /* make sure there are no more arguments */ 10230Sstevel@tonic-gate if (strtok(NULL, " \t") != NULL) { 10240Sstevel@tonic-gate free(configstr); 10250Sstevel@tonic-gate return (-1); 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate configfile = arg1; 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* configuration file must be an absolute pathname */ 10310Sstevel@tonic-gate if (*configfile != '/') { 10320Sstevel@tonic-gate free(configstr); 10330Sstevel@tonic-gate return (-1); 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate if (realpath(configfile, cpath) == NULL) 10370Sstevel@tonic-gate (void) strlcpy(cpath, configfile, sizeof (cpath)); 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate free(configstr); 10400Sstevel@tonic-gate *path = safe_strdup(cpath); 10410Sstevel@tonic-gate return (0); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate static int 10450Sstevel@tonic-gate update_hash(char *srcfile) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate scf_error_t rval; 10480Sstevel@tonic-gate char *inetd_cpath, *hashstr; 10490Sstevel@tonic-gate char cpath[PATH_MAX]; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate /* determine the config file inetd is using */ 10520Sstevel@tonic-gate if (inetd_config_path(&inetd_cpath) == -1) { 10530Sstevel@tonic-gate (void) fprintf(stderr, 10540Sstevel@tonic-gate gettext("%s: Error reading from repository\n"), progname); 10550Sstevel@tonic-gate return (-1); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* resolve inetconv input filename */ 10590Sstevel@tonic-gate if (realpath(srcfile, cpath) == NULL) 10600Sstevel@tonic-gate (void) strlcpy(cpath, srcfile, sizeof (cpath)); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate /* if inetconv and inetd are using the same config file, update hash */ 10630Sstevel@tonic-gate if (strcmp(cpath, inetd_cpath) != 0) { 10640Sstevel@tonic-gate free(inetd_cpath); 10650Sstevel@tonic-gate return (0); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate free(inetd_cpath); 10680Sstevel@tonic-gate 10690Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */ 10700Sstevel@tonic-gate if (calculate_hash(cpath, &hashstr) != 0) { 10710Sstevel@tonic-gate (void) fprintf(stderr, 10720Sstevel@tonic-gate gettext("%s: Error unable to update repository\n"), 10730Sstevel@tonic-gate progname); 10740Sstevel@tonic-gate return (-1); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */ 10770Sstevel@tonic-gate if ((rval = store_inetd_hash(hashstr)) != SCF_ERROR_NONE) { 10780Sstevel@tonic-gate (void) fprintf(stderr, 10790Sstevel@tonic-gate gettext("%s: Error updating repository: %s\n"), 10800Sstevel@tonic-gate progname, scf_strerror(rval)); 10810Sstevel@tonic-gate free(hashstr); 10820Sstevel@tonic-gate return (-1); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate free(hashstr); 10850Sstevel@tonic-gate return (0); 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate static void 10890Sstevel@tonic-gate property_error(const char *fmri, const char *prop) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate (void) fprintf(stderr, 10920Sstevel@tonic-gate gettext("Error: Instance %1$s is missing property '%2$s'.\n"), 10930Sstevel@tonic-gate fmri, prop); 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate /* 10970Sstevel@tonic-gate * modify_sprop takes a handle, an instance, a property group, a property, 10980Sstevel@tonic-gate * and an astring value, and modifies the instance (or service's) specified 10990Sstevel@tonic-gate * property in the repository to the submitted value. 11000Sstevel@tonic-gate * 11010Sstevel@tonic-gate * returns -1 on error, 1 on successful transaction completion. 11020Sstevel@tonic-gate */ 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate static int 11050Sstevel@tonic-gate modify_sprop(scf_handle_t *h, const scf_instance_t *inst, 11060Sstevel@tonic-gate const char *pg, const char *prop, const char *value) 11070Sstevel@tonic-gate { 11080Sstevel@tonic-gate scf_transaction_t *tx = NULL; 11090Sstevel@tonic-gate scf_transaction_entry_t *ent = NULL; 11100Sstevel@tonic-gate scf_propertygroup_t *gpg = NULL; 11110Sstevel@tonic-gate scf_property_t *eprop = NULL; 11120Sstevel@tonic-gate scf_value_t *v = NULL; 11130Sstevel@tonic-gate scf_service_t *svc = NULL; 11140Sstevel@tonic-gate int ret = 0, create = 0; 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate if ((gpg = scf_pg_create(h)) == NULL) 11170Sstevel@tonic-gate return (-1); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate /* Get the property group */ 11200Sstevel@tonic-gate if (scf_instance_get_pg(inst, pg, gpg) == -1) { 11210Sstevel@tonic-gate /* Not a property of the instance, try the service instead */ 11220Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL) { 11230Sstevel@tonic-gate ret = -1; 11240Sstevel@tonic-gate goto out; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate if ((scf_instance_get_parent(inst, svc) == -1) || 11270Sstevel@tonic-gate (scf_service_get_pg(svc, pg, gpg) == -1)) { 11280Sstevel@tonic-gate ret = -1; 11290Sstevel@tonic-gate goto out; 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate if ((eprop = scf_property_create(h)) == NULL) { 11340Sstevel@tonic-gate ret = -1; 11350Sstevel@tonic-gate goto out; 11360Sstevel@tonic-gate } 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate if (scf_pg_get_property(gpg, prop, eprop) == -1) { 11390Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 11400Sstevel@tonic-gate ret = -1; 11410Sstevel@tonic-gate goto out; 11420Sstevel@tonic-gate } 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate create = 1; 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate if ((tx = scf_transaction_create(h)) == NULL || 11480Sstevel@tonic-gate (ent = scf_entry_create(h)) == NULL) { 11490Sstevel@tonic-gate ret = -1; 11500Sstevel@tonic-gate goto out; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate do { 11540Sstevel@tonic-gate if (scf_transaction_start(tx, gpg) == -1) { 11550Sstevel@tonic-gate ret = -1; 11560Sstevel@tonic-gate goto out; 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate /* Modify the property */ 11600Sstevel@tonic-gate if (create) 11610Sstevel@tonic-gate ret = scf_transaction_property_new(tx, ent, prop, 11620Sstevel@tonic-gate SCF_TYPE_ASTRING); 11630Sstevel@tonic-gate else 11640Sstevel@tonic-gate ret = scf_transaction_property_change_type(tx, ent, 11650Sstevel@tonic-gate prop, SCF_TYPE_ASTRING); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate if (ret == -1) 11680Sstevel@tonic-gate goto out; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate if ((v = scf_value_create(h)) == NULL) { 11710Sstevel@tonic-gate ret = -1; 11720Sstevel@tonic-gate goto out; 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate if (scf_value_set_astring(v, value) == -1) { 11760Sstevel@tonic-gate ret = -1; 11770Sstevel@tonic-gate goto out; 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate if (scf_entry_add_value(ent, v) == -1) { 11810Sstevel@tonic-gate ret = -1; 11820Sstevel@tonic-gate goto out; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate ret = scf_transaction_commit(tx); 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate if (ret == 0) { 11880Sstevel@tonic-gate /* Property group was stale, retry */ 11890Sstevel@tonic-gate if (scf_pg_update(gpg) == -1) { 11900Sstevel@tonic-gate ret = -1; 11910Sstevel@tonic-gate goto out; 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate scf_transaction_reset(tx); 11940Sstevel@tonic-gate } 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate } while (ret == 0); 11970Sstevel@tonic-gate out: 11980Sstevel@tonic-gate scf_value_destroy(v); 11990Sstevel@tonic-gate scf_entry_destroy(ent); 12000Sstevel@tonic-gate scf_transaction_destroy(tx); 12010Sstevel@tonic-gate scf_property_destroy(eprop); 12020Sstevel@tonic-gate scf_service_destroy(svc); 12030Sstevel@tonic-gate scf_pg_destroy(gpg); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate return (ret); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate /* 12090Sstevel@tonic-gate * list_callback is the callback function to be handed to simple_walk_instances 12100Sstevel@tonic-gate * in main. It is called once on every instance on a machine. If that 12110Sstevel@tonic-gate * instance is controlled by inetd, we test whether it's the same 12120Sstevel@tonic-gate * service that we're looking at from the inetd.conf file, and enable it if 12130Sstevel@tonic-gate * they are the same. 12140Sstevel@tonic-gate */ 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate /*ARGSUSED*/ 12170Sstevel@tonic-gate static int 12180Sstevel@tonic-gate list_callback(scf_handle_t *h, scf_instance_t *inst, void *buf) 12190Sstevel@tonic-gate { 12200Sstevel@tonic-gate ssize_t max_name_length; 12210Sstevel@tonic-gate char *svc_name; 12220Sstevel@tonic-gate scf_simple_prop_t *prop = NULL; 12230Sstevel@tonic-gate scf_simple_prop_t *sockprop = NULL; 12240Sstevel@tonic-gate scf_simple_prop_t *rpcprop = NULL; 12250Sstevel@tonic-gate scf_simple_prop_t *progprop = NULL; 12260Sstevel@tonic-gate const char *name, *endpoint, *restart_str, *prog; 12270Sstevel@tonic-gate struct inetconfent *iconf = (struct inetconfent *)buf; 12280Sstevel@tonic-gate uint8_t *isrpc; 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 12310Sstevel@tonic-gate if ((svc_name = malloc(max_name_length + 1)) == NULL) { 12320Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error: Out of memory.\n")); 12330Sstevel@tonic-gate return (SCF_FAILED); 12340Sstevel@tonic-gate } 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate /* 12370Sstevel@tonic-gate * Get the FMRI of the instance, and check if its delegated restarter 12380Sstevel@tonic-gate * is inetd. A missing or empty restarter property implies that 12390Sstevel@tonic-gate * svc.startd is the restarter. 12400Sstevel@tonic-gate */ 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate if (scf_instance_to_fmri(inst, svc_name, max_name_length) < 0) { 12430Sstevel@tonic-gate (void) fprintf(stderr, 12440Sstevel@tonic-gate gettext("Error: Unable to obtain FMRI for service %1$s."), 12450Sstevel@tonic-gate svc_name); 12460Sstevel@tonic-gate free(svc_name); 12470Sstevel@tonic-gate return (SCF_FAILED); 12480Sstevel@tonic-gate } 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate if ((prop = scf_simple_prop_get(h, svc_name, SCF_PG_GENERAL, 12510Sstevel@tonic-gate SCF_PROPERTY_RESTARTER)) == NULL) 12520Sstevel@tonic-gate goto out; 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) 12550Sstevel@tonic-gate goto out; 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate if (strcmp(restart_str, INETD_INSTANCE_FMRI) != 0) 12580Sstevel@tonic-gate goto out; 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate /* Free restarter prop so it can be reused below */ 12610Sstevel@tonic-gate scf_simple_prop_free(prop); 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate /* 12640Sstevel@tonic-gate * We know that this instance is managed by inetd. 12650Sstevel@tonic-gate * Now get the properties needed to decide if it matches this 12660Sstevel@tonic-gate * line in the old config file. 12670Sstevel@tonic-gate */ 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate if (((prop = scf_simple_prop_get(h, svc_name, PG_NAME_SERVICE_CONFIG, 12700Sstevel@tonic-gate PR_SVC_NAME_NAME)) == NULL) || 12710Sstevel@tonic-gate ((name = scf_simple_prop_next_astring(prop)) == NULL)) { 12720Sstevel@tonic-gate property_error(svc_name, PR_SVC_NAME_NAME); 12730Sstevel@tonic-gate goto out; 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate if (((sockprop = scf_simple_prop_get(h, svc_name, 12770Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_SOCK_TYPE_NAME)) == NULL) || 12780Sstevel@tonic-gate ((endpoint = scf_simple_prop_next_astring(sockprop)) == NULL)) { 12790Sstevel@tonic-gate property_error(svc_name, PR_SOCK_TYPE_NAME); 12800Sstevel@tonic-gate goto out; 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate if (((rpcprop = scf_simple_prop_get(h, svc_name, 12840Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_ISRPC_NAME)) == NULL) || 12850Sstevel@tonic-gate ((isrpc = scf_simple_prop_next_boolean(rpcprop)) == NULL)) { 12860Sstevel@tonic-gate property_error(svc_name, PR_ISRPC_NAME); 12870Sstevel@tonic-gate goto out; 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate if (((progprop = scf_simple_prop_get(h, svc_name, START_METHOD_NAME, 12910Sstevel@tonic-gate PR_EXEC_NAME)) == NULL) || 12920Sstevel@tonic-gate ((prog = scf_simple_prop_next_astring(progprop)) == NULL)) { 12930Sstevel@tonic-gate property_error(svc_name, PR_EXEC_NAME); 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate /* If it's RPC, we truncate off the version portion for comparison */ 12980Sstevel@tonic-gate if (*isrpc) { 12990Sstevel@tonic-gate char *cp; 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate cp = strchr(iconf->service, '/'); 13020Sstevel@tonic-gate if (cp != NULL) 13030Sstevel@tonic-gate *cp = '\0'; 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate /* 13070Sstevel@tonic-gate * If name of this service and endpoint are equal to values from 13080Sstevel@tonic-gate * iconf fields, and they're either both RPC or both non-RPC, 13090Sstevel@tonic-gate * then we have a match; update the exec and arg0 properties if 13100Sstevel@tonic-gate * necessary, then enable it. 13110Sstevel@tonic-gate * We don't return an error if either operation fails so that we 13120Sstevel@tonic-gate * continue to try all the other services. 13130Sstevel@tonic-gate */ 13140Sstevel@tonic-gate if (strcmp(name, iconf->service) == 0 && 13150Sstevel@tonic-gate strcmp(endpoint, iconf->endpoint) == 0 && 13160Sstevel@tonic-gate *isrpc == (strncmp(iconf->protocol, "rpc/", 4) == 0)) { 13170Sstevel@tonic-gate /* Can't update exec on internal services */ 13180Sstevel@tonic-gate if ((strcmp(iconf->server_program, "internal") != 0) && 13190Sstevel@tonic-gate (strcmp(iconf->exec, prog) != 0)) { 13200Sstevel@tonic-gate /* User had edited the command */ 13210Sstevel@tonic-gate if (!import) { 13220Sstevel@tonic-gate /* Dry run only */ 13230Sstevel@tonic-gate (void) printf( 13240Sstevel@tonic-gate gettext("Would update %s to %s %s"), 13250Sstevel@tonic-gate svc_name, PR_EXEC_NAME, iconf->exec); 13260Sstevel@tonic-gate if (iconf->arg0 != NULL) { 13270Sstevel@tonic-gate (void) printf( 13280Sstevel@tonic-gate gettext(" with %s of %s\n"), 13290Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0); 13300Sstevel@tonic-gate } else { 13310Sstevel@tonic-gate (void) printf("\n"); 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate } else { 13340Sstevel@tonic-gate /* Update instance's exec property */ 13350Sstevel@tonic-gate if (modify_sprop(h, inst, START_METHOD_NAME, 13360Sstevel@tonic-gate PR_EXEC_NAME, iconf->exec) != 1) 13370Sstevel@tonic-gate (void) fprintf(stderr, 13380Sstevel@tonic-gate gettext("Error: Unable to update " 13390Sstevel@tonic-gate "%s property of %s, %s\n"), 13400Sstevel@tonic-gate PR_EXEC_NAME, svc_name, 13410Sstevel@tonic-gate scf_strerror(scf_error())); 13420Sstevel@tonic-gate else 13430Sstevel@tonic-gate (void) printf("%s will %s %s\n", 13440Sstevel@tonic-gate svc_name, PR_EXEC_NAME, 13450Sstevel@tonic-gate iconf->exec); 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate /* Update arg0 prop, if needed */ 13480Sstevel@tonic-gate if (iconf->arg0 != NULL) { 13490Sstevel@tonic-gate if (modify_sprop(h, inst, 13500Sstevel@tonic-gate START_METHOD_NAME, PR_ARG0_NAME, 13510Sstevel@tonic-gate iconf->arg0) != 1) { 13520Sstevel@tonic-gate (void) fprintf(stderr, 13530Sstevel@tonic-gate gettext("Error: Unable to " 13540Sstevel@tonic-gate "update %s property of " 13550Sstevel@tonic-gate "%s, %s\n"), PR_ARG0_NAME, 13560Sstevel@tonic-gate svc_name, 13570Sstevel@tonic-gate scf_strerror(scf_error())); 13580Sstevel@tonic-gate } else { 13590Sstevel@tonic-gate (void) printf("%s will have an " 13600Sstevel@tonic-gate "%s of %s\n", svc_name, 13610Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0); 13620Sstevel@tonic-gate } 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate if (!import) { 13680Sstevel@tonic-gate /* Dry-run only */ 13690Sstevel@tonic-gate (void) printf("Would enable %s\n", svc_name); 13700Sstevel@tonic-gate } else { 13710Sstevel@tonic-gate if (smf_enable_instance(svc_name, 0) != 0) 13720Sstevel@tonic-gate (void) fprintf(stderr, 13730Sstevel@tonic-gate gettext("Error: Failed to enable %s\n"), 13740Sstevel@tonic-gate svc_name); 13750Sstevel@tonic-gate else 13760Sstevel@tonic-gate (void) printf("%s enabled\n", svc_name); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate out: 13810Sstevel@tonic-gate free(svc_name); 13820Sstevel@tonic-gate scf_simple_prop_free(prop); 13830Sstevel@tonic-gate scf_simple_prop_free(sockprop); 13840Sstevel@tonic-gate scf_simple_prop_free(rpcprop); 13850Sstevel@tonic-gate scf_simple_prop_free(progprop); 13860Sstevel@tonic-gate return (SCF_SUCCESS); 13870Sstevel@tonic-gate } 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate static void 13900Sstevel@tonic-gate usage(void) 13910Sstevel@tonic-gate { 13920Sstevel@tonic-gate (void) fprintf(stderr, gettext( 13930Sstevel@tonic-gate "Usage: %s [-fn] [-i srcfile] [-o destdir]\n" 13940Sstevel@tonic-gate " %1$s -e [-n] [-i srcfile]\n" 13950Sstevel@tonic-gate "-? Display this usage message\n" 13960Sstevel@tonic-gate "-e Enable smf services which are enabled in the input\n" 13970Sstevel@tonic-gate " file\n" 13980Sstevel@tonic-gate "-f Force overwrite of existing manifests\n" 13990Sstevel@tonic-gate "-n Do not import converted manifests,\n" 14000Sstevel@tonic-gate " or only display services which would be enabled\n" 14010Sstevel@tonic-gate "-i srcfile Alternate input file\n" 14020Sstevel@tonic-gate "-o destdir Alternate output directory for manifests\n"), 14030Sstevel@tonic-gate progname); 14040Sstevel@tonic-gate exit(EXIT_USAGE); 14050Sstevel@tonic-gate } 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate int 14080Sstevel@tonic-gate main(int argc, char *argv[]) 14090Sstevel@tonic-gate { 14100Sstevel@tonic-gate int c, rval, convert_err, import_err = 0, enable_err = 0; 14110Sstevel@tonic-gate boolean_t overwrite = B_FALSE; 14120Sstevel@tonic-gate boolean_t enable = B_FALSE; 14130Sstevel@tonic-gate char *srcfile = NULL; 14140Sstevel@tonic-gate char *destdir = NULL; 14150Sstevel@tonic-gate struct fileinfo *srcfinfo, *dstfinfo; 14160Sstevel@tonic-gate struct inetconfent *iconf; 14170Sstevel@tonic-gate 14180Sstevel@tonic-gate setbuf(stdout, NULL); 14190Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 14200Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) == NULL) 14230Sstevel@tonic-gate progname = argv[0]; 14240Sstevel@tonic-gate else 14250Sstevel@tonic-gate progname++; 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate while ((c = getopt(argc, argv, "?efni:o:")) != -1) { 14280Sstevel@tonic-gate switch (c) { 14290Sstevel@tonic-gate case 'e': 14300Sstevel@tonic-gate /* enable services based on existing file config */ 14310Sstevel@tonic-gate enable = B_TRUE; 14320Sstevel@tonic-gate break; 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate case 'f': 14350Sstevel@tonic-gate /* overwrite existing manifests */ 14360Sstevel@tonic-gate overwrite = B_TRUE; 14370Sstevel@tonic-gate break; 14380Sstevel@tonic-gate case 'n': 14390Sstevel@tonic-gate /* don't import manifests, or dry-run enable */ 14400Sstevel@tonic-gate import = B_FALSE; 14410Sstevel@tonic-gate break; 14420Sstevel@tonic-gate case 'i': 14430Sstevel@tonic-gate /* alternate input file */ 14440Sstevel@tonic-gate if (srcfile != NULL) { 14450Sstevel@tonic-gate (void) fprintf(stderr, 14460Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"), 14470Sstevel@tonic-gate progname, optopt); 14480Sstevel@tonic-gate usage(); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate srcfile = optarg; 14510Sstevel@tonic-gate break; 14520Sstevel@tonic-gate case 'o': 14530Sstevel@tonic-gate /* alternate output directory */ 14540Sstevel@tonic-gate if (destdir != NULL) { 14550Sstevel@tonic-gate (void) fprintf(stderr, 14560Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"), 14570Sstevel@tonic-gate progname, optopt); 14580Sstevel@tonic-gate usage(); 14590Sstevel@tonic-gate } 14600Sstevel@tonic-gate destdir = optarg; 14610Sstevel@tonic-gate break; 14620Sstevel@tonic-gate case '?': /*FALLTHROUGH*/ 14630Sstevel@tonic-gate default: 14640Sstevel@tonic-gate usage(); 14650Sstevel@tonic-gate break; 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /* 14700Sstevel@tonic-gate * Display usage if extraneous args supplied or enable specified in 14710Sstevel@tonic-gate * combination with overwrite or destdir 14720Sstevel@tonic-gate */ 14730Sstevel@tonic-gate if ((optind != argc) || (enable && (overwrite || destdir != NULL))) 14740Sstevel@tonic-gate usage(); 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate if ((srcfinfo = open_srcfile(srcfile)) == NULL) 14770Sstevel@tonic-gate return (EXIT_ERROR_CONV); 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate while ((iconf = fgetinetconfent(srcfinfo, !enable)) != NULL) { 14800Sstevel@tonic-gate /* 14810Sstevel@tonic-gate * If we're enabling, then just walk all the services for each 14820Sstevel@tonic-gate * line and enable those which match. 14830Sstevel@tonic-gate */ 14840Sstevel@tonic-gate if (enable) { 14850Sstevel@tonic-gate rval = scf_simple_walk_instances(SCF_STATE_ALL, iconf, 14860Sstevel@tonic-gate list_callback); 14870Sstevel@tonic-gate free_inetconfent(iconf); 14880Sstevel@tonic-gate if (rval == SCF_FAILED) { 14890Sstevel@tonic-gate /* Only print msg if framework error */ 14900Sstevel@tonic-gate if (scf_error() != SCF_ERROR_CALLBACK_FAILED) 14910Sstevel@tonic-gate (void) fprintf(stderr, gettext( 14920Sstevel@tonic-gate "Error walking instances: %s.\n"), 14930Sstevel@tonic-gate scf_strerror(scf_error())); 14940Sstevel@tonic-gate enable_err++; 14950Sstevel@tonic-gate break; 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate continue; 14980Sstevel@tonic-gate } 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate /* Remainder of loop used for conversion & import */ 15010Sstevel@tonic-gate if ((rval = open_dstfile(destdir, overwrite, iconf, &dstfinfo)) 15020Sstevel@tonic-gate < 0) { 15030Sstevel@tonic-gate /* 15040Sstevel@tonic-gate * Only increment error counter if the failure was 15050Sstevel@tonic-gate * other than the file already existing. 15060Sstevel@tonic-gate */ 15070Sstevel@tonic-gate if (rval == -2) 15080Sstevel@tonic-gate srcfinfo->failcnt++; 15090Sstevel@tonic-gate free_inetconfent(iconf); 15100Sstevel@tonic-gate continue; 15110Sstevel@tonic-gate } 15120Sstevel@tonic-gate rval = print_manifest(dstfinfo->fp, dstfinfo->filename, iconf); 15130Sstevel@tonic-gate (void) fclose(dstfinfo->fp); 15140Sstevel@tonic-gate if (rval == 0) { 15150Sstevel@tonic-gate if (import && 15160Sstevel@tonic-gate (import_manifest(dstfinfo->filename) != 0)) 15170Sstevel@tonic-gate import_err++; 15180Sstevel@tonic-gate } else { 15190Sstevel@tonic-gate (void) unlink(dstfinfo->filename); 15200Sstevel@tonic-gate srcfinfo->failcnt++; 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate free(dstfinfo->filename); 15230Sstevel@tonic-gate free(dstfinfo); 15240Sstevel@tonic-gate free_inetconfent(iconf); 15250Sstevel@tonic-gate } 15260Sstevel@tonic-gate (void) fclose(srcfinfo->fp); 15270Sstevel@tonic-gate convert_err = srcfinfo->failcnt; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate /* Update hash only if not in enable mode, and only if importing */ 15300Sstevel@tonic-gate if (!enable && import && (update_hash(srcfinfo->filename) != 0)) 15310Sstevel@tonic-gate import_err++; 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate free(srcfinfo); 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if (enable_err != 0) 15360Sstevel@tonic-gate return (EXIT_ERROR_ENBL); 15370Sstevel@tonic-gate if (import_err != 0) 15380Sstevel@tonic-gate return (EXIT_ERROR_IMP); 15390Sstevel@tonic-gate if (convert_err != 0) 15400Sstevel@tonic-gate return (EXIT_ERROR_CONV); 15410Sstevel@tonic-gate return (EXIT_SUCCESS); 15420Sstevel@tonic-gate } 1543