1 /*
2  * Copyright (C) 2003     Manuel Novoa III <mjn3@uclibc.org>
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7 
8 /*  Nov 6, 2003  Initial version.
9  *
10  *  NOTE: This implementation is quite strict about requiring all
11  *    field seperators.  It also does not allow leading whitespace
12  *    except when processing the numeric fields.  glibc is more
13  *    lenient.  See the various glibc difference comments below.
14  *
15  *  TODO:
16  *    Move to dynamic allocation of (currently statically allocated)
17  *      buffers; especially for the group-related functions since
18  *      large group member lists will cause error returns.
19  *
20  */
21 
22 #include <features.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <pwd.h>
32 #include <grp.h>
33 #include <paths.h>
34 #ifdef __UCLIBC_HAS_SHADOW__
35 # include <shadow.h>
36 #endif
37 #include <bits/uClibc_mutex.h>
38 
39 /**********************************************************************/
40 /* Prototypes for internal functions. */
41 
42 extern int __parsepwent(void *pw, char *line) attribute_hidden;
43 extern int __parsegrent(void *gr, char *line) attribute_hidden;
44 extern int __parsespent(void *sp, char *line) attribute_hidden;
45 
46 extern int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
47 			   char *__restrict line_buff, size_t buflen, FILE *f) attribute_hidden;
48 
49 extern gid_t* __getgrouplist_internal(const char *user, gid_t gid, int *ngroups) attribute_hidden;
50 
51 /**********************************************************************/
52 /* For the various fget??ent_r funcs, return
53  *
54  *  0: success
55  *  ENOENT: end-of-file encountered
56  *  ERANGE: buflen too small
57  *  other error values possible. See __pgsreader.
58  *
59  * Also, *result == resultbuf on success and NULL on failure.
60  *
61  * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
62  *   We do not, as it really isn't an error if we reach the end-of-file.
63  *   Doing so is analogous to having fgetc() set errno on EOF.
64  */
65 /**********************************************************************/
66 #ifdef L_fgetpwent_r
67 
68 #ifdef __USE_SVID
fgetpwent_r(FILE * __restrict stream,struct passwd * __restrict resultbuf,char * __restrict buffer,size_t buflen,struct passwd ** __restrict result)69 int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
70 				char *__restrict buffer, size_t buflen,
71 				struct passwd **__restrict result)
72 {
73 	int rv;
74 
75 	*result = NULL;
76 
77 	if (!(rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, stream))) {
78 		*result = resultbuf;
79 	}
80 
81 	return rv;
82 }
libc_hidden_def(fgetpwent_r)83 libc_hidden_def(fgetpwent_r)
84 #endif
85 
86 #endif
87 /**********************************************************************/
88 #ifdef L_fgetgrent_r
89 
90 #ifdef __USE_SVID
91 int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
92 				char *__restrict buffer, size_t buflen,
93 				struct group **__restrict result)
94 {
95 	int rv;
96 
97 	*result = NULL;
98 
99 	if (!(rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, stream))) {
100 		*result = resultbuf;
101 	}
102 
103 	return rv;
104 }
libc_hidden_def(fgetgrent_r)105 libc_hidden_def(fgetgrent_r)
106 #endif
107 
108 #endif
109 /**********************************************************************/
110 #ifdef L_fgetspent_r
111 
112 int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
113 				char *__restrict buffer, size_t buflen,
114 				struct spwd **__restrict result)
115 {
116 	int rv;
117 
118 	*result = NULL;
119 
120 	if (!(rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, stream))) {
121 		*result = resultbuf;
122 	}
123 
124 	return rv;
125 }
libc_hidden_def(fgetspent_r)126 libc_hidden_def(fgetspent_r)
127 
128 #endif
129 /**********************************************************************/
130 /* For the various fget??ent funcs, return NULL on failure and a
131  * pointer to the appropriate struct (statically allocated) on success.
132  */
133 /**********************************************************************/
134 #ifdef L_fgetpwent
135 
136 #ifdef __USE_SVID
137 
138 struct passwd *fgetpwent(FILE *stream)
139 {
140 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
141 	static struct passwd resultbuf;
142 	struct passwd *result;
143 
144 	fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
145 	return result;
146 }
147 #endif
148 
149 #endif
150 /**********************************************************************/
151 #ifdef L_fgetgrent
152 
153 #ifdef __USE_SVID
154 
fgetgrent(FILE * stream)155 struct group *fgetgrent(FILE *stream)
156 {
157 	static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
158 	static struct group resultbuf;
159 	struct group *result;
160 
161 	fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
162 	return result;
163 }
164 #endif
165 
166 #endif
167 /**********************************************************************/
168 #ifdef L_fgetspent
169 
170 
fgetspent(FILE * stream)171 struct spwd *fgetspent(FILE *stream)
172 {
173 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
174 	static struct spwd resultbuf;
175 	struct spwd *result;
176 
177 	fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
178 	return result;
179 }
180 
181 #endif
182 /**********************************************************************/
183 #ifdef L_sgetspent_r
184 
sgetspent_r(const char * string,struct spwd * result_buf,char * buffer,size_t buflen,struct spwd ** result)185 int sgetspent_r(const char *string, struct spwd *result_buf,
186 				char *buffer, size_t buflen, struct spwd **result)
187 {
188 	int rv = ERANGE;
189 
190 	*result = NULL;
191 
192 	if (buflen < __UCLIBC_PWD_BUFFER_SIZE__) {
193 	DO_ERANGE:
194 		__set_errno(rv);
195 		goto DONE;
196 	}
197 
198 	if (string != buffer) {
199 		if (strlen(string) >= buflen) {
200 			goto DO_ERANGE;
201 		}
202 		strcpy(buffer, string);
203 	}
204 
205 	if (!(rv = __parsespent(result_buf, buffer))) {
206 		*result = result_buf;
207 	}
208 
209  DONE:
210 	return rv;
211 }
libc_hidden_def(sgetspent_r)212 libc_hidden_def(sgetspent_r)
213 
214 #endif
215 /**********************************************************************/
216 
217 #ifdef GETXXKEY_R_FUNC
218 #error GETXXKEY_R_FUNC is already defined!
219 #endif
220 
221 #ifdef L_getpwnam_r
222 #define GETXXKEY_R_FUNC		getpwnam_r
223 #define GETXXKEY_R_PARSER	__parsepwent
224 #define GETXXKEY_R_ENTTYPE	struct passwd
225 #define GETXXKEY_R_TEST(ENT)	(!strcmp((ENT)->pw_name, key))
226 #define DO_GETXXKEY_R_KEYTYPE	const char *__restrict
227 #define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
228 #include "pwd_grp_internal.c"
229 #endif
230 
231 #ifdef L_getgrnam_r
232 #define GETXXKEY_R_FUNC		getgrnam_r
233 #define GETXXKEY_R_PARSER	__parsegrent
234 #define GETXXKEY_R_ENTTYPE	struct group
235 #define GETXXKEY_R_TEST(ENT)	(!strcmp((ENT)->gr_name, key))
236 #define DO_GETXXKEY_R_KEYTYPE	const char *__restrict
237 #define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
238 #include "pwd_grp_internal.c"
239 #endif
240 
241 #ifdef L_getspnam_r
242 #define GETXXKEY_R_FUNC		getspnam_r
243 #define GETXXKEY_R_PARSER	__parsespent
244 #define GETXXKEY_R_ENTTYPE	struct spwd
245 #define GETXXKEY_R_TEST(ENT)	(!strcmp((ENT)->sp_namp, key))
246 #define DO_GETXXKEY_R_KEYTYPE	const char *__restrict
247 #define DO_GETXXKEY_R_PATHNAME  _PATH_SHADOW
248 #include "pwd_grp_internal.c"
249 #endif
250 
251 #ifdef L_getpwuid_r
252 #define GETXXKEY_R_FUNC		getpwuid_r
253 #define GETXXKEY_R_PARSER	__parsepwent
254 #define GETXXKEY_R_ENTTYPE	struct passwd
255 #define GETXXKEY_R_TEST(ENT)	((ENT)->pw_uid == key)
256 #define DO_GETXXKEY_R_KEYTYPE	uid_t
257 #define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
258 #include "pwd_grp_internal.c"
259 #endif
260 
261 #ifdef L_getgrgid_r
262 #define GETXXKEY_R_FUNC		getgrgid_r
263 #define GETXXKEY_R_PARSER	__parsegrent
264 #define GETXXKEY_R_ENTTYPE	struct group
265 #define GETXXKEY_R_TEST(ENT)	((ENT)->gr_gid == key)
266 #define DO_GETXXKEY_R_KEYTYPE	gid_t
267 #define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
268 #include "pwd_grp_internal.c"
269 #endif
270 
271 /**********************************************************************/
272 #ifdef L_getpwuid
273 
274 
275 struct passwd *getpwuid(uid_t uid)
276 {
277 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
278 	static struct passwd resultbuf;
279 	struct passwd *result;
280 
281 	getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
282 	return result;
283 }
284 
285 #endif
286 /**********************************************************************/
287 #ifdef L_getgrgid
288 
289 
getgrgid(gid_t gid)290 struct group *getgrgid(gid_t gid)
291 {
292 	static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
293 	static struct group resultbuf;
294 	struct group *result;
295 
296 	getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
297 	return result;
298 }
299 
300 #endif
301 /**********************************************************************/
302 #ifdef L_getspuid_r
303 
304 /* This function is non-standard and is currently not built.  It seems
305  * to have been created as a reentrant version of the non-standard
306  * functions getspuid.  Why getspuid was added, I do not know. */
307 
308 
getspuid_r(uid_t uid,struct spwd * __restrict resultbuf,char * __restrict buffer,size_t buflen,struct spwd ** __restrict result)309 int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
310 		       char *__restrict buffer, size_t buflen,
311 		       struct spwd **__restrict result)
312 {
313 	int rv;
314 	struct passwd *pp;
315 	struct passwd password;
316 	char pwd_buff[__UCLIBC_PWD_BUFFER_SIZE__];
317 
318 	*result = NULL;
319 	if (!(rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp))) {
320 		rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
321 	}
322 
323 	return rv;
324 }
325 
326 #endif
327 /**********************************************************************/
328 #ifdef L_getspuid
329 
330 /* This function is non-standard and is currently not built.
331  * Why it was added, I do not know. */
332 
getspuid(uid_t uid)333 struct spwd *getspuid(uid_t uid)
334 {
335 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
336 	static struct spwd resultbuf;
337 	struct spwd *result;
338 
339 	getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
340 	return result;
341 }
342 
343 #endif
344 /**********************************************************************/
345 #ifdef L_getpwnam
346 
347 
getpwnam(const char * name)348 struct passwd *getpwnam(const char *name)
349 {
350 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
351 	static struct passwd resultbuf;
352 	struct passwd *result;
353 
354 	getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
355 	return result;
356 }
libc_hidden_def(getpwnam)357 libc_hidden_def(getpwnam)
358 
359 #endif
360 /**********************************************************************/
361 #ifdef L_getgrnam
362 
363 
364 struct group *getgrnam(const char *name)
365 {
366 	static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
367 	static struct group resultbuf;
368 	struct group *result;
369 
370 	getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
371 	return result;
372 }
373 
374 #endif
375 /**********************************************************************/
376 #ifdef L_getspnam
377 
378 
getspnam(const char * name)379 struct spwd *getspnam(const char *name)
380 {
381 	static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
382 	static struct spwd resultbuf;
383 	struct spwd *result;
384 
385 	getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
386 	return result;
387 }
388 
389 #endif
390 /**********************************************************************/
391 #ifdef L_getpw
392 
393 
getpw(uid_t uid,char * buf)394 int getpw(uid_t uid, char *buf)
395 {
396 	struct passwd resultbuf;
397 	struct passwd *result;
398 	char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
399 
400 	if (!buf) {
401 		__set_errno(EINVAL);
402 	} else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
403 		if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
404 					resultbuf.pw_name, resultbuf.pw_passwd,
405 					(unsigned long)(resultbuf.pw_uid),
406 					(unsigned long)(resultbuf.pw_gid),
407 					resultbuf.pw_gecos, resultbuf.pw_dir,
408 					resultbuf.pw_shell) >= 0
409 			) {
410 			return 0;
411 		}
412 	}
413 
414 	return -1;
415 }
416 
417 #endif
418 /**********************************************************************/
419 
420 #ifdef L_getpwent_r
421 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
422 
423 static FILE *pwf /*= NULL*/;
424 
setpwent(void)425 void setpwent(void)
426 {
427 	__UCLIBC_MUTEX_LOCK(mylock);
428 	if (pwf) {
429 		rewind(pwf);
430 	}
431 	__UCLIBC_MUTEX_UNLOCK(mylock);
432 }
433 
endpwent(void)434 void endpwent(void)
435 {
436 	__UCLIBC_MUTEX_LOCK(mylock);
437 	if (pwf) {
438 		fclose(pwf);
439 		pwf = NULL;
440 	}
441 	__UCLIBC_MUTEX_UNLOCK(mylock);
442 }
443 
444 
getpwent_r(struct passwd * __restrict resultbuf,char * __restrict buffer,size_t buflen,struct passwd ** __restrict result)445 int getpwent_r(struct passwd *__restrict resultbuf,
446 			   char *__restrict buffer, size_t buflen,
447 			   struct passwd **__restrict result)
448 {
449 	int rv;
450 
451 	__UCLIBC_MUTEX_LOCK(mylock);
452 
453 	*result = NULL;				/* In case of error... */
454 
455 	if (!pwf) {
456 		if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
457 			rv = errno;
458 			goto ERR;
459 		}
460 		__STDIO_SET_USER_LOCKING(pwf);
461 	}
462 
463 	if (!(rv = __pgsreader(__parsepwent, resultbuf,
464 						   buffer, buflen, pwf))) {
465 		*result = resultbuf;
466 	}
467 
468  ERR:
469 	__UCLIBC_MUTEX_UNLOCK(mylock);
470 
471 	return rv;
472 }
473 libc_hidden_def(getpwent_r)
474 
475 #endif
476 /**********************************************************************/
477 #ifdef L_getgrent_r
478 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
479 
480 static FILE *grf /*= NULL*/;
481 
setgrent(void)482 void setgrent(void)
483 {
484 	__UCLIBC_MUTEX_LOCK(mylock);
485 	if (grf) {
486 		rewind(grf);
487 	}
488 	__UCLIBC_MUTEX_UNLOCK(mylock);
489 }
490 
endgrent(void)491 void endgrent(void)
492 {
493 	__UCLIBC_MUTEX_LOCK(mylock);
494 	if (grf) {
495 		fclose(grf);
496 		grf = NULL;
497 	}
498 	__UCLIBC_MUTEX_UNLOCK(mylock);
499 }
500 
getgrent_r(struct group * __restrict resultbuf,char * __restrict buffer,size_t buflen,struct group ** __restrict result)501 int getgrent_r(struct group *__restrict resultbuf,
502 			   char *__restrict buffer, size_t buflen,
503 			   struct group **__restrict result)
504 {
505 	int rv;
506 
507 	__UCLIBC_MUTEX_LOCK(mylock);
508 
509 	*result = NULL;				/* In case of error... */
510 
511 	if (!grf) {
512 		if (!(grf = fopen(_PATH_GROUP, "r"))) {
513 			rv = errno;
514 			goto ERR;
515 		}
516 		__STDIO_SET_USER_LOCKING(grf);
517 	}
518 
519 	if (!(rv = __pgsreader(__parsegrent, resultbuf,
520 						   buffer, buflen, grf))) {
521 		*result = resultbuf;
522 	}
523 
524  ERR:
525 	__UCLIBC_MUTEX_UNLOCK(mylock);
526 
527 	return rv;
528 }
529 libc_hidden_def(getgrent_r)
530 
531 #endif
532 /**********************************************************************/
533 #ifdef L_getspent_r
534 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
535 
536 static FILE *spf /*= NULL*/;
537 
setspent(void)538 void setspent(void)
539 {
540 	__UCLIBC_MUTEX_LOCK(mylock);
541 	if (spf) {
542 		rewind(spf);
543 	}
544 	__UCLIBC_MUTEX_UNLOCK(mylock);
545 }
546 
endspent(void)547 void endspent(void)
548 {
549 	__UCLIBC_MUTEX_LOCK(mylock);
550 	if (spf) {
551 		fclose(spf);
552 		spf = NULL;
553 	}
554 	__UCLIBC_MUTEX_UNLOCK(mylock);
555 }
556 
getspent_r(struct spwd * resultbuf,char * buffer,size_t buflen,struct spwd ** result)557 int getspent_r(struct spwd *resultbuf, char *buffer,
558 			   size_t buflen, struct spwd **result)
559 {
560 	int rv;
561 
562 	__UCLIBC_MUTEX_LOCK(mylock);
563 
564 	*result = NULL;				/* In case of error... */
565 
566 	if (!spf) {
567 		if (!(spf = fopen(_PATH_SHADOW, "r"))) {
568 			rv = errno;
569 			goto ERR;
570 		}
571 		__STDIO_SET_USER_LOCKING(spf);
572 	}
573 
574 	if (!(rv = __pgsreader(__parsespent, resultbuf,
575 						   buffer, buflen, spf))) {
576 		*result = resultbuf;
577 	}
578 
579  ERR:
580 	__UCLIBC_MUTEX_UNLOCK(mylock);
581 
582 	return rv;
583 }
libc_hidden_def(getspent_r)584 libc_hidden_def(getspent_r)
585 
586 #endif
587 /**********************************************************************/
588 #ifdef L_getpwent
589 
590 
591 struct passwd *getpwent(void)
592 {
593 	static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
594 	static struct passwd pwd;
595 	struct passwd *result;
596 
597 	getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
598 	return result;
599 }
600 
601 #endif
602 /**********************************************************************/
603 #ifdef L_getgrent
604 
605 
getgrent(void)606 struct group *getgrent(void)
607 {
608 	static char line_buff[__UCLIBC_GRP_BUFFER_SIZE__];
609 	static struct group gr;
610 	struct group *result;
611 
612 	getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
613 	return result;
614 }
615 
616 #endif
617 /**********************************************************************/
618 #ifdef L_getspent
619 
620 
getspent(void)621 struct spwd *getspent(void)
622 {
623 	static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
624 	static struct spwd spwd;
625 	struct spwd *result;
626 
627 	getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
628 	return result;
629 }
630 
631 #endif
632 /**********************************************************************/
633 #ifdef L_sgetspent
634 
635 
sgetspent(const char * string)636 struct spwd *sgetspent(const char *string)
637 {
638 	static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
639 	static struct spwd spwd;
640 	struct spwd *result;
641 
642 	sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
643 	return result;
644 }
645 
646 #endif
647 /**********************************************************************/
648 #ifdef L___getgrouplist_internal
649 
__getgrouplist_internal(const char * user,gid_t gid,int * ngroups)650 gid_t attribute_hidden *__getgrouplist_internal(const char *user, gid_t gid, int *ngroups)
651 {
652 	FILE *grfile;
653 	gid_t *group_list;
654 	int num_groups;
655 	struct group group;
656 	char buff[__UCLIBC_PWD_BUFFER_SIZE__];
657 
658 	*ngroups = num_groups = 1;
659 
660 	/* We alloc space for 8 gids at a time. */
661 	group_list = malloc(8 * sizeof(group_list[0]));
662 	if (!group_list)
663 		return NULL;
664 
665 	group_list[0] = gid;
666 	grfile = fopen(_PATH_GROUP, "r");
667 	/* If /etc/group doesn't exist, we still return 1-element vector */
668 	if (!grfile)
669 		return group_list;
670 
671 	__STDIO_SET_USER_LOCKING(grfile);
672 
673 	while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) {
674 		char **m;
675 
676 		assert(group.gr_mem); /* Must have at least a NULL terminator. */
677 		if (group.gr_gid == gid)
678 			continue;
679 		for (m = group.gr_mem; *m; m++) {
680 			if (strcmp(*m, user) != 0)
681 				continue;
682 			if (!(num_groups & 7)) {
683 				gid_t *tmp = realloc(group_list, (num_groups+8) * sizeof(group_list[0]));
684 				if (!tmp)
685 					goto DO_CLOSE;
686 				group_list = tmp;
687 			}
688 			group_list[num_groups++] = group.gr_gid;
689 			break;
690 		}
691 	}
692 
693  DO_CLOSE:
694 	fclose(grfile);
695 	*ngroups = num_groups;
696 	return group_list;
697 }
698 
699 #endif
700 /**********************************************************************/
701 #ifdef L_getgrouplist
702 
703 #if defined __USE_BSD || defined __USE_GNU
getgrouplist(const char * user,gid_t gid,gid_t * groups,int * ngroups)704 int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
705 {
706 	int sz = *ngroups;
707 	gid_t *group_list = __getgrouplist_internal(user, gid, ngroups);
708 
709 	if (!group_list) {
710 		/* malloc failure - what shall we do?
711 		 * fail with ENOMEM? I bet users never check for that */
712 		/* *ngroups = 1; - already done by __getgrouplist_internal */
713 		if (sz) {
714 			groups[0] = gid;
715 			return 1;
716 		}
717 		return -1;
718 	}
719 	/* *ngroups is non-zero here */
720 
721 	if (sz > *ngroups)
722 		sz = *ngroups;
723 	if (sz)
724 		memcpy(groups, group_list, sz * sizeof(group_list[0]));
725 	free(group_list);
726 	if (sz < *ngroups)
727 		return -1;
728 	return sz;
729 }
730 #endif
731 
732 #endif
733 /**********************************************************************/
734 #ifdef L_initgroups
735 
736 #ifdef __USE_BSD
737 
initgroups(const char * user,gid_t gid)738 int initgroups(const char *user, gid_t gid)
739 {
740 	int rv;
741 	int num_groups = ((unsigned)~0) >> 1; /* INT_MAX */
742 	gid_t *group_list = __getgrouplist_internal(user, gid, &num_groups);
743 	if (!group_list)
744 		return -1;
745 	rv = setgroups(num_groups, group_list);
746 	free(group_list);
747 	return rv;
748 }
749 #endif
750 
751 #endif
752 /**********************************************************************/
753 #ifdef L_putpwent
754 
755 #ifdef __USE_SVID
putpwent(const struct passwd * __restrict p,FILE * __restrict f)756 int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
757 {
758 	int rv = -1;
759 
760 	if (!p || !f) {
761 		__set_errno(EINVAL);
762 	} else {
763 		/* No extra thread locking is needed above what fprintf does. */
764 		if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
765 					p->pw_name, p->pw_passwd,
766 					(unsigned long)(p->pw_uid),
767 					(unsigned long)(p->pw_gid),
768 					p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
769 			) {
770 			rv = 0;
771 		}
772 	}
773 
774 	return rv;
775 }
776 #endif
777 
778 #endif
779 /**********************************************************************/
780 #ifdef L_putgrent
781 
putgrent(const struct group * __restrict p,FILE * __restrict f)782 int putgrent(const struct group *__restrict p, FILE *__restrict f)
783 {
784 	static const char format[] = ",%s";
785 	char **m;
786 	const char *fmt;
787 	int rv = -1;
788 	__STDIO_AUTO_THREADLOCK_VAR;
789 
790 	if (!p || !f) {				/* Sigh... glibc checks. */
791 		__set_errno(EINVAL);
792 	} else {
793 		__STDIO_AUTO_THREADLOCK(f);
794 
795 		if (fprintf(f, "%s:%s:%lu:",
796 					p->gr_name, p->gr_passwd,
797 					(unsigned long)(p->gr_gid)) >= 0
798 			) {
799 
800 			fmt = format + 1;
801 
802 			assert(p->gr_mem);
803 			m = p->gr_mem;
804 
805 			do {
806 				if (!*m) {
807 					if (__fputc_unlocked('\n', f) >= 0) {
808 						rv = 0;
809 					}
810 					break;
811 				}
812 				if (fprintf(f, fmt, *m) < 0) {
813 					break;
814 				}
815 				++m;
816 				fmt = format;
817 			} while (1);
818 
819 		}
820 
821 		__STDIO_AUTO_THREADUNLOCK(f);
822 	}
823 
824 	return rv;
825 }
826 
827 #endif
828 /**********************************************************************/
829 #ifdef L_putspent
830 
831 static const unsigned char _sp_off[] = {
832 	offsetof(struct spwd, sp_lstchg),	/* 2 - not a char ptr */
833 	offsetof(struct spwd, sp_min),		/* 3 - not a char ptr */
834 	offsetof(struct spwd, sp_max),		/* 4 - not a char ptr */
835 	offsetof(struct spwd, sp_warn),		/* 5 - not a char ptr */
836 	offsetof(struct spwd, sp_inact),	/* 6 - not a char ptr */
837 	offsetof(struct spwd, sp_expire),	/* 7 - not a char ptr */
838 };
839 
putspent(const struct spwd * p,FILE * stream)840 int putspent(const struct spwd *p, FILE *stream)
841 {
842 	static const char ld_format[] = "%ld:";
843 	const char *f;
844 	long int x;
845 	size_t i;
846 	int rv = -1;
847 	__STDIO_AUTO_THREADLOCK_VAR;
848 
849 	/* Unlike putpwent and putgrent, glibc does not check the args. */
850 
851 	__STDIO_AUTO_THREADLOCK(stream);
852 
853 	if (fprintf(stream, "%s:%s:", p->sp_namp,
854 				(p->sp_pwdp ? p->sp_pwdp : "")) < 0
855 		) {
856 		goto DO_UNLOCK;
857 	}
858 
859 	for (i=0 ; i < sizeof(_sp_off) ; i++) {
860 		f = ld_format;
861 		if ((x = *(const long int *)(((const char *) p) + _sp_off[i])) == -1) {
862 			f += 3;
863 		}
864 		if (fprintf(stream, f, x) < 0) {
865 			goto DO_UNLOCK;
866 		}
867 	}
868 
869 	if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
870 		goto DO_UNLOCK;
871 	}
872 
873 	if (__fputc_unlocked('\n', stream) > 0) {
874 		rv = 0;
875 	}
876 
877  DO_UNLOCK:
878 	__STDIO_AUTO_THREADUNLOCK(stream);
879 
880 	return rv;
881 }
882 
883 #endif
884 /**********************************************************************/
885 /* Internal uClibc functions.                                         */
886 /**********************************************************************/
887 #ifdef L___parsepwent
888 
889 static const unsigned char pw_off[] = {
890 	offsetof(struct passwd, pw_name),	/* 0 */
891 	offsetof(struct passwd, pw_passwd),	/* 1 */
892 	offsetof(struct passwd, pw_uid),	/* 2 - not a char ptr */
893 	offsetof(struct passwd, pw_gid),	/* 3 - not a char ptr */
894 	offsetof(struct passwd, pw_gecos),	/* 4 */
895 	offsetof(struct passwd, pw_dir),	/* 5 */
896 	offsetof(struct passwd, pw_shell)	/* 6 */
897 };
898 
__parsepwent(void * data,char * line)899 int attribute_hidden __parsepwent(void *data, char *line)
900 {
901 	char *endptr;
902 	char *p;
903 	int i;
904 
905 	i = 0;
906 	do {
907 		p = ((char *) ((struct passwd *) data)) + pw_off[i];
908 
909 		if ((i & 6) ^ 2) {	/* i!=2 and i!=3 */
910 			*((char **) p) = line;
911 			if (i==6) {
912 				return 0;
913 			}
914 			/* NOTE: glibc difference - glibc allows omission of
915 			 * ':' seperators after the gid field if all remaining
916 			 * entries are empty.  We require all separators. */
917 			if (!(line = strchr(line, ':'))) {
918 				break;
919 			}
920 		} else {
921 			unsigned long t = strtoul(line, &endptr, 10);
922 			/* Make sure we had at least one digit, and that the
923 			 * failing char is the next field seperator ':'.  See
924 			 * glibc difference note above. */
925 			/* TODO: Also check for leading whitespace? */
926 			if ((endptr == line) || (*endptr != ':')) {
927 				break;
928 			}
929 			line = endptr;
930 			if (i & 1) {		/* i == 3 -- gid */
931 				*((gid_t *) p) = t;
932 			} else {			/* i == 2 -- uid */
933 				*((uid_t *) p) = t;
934 			}
935 		}
936 
937 		*line++ = 0;
938 		++i;
939 	} while (1);
940 
941 	return -1;
942 }
943 
944 #endif
945 /**********************************************************************/
946 #ifdef L___parsegrent
947 
948 static const unsigned char gr_off[] = {
949 	offsetof(struct group, gr_name),	/* 0 */
950 	offsetof(struct group, gr_passwd),	/* 1 */
951 	offsetof(struct group, gr_gid)		/* 2 - not a char ptr */
952 };
953 
__parsegrent(void * data,char * line)954 int attribute_hidden __parsegrent(void *data, char *line)
955 {
956 	char *endptr;
957 	char *p;
958 	int i;
959 	char **members;
960 	char *end_of_buf;
961 
962 	end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
963 	i = 0;
964 	do {
965 		p = ((char *) ((struct group *) data)) + gr_off[i];
966 
967 		if (i < 2) {
968 			*((char **) p) = line;
969 			if (!(line = strchr(line, ':'))) {
970 				break;
971 			}
972 			*line++ = 0;
973 			++i;
974 		} else {
975 			*((gid_t *) p) = strtoul(line, &endptr, 10);
976 
977 			/* NOTE: glibc difference - glibc allows omission of the
978 			 * trailing colon when there is no member list.  We treat
979 			 * this as an error. */
980 
981 			/* Make sure we had at least one digit, and that the
982 			 * failing char is the next field seperator ':'.  See
983 			 * glibc difference note above. */
984 			if ((endptr == line) || (*endptr != ':')) {
985 				break;
986 			}
987 
988 			i = 1;				/* Count terminating NULL ptr. */
989 			p = endptr;
990 
991 			if (p[1]) { /* We have a member list to process. */
992 				/* Overwrite the last ':' with a ',' before counting.
993 				 * This allows us to test for initial ',' and adds
994 				 * one ',' so that the ',' count equals the member
995 				 * count. */
996 				*p = ',';
997 				do {
998 					/* NOTE: glibc difference - glibc allows and trims leading
999 					 * (but not trailing) space.  We treat this as an error. */
1000 					/* NOTE: glibc difference - glibc allows consecutive and
1001 					 * trailing commas, and ignores "empty string" users.  We
1002 					 * treat this as an error. */
1003 					if (*p == ',') {
1004 						++i;
1005 						*p = 0;	/* nul-terminate each member string. */
1006 						if (!*++p || (*p == ',') || isspace(*p)) {
1007 							goto ERR;
1008 						}
1009 					}
1010 				} while (*++p);
1011 			}
1012 
1013 			/* Now align (p+1), rounding up. */
1014 			/* Assumes sizeof(char **) is a power of 2. */
1015 			members = (char **)( (((intptr_t) p) + sizeof(char **))
1016 								 & ~((intptr_t)(sizeof(char **) - 1)) );
1017 
1018 			if (((char *)(members + i)) > end_of_buf) {	/* No space. */
1019 				break;
1020 			}
1021 
1022 			((struct group *) data)->gr_mem = members;
1023 
1024 			if (--i) {
1025 				p = endptr;	/* Pointing to char prior to first member. */
1026 				do {
1027 					*members++ = ++p;
1028 					if (!--i) break;
1029 					while (*++p) {}
1030 				} while (1);
1031 			}
1032 			*members = NULL;
1033 
1034 			return 0;
1035 		}
1036 	} while (1);
1037 
1038  ERR:
1039 	return -1;
1040 }
1041 
1042 #endif
1043 /**********************************************************************/
1044 #ifdef L___parsespent
1045 
1046 static const unsigned char sp_off[] = {
1047 	offsetof(struct spwd, sp_namp),		/* 0 */
1048 	offsetof(struct spwd, sp_pwdp),		/* 1 */
1049 	offsetof(struct spwd, sp_lstchg),	/* 2 - not a char ptr */
1050 	offsetof(struct spwd, sp_min),		/* 3 - not a char ptr */
1051 	offsetof(struct spwd, sp_max),		/* 4 - not a char ptr */
1052 	offsetof(struct spwd, sp_warn),		/* 5 - not a char ptr */
1053 	offsetof(struct spwd, sp_inact),	/* 6 - not a char ptr */
1054 	offsetof(struct spwd, sp_expire),	/* 7 - not a char ptr */
1055 	offsetof(struct spwd, sp_flag)		/* 8 - not a char ptr */
1056 };
1057 
__parsespent(void * data,char * line)1058 int attribute_hidden __parsespent(void *data, char * line)
1059 {
1060 	char *endptr;
1061 	char *p;
1062 	int i;
1063 
1064 	i = 0;
1065 	do {
1066 		p = ((char *) ((struct spwd *) data)) + sp_off[i];
1067 		if (i < 2) {
1068 			*((char **) p) = line;
1069 			if (!(line = strchr(line, ':'))) {
1070 				break;
1071 			}
1072 		} else {
1073 #if 0
1074 			if (i==5) {			/* Support for old format. */
1075 				while (isspace(*line)) ++line; /* glibc eats space here. */
1076 				if (!*line) {
1077 					((struct spwd *) data)->sp_warn = -1;
1078 					((struct spwd *) data)->sp_inact = -1;
1079 					((struct spwd *) data)->sp_expire = -1;
1080 					((struct spwd *) data)->sp_flag = ~0UL;
1081 					return 0;
1082 				}
1083 			}
1084 #endif
1085 
1086 			*((long *) p) = (long) strtoul(line, &endptr, 10);
1087 
1088 			if (endptr == line) {
1089 				*((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
1090 			}
1091 
1092 			line = endptr;
1093 
1094 			if (i == 8) {
1095 				if (!*endptr) {
1096 					return 0;
1097 				}
1098 				break;
1099 			}
1100 
1101 			if (*endptr != ':') {
1102 				break;
1103 			}
1104 
1105 		}
1106 
1107 		*line++ = 0;
1108 		++i;
1109 	} while (1);
1110 
1111 	return EINVAL;
1112 }
1113 
1114 #endif
1115 /**********************************************************************/
1116 #ifdef L___pgsreader
1117 
1118 /* Reads until if EOF, or until if finds a line which fits in the buffer
1119  * and for which the parser function succeeds.
1120  *
1121  * Returns 0 on success and ENOENT for end-of-file (glibc concession).
1122  */
1123 
__pgsreader(int (* __parserfunc)(void * d,char * line),void * data,char * __restrict line_buff,size_t buflen,FILE * f)1124 int attribute_hidden __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
1125 				char *__restrict line_buff, size_t buflen, FILE *f)
1126 {
1127 	size_t line_len;
1128 	int skip;
1129 	int rv = ERANGE;
1130 	__STDIO_AUTO_THREADLOCK_VAR;
1131 
1132 	if (buflen < __UCLIBC_PWD_BUFFER_SIZE__) {
1133 		__set_errno(rv);
1134 	} else {
1135 		__STDIO_AUTO_THREADLOCK(f);
1136 
1137 		skip = 0;
1138 		do {
1139 			if (!fgets_unlocked(line_buff, buflen, f)) {
1140 				if (feof_unlocked(f)) {
1141 					rv = ENOENT;
1142 				}
1143 				break;
1144 			}
1145 
1146 			line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
1147 			if (line_buff[line_len] == '\n') {
1148 				line_buff[line_len] = 0;
1149 			} else if (line_len + 2 == buflen) { /* line too long */
1150 				++skip;
1151 				continue;
1152 			}
1153 
1154 			if (skip) {
1155 				--skip;
1156 				continue;
1157 			}
1158 
1159 			/* NOTE: glibc difference - glibc strips leading whitespace from
1160 			 * records.  We do not allow leading whitespace. */
1161 
1162 			/* Skip empty lines, comment lines, and lines with leading
1163 			 * whitespace. */
1164 			if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
1165 				if (__parserfunc == __parsegrent) {	/* Do evil group hack. */
1166 					/* The group entry parsing function needs to know where
1167 					 * the end of the buffer is so that it can construct the
1168 					 * group member ptr table. */
1169 					((struct group *) data)->gr_name = line_buff + buflen;
1170 				}
1171 
1172 				if (!__parserfunc(data, line_buff)) {
1173 					rv = 0;
1174 					break;
1175 				}
1176 			}
1177 		} while (1);
1178 
1179 		__STDIO_AUTO_THREADUNLOCK(f);
1180 	}
1181 
1182 	return rv;
1183 }
1184 
1185 #endif
1186 /**********************************************************************/
1187