Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/src/hooks.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2012-2016 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
#include <errno.h>
24
25
#include <sudo.h>
26
#include <sudo_plugin.h>
27
#include <sudo_plugin_int.h>
28
29
/* Singly linked hook list. */
30
struct sudo_hook_entry {
31
SLIST_ENTRY(sudo_hook_entry) entries;
32
union {
33
sudo_hook_fn_t generic_fn;
34
sudo_hook_fn_setenv_t setenv_fn;
35
sudo_hook_fn_unsetenv_t unsetenv_fn;
36
sudo_hook_fn_getenv_t getenv_fn;
37
sudo_hook_fn_putenv_t putenv_fn;
38
} u;
39
void *closure;
40
};
41
SLIST_HEAD(sudo_hook_list, sudo_hook_entry);
42
43
/* Each hook type gets own hook list. */
44
static struct sudo_hook_list sudo_hook_setenv_list =
45
SLIST_HEAD_INITIALIZER(sudo_hook_setenv_list);
46
static struct sudo_hook_list sudo_hook_unsetenv_list =
47
SLIST_HEAD_INITIALIZER(sudo_hook_unsetenv_list);
48
static struct sudo_hook_list sudo_hook_getenv_list =
49
SLIST_HEAD_INITIALIZER(sudo_hook_getenv_list);
50
static struct sudo_hook_list sudo_hook_putenv_list =
51
SLIST_HEAD_INITIALIZER(sudo_hook_putenv_list);
52
53
/* NOTE: must not anything that might call setenv() */
54
int
55
process_hooks_setenv(const char *name, const char *value, int overwrite)
56
{
57
struct sudo_hook_entry *hook;
58
int rc = SUDO_HOOK_RET_NEXT;
59
60
/* First process the hooks. */
61
SLIST_FOREACH(hook, &sudo_hook_setenv_list, entries) {
62
rc = hook->u.setenv_fn(name, value, overwrite, hook->closure);
63
if (rc == SUDO_HOOK_RET_STOP || rc == SUDO_HOOK_RET_ERROR)
64
break;
65
}
66
return rc;
67
}
68
69
/* NOTE: must not anything that might call putenv() */
70
int
71
process_hooks_putenv(char *string)
72
{
73
struct sudo_hook_entry *hook;
74
int rc = SUDO_HOOK_RET_NEXT;
75
76
/* First process the hooks. */
77
SLIST_FOREACH(hook, &sudo_hook_putenv_list, entries) {
78
rc = hook->u.putenv_fn(string, hook->closure);
79
if (rc == SUDO_HOOK_RET_STOP || rc == SUDO_HOOK_RET_ERROR)
80
break;
81
}
82
return rc;
83
}
84
85
/* NOTE: must not anything that might call getenv() */
86
int
87
process_hooks_getenv(const char *name, char **value)
88
{
89
struct sudo_hook_entry *hook;
90
char *val = NULL;
91
int rc = SUDO_HOOK_RET_NEXT;
92
93
/* First process the hooks. */
94
SLIST_FOREACH(hook, &sudo_hook_getenv_list, entries) {
95
rc = hook->u.getenv_fn(name, &val, hook->closure);
96
if (rc == SUDO_HOOK_RET_STOP || rc == SUDO_HOOK_RET_ERROR)
97
break;
98
}
99
if (val != NULL)
100
*value = val;
101
return rc;
102
}
103
104
/* NOTE: must not anything that might call unsetenv() */
105
int
106
process_hooks_unsetenv(const char *name)
107
{
108
struct sudo_hook_entry *hook;
109
int rc = SUDO_HOOK_RET_NEXT;
110
111
/* First process the hooks. */
112
SLIST_FOREACH(hook, &sudo_hook_unsetenv_list, entries) {
113
rc = hook->u.unsetenv_fn(name, hook->closure);
114
if (rc == SUDO_HOOK_RET_STOP || rc == SUDO_HOOK_RET_ERROR)
115
break;
116
}
117
return rc;
118
}
119
120
/* Hook registration internals. */
121
static int
122
register_hook_internal(struct sudo_hook_list *head,
123
sudo_hook_fn_t hook_fn, void *closure)
124
{
125
struct sudo_hook_entry *hook;
126
debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS);
127
128
if ((hook = calloc(1, sizeof(*hook))) == NULL) {
129
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
130
"unable to allocate memory");
131
debug_return_int(-1);
132
}
133
hook->u.generic_fn = hook_fn;
134
hook->closure = closure;
135
SLIST_INSERT_HEAD(head, hook, entries);
136
137
debug_return_int(0);
138
}
139
140
/* Register the specified hook. */
141
int
142
register_hook(struct sudo_hook *hook)
143
{
144
int ret;
145
debug_decl(register_hook, SUDO_DEBUG_HOOKS);
146
147
if (SUDO_API_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
148
/* Major versions must match. */
149
errno = EINVAL;
150
ret = -1;
151
} else {
152
switch (hook->hook_type) {
153
case SUDO_HOOK_GETENV:
154
ret = register_hook_internal(&sudo_hook_getenv_list,
155
hook->hook_fn, hook->closure);
156
break;
157
case SUDO_HOOK_PUTENV:
158
ret = register_hook_internal(&sudo_hook_putenv_list,
159
hook->hook_fn, hook->closure);
160
break;
161
case SUDO_HOOK_SETENV:
162
ret = register_hook_internal(&sudo_hook_setenv_list,
163
hook->hook_fn, hook->closure);
164
break;
165
case SUDO_HOOK_UNSETENV:
166
ret = register_hook_internal(&sudo_hook_unsetenv_list,
167
hook->hook_fn, hook->closure);
168
break;
169
default:
170
/* XXX - use define for unknown value */
171
errno = ENOTSUP;
172
ret = 1;
173
break;
174
}
175
}
176
177
debug_return_int(ret);
178
}
179
180
/* Hook deregistration internals. */
181
static void
182
deregister_hook_internal(struct sudo_hook_list *head,
183
sudo_hook_fn_t hook_fn, void *closure)
184
{
185
struct sudo_hook_entry *hook, *prev = NULL;
186
debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS);
187
188
SLIST_FOREACH(hook, head, entries) {
189
if (hook->u.generic_fn == hook_fn && hook->closure == closure) {
190
/* Remove from list and free. */
191
if (prev == NULL)
192
SLIST_REMOVE_HEAD(head, entries);
193
else
194
SLIST_REMOVE_AFTER(prev, entries);
195
free(hook);
196
break;
197
}
198
prev = hook;
199
}
200
201
debug_return;
202
}
203
204
/* Deregister the specified hook. */
205
int
206
deregister_hook(struct sudo_hook *hook)
207
{
208
int ret = 0;
209
debug_decl(deregister_hook, SUDO_DEBUG_HOOKS);
210
211
if (SUDO_API_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
212
/* Major versions must match. */
213
ret = -1;
214
} else {
215
switch (hook->hook_type) {
216
case SUDO_HOOK_GETENV:
217
deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
218
hook->closure);
219
break;
220
case SUDO_HOOK_PUTENV:
221
deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
222
hook->closure);
223
break;
224
case SUDO_HOOK_SETENV:
225
deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
226
hook->closure);
227
break;
228
case SUDO_HOOK_UNSETENV:
229
deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
230
hook->closure);
231
break;
232
default:
233
/* XXX - use define for unknown value */
234
ret = 1;
235
break;
236
}
237
}
238
239
debug_return_int(ret);
240
}
241
242