]> granicus.if.org Git - sudo/blob - plugins/sudoers/tsgetgrpw.c
Add SPDX-License-Identifier to files.
[sudo] / plugins / sudoers / tsgetgrpw.c
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2005, 2008, 2010-2015
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
20 /*
21  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
22  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
23  */
24
25 /*
26  * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines
27  * for use by testsudoers in the sudo test harness.
28  * We need our own since many platforms don't provide set{pw,gr}file().
29  */
30
31 #include <config.h>
32
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #endif /* HAVE_STRING_H */
39 #ifdef HAVE_STRINGS_H
40 # include <strings.h>
41 #endif /* HAVE_STRINGS_H */
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <limits.h>
45 #include <unistd.h>
46
47 #include "tsgetgrpw.h"
48 #include "sudoers.h"
49
50 #undef GRMEM_MAX
51 #define GRMEM_MAX 200
52
53 #ifndef UID_MAX
54 # define UID_MAX 0xffffffffU
55 #endif
56
57 #ifndef GID_MAX
58 # define GID_MAX UID_MAX
59 #endif
60
61 static FILE *pwf;
62 static const char *pwfile = "/etc/passwd";
63 static int pw_stayopen;
64
65 static FILE *grf;
66 static const char *grfile = "/etc/group";
67 static int gr_stayopen;
68
69 void setgrfile(const char *);
70 void setgrent(void);
71 void endgrent(void);
72 struct group *getgrent(void);
73 struct group *getgrnam(const char *);
74 struct group *getgrgid(gid_t);
75
76 void setpwfile(const char *);
77 void setpwent(void);
78 void endpwent(void);
79 struct passwd *getpwent(void);
80 struct passwd *getpwnam(const char *);
81 struct passwd *getpwuid(uid_t);
82
83 void
84 setpwfile(const char *file)
85 {
86     pwfile = file;
87     if (pwf != NULL)
88         endpwent();
89 }
90
91 void
92 setpwent(void)
93 {
94     if (pwf == NULL) {
95         pwf = fopen(pwfile, "r");
96         if (pwf != NULL)
97             (void)fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
98     } else {
99         rewind(pwf);
100     }
101     pw_stayopen = 1;
102 }
103
104 void
105 endpwent(void)
106 {
107     if (pwf != NULL) {
108         fclose(pwf);
109         pwf = NULL;
110     }
111     pw_stayopen = 0;
112 }
113
114 struct passwd *
115 getpwent(void)
116 {
117     static struct passwd pw;
118     static char pwbuf[LINE_MAX];
119     size_t len;
120     id_t id;
121     char *cp, *colon;
122     const char *errstr;
123
124 next_entry:
125     if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
126         return NULL;
127
128     memset(&pw, 0, sizeof(pw));
129     if ((colon = strchr(cp = colon, ':')) == NULL)
130         goto next_entry;
131     *colon++ = '\0';
132     pw.pw_name = cp;
133     if ((colon = strchr(cp = colon, ':')) == NULL)
134         goto next_entry;
135     *colon++ = '\0';
136     pw.pw_passwd = cp;
137     if ((colon = strchr(cp = colon, ':')) == NULL)
138         goto next_entry;
139     *colon++ = '\0';
140     id = sudo_strtoid(cp, NULL, NULL, &errstr);
141     if (errstr != NULL)
142         goto next_entry;
143     pw.pw_uid = (uid_t)id;
144     if ((colon = strchr(cp = colon, ':')) == NULL)
145         goto next_entry;
146     *colon++ = '\0';
147     id = sudo_strtoid(cp, NULL, NULL, &errstr);
148     if (errstr != NULL)
149         goto next_entry;
150     pw.pw_gid = (gid_t)id;
151     if ((colon = strchr(cp = colon, ':')) == NULL)
152         goto next_entry;
153     *colon++ = '\0';
154     pw.pw_gecos = cp;
155     if ((colon = strchr(cp = colon, ':')) == NULL)
156         goto next_entry;
157     *colon++ = '\0';
158     pw.pw_dir = cp;
159     pw.pw_shell = colon;
160     len = strlen(colon);
161     if (len > 0 && colon[len - 1] == '\n')
162         colon[len - 1] = '\0';
163     return &pw;
164 }
165
166 struct passwd *
167 getpwnam(const char *name)
168 {
169     struct passwd *pw;
170
171     if (pwf == NULL) {
172         if ((pwf = fopen(pwfile, "r")) == NULL)
173             return NULL;
174         (void)fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
175     } else {
176         rewind(pwf);
177     }
178     while ((pw = getpwent()) != NULL) {
179         if (strcmp(pw->pw_name, name) == 0)
180             break;
181     }
182     if (!pw_stayopen) {
183         fclose(pwf);
184         pwf = NULL;
185     }
186     return pw;
187 }
188
189 struct passwd *
190 getpwuid(uid_t uid)
191 {
192     struct passwd *pw;
193
194     if (pwf == NULL) {
195         if ((pwf = fopen(pwfile, "r")) == NULL)
196             return NULL;
197         (void)fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
198     } else {
199         rewind(pwf);
200     }
201     while ((pw = getpwent()) != NULL) {
202         if (pw->pw_uid == uid)
203             break;
204     }
205     if (!pw_stayopen) {
206         fclose(pwf);
207         pwf = NULL;
208     }
209     return pw;
210 }
211
212 void
213 setgrfile(const char *file)
214 {
215     grfile = file;
216     if (grf != NULL)
217         endgrent();
218 }
219
220 void
221 setgrent(void)
222 {
223     if (grf == NULL) {
224         grf = fopen(grfile, "r");
225         if (grf != NULL)
226             (void)fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
227     } else {
228         rewind(grf);
229     }
230     gr_stayopen = 1;
231 }
232
233 void
234 endgrent(void)
235 {
236     if (grf != NULL) {
237         fclose(grf);
238         grf = NULL;
239     }
240     gr_stayopen = 0;
241 }
242
243 struct group *
244 getgrent(void)
245 {
246     static struct group gr;
247     static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
248     size_t len;
249     id_t id;
250     char *cp, *colon;
251     const char *errstr;
252     int n;
253
254 next_entry:
255     if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
256         return NULL;
257
258     memset(&gr, 0, sizeof(gr));
259     if ((colon = strchr(cp = colon, ':')) == NULL)
260         goto next_entry;
261     *colon++ = '\0';
262     gr.gr_name = cp;
263     if ((colon = strchr(cp = colon, ':')) == NULL)
264         goto next_entry;
265     *colon++ = '\0';
266     gr.gr_passwd = cp;
267     if ((colon = strchr(cp = colon, ':')) == NULL)
268         goto next_entry;
269     *colon++ = '\0';
270     id = sudo_strtoid(cp, NULL, NULL, &errstr);
271     if (errstr != NULL)
272         goto next_entry;
273     gr.gr_gid = (gid_t)id;
274     len = strlen(colon);
275     if (len > 0 && colon[len - 1] == '\n')
276         colon[len - 1] = '\0';
277     if (*colon != '\0') {
278         char *last;
279
280         gr.gr_mem = gr_mem;
281         cp = strtok_r(colon, ",", &last);
282         for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
283             gr.gr_mem[n] = cp;
284             cp = strtok_r(NULL, ",", &last);
285         }
286         gr.gr_mem[n++] = NULL;
287     } else
288         gr.gr_mem = NULL;
289     return &gr;
290 }
291
292 struct group *
293 getgrnam(const char *name)
294 {
295     struct group *gr;
296
297     if (grf == NULL) {
298         if ((grf = fopen(grfile, "r")) == NULL)
299             return NULL;
300         (void)fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
301     } else {
302         rewind(grf);
303     }
304     while ((gr = getgrent()) != NULL) {
305         if (strcmp(gr->gr_name, name) == 0)
306             break;
307     }
308     if (!gr_stayopen) {
309         fclose(grf);
310         grf = NULL;
311     }
312     return gr;
313 }
314
315 struct group *
316 getgrgid(gid_t gid)
317 {
318     struct group *gr;
319
320     if (grf == NULL) {
321         if ((grf = fopen(grfile, "r")) == NULL)
322             return NULL;
323         (void)fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
324     } else {
325         rewind(grf);
326     }
327     while ((gr = getgrent()) != NULL) {
328         if (gr->gr_gid == gid)
329             break;
330     }
331     if (!gr_stayopen) {
332         fclose(grf);
333         grf = NULL;
334     }
335     return gr;
336 }
337
338 /*
339  * Copied from getgrouplist.c
340  */
341 int
342 sudo_getgrouplist2_v1(const char *name, GETGROUPS_T basegid,
343     GETGROUPS_T **groupsp, int *ngroupsp)
344 {
345     GETGROUPS_T *groups = *groupsp;
346     int grpsize = *ngroupsp;
347     int i, ngroups = 1;
348     int ret = -1;
349     struct group *grp;
350
351     if (groups == NULL) {
352         /* Dynamically-sized group vector. */
353         grpsize = (int)sysconf(_SC_NGROUPS_MAX);
354         if (grpsize < 0)
355             grpsize = NGROUPS_MAX;
356         groups = reallocarray(NULL, grpsize, 4 * sizeof(*groups));
357         if (groups == NULL)
358             return -1;
359         grpsize <<= 2;
360     } else {
361         /* Static group vector. */
362         if (grpsize < 1)
363             return -1;
364     }
365
366     /* We support BSD semantics where the first element is the base gid */
367     groups[0] = basegid;
368
369     setgrent();
370     while ((grp = getgrent()) != NULL) {
371         if (grp->gr_gid == basegid || grp->gr_mem == NULL)
372             continue;
373
374         for (i = 0; grp->gr_mem[i] != NULL; i++) {
375             if (strcmp(name, grp->gr_mem[i]) == 0)
376                 break;
377         }
378         if (grp->gr_mem[i] == NULL)
379             continue; /* user not found */
380
381         /* Only add if it is not the same as an existing gid */
382         for (i = 0; i < ngroups; i++) {
383             if (grp->gr_gid == groups[i])
384                 break;
385         }
386         if (i == ngroups) {
387             if (ngroups == grpsize) {
388                 GETGROUPS_T *tmp;
389
390                 if (*groupsp != NULL) {
391                     /* Static group vector. */
392                     goto done;
393                 }
394                 tmp = reallocarray(groups, grpsize, 2 * sizeof(*groups));
395                 if (tmp == NULL) {
396                     free(groups);
397                     groups = NULL;
398                     ngroups = 0;
399                     goto done;
400                 }
401                 groups = tmp;
402                 grpsize <<= 1;
403             }
404             groups[ngroups++] = grp->gr_gid;
405         }
406     }
407     ret = 0;
408
409 done:
410     endgrent();
411     *groupsp = groups;
412     *ngroupsp = ngroups;
413
414     return ret;
415 }