]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/env-util.c
96b9613d24ad1f715d5089c2e8695628582216da
[thirdparty/systemd.git] / src / basic / env-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #include "alloc-util.h"
10 #include "env-util.h"
11 #include "errno-util.h"
12 #include "escape.h"
13 #include "extract-word.h"
14 #include "macro.h"
15 #include "parse-util.h"
16 #include "path-util.h"
17 #include "process-util.h"
18 #include "stdio-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "utf8.h"
22
23 /* We follow bash for the character set. Different shells have different rules. */
24 #define VALID_BASH_ENV_NAME_CHARS \
25 DIGITS LETTERS \
26 "_"
27
28 static bool env_name_is_valid_n(const char *e, size_t n) {
29 if (!e)
30 return false;
31
32 if (n <= 0)
33 return false;
34
35 if (e[0] >= '0' && e[0] <= '9')
36 return false;
37
38 /* POSIX says the overall size of the environment block cannot
39 * be > ARG_MAX, an individual assignment hence cannot be
40 * either. Discounting the equal sign and trailing NUL this
41 * hence leaves ARG_MAX-2 as longest possible variable
42 * name. */
43 if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
44 return false;
45
46 for (const char *p = e; p < e + n; p++)
47 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
48 return false;
49
50 return true;
51 }
52
53 bool env_name_is_valid(const char *e) {
54 return env_name_is_valid_n(e, strlen_ptr(e));
55 }
56
57 bool env_value_is_valid(const char *e) {
58 if (!e)
59 return false;
60
61 if (!utf8_is_valid(e))
62 return false;
63
64 /* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
65 * When printing those variables with show-environment, we'll escape them. Make sure to print
66 * environment variables carefully! */
67
68 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
69 * hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
70 * sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
71 if (strlen(e) > sc_arg_max() - 3)
72 return false;
73
74 return true;
75 }
76
77 bool env_assignment_is_valid(const char *e) {
78 const char *eq;
79
80 eq = strchr(e, '=');
81 if (!eq)
82 return false;
83
84 if (!env_name_is_valid_n(e, eq - e))
85 return false;
86
87 if (!env_value_is_valid(eq + 1))
88 return false;
89
90 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
91 * variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
92 if (strlen(e) > sc_arg_max() - 1)
93 return false;
94
95 return true;
96 }
97
98 bool strv_env_is_valid(char **e) {
99 char **p, **q;
100
101 STRV_FOREACH(p, e) {
102 size_t k;
103
104 if (!env_assignment_is_valid(*p))
105 return false;
106
107 /* Check if there are duplicate assignments */
108 k = strcspn(*p, "=");
109 STRV_FOREACH(q, p + 1)
110 if (strneq(*p, *q, k) && (*q)[k] == '=')
111 return false;
112 }
113
114 return true;
115 }
116
117 bool strv_env_name_is_valid(char **l) {
118 char **p;
119
120 STRV_FOREACH(p, l) {
121 if (!env_name_is_valid(*p))
122 return false;
123
124 if (strv_contains(p + 1, *p))
125 return false;
126 }
127
128 return true;
129 }
130
131 bool strv_env_name_or_assignment_is_valid(char **l) {
132 char **p;
133
134 STRV_FOREACH(p, l) {
135 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
136 return false;
137
138 if (strv_contains(p + 1, *p))
139 return false;
140 }
141
142 return true;
143 }
144
145 static int env_append(char **r, char ***k, char **a) {
146 assert(r);
147 assert(k);
148 assert(*k >= r);
149
150 if (!a)
151 return 0;
152
153 /* Expects the following arguments: 'r' shall point to the beginning of an strv we are going to append to, 'k'
154 * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
155 *
156 * This call adds every entry of 'a' to 'r', either overriding an existing matching entry, or appending to it.
157 *
158 * This call assumes 'r' has enough pre-allocated space to grow by all of 'a''s items. */
159
160 for (; *a; a++) {
161 char **j, *c;
162 size_t n;
163
164 n = strcspn(*a, "=");
165 if ((*a)[n] == '=')
166 n++;
167
168 for (j = r; j < *k; j++)
169 if (strneq(*j, *a, n))
170 break;
171
172 c = strdup(*a);
173 if (!c)
174 return -ENOMEM;
175
176 if (j >= *k) { /* Append to the end? */
177 (*k)[0] = c;
178 (*k)[1] = NULL;
179 (*k)++;
180 } else
181 free_and_replace(*j, c); /* Override existing item */
182 }
183
184 return 0;
185 }
186
187 char** _strv_env_merge(char **first, ...) {
188 _cleanup_strv_free_ char **merged = NULL;
189 char **k;
190 va_list ap;
191
192 /* Merges an arbitrary number of environment sets */
193
194 size_t n = strv_length(first);
195
196 va_start(ap, first);
197 for (;;) {
198 char **l;
199
200 l = va_arg(ap, char**);
201 if (l == POINTER_MAX)
202 break;
203
204 n += strv_length(l);
205 }
206 va_end(ap);
207
208 k = merged = new(char*, n + 1);
209 if (!merged)
210 return NULL;
211 merged[0] = NULL;
212
213 if (env_append(merged, &k, first) < 0)
214 return NULL;
215
216 va_start(ap, first);
217 for (;;) {
218 char **l;
219
220 l = va_arg(ap, char**);
221 if (l == POINTER_MAX)
222 break;
223
224 if (env_append(merged, &k, l) < 0) {
225 va_end(ap);
226 return NULL;
227 }
228 }
229 va_end(ap);
230
231 return TAKE_PTR(merged);
232 }
233
234 static bool env_match(const char *t, const char *pattern) {
235 assert(t);
236 assert(pattern);
237
238 /* pattern a matches string a
239 * a matches a=
240 * a matches a=b
241 * a= matches a=
242 * a=b matches a=b
243 * a= does not match a
244 * a=b does not match a=
245 * a=b does not match a
246 * a=b does not match a=c */
247
248 if (streq(t, pattern))
249 return true;
250
251 if (!strchr(pattern, '=')) {
252 size_t l = strlen(pattern);
253
254 return strneq(t, pattern, l) && t[l] == '=';
255 }
256
257 return false;
258 }
259
260 static bool env_entry_has_name(const char *entry, const char *name) {
261 const char *t;
262
263 assert(entry);
264 assert(name);
265
266 t = startswith(entry, name);
267 if (!t)
268 return false;
269
270 return *t == '=';
271 }
272
273 char **strv_env_delete(char **x, size_t n_lists, ...) {
274 size_t n, i = 0;
275 char **k, **r;
276 va_list ap;
277
278 /* Deletes every entry from x that is mentioned in the other
279 * string lists */
280
281 n = strv_length(x);
282
283 r = new(char*, n+1);
284 if (!r)
285 return NULL;
286
287 STRV_FOREACH(k, x) {
288 va_start(ap, n_lists);
289 for (size_t v = 0; v < n_lists; v++) {
290 char **l, **j;
291
292 l = va_arg(ap, char**);
293 STRV_FOREACH(j, l)
294 if (env_match(*k, *j))
295 goto skip;
296 }
297 va_end(ap);
298
299 r[i] = strdup(*k);
300 if (!r[i]) {
301 strv_free(r);
302 return NULL;
303 }
304
305 i++;
306 continue;
307
308 skip:
309 va_end(ap);
310 }
311
312 r[i] = NULL;
313
314 assert(i <= n);
315
316 return r;
317 }
318
319 char **strv_env_unset(char **l, const char *p) {
320 char **f, **t;
321
322 if (!l)
323 return NULL;
324
325 assert(p);
326
327 /* Drops every occurrence of the env var setting p in the
328 * string list. Edits in-place. */
329
330 for (f = t = l; *f; f++) {
331
332 if (env_match(*f, p)) {
333 free(*f);
334 continue;
335 }
336
337 *(t++) = *f;
338 }
339
340 *t = NULL;
341 return l;
342 }
343
344 char **strv_env_unset_many(char **l, ...) {
345 char **f, **t;
346
347 if (!l)
348 return NULL;
349
350 /* Like strv_env_unset() but applies many at once. Edits in-place. */
351
352 for (f = t = l; *f; f++) {
353 bool found = false;
354 const char *p;
355 va_list ap;
356
357 va_start(ap, l);
358
359 while ((p = va_arg(ap, const char*))) {
360 if (env_match(*f, p)) {
361 found = true;
362 break;
363 }
364 }
365
366 va_end(ap);
367
368 if (found) {
369 free(*f);
370 continue;
371 }
372
373 *(t++) = *f;
374 }
375
376 *t = NULL;
377 return l;
378 }
379
380 int strv_env_replace_consume(char ***l, char *p) {
381 const char *t, *name;
382 char **f;
383 int r;
384
385 assert(p);
386
387 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
388 * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE.
389 *
390 * p must be a valid key=value assignment. */
391
392 t = strchr(p, '=');
393 if (!t) {
394 free(p);
395 return -EINVAL;
396 }
397
398 name = strndupa_safe(p, t - p);
399
400 STRV_FOREACH(f, *l)
401 if (env_entry_has_name(*f, name)) {
402 free_and_replace(*f, p);
403 strv_env_unset(f + 1, *f);
404 return 0;
405 }
406
407 /* We didn't find a match, we need to append p or create a new strv */
408 r = strv_consume(l, p);
409 if (r < 0)
410 return r;
411
412 return 1;
413 }
414
415 int strv_env_replace_strdup(char ***l, const char *assignment) {
416 /* Like strv_env_replace_consume(), but copies the argument. */
417
418 char *p = strdup(assignment);
419 if (!p)
420 return -ENOMEM;
421
422 return strv_env_replace_consume(l, p);
423 }
424
425 int strv_env_replace_strdup_passthrough(char ***l, const char *assignment) {
426 /* Like strv_env_replace_strdup(), but pulls the variable from the environment of
427 * the calling program, if a variable name without value is specified.
428 */
429 char *p;
430
431 if (strchr(assignment, '=')) {
432 if (!env_assignment_is_valid(assignment))
433 return -EINVAL;
434
435 p = strdup(assignment);
436 } else {
437 if (!env_name_is_valid(assignment))
438 return -EINVAL;
439
440 /* If we can't find the variable in our environment, we will use
441 * the empty string. This way "passthrough" is equivalent to passing
442 * --setenv=FOO=$FOO in the shell. */
443 p = strjoin(assignment, "=", secure_getenv(assignment));
444 }
445 if (!p)
446 return -ENOMEM;
447
448 return strv_env_replace_consume(l, p);
449 }
450
451 int strv_env_assign(char ***l, const char *key, const char *value) {
452 if (!env_name_is_valid(key))
453 return -EINVAL;
454
455 /* NULL removes assignment, "" creates an empty assignment. */
456
457 if (!value) {
458 strv_env_unset(*l, key);
459 return 0;
460 }
461
462 char *p = strjoin(key, "=", value);
463 if (!p)
464 return -ENOMEM;
465
466 return strv_env_replace_consume(l, p);
467 }
468
469 char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
470 char **i;
471
472 assert(name);
473
474 if (k <= 0)
475 return NULL;
476
477 STRV_FOREACH_BACKWARDS(i, l)
478 if (strneq(*i, name, k) &&
479 (*i)[k] == '=')
480 return *i + k + 1;
481
482 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
483 const char *t;
484
485 t = strndupa_safe(name, k);
486 return getenv(t);
487 };
488
489 return NULL;
490 }
491
492 char *strv_env_get(char **l, const char *name) {
493 assert(name);
494
495 return strv_env_get_n(l, name, strlen(name), 0);
496 }
497
498 char *strv_env_pairs_get(char **l, const char *name) {
499 char **key, **value, *result = NULL;
500
501 assert(name);
502
503 STRV_FOREACH_PAIR(key, value, l)
504 if (streq(*key, name))
505 result = *value;
506
507 return result;
508 }
509
510 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
511 char **p, **q;
512 int k = 0;
513
514 STRV_FOREACH(p, e) {
515 size_t n;
516 bool duplicate = false;
517
518 if (!env_assignment_is_valid(*p)) {
519 if (invalid_callback)
520 invalid_callback(*p, userdata);
521 free(*p);
522 continue;
523 }
524
525 n = strcspn(*p, "=");
526 STRV_FOREACH(q, p + 1)
527 if (strneq(*p, *q, n) && (*q)[n] == '=') {
528 duplicate = true;
529 break;
530 }
531
532 if (duplicate) {
533 free(*p);
534 continue;
535 }
536
537 e[k++] = *p;
538 }
539
540 if (e)
541 e[k] = NULL;
542
543 return e;
544 }
545
546 char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
547 enum {
548 WORD,
549 CURLY,
550 VARIABLE,
551 VARIABLE_RAW,
552 TEST,
553 DEFAULT_VALUE,
554 ALTERNATE_VALUE,
555 } state = WORD;
556
557 const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
558 char *k;
559 _cleanup_free_ char *r = NULL;
560 size_t i, len = 0; /* len is initialized to appease gcc */
561 int nest = 0;
562
563 assert(format);
564
565 for (e = format, i = 0; *e && i < n; e ++, i ++)
566 switch (state) {
567
568 case WORD:
569 if (*e == '$')
570 state = CURLY;
571 break;
572
573 case CURLY:
574 if (*e == '{') {
575 k = strnappend(r, word, e-word-1);
576 if (!k)
577 return NULL;
578
579 free_and_replace(r, k);
580
581 word = e-1;
582 state = VARIABLE;
583 nest++;
584 } else if (*e == '$') {
585 k = strnappend(r, word, e-word);
586 if (!k)
587 return NULL;
588
589 free_and_replace(r, k);
590
591 word = e+1;
592 state = WORD;
593
594 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
595 k = strnappend(r, word, e-word-1);
596 if (!k)
597 return NULL;
598
599 free_and_replace(r, k);
600
601 word = e-1;
602 state = VARIABLE_RAW;
603
604 } else
605 state = WORD;
606 break;
607
608 case VARIABLE:
609 if (*e == '}') {
610 const char *t;
611
612 t = strv_env_get_n(env, word+2, e-word-2, flags);
613
614 if (!strextend(&r, t))
615 return NULL;
616
617 word = e+1;
618 state = WORD;
619 nest--;
620 } else if (*e == ':') {
621 if (flags & REPLACE_ENV_ALLOW_EXTENDED) {
622 len = e - word - 2;
623 state = TEST;
624 } else
625 /* Treat this as unsupported syntax, i.e. do no replacement */
626 state = WORD;
627 }
628 break;
629
630 case TEST:
631 if (*e == '-')
632 state = DEFAULT_VALUE;
633 else if (*e == '+')
634 state = ALTERNATE_VALUE;
635 else {
636 state = WORD;
637 break;
638 }
639
640 test_value = e+1;
641 break;
642
643 case DEFAULT_VALUE: /* fall through */
644 case ALTERNATE_VALUE:
645 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
646
647 if (*e == '{') {
648 nest++;
649 break;
650 }
651
652 if (*e != '}')
653 break;
654
655 nest--;
656 if (nest == 0) {
657 const char *t;
658 _cleanup_free_ char *v = NULL;
659
660 t = strv_env_get_n(env, word+2, len, flags);
661
662 if (t && state == ALTERNATE_VALUE)
663 t = v = replace_env_n(test_value, e-test_value, env, flags);
664 else if (!t && state == DEFAULT_VALUE)
665 t = v = replace_env_n(test_value, e-test_value, env, flags);
666
667 if (!strextend(&r, t))
668 return NULL;
669
670 word = e+1;
671 state = WORD;
672 }
673 break;
674
675 case VARIABLE_RAW:
676 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
677
678 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
679 const char *t;
680
681 t = strv_env_get_n(env, word+1, e-word-1, flags);
682
683 if (!strextend(&r, t))
684 return NULL;
685
686 word = e--;
687 i--;
688 state = WORD;
689 }
690 break;
691 }
692
693 if (state == VARIABLE_RAW) {
694 const char *t;
695
696 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
697
698 t = strv_env_get_n(env, word+1, e-word-1, flags);
699 return strjoin(r, t);
700 } else
701 return strnappend(r, word, e-word);
702 }
703
704 char **replace_env_argv(char **argv, char **env) {
705 char **ret, **i;
706 size_t k = 0, l = 0;
707
708 l = strv_length(argv);
709
710 ret = new(char*, l+1);
711 if (!ret)
712 return NULL;
713
714 STRV_FOREACH(i, argv) {
715
716 /* If $FOO appears as single word, replace it by the split up variable */
717 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
718 char *e;
719 char **w, **m = NULL;
720 size_t q;
721
722 e = strv_env_get(env, *i+1);
723 if (e) {
724 int r;
725
726 r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
727 if (r < 0) {
728 ret[k] = NULL;
729 strv_free(ret);
730 return NULL;
731 }
732 } else
733 m = NULL;
734
735 q = strv_length(m);
736 l = l + q - 1;
737
738 w = reallocarray(ret, l + 1, sizeof(char *));
739 if (!w) {
740 ret[k] = NULL;
741 strv_free(ret);
742 strv_free(m);
743 return NULL;
744 }
745
746 ret = w;
747 if (m) {
748 memcpy(ret + k, m, q * sizeof(char*));
749 free(m);
750 }
751
752 k += q;
753 continue;
754 }
755
756 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
757 ret[k] = replace_env(*i, env, 0);
758 if (!ret[k]) {
759 strv_free(ret);
760 return NULL;
761 }
762 k++;
763 }
764
765 ret[k] = NULL;
766 return ret;
767 }
768
769 int getenv_bool(const char *p) {
770 const char *e;
771
772 e = getenv(p);
773 if (!e)
774 return -ENXIO;
775
776 return parse_boolean(e);
777 }
778
779 int getenv_bool_secure(const char *p) {
780 const char *e;
781
782 e = secure_getenv(p);
783 if (!e)
784 return -ENXIO;
785
786 return parse_boolean(e);
787 }
788
789 int set_unset_env(const char *name, const char *value, bool overwrite) {
790 assert(name);
791
792 if (value)
793 return RET_NERRNO(setenv(name, value, overwrite));
794
795 return RET_NERRNO(unsetenv(name));
796 }
797
798 int putenv_dup(const char *assignment, bool override) {
799 const char *e, *n;
800
801 e = strchr(assignment, '=');
802 if (!e)
803 return -EINVAL;
804
805 n = strndupa_safe(assignment, e - assignment);
806
807 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
808 return RET_NERRNO(setenv(n, e + 1, override));
809 }
810
811 int setenv_systemd_exec_pid(bool update_only) {
812 char str[DECIMAL_STR_MAX(pid_t)];
813 const char *e;
814
815 /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
816
817 e = secure_getenv("SYSTEMD_EXEC_PID");
818 if (!e && update_only)
819 return 0;
820
821 if (streq_ptr(e, "*"))
822 return 0;
823
824 xsprintf(str, PID_FMT, getpid_cached());
825
826 if (setenv("SYSTEMD_EXEC_PID", str, 1) < 0)
827 return -errno;
828
829 return 1;
830 }
831
832 int getenv_path_list(const char *name, char ***ret_paths) {
833 _cleanup_strv_free_ char **l = NULL;
834 const char *e;
835 char **p;
836 int r;
837
838 assert(name);
839 assert(ret_paths);
840
841 e = secure_getenv(name);
842 if (!e)
843 return -ENXIO;
844
845 r = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
846 if (r < 0)
847 return log_debug_errno(r, "Failed to parse $%s: %m", name);
848
849 STRV_FOREACH(p, l) {
850 if (!path_is_absolute(*p))
851 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
852 "Path '%s' is not absolute, refusing.", *p);
853
854 if (!path_is_normalized(*p))
855 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
856 "Path '%s' is not normalized, refusing.", *p);
857
858 if (path_equal(*p, "/"))
859 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
860 "Path '%s' is the root fs, refusing.", *p);
861 }
862
863 if (strv_isempty(l))
864 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
865 "No paths specified, refusing.");
866
867 *ret_paths = TAKE_PTR(l);
868 return 1;
869 }
870
871 int getenv_steal_erase(const char *name, char **ret) {
872 _cleanup_(erase_and_freep) char *a = NULL;
873 char *e;
874
875 assert(name);
876
877 /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
878 * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
879 * testing, and given that people are likely going to misuse this, be thorough) */
880
881 e = getenv(name);
882 if (!e) {
883 if (ret)
884 *ret = NULL;
885 return 0;
886 }
887
888 if (ret) {
889 a = strdup(e);
890 if (!a)
891 return -ENOMEM;
892 }
893
894 string_erase(e);
895
896 if (unsetenv(name) < 0)
897 return -errno;
898
899 if (ret)
900 *ret = TAKE_PTR(a);
901
902 return 1;
903 }