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