]>
Commit | Line | Data |
---|---|---|
7eda085c | 1 | /* |
cb776288 | 2 | * environ[] array cleanup code and getenv() wrappers |
7eda085c | 3 | * |
3836cd2d KZ |
4 | * No copyright is claimed. This code is in the public domain; do with |
5 | * it what you wish. | |
035507c8 | 6 | */ |
7eda085c KZ |
7 | #include <stdio.h> |
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
035507c8 KZ |
10 | #ifdef HAVE_SYS_PRCTL_H |
11 | #include <sys/prctl.h> | |
12 | #else | |
13 | #define PR_GET_DUMPABLE 3 | |
14 | #endif | |
15 | #if (!defined(HAVE_PRCTL) && defined(linux)) | |
16 | #include <sys/syscall.h> | |
17 | #endif | |
18 | #include <unistd.h> | |
19 | #include <sys/types.h> | |
20 | ||
7eda085c | 21 | #include "env.h" |
4e9ec856 | 22 | #include "all-io.h" |
7eda085c | 23 | |
0e9b73d3 | 24 | #ifndef HAVE_ENVIRON_DECL |
7eda085c | 25 | extern char **environ; |
0e9b73d3 | 26 | #endif |
7eda085c KZ |
27 | |
28 | static char * const forbid[] = { | |
7eda085c KZ |
29 | "BASH_ENV=", /* GNU creeping featurism strikes again... */ |
30 | "ENV=", | |
31 | "HOME=", | |
32 | "IFS=", | |
33 | "KRB_CONF=", | |
34 | "LD_", /* anything with the LD_ prefix */ | |
35 | "LIBPATH=", | |
36 | "MAIL=", | |
37 | "NLSPATH=", | |
38 | "PATH=", | |
39 | "SHELL=", | |
40 | "SHLIB_PATH=", | |
41 | (char *) 0 | |
42 | }; | |
43 | ||
44 | /* these are allowed, but with no slashes inside | |
45 | (to work around security problems in GNU gettext) */ | |
46 | static char * const noslash[] = { | |
47 | "LANG=", | |
48 | "LANGUAGE=", | |
49 | "LC_", /* anything with the LC_ prefix */ | |
50 | (char *) 0 | |
51 | }; | |
52 | ||
e113093c KZ |
53 | |
54 | struct ul_env_list { | |
55 | char *env; | |
56 | struct ul_env_list *next; | |
57 | }; | |
58 | ||
59 | /* | |
cb776288 | 60 | * Saves @name env.variable to @ls, returns pointer to the new head of the list. |
e113093c KZ |
61 | */ |
62 | static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str) | |
63 | { | |
64 | struct ul_env_list *ls; | |
65 | char *p; | |
66 | size_t sz = 0; | |
67 | ||
68 | if (!str || !*str) | |
69 | return ls0; | |
70 | ||
71 | sz = strlen(str) + 1; | |
72 | p = malloc(sizeof(struct ul_env_list) + sz); | |
8b3d8aad KZ |
73 | if (!p) |
74 | return ls0; | |
e113093c KZ |
75 | |
76 | ls = (struct ul_env_list *) p; | |
77 | p += sizeof(struct ul_env_list); | |
78 | memcpy(p, str, sz); | |
79 | ls->env = p; | |
80 | ||
81 | ls->next = ls0; | |
82 | return ls; | |
83 | } | |
84 | ||
4e9ec856 | 85 | /* |
86 | * Use env_from_fd() to read environment from @fd. | |
87 | * | |
88 | * @fd must be /proc/<pid>/environ file. | |
89 | */ | |
90 | struct ul_env_list *env_from_fd(int fd) | |
91 | { | |
11208370 | 92 | char *buf = NULL, *p; |
07ef43df | 93 | ssize_t rc = 0; |
4e9ec856 | 94 | struct ul_env_list *ls = NULL; |
95 | ||
96 | if ((rc = read_all_alloc(fd, &buf)) < 1) | |
97 | return NULL; | |
98 | buf[rc] = '\0'; | |
11208370 | 99 | p = buf; |
4e9ec856 | 100 | |
101 | while (rc > 0) { | |
11208370 KZ |
102 | ls = env_list_add(ls, p); |
103 | p += strlen(p) + 1; | |
104 | rc -= strlen(p) + 1; | |
4e9ec856 | 105 | } |
11208370 KZ |
106 | |
107 | free(buf); | |
4e9ec856 | 108 | return ls; |
109 | } | |
110 | ||
e113093c KZ |
111 | /* |
112 | * Use setenv() for all stuff in @ls. | |
113 | * | |
114 | * It would be possible to use putenv(), but we want to keep @ls free()-able. | |
115 | */ | |
116 | int env_list_setenv(struct ul_env_list *ls) | |
117 | { | |
118 | int rc = 0; | |
119 | ||
120 | while (ls && rc == 0) { | |
121 | if (ls->env) { | |
122 | char *val = strchr(ls->env, '='); | |
123 | if (!val) | |
124 | continue; | |
125 | *val = '\0'; | |
126 | rc = setenv(ls->env, val + 1, 0); | |
127 | *val = '='; | |
128 | } | |
129 | ls = ls->next; | |
130 | } | |
131 | return rc; | |
132 | } | |
133 | ||
134 | void env_list_free(struct ul_env_list *ls) | |
135 | { | |
136 | while (ls) { | |
137 | struct ul_env_list *x = ls; | |
138 | ls = ls->next; | |
139 | free(x); | |
140 | } | |
141 | } | |
142 | ||
143 | /* | |
8b3d8aad | 144 | * Removes unwanted variables from environ[]. If @org is not NULL than stores |
e113093c KZ |
145 | * unwnated variables to the list. |
146 | */ | |
147 | void __sanitize_env(struct ul_env_list **org) | |
7eda085c KZ |
148 | { |
149 | char **envp = environ; | |
150 | char * const *bad; | |
151 | char **cur; | |
ed292a08 SK |
152 | int last = 0; |
153 | ||
154 | for (cur = envp; *cur; cur++) | |
155 | last++; | |
7eda085c KZ |
156 | |
157 | for (cur = envp; *cur; cur++) { | |
158 | for (bad = forbid; *bad; bad++) { | |
159 | if (strncmp(*cur, *bad, strlen(*bad)) == 0) { | |
e113093c KZ |
160 | if (org) |
161 | *org = env_list_add(*org, *cur); | |
5e2bc9d6 | 162 | last = remove_entry(envp, cur - envp, last); |
7eda085c KZ |
163 | cur--; |
164 | break; | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
169 | for (cur = envp; *cur; cur++) { | |
170 | for (bad = noslash; *bad; bad++) { | |
171 | if (strncmp(*cur, *bad, strlen(*bad)) != 0) | |
172 | continue; | |
173 | if (!strchr(*cur, '/')) | |
174 | continue; /* OK */ | |
e113093c KZ |
175 | if (org) |
176 | *org = env_list_add(*org, *cur); | |
5e2bc9d6 | 177 | last = remove_entry(envp, cur - envp, last); |
7eda085c KZ |
178 | cur--; |
179 | break; | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
e113093c KZ |
184 | void sanitize_env(void) |
185 | { | |
186 | __sanitize_env(NULL); | |
187 | } | |
035507c8 KZ |
188 | |
189 | char *safe_getenv(const char *arg) | |
190 | { | |
16a2e060 | 191 | if ((getuid() != geteuid()) || (getgid() != getegid())) |
035507c8 | 192 | return NULL; |
fbc333fe | 193 | #ifdef HAVE_PRCTL |
035507c8 KZ |
194 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) |
195 | return NULL; | |
196 | #else | |
197 | #if (defined(linux) && defined(SYS_prctl)) | |
198 | if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) | |
199 | return NULL; | |
200 | #endif | |
201 | #endif | |
075f4bfd CR |
202 | #ifdef HAVE_SECURE_GETENV |
203 | return secure_getenv(arg); | |
204 | #elif HAVE___SECURE_GETENV | |
035507c8 KZ |
205 | return __secure_getenv(arg); |
206 | #else | |
207 | return getenv(arg); | |
208 | #endif | |
209 | } | |
3d6fa8da SK |
210 | |
211 | #ifdef TEST_PROGRAM | |
9faba211 | 212 | int main(void) |
3d6fa8da SK |
213 | { |
214 | char *const *bad; | |
215 | char copy[32]; | |
216 | char *p; | |
217 | int retval = EXIT_SUCCESS; | |
e113093c | 218 | struct ul_env_list *removed = NULL; |
3d6fa8da SK |
219 | |
220 | for (bad = forbid; *bad; bad++) { | |
221 | strcpy(copy, *bad); | |
222 | p = strchr(copy, '='); | |
223 | if (p) | |
224 | *p = '\0'; | |
225 | setenv(copy, copy, 1); | |
226 | } | |
e113093c KZ |
227 | |
228 | /* removed */ | |
229 | __sanitize_env(&removed); | |
230 | ||
231 | /* check removal */ | |
3d6fa8da SK |
232 | for (bad = forbid; *bad; bad++) { |
233 | strcpy(copy, *bad); | |
234 | p = strchr(copy, '='); | |
235 | if (p) | |
236 | *p = '\0'; | |
237 | p = getenv(copy); | |
238 | if (p) { | |
239 | warnx("%s was not removed", copy); | |
240 | retval = EXIT_FAILURE; | |
241 | } | |
242 | } | |
e113093c KZ |
243 | |
244 | /* restore removed */ | |
245 | env_list_setenv(removed); | |
246 | ||
247 | /* check restore */ | |
248 | for (bad = forbid; *bad; bad++) { | |
249 | strcpy(copy, *bad); | |
250 | p = strchr(copy, '='); | |
251 | if (p) | |
252 | *p = '\0'; | |
253 | p = getenv(copy); | |
254 | if (!p) { | |
255 | warnx("%s was not restored", copy); | |
256 | retval = EXIT_FAILURE; | |
257 | } | |
258 | } | |
259 | ||
260 | env_list_free(removed); | |
261 | ||
3d6fa8da SK |
262 | return retval; |
263 | } | |
264 | #endif |