GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/getgrent.c Lines: 96 208 46.2 %
Date: 2017-11-07 Branches: 58 182 31.9 %

Line Branch Exec Source
1
/*	$OpenBSD: getgrent.c,v 1.46 2015/12/01 15:08:25 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.h>
40
#ifdef YP
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);
51
static struct group_storage {
52
#define	MAXGRP		200
53
	char *members[MAXGRP];
54
#define	MAXLINELENGTH	1024
55
	char line[MAXLINELENGTH];
56
} gr_storage;
57
#define GETGR_R_SIZE_MAX	_GR_BUF_LEN
58
59
/* File pointers are locked with the 'gr' mutex */
60
_THREAD_PRIVATE_KEY(gr);
61
static FILE *_gr_fp;
62
static struct group _gr_group;
63
static int _gr_stayopen;
64
static int grscan(int, gid_t, const char *, struct group *, struct group_storage *,
65
	int *);
66
static int start_gr(void);
67
static void endgrent_basic(void);
68
69
static struct group *getgrnam_gs(const char *, struct group *,
70
	struct group_storage *);
71
static struct group *getgrgid_gs(gid_t, struct group *,
72
	struct group_storage *);
73
74
#ifdef YP
75
static struct _ypexclude *__ypexhead = NULL;
76
static int	__ypmode = 0;
77
static char	*__ypcurrent, *__ypdomain;
78
static int	__ypcurrentlen;
79
#endif
80
81
struct group *
82
_getgrent_yp(int *foundyp)
83
{
84
	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL);
85
	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
86
	    gr_storage, NULL);
87
88
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
89
	if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr, gs, foundyp))
90
		p_gr = NULL;
91
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
92
	return (p_gr);
93
}
94
95
struct group *
96
getgrent(void)
97
{
98
	return (_getgrent_yp(NULL));
99
}
100
101
static struct group *
102
getgrnam_gs(const char *name, struct group *p_gr, struct group_storage *gs)
103
{
104
	int rval;
105
106
802
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
107
401
	if (!start_gr())
108
		rval = 0;
109
	else {
110
401
		rval = grscan(1, 0, name, p_gr, gs, NULL);
111
401
		if (!_gr_stayopen)
112
301
			endgrent_basic();
113
	}
114
401
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
115
401
	return(rval ? p_gr : NULL);
116
}
117
118
struct group *
119
getgrnam(const char *name)
120
{
121
1203
	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
122
802
	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
123
	    gr_storage, NULL);
124
125
401
	return getgrnam_gs(name, p_gr, gs);
126
}
127
128
int
129
getgrnam_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)
136
		return ERANGE;
137
	errnosave = errno;
138
	errno = 0;
139
	*result = getgrnam_gs(name, grp, (struct group_storage *)buffer);
140
	if (*result == NULL)
141
		ret = errno;
142
	else
143
		ret = 0;
144
	errno = errnosave;
145
	return ret;
146
}
147
148
static struct group *
149
getgrgid_gs(gid_t gid, struct group *p_gr, struct group_storage *gs)
150
{
151
	int rval;
152
153
1478
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
154
739
	if (!start_gr())
155
		rval = 0;
156
	else {
157
739
		rval = grscan(1, gid, NULL, p_gr, gs, NULL);
158
739
		if (!_gr_stayopen)
159
729
			endgrent_basic();
160
	}
161
739
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
162
739
	return(rval ? p_gr : NULL);
163
}
164
165
struct group *
166
getgrgid(gid_t gid)
167
{
168
	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL);
169
	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
170
	    gr_storage, NULL);
171
172
	return getgrgid_gs(gid, p_gr, gs);
173
}
174
175
int
176
getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
177
	struct group **result)
