Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/plugins/sudoers/group_plugin.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2010-2020, 2022 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 <sys/stat.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
#include <ctype.h>
27
#include <errno.h>
28
29
#include <sudoers.h>
30
#include <sudo_dso.h>
31
32
#if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD)
33
34
static void *group_handle;
35
static struct sudoers_group_plugin *group_plugin;
36
37
/*
38
* Check for a fallback path when the original group plugin is not loadable.
39
* Returns true on success, rewriting path and filling in sb, else false.
40
*/
41
static bool
42
group_plugin_fallback(char *path, size_t pathsize)
43
{
44
#if defined(__LP64__)
45
char newpath[PATH_MAX];
46
bool ret = false;
47
struct stat sb;
48
int len;
49
debug_decl(group_plugin_fallback, SUDOERS_DEBUG_UTIL);
50
51
# if defined(__sun__) || defined(__linux__)
52
/*
53
* Solaris uses /lib/64 and /usr/lib/64 for 64-bit libraries.
54
* Linux may use /lib64 and /usr/lib64 for 64-bit libraries.
55
* If dirname(path) ends in /lib, try /lib/64 (Solaris) or /lib64 (Linux).
56
*/
57
# if defined(__sun__)
58
const char *lib64 = "lib/64";
59
# else
60
const char *lib64 = "lib64";
61
# endif
62
const char *base, *slash;
63
int dirlen;
64
65
slash = strrchr(path, '/');
66
if (slash == NULL) {
67
goto done;
68
}
69
base = slash + 1;
70
71
/* Collapse consecutive slashes. */
72
while (slash > path && slash[-1] == '/') {
73
slash--;
74
}
75
76
/* If directory ends in /lib/, try again with /lib/64/ or /lib64/. */
77
dirlen = (int)(slash - path);
78
if (dirlen < 4 || strncmp(slash - 4, "/lib", 4) != 0) {
79
goto done;
80
}
81
dirlen -= 4;
82
len = snprintf(newpath, sizeof(newpath), "%.*s/%s/%s", dirlen, path, lib64,
83
base);
84
# else /* !__sun__ && !__linux__ */
85
/*
86
* Multilib not supported, check for a path of the form libfoo64.so.
87
*/
88
const char *dot;
89
int plen;
90
91
dot = strrchr(path, '.');
92
if (dot == NULL) {
93
goto done;
94
}
95
plen = (int)(dot - path);
96
97
/* If basename(path) doesn't match libfoo64.so, try adding the 64. */
98
if (plen >= 2 && strncmp(dot - 2, "64", 2) == 0) {
99
goto done;
100
}
101
len = snprintf(newpath, sizeof(newpath), "%.*s64%s", plen, path, dot);
102
# endif /* __sun__ || __linux__ */
103
if (len < 0 || len >= ssizeof(newpath)) {
104
errno = ENAMETOOLONG;
105
goto done;
106
}
107
if (stat(newpath, &sb) == -1) {
108
goto done;
109
}
110
if (strlcpy(path, newpath, pathsize) >= pathsize) {
111
errno = ENAMETOOLONG;
112
goto done;
113
}
114
ret = true;
115
done:
116
debug_return_bool(ret);
117
#else
118
return false;
119
#endif /* __LP64__ */
120
}
121
122
/*
123
* Load the specified plugin and run its init function.
124
* Returns -1 if unable to open the plugin, else it returns
125
* the value from the plugin's init function.
126
*/
127
static int
128
group_plugin_load(const struct sudoers_context *ctx, const char *plugin_info)
129
{
130
const char *plugin_dir = ctx->settings.plugin_dir;
131
char *args, path[PATH_MAX];
132
char **argv = NULL;
133
int len, rc = -1;
134
bool retry = true;
135
debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL);
136
137
/*
138
* Fill in .so path and split out args (if any).
139
*/
140
if ((args = strpbrk(plugin_info, " \t")) != NULL) {
141
len = snprintf(path, sizeof(path), "%s%.*s",
142
(*plugin_info != '/') ? plugin_dir : "",
143
(int)(args - plugin_info), plugin_info);
144
args++;
145
} else {
146
len = snprintf(path, sizeof(path), "%s%s",
147
(*plugin_info != '/') ? plugin_dir : "", plugin_info);
148
}
149
if (len < 0 || len >= ssizeof(path)) {
150
errno = ENAMETOOLONG;
151
sudo_warn("%s%s",
152
(*plugin_info != '/') ? plugin_dir : "", plugin_info);
153
goto done;
154
}
155
156
for (;;) {
157
group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL);
158
if (group_handle != NULL) {
159
break;
160
}
161
162
if (!retry || !group_plugin_fallback(path, sizeof(path))) {
163
const char *errstr = sudo_dso_strerror();
164
sudo_warnx(U_("unable to load %s: %s"), path,
165
errstr ? errstr : "unknown error");
166
goto done;
167
}
168
169
/* Retry once with the fallback path. */
170
retry = false;
171
}
172
173
/* Map in symbol from group plugin. */
174
group_plugin = sudo_dso_findsym(group_handle, "group_plugin");
175
if (group_plugin == NULL) {
176
sudo_warnx(U_("unable to find symbol \"group_plugin\" in %s"), path);
177
goto done;
178
}
179
180
if (SUDO_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
181
sudo_warnx(U_("%s: incompatible group plugin major version %d, expected %d"),
182
path, SUDO_API_VERSION_GET_MAJOR(group_plugin->version),
183
GROUP_API_VERSION_MAJOR);
184
goto done;
185
}
186
187
/*
188
* Split args into a vector if specified.
189
*/
190
if (args != NULL) {
191
int ac = 0;
192
bool wasblank = true;
193
char *cp, *last;
194
195
for (cp = args; *cp != '\0'; cp++) {
196
if (isblank((unsigned char)*cp)) {
197
wasblank = true;
198
} else if (wasblank) {
199
wasblank = false;
200
ac++;
201
}
202
}
203
if (ac != 0) {
204
argv = reallocarray(NULL, (size_t)ac + 1, sizeof(char *));
205
if (argv == NULL) {
206
sudo_warnx(U_("%s: %s"), __func__,
207
U_("unable to allocate memory"));
208
goto done;
209
}
210
ac = 0;
211
cp = strtok_r(args, " \t", &last);
212
while (cp != NULL) {
213
argv[ac++] = cp;
214
cp = strtok_r(NULL, " \t", &last);
215
}
216
argv[ac] = NULL;
217
}
218
}
219
220
rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);
221
222
done:
223
free(argv);
224
225
if (rc != true) {
226
if (group_handle != NULL) {
227
sudo_dso_unload(group_handle);
228
group_handle = NULL;
229
group_plugin = NULL;
230
}
231
}
232
233
debug_return_int(rc);
234
}
235
236
void
237
group_plugin_unload(void)
238
{
239
debug_decl(group_plugin_unload, SUDOERS_DEBUG_UTIL);
240
241
if (group_plugin != NULL) {
242
(group_plugin->cleanup)();
243
group_plugin = NULL;
244
}
245
if (group_handle != NULL) {
246
sudo_dso_unload(group_handle);
247
group_handle = NULL;
248
}
249
debug_return;
250
}
251
252
int
253
group_plugin_query(const char *user, const char *group,
254
const struct passwd *pwd)
255
{
256
debug_decl(group_plugin_query, SUDOERS_DEBUG_UTIL);
257
258
if (group_plugin == NULL)
259
debug_return_int(false);
260
debug_return_int((group_plugin->query)(user, group, pwd));
261
}
262
263
#else /* !HAVE_DLOPEN && !HAVE_SHL_LOAD */
264
265
/*
266
* No loadable shared object support.
267
*/
268
269
static int
270
group_plugin_load(const struct sudoers_context *ctx, const char *plugin_info)
271
{
272
debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL);
273
debug_return_int(false);
274
}
275
276
void
277
group_plugin_unload(void)
278
{
279
debug_decl(group_plugin_unload, SUDOERS_DEBUG_UTIL);
280
debug_return;
281
}
282
283
int
284
group_plugin_query(const char *user, const char *group,
285
const struct passwd *pwd)
286
{
287
debug_decl(group_plugin_query, SUDOERS_DEBUG_UTIL);
288
debug_return_int(false);
289
}
290
291
#endif /* HAVE_DLOPEN || HAVE_SHL_LOAD */
292
293
/*
294
* Group plugin sudoers callback.
295
*/
296
bool
297
cb_group_plugin(struct sudoers_context *ctx, const char *file,
298
int line, int column, const union sudo_defs_val *sd_un, int op)
299
{
300
bool rc = true;
301
debug_decl(cb_group_plugin, SUDOERS_DEBUG_PLUGIN);
302
303
/* Unload any existing group plugin before loading a new one. */
304
group_plugin_unload();
305
if (sd_un->str != NULL)
306
rc = group_plugin_load(ctx, sd_un->str);
307
debug_return_bool(rc);
308
}
309
310