]> granicus.if.org Git - sudo/blob - plugins/sudoers/group_plugin.c
Add SPDX-License-Identifier to files.
[sudo] / plugins / sudoers / group_plugin.c
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2010-2019 Todd C. Miller <Todd.Miller@sudo.ws>
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 /*
20  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22  */
23
24 #include <config.h>
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_STRING_H
31 # include <string.h>
32 #endif /* HAVE_STRING_H */
33 #ifdef HAVE_STRINGS_H
34 # include <strings.h>
35 #endif /* HAVE_STRINGS_H */
36 #include <unistd.h>
37 #include <time.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <pwd.h>
41
42 #include "sudoers.h"
43 #include "sudo_dso.h"
44
45 #if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD)
46
47 static void *group_handle;
48 static struct sudoers_group_plugin *group_plugin;
49 const char *path_plugin_dir = _PATH_SUDO_PLUGIN_DIR;
50
51 /*
52  * Load the specified plugin and run its init function.
53  * Returns -1 if unable to open the plugin, else it returns
54  * the value from the plugin's init function.
55  */
56 int
57 group_plugin_load(char *plugin_info)
58 {
59     struct stat sb;
60     char *args, path[PATH_MAX];
61     char **argv = NULL;
62     int len, rc = -1;
63     debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL)
64
65     /*
66      * Fill in .so path and split out args (if any).
67      */
68     if ((args = strpbrk(plugin_info, " \t")) != NULL) {
69         len = snprintf(path, sizeof(path), "%s%.*s",
70             (*plugin_info != '/') ? path_plugin_dir : "",
71             (int)(args - plugin_info), plugin_info);
72         args++;
73     } else {
74         len = snprintf(path, sizeof(path), "%s%s",
75             (*plugin_info != '/') ? path_plugin_dir : "", plugin_info);
76     }
77     if (len <= 0 || len >= (int)sizeof(path)) {
78         errno = ENAMETOOLONG;
79         sudo_warn("%s%s",
80             (*plugin_info != '/') ? path_plugin_dir : "", plugin_info);
81         goto done;
82     }
83
84     /* Sanity check plugin path. */
85     if (stat(path, &sb) != 0) {
86         sudo_warn("%s", path);
87         goto done;
88     }
89     if (sb.st_uid != ROOT_UID) {
90         sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID);
91         goto done;
92     }
93     if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
94         sudo_warnx(U_("%s must only be writable by owner"), path);
95         goto done;
96     }
97
98     /* Open plugin and map in symbol. */
99     group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL);
100     if (!group_handle) {
101         const char *errstr = sudo_dso_strerror();
102         sudo_warnx(U_("unable to load %s: %s"), path,
103             errstr ? errstr : "unknown error");
104         goto done;
105     }
106     group_plugin = sudo_dso_findsym(group_handle, "group_plugin");
107     if (group_plugin == NULL) {
108         sudo_warnx(U_("unable to find symbol \"group_plugin\" in %s"), path);
109         goto done;
110     }
111
112     if (SUDO_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
113         sudo_warnx(U_("%s: incompatible group plugin major version %d, expected %d"),
114             path, SUDO_API_VERSION_GET_MAJOR(group_plugin->version),
115             GROUP_API_VERSION_MAJOR);
116         goto done;
117     }
118
119     /*
120      * Split args into a vector if specified.
121      */
122     if (args != NULL) {
123         int ac = 0;
124         bool wasblank = true;
125         char *cp, *last;
126
127         for (cp = args; *cp != '\0'; cp++) {
128             if (isblank((unsigned char)*cp)) {
129                 wasblank = true;
130             } else if (wasblank) {
131                 wasblank = false;
132                 ac++;
133             }
134         }
135         if (ac != 0) {
136             argv = reallocarray(NULL, ac, sizeof(char *));
137             if (argv == NULL) {
138                 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
139                 goto done;
140             }
141             ac = 0;
142             for ((cp = strtok_r(args, " \t", &last)); cp != NULL; (cp = strtok_r(NULL, " \t", &last)))
143                 argv[ac++] = cp;
144         }
145     }
146
147     rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);
148
149 done:
150     free(argv);
151
152     if (rc != true) {
153         if (group_handle != NULL) {
154             sudo_dso_unload(group_handle);
155             group_handle = NULL;
156             group_plugin = NULL;
157         }
158     }
159
160     debug_return_int(rc);
161 }
162
163 void
164 group_plugin_unload(void)
165 {
166     debug_decl(group_plugin_unload, SUDOERS_DEBUG_UTIL)
167
168     if (group_plugin != NULL) {
169         (group_plugin->cleanup)();
170         group_plugin = NULL;
171     }
172     if (group_handle != NULL) {
173         sudo_dso_unload(group_handle);
174         group_handle = NULL;
175     }
176     debug_return;
177 }
178
179 int
180 group_plugin_query(const char *user, const char *group,
181     const struct passwd *pwd)
182 {
183     debug_decl(group_plugin_query, SUDOERS_DEBUG_UTIL)
184
185     if (group_plugin == NULL)
186         debug_return_int(false);
187     debug_return_int((group_plugin->query)(user, group, pwd));
188 }
189
190 #else /* !HAVE_DLOPEN && !HAVE_SHL_LOAD */
191
192 /*
193  * No loadable shared object support.
194  */
195
196 int
197 group_plugin_load(char *plugin_info)
198 {
199     debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL)
200     debug_return_int(false);
201 }
202
203 void
204 group_plugin_unload(void)
205 {
206     debug_decl(group_plugin_unload, SUDOERS_DEBUG_UTIL)
207     debug_return;
208 }
209
210 int
211 group_plugin_query(const char *user, const char *group,
212     const struct passwd *pwd)
213 {
214     debug_decl(group_plugin_query, SUDOERS_DEBUG_UTIL)
215     debug_return_int(false);
216 }
217
218 #endif /* HAVE_DLOPEN || HAVE_SHL_LOAD */
219
220 /*
221  * Group plugin sudoers callback.
222  */
223 bool
224 cb_group_plugin(const union sudo_defs_val *sd_un)
225 {
226     bool rc = true;
227     debug_decl(cb_group_plugin, SUDOERS_DEBUG_PLUGIN)
228
229     /* Unload any existing group plugin before loading a new one. */
230     group_plugin_unload();
231     if (sd_un->str != NULL)
232         rc = group_plugin_load(sd_un->str);
233     debug_return_bool(rc);
234 }