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