1 /*
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2000-2005, 2007-2019
5 * Todd C. Miller <Todd.Miller@sudo.ws>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * Sponsored in part by the Defense Advanced Research Projects
20 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22 */
23
24 /*
25 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
26 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
27 */
28
29 #include <config.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #include "sudoers.h"
37
38 /*
39 * Similar to setenv(3) but operates on a private copy of the environment.
40 * Does not include warnings or debugging to avoid recursive calls.
41 */
42 static int
sudo_setenv_nodebug(const char * var,const char * val,int overwrite)43 sudo_setenv_nodebug(const char *var, const char *val, int overwrite)
44 {
45 char *ep, *estring = NULL;
46 const char *cp;
47 size_t esize;
48 int ret = -1;
49
50 if (var == NULL || *var == '\0') {
51 errno = EINVAL;
52 goto done;
53 }
54
55 /*
56 * POSIX says a var name with '=' is an error but BSD
57 * just ignores the '=' and anything after it.
58 */
59 for (cp = var; *cp && *cp != '='; cp++)
60 continue;
61 esize = (size_t)(cp - var) + 2;
62 if (val) {
63 esize += strlen(val); /* glibc treats a NULL val as "" */
64 }
65
66 /* Allocate and fill in estring. */
67 if ((estring = ep = malloc(esize)) == NULL)
68 goto done;
69 for (cp = var; *cp && *cp != '='; cp++)
70 *ep++ = *cp;
71 *ep++ = '=';
72 if (val) {
73 for (cp = val; *cp; cp++)
74 *ep++ = *cp;
75 }
76 *ep = '\0';
77
78 ret = sudo_putenv_nodebug(estring, true, overwrite);
79 done:
80 if (ret == -1)
81 free(estring);
82 else
83 sudoers_gc_add(GC_PTR, estring);
84 return ret;
85 }
86
87 int
sudoers_hook_getenv(const char * name,char ** value,void * closure)88 sudoers_hook_getenv(const char *name, char **value, void *closure)
89 {
90 static bool in_progress = false; /* avoid recursion */
91
92 if (in_progress || env_get() == NULL)
93 return SUDO_HOOK_RET_NEXT;
94
95 in_progress = true;
96
97 /* Hack to make GNU gettext() find the sudoers locale when needed. */
98 if (*name == 'L' && sudoers_getlocale() == SUDOERS_LOCALE_SUDOERS) {
99 if (strcmp(name, "LANGUAGE") == 0 || strcmp(name, "LANG") == 0) {
100 *value = NULL;
101 goto done;
102 }
103 if (strcmp(name, "LC_ALL") == 0 || strcmp(name, "LC_MESSAGES") == 0) {
104 *value = def_sudoers_locale;
105 goto done;
106 }
107 }
108
109 *value = sudo_getenv_nodebug(name);
110 done:
111 in_progress = false;
112 return SUDO_HOOK_RET_STOP;
113 }
114
115 int
sudoers_hook_putenv(char * string,void * closure)116 sudoers_hook_putenv(char *string, void *closure)
117 {
118 static bool in_progress = false; /* avoid recursion */
119
120 if (in_progress || env_get() == NULL)
121 return SUDO_HOOK_RET_NEXT;
122
123 in_progress = true;
124 sudo_putenv_nodebug(string, true, true);
125 in_progress = false;
126 return SUDO_HOOK_RET_STOP;
127 }
128
129 int
sudoers_hook_setenv(const char * name,const char * value,int overwrite,void * closure)130 sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure)
131 {
132 static bool in_progress = false; /* avoid recursion */
133
134 if (in_progress || env_get() == NULL)
135 return SUDO_HOOK_RET_NEXT;
136
137 in_progress = true;
138 sudo_setenv_nodebug(name, value, overwrite);
139 in_progress = false;
140 return SUDO_HOOK_RET_STOP;
141 }
142
143 int
sudoers_hook_unsetenv(const char * name,void * closure)144 sudoers_hook_unsetenv(const char *name, void *closure)
145 {
146 static bool in_progress = false; /* avoid recursion */
147
148 if (in_progress || env_get() == NULL)
149 return SUDO_HOOK_RET_NEXT;
150
151 in_progress = true;
152 sudo_unsetenv_nodebug(name);
153 in_progress = false;
154 return SUDO_HOOK_RET_STOP;
155 }
156