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 #include <assert.h> 30*7c478bd9Sstevel@tonic-gate #include <libuutil.h> 31*7c478bd9Sstevel@tonic-gate #include <stdio.h> 32*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include "startd.h" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * This file contains functions for setting the environment for 41*7c478bd9Sstevel@tonic-gate * processes started by svc.startd. 42*7c478bd9Sstevel@tonic-gate */ 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #define MAXCMDL 512 45*7c478bd9Sstevel@tonic-gate #define DEF_PATH "PATH=/usr/sbin:/usr/bin" 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static char *ENVFILE = "/etc/default/init"; /* Default env. */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate static char **glob_envp; /* Array of environment strings */ 50*7c478bd9Sstevel@tonic-gate static int glob_env_n; /* Number of environment slots allocated. */ 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* 53*7c478bd9Sstevel@tonic-gate * init_env() 54*7c478bd9Sstevel@tonic-gate * A clone of the work init.c does to provide as much compatibility 55*7c478bd9Sstevel@tonic-gate * for startup scripts as possible. 56*7c478bd9Sstevel@tonic-gate */ 57*7c478bd9Sstevel@tonic-gate void 58*7c478bd9Sstevel@tonic-gate init_env() 59*7c478bd9Sstevel@tonic-gate { 60*7c478bd9Sstevel@tonic-gate int i; 61*7c478bd9Sstevel@tonic-gate char line[MAXCMDL]; 62*7c478bd9Sstevel@tonic-gate FILE *fp; 63*7c478bd9Sstevel@tonic-gate int inquotes, length, wslength; 64*7c478bd9Sstevel@tonic-gate char *tokp, *cp1, *cp2; 65*7c478bd9Sstevel@tonic-gate char **newp; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate glob_env_n = 16; 68*7c478bd9Sstevel@tonic-gate glob_envp = startd_alloc(sizeof (*glob_envp) * glob_env_n); 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate glob_envp[0] = startd_alloc((unsigned)(strlen(DEF_PATH)+2)); 71*7c478bd9Sstevel@tonic-gate (void) strcpy(glob_envp[0], DEF_PATH); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate if ((fp = fopen(ENVFILE, "r")) == NULL) { 74*7c478bd9Sstevel@tonic-gate uu_warn("Cannot open %s. Environment not initialized.\n", 75*7c478bd9Sstevel@tonic-gate ENVFILE); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate glob_envp[1] = NULL; 78*7c478bd9Sstevel@tonic-gate return; 79*7c478bd9Sstevel@tonic-gate } 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate i = 1; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate while (fgets(line, MAXCMDL - 1, fp) != NULL) { 84*7c478bd9Sstevel@tonic-gate /* 85*7c478bd9Sstevel@tonic-gate * Toss newline 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate length = strlen(line); 88*7c478bd9Sstevel@tonic-gate if (line[length - 1] == '\n') 89*7c478bd9Sstevel@tonic-gate line[length - 1] = '\0'; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Ignore blank or comment lines. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate if (line[0] == '#' || line[0] == '\0' || 95*7c478bd9Sstevel@tonic-gate (wslength = strspn(line, " \t\n")) == strlen(line) || 96*7c478bd9Sstevel@tonic-gate strchr(line, '#') == line + wslength) 97*7c478bd9Sstevel@tonic-gate continue; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate * First make a pass through the line and change 101*7c478bd9Sstevel@tonic-gate * any non-quoted semi-colons to blanks so they 102*7c478bd9Sstevel@tonic-gate * will be treated as token separators below. 103*7c478bd9Sstevel@tonic-gate */ 104*7c478bd9Sstevel@tonic-gate inquotes = 0; 105*7c478bd9Sstevel@tonic-gate for (cp1 = line; *cp1 != '\0'; cp1++) { 106*7c478bd9Sstevel@tonic-gate if (*cp1 == '"') { 107*7c478bd9Sstevel@tonic-gate if (inquotes == 0) 108*7c478bd9Sstevel@tonic-gate inquotes = 1; 109*7c478bd9Sstevel@tonic-gate else 110*7c478bd9Sstevel@tonic-gate inquotes = 0; 111*7c478bd9Sstevel@tonic-gate } else if (*cp1 == ';') { 112*7c478bd9Sstevel@tonic-gate if (inquotes == 0) 113*7c478bd9Sstevel@tonic-gate *cp1 = ' '; 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * Tokens within the line are separated by blanks 119*7c478bd9Sstevel@tonic-gate * and tabs. For each token in the line which 120*7c478bd9Sstevel@tonic-gate * contains a '=' we strip out any quotes and then 121*7c478bd9Sstevel@tonic-gate * stick the token in the environment array. 122*7c478bd9Sstevel@tonic-gate */ 123*7c478bd9Sstevel@tonic-gate if ((tokp = strtok(line, " \t")) == NULL) 124*7c478bd9Sstevel@tonic-gate continue; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate do { 127*7c478bd9Sstevel@tonic-gate cp1 = strchr(tokp, '='); 128*7c478bd9Sstevel@tonic-gate if (cp1 == NULL || cp1 == tokp) 129*7c478bd9Sstevel@tonic-gate continue; 130*7c478bd9Sstevel@tonic-gate length = strlen(tokp); 131*7c478bd9Sstevel@tonic-gate while ((cp1 = strpbrk(tokp, "\"\'")) != NULL) { 132*7c478bd9Sstevel@tonic-gate for (cp2 = cp1; cp2 < &tokp[length]; cp2++) 133*7c478bd9Sstevel@tonic-gate *cp2 = *(cp2 + 1); 134*7c478bd9Sstevel@tonic-gate length--; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * init already started us with this umask, and we 139*7c478bd9Sstevel@tonic-gate * handled it in startd.c, so just skip it. 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate if (strncmp(tokp, "CMASK=", 6) == 0 || 142*7c478bd9Sstevel@tonic-gate strncmp(tokp, "SMF_", 4) == 0) 143*7c478bd9Sstevel@tonic-gate continue; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate glob_envp[i] = startd_alloc((unsigned)(length + 1)); 146*7c478bd9Sstevel@tonic-gate (void) strcpy(glob_envp[i], tokp); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * Double the environment size whenever it is 150*7c478bd9Sstevel@tonic-gate * full. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate if (++i == glob_env_n) { 153*7c478bd9Sstevel@tonic-gate glob_env_n *= 2; 154*7c478bd9Sstevel@tonic-gate newp = startd_alloc(sizeof (*glob_envp) * 155*7c478bd9Sstevel@tonic-gate glob_env_n); 156*7c478bd9Sstevel@tonic-gate (void) memcpy(newp, glob_envp, 157*7c478bd9Sstevel@tonic-gate sizeof (*glob_envp) * glob_env_n / 2); 158*7c478bd9Sstevel@tonic-gate startd_free(glob_envp, 159*7c478bd9Sstevel@tonic-gate sizeof (*glob_envp) * glob_env_n / 2); 160*7c478bd9Sstevel@tonic-gate glob_envp = newp; 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate } while ((tokp = strtok(NULL, " \t")) != NULL); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate startd_fclose(fp); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate /* Append a null pointer to the environment array to mark its end. */ 168*7c478bd9Sstevel@tonic-gate glob_envp[i] = NULL; 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate static int 172*7c478bd9Sstevel@tonic-gate valid_env_var(const char *var, const restarter_inst_t *inst, const char *path) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate char *cp = strchr(var, '='); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate if (cp == NULL || cp == var) { 177*7c478bd9Sstevel@tonic-gate if (inst != NULL) 178*7c478bd9Sstevel@tonic-gate log_instance(inst, B_FALSE, "Invalid environment " 179*7c478bd9Sstevel@tonic-gate "variable \"%s\".", var); 180*7c478bd9Sstevel@tonic-gate return (0); 181*7c478bd9Sstevel@tonic-gate } else if (strncmp(var, "SMF_", 4) == 0) { 182*7c478bd9Sstevel@tonic-gate if (inst != NULL) 183*7c478bd9Sstevel@tonic-gate log_instance(inst, B_FALSE, "Invalid environment " 184*7c478bd9Sstevel@tonic-gate "variable \"%s\"; \"SMF_\" prefix is reserved.", 185*7c478bd9Sstevel@tonic-gate var); 186*7c478bd9Sstevel@tonic-gate return (0); 187*7c478bd9Sstevel@tonic-gate } else if (path != NULL && strncmp(var, "PATH=", 5) == 0) { 188*7c478bd9Sstevel@tonic-gate return (0); 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate return (1); 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate static char ** 195*7c478bd9Sstevel@tonic-gate find_dup(const char *var, char **env, const restarter_inst_t *inst) 196*7c478bd9Sstevel@tonic-gate { 197*7c478bd9Sstevel@tonic-gate char **p; 198*7c478bd9Sstevel@tonic-gate char *tmp; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate for (p = env; *p != NULL; p++) { 201*7c478bd9Sstevel@tonic-gate assert((tmp = strchr(*p, '=')) != NULL); 202*7c478bd9Sstevel@tonic-gate tmp++; 203*7c478bd9Sstevel@tonic-gate if (strncmp(*p, var, tmp - *p) == 0) 204*7c478bd9Sstevel@tonic-gate break; 205*7c478bd9Sstevel@tonic-gate } 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate if (*p == NULL) 208*7c478bd9Sstevel@tonic-gate return (NULL); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate if (inst != NULL) 211*7c478bd9Sstevel@tonic-gate log_instance(inst, B_FALSE, "Ignoring duplicate " 212*7c478bd9Sstevel@tonic-gate "environment variable \"%s\".", *p); 213*7c478bd9Sstevel@tonic-gate return (p); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * Create an environment which is appropriate for spawning an SMF 218*7c478bd9Sstevel@tonic-gate * aware process. The new environment will consist of the values from 219*7c478bd9Sstevel@tonic-gate * the global environment as modified by the supplied (local) environment. 220*7c478bd9Sstevel@tonic-gate * 221*7c478bd9Sstevel@tonic-gate * In order to preserve the correctness of the new environment, 222*7c478bd9Sstevel@tonic-gate * various checks are performed on the local environment (init_env() 223*7c478bd9Sstevel@tonic-gate * is relied upon to ensure the global environment is correct): 224*7c478bd9Sstevel@tonic-gate * 225*7c478bd9Sstevel@tonic-gate * - All SMF_ entries are ignored. All SMF_ entries should be provided 226*7c478bd9Sstevel@tonic-gate * by this function. 227*7c478bd9Sstevel@tonic-gate * - Duplicates in the entry are eliminated. 228*7c478bd9Sstevel@tonic-gate * - Malformed entries are eliminated. 229*7c478bd9Sstevel@tonic-gate * 230*7c478bd9Sstevel@tonic-gate * Detected errors are logged as warnings to the appropriate instance 231*7c478bd9Sstevel@tonic-gate * logfile, since a single bad entry should not be enough to prevent 232*7c478bd9Sstevel@tonic-gate * an SMF_ functional environment from being created. The faulty entry 233*7c478bd9Sstevel@tonic-gate * is then ignored when building the environment. 234*7c478bd9Sstevel@tonic-gate * 235*7c478bd9Sstevel@tonic-gate * If env is NULL, then the return is an environment which contains 236*7c478bd9Sstevel@tonic-gate * all default values. 237*7c478bd9Sstevel@tonic-gate * 238*7c478bd9Sstevel@tonic-gate * If "path" is non-NULL, it will silently over-ride any previous 239*7c478bd9Sstevel@tonic-gate * PATH environment variable. 240*7c478bd9Sstevel@tonic-gate * 241*7c478bd9Sstevel@tonic-gate * NB: The returned env and strings are allocated using startd_alloc(). 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate char ** 244*7c478bd9Sstevel@tonic-gate set_smf_env(char **env, size_t env_sz, const char *path, 245*7c478bd9Sstevel@tonic-gate const restarter_inst_t *inst, const char *method) 246*7c478bd9Sstevel@tonic-gate { 247*7c478bd9Sstevel@tonic-gate char **nenv; 248*7c478bd9Sstevel@tonic-gate char **p, **np; 249*7c478bd9Sstevel@tonic-gate size_t nenv_size; 250*7c478bd9Sstevel@tonic-gate size_t sz; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* 253*7c478bd9Sstevel@tonic-gate * Max. of glob_env, env, three SMF_ variables, 254*7c478bd9Sstevel@tonic-gate * path, and terminating NULL. 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate nenv_size = glob_env_n + env_sz + 3 + 1 + 1; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate nenv = startd_zalloc(sizeof (char *) * nenv_size); 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate np = nenv; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate if (path != NULL) { 263*7c478bd9Sstevel@tonic-gate sz = strlen(path) + 1; 264*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 265*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, path, sz); 266*7c478bd9Sstevel@tonic-gate np++; 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate if (inst) { 271*7c478bd9Sstevel@tonic-gate sz = sizeof ("SMF_FMRI=") + strlen(inst->ri_i.i_fmri); 272*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 273*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, "SMF_FMRI=", sz); 274*7c478bd9Sstevel@tonic-gate (void) strlcat(*np, inst->ri_i.i_fmri, sz); 275*7c478bd9Sstevel@tonic-gate np++; 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (method) { 279*7c478bd9Sstevel@tonic-gate sz = sizeof ("SMF_METHOD=") + strlen(method); 280*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 281*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, "SMF_METHOD=", sz); 282*7c478bd9Sstevel@tonic-gate (void) strlcat(*np, method, sz); 283*7c478bd9Sstevel@tonic-gate np++; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate sz = sizeof ("SMF_RESTARTER=") + strlen(SCF_SERVICE_STARTD); 287*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 288*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, "SMF_RESTARTER=", sz); 289*7c478bd9Sstevel@tonic-gate (void) strlcat(*np, SCF_SERVICE_STARTD, sz); 290*7c478bd9Sstevel@tonic-gate np++; 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate for (p = glob_envp; *p != NULL; p++) { 293*7c478bd9Sstevel@tonic-gate if (valid_env_var(*p, inst, path)) { 294*7c478bd9Sstevel@tonic-gate sz = strlen(*p) + 1; 295*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 296*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, *p, sz); 297*7c478bd9Sstevel@tonic-gate np++; 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (env) { 302*7c478bd9Sstevel@tonic-gate for (p = env; *p != NULL; p++) { 303*7c478bd9Sstevel@tonic-gate char **dup_pos; 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate if (!valid_env_var(*p, inst, path)) 306*7c478bd9Sstevel@tonic-gate continue; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate if ((dup_pos = find_dup(*p, nenv, inst)) != NULL) { 309*7c478bd9Sstevel@tonic-gate startd_free(*dup_pos, strlen(*dup_pos) + 1); 310*7c478bd9Sstevel@tonic-gate sz = strlen(*p) + 1; 311*7c478bd9Sstevel@tonic-gate *dup_pos = startd_alloc(sz); 312*7c478bd9Sstevel@tonic-gate (void) strlcpy(*dup_pos, *p, sz); 313*7c478bd9Sstevel@tonic-gate } else { 314*7c478bd9Sstevel@tonic-gate sz = strlen(*p) + 1; 315*7c478bd9Sstevel@tonic-gate *np = startd_alloc(sz); 316*7c478bd9Sstevel@tonic-gate (void) strlcpy(*np, *p, sz); 317*7c478bd9Sstevel@tonic-gate np++; 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate *np = NULL; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate return (nenv); 324*7c478bd9Sstevel@tonic-gate } 325