Bug Summary

File:src/lib/libc/gen/getgrent.c
Warning:line 201, column 6
Value stored to 'saved_errno' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name getgrent.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libc/obj -resource-dir /usr/local/lib/clang/13.0.0 -include namespace.h -I /usr/src/lib/libc/include -I /usr/src/lib/libc/hidden -D __LIBC__ -D APIWARN -D YP -I /usr/src/lib/libc/yp -I /usr/src/lib/libc -I /usr/src/lib/libc/gdtoa -I /usr/src/lib/libc/arch/amd64/gdtoa -D INFNAN_CHECK -D MULTIPLE_THREADS -D NO_FENV_H -D USE_LOCALE -I /usr/src/lib/libc -I /usr/src/lib/libc/citrus -D RESOLVSORT -D FLOATING_POINT -D PRINTF_WIDE_CHAR -D SCANF_WIDE_CHAR -D FUTEX -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libc/gen/getgrent.c
1/* $OpenBSD: getgrent.c,v 1.48 2019/07/02 15:54:05 deraadt Exp $ */
2/*
3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <limits.h>
37#include <unistd.h>
38#include <grp.h>
39#include <errno(*__errno()).h>
40#ifdef YP1
41#include <rpc/rpc.h>
42#include <rpcsvc/yp.h>
43#include <rpcsvc/ypclnt.h>
44#include "ypinternal.h"
45#include "ypexclude.h"
46#endif
47#include "thread_private.h"
48
49/* This global storage is locked for the non-rentrant functions */
50_THREAD_PRIVATE_KEY(gr_storage)static void *_thread_tagname_gr_storage;
51static struct group_storage {
52#define MAXGRP200 200
53 char *members[MAXGRP200];
54#define MAXLINELENGTH1024 1024
55 char line[MAXLINELENGTH1024];
56} gr_storage;
57#define GETGR_R_SIZE_MAX(1024+200*sizeof(char*)) _GR_BUF_LEN(1024+200*sizeof(char*))
58
59/* File pointers are locked with the 'gr' mutex */
60_THREAD_PRIVATE_KEY(gr)static void *_thread_tagname_gr;
61static FILE *_gr_fp;
62static struct group _gr_group;
63static int _gr_stayopen;
64static int grscan(int, gid_t, const char *, struct group *, struct group_storage *,
65 int *);
66static int start_gr(void);
67static void endgrent_basic(void);
68
69static struct group *getgrnam_gs(const char *, struct group *,
70 struct group_storage *);
71static struct group *getgrgid_gs(gid_t, struct group *,
72 struct group_storage *);
73
74#ifdef YP1
75static struct _ypexclude *__ypexhead = NULL((void *)0);
76static int __ypmode = 0;
77static char *__ypcurrent, *__ypdomain;
78static int __ypcurrentlen;
79#endif
80
81struct group *
82_getgrent_yp(int *foundyp)
83{
84 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(_gr_group) :
_thread_cb.tc_tag_storage(&(_thread_tagname_gr), &(_gr_group
), sizeof(_gr_group), ((void *)0), (((void *)0))))
;
85 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
86 gr_storage, NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
;
87
88 _THREAD_PRIVATE_MUTEX_LOCK(gr)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_gr)); } while (0)
;
89 if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL((void *)0), p_gr, gs, foundyp))
90 p_gr = NULL((void *)0);
91 _THREAD_PRIVATE_MUTEX_UNLOCK(gr)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_gr)); } while (0)
;
92 return (p_gr);
93}
94
95struct group *
96getgrent(void)
97{
98 return (_getgrent_yp(NULL((void *)0)));
99}
100
101static struct group *
102getgrnam_gs(const char *name, struct group *p_gr, struct group_storage *gs)
103{
104 int rval;
105
106 _THREAD_PRIVATE_MUTEX_LOCK(gr)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_gr)); } while (0)
;
107 if (!start_gr())
108 rval = 0;
109 else {
110 rval = grscan(1, 0, name, p_gr, gs, NULL((void *)0));
111 if (!_gr_stayopen)
112 endgrent_basic();
113 }
114 _THREAD_PRIVATE_MUTEX_UNLOCK(gr)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_gr)); } while (0)
;
115 return(rval ? p_gr : NULL((void *)0));
116}
117
118struct group *
119getgrnam(const char *name)
120{
121 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(_gr_group) :
_thread_cb.tc_tag_storage(&(_thread_tagname_gr), &(_gr_group
), sizeof(_gr_group), ((void *)0), (((void *)0))))
;
122 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
123 gr_storage, NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
;
124
125 return getgrnam_gs(name, p_gr, gs);
126}
127
128int
129getgrnam_r(const char *name, struct group *grp, char *buffer,
130 size_t bufsize, struct group **result)
131{
132 int errnosave;
133 int ret;
134
135 if (bufsize < GETGR_R_SIZE_MAX(1024+200*sizeof(char*)))
136 return ERANGE34;
137 errnosave = errno(*__errno());
138 errno(*__errno()) = 0;
139 *result = getgrnam_gs(name, grp, (struct group_storage *)buffer);
140 if (*result == NULL((void *)0))
141 ret = errno(*__errno());
142 else
143 ret = 0;
144 errno(*__errno()) = errnosave;
145 return ret;
146}
147DEF_WEAK(getgrnam_r)__asm__(".weak " "getgrnam_r" " ; " "getgrnam_r" " = " "_libc_getgrnam_r"
)
;
148
149static struct group *
150getgrgid_gs(gid_t gid, struct group *p_gr, struct group_storage *gs)
151{
152 int rval;
153
154 _THREAD_PRIVATE_MUTEX_LOCK(gr)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_gr)); } while (0)
;
155 if (!start_gr())
156 rval = 0;
157 else {
158 rval = grscan(1, gid, NULL((void *)0), p_gr, gs, NULL((void *)0));
159 if (!_gr_stayopen)
160 endgrent_basic();
161 }
162 _THREAD_PRIVATE_MUTEX_UNLOCK(gr)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_gr)); } while (0)
;
163 return(rval ? p_gr : NULL((void *)0));
164}
165
166struct group *
167getgrgid(gid_t gid)
168{
169 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(_gr_group) :
_thread_cb.tc_tag_storage(&(_thread_tagname_gr), &(_gr_group
), sizeof(_gr_group), ((void *)0), (((void *)0))))
;
170 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
171 gr_storage, NULL)(_thread_cb.tc_tag_storage == ((void *)0) ? &(gr_storage)
: _thread_cb.tc_tag_storage(&(_thread_tagname_gr_storage
), &(gr_storage), sizeof(gr_storage), ((void *)0), (((void
*)0))))
;
172
173 return getgrgid_gs(gid, p_gr, gs);
174}
175
176int
177getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
178 struct group **result)
179{
180 int errnosave;
181 int ret;
182
183 if (bufsize < GETGR_R_SIZE_MAX(1024+200*sizeof(char*)))
184 return ERANGE34;
185 errnosave = errno(*__errno());
186 errno(*__errno()) = 0;
187 *result = getgrgid_gs(gid, grp, (struct group_storage *)buffer);
188 if (*result == NULL((void *)0))
189 ret = errno(*__errno());
190 else
191 ret = 0;
192 errno(*__errno()) = errnosave;
193 return ret;
194}
195DEF_WEAK(getgrgid_r)__asm__(".weak " "getgrgid_r" " ; " "getgrgid_r" " = " "_libc_getgrgid_r"
)
;
196
197static int
198start_gr(void)
199{
200#ifdef YP1
201 int saved_errno = errno(*__errno());
Value stored to 'saved_errno' during its initialization is never read
202#endif
203
204 if (_gr_fp) {
205 rewind(_gr_fp);
206#ifdef YP1
207 __ypmode = 0;
208 free(__ypcurrent);
209 __ypcurrent = NULL((void *)0);
210 if (__ypexhead)
211 __ypexclude_free(&__ypexhead);
212 __ypexhead = NULL((void *)0);
213#endif
214 return(1);
215 }
216
217#ifdef YP1
218 /*
219 * Hint to the kernel that a passwd database operation is happening.
220 */
221 saved_errno = errno(*__errno());
222 (void)access("/var/run/ypbind.lock", R_OK0x04);
223 errno(*__errno()) = saved_errno;
224#endif
225
226 return((_gr_fp = fopen(_PATH_GROUP"/etc/group", "re")) ? 1 : 0);
227}
228
229void
230setgrent(void)
231{
232 int saved_errno;
233
234 saved_errno = errno(*__errno());
235 setgroupent(0);
236 errno(*__errno()) = saved_errno;
237}
238DEF_WEAK(setgrent)__asm__(".weak " "setgrent" " ; " "setgrent" " = " "_libc_setgrent"
)
;
239
240int
241setgroupent(int stayopen)
242{
243 int retval;
244
245 _THREAD_PRIVATE_MUTEX_LOCK(gr)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_gr)); } while (0)
;
246 if (!start_gr())
247 retval = 0;
248 else {
249 _gr_stayopen = stayopen;
250 retval = 1;
251 }
252 _THREAD_PRIVATE_MUTEX_UNLOCK(gr)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_gr)); } while (0)
;
253 return (retval);
254}
255DEF_WEAK(setgroupent)__asm__(".weak " "setgroupent" " ; " "setgroupent" " = " "_libc_setgroupent"
)
;
256
257static
258void
259endgrent_basic(void)
260{
261 int saved_errno;
262
263 if (_gr_fp) {
264 saved_errno = errno(*__errno());
265 fclose(_gr_fp);
266 _gr_fp = NULL((void *)0);
267#ifdef YP1
268 __ypmode = 0;
269 free(__ypcurrent);
270 __ypcurrent = NULL((void *)0);
271 if (__ypexhead)
272 __ypexclude_free(&__ypexhead);
273 __ypexhead = NULL((void *)0);
274#endif
275 errno(*__errno()) = saved_errno;
276 }
277}
278
279void
280endgrent(void)
281{
282 _THREAD_PRIVATE_MUTEX_LOCK(gr)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_gr)); } while (0)
;
283 endgrent_basic();
284 _THREAD_PRIVATE_MUTEX_UNLOCK(gr)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_gr)); } while (0)
;
285}
286DEF_WEAK(endgrent)__asm__(".weak " "endgrent" " ; " "endgrent" " = " "_libc_endgrent"
)
;
287
288static int
289grscan(int search, gid_t gid, const char *name, struct group *p_gr,
290 struct group_storage *gs, int *foundyp)
291{
292 char *cp, **m;
293 char *bp, *endp;
294 u_long ul;
295#ifdef YP1
296 char *key, *data;
297 int keylen, datalen;
298 int r;
299#endif
300 char **members;
301 char *line;
302 int saved_errno;
303
304 if (gs == NULL((void *)0))
305 return 0;
306 members = gs->members;
307 line = gs->line;
308 saved_errno = errno(*__errno());
309
310 for (;;) {
311#ifdef YP1
312 if (__ypmode) {
313 if (__ypcurrent) {
314 r = yp_next(__ypdomain, "group.byname",
315 __ypcurrent, __ypcurrentlen,
316 &key, &keylen, &data, &datalen);
317 free(__ypcurrent);
318 __ypcurrent = key;
319 __ypcurrentlen = keylen;
320 } else {
321 r = yp_first(__ypdomain, "group.byname",
322 &__ypcurrent, &__ypcurrentlen,
323 &data, &datalen);
324 }
325 if (r) {
326 __ypmode = 0;
327 __ypcurrent = NULL((void *)0);
328 if (r == YPERR_NOMORE8)
329 continue;
330 else
331 return 0;
332 }
333 bcopy(data, line, datalen);
334 free(data);
335 line[datalen] = '\0';
336 bp = line;
337 goto parse;
338 }
339#endif
340 if (!fgets(line, sizeof(gs->line), _gr_fp)) {
341 if (feof(_gr_fp)(!__isthreaded ? (((_gr_fp)->_flags & 0x0020) != 0) : (
feof)(_gr_fp))
&& !ferror(_gr_fp)(!__isthreaded ? (((_gr_fp)->_flags & 0x0040) != 0) : (
ferror)(_gr_fp))
)
342 errno(*__errno()) = saved_errno;
343 return 0;
344 }
345 bp = line;
346 /* skip lines that are too big */
347 if (!strchr(line, '\n')) {
348 int ch;
349
350 while ((ch = getc_unlocked(_gr_fp)(--(_gr_fp)->_r < 0 ? __srget(_gr_fp) : (int)(*(_gr_fp)
->_p++))
) != '\n' &&
351 ch != EOF(-1))
352 ;
353 continue;
354 }
355#ifdef YP1
356 if (line[0] == '+' || line[0] == '-') {
357 if (__ypdomain == NULL((void *)0) &&
358 yp_get_default_domain(&__ypdomain))
359 goto parse;
360 switch (yp_bind(__ypdomain)) {
361 case 0:
362 break;
363 case YPERR_BADARGS1:
364 case YPERR_YPBIND10:
365 goto parse;
366 default:
367 return 0;
368 }
369 }
370 if (line[0] == '+') {
371 switch (line[1]) {
372 case ':':
373 case '\0':
374 case '\n':
375 if (foundyp) {
376 *foundyp = 1;
377 errno(*__errno()) = saved_errno;
378 return 0;
379 }
380 if (!search) {
381 __ypmode = 1;
382 continue;
383 }
384 if (name) {
385 r = yp_match(__ypdomain,
386 "group.byname", name, strlen(name),
387 &data, &datalen);
388 } else {
389 char buf[20];
390 snprintf(buf, sizeof buf, "%u", gid);
391 r = yp_match(__ypdomain, "group.bygid",
392 buf, strlen(buf), &data, &datalen);
393 }
394 switch (r) {
395 case 0:
396 break;
397 case YPERR_KEY5:
398 continue;
399 default:
400 return 0;
401 }
402 bcopy(data, line, datalen);
403 free(data);
404 line[datalen] = '\0';
405 bp = line;
406 p_gr->gr_name = strsep(&bp, ":\n");
407 if (__ypexclude_is(&__ypexhead, p_gr->gr_name))
408 continue;
409 p_gr->gr_passwd = strsep(&bp, ":\n");
410 if (!(cp = strsep(&bp, ":\n")))
411 continue;
412 if (name) {
413 ul = strtoul(cp, &endp, 10);
414 if (*endp != '\0' || endp == cp ||
415 ul >= GID_MAX(2147483647 *2U +1U))
416 continue;
417 p_gr->gr_gid = ul;
418 } else
419 p_gr->gr_gid = gid;
420 goto found_it;
421 default:
422 bp = strsep(&bp, ":\n") + 1;
423 if ((search && name && strcmp(bp, name)) ||
424 __ypexclude_is(&__ypexhead, bp))
425 continue;
426 r = yp_match(__ypdomain, "group.byname",
427 bp, strlen(bp), &data, &datalen);
428 switch (r) {
429 case 0:
430 break;
431 case YPERR_KEY5:
432 continue;
433 default:
434 return 0;
435 }
436 bcopy(data, line, datalen);
437 free(data);
438 line[datalen] = '\0';
439 bp = line;
440 }
441 } else if (line[0] == '-') {
442 if (__ypexclude_add(&__ypexhead,
443 strsep(&line, ":\n") + 1))
444 return 0;
445 if (foundyp) {
446 *foundyp = -1;
447 errno(*__errno()) = saved_errno;
448 return 0;
449 }
450 continue;
451 }
452parse:
453#endif
454 p_gr->gr_name = strsep(&bp, ":\n");
455 if (search && name && strcmp(p_gr->gr_name, name))
456 continue;
457#ifdef YP1
458 if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name))
459 continue;
460#endif
461 p_gr->gr_passwd = strsep(&bp, ":\n");
462 if (!(cp = strsep(&bp, ":\n")))
463 continue;
464 ul = strtoul(cp, &endp, 10);
465 if (endp == cp || *endp != '\0' || ul >= GID_MAX(2147483647 *2U +1U))
466 continue;
467 p_gr->gr_gid = ul;
468 if (search && name == NULL((void *)0) && p_gr->gr_gid != gid)
469 continue;
470#ifdef YP1
471 found_it:
472#endif
473 cp = NULL((void *)0);
474 if (bp == NULL((void *)0))
475 continue;
476 for (m = p_gr->gr_mem = members;; bp++) {
477 if (m == &members[MAXGRP200 - 1])
478 break;
479 if (*bp == ',') {
480 if (cp) {
481 *bp = '\0';
482 *m++ = cp;
483 cp = NULL((void *)0);
484 }
485 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
486 if (cp) {
487 *bp = '\0';
488 *m++ = cp;
489 }
490 break;
491 } else if (cp == NULL((void *)0))
492 cp = bp;
493 }
494 *m = NULL((void *)0);
495 errno(*__errno()) = saved_errno;
496 return 1;
497 }
498 /* NOTREACHED */
499}