1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2005,2008,2010-2015 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 /*
25  * Trivial replacements for the libc getgr{uid,nam}() routines.
26  */
27 
28 #include <config.h>
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <limits.h>
35 #include <grp.h>
36 
37 #include "sudo_compat.h"
38 #include "sudo_util.h"
39 
40 #undef GRMEM_MAX
41 #define GRMEM_MAX 200
42 
43 static FILE *grf;
44 static const char *grfile = "/etc/group";
45 static int gr_stayopen;
46 
47 void mysetgrfile(const char *);
48 void mysetgrent(void);
49 void myendgrent(void);
50 struct group *mygetgrent(void);
51 struct group *mygetgrnam(const char *);
52 struct group *mygetgrgid(gid_t);
53 
54 void
mysetgrfile(const char * file)55 mysetgrfile(const char *file)
56 {
57     grfile = file;
58     if (grf != NULL)
59 	myendgrent();
60 }
61 
62 void
mysetgrent(void)63 mysetgrent(void)
64 {
65     if (grf == NULL) {
66 	grf = fopen(grfile, "r");
67 	if (grf != NULL) {
68 	    if (fcntl(fileno(grf), F_SETFD, FD_CLOEXEC) == -1) {
69 		fclose(grf);
70 		grf = NULL;
71 	    }
72 	}
73     } else {
74 	rewind(grf);
75     }
76     gr_stayopen = 1;
77 }
78 
79 void
myendgrent(void)80 myendgrent(void)
81 {
82     if (grf != NULL) {
83 	fclose(grf);
84 	grf = NULL;
85     }
86     gr_stayopen = 0;
87 }
88 
89 struct group *
mygetgrent(void)90 mygetgrent(void)
91 {
92     static struct group gr;
93     static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
94     size_t len;
95     id_t id;
96     char *cp, *colon;
97     const char *errstr;
98     int n;
99 
100 next_entry:
101     if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
102 	return NULL;
103 
104     memset(&gr, 0, sizeof(gr));
105     if ((colon = strchr(cp = colon, ':')) == NULL)
106 	goto next_entry;
107     *colon++ = '\0';
108     gr.gr_name = cp;
109     if ((colon = strchr(cp = colon, ':')) == NULL)
110 	goto next_entry;
111     *colon++ = '\0';
112     gr.gr_passwd = cp;
113     if ((colon = strchr(cp = colon, ':')) == NULL)
114 	goto next_entry;
115     *colon++ = '\0';
116     id = sudo_strtoid(cp, &errstr);
117     if (errstr != NULL)
118 	goto next_entry;
119     gr.gr_gid = (gid_t)id;
120     len = strlen(colon);
121     if (len > 0 && colon[len - 1] == '\n')
122 	colon[len - 1] = '\0';
123     if (*colon != '\0') {
124 	char *last;
125 
126 	gr.gr_mem = gr_mem;
127 	cp = strtok_r(colon, ",", &last);
128 	for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
129 	    gr.gr_mem[n] = cp;
130 	    cp = strtok_r(NULL, ",", &last);
131 	}
132 	gr.gr_mem[n++] = NULL;
133     } else
134 	gr.gr_mem = NULL;
135     return &gr;
136 }
137 
138 struct group *
mygetgrnam(const char * name)139 mygetgrnam(const char *name)
140 {
141     struct group *gr;
142 
143     if (grf == NULL) {
144 	if ((grf = fopen(grfile, "r")) == NULL)
145 	    return NULL;
146 	if (fcntl(fileno(grf), F_SETFD, FD_CLOEXEC) == -1) {
147 	    fclose(grf);
148 	    return NULL;
149 	}
150     } else {
151 	rewind(grf);
152     }
153     while ((gr = mygetgrent()) != NULL) {
154 	if (strcmp(gr->gr_name, name) == 0)
155 	    break;
156     }
157     if (!gr_stayopen) {
158 	fclose(grf);
159 	grf = NULL;
160     }
161     return gr;
162 }
163 
164 struct group *
mygetgrgid(gid_t gid)165 mygetgrgid(gid_t gid)
166 {
167     struct group *gr;
168 
169     if (grf == NULL) {
170 	if ((grf = fopen(grfile, "r")) == NULL)
171 	    return NULL;
172 	if (fcntl(fileno(grf), F_SETFD, FD_CLOEXEC) == -1) {
173 	    fclose(grf);
174 	    return NULL;
175 	}
176     } else {
177 	rewind(grf);
178     }
179     while ((gr = mygetgrent()) != NULL) {
180 	if (gr->gr_gid == gid)
181 	    break;
182     }
183     if (!gr_stayopen) {
184 	fclose(grf);
185 	grf = NULL;
186     }
187     return gr;
188 }
189