source: branches/stable/mindi-busybox/libpwdgrp/pwd_grp.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 24.5 KB
Line 
1/* 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
46static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
47        char *__restrict line_buff, size_t buflen, FILE *f);
48
49static int bb__parsepwent(void *pw, char *line);
50static int bb__parsegrent(void *gr, char *line);
51#if ENABLE_USE_BB_SHADOW
52static int bb__parsespent(void *sp, char *line);
53#endif
54
55/**********************************************************************/
56/* We avoid having big global data. */
57
58struct 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
102static struct statics *ptr_to_statics;
103
104static 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/* 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
131int 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
147int 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
164int 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 * TODO: audit & stop using these in bbox, they pull in static buffers */
185/**********************************************************************/
186
187#if 0
188struct passwd *fgetpwent(FILE *stream)
189{
190    struct statics *S;
191    struct passwd *resultbuf = RESULTBUF(fgetpwent);
192    char *buffer = BUFFER(fgetpwent);
193    struct passwd *result;
194
195    fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result);
196    return result;
197}
198
199struct group *fgetgrent(FILE *stream)
200{
201    struct statics *S;
202    struct group *resultbuf = RESULTBUF(fgetgrent);
203    char *buffer = BUFFER(fgetgrent);
204    struct group *result;
205
206    fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result);
207    return result;
208}
209#endif
210
211#if ENABLE_USE_BB_SHADOW
212#if 0
213struct spwd *fgetspent(FILE *stream)
214{
215    struct statics *S;
216    struct spwd *resultbuf = RESULTBUF(fgetspent);
217    char *buffer = BUFFER(fgetspent);
218    struct spwd *result;
219
220    fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result);
221    return result;
222}
223#endif
224
225int 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/* TODO: audit & stop using these in bbox, they pull in static buffers */
301
302/* This one has many users */
303struct passwd *getpwuid(uid_t uid)
304{
305    struct statics *S;
306    struct passwd *resultbuf = RESULTBUF(getpwuid);
307    char *buffer = BUFFER(getpwuid);
308    struct passwd *result;
309
310    getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result);
311    return result;
312}
313
314/* This one has many users */
315struct group *getgrgid(gid_t gid)
316{
317    struct statics *S;
318    struct group *resultbuf = RESULTBUF(getgrgid);
319    char *buffer = BUFFER(getgrgid);
320    struct group *result;
321
322    getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result);
323    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. */
330int 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. */
350struct spwd *getspuid(uid_t uid)
351{
352    struct statics *S;
353    struct spwd *resultbuf = RESULTBUF(getspuid);
354    char *buffer = BUFFER(getspuid);
355    struct spwd *result;
356
357    getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result);
358    return result;
359}
360#endif
361
362/* This one has many users */
363struct passwd *getpwnam(const char *name)
364{
365    struct statics *S;
366    struct passwd *resultbuf = RESULTBUF(getpwnam);
367    char *buffer = BUFFER(getpwnam);
368    struct passwd *result;
369
370    getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result);
371    return result;
372}
373
374/* This one has many users */
375struct group *getgrnam(const char *name)
376{
377    struct statics *S;
378    struct group *resultbuf = RESULTBUF(getgrnam);
379    char *buffer = BUFFER(getgrnam);
380    struct group *result;
381
382    getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result);
383    return result;
384}
385
386#if 0 //ENABLE_USE_BB_SHADOW
387struct spwd *getspnam(const char *name)
388{
389    struct statics *S;
390    struct spwd *resultbuf = RESULTBUF(getspnam);
391    char *buffer = BUFFER(getspnam);
392    struct spwd *result;
393
394    getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result);
395    return result;
396}
397#endif
398
399/* This one doesn't use static buffers */
400int getpw(uid_t uid, char *buf)
401{
402    struct passwd resultbuf;
403    struct passwd *result;
404    char buffer[PWD_BUFFER_SIZE];
405
406    if (!buf) {
407        errno = EINVAL;
408    } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
409        if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
410                    resultbuf.pw_name, resultbuf.pw_passwd,
411                    (unsigned long)(resultbuf.pw_uid),
412                    (unsigned long)(resultbuf.pw_gid),
413                    resultbuf.pw_gecos, resultbuf.pw_dir,
414                    resultbuf.pw_shell) >= 0
415            ) {
416            return 0;
417        }
418    }
419
420    return -1;
421}
422
423/**********************************************************************/
424
425/* FIXME: we don't have such CONFIG_xx - ?! */
426
427#if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
428static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
429# define LOCK       pthread_mutex_lock(&mylock)
430# define UNLOCK     pthread_mutex_unlock(&mylock);
431#else
432# define LOCK       ((void) 0)
433# define UNLOCK     ((void) 0)
434#endif
435
436static FILE *pwf /*= NULL*/;
437void setpwent(void)
438{
439    LOCK;
440    if (pwf) {
441        rewind(pwf);
442    }
443    UNLOCK;
444}
445
446void endpwent(void)
447{
448    LOCK;
449    if (pwf) {
450        fclose(pwf);
451        pwf = NULL;
452    }
453    UNLOCK;
454}
455
456
457int getpwent_r(struct passwd *__restrict resultbuf,
458               char *__restrict buffer, size_t buflen,
459               struct passwd **__restrict result)
460{
461    int rv;
462
463    LOCK;
464    *result = NULL;             /* In case of error... */
465
466    if (!pwf) {
467        pwf = fopen(_PATH_PASSWD, "r");
468        if (!pwf) {
469            rv = errno;
470            goto ERR;
471        }
472    }
473
474    rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
475    if (!rv) {
476        *result = resultbuf;
477    }
478
479 ERR:
480    UNLOCK;
481    return rv;
482}
483
484static FILE *grf /*= NULL*/;
485void setgrent(void)
486{
487    LOCK;
488    if (grf) {
489        rewind(grf);
490    }
491    UNLOCK;
492}
493
494void endgrent(void)
495{
496    LOCK;
497    if (grf) {
498        fclose(grf);
499        grf = NULL;
500    }
501    UNLOCK;
502}
503
504int getgrent_r(struct group *__restrict resultbuf,
505               char *__restrict buffer, size_t buflen,
506               struct group **__restrict result)
507{
508    int rv;
509
510    LOCK;
511    *result = NULL;             /* In case of error... */
512
513    if (!grf) {
514        grf = fopen(_PATH_GROUP, "r");
515        if (!grf) {
516            rv = errno;
517            goto ERR;
518        }
519    }
520
521    rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
522    if (!rv) {
523        *result = resultbuf;
524    }
525
526 ERR:
527    UNLOCK;
528    return rv;
529}
530
531#if ENABLE_USE_BB_SHADOW
532static FILE *spf /*= NULL*/;
533void setspent(void)
534{
535    LOCK;
536    if (spf) {
537        rewind(spf);
538    }
539    UNLOCK;
540}
541
542void endspent(void)
543{
544    LOCK;
545    if (spf) {
546        fclose(spf);
547        spf = NULL;
548    }
549    UNLOCK;
550}
551
552int getspent_r(struct spwd *resultbuf, char *buffer,
553               size_t buflen, struct spwd **result)
554{
555    int rv;
556
557    LOCK;
558    *result = NULL;             /* In case of error... */
559
560    if (!spf) {
561        spf = fopen(_PATH_SHADOW, "r");
562        if (!spf) {
563            rv = errno;
564            goto ERR;
565        }
566    }
567
568    rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
569    if (!rv) {
570        *result = resultbuf;
571    }
572
573 ERR:
574    UNLOCK;
575    return rv;
576}
577#endif
578
579#if 0
580struct passwd *getpwent(void)
581{
582    static char line_buff[PWD_BUFFER_SIZE];
583    static struct passwd pwd;
584    struct passwd *result;
585
586    getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
587    return result;
588}
589
590struct group *getgrent(void)
591{
592    static char line_buff[GRP_BUFFER_SIZE];
593    static struct group gr;
594    struct group *result;
595
596    getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
597    return result;
598}
599#endif
600
601#if 0 //ENABLE_USE_BB_SHADOW
602struct spwd *getspent(void)
603{
604    static char line_buff[PWD_BUFFER_SIZE];
605    static struct spwd spwd;
606    struct spwd *result;
607
608    getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
609    return result;
610}
611
612struct spwd *sgetspent(const char *string)
613{
614    static char line_buff[PWD_BUFFER_SIZE];
615    static struct spwd spwd;
616    struct spwd *result;
617
618    sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
619    return result;
620}
621#endif
622
623int initgroups(const char *user, gid_t gid)
624{
625    FILE *grfile;
626    gid_t *group_list;
627    int num_groups, rv;
628    char **m;
629    struct group group;
630    char buff[PWD_BUFFER_SIZE];
631
632    rv = -1;
633
634    /* We alloc space for 8 gids at a time. */
635    group_list = (gid_t *) malloc(8*sizeof(gid_t *));
636    if (group_list
637     && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
638    ) {
639        *group_list = gid;
640        num_groups = 1;
641
642        while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
643            assert(group.gr_mem); /* Must have at least a NULL terminator. */
644            if (group.gr_gid != gid) {
645                for (m = group.gr_mem; *m; m++) {
646                    if (!strcmp(*m, user)) {
647                        if (!(num_groups & 7)) {
648                            gid_t *tmp = (gid_t *)
649                                realloc(group_list,
650                                        (num_groups+8) * sizeof(gid_t *));
651                            if (!tmp) {
652                                rv = -1;
653                                goto DO_CLOSE;
654                            }
655                            group_list = tmp;
656                        }
657                        group_list[num_groups++] = group.gr_gid;
658                        break;
659                    }
660                }
661            }
662        }
663
664        rv = setgroups(num_groups, group_list);
665    DO_CLOSE:
666        fclose(grfile);
667    }
668
669    /* group_list will be NULL if initial malloc failed, which may trigger
670     * warnings from various malloc debuggers. */
671    free(group_list);
672    return rv;
673}
674
675int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
676{
677    int rv = -1;
678
679    if (!p || !f) {
680        errno=EINVAL;
681    } else {
682        /* No extra thread locking is needed above what fprintf does. */
683        if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
684                    p->pw_name, p->pw_passwd,
685                    (unsigned long)(p->pw_uid),
686                    (unsigned long)(p->pw_gid),
687                    p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
688            ) {
689            rv = 0;
690        }
691    }
692
693    return rv;
694}
695
696int putgrent(const struct group *__restrict p, FILE *__restrict f)
697{
698    static const char format[] ALIGN1 = ",%s";
699
700    char **m;
701    const char *fmt;
702    int rv = -1;
703
704    if (!p || !f) {             /* Sigh... glibc checks. */
705        errno=EINVAL;
706    } else {
707        if (fprintf(f, "%s:%s:%lu:",
708                    p->gr_name, p->gr_passwd,
709                    (unsigned long)(p->gr_gid)) >= 0
710            ) {
711
712            fmt = format + 1;
713
714            assert(p->gr_mem);
715            m = p->gr_mem;
716
717            do {
718                if (!*m) {
719                    if (fputc('\n', f) >= 0) {
720                        rv = 0;
721                    }
722                    break;
723                }
724                if (fprintf(f, fmt, *m) < 0) {
725                    break;
726                }
727                ++m;
728                fmt = format;
729            } while (1);
730
731        }
732
733    }
734
735    return rv;
736}
737
738#if ENABLE_USE_BB_SHADOW
739static const unsigned char _sp_off[] ALIGN1 = {
740    offsetof(struct spwd, sp_lstchg),       /* 2 - not a char ptr */
741    offsetof(struct spwd, sp_min),          /* 3 - not a char ptr */
742    offsetof(struct spwd, sp_max),          /* 4 - not a char ptr */
743    offsetof(struct spwd, sp_warn),         /* 5 - not a char ptr */
744    offsetof(struct spwd, sp_inact),        /* 6 - not a char ptr */
745    offsetof(struct spwd, sp_expire)        /* 7 - not a char ptr */
746};
747
748int putspent(const struct spwd *p, FILE *stream)
749{
750    static const char ld_format[] ALIGN1 = "%ld:";
751
752    const char *f;
753    long x;
754    int i;
755    int rv = -1;
756
757    /* Unlike putpwent and putgrent, glibc does not check the args. */
758    if (fprintf(stream, "%s:%s:", p->sp_namp,
759                (p->sp_pwdp ? p->sp_pwdp : "")) < 0
760    ) {
761        goto DO_UNLOCK;
762    }
763
764    for (i = 0; i < sizeof(_sp_off); i++) {
765        f = ld_format;
766        x = *(const long *)(((const char *) p) + _sp_off[i]);
767        if (x == -1) {
768            f += 3;
769        }
770        if (fprintf(stream, f, x) < 0) {
771            goto DO_UNLOCK;
772        }
773    }
774
775    if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
776        goto DO_UNLOCK;
777    }
778
779    if (fputc('\n', stream) > 0) {
780        rv = 0;
781    }
782
783DO_UNLOCK:
784    return rv;
785}
786#endif
787
788/**********************************************************************/
789/* Internal uClibc functions.                                         */
790/**********************************************************************/
791
792static const unsigned char pw_off[] ALIGN1 = {
793    offsetof(struct passwd, pw_name),       /* 0 */
794    offsetof(struct passwd, pw_passwd),     /* 1 */
795    offsetof(struct passwd, pw_uid),        /* 2 - not a char ptr */
796    offsetof(struct passwd, pw_gid),        /* 3 - not a char ptr */
797    offsetof(struct passwd, pw_gecos),      /* 4 */
798    offsetof(struct passwd, pw_dir),        /* 5 */
799    offsetof(struct passwd, pw_shell)       /* 6 */
800};
801
802static int bb__parsepwent(void *data, char *line)
803{
804    char *endptr;
805    char *p;
806    int i;
807
808    i = 0;
809    do {
810        p = ((char *) ((struct passwd *) data)) + pw_off[i];
811
812        if ((i & 6) ^ 2) {  /* i!=2 and i!=3 */
813            *((char **) p) = line;
814            if (i==6) {
815                return 0;
816            }
817            /* NOTE: glibc difference - glibc allows omission of
818             * ':' seperators after the gid field if all remaining
819             * entries are empty.  We require all separators. */
820            line = strchr(line, ':');
821            if (!line) {
822                break;
823            }
824        } else {
825            unsigned long t = strtoul(line, &endptr, 10);
826            /* Make sure we had at least one digit, and that the
827             * failing char is the next field seperator ':'.  See
828             * glibc difference note above. */
829            /* TODO: Also check for leading whitespace? */
830            if ((endptr == line) || (*endptr != ':')) {
831                break;
832            }
833            line = endptr;
834            if (i & 1) {        /* i == 3 -- gid */
835                *((gid_t *) p) = t;
836            } else {            /* i == 2 -- uid */
837                *((uid_t *) p) = t;
838            }
839        }
840
841        *line++ = 0;
842        ++i;
843    } while (1);
844
845    return -1;
846}
847
848/**********************************************************************/
849
850static const unsigned char gr_off[] ALIGN1 = {
851    offsetof(struct group, gr_name),        /* 0 */
852    offsetof(struct group, gr_passwd),      /* 1 */
853    offsetof(struct group, gr_gid)          /* 2 - not a char ptr */
854};
855
856static int bb__parsegrent(void *data, char *line)
857{
858    char *endptr;
859    char *p;
860    int i;
861    char **members;
862    char *end_of_buf;
863
864    end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
865    i = 0;
866    do {
867        p = ((char *) ((struct group *) data)) + gr_off[i];
868
869        if (i < 2) {
870            *((char **) p) = line;
871            line = strchr(line, ':');
872            if (!line) {
873                break;
874            }
875            *line++ = 0;
876            ++i;
877        } else {
878            *((gid_t *) p) = strtoul(line, &endptr, 10);
879
880            /* NOTE: glibc difference - glibc allows omission of the
881             * trailing colon when there is no member list.  We treat
882             * this as an error. */
883
884            /* Make sure we had at least one digit, and that the
885             * failing char is the next field seperator ':'.  See
886             * glibc difference note above. */
887            if ((endptr == line) || (*endptr != ':')) {
888                break;
889            }
890
891            i = 1;              /* Count terminating NULL ptr. */
892            p = endptr;
893
894            if (p[1]) { /* We have a member list to process. */
895                /* Overwrite the last ':' with a ',' before counting.
896                 * This allows us to test for initial ',' and adds
897                 * one ',' so that the ',' count equals the member
898                 * count. */
899                *p = ',';
900                do {
901                    /* NOTE: glibc difference - glibc allows and trims leading
902                     * (but not trailing) space.  We treat this as an error. */
903                    /* NOTE: glibc difference - glibc allows consecutive and
904                     * trailing commas, and ignores "empty string" users.  We
905                     * treat this as an error. */
906                    if (*p == ',') {
907                        ++i;
908                        *p = 0; /* nul-terminate each member string. */
909                        if (!*++p || (*p == ',') || isspace(*p)) {
910                            goto ERR;
911                        }
912                    }
913                } while (*++p);
914            }
915
916            /* Now align (p+1), rounding up. */
917            /* Assumes sizeof(char **) is a power of 2. */
918            members = (char **)( (((intptr_t) p) + sizeof(char **))
919                                 & ~((intptr_t)(sizeof(char **) - 1)) );
920
921            if (((char *)(members + i)) > end_of_buf) { /* No space. */
922                break;
923            }
924
925            ((struct group *) data)->gr_mem = members;
926
927            if (--i) {
928                p = endptr; /* Pointing to char prior to first member. */
929                do {
930                    *members++ = ++p;
931                    if (!--i) break;
932                    while (*++p) {}
933                } while (1);
934            }
935            *members = NULL;
936
937            return 0;
938        }
939    } while (1);
940
941 ERR:
942    return -1;
943}
944
945/**********************************************************************/
946
947#if ENABLE_USE_BB_SHADOW
948static const unsigned char sp_off[] ALIGN1 = {
949    offsetof(struct spwd, sp_namp),         /* 0 */
950    offsetof(struct spwd, sp_pwdp),         /* 1 */
951    offsetof(struct spwd, sp_lstchg),       /* 2 - not a char ptr */
952    offsetof(struct spwd, sp_min),          /* 3 - not a char ptr */
953    offsetof(struct spwd, sp_max),          /* 4 - not a char ptr */
954    offsetof(struct spwd, sp_warn),         /* 5 - not a char ptr */
955    offsetof(struct spwd, sp_inact),        /* 6 - not a char ptr */
956    offsetof(struct spwd, sp_expire),       /* 7 - not a char ptr */
957    offsetof(struct spwd, sp_flag)          /* 8 - not a char ptr */
958};
959
960static int bb__parsespent(void *data, char * line)
961{
962    char *endptr;
963    char *p;
964    int i;
965
966    i = 0;
967    do {
968        p = ((char *) ((struct spwd *) data)) + sp_off[i];
969        if (i < 2) {
970            *((char **) p) = line;
971            line = strchr(line, ':');
972            if (!line) {
973                break;
974            }
975        } else {
976            *((long *) p) = (long) strtoul(line, &endptr, 10);
977
978            if (endptr == line) {
979                *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
980            }
981
982            line = endptr;
983
984            if (i == 8) {
985                if (!*endptr) {
986                    return 0;
987                }
988                break;
989            }
990
991            if (*endptr != ':') {
992                break;
993            }
994
995        }
996
997        *line++ = 0;
998        ++i;
999    } while (1);
1000
1001    return EINVAL;
1002}
1003#endif
1004
1005/**********************************************************************/
1006
1007/* Reads until if EOF, or until if finds a line which fits in the buffer
1008 * and for which the parser function succeeds.
1009 *
1010 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
1011 */
1012
1013static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
1014                char *__restrict line_buff, size_t buflen, FILE *f)
1015{
1016    int line_len;
1017    int skip;
1018    int rv = ERANGE;
1019
1020    if (buflen < PWD_BUFFER_SIZE) {
1021        errno = rv;
1022    } else {
1023        skip = 0;
1024        do {
1025            if (!fgets(line_buff, buflen, f)) {
1026                if (feof(f)) {
1027                    rv = ENOENT;
1028                }
1029                break;
1030            }
1031
1032            line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
1033            if (line_buff[line_len] == '\n') {
1034                line_buff[line_len] = 0;
1035            } else if (line_len + 2 == buflen) { /* line too long */
1036                ++skip;
1037                continue;
1038            }
1039
1040            if (skip) {
1041                --skip;
1042                continue;
1043            }
1044
1045            /* NOTE: glibc difference - glibc strips leading whitespace from
1046             * records.  We do not allow leading whitespace. */
1047
1048            /* Skip empty lines, comment lines, and lines with leading
1049             * whitespace. */
1050            if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
1051                if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
1052                    /* The group entry parsing function needs to know where
1053                     * the end of the buffer is so that it can construct the
1054                     * group member ptr table. */
1055                    ((struct group *) data)->gr_name = line_buff + buflen;
1056                }
1057
1058                if (!parserfunc(data, line_buff)) {
1059                    rv = 0;
1060                    break;
1061                }
1062            }
1063        } while (1);
1064
1065    }
1066
1067    return rv;
1068}
Note: See TracBrowser for help on using the repository browser.