178
{
179
	int errnosave;
180
	int ret;
181
182
1478
	if (bufsize < GETGR_R_SIZE_MAX)
183
		return ERANGE;
184
739
	errnosave = errno;
185
739
	errno = 0;
186
739
	*result = getgrgid_gs(gid, grp, (struct group_storage *)buffer);
187
739
	if (*result == NULL)
188
		ret = errno;
189
	else
190
		ret = 0;
191
739
	errno = errnosave;
192
739
	return ret;
193
739
}
194
DEF_WEAK(getgrgid_r);
195
196
static int
197
start_gr(void)
198
{
199
2480
	if (_gr_fp) {
200
110
		rewind(_gr_fp);
201
#ifdef YP
202
110
		__ypmode = 0;
203
110
		free(__ypcurrent);
204
110
		__ypcurrent = NULL;
205
110
		if (__ypexhead)
206
			__ypexclude_free(&__ypexhead);
207
110
		__ypexhead = NULL;
208
#endif
209
110
		return(1);
210
	}
211
212
#ifdef YP
213
	/*
214
	 * Hint to the kernel that a passwd database operation is happening.
215
	 */
216
1130
	(void)access("/var/run/ypbind.lock", R_OK);
217
#endif
218
219
1130
	return((_gr_fp = fopen(_PATH_GROUP, "re")) ? 1 : 0);
220
1240
}
221
222
void
223
setgrent(void)
224
{
225
	int saved_errno;
226
227
	saved_errno = errno;
228
	setgroupent(0);
229
	errno = saved_errno;
230
}
231
DEF_WEAK(setgrent);
232
233
int
234
setgroupent(int stayopen)
235
{
236
	int retval;
237
238
200
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
239
100
	if (!start_gr())
240
		retval = 0;
241
	else {
242
100
		_gr_stayopen = stayopen;
243
		retval = 1;
244
	}
245
100
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
246
100
	return (retval);
247
}
248
DEF_WEAK(setgroupent);
249
250
static
251
void
252
endgrent_basic(void)
253
{
254
	int saved_errno;
255
256
2060
	if (_gr_fp) {
257
1030
		saved_errno = errno;
258
1030
		fclose(_gr_fp);
259
1030
		_gr_fp = NULL;
260
#ifdef YP
261
1030
		__ypmode = 0;
262
1030
		free(__ypcurrent);
263
1030
		__ypcurrent = NULL;
264
1030
		if (__ypexhead)
265
			__ypexclude_free(&__ypexhead);
266
1030
		__ypexhead = NULL;
267
#endif
268
1030
		errno = saved_errno;
269
1030
	}
270
1030
}
271
272
void
273
endgrent(void)
274
{
275
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
276
	endgrent_basic();
277
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
278
}
279
DEF_WEAK(endgrent);
280
281
static int
282
grscan(int search, gid_t gid, const char *name, struct group *p_gr,
283
    struct group_storage *gs, int *foundyp)
