chiark / gitweb /
Add function to open temp files in selinux mode
[elogind.git] / src / shared / env-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <limits.h>
23 #include <sys/param.h>
24 #include <unistd.h>
25
26 #include "strv.h"
27 #include "utf8.h"
28 #include "util.h"
29 #include "env-util.h"
30 #include "def.h"
31
32 #define VALID_CHARS_ENV_NAME                    \
33         DIGITS LETTERS                          \
34         "_"
35
36 #ifndef ARG_MAX
37 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
38 #endif
39
40 static bool env_name_is_valid_n(const char *e, size_t n) {
41         const char *p;
42
43         if (!e)
44                 return false;
45
46         if (n <= 0)
47                 return false;
48
49         if (e[0] >= '0' && e[0] <= '9')
50                 return false;
51
52         /* POSIX says the overall size of the environment block cannot
53          * be > ARG_MAX, an individual assignment hence cannot be
54          * either. Discounting the equal sign and trailing NUL this
55          * hence leaves ARG_MAX-2 as longest possible variable
56          * name. */
57         if (n > ARG_MAX - 2)
58                 return false;
59
60         for (p = e; p < e + n; p++)
61                 if (!strchr(VALID_CHARS_ENV_NAME, *p))
62                         return false;
63
64         return true;
65 }
66
67 bool env_name_is_valid(const char *e) {
68         if (!e)
69                 return false;
70
71         return env_name_is_valid_n(e, strlen(e));
72 }
73
74 bool env_value_is_valid(const char *e) {
75         if (!e)
76                 return false;
77
78         if (!utf8_is_valid(e))
79                 return false;
80
81         /* bash allows tabs in environment variables, and so should
82          * we */
83         if (string_has_cc(e, "\t"))
84                 return false;
85
86         /* POSIX says the overall size of the environment block cannot
87          * be > ARG_MAX, an individual assignment hence cannot be
88          * either. Discounting the shortest possible variable name of
89          * length 1, the equal sign and trailing NUL this hence leaves
90          * ARG_MAX-3 as longest possible variable value. */
91         if (strlen(e) > ARG_MAX - 3)
92                 return false;
93
94         return true;
95 }
96
97 bool env_assignment_is_valid(const char *e) {
98         const char *eq;
99
100         eq = strchr(e, '=');
101         if (!eq)
102                 return false;
103
104         if (!env_name_is_valid_n(e, eq - e))
105                 return false;
106
107         if (!env_value_is_valid(eq + 1))
108                 return false;
109
110         /* POSIX says the overall size of the environment block cannot
111          * be > ARG_MAX, hence the individual variable assignments
112          * cannot be either, but let's leave room for one trailing NUL
113          * byte. */
114         if (strlen(e) > ARG_MAX - 1)
115                 return false;
116
117         return true;
118 }
119
120 bool strv_env_is_valid(char **e) {
121         char **p, **q;
122
123         STRV_FOREACH(p, e) {
124                 size_t k;
125
126                 if (!env_assignment_is_valid(*p))
127                         return false;
128
129                 /* Check if there are duplicate assginments */
130                 k = strcspn(*p, "=");
131                 STRV_FOREACH(q, p + 1)
132                         if (strneq(*p, *q, k) && (*q)[k] == '=')
133                                 return false;
134         }
135
136         return true;
137 }
138
139 bool strv_env_name_or_assignment_is_valid(char **l) {
140         char **p, **q;
141
142         STRV_FOREACH(p, l) {
143                 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
144                         return false;
145
146                 STRV_FOREACH(q, p + 1)
147                         if (streq(*p, *q))
148                                 return false;
149         }
150
151         return true;
152 }
153
154 static int env_append(char **r, char ***k, char **a) {
155         assert(r);
156         assert(k);
157
158         if (!a)
159                 return 0;
160
161         /* Add the entries of a to *k unless they already exist in *r
162          * in which case they are overridden instead. This assumes
163          * there is enough space in the r array. */
164
165         for (; *a; a++) {
166                 char **j;
167                 size_t n;
168
169                 n = strcspn(*a, "=");
170
171                 if ((*a)[n] == '=')
172                         n++;
173
174                 for (j = r; j < *k; j++)
175                         if (strneq(*j, *a, n))
176                                 break;
177
178                 if (j >= *k)
179                         (*k)++;
180                 else
181                         free(*j);
182
183                 *j = strdup(*a);
184                 if (!*j)
185                         return -ENOMEM;
186         }
187
188         return 0;
189 }
190
191 char **strv_env_merge(unsigned n_lists, ...) {
192         size_t n = 0;
193         char **l, **k, **r;
194         va_list ap;
195         unsigned i;
196
197         /* Merges an arbitrary number of environment sets */
198
199         va_start(ap, n_lists);
200         for (i = 0; i < n_lists; i++) {
201                 l = va_arg(ap, char**);
202                 n += strv_length(l);
203         }
204         va_end(ap);
205
206         r = new(char*, n+1);
207         if (!r)
208                 return NULL;
209
210         k = r;
211
212         va_start(ap, n_lists);
213         for (i = 0; i < n_lists; i++) {
214                 l = va_arg(ap, char**);
215                 if (env_append(r, &k, l) < 0)
216                         goto fail;
217         }
218         va_end(ap);
219
220         *k = NULL;
221
222         return r;
223
224 fail:
225         va_end(ap);
226         strv_free(r);
227
228         return NULL;
229 }
230
231 _pure_ static bool env_match(const char *t, const char *pattern) {
232         assert(t);
233         assert(pattern);
234
235         /* pattern a matches string a
236          *         a matches a=
237          *         a matches a=b
238          *         a= matches a=
239          *         a=b matches a=b
240          *         a= does not match a
241          *         a=b does not match a=
242          *         a=b does not match a
243          *         a=b does not match a=c */
244
245         if (streq(t, pattern))
246                 return true;
247
248         if (!strchr(pattern, '=')) {
249                 size_t l = strlen(pattern);
250
251                 return strneq(t, pattern, l) && t[l] == '=';
252         }
253
254         return false;
255 }
256
257 char **strv_env_delete(char **x, unsigned n_lists, ...) {
258         size_t n, i = 0;
259         char **k, **r;
260         va_list ap;
261
262         /* Deletes every entry from x that is mentioned in the other
263          * string lists */
264
265         n = strv_length(x);
266
267         r = new(char*, n+1);
268         if (!r)
269                 return NULL;
270
271         STRV_FOREACH(k, x) {
272                 unsigned v;
273
274                 va_start(ap, n_lists);
275                 for (v = 0; v < n_lists; v++) {
276                         char **l, **j;
277
278                         l = va_arg(ap, char**);
279                         STRV_FOREACH(j, l)
280                                 if (env_match(*k, *j))
281                                         goto skip;
282                 }
283                 va_end(ap);
284
285                 r[i] = strdup(*k);
286                 if (!r[i]) {
287                         strv_free(r);
288                         return NULL;
289                 }
290
291                 i++;
292                 continue;
293
294         skip:
295                 va_end(ap);
296         }
297
298         r[i] = NULL;
299
300         assert(i <= n);
301
302         return r;
303 }
304
305 char **strv_env_unset(char **l, const char *p) {
306
307         char **f, **t;
308
309         if (!l)
310                 return NULL;
311
312         assert(p);
313
314         /* Drops every occurrence of the env var setting p in the
315          * string list. Edits in-place. */
316
317         for (f = t = l; *f; f++) {
318
319                 if (env_match(*f, p)) {
320                         free(*f);
321                         continue;
322                 }
323
324                 *(t++) = *f;
325         }
326
327         *t = NULL;
328         return l;
329 }
330
331 char **strv_env_unset_many(char **l, ...) {
332
333         char **f, **t;
334
335         if (!l)
336                 return NULL;
337
338         /* Like strv_env_unset() but applies many at once. Edits in-place. */
339
340         for (f = t = l; *f; f++) {
341                 bool found = false;
342                 const char *p;
343                 va_list ap;
344
345                 va_start(ap, l);
346
347                 while ((p = va_arg(ap, const char*))) {
348                         if (env_match(*f, p)) {
349                                 found = true;
350                                 break;
351                         }
352                 }
353
354                 va_end(ap);
355
356                 if (found) {
357                         free(*f);
358                         continue;
359                 }
360
361                 *(t++) = *f;
362         }
363
364         *t = NULL;
365         return l;
366 }
367
368 char **strv_env_set(char **x, const char *p) {
369
370         char **k, **r;
371         char* m[2] = { (char*) p, NULL };
372
373         /* Overrides the env var setting of p, returns a new copy */
374
375         r = new(char*, strv_length(x)+2);
376         if (!r)
377                 return NULL;
378
379         k = r;
380         if (env_append(r, &k, x) < 0)
381                 goto fail;
382
383         if (env_append(r, &k, m) < 0)
384                 goto fail;
385
386         *k = NULL;
387
388         return r;
389
390 fail:
391         strv_free(r);
392         return NULL;
393 }
394
395 char *strv_env_get_n(char **l, const char *name, size_t k) {
396         char **i;
397
398         assert(name);
399
400         if (k <= 0)
401                 return NULL;
402
403         STRV_FOREACH(i, l)
404                 if (strneq(*i, name, k) &&
405                     (*i)[k] == '=')
406                         return *i + k + 1;
407
408         return NULL;
409 }
410
411 char *strv_env_get(char **l, const char *name) {
412         assert(name);
413
414         return strv_env_get_n(l, name, strlen(name));
415 }
416
417 char **strv_env_clean_log(char **e, const char *message) {
418         char **p, **q;
419         int k = 0;
420
421         STRV_FOREACH(p, e) {
422                 size_t n;
423                 bool duplicate = false;
424
425                 if (!env_assignment_is_valid(*p)) {
426                         if (message)
427                                 log_error("Ignoring invalid environment '%s': %s", *p, message);
428                         free(*p);
429                         continue;
430                 }
431
432                 n = strcspn(*p, "=");
433                 STRV_FOREACH(q, p + 1)
434                         if (strneq(*p, *q, n) && (*q)[n] == '=') {
435                                 duplicate = true;
436                                 break;
437                         }
438
439                 if (duplicate) {
440                         free(*p);
441                         continue;
442                 }
443
444                 e[k++] = *p;
445         }
446
447         if (e)
448                 e[k] = NULL;
449
450         return e;
451 }
452
453 char **strv_env_clean(char **e) {
454         return strv_env_clean_log(e, NULL);
455 }