1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. 25 */ 26 27 #include <assert.h> 28 #include <definit.h> 29 #include <libuutil.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <zone.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 37 #include "startd.h" 38 39 /* 40 * This file contains functions for setting the environment for 41 * processes started by svc.startd. 42 */ 43 44 #define MAXCMDL 512 45 #define DEF_PATH "PATH=/usr/sbin:/usr/bin" 46 47 static char **glob_envp; /* Array of environment strings */ 48 static int glob_env_n; /* Number of environment slots allocated. */ 49 50 static char zonename[ZONENAME_MAX]; 51 52 /* 53 * init_env() 54 * A clone of the work init.c does to provide as much compatibility 55 * for startup scripts as possible. 56 */ 57 void 58 init_env() 59 { 60 void *dstate; 61 const char *tokp; 62 int i; 63 64 glob_env_n = 16; 65 glob_envp = startd_alloc(sizeof (*glob_envp) * glob_env_n); 66 67 glob_envp[0] = startd_alloc((unsigned)(strlen(DEF_PATH)+2)); 68 (void) strcpy(glob_envp[0], DEF_PATH); 69 70 if (definit_open(DEFINIT_DEFAULT_FILE, &dstate) != 0) { 71 uu_warn("Cannot open %s. Environment not initialized.\n", 72 DEFINIT_DEFAULT_FILE); 73 74 glob_envp[1] = NULL; 75 return; 76 } 77 78 i = 1; 79 while ((tokp = definit_token(dstate)) != NULL) { 80 size_t length = strlen(tokp); 81 82 /* 83 * init already started us with this umask, and we 84 * handled it in startd.c, so just skip it. 85 */ 86 if (strncmp(tokp, "CMASK=", 6) == 0 || 87 strncmp(tokp, "SMF_", 4) == 0) { 88 continue; 89 } 90 91 glob_envp[i] = startd_alloc((unsigned)(length + 1)); 92 (void) strcpy(glob_envp[i], tokp); 93 94 /* 95 * Double the environment size whenever it is 96 * full. 97 */ 98 if (++i == glob_env_n) { 99 char **newp; 100 101 glob_env_n *= 2; 102 newp = startd_alloc(sizeof (*glob_envp) * glob_env_n); 103 (void) memcpy(newp, glob_envp, 104 sizeof (*glob_envp) * glob_env_n / 2); 105 startd_free(glob_envp, 106 sizeof (*glob_envp) * glob_env_n / 2); 107 glob_envp = newp; 108 } 109 } 110 111 /* Append a null pointer to the environment array to mark its end. */ 112 glob_envp[i] = NULL; 113 114 definit_close(dstate); 115 116 /* 117 * Get the zonename once; it is used to set SMF_ZONENAME for methods. 118 */ 119 (void) getzonenamebyid(getzoneid(), zonename, sizeof (zonename)); 120 121 } 122 123 static int 124 valid_env_var(const char *var, const restarter_inst_t *inst, const char *path) 125 { 126 char *cp = strchr(var, '='); 127 128 if (cp == NULL || cp == var) { 129 if (inst != NULL) 130 log_instance(inst, B_FALSE, "Invalid environment " 131 "variable \"%s\".", var); 132 return (0); 133 } else if (strncmp(var, "SMF_", 4) == 0) { 134 if (inst != NULL) 135 log_instance(inst, B_FALSE, "Invalid environment " 136 "variable \"%s\"; \"SMF_\" prefix is reserved.", 137 var); 138 return (0); 139 } else if (path != NULL && strncmp(var, "PATH=", 5) == 0) { 140 return (0); 141 } 142 143 return (1); 144 } 145 146 static char ** 147 find_dup(const char *var, char **env, const restarter_inst_t *inst) 148 { 149 char **p; 150 char *tmp; 151 152 for (p = env; *p != NULL; p++) { 153 assert((tmp = strchr(*p, '=')) != NULL); 154 tmp++; 155 if (strncmp(*p, var, tmp - *p) == 0) 156 break; 157 } 158 159 if (*p == NULL) 160 return (NULL); 161 162 /* 163 * The first entry in the array can be ignored when it is the 164 * default path. 165 */ 166 if (inst != NULL && p != env && 167 strncmp(*p, DEF_PATH, strlen(DEF_PATH)) != 0) { 168 log_instance(inst, B_FALSE, "Ignoring duplicate " 169 "environment variable \"%s\".", *p); 170 } 171 172 return (p); 173 } 174 175 /* 176 * Create an environment which is appropriate for spawning an SMF 177 * aware process. The new environment will consist of the values from 178 * the global environment as modified by the supplied (local) environment. 179 * 180 * In order to preserve the correctness of the new environment, 181 * various checks are performed on the local environment (init_env() 182 * is relied upon to ensure the global environment is correct): 183 * 184 * - All SMF_ entries are ignored. All SMF_ entries should be provided 185 * by this function. 186 * - Duplicates in the entry are eliminated. 187 * - Malformed entries are eliminated. 188 * 189 * Detected errors are logged as warnings to the appropriate instance 190 * logfile, since a single bad entry should not be enough to prevent 191 * an SMF_ functional environment from being created. The faulty entry 192 * is then ignored when building the environment. 193 * 194 * If env is NULL, then the return is an environment which contains 195 * all default values. 196 * 197 * If "path" is non-NULL, it will silently over-ride any previous 198 * PATH environment variable. 199 * 200 * NB: The returned env and strings are allocated using startd_alloc(). 201 */ 202 char ** 203 set_smf_env(char **env, size_t env_sz, const char *path, 204 const restarter_inst_t *inst, const char *method) 205 { 206 char **nenv; 207 char **p, **np; 208 size_t nenv_size; 209 size_t sz; 210 211 /* 212 * Max. of glob_env, env, four SMF_ variables, 213 * path, and terminating NULL. 214 */ 215 nenv_size = glob_env_n + env_sz + 4 + 1 + 1; 216 217 nenv = startd_zalloc(sizeof (char *) * nenv_size); 218 219 np = nenv; 220 221 if (path != NULL) { 222 sz = strlen(path) + 1; 223 *np = startd_alloc(sz); 224 (void) strlcpy(*np, path, sz); 225 np++; 226 } 227 228 if (inst) { 229 sz = sizeof ("SMF_FMRI=") + strlen(inst->ri_i.i_fmri); 230 *np = startd_alloc(sz); 231 (void) strlcpy(*np, "SMF_FMRI=", sz); 232 (void) strlcat(*np, inst->ri_i.i_fmri, sz); 233 np++; 234 } 235 236 if (method) { 237 sz = sizeof ("SMF_METHOD=") + strlen(method); 238 *np = startd_alloc(sz); 239 (void) strlcpy(*np, "SMF_METHOD=", sz); 240 (void) strlcat(*np, method, sz); 241 np++; 242 } 243 244 sz = sizeof ("SMF_RESTARTER=") + strlen(SCF_SERVICE_STARTD); 245 *np = startd_alloc(sz); 246 (void) strlcpy(*np, "SMF_RESTARTER=", sz); 247 (void) strlcat(*np, SCF_SERVICE_STARTD, sz); 248 np++; 249 250 sz = sizeof ("SMF_ZONENAME=") + strlen(zonename); 251 *np = startd_alloc(sz); 252 (void) strlcpy(*np, "SMF_ZONENAME=", sz); 253 (void) strlcat(*np, zonename, sz); 254 np++; 255 256 for (p = glob_envp; *p != NULL; p++) { 257 if (valid_env_var(*p, inst, path)) { 258 sz = strlen(*p) + 1; 259 *np = startd_alloc(sz); 260 (void) strlcpy(*np, *p, sz); 261 np++; 262 } 263 } 264 265 if (env) { 266 for (p = env; *p != NULL; p++) { 267 char **dup_pos; 268 269 if (!valid_env_var(*p, inst, path)) 270 continue; 271 272 if ((dup_pos = find_dup(*p, nenv, inst)) != NULL) { 273 startd_free(*dup_pos, strlen(*dup_pos) + 1); 274 sz = strlen(*p) + 1; 275 *dup_pos = startd_alloc(sz); 276 (void) strlcpy(*dup_pos, *p, sz); 277 } else { 278 sz = strlen(*p) + 1; 279 *np = startd_alloc(sz); 280 (void) strlcpy(*np, *p, sz); 281 np++; 282 } 283 } 284 } 285 *np = NULL; 286 287 return (nenv); 288 } 289