source: trunk/mindi-busybox/libpwdgrp/pwd_grp.c @ 954

Last change on this file since 954 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 24.6 KB
Line 
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
54extern int __parsepwent(void *pw, char *line);
55extern int __parsegrent(void *gr, char *line);
56extern int __parsespent(void *sp, char *line);
57
58extern 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
79int 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
98int 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
117int 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
140struct 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
154struct 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
168extern int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
169                char *__restrict buffer, size_t buflen,
170                struct spwd **__restrict result);
171struct 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
185int 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
273struct 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
287struct 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
305int 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
329struct 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
343struct 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
357struct 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
371struct 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
385int 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
413static 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
423static FILE *pwf /*= NULL*/;
424void setpwent(void)
425{
426    LOCK;
427    if (pwf) {
428        rewind(pwf);
429    }
430    UNLOCK;
431}
432
433void endpwent(void)
434{
435    LOCK;
436    if (pwf) {
437        fclose(pwf);
438        pwf = NULL;
439    }
440    UNLOCK;
441}
442
443
444int 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
474static FILE *grf /*= NULL*/;
475void setgrent(void)
476{
477    LOCK;
478    if (grf) {
479        rewind(grf);
480    }
481    UNLOCK;
482}
483
484void endgrent(void)
485{
486    LOCK;
487    if (grf) {
488        fclose(grf);
489        grf = NULL;
490    }
491    UNLOCK;
492}
493
494int 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
524static FILE *spf /*= NULL*/;
525void setspent(void)
526{
527    LOCK;
528    if (spf) {
529        rewind(spf);
530    }
531    UNLOCK;
532}
533
534void endspent(void)
535{
536    LOCK;
537    if (spf) {
538        fclose(spf);
539        spf = NULL;
540    }
541    UNLOCK;
542}
543
544int 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
573struct 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
587struct 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
601struct 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
615struct 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
629int 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
685int 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
710int 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
755static 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
764int 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
797DO_UNLOCK:
798    return rv;
799}
800
801#endif
802/**********************************************************************/
803/* Internal uClibc functions.                    */
804/**********************************************************************/
805#ifdef L___parsepwent
806
807static 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
817int __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
866static 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
872int __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
964static 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
976int __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#if 0
992            if (i==5) {         /* Support for old format. */
993                while (isspace(*line)) ++line; /* glibc eats space here. */
994                if (!*line) {
995                    ((struct spwd *) data)->sp_warn = -1;
996                    ((struct spwd *) data)->sp_inact = -1;
997                    ((struct spwd *) data)->sp_expire = -1;
998                    ((struct spwd *) data)->sp_flag = ~0UL;
999                    return 0;
1000                }
1001            }
1002#endif
1003
1004            *((long *) p) = (long) strtoul(line, &endptr, 10);
1005
1006            if (endptr == line) {
1007                *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
1008            }
1009
1010            line = endptr;
1011
1012            if (i == 8) {
1013                if (!*endptr) {
1014                    return 0;
1015                }
1016                break;
1017            }
1018
1019            if (*endptr != ':') {
1020                break;
1021            }
1022
1023        }
1024
1025        *line++ = 0;
1026        ++i;
1027    } while (1);
1028
1029    return EINVAL;
1030}
1031
1032#endif
1033/**********************************************************************/
1034#ifdef L___pgsreader
1035
1036/* Reads until if EOF, or until if finds a line which fits in the buffer
1037 * and for which the parser function succeeds.
1038 *
1039 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
1040 */
1041
1042int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
1043                char *__restrict line_buff, size_t buflen, FILE *f)
1044{
1045    int line_len;
1046    int skip;
1047    int rv = ERANGE;
1048
1049    if (buflen < PWD_BUFFER_SIZE) {
1050        errno=rv;
1051    } else {
1052        skip = 0;
1053        do {
1054            if (!fgets(line_buff, buflen, f)) {
1055                if (feof(f)) {
1056                    rv = ENOENT;
1057                }
1058                break;
1059            }
1060
1061            line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
1062            if (line_buff[line_len] == '\n') {
1063                line_buff[line_len] = 0;
1064            } else if (line_len + 2 == buflen) { /* line too long */
1065                ++skip;
1066                continue;
1067            }
1068
1069            if (skip) {
1070                --skip;
1071                continue;
1072            }
1073
1074            /* NOTE: glibc difference - glibc strips leading whitespace from
1075             * records.  We do not allow leading whitespace. */
1076
1077            /* Skip empty lines, comment lines, and lines with leading
1078             * whitespace. */
1079            if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
1080                if (__parserfunc == __parsegrent) { /* Do evil group hack. */
1081                    /* The group entry parsing function needs to know where
1082                     * the end of the buffer is so that it can construct the
1083                     * group member ptr table. */
1084                    ((struct group *) data)->gr_name = line_buff + buflen;
1085                }
1086
1087                if (!__parserfunc(data, line_buff)) {
1088                    rv = 0;
1089                    break;
1090                }
1091            }
1092        } while (1);
1093
1094    }
1095
1096    return rv;
1097}
1098
1099#endif
1100/**********************************************************************/
Note: See TracBrowser for help on using the repository browser.