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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 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
RevLine 
[1770]1/* vi: set sw=4 ts=4: */
[821]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
[1770]46static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
47 char *__restrict line_buff, size_t buflen, FILE *f);
[821]48
[1770]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
[821]54
55/**********************************************************************/
[1770]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/**********************************************************************/
[821]116/* For the various fget??ent_r funcs, return
117 *
118 * 0: success
119 * ENOENT: end-of-file encountered
120 * ERANGE: buflen too small
[1770]121 * other error values possible. See bb__pgsreader.
[821]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
[1770]139 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, stream);
140 if (!rv) {
[821]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
[1770]155 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, stream);
156 if (!rv) {
[821]157 *result = resultbuf;
158 }
159
160 return rv;
161}
162
[1770]163#if ENABLE_USE_BB_SHADOW
[821]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
[1770]172 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, stream);
173 if (!rv) {
[821]174 *result = resultbuf;
175 }
176
177 return rv;
178}
[1770]179#endif
[821]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.
[1770]184 * TODO: audit & stop using these in bbox, they pull in static buffers */
[821]185/**********************************************************************/
186
[1770]187#if 0
[821]188struct passwd *fgetpwent(FILE *stream)
189{
[1770]190 struct statics *S;
191 struct passwd *resultbuf = RESULTBUF(fgetpwent);
192 char *buffer = BUFFER(fgetpwent);
[821]193 struct passwd *result;
194
[1770]195 fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result);
[821]196 return result;
197}
198
199struct group *fgetgrent(FILE *stream)
200{
[1770]201 struct statics *S;
202 struct group *resultbuf = RESULTBUF(fgetgrent);
203 char *buffer = BUFFER(fgetgrent);
[821]204 struct group *result;
205
[1770]206 fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result);
[821]207 return result;
208}
209#endif
210
[1770]211#if ENABLE_USE_BB_SHADOW
212#if 0
[821]213struct spwd *fgetspent(FILE *stream)
214{
[1770]215 struct statics *S;
216 struct spwd *resultbuf = RESULTBUF(fgetspent);
217 char *buffer = BUFFER(fgetspent);
[821]218 struct spwd *result;
219
[1770]220 fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result);
[821]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
[1770]245 rv = bb__parsespent(result_buf, buffer);
246 if (!rv) {
[821]247 *result = result_buf;
248 }
249
250 DONE:
251 return rv;
252}
[1770]253#endif
[821]254
255/**********************************************************************/
256
[1770]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
[821]263#include "pwd_grp_internal.c"
264
[1770]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
[821]271#include "pwd_grp_internal.c"
272
[1770]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
[821]280#include "pwd_grp_internal.c"
281#endif
282
[1770]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
[821]289#include "pwd_grp_internal.c"
290
[1770]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
[821]297#include "pwd_grp_internal.c"
298
299/**********************************************************************/
[1770]300/* TODO: audit & stop using these in bbox, they pull in static buffers */
[821]301
[1770]302/* This one has many users */
[821]303struct passwd *getpwuid(uid_t uid)
304{
[1770]305 struct statics *S;
306 struct passwd *resultbuf = RESULTBUF(getpwuid);
307 char *buffer = BUFFER(getpwuid);
[821]308 struct passwd *result;
309
[1770]310 getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result);
[821]311 return result;
312}
313
[1770]314/* This one has many users */
[821]315struct group *getgrgid(gid_t gid)
316{
[1770]317 struct statics *S;
318 struct group *resultbuf = RESULTBUF(getgrgid);
319 char *buffer = BUFFER(getgrgid);
[821]320 struct group *result;
321
[1770]322 getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result);
[821]323 return result;
324}
325
[1770]326#if 0 //ENABLE_USE_BB_SHADOW
[821]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;
[1770]340 rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp);
341 if (!rv) {
[821]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{
[1770]352 struct statics *S;
353 struct spwd *resultbuf = RESULTBUF(getspuid);
354 char *buffer = BUFFER(getspuid);
[821]355 struct spwd *result;
356
[1770]357 getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result);
[821]358 return result;
359}
360#endif
361
[1770]362/* This one has many users */
[821]363struct passwd *getpwnam(const char *name)
364{
[1770]365 struct statics *S;
366 struct passwd *resultbuf = RESULTBUF(getpwnam);
367 char *buffer = BUFFER(getpwnam);
[821]368 struct passwd *result;
369
[1770]370 getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result);
[821]371 return result;
372}
373
[1770]374/* This one has many users */
[821]375struct group *getgrnam(const char *name)
376{
[1770]377 struct statics *S;
378 struct group *resultbuf = RESULTBUF(getgrnam);
379 char *buffer = BUFFER(getgrnam);
[821]380 struct group *result;
381
[1770]382 getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result);
[821]383 return result;
384}
385
[1770]386#if 0 //ENABLE_USE_BB_SHADOW
[821]387struct spwd *getspnam(const char *name)
388{
[1770]389 struct statics *S;
390 struct spwd *resultbuf = RESULTBUF(getspnam);
391 char *buffer = BUFFER(getspnam);
[821]392 struct spwd *result;
393
[1770]394 getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result);
[821]395 return result;
396}
397#endif
398
[1770]399/* This one doesn't use static buffers */
[821]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) {
[1770]407 errno = EINVAL;
[821]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
[1770]425/* FIXME: we don't have such CONFIG_xx - ?! */
426
[821]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) {
[1770]467 pwf = fopen(_PATH_PASSWD, "r");
468 if (!pwf) {
[821]469 rv = errno;
470 goto ERR;
471 }
472 }
473
[1770]474 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
475 if (!rv) {
[821]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) {
[1770]514 grf = fopen(_PATH_GROUP, "r");
515 if (!grf) {
[821]516 rv = errno;
517 goto ERR;
518 }
519 }
520
[1770]521 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
522 if (!rv) {
[821]523 *result = resultbuf;
524 }
525
526 ERR:
527 UNLOCK;
528 return rv;
529}
530
[1770]531#if ENABLE_USE_BB_SHADOW
[821]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) {
[1770]561 spf = fopen(_PATH_SHADOW, "r");
562 if (!spf) {
[821]563 rv = errno;
564 goto ERR;
565 }
566 }
567
[1770]568 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
569 if (!rv) {
[821]570 *result = resultbuf;
571 }
572
573 ERR:
574 UNLOCK;
575 return rv;
576}
577#endif
578
[1770]579#if 0
[821]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
[1770]601#if 0 //ENABLE_USE_BB_SHADOW
[821]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. */
[1770]635 group_list = (gid_t *) malloc(8*sizeof(gid_t *));
636 if (group_list
637 && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
638 ) {
[821]639 *group_list = gid;
640 num_groups = 1;
641
[1770]642 while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
[821]643 assert(group.gr_mem); /* Must have at least a NULL terminator. */
644 if (group.gr_gid != gid) {
[1770]645 for (m = group.gr_mem; *m; m++) {
[821]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{
[1770]698 static const char format[] ALIGN1 = ",%s";
699
[821]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
[1770]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 */
[821]746};
747
748int putspent(const struct spwd *p, FILE *stream)
749{
[1770]750 static const char ld_format[] ALIGN1 = "%ld:";
751
[821]752 const char *f;
[1770]753 long x;
[821]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
[1770]760 ) {
[821]761 goto DO_UNLOCK;
762 }
763
[1770]764 for (i = 0; i < sizeof(_sp_off); i++) {
[821]765 f = ld_format;
[1770]766 x = *(const long *)(((const char *) p) + _sp_off[i]);
767 if (x == -1) {
[821]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}
[1770]786#endif
[821]787
788/**********************************************************************/
[1770]789/* Internal uClibc functions. */
[821]790/**********************************************************************/
791
[1770]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 */
[821]800};
801
[1770]802static int bb__parsepwent(void *data, char *line)
[821]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. */
[1770]820 line = strchr(line, ':');
821 if (!line) {
[821]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
[1770]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 */
[821]854};
855
[1770]856static int bb__parsegrent(void *data, char *line)
[821]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;
[1770]871 line = strchr(line, ':');
872 if (!line) {
[821]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
[1770]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 */
[821]958};
959
[1770]960static int bb__parsespent(void *data, char * line)
[821]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;
[1770]971 line = strchr(line, ':');
972 if (!line) {
[821]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}
[1770]1003#endif
[821]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
[1770]1013static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
[821]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) {
[1770]1021 errno = rv;
[821]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)) {
[1770]1051 if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
[821]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
[1770]1058 if (!parserfunc(data, line_buff)) {
[821]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.