]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/env.c
Merge branch 'master' of https://github.com/u2386/util-linux
[thirdparty/util-linux.git] / lib / env.c
CommitLineData
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 25extern char **environ;
0e9b73d3 26#endif
7eda085c
KZ
27
28static 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) */
46static char * const noslash[] = {
47 "LANG=",
48 "LANGUAGE=",
49 "LC_", /* anything with the LC_ prefix */
50 (char *) 0
51};
52
e113093c
KZ
53
54struct 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 */
62static 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*/
90struct ul_env_list *env_from_fd(int fd)
91{
11208370 92 char *buf = NULL, *p;
4e9ec856 93 size_t rc = 0;
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 */
116int 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
134void 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 */
147void __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);
ed292a08 162 last = remote_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);
ed292a08 177 last = remote_entry(envp, cur - envp, last);
7eda085c
KZ
178 cur--;
179 break;
180 }
181 }
182}
183
e113093c
KZ
184void sanitize_env(void)
185{
186 __sanitize_env(NULL);
187}
035507c8
KZ
188
189char *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
203return 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 212int 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