]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/env.c
lscpu: fix variable shadowing
[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
73 ls = (struct ul_env_list *) p;
74 p += sizeof(struct ul_env_list);
75 memcpy(p, str, sz);
76 ls->env = p;
77
78 ls->next = ls0;
79 return ls;
80 }
81
82 /*
83 * Use setenv() for all stuff in @ls.
84 *
85 * It would be possible to use putenv(), but we want to keep @ls free()-able.
86 */
87 int env_list_setenv(struct ul_env_list *ls)
88 {
89 int rc = 0;
90
91 while (ls && rc == 0) {
92 if (ls->env) {
93 char *val = strchr(ls->env, '=');
94 if (!val)
95 continue;
96 *val = '\0';
97 rc = setenv(ls->env, val + 1, 0);
98 *val = '=';
99 }
100 ls = ls->next;
101 }
102 return rc;
103 }
104
105 void env_list_free(struct ul_env_list *ls)
106 {
107 while (ls) {
108 struct ul_env_list *x = ls;
109 ls = ls->next;
110 free(x);
111 }
112 }
113
114 /*
115 * Removes unwanted variables from environ[]. If @ls is not NULL than stores
116 * unwnated variables to the list.
117 */
118 void __sanitize_env(struct ul_env_list **org)
119 {
120 char **envp = environ;
121 char * const *bad;
122 char **cur;
123 int last = 0;
124
125 for (cur = envp; *cur; cur++)
126 last++;
127
128 for (cur = envp; *cur; cur++) {
129 for (bad = forbid; *bad; bad++) {
130 if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
131 if (org)
132 *org = env_list_add(*org, *cur);
133 last = remote_entry(envp, cur - envp, last);
134 cur--;
135 break;
136 }
137 }
138 }
139
140 for (cur = envp; *cur; cur++) {
141 for (bad = noslash; *bad; bad++) {
142 if (strncmp(*cur, *bad, strlen(*bad)) != 0)
143 continue;
144 if (!strchr(*cur, '/'))
145 continue; /* OK */
146 if (org)
147 *org = env_list_add(*org, *cur);
148 last = remote_entry(envp, cur - envp, last);
149 cur--;
150 break;
151 }
152 }
153 }
154
155 void sanitize_env(void)
156 {
157 __sanitize_env(NULL);
158 }
159
160 char *safe_getenv(const char *arg)
161 {
162 uid_t ruid = getuid();
163
164 if (ruid != 0 || (ruid != 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