1 /* $OpenBSD: env.c,v 1.21 2008/02/29 23:33:29 deraadt Exp $ */ 2 3 /* Copyright 1988,1990,1993,1994 by Paul Vixie 4 * All rights reserved 5 */ 6 7 /* 8 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 #if !defined(lint) && !defined(LINT) 25 static char const rcsid[] = "$OpenBSD: env.c,v 1.21 2008/02/29 23:33:29 deraadt Exp $"; 26 #endif 27 28 #include "cron.h" 29 30 char ** 31 env_init(void) { 32 char **p = (char **) malloc(sizeof(char **)); 33 34 if (p != NULL) 35 p[0] = NULL; 36 return (p); 37 } 38 39 void 40 env_free(char **envp) { 41 char **p; 42 43 for (p = envp; *p != NULL; p++) 44 free(*p); 45 free(envp); 46 } 47 48 char ** 49 env_copy(char **envp) { 50 int count, i, save_errno; 51 char **p; 52 53 for (count = 0; envp[count] != NULL; count++) 54 continue; 55 p = (char **) calloc(count+1, sizeof(char *)); /* 1 for the NULL */ 56 if (p != NULL) { 57 for (i = 0; i < count; i++) 58 if ((p[i] = strdup(envp[i])) == NULL) { 59 save_errno = errno; 60 while (--i >= 0) 61 free(p[i]); 62 free(p); 63 errno = save_errno; 64 return (NULL); 65 } 66 p[count] = NULL; 67 } 68 return (p); 69 } 70 71 char ** 72 env_set(char **envp, char *envstr) { 73 int count, found; 74 char **p, *envtmp; 75 76 /* 77 * count the number of elements, including the null pointer; 78 * also set 'found' to -1 or index of entry if already in here. 79 */ 80 found = -1; 81 for (count = 0; envp[count] != NULL; count++) { 82 if (!strcmp_until(envp[count], envstr, '=')) 83 found = count; 84 } 85 count++; /* for the NULL */ 86 87 if (found != -1) { 88 /* 89 * it exists already, so just free the existing setting, 90 * save our new one there, and return the existing array. 91 */ 92 if ((envtmp = strdup(envstr)) == NULL) 93 return (NULL); 94 free(envp[found]); 95 envp[found] = envtmp; 96 return (envp); 97 } 98 99 /* 100 * it doesn't exist yet, so resize the array, move null pointer over 101 * one, save our string over the old null pointer, and return resized 102 * array. 103 */ 104 if ((envtmp = strdup(envstr)) == NULL) 105 return (NULL); 106 p = (char **) realloc((void *) envp, 107 (size_t) ((count+1) * sizeof(char **))); 108 if (p == NULL) { 109 free(envtmp); 110 return (NULL); 111 } 112 p[count] = p[count-1]; 113 p[count-1] = envtmp; 114 return (p); 115 } 116 117 /* The following states are used by load_env(), traversed in order: */ 118 enum env_state { 119 NAMEI, /* First char of NAME, may be quote */ 120 NAME, /* Subsequent chars of NAME */ 121 EQ1, /* After end of name, looking for '=' sign */ 122 EQ2, /* After '=', skipping whitespace */ 123 VALUEI, /* First char of VALUE, may be quote */ 124 VALUE, /* Subsequent chars of VALUE */ 125 FINI, /* All done, skipping trailing whitespace */ 126 ERROR /* Error */ 127 }; 128 129 /* return ERR = end of file 130 * FALSE = not an env setting (file was repositioned) 131 * TRUE = was an env setting 132 */ 133 int 134 load_env(char *envstr, FILE *f) { 135 long filepos; 136 int fileline; 137 enum env_state state; 138 char name[MAX_ENVSTR], val[MAX_ENVSTR]; 139 char quotechar, *c, *str; 140 141 filepos = ftell(f); 142 fileline = LineNumber; 143 skip_comments(f); 144 if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n")) 145 return (ERR); 146 147 Debug(DPARS, ("load_env, read <%s>\n", envstr)) 148 149 bzero(name, sizeof name); 150 bzero(val, sizeof val); 151 str = name; 152 state = NAMEI; 153 quotechar = '\0'; 154 c = envstr; 155 while (state != ERROR && *c) { 156 switch (state) { 157 case NAMEI: 158 case VALUEI: 159 if (*c == '\'' || *c == '"') 160 quotechar = *c++; 161 state++; 162 /* FALLTHROUGH */ 163 case NAME: 164 case VALUE: 165 if (quotechar) { 166 if (*c == quotechar) { 167 state++; 168 c++; 169 break; 170 } 171 if (state == NAME && *c == '=') { 172 state = ERROR; 173 break; 174 } 175 } else { 176 if (state == NAME) { 177 if (isspace((unsigned char)*c)) { 178 c++; 179 state++; 180 break; 181 } 182 if (*c == '=') { 183 state++; 184 break; 185 } 186 } 187 } 188 *str++ = *c++; 189 break; 190 case EQ1: 191 if (*c == '=') { 192 state++; 193 str = val; 194 quotechar = '\0'; 195 } else { 196 if (!isspace((unsigned char)*c)) 197 state = ERROR; 198 } 199 c++; 200 break; 201 case EQ2: 202 case FINI: 203 if (isspace((unsigned char)*c)) 204 c++; 205 else 206 state++; 207 break; 208 } 209 } 210 if (state != FINI && !(state == VALUE && !quotechar)) { 211 Debug(DPARS, ("load_env, not an env var, state = %d\n", state)) 212 fseek(f, filepos, SEEK_SET); 213 Set_LineNum(fileline); 214 return (FALSE); 215 } 216 if (state == VALUE) { 217 /* End of unquoted value: trim trailing whitespace */ 218 c = val + strlen(val); 219 while (c > val && isspace((unsigned char)c[-1])) 220 *(--c) = '\0'; 221 } 222 223 /* 2 fields from parser; looks like an env setting */ 224 225 /* 226 * This can't overflow because get_string() limited the size of the 227 * name and val fields. Still, it doesn't hurt to be careful... 228 */ 229 if (snprintf(envstr, MAX_ENVSTR, "%s=%s", name, val) >= MAX_ENVSTR) 230 return (FALSE); 231 Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr)) 232 return (TRUE); 233 } 234 235 char * 236 env_get(char *name, char **envp) { 237 int len = strlen(name); 238 char *p, *q; 239 240 while ((p = *envp++) != NULL) { 241 if (!(q = strchr(p, '='))) 242 continue; 243 if ((q - p) == len && !strncmp(p, name, len)) 244 return (q+1); 245 } 246 return (NULL); 247 } 248