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 51573Sdp * Common Development and Distribution License (the "License"). 61573Sdp * 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*9263SSean.Wilcox@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <assert.h> 270Sstevel@tonic-gate #include <libuutil.h> 280Sstevel@tonic-gate #include <stdio.h> 290Sstevel@tonic-gate #include <stdlib.h> 300Sstevel@tonic-gate #include <string.h> 311573Sdp #include <zone.h> 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/stat.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include "startd.h" 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * This file contains functions for setting the environment for 390Sstevel@tonic-gate * processes started by svc.startd. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define MAXCMDL 512 430Sstevel@tonic-gate #define DEF_PATH "PATH=/usr/sbin:/usr/bin" 440Sstevel@tonic-gate 450Sstevel@tonic-gate static char *ENVFILE = "/etc/default/init"; /* Default env. */ 460Sstevel@tonic-gate 470Sstevel@tonic-gate static char **glob_envp; /* Array of environment strings */ 480Sstevel@tonic-gate static int glob_env_n; /* Number of environment slots allocated. */ 490Sstevel@tonic-gate 501573Sdp static char zonename[ZONENAME_MAX]; 511573Sdp 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * init_env() 540Sstevel@tonic-gate * A clone of the work init.c does to provide as much compatibility 550Sstevel@tonic-gate * for startup scripts as possible. 560Sstevel@tonic-gate */ 570Sstevel@tonic-gate void 580Sstevel@tonic-gate init_env() 590Sstevel@tonic-gate { 600Sstevel@tonic-gate int i; 610Sstevel@tonic-gate char line[MAXCMDL]; 620Sstevel@tonic-gate FILE *fp; 630Sstevel@tonic-gate int inquotes, length, wslength; 640Sstevel@tonic-gate char *tokp, *cp1, *cp2; 650Sstevel@tonic-gate char **newp; 660Sstevel@tonic-gate 670Sstevel@tonic-gate glob_env_n = 16; 680Sstevel@tonic-gate glob_envp = startd_alloc(sizeof (*glob_envp) * glob_env_n); 690Sstevel@tonic-gate 700Sstevel@tonic-gate glob_envp[0] = startd_alloc((unsigned)(strlen(DEF_PATH)+2)); 710Sstevel@tonic-gate (void) strcpy(glob_envp[0], DEF_PATH); 720Sstevel@tonic-gate 730Sstevel@tonic-gate if ((fp = fopen(ENVFILE, "r")) == NULL) { 740Sstevel@tonic-gate uu_warn("Cannot open %s. Environment not initialized.\n", 750Sstevel@tonic-gate ENVFILE); 760Sstevel@tonic-gate 770Sstevel@tonic-gate glob_envp[1] = NULL; 780Sstevel@tonic-gate return; 790Sstevel@tonic-gate } 800Sstevel@tonic-gate 810Sstevel@tonic-gate i = 1; 820Sstevel@tonic-gate 830Sstevel@tonic-gate while (fgets(line, MAXCMDL - 1, fp) != NULL) { 840Sstevel@tonic-gate /* 850Sstevel@tonic-gate * Toss newline 860Sstevel@tonic-gate */ 870Sstevel@tonic-gate length = strlen(line); 880Sstevel@tonic-gate if (line[length - 1] == '\n') 890Sstevel@tonic-gate line[length - 1] = '\0'; 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * Ignore blank or comment lines. 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate if (line[0] == '#' || line[0] == '\0' || 950Sstevel@tonic-gate (wslength = strspn(line, " \t\n")) == strlen(line) || 960Sstevel@tonic-gate strchr(line, '#') == line + wslength) 970Sstevel@tonic-gate continue; 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * First make a pass through the line and change 1010Sstevel@tonic-gate * any non-quoted semi-colons to blanks so they 1020Sstevel@tonic-gate * will be treated as token separators below. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate inquotes = 0; 1050Sstevel@tonic-gate for (cp1 = line; *cp1 != '\0'; cp1++) { 1060Sstevel@tonic-gate if (*cp1 == '"') { 1070Sstevel@tonic-gate if (inquotes == 0) 1080Sstevel@tonic-gate inquotes = 1; 1090Sstevel@tonic-gate else 1100Sstevel@tonic-gate inquotes = 0; 1110Sstevel@tonic-gate } else if (*cp1 == ';') { 1120Sstevel@tonic-gate if (inquotes == 0) 1130Sstevel@tonic-gate *cp1 = ' '; 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Tokens within the line are separated by blanks 1190Sstevel@tonic-gate * and tabs. For each token in the line which 1200Sstevel@tonic-gate * contains a '=' we strip out any quotes and then 1210Sstevel@tonic-gate * stick the token in the environment array. 1220Sstevel@tonic-gate */ 1230Sstevel@tonic-gate if ((tokp = strtok(line, " \t")) == NULL) 1240Sstevel@tonic-gate continue; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate do { 1270Sstevel@tonic-gate cp1 = strchr(tokp, '='); 1280Sstevel@tonic-gate if (cp1 == NULL || cp1 == tokp) 1290Sstevel@tonic-gate continue; 1300Sstevel@tonic-gate length = strlen(tokp); 1310Sstevel@tonic-gate while ((cp1 = strpbrk(tokp, "\"\'")) != NULL) { 1320Sstevel@tonic-gate for (cp2 = cp1; cp2 < &tokp[length]; cp2++) 1330Sstevel@tonic-gate *cp2 = *(cp2 + 1); 1340Sstevel@tonic-gate length--; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * init already started us with this umask, and we 1390Sstevel@tonic-gate * handled it in startd.c, so just skip it. 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate if (strncmp(tokp, "CMASK=", 6) == 0 || 1420Sstevel@tonic-gate strncmp(tokp, "SMF_", 4) == 0) 1430Sstevel@tonic-gate continue; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate glob_envp[i] = startd_alloc((unsigned)(length + 1)); 1460Sstevel@tonic-gate (void) strcpy(glob_envp[i], tokp); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* 1490Sstevel@tonic-gate * Double the environment size whenever it is 1500Sstevel@tonic-gate * full. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate if (++i == glob_env_n) { 1530Sstevel@tonic-gate glob_env_n *= 2; 1540Sstevel@tonic-gate newp = startd_alloc(sizeof (*glob_envp) * 1550Sstevel@tonic-gate glob_env_n); 1560Sstevel@tonic-gate (void) memcpy(newp, glob_envp, 1570Sstevel@tonic-gate sizeof (*glob_envp) * glob_env_n / 2); 1580Sstevel@tonic-gate startd_free(glob_envp, 1590Sstevel@tonic-gate sizeof (*glob_envp) * glob_env_n / 2); 1600Sstevel@tonic-gate glob_envp = newp; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate } while ((tokp = strtok(NULL, " \t")) != NULL); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate startd_fclose(fp); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* Append a null pointer to the environment array to mark its end. */ 1680Sstevel@tonic-gate glob_envp[i] = NULL; 1691573Sdp 1701573Sdp /* 1711573Sdp * Get the zonename once; it is used to set SMF_ZONENAME for methods. 1721573Sdp */ 1731573Sdp (void) getzonenamebyid(getzoneid(), zonename, sizeof (zonename)); 1741573Sdp 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate valid_env_var(const char *var, const restarter_inst_t *inst, const char *path) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate char *cp = strchr(var, '='); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (cp == NULL || cp == var) { 1830Sstevel@tonic-gate if (inst != NULL) 1840Sstevel@tonic-gate log_instance(inst, B_FALSE, "Invalid environment " 1850Sstevel@tonic-gate "variable \"%s\".", var); 1860Sstevel@tonic-gate return (0); 1870Sstevel@tonic-gate } else if (strncmp(var, "SMF_", 4) == 0) { 1880Sstevel@tonic-gate if (inst != NULL) 1890Sstevel@tonic-gate log_instance(inst, B_FALSE, "Invalid environment " 1900Sstevel@tonic-gate "variable \"%s\"; \"SMF_\" prefix is reserved.", 1910Sstevel@tonic-gate var); 1920Sstevel@tonic-gate return (0); 1930Sstevel@tonic-gate } else if (path != NULL && strncmp(var, "PATH=", 5) == 0) { 1940Sstevel@tonic-gate return (0); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate return (1); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate static char ** 2010Sstevel@tonic-gate find_dup(const char *var, char **env, const restarter_inst_t *inst) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate char **p; 2040Sstevel@tonic-gate char *tmp; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate for (p = env; *p != NULL; p++) { 2070Sstevel@tonic-gate assert((tmp = strchr(*p, '=')) != NULL); 2080Sstevel@tonic-gate tmp++; 2090Sstevel@tonic-gate if (strncmp(*p, var, tmp - *p) == 0) 2100Sstevel@tonic-gate break; 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate if (*p == NULL) 2140Sstevel@tonic-gate return (NULL); 2150Sstevel@tonic-gate 216*9263SSean.Wilcox@Sun.COM /* 217*9263SSean.Wilcox@Sun.COM * The first entry in the array can be ignored when it is the 218*9263SSean.Wilcox@Sun.COM * default path. 219*9263SSean.Wilcox@Sun.COM */ 220*9263SSean.Wilcox@Sun.COM if (inst != NULL && p != env && 221*9263SSean.Wilcox@Sun.COM strncmp(*p, DEF_PATH, strlen(DEF_PATH)) != 0) { 2220Sstevel@tonic-gate log_instance(inst, B_FALSE, "Ignoring duplicate " 2230Sstevel@tonic-gate "environment variable \"%s\".", *p); 224*9263SSean.Wilcox@Sun.COM } 225*9263SSean.Wilcox@Sun.COM 2260Sstevel@tonic-gate return (p); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Create an environment which is appropriate for spawning an SMF 2310Sstevel@tonic-gate * aware process. The new environment will consist of the values from 2320Sstevel@tonic-gate * the global environment as modified by the supplied (local) environment. 2330Sstevel@tonic-gate * 2340Sstevel@tonic-gate * In order to preserve the correctness of the new environment, 2350Sstevel@tonic-gate * various checks are performed on the local environment (init_env() 2360Sstevel@tonic-gate * is relied upon to ensure the global environment is correct): 2370Sstevel@tonic-gate * 2380Sstevel@tonic-gate * - All SMF_ entries are ignored. All SMF_ entries should be provided 2390Sstevel@tonic-gate * by this function. 2400Sstevel@tonic-gate * - Duplicates in the entry are eliminated. 2410Sstevel@tonic-gate * - Malformed entries are eliminated. 2420Sstevel@tonic-gate * 2430Sstevel@tonic-gate * Detected errors are logged as warnings to the appropriate instance 2440Sstevel@tonic-gate * logfile, since a single bad entry should not be enough to prevent 2450Sstevel@tonic-gate * an SMF_ functional environment from being created. The faulty entry 2460Sstevel@tonic-gate * is then ignored when building the environment. 2470Sstevel@tonic-gate * 2480Sstevel@tonic-gate * If env is NULL, then the return is an environment which contains 2490Sstevel@tonic-gate * all default values. 2500Sstevel@tonic-gate * 2510Sstevel@tonic-gate * If "path" is non-NULL, it will silently over-ride any previous 2520Sstevel@tonic-gate * PATH environment variable. 2530Sstevel@tonic-gate * 2540Sstevel@tonic-gate * NB: The returned env and strings are allocated using startd_alloc(). 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate char ** 2570Sstevel@tonic-gate set_smf_env(char **env, size_t env_sz, const char *path, 2580Sstevel@tonic-gate const restarter_inst_t *inst, const char *method) 2590Sstevel@tonic-gate { 2600Sstevel@tonic-gate char **nenv; 2610Sstevel@tonic-gate char **p, **np; 2620Sstevel@tonic-gate size_t nenv_size; 2630Sstevel@tonic-gate size_t sz; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2661573Sdp * Max. of glob_env, env, four SMF_ variables, 2670Sstevel@tonic-gate * path, and terminating NULL. 2680Sstevel@tonic-gate */ 2691573Sdp nenv_size = glob_env_n + env_sz + 4 + 1 + 1; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate nenv = startd_zalloc(sizeof (char *) * nenv_size); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate np = nenv; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (path != NULL) { 2760Sstevel@tonic-gate sz = strlen(path) + 1; 2770Sstevel@tonic-gate *np = startd_alloc(sz); 2780Sstevel@tonic-gate (void) strlcpy(*np, path, sz); 2790Sstevel@tonic-gate np++; 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate if (inst) { 2830Sstevel@tonic-gate sz = sizeof ("SMF_FMRI=") + strlen(inst->ri_i.i_fmri); 2840Sstevel@tonic-gate *np = startd_alloc(sz); 2850Sstevel@tonic-gate (void) strlcpy(*np, "SMF_FMRI=", sz); 2860Sstevel@tonic-gate (void) strlcat(*np, inst->ri_i.i_fmri, sz); 2870Sstevel@tonic-gate np++; 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate if (method) { 2910Sstevel@tonic-gate sz = sizeof ("SMF_METHOD=") + strlen(method); 2920Sstevel@tonic-gate *np = startd_alloc(sz); 2930Sstevel@tonic-gate (void) strlcpy(*np, "SMF_METHOD=", sz); 2940Sstevel@tonic-gate (void) strlcat(*np, method, sz); 2950Sstevel@tonic-gate np++; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate sz = sizeof ("SMF_RESTARTER=") + strlen(SCF_SERVICE_STARTD); 2990Sstevel@tonic-gate *np = startd_alloc(sz); 3000Sstevel@tonic-gate (void) strlcpy(*np, "SMF_RESTARTER=", sz); 3010Sstevel@tonic-gate (void) strlcat(*np, SCF_SERVICE_STARTD, sz); 3020Sstevel@tonic-gate np++; 3030Sstevel@tonic-gate 3041573Sdp sz = sizeof ("SMF_ZONENAME=") + strlen(zonename); 3051573Sdp *np = startd_alloc(sz); 3061573Sdp (void) strlcpy(*np, "SMF_ZONENAME=", sz); 3071573Sdp (void) strlcat(*np, zonename, sz); 3081573Sdp np++; 3091573Sdp 3100Sstevel@tonic-gate for (p = glob_envp; *p != NULL; p++) { 3110Sstevel@tonic-gate if (valid_env_var(*p, inst, path)) { 3120Sstevel@tonic-gate sz = strlen(*p) + 1; 3130Sstevel@tonic-gate *np = startd_alloc(sz); 3140Sstevel@tonic-gate (void) strlcpy(*np, *p, sz); 3150Sstevel@tonic-gate np++; 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate if (env) { 3200Sstevel@tonic-gate for (p = env; *p != NULL; p++) { 3210Sstevel@tonic-gate char **dup_pos; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (!valid_env_var(*p, inst, path)) 3240Sstevel@tonic-gate continue; 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate if ((dup_pos = find_dup(*p, nenv, inst)) != NULL) { 3270Sstevel@tonic-gate startd_free(*dup_pos, strlen(*dup_pos) + 1); 3280Sstevel@tonic-gate sz = strlen(*p) + 1; 3290Sstevel@tonic-gate *dup_pos = startd_alloc(sz); 3300Sstevel@tonic-gate (void) strlcpy(*dup_pos, *p, sz); 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate sz = strlen(*p) + 1; 3330Sstevel@tonic-gate *np = startd_alloc(sz); 3340Sstevel@tonic-gate (void) strlcpy(*np, *p, sz); 3350Sstevel@tonic-gate np++; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate *np = NULL; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate return (nenv); 3420Sstevel@tonic-gate } 343