GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/getgrent.c Lines: 0 216 0.0 %
Date: 2017-11-13 Branches: 0 182 0.0 %

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
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
107
	if (!start_gr())
108
		rval = 0;
109
	else {
110
		rval = grscan(1, 0, name, p_gr, gs, NULL);
111
		if (!_gr_stayopen)
112
			endgrent_basic();
113
	}
114
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
115
	return(rval ? p_gr : NULL);
116
}
117
118
struct group *
119
getgrnam(const char *name)
120
{
121
	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
122
	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
123
	    gr_storage, NULL);
124
125
	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
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
154
	if (!start_gr())
155
		rval = 0;
156
	else {
157
		rval = grscan(1, gid, NULL, p_gr, gs, NULL);
158
		if (!_gr_stayopen)
159
			endgrent_basic();
160
	}
161
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
162
	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
	if (bufsize < GETGR_R_SIZE_MAX)
183
		return ERANGE;
184
	errnosave = errno;
185
	errno = 0;
186
	*result = getgrgid_gs(gid, grp, (struct group_storage *)buffer);
187
	if (*result == NULL)
188
		ret = errno;
189
	else
190
		ret = 0;
191
	errno = errnosave;
192
	return ret;
193
}
194
DEF_WEAK(getgrgid_r);
195
196
static int
197
start_gr(void)
198
{
199
	if (_gr_fp) {
200
		rewind(_gr_fp);
201
#ifdef YP
202
		__ypmode = 0;
203
		free(__ypcurrent);
204
		__ypcurrent = NULL;
205
		if (__ypexhead)
206
			__ypexclude_free(&__ypexhead);
207
		__ypexhead = NULL;
208
#endif
209
		return(1);
210
	}
211
212
#ifdef YP
213
	/*
214
	 * Hint to the kernel that a passwd database operation is happening.
215
	 */
216
	(void)access("/var/run/ypbind.lock", R_OK);
217
#endif
218
219
	return((_gr_fp = fopen(_PATH_GROUP, "re")) ? 1 : 0);
220
}
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
	_THREAD_PRIVATE_MUTEX_LOCK(gr);
239
	if (!start_gr())
240
		retval = 0;
241
	else {
242
		_gr_stayopen = stayopen;
243
		retval = 1;
244
	}
245
	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
246
	return (retval);
247
}
248
DEF_WEAK(setgroupent);
249
250
static
251
void
252
endgrent_basic(void)
253
{
254
	int saved_errno;
255
256
	if (_gr_fp) {
257
		saved_errno = errno;
258
		fclose(_gr_fp);
259
		_gr_fp = NULL;
260
#ifdef YP
261
		__ypmode = 0;
262
		free(__ypcurrent);
263
		__ypcurrent = NULL;
264
		if (__ypexhead)
265
			__ypexclude_free(&__ypexhead);
266
		__ypexhead = NULL;
267
#endif
268
		errno = saved_errno;
269
	}
270
}
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
	char *bp, *endp;
287
	u_long ul;
288
#ifdef YP
289
	char *key, *data;
290
	int keylen, datalen;
291
	int r;
292
#endif
293
	char **members;
294
	char *line;
295
	int saved_errno;
296
297
	if (gs == NULL)
298
		return 0;
299
	members = gs->members;
300
	line = gs->line;
301
	saved_errno = errno;
302
303
	for (;;) {
304
#ifdef YP
305
		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
		if (!fgets(line, sizeof(gs->line), _gr_fp)) {
334
			if (feof(_gr_fp) && !ferror(_gr_fp))
335
				errno = saved_errno;
336
			return 0;
337
		}
338
		bp = line;
339
		/* skip lines that are too big */
340
		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
		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
		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
		} 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
		p_gr->gr_name = strsep(&bp, ":\n");
448
		if (search && name && strcmp(p_gr->gr_name, name))
449
			continue;
450
#ifdef YP
451
		if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name))
452
			continue;
453
#endif
454
		p_gr->gr_passwd = strsep(&bp, ":\n");
455
		if (!(cp = strsep(&bp, ":\n")))
456
			continue;
457
		ul = strtoul(cp, &endp, 10);
458
		if (endp == cp || *endp != '\0' || ul >= GID_MAX)
459
			continue;
460
		p_gr->gr_gid = ul;
461
		if (search && name == NULL && p_gr->gr_gid != gid)
462
			continue;
463
#ifdef YP
464
	found_it:
465
#endif
466
		cp = NULL;
467
		if (bp == NULL)
468
			continue;
469
		for (m = p_gr->gr_mem = members;; bp++) {
470
			if (m == &members[MAXGRP - 1])
471
				break;
472
			if (*bp == ',') {
473
				if (cp) {
474
					*bp = '\0';
475
					*m++ = cp;
476
					cp = NULL;
477
				}
478
			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
479
				if (cp) {
480
					*bp = '\0';
481
					*m++ = cp;
482
				}
483
				break;
484
			} else if (cp == NULL)
485
				cp = bp;
486
		}
487
		*m = NULL;
488
		errno = saved_errno;
489
		return 1;
490
	}
491
	/* NOTREACHED */
492
}