1 /* vi: set sw=4 ts=4: */
2 /* Copyright (C) 2003 Manuel Novoa III
4 * Licensed under GPL v2, or later. See file LICENSE in this tarball.
7 /* Nov 6, 2003 Initial version.
9 * NOTE: This implementation is quite strict about requiring all
10 * field seperators. It also does not allow leading whitespace
11 * except when processing the numeric fields. glibc is more
12 * lenient. See the various glibc difference comments below.
15 * Move to dynamic allocation of (currently statically allocated)
16 * buffers; especially for the group-related functions since
17 * large group member lists will cause error returns.
26 #define _PATH_SHADOW "/etc/shadow"
29 #define _PATH_PASSWD "/etc/passwd"
32 #define _PATH_GROUP "/etc/group"
35 /**********************************************************************/
36 /* Sizes for statically allocated buffers. */
38 /* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
39 * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
40 #define PWD_BUFFER_SIZE 256
41 #define GRP_BUFFER_SIZE 256
43 /**********************************************************************/
44 /* Prototypes for internal functions. */
46 static int __pgsreader(int (*parserfunc)(void *d, char *line), void *data,
47 char *__restrict line_buff, size_t buflen, FILE *f);
49 static int __parsepwent(void *pw, char *line);
50 static int __parsegrent(void *gr, char *line);
51 #if ENABLE_USE_BB_SHADOW
52 static int __parsespent(void *sp, char *line);
55 /**********************************************************************/
56 /* For the various fget??ent_r funcs, return
59 * ENOENT: end-of-file encountered
60 * ERANGE: buflen too small
61 * other error values possible. See __pgsreader.
63 * Also, *result == resultbuf on success and NULL on failure.
65 * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
66 * We do not, as it really isn't an error if we reach the end-of-file.
67 * Doing so is analogous to having fgetc() set errno on EOF.
69 /**********************************************************************/
71 int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
72 char *__restrict buffer, size_t buflen,
73 struct passwd **__restrict result)
79 rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, stream);
87 int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
88 char *__restrict buffer, size_t buflen,
89 struct group **__restrict result)
95 rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, stream);
103 #if ENABLE_USE_BB_SHADOW
104 int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
105 char *__restrict buffer, size_t buflen,
106 struct spwd **__restrict result)
112 rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, stream);
121 /**********************************************************************/
122 /* For the various fget??ent funcs, return NULL on failure and a
123 * pointer to the appropriate struct (statically allocated) on success.
125 /**********************************************************************/
127 struct passwd *fgetpwent(FILE *stream)
129 static char buffer[PWD_BUFFER_SIZE];
130 static struct passwd resultbuf;
131 struct passwd *result;
133 fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
137 struct group *fgetgrent(FILE *stream)
139 static char buffer[GRP_BUFFER_SIZE];
140 static struct group resultbuf;
141 struct group *result;
143 fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
147 #if ENABLE_USE_BB_SHADOW
148 struct spwd *fgetspent(FILE *stream)
150 static char buffer[PWD_BUFFER_SIZE];
151 static struct spwd resultbuf;
154 fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
158 int sgetspent_r(const char *string, struct spwd *result_buf,
159 char *buffer, size_t buflen, struct spwd **result)
165 if (buflen < PWD_BUFFER_SIZE) {
171 if (string != buffer) {
172 if (strlen(string) >= buflen) {
175 strcpy(buffer, string);
178 rv = __parsespent(result_buf, buffer);
180 *result = result_buf;
188 /**********************************************************************/
190 #ifdef GETXXKEY_R_FUNC
191 #error GETXXKEY_R_FUNC is already defined!
194 #define GETXXKEY_R_FUNC getpwnam_R
195 #define GETXXKEY_R_PARSER __parsepwent
196 #define GETXXKEY_R_ENTTYPE struct passwd
197 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
198 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
199 #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
200 #include "pwd_grp_internal.c"
202 #define GETXXKEY_R_FUNC getgrnam_R
203 #define GETXXKEY_R_PARSER __parsegrent
204 #define GETXXKEY_R_ENTTYPE struct group
205 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
206 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
207 #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
208 #include "pwd_grp_internal.c"
210 #if ENABLE_USE_BB_SHADOW
211 #define GETXXKEY_R_FUNC getspnam_R
212 #define GETXXKEY_R_PARSER __parsespent
213 #define GETXXKEY_R_ENTTYPE struct spwd
214 #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
215 #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
216 #define DO_GETXXKEY_R_PATHNAME _PATH_SHADOW
217 #include "pwd_grp_internal.c"
220 #define GETXXKEY_R_FUNC getpwuid_R
221 #define GETXXKEY_R_PARSER __parsepwent
222 #define GETXXKEY_R_ENTTYPE struct passwd
223 #define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
224 #define DO_GETXXKEY_R_KEYTYPE uid_t
225 #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
226 #include "pwd_grp_internal.c"
228 #define GETXXKEY_R_FUNC getgrgid_R
229 #define GETXXKEY_R_PARSER __parsegrent
230 #define GETXXKEY_R_ENTTYPE struct group
231 #define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
232 #define DO_GETXXKEY_R_KEYTYPE gid_t
233 #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
234 #include "pwd_grp_internal.c"
236 /**********************************************************************/
238 struct passwd *getpwuid(uid_t uid)
240 static char buffer[PWD_BUFFER_SIZE];
241 static struct passwd resultbuf;
242 struct passwd *result;
244 getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
248 struct group *getgrgid(gid_t gid)
250 static char buffer[GRP_BUFFER_SIZE];
251 static struct group resultbuf;
252 struct group *result;
254 getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
258 #if 0 //ENABLE_USE_BB_SHADOW
259 /* This function is non-standard and is currently not built. It seems
260 * to have been created as a reentrant version of the non-standard
261 * functions getspuid. Why getspuid was added, I do not know. */
262 int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
263 char *__restrict buffer, size_t buflen,
264 struct spwd **__restrict result)
268 struct passwd password;
269 char pwd_buff[PWD_BUFFER_SIZE];
272 rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp);
274 rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
280 /* This function is non-standard and is currently not built.
281 * Why it was added, I do not know. */
282 struct spwd *getspuid(uid_t uid)
284 static char buffer[PWD_BUFFER_SIZE];
285 static struct spwd resultbuf;
288 getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
293 struct passwd *getpwnam(const char *name)
295 static char buffer[PWD_BUFFER_SIZE];
296 static struct passwd resultbuf;
297 struct passwd *result;
299 getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
303 struct group *getgrnam(const char *name)
305 static char buffer[GRP_BUFFER_SIZE];
306 static struct group resultbuf;
307 struct group *result;
309 getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
313 #if ENABLE_USE_BB_SHADOW
314 struct spwd *getspnam(const char *name)
316 static char buffer[PWD_BUFFER_SIZE];
317 static struct spwd resultbuf;
320 getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
325 int getpw(uid_t uid, char *buf)
327 struct passwd resultbuf;
328 struct passwd *result;
329 char buffer[PWD_BUFFER_SIZE];
333 } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
334 if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
335 resultbuf.pw_name, resultbuf.pw_passwd,
336 (unsigned long)(resultbuf.pw_uid),
337 (unsigned long)(resultbuf.pw_gid),
338 resultbuf.pw_gecos, resultbuf.pw_dir,
339 resultbuf.pw_shell) >= 0
348 /**********************************************************************/
350 #if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
351 static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
352 # define LOCK pthread_mutex_lock(&mylock)
353 # define UNLOCK pthread_mutex_unlock(&mylock);
355 # define LOCK ((void) 0)
356 # define UNLOCK ((void) 0)
359 static FILE *pwf /*= NULL*/;
380 int getpwent_r(struct passwd *__restrict resultbuf,
381 char *__restrict buffer, size_t buflen,
382 struct passwd **__restrict result)
387 *result = NULL; /* In case of error... */
390 pwf = fopen(_PATH_PASSWD, "r");
397 rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, pwf);
407 static FILE *grf /*= NULL*/;
427 int getgrent_r(struct group *__restrict resultbuf,
428 char *__restrict buffer, size_t buflen,
429 struct group **__restrict result)
434 *result = NULL; /* In case of error... */
437 grf = fopen(_PATH_GROUP, "r");
444 rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, grf);
454 #if ENABLE_USE_BB_SHADOW
455 static FILE *spf /*= NULL*/;
475 int getspent_r(struct spwd *resultbuf, char *buffer,
476 size_t buflen, struct spwd **result)
481 *result = NULL; /* In case of error... */
484 spf = fopen(_PATH_SHADOW, "r");
491 rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, spf);
502 struct passwd *getpwent(void)
504 static char line_buff[PWD_BUFFER_SIZE];
505 static struct passwd pwd;
506 struct passwd *result;
508 getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
512 struct group *getgrent(void)
514 static char line_buff[GRP_BUFFER_SIZE];
515 static struct group gr;
516 struct group *result;
518 getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
522 #if ENABLE_USE_BB_SHADOW
523 struct spwd *getspent(void)
525 static char line_buff[PWD_BUFFER_SIZE];
526 static struct spwd spwd;
529 getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
533 struct spwd *sgetspent(const char *string)
535 static char line_buff[PWD_BUFFER_SIZE];
536 static struct spwd spwd;
539 sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
544 int initgroups(const char *user, gid_t gid)
551 char buff[PWD_BUFFER_SIZE];
555 /* We alloc space for 8 gids at a time. */
556 group_list = (gid_t *) malloc(8*sizeof(gid_t *));
558 && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
563 while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) {
564 assert(group.gr_mem); /* Must have at least a NULL terminator. */
565 if (group.gr_gid != gid) {
566 for (m=group.gr_mem ; *m ; m++) {
567 if (!strcmp(*m, user)) {
568 if (!(num_groups & 7)) {
569 gid_t *tmp = (gid_t *)
571 (num_groups+8) * sizeof(gid_t *));
578 group_list[num_groups++] = group.gr_gid;
585 rv = setgroups(num_groups, group_list);
590 /* group_list will be NULL if initial malloc failed, which may trigger
591 * warnings from various malloc debuggers. */
596 int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
603 /* No extra thread locking is needed above what fprintf does. */
604 if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
605 p->pw_name, p->pw_passwd,
606 (unsigned long)(p->pw_uid),
607 (unsigned long)(p->pw_gid),
608 p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
617 int putgrent(const struct group *__restrict p, FILE *__restrict f)
619 static const char format[] = ",%s";
624 if (!p || !f) { /* Sigh... glibc checks. */
627 if (fprintf(f, "%s:%s:%lu:",
628 p->gr_name, p->gr_passwd,
629 (unsigned long)(p->gr_gid)) >= 0
639 if (fputc('\n', f) >= 0) {
644 if (fprintf(f, fmt, *m) < 0) {
658 #if ENABLE_USE_BB_SHADOW
659 static const unsigned char _sp_off[] = {
660 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
661 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
662 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
663 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
664 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
665 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
668 int putspent(const struct spwd *p, FILE *stream)
670 static const char ld_format[] = "%ld:";
676 /* Unlike putpwent and putgrent, glibc does not check the args. */
677 if (fprintf(stream, "%s:%s:", p->sp_namp,
678 (p->sp_pwdp ? p->sp_pwdp : "")) < 0
683 for (i=0 ; i < sizeof(_sp_off) ; i++) {
685 x = *(const long int *)(((const char *) p) + _sp_off[i]);
689 if (fprintf(stream, f, x) < 0) {
694 if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
698 if (fputc('\n', stream) > 0) {
707 /**********************************************************************/
708 /* Internal uClibc functions. */
709 /**********************************************************************/
711 static const unsigned char pw_off[] = {
712 offsetof(struct passwd, pw_name), /* 0 */
713 offsetof(struct passwd, pw_passwd), /* 1 */
714 offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
715 offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
716 offsetof(struct passwd, pw_gecos), /* 4 */
717 offsetof(struct passwd, pw_dir), /* 5 */
718 offsetof(struct passwd, pw_shell) /* 6 */
721 static int __parsepwent(void *data, char *line)
729 p = ((char *) ((struct passwd *) data)) + pw_off[i];
731 if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
732 *((char **) p) = line;
736 /* NOTE: glibc difference - glibc allows omission of
737 * ':' seperators after the gid field if all remaining
738 * entries are empty. We require all separators. */
739 line = strchr(line, ':');
744 unsigned long t = strtoul(line, &endptr, 10);
745 /* Make sure we had at least one digit, and that the
746 * failing char is the next field seperator ':'. See
747 * glibc difference note above. */
748 /* TODO: Also check for leading whitespace? */
749 if ((endptr == line) || (*endptr != ':')) {
753 if (i & 1) { /* i == 3 -- gid */
755 } else { /* i == 2 -- uid */
767 /**********************************************************************/
769 static const unsigned char gr_off[] = {
770 offsetof(struct group, gr_name), /* 0 */
771 offsetof(struct group, gr_passwd), /* 1 */
772 offsetof(struct group, gr_gid) /* 2 - not a char ptr */
775 static int __parsegrent(void *data, char *line)
783 end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
786 p = ((char *) ((struct group *) data)) + gr_off[i];
789 *((char **) p) = line;
790 line = strchr(line, ':');
797 *((gid_t *) p) = strtoul(line, &endptr, 10);
799 /* NOTE: glibc difference - glibc allows omission of the
800 * trailing colon when there is no member list. We treat
801 * this as an error. */
803 /* Make sure we had at least one digit, and that the
804 * failing char is the next field seperator ':'. See
805 * glibc difference note above. */
806 if ((endptr == line) || (*endptr != ':')) {
810 i = 1; /* Count terminating NULL ptr. */
813 if (p[1]) { /* We have a member list to process. */
814 /* Overwrite the last ':' with a ',' before counting.
815 * This allows us to test for initial ',' and adds
816 * one ',' so that the ',' count equals the member
820 /* NOTE: glibc difference - glibc allows and trims leading
821 * (but not trailing) space. We treat this as an error. */
822 /* NOTE: glibc difference - glibc allows consecutive and
823 * trailing commas, and ignores "empty string" users. We
824 * treat this as an error. */
827 *p = 0; /* nul-terminate each member string. */
828 if (!*++p || (*p == ',') || isspace(*p)) {
835 /* Now align (p+1), rounding up. */
836 /* Assumes sizeof(char **) is a power of 2. */
837 members = (char **)( (((intptr_t) p) + sizeof(char **))
838 & ~((intptr_t)(sizeof(char **) - 1)) );
840 if (((char *)(members + i)) > end_of_buf) { /* No space. */
844 ((struct group *) data)->gr_mem = members;
847 p = endptr; /* Pointing to char prior to first member. */
864 /**********************************************************************/
865 #if ENABLE_USE_BB_SHADOW
866 static const unsigned char sp_off[] = {
867 offsetof(struct spwd, sp_namp), /* 0 */
868 offsetof(struct spwd, sp_pwdp), /* 1 */
869 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
870 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
871 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
872 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
873 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
874 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
875 offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
878 static int __parsespent(void *data, char * line)
886 p = ((char *) ((struct spwd *) data)) + sp_off[i];
888 *((char **) p) = line;
889 line = strchr(line, ':');
894 *((long *) p) = (long) strtoul(line, &endptr, 10);
896 if (endptr == line) {
897 *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
909 if (*endptr != ':') {
923 /**********************************************************************/
925 /* Reads until if EOF, or until if finds a line which fits in the buffer
926 * and for which the parser function succeeds.
928 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
931 static int __pgsreader(int (*parserfunc)(void *d, char *line), void *data,
932 char *__restrict line_buff, size_t buflen, FILE *f)
938 if (buflen < PWD_BUFFER_SIZE) {
943 if (!fgets(line_buff, buflen, f)) {
950 line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
951 if (line_buff[line_len] == '\n') {
952 line_buff[line_len] = 0;
953 } else if (line_len + 2 == buflen) { /* line too long */
963 /* NOTE: glibc difference - glibc strips leading whitespace from
964 * records. We do not allow leading whitespace. */
966 /* Skip empty lines, comment lines, and lines with leading
968 if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
969 if (parserfunc == __parsegrent) { /* Do evil group hack. */
970 /* The group entry parsing function needs to know where
971 * the end of the buffer is so that it can construct the
972 * group member ptr table. */
973 ((struct group *) data)->gr_name = line_buff + buflen;
976 if (!parserfunc(data, line_buff)) {