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