284
{
285
	char *cp, **m;
286
2280
	char *bp, *endp;
287
	u_long ul;
288
#ifdef YP
289
1140
	char *key, *data;
290
1140
	int keylen, datalen;
291
	int r;
292
#endif
293
	char **members;
294
1140
	char *line;
295
	int saved_errno;
296
297
1140
	if (gs == NULL)
298
		return 0;
299
1140
	members = gs->members;
300
1140
	line = gs->line;
301
1140
	saved_errno = errno;
302
303
1140
	for (;;) {
304
#ifdef YP
305
20281
		if (__ypmode) {
306
			if (__ypcurrent) {
307
				r = yp_next(__ypdomain, "group.byname",
308
				    __ypcurrent, __ypcurrentlen,
309
				    &key, &keylen, &data, &datalen);
310
				free(__ypcurrent);
311
				__ypcurrent = key;
312
				__ypcurrentlen = keylen;
313
			} else {
314
				r = yp_first(__ypdomain, "group.byname",
315
				    &__ypcurrent, &__ypcurrentlen,
316
				    &data, &datalen);
317
			}
318
			if (r) {
319
				__ypmode = 0;
320
				__ypcurrent = NULL;
321
				if (r == YPERR_NOMORE)
322
					continue;
323
				else
324
					return 0;
325
			}
326
			bcopy(data, line, datalen);
327
			free(data);
328
			line[datalen] = '\0';
329
			bp = line;
330
			goto parse;
331
		}
332
#endif
333
20281
		if (!fgets(line, sizeof(gs->line), _gr_fp)) {
334



160
			if (feof(_gr_fp) && !ferror(_gr_fp))
335
40
				errno = saved_errno;
336
40
			return 0;
337
		}
338
20241
		bp = line;
339
		/* skip lines that are too big */
340
20241
		if (!strchr(line, '\n')) {
341
			int ch;
342
343
			while ((ch = getc_unlocked(_gr_fp)) != '\n' &&
344
			    ch != EOF)
345
				;
346
			continue;
347
		}
348
#ifdef YP
349

40482
		if (line[0] == '+' || line[0] == '-') {
350
			if (__ypdomain == NULL &&
351
			    yp_get_default_domain(&__ypdomain))
352
				goto parse;
353
			switch (yp_bind(__ypdomain)) {
354
			case 0:
355
				break;
356
			case YPERR_BADARGS:
357
			case YPERR_YPBIND:
358
				goto parse;
359
			default:
360
				return 0;
361
			}
362
		}
363
20241
		if (line[0] == '+') {
364
			switch (line[1]) {
365
			case ':':
366
			case '\0':
367
			case '\n':
368
				if (foundyp) {
369
					*foundyp = 1;
370
					errno = saved_errno;
371
					return 0;
372
				}
373
				if (!search) {
374
					__ypmode = 1;
375
					continue;
376
				}
377
				if (name) {
378
					r = yp_match(__ypdomain,
379
					    "group.byname", name, strlen(name),
380
					    &data, &datalen);
381
				} else {
382
					char buf[20];
383
					snprintf(buf, sizeof buf, "%u", gid);
384
					r = yp_match(__ypdomain, "group.bygid",
385
					    buf, strlen(buf), &data, &datalen);
386
				}
387
				switch (r) {
388
				case 0:
389
					break;
390
				case YPERR_KEY:
391
					continue;
392
				default:
393
					return 0;
394
				}
395
				bcopy(data, line, datalen);
396
				free(data);
397
				line[datalen] = '\0';
398
				bp = line;
399
				p_gr->gr_name = strsep(&bp, ":\n");
400
				if (__ypexclude_is(&__ypexhead, p_gr->gr_name))
401
					continue;
402
				p_gr->gr_passwd = strsep(&bp, ":\n");
403
				if (!(cp = strsep(&bp, ":\n")))
404
					continue;
405
				if (name) {
406
					ul = strtoul(cp, &endp, 10);
407
					if (*endp != '\0' || endp == cp ||
408
					    ul >= GID_MAX)
409
						continue;
410
					p_gr->gr_gid = ul;
411
				} else
412
					p_gr->gr_gid = gid;
413
				goto found_it;
414
			default:
415
				bp = strsep(&bp, ":\n") + 1;
416
				if ((search && name && strcmp(bp, name)) ||
417
				    __ypexclude_is(&__ypexhead, bp))
418
					continue;
419
				r = yp_match(__ypdomain, "group.byname",
420
				    bp, strlen(bp), &data, &datalen);
421
				switch (r) {
422
				case 0:
423
					break;
424
				case YPERR_KEY:
425
					continue;
426
				default:
427
					return 0;
428
				}
429
				bcopy(data, line, datalen);
430
				free(data);
431
				line[datalen] = '\0';
432
				bp = line;
433
			}
434
20241
		} else if (line[0] == '-') {
435
			if (__ypexclude_add(&__ypexhead,
436
			    strsep(&line, ":\n") + 1))
437
				return 0;
438
			if (foundyp) {
439
				*foundyp = -1;
440
				errno = saved_errno;
441
				return 0;
442
			}
443
			continue;
444
		}
445
parse:
446
#endif
447
20241
		p_gr->gr_name = strsep(&bp, ":\n");
448

30134
		if (search && name && strcmp(p_gr->gr_name, name))
449
			continue;
450
#ifdef YP
451

10709
		if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name))
452
			continue;
453
#endif
454
10709
		p_gr->gr_passwd = strsep(&bp, ":\n");
455
10709
		if (!(cp = strsep(&bp, ":\n")))
456
			continue;
457
10709
		ul = strtoul(cp, &endp, 10);
458

21418
		if (endp == cp || *endp != '\0' || ul >= GID_MAX)
459
			continue;
460
10709
		p_gr->gr_gid = ul;
461

21057
		if (search && name == NULL && p_gr->gr_gid != gid)
462
			continue;
463
#ifdef YP
464
	found_it:
465
#endif
466
		cp = NULL;
467
1100
		if (bp == NULL)
468
			continue;
469
3160
		for (m = p_gr->gr_mem = members;; bp++) {
470
3160
			if (m == &members[MAXGRP - 1])
471
				break;
472
3160
			if (*bp == ',') {
473
				if (cp) {
474
					*bp = '\0';
475
					*m++ = cp;
476
					cp = NULL;
477
				}
478

8380
			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
479
1100
				if (cp) {
480
515
					*bp = '\0';
481
515
					*m++ = cp;
482
515
				}
483
				break;
484
2060
			} else if (cp == NULL)
485
515
				cp = bp;
486
		}
487
1100
		*m = NULL;
488
1100
		errno = saved_errno;
489
1100
		return 1;
490
	}
491
	/* NOTREACHED */
492
1140
}