]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/env.c
Revert "lib/pager: Apply pager-specific fixes only when needed"
[thirdparty/util-linux.git] / lib / env.c
1 /*
2 * environ[] array cleanup code and getenv() wrappers
3 *
4 * No copyright is claimed. This code is in the public domain; do with
5 * it what you wish.
6 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
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
21 #include "env.h"
22 #include "all-io.h"
23
24 #ifndef HAVE_ENVIRON_DECL
25 extern char **environ;
26 #endif
27
28 static char * const forbid[] = {
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
53
54 struct ul_env_list {
55 char *env;
56 struct ul_env_list *next;
57 };
58
59 /*
60 * Saves @name env.variable to @ls, returns pointer to the new head of the list.
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);
73 if (!p)
74 return ls0;
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
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 {
92 char *buf = NULL, *p;
93 ssize_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';
99 p = buf;
100
101 while (rc > 0) {
102 ls = env_list_add(ls, p);
103 p += strlen(p) + 1;
104 rc -= strlen(p) + 1;
105 }
106
107 free(buf);
108 return ls;
109 }
110
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 /*
144 * Removes unwanted variables from environ[]. If @org is not NULL than stores
145 * unwnated variables to the list.
146 */
147 void __sanitize_env(struct ul_env_list **org)
148 {
149 char **envp = environ;
150 char * const *bad;
151 char **cur;
152 int last = 0;
153
154 for (cur = envp; *cur; cur++)
155 last++;
156
157 for (cur = envp; *cur; cur++) {
158 for (bad = forbid; *bad; bad++) {
159 if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
160 if (org)
161 *org = env_list_add(*org, *cur);
162 last = remove_entry(envp, cur - envp, last);
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 */
175 if (org)
176 *org = env_list_add(*org, *cur);
177 last = remove_entry(envp, cur - envp, last);
178 cur--;
179 break;
180 }
181 }
182 }
183
184 void sanitize_env(void)
185 {
186 __sanitize_env(NULL);
187 }
188
189 char *safe_getenv(const char *arg)
190 {
191 if ((getuid() != geteuid()) || (getgid() != getegid()))
192 return NULL;
193 #ifdef HAVE_PRCTL
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
202 #ifdef HAVE_SECURE_GETENV
203 return secure_getenv(arg);
204 #elif HAVE___SECURE_GETENV
205 return __secure_getenv(arg);
206 #else
207 return getenv(arg);
208 #endif
209 }
210
211 #ifdef TEST_PROGRAM
212 int main(void)
213 {
214 char *const *bad;
215 char copy[32];
216 char *p;
217 int retval = EXIT_SUCCESS;
218 struct ul_env_list *removed = NULL;
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 }
227
228 /* removed */
229 __sanitize_env(&removed);
230
231 /* check removal */
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 }
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
262 return retval;
263 }
264 #endif