1 /* Copyright (C) 2003 Manuel Novoa III
3 * Licensed under GPL v2, or later. See file LICENSE in this tarball.
6 /* Nov 6, 2003 Initial version.
8 * NOTE: This implementation is quite strict about requiring all
9 * field seperators. It also does not allow leading whitespace
10 * except when processing the numeric fields. glibc is more
11 * lenient. See the various glibc difference comments below.
14 * Move to dynamic allocation of (currently statically allocated)
15 * buffers; especially for the group-related functions since
16 * large group member lists will cause error returns.
36 #define _PATH_SHADOW "/etc/shadow"
39 #define _PATH_PASSWD "/etc/passwd"
42 #define _PATH_GROUP "/etc/group"
45 /**********************************************************************/
46 /* Sizes for statically allocated buffers. */
48 /* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
49 * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
50 #define PWD_BUFFER_SIZE 256
51 #define GRP_BUFFER_SIZE 256
53 /**********************************************************************/
54 /* Prototypes for internal functions. */
56 extern int __parsepwent(void *pw, char *line);
57 extern int __parsegrent(void *gr, char *line);
58 extern int __parsespent(void *sp, char *line);
60 extern int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
61 char *__restrict line_buff, size_t buflen, FILE *f);
63 /**********************************************************************/
64 /* For the various fget??ent_r funcs, return
67 * ENOENT: end-of-file encountered
68 * ERANGE: buflen too small
69 * other error values possible. See __pgsreader.
71 * Also, *result == resultbuf on success and NULL on failure.
73 * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
74 * We do not, as it really isn't an error if we reach the end-of-file.
75 * Doing so is analogous to having fgetc() set errno on EOF.
77 /**********************************************************************/
81 int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
82 char *__restrict buffer, size_t buflen,
83 struct passwd **__restrict result)
89 if (!(rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, stream))) {
97 /**********************************************************************/
100 int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
101 char *__restrict buffer, size_t buflen,
102 struct group **__restrict result)
108 if (!(rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, stream))) {
116 /**********************************************************************/
119 int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
120 char *__restrict buffer, size_t buflen,
121 struct spwd **__restrict result)
127 if (!(rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, stream))) {
135 /**********************************************************************/
136 /* For the various fget??ent funcs, return NULL on failure and a
137 * pointer to the appropriate struct (statically allocated) on success.
139 /**********************************************************************/
142 struct passwd *fgetpwent(FILE *stream)
144 static char buffer[PWD_BUFFER_SIZE];
145 static struct passwd resultbuf;
146 struct passwd *result;
148 fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
153 /**********************************************************************/
156 struct group *fgetgrent(FILE *stream)
158 static char buffer[GRP_BUFFER_SIZE];
159 static struct group resultbuf;
160 struct group *result;
162 fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
167 /**********************************************************************/
170 extern int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
171 char *__restrict buffer, size_t buflen,
172 struct spwd **__restrict result);
173 struct spwd *fgetspent(FILE *stream)
175 static char buffer[PWD_BUFFER_SIZE];
176 static struct spwd resultbuf;
179 fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
184 /**********************************************************************/
187 int sgetspent_r(const char *string, struct spwd *result_buf,
188 char *buffer, size_t buflen, struct spwd **result)
194 if (buflen < PWD_BUFFER_SIZE) {
200 if (string != buffer) {
201 if (strlen(string) >= buflen) {
204 strcpy(buffer, string);
207 if (!(rv = __parsespent(result_buf, buffer))) {
208 *result = result_buf;
216 /**********************************************************************/
218 #ifdef GETXXKEY_R_FUNC
219 #error GETXXKEY_R_FUNC is already defined!
223 #define GETXXKEY_R_FUNC getpwnam_r
224 #define GETXXKEY_R_PARSER __parsepwent
225 #define GETXXKEY_R_ENTTYPE struct passwd
226 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
227 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
228 #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
229 #include "pwd_grp_internal.c"
233 #define GETXXKEY_R_FUNC getgrnam_r
234 #define GETXXKEY_R_PARSER __parsegrent
235 #define GETXXKEY_R_ENTTYPE struct group
236 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
237 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
238 #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
239 #include "pwd_grp_internal.c"
243 #define GETXXKEY_R_FUNC getspnam_r
244 #define GETXXKEY_R_PARSER __parsespent
245 #define GETXXKEY_R_ENTTYPE struct spwd
246 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
247 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
248 #define DO_GETXXKEY_R_PATHNAME _PATH_SHADOW
249 #include "pwd_grp_internal.c"
253 #define GETXXKEY_R_FUNC getpwuid_r
254 #define GETXXKEY_R_PARSER __parsepwent
255 #define GETXXKEY_R_ENTTYPE struct passwd
256 #define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
257 #define DO_GETXXKEY_R_KEYTYPE uid_t
258 #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
259 #include "pwd_grp_internal.c"
263 #define GETXXKEY_R_FUNC getgrgid_r
264 #define GETXXKEY_R_PARSER __parsegrent
265 #define GETXXKEY_R_ENTTYPE struct group
266 #define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
267 #define DO_GETXXKEY_R_KEYTYPE gid_t
268 #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
269 #include "pwd_grp_internal.c"
272 /**********************************************************************/
275 struct passwd *getpwuid(uid_t uid)
277 static char buffer[PWD_BUFFER_SIZE];
278 static struct passwd resultbuf;
279 struct passwd *result;
281 getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
286 /**********************************************************************/
289 struct group *getgrgid(gid_t gid)
291 static char buffer[GRP_BUFFER_SIZE];
292 static struct group resultbuf;
293 struct group *result;
295 getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
300 /**********************************************************************/
303 /* This function is non-standard and is currently not built. It seems
304 * to have been created as a reentrant version of the non-standard
305 * functions getspuid. Why getspuid was added, I do not know. */
307 int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
308 char *__restrict buffer, size_t buflen,
309 struct spwd **__restrict result)
313 struct passwd password;
314 char pwd_buff[PWD_BUFFER_SIZE];
317 if (!(rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp))) {
318 rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
325 /**********************************************************************/
328 /* This function is non-standard and is currently not built.
329 * Why it was added, I do not know. */
331 struct spwd *getspuid(uid_t uid)
333 static char buffer[PWD_BUFFER_SIZE];
334 static struct spwd resultbuf;
337 getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
342 /**********************************************************************/
345 struct passwd *getpwnam(const char *name)
347 static char buffer[PWD_BUFFER_SIZE];
348 static struct passwd resultbuf;
349 struct passwd *result;
351 getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
356 /**********************************************************************/
359 struct group *getgrnam(const char *name)
361 static char buffer[GRP_BUFFER_SIZE];
362 static struct group resultbuf;
363 struct group *result;
365 getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
370 /**********************************************************************/
373 struct spwd *getspnam(const char *name)
375 static char buffer[PWD_BUFFER_SIZE];
376 static struct spwd resultbuf;
379 getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
384 /**********************************************************************/
387 int getpw(uid_t uid, char *buf)
389 struct passwd resultbuf;
390 struct passwd *result;
391 char buffer[PWD_BUFFER_SIZE];
395 } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
396 if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
397 resultbuf.pw_name, resultbuf.pw_passwd,
398 (unsigned long)(resultbuf.pw_uid),
399 (unsigned long)(resultbuf.pw_gid),
400 resultbuf.pw_gecos, resultbuf.pw_dir,
401 resultbuf.pw_shell) >= 0
411 /**********************************************************************/
413 #if defined(L_getpwent_r) || defined(L_getgrent_r) || defined(L_getspent_r)
414 #if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
415 static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
416 # define LOCK pthread_mutex_lock(&mylock)
417 # define UNLOCK pthread_mutex_unlock(&mylock);
419 # define LOCK ((void) 0)
420 # define UNLOCK ((void) 0)
425 static FILE *pwf /*= NULL*/;
446 int getpwent_r(struct passwd *__restrict resultbuf,
447 char *__restrict buffer, size_t buflen,
448 struct passwd **__restrict result)
453 *result = NULL; /* In case of error... */
456 if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
462 if (!(rv = __pgsreader(__parsepwent, resultbuf,
463 buffer, buflen, pwf))) {
473 /**********************************************************************/
476 static FILE *grf /*= NULL*/;
496 int getgrent_r(struct group *__restrict resultbuf,
497 char *__restrict buffer, size_t buflen,
498 struct group **__restrict result)
503 *result = NULL; /* In case of error... */
506 if (!(grf = fopen(_PATH_GROUP, "r"))) {
512 if (!(rv = __pgsreader(__parsegrent, resultbuf,
513 buffer, buflen, grf))) {
523 /**********************************************************************/
526 static FILE *spf /*= NULL*/;
546 int getspent_r(struct spwd *resultbuf, char *buffer,
547 size_t buflen, struct spwd **result)
552 *result = NULL; /* In case of error... */
555 if (!(spf = fopen(_PATH_SHADOW, "r"))) {
561 if (!(rv = __pgsreader(__parsespent, resultbuf,
562 buffer, buflen, spf))) {
572 /**********************************************************************/
575 struct passwd *getpwent(void)
577 static char line_buff[PWD_BUFFER_SIZE];
578 static struct passwd pwd;
579 struct passwd *result;
581 getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
586 /**********************************************************************/
589 struct group *getgrent(void)
591 static char line_buff[GRP_BUFFER_SIZE];
592 static struct group gr;
593 struct group *result;
595 getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
600 /**********************************************************************/
603 struct spwd *getspent(void)
605 static char line_buff[PWD_BUFFER_SIZE];
606 static struct spwd spwd;
609 getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
614 /**********************************************************************/
617 struct spwd *sgetspent(const char *string)
619 static char line_buff[PWD_BUFFER_SIZE];
620 static struct spwd spwd;
623 sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
628 /**********************************************************************/
631 int initgroups(const char *user, gid_t gid)
638 char buff[PWD_BUFFER_SIZE];
642 /* We alloc space for 8 gids at a time. */
643 if (((group_list = (gid_t *) malloc(8*sizeof(gid_t *))) != NULL)
644 && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
650 while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) {
651 assert(group.gr_mem); /* Must have at least a NULL terminator. */
652 if (group.gr_gid != gid) {
653 for (m=group.gr_mem ; *m ; m++) {
654 if (!strcmp(*m, user)) {
655 if (!(num_groups & 7)) {
656 gid_t *tmp = (gid_t *)
658 (num_groups+8) * sizeof(gid_t *));
665 group_list[num_groups++] = group.gr_gid;
672 rv = setgroups(num_groups, group_list);
677 /* group_list will be NULL if initial malloc failed, which may trigger
678 * warnings from various malloc debuggers. */
684 /**********************************************************************/
687 int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
694 /* No extra thread locking is needed above what fprintf does. */
695 if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
696 p->pw_name, p->pw_passwd,
697 (unsigned long)(p->pw_uid),
698 (unsigned long)(p->pw_gid),
699 p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
709 /**********************************************************************/
712 int putgrent(const struct group *__restrict p, FILE *__restrict f)
714 static const char format[] = ",%s";
719 if (!p || !f) { /* Sigh... glibc checks. */
722 if (fprintf(f, "%s:%s:%lu:",
723 p->gr_name, p->gr_passwd,
724 (unsigned long)(p->gr_gid)) >= 0
734 if (fputc('\n', f) >= 0) {
739 if (fprintf(f, fmt, *m) < 0) {
754 /**********************************************************************/
757 static const unsigned char _sp_off[] = {
758 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
759 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
760 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
761 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
762 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
763 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
766 int putspent(const struct spwd *p, FILE *stream)
768 static const char ld_format[] = "%ld:";
774 /* Unlike putpwent and putgrent, glibc does not check the args. */
775 if (fprintf(stream, "%s:%s:", p->sp_namp,
776 (p->sp_pwdp ? p->sp_pwdp : "")) < 0
781 for (i=0 ; i < sizeof(_sp_off) ; i++) {
783 if ((x = *(const long int *)(((const char *) p) + _sp_off[i])) == -1) {
786 if (fprintf(stream, f, x) < 0) {
791 if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
795 if (fputc('\n', stream) > 0) {
804 /**********************************************************************/
805 /* Internal uClibc functions. */
806 /**********************************************************************/
807 #ifdef L___parsepwent
809 static const unsigned char pw_off[] = {
810 offsetof(struct passwd, pw_name), /* 0 */
811 offsetof(struct passwd, pw_passwd), /* 1 */
812 offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
813 offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
814 offsetof(struct passwd, pw_gecos), /* 4 */
815 offsetof(struct passwd, pw_dir), /* 5 */
816 offsetof(struct passwd, pw_shell) /* 6 */
819 int __parsepwent(void *data, char *line)
827 p = ((char *) ((struct passwd *) data)) + pw_off[i];
829 if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
830 *((char **) p) = line;
834 /* NOTE: glibc difference - glibc allows omission of
835 * ':' seperators after the gid field if all remaining
836 * entries are empty. We require all separators. */
837 if (!(line = strchr(line, ':'))) {
841 unsigned long t = strtoul(line, &endptr, 10);
842 /* Make sure we had at least one digit, and that the
843 * failing char is the next field seperator ':'. See
844 * glibc difference note above. */
845 /* TODO: Also check for leading whitespace? */
846 if ((endptr == line) || (*endptr != ':')) {
850 if (i & 1) { /* i == 3 -- gid */
852 } else { /* i == 2 -- uid */
865 /**********************************************************************/
866 #ifdef L___parsegrent
868 static const unsigned char gr_off[] = {
869 offsetof(struct group, gr_name), /* 0 */
870 offsetof(struct group, gr_passwd), /* 1 */
871 offsetof(struct group, gr_gid) /* 2 - not a char ptr */
874 int __parsegrent(void *data, char *line)
882 end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
885 p = ((char *) ((struct group *) data)) + gr_off[i];
888 *((char **) p) = line;
889 if (!(line = strchr(line, ':'))) {
895 *((gid_t *) p) = strtoul(line, &endptr, 10);
897 /* NOTE: glibc difference - glibc allows omission of the
898 * trailing colon when there is no member list. We treat
899 * this as an error. */
901 /* Make sure we had at least one digit, and that the
902 * failing char is the next field seperator ':'. See
903 * glibc difference note above. */
904 if ((endptr == line) || (*endptr != ':')) {
908 i = 1; /* Count terminating NULL ptr. */
911 if (p[1]) { /* We have a member list to process. */
912 /* Overwrite the last ':' with a ',' before counting.
913 * This allows us to test for initial ',' and adds
914 * one ',' so that the ',' count equals the member
918 /* NOTE: glibc difference - glibc allows and trims leading
919 * (but not trailing) space. We treat this as an error. */
920 /* NOTE: glibc difference - glibc allows consecutive and
921 * trailing commas, and ignores "empty string" users. We
922 * treat this as an error. */
925 *p = 0; /* nul-terminate each member string. */
926 if (!*++p || (*p == ',') || isspace(*p)) {
933 /* Now align (p+1), rounding up. */
934 /* Assumes sizeof(char **) is a power of 2. */
935 members = (char **)( (((intptr_t) p) + sizeof(char **))
936 & ~((intptr_t)(sizeof(char **) - 1)) );
938 if (((char *)(members + i)) > end_of_buf) { /* No space. */
942 ((struct group *) data)->gr_mem = members;
945 p = endptr; /* Pointing to char prior to first member. */
963 /**********************************************************************/
964 #ifdef L___parsespent
966 static const unsigned char sp_off[] = {
967 offsetof(struct spwd, sp_namp), /* 0 */
968 offsetof(struct spwd, sp_pwdp), /* 1 */
969 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
970 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
971 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
972 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
973 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
974 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
975 offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
978 int __parsespent(void *data, char * line)
986 p = ((char *) ((struct spwd *) data)) + sp_off[i];
988 *((char **) p) = line;
989 if (!(line = strchr(line, ':'))) {
994 if (i==5) { /* Support for old format. */
995 while (isspace(*line)) ++line; /* glibc eats space here. */
997 ((struct spwd *) data)->sp_warn = -1;
998 ((struct spwd *) data)->sp_inact = -1;
999 ((struct spwd *) data)->sp_expire = -1;
1000 ((struct spwd *) data)->sp_flag = ~0UL;
1006 *((long *) p) = (long) strtoul(line, &endptr, 10);
1008 if (endptr == line) {
1009 *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
1021 if (*endptr != ':') {
1035 /**********************************************************************/
1036 #ifdef L___pgsreader
1038 /* Reads until if EOF, or until if finds a line which fits in the buffer
1039 * and for which the parser function succeeds.
1041 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
1044 int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
1045 char *__restrict line_buff, size_t buflen, FILE *f)
1051 if (buflen < PWD_BUFFER_SIZE) {
1056 if (!fgets(line_buff, buflen, f)) {
1063 line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
1064 if (line_buff[line_len] == '\n') {
1065 line_buff[line_len] = 0;
1066 } else if (line_len + 2 == buflen) { /* line too long */
1076 /* NOTE: glibc difference - glibc strips leading whitespace from
1077 * records. We do not allow leading whitespace. */
1079 /* Skip empty lines, comment lines, and lines with leading
1081 if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
1082 if (__parserfunc == __parsegrent) { /* Do evil group hack. */
1083 /* The group entry parsing function needs to know where
1084 * the end of the buffer is so that it can construct the
1085 * group member ptr table. */
1086 ((struct group *) data)->gr_name = line_buff + buflen;
1089 if (!__parserfunc(data, line_buff)) {
1102 /**********************************************************************/