]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/env.c
Merge branch 'better-bsd-compat' of https://github.com/bsdimp/util-linux
[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
23 #ifndef HAVE_ENVIRON_DECL
24 extern char **environ;
25 #endif
26
27 static char * const forbid[] = {
28 "BASH_ENV=", /* GNU creeping featurism strikes again... */
29 "ENV=",
30 "HOME=",
31 "IFS=",
32 "KRB_CONF=",
33 "LD_", /* anything with the LD_ prefix */
34 "LIBPATH=",
35 "MAIL=",
36 "NLSPATH=",
37 "PATH=",
38 "SHELL=",
39 "SHLIB_PATH=",
40 (char *) 0
41 };
42
43 /* these are allowed, but with no slashes inside
44 (to work around security problems in GNU gettext) */
45 static char * const noslash[] = {
46 "LANG=",
47 "LANGUAGE=",
48 "LC_", /* anything with the LC_ prefix */
49 (char *) 0
50 };
51
52
53 struct ul_env_list {
54 char *env;
55 struct ul_env_list *next;
56 };
57
58 /*
59 * Saves @name env.variable to @ls, returns pointer to the new head of the list.
60 */
61 static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str)
62 {
63 struct ul_env_list *ls;
64 char *p;
65 size_t sz = 0;
66
67 if (!str || !*str)
68 return ls0;
69
70 sz = strlen(str) + 1;
71 p = malloc(sizeof(struct ul_env_list) + sz);
72 if (!p)
73 return ls0;
74
75 ls = (struct ul_env_list *) p;
76 p += sizeof(struct ul_env_list);
77 memcpy(p, str, sz);
78 ls->env = p;
79
80 ls->next = ls0;
81 return ls;
82 }
83
84 /*
85 * Use setenv() for all stuff in @ls.
86 *
87 * It would be possible to use putenv(), but we want to keep @ls free()-able.
88 */
89 int env_list_setenv(struct ul_env_list *ls)
90 {
91 int rc = 0;
92
93 while (ls && rc == 0) {
94 if (ls->env) {
95 char *val = strchr(ls->env, '=');
96 if (!val)
97 continue;
98 *val = '\0';
99 rc = setenv(ls->env, val + 1, 0);
100 *val = '=';
101 }
102 ls = ls->next;
103 }
104 return rc;
105 }
106
107 void env_list_free(struct ul_env_list *ls)
108 {
109 while (ls) {
110 struct ul_env_list *x = ls;
111 ls = ls->next;
112 free(x);
113 }
114 }
115
116 /*
117 * Removes unwanted variables from environ[]. If @org is not NULL than stores
118 * unwnated variables to the list.
119 */
120 void __sanitize_env(struct ul_env_list **org)
121 {
122 char **envp = environ;
123 char * const *bad;
124 char **cur;
125 int last = 0;
126
127 for (cur = envp; *cur; cur++)
128 last++;
129
130 for (cur = envp; *cur; cur++) {
131 for (bad = forbid; *bad; bad++) {
132 if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
133 if (org)
134 *org = env_list_add(*org, *cur);
135 last = remote_entry(envp, cur - envp, last);
136 cur--;
137 break;
138 }
139 }
140 }
141
142 for (cur = envp; *cur; cur++) {
143 for (bad = noslash; *bad; bad++) {
144 if (strncmp(*cur, *bad, strlen(*bad)) != 0)
145 continue;
146 if (!strchr(*cur, '/'))
147 continue; /* OK */
148 if (org)
149 *org = env_list_add(*org, *cur);
150 last = remote_entry(envp, cur - envp, last);
151 cur--;
152 break;
153 }
154 }
155 }
156
157 void sanitize_env(void)
158 {
159 __sanitize_env(NULL);
160 }
161
162 char *safe_getenv(const char *arg)
163 {
164 if ((getuid() != geteuid()) || (getgid() != getegid()))
165 return NULL;
166 #ifdef HAVE_PRCTL
167 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
168 return NULL;
169 #else
170 #if (defined(linux) && defined(SYS_prctl))
171 if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
172 return NULL;
173 #endif
174 #endif
175 #ifdef HAVE_SECURE_GETENV
176 return secure_getenv(arg);
177 #elif HAVE___SECURE_GETENV
178 return __secure_getenv(arg);
179 #else
180 return getenv(arg);
181 #endif
182 }
183
184 #ifdef TEST_PROGRAM
185 int main(void)
186 {
187 char *const *bad;
188 char copy[32];
189 char *p;
190 int retval = EXIT_SUCCESS;
191 struct ul_env_list *removed = NULL;
192
193 for (bad = forbid; *bad; bad++) {
194 strcpy(copy, *bad);
195 p = strchr(copy, '=');
196 if (p)
197 *p = '\0';
198 setenv(copy, copy, 1);
199 }
200
201 /* removed */
202 __sanitize_env(&removed);
203
204 /* check removal */
205 for (bad = forbid; *bad; bad++) {
206 strcpy(copy, *bad);
207 p = strchr(copy, '=');
208 if (p)
209 *p = '\0';
210 p = getenv(copy);
211 if (p) {
212 warnx("%s was not removed", copy);
213 retval = EXIT_FAILURE;
214 }
215 }
216
217 /* restore removed */
218 env_list_setenv(removed);
219
220 /* check restore */
221 for (bad = forbid; *bad; bad++) {
222 strcpy(copy, *bad);
223 p = strchr(copy, '=');
224 if (p)
225 *p = '\0';
226 p = getenv(copy);
227 if (!p) {
228 warnx("%s was not restored", copy);
229 retval = EXIT_FAILURE;
230 }
231 }
232
233 env_list_free(removed);
234
235 return retval;
236 }
237 #endif