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