Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/libpwdgrp/pwd_grp.c

Parent Directory Parent Directory | Revision Log Revision Log


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