Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / tsgetgrpw.c
1 /*
2  * Copyright (c) 2005, 2008, 2010-2013
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines
20  * for use by testsudoers in the sudo test harness.
21  * We need our own since many platforms don't provide set{pw,gr}file().
22  */
23
24 #include <config.h>
25
26 #include <sys/types.h>
27 #include <stdio.h>
28 #ifdef STDC_HEADERS
29 # include <stdlib.h>
30 # include <stddef.h>
31 #else
32 # ifdef HAVE_STDLIB_H
33 #  include <stdlib.h>
34 # endif
35 #endif /* STDC_HEADERS */
36 #ifdef HAVE_STRING_H
37 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
38 #  include <memory.h>
39 # endif
40 # include <string.h>
41 #endif /* HAVE_STRING_H */
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif /* HAVE_STRINGS_H */
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <limits.h>
48
49 #include "tsgetgrpw.h"
50 #include "sudoers.h"
51
52 #ifndef LINE_MAX
53 # define LINE_MAX 2048
54 #endif
55
56 #undef GRMEM_MAX
57 #define GRMEM_MAX 200
58
59 #ifndef UID_MAX
60 # define UID_MAX 0xffffffffU
61 #endif
62
63 #ifndef GID_MAX
64 # define GID_MAX UID_MAX
65 #endif
66
67 static FILE *pwf;
68 static const char *pwfile = "/etc/passwd";
69 static int pw_stayopen;
70
71 static FILE *grf;
72 static const char *grfile = "/etc/group";
73 static int gr_stayopen;
74
75 void setgrfile(const char *);
76 void setgrent(void);
77 void endgrent(void);
78 struct group *getgrent(void);
79 struct group *getgrnam(const char *);
80 struct group *getgrgid(gid_t);
81
82 void setpwfile(const char *);
83 void setpwent(void);
84 void endpwent(void);
85 struct passwd *getpwent(void);
86 struct passwd *getpwnam(const char *);
87 struct passwd *getpwuid(uid_t);
88
89 void
90 setpwfile(const char *file)
91 {
92     pwfile = file;
93     if (pwf != NULL)
94         endpwent();
95 }
96
97 void
98 setpwent(void)
99 {
100     if (pwf == NULL) {
101         pwf = fopen(pwfile, "r");
102         if (pwf != NULL)
103             fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
104     } else {
105         rewind(pwf);
106     }
107     pw_stayopen = 1;
108 }
109
110 void
111 endpwent(void)
112 {
113     if (pwf != NULL) {
114         fclose(pwf);
115         pwf = NULL;
116     }
117     pw_stayopen = 0;
118 }
119
120 struct passwd *
121 getpwent(void)
122 {
123     static struct passwd pw;
124     static char pwbuf[LINE_MAX];
125     size_t len;
126     unsigned long id;
127     char *cp, *colon, *ep;
128
129 next_entry:
130     if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
131         return NULL;
132
133     zero_bytes(&pw, sizeof(pw));
134     if ((colon = strchr(cp = colon, ':')) == NULL)
135         goto next_entry;
136     *colon++ = '\0';
137     pw.pw_name = cp;
138     if ((colon = strchr(cp = colon, ':')) == NULL)
139         goto next_entry;
140     *colon++ = '\0';
141     pw.pw_passwd = cp;
142     if ((colon = strchr(cp = colon, ':')) == NULL)
143         goto next_entry;
144     *colon++ = '\0';
145     id = strtoul(cp, &ep, 10);
146     if (*cp == '\0' || *ep != '\0')
147         goto next_entry;
148     if (id > UID_MAX || (id == ULONG_MAX && errno == ERANGE))
149         goto next_entry;
150     pw.pw_uid = (uid_t)id;
151     if ((colon = strchr(cp = colon, ':')) == NULL)
152         goto next_entry;
153     *colon++ = '\0';
154     id = strtoul(cp, &ep, 10);
155     if (*cp == '\0' || *ep != '\0')
156         goto next_entry;
157     if (id > GID_MAX || (id == ULONG_MAX && errno == ERANGE))
158         goto next_entry;
159     pw.pw_gid = (gid_t)id;
160     if ((colon = strchr(cp = colon, ':')) == NULL)
161         goto next_entry;
162     *colon++ = '\0';
163     pw.pw_gecos = cp;
164     if ((colon = strchr(cp = colon, ':')) == NULL)
165         goto next_entry;
166     *colon++ = '\0';
167     pw.pw_dir = cp;
168     pw.pw_shell = colon;
169     len = strlen(colon);
170     if (len > 0 && colon[len - 1] == '\n')
171         colon[len - 1] = '\0';
172     return &pw;
173 }
174
175 struct passwd *
176 getpwnam(const char *name)
177 {
178     struct passwd *pw;
179
180     if (pwf == NULL) {
181         if ((pwf = fopen(pwfile, "r")) == NULL)
182             return NULL;
183         fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
184     } else {
185         rewind(pwf);
186     }
187     while ((pw = getpwent()) != NULL) {
188         if (strcmp(pw->pw_name, name) == 0)
189             break;
190     }
191     if (!pw_stayopen) {
192         fclose(pwf);
193         pwf = NULL;
194     }
195     return pw;
196 }
197
198 struct passwd *
199 getpwuid(uid_t uid)
200 {
201     struct passwd *pw;
202
203     if (pwf == NULL) {
204         if ((pwf = fopen(pwfile, "r")) == NULL)
205             return NULL;
206         fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
207     } else {
208         rewind(pwf);
209     }
210     while ((pw = getpwent()) != NULL) {
211         if (pw->pw_uid == uid)
212             break;
213     }
214     if (!pw_stayopen) {
215         fclose(pwf);
216         pwf = NULL;
217     }
218     return pw;
219 }
220
221 void
222 setgrfile(const char *file)
223 {
224     grfile = file;
225     if (grf != NULL)
226         endgrent();
227 }
228
229 void
230 setgrent(void)
231 {
232     if (grf == NULL) {
233         grf = fopen(grfile, "r");
234         if (grf != NULL)
235             fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
236     } else {
237         rewind(grf);
238     }
239     gr_stayopen = 1;
240 }
241
242 void
243 endgrent(void)
244 {
245     if (grf != NULL) {
246         fclose(grf);
247         grf = NULL;
248     }
249     gr_stayopen = 0;
250 }
251
252 struct group *
253 getgrent(void)
254 {
255     static struct group gr;
256     static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
257     size_t len;
258     unsigned long id;
259     char *cp, *colon, *ep;
260     int n;
261
262 next_entry:
263     if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
264         return NULL;
265
266     zero_bytes(&gr, sizeof(gr));
267     if ((colon = strchr(cp = colon, ':')) == NULL)
268         goto next_entry;
269     *colon++ = '\0';
270     gr.gr_name = cp;
271     if ((colon = strchr(cp = colon, ':')) == NULL)
272         goto next_entry;
273     *colon++ = '\0';
274     gr.gr_passwd = cp;
275     if ((colon = strchr(cp = colon, ':')) == NULL)
276         goto next_entry;
277     *colon++ = '\0';
278     id = strtoul(cp, &ep, 10);
279     if (*cp == '\0' || *ep != '\0')
280         goto next_entry;
281     if (id > GID_MAX || (id == ULONG_MAX && errno == ERANGE))
282         goto next_entry;
283     gr.gr_gid = (gid_t)id;
284     len = strlen(colon);
285     if (len > 0 && colon[len - 1] == '\n')
286         colon[len - 1] = '\0';
287     if (*colon != '\0') {
288         gr.gr_mem = gr_mem;
289         cp = strtok(colon, ",");
290         for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
291             gr.gr_mem[n] = cp;
292             cp = strtok(NULL, ",");
293         }
294         gr.gr_mem[n++] = NULL;
295     } else
296         gr.gr_mem = NULL;
297     return &gr;
298 }
299
300 struct group *
301 getgrnam(const char *name)
302 {
303     struct group *gr;
304
305     if (grf == NULL) {
306         if ((grf = fopen(grfile, "r")) == NULL)
307             return NULL;
308         fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
309     } else {
310         rewind(grf);
311     }
312     while ((gr = getgrent()) != NULL) {
313         if (strcmp(gr->gr_name, name) == 0)
314             break;
315     }
316     if (!gr_stayopen) {
317         fclose(grf);
318         grf = NULL;
319     }
320     return gr;
321 }
322
323 struct group *
324 getgrgid(gid_t gid)
325 {
326     struct group *gr;
327
328     if (grf == NULL) {
329         if ((grf = fopen(grfile, "r")) == NULL)
330             return NULL;
331         fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
332     } else {
333         rewind(grf);
334     }
335     while ((gr = getgrent()) != NULL) {
336         if (gr->gr_gid == gid)
337             break;
338     }
339     if (!gr_stayopen) {
340         fclose(grf);
341         grf = NULL;
342     }
343     return gr;
344 }