1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include "libbb.h"
33
34struct const_passdb {
35 const char *filename;
36 char def[7 + 2*ENABLE_USE_BB_SHADOW];
37 uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW];
38 uint8_t numfields;
39 uint8_t size_of;
40};
41struct passdb {
42 const char *filename;
43 char def[7 + 2*ENABLE_USE_BB_SHADOW];
44 uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW];
45 uint8_t numfields;
46 uint8_t size_of;
47 FILE *fp;
48 char *malloced;
49};
50
51
52
53
54
55
56
57
58
59
60#define PW_DEF "SsIIsss"
61#define GR_DEF "SsIm"
62#define SP_DEF "Ssllllllr"
63
64static const struct const_passdb const_pw_db = {
65 _PATH_PASSWD, PW_DEF,
66 {
67 offsetof(struct passwd, pw_name),
68 offsetof(struct passwd, pw_passwd),
69 offsetof(struct passwd, pw_uid),
70 offsetof(struct passwd, pw_gid),
71 offsetof(struct passwd, pw_gecos),
72 offsetof(struct passwd, pw_dir),
73 offsetof(struct passwd, pw_shell)
74 },
75 sizeof(PW_DEF)-1, sizeof(struct passwd)
76};
77static const struct const_passdb const_gr_db = {
78 _PATH_GROUP, GR_DEF,
79 {
80 offsetof(struct group, gr_name),
81 offsetof(struct group, gr_passwd),
82 offsetof(struct group, gr_gid),
83 offsetof(struct group, gr_mem)
84 },
85 sizeof(GR_DEF)-1, sizeof(struct group)
86};
87#if ENABLE_USE_BB_SHADOW
88static const struct const_passdb const_sp_db = {
89 _PATH_SHADOW, SP_DEF,
90 {
91 offsetof(struct spwd, sp_namp),
92 offsetof(struct spwd, sp_pwdp),
93 offsetof(struct spwd, sp_lstchg),
94 offsetof(struct spwd, sp_min),
95 offsetof(struct spwd, sp_max),
96 offsetof(struct spwd, sp_warn),
97 offsetof(struct spwd, sp_inact),
98 offsetof(struct spwd, sp_expire),
99 offsetof(struct spwd, sp_flag)
100 },
101 sizeof(SP_DEF)-1, sizeof(struct spwd)
102};
103#endif
104
105
106struct statics {
107
108
109
110
111
112 struct passdb db[2 + ENABLE_USE_BB_SHADOW];
113 char *tokenize_end;
114 unsigned string_size;
115};
116
117static struct statics *ptr_to_statics;
118#define S (*ptr_to_statics)
119#define has_S (ptr_to_statics)
120
121#if ENABLE_FEATURE_CLEAN_UP
122static void free_static(void)
123{
124 free(S.db[0].malloced);
125 free(S.db[1].malloced);
126# if ENABLE_USE_BB_SHADOW
127 free(S.db[2].malloced);
128# endif
129 free(ptr_to_statics);
130}
131#endif
132
133static struct statics *get_S(void)
134{
135 if (!ptr_to_statics) {
136 ptr_to_statics = xzalloc(sizeof(S));
137 memcpy(&S.db[0], &const_pw_db, sizeof(const_pw_db));
138 memcpy(&S.db[1], &const_gr_db, sizeof(const_gr_db));
139#if ENABLE_USE_BB_SHADOW
140 memcpy(&S.db[2], &const_sp_db, sizeof(const_sp_db));
141#endif
142#if ENABLE_FEATURE_CLEAN_UP
143 atexit(free_static);
144#endif
145 }
146 return ptr_to_statics;
147}
148
149
150
151
152
153
154
155
156
157static int tokenize(char *buffer, int ch)
158{
159 char *p = buffer;
160 char *s = p;
161 int num_fields = 0;
162
163 for (;;) {
164 if (isblank(*s)) {
165 overlapping_strcpy(s, skip_whitespace(s));
166 }
167 if (*p == ch || *p == '\0') {
168 char *end = p;
169 while (p != s && isblank(p[-1]))
170 p--;
171 if (p != end)
172 overlapping_strcpy(p, end);
173 num_fields++;
174 if (*end == '\0') {
175 S.tokenize_end = p + 1;
176 return num_fields;
177 }
178 *p = '\0';
179 s = p + 1;
180 }
181 p++;
182 }
183}
184
185
186
187
188static char *parse_common(FILE *fp, struct passdb *db,
189 const char *key, int field_pos)
190{
191 char *buf;
192
193 while ((buf = xmalloc_fgetline(fp)) != NULL) {
194 int n;
195 char *field;
196
197
198 if (buf[0] == '\0' || buf[0] == '#')
199 goto free_and_next;
200 if (tokenize(buf, ':') != db->numfields) {
201
202 bb_error_msg("%s: bad record", db->filename);
203 goto free_and_next;
204 }
205
206 if (field_pos == -1) {
207
208 break;
209 }
210
211
212
213 n = field_pos;
214 field = buf;
215 while (n) {
216 n--;
217 field += strlen(field) + 1;
218 }
219 if (strcmp(key, field) == 0) {
220
221 break;
222 }
223 free_and_next:
224 free(buf);
225 }
226
227 S.string_size = S.tokenize_end - buf;
228
229
230
231
232
233
234 if (buf && db->numfields == sizeof(GR_DEF)-1) {
235 int cnt = 3;
236 char *p = buf;
237 while (p < S.tokenize_end)
238 if (*p++ == ',')
239 cnt++;
240 S.string_size += cnt * sizeof(char*);
241
242 buf = xrealloc(buf, S.string_size);
243 }
244
245 return buf;
246}
247
248static char *parse_file(struct passdb *db,
249 const char *key, int field_pos)
250{
251 char *buf = NULL;
252 FILE *fp = fopen_for_read(db->filename);
253
254 if (fp) {
255 buf = parse_common(fp, db, key, field_pos);
256 fclose(fp);
257 }
258 return buf;
259}
260
261
262static void *convert_to_struct(struct passdb *db,
263 char *buffer, void *result)
264{
265 const char *def = db->def;
266 const uint8_t *off = db->off;
267
268
269 memset(result, 0, db->size_of);
270
271 for (;;) {
272 void *member = (char*)result + (*off++);
273
274 if ((*def | 0x20) == 's') {
275 *(char **)member = (char*)buffer;
276 if (!buffer[0] && (*def == 'S')) {
277 errno = EINVAL;
278 }
279 }
280 if (*def == 'I') {
281 *(int *)member = bb_strtou(buffer, NULL, 10);
282 }
283#if ENABLE_USE_BB_SHADOW
284 if (*def == 'l') {
285 long n = -1;
286 if (buffer[0])
287 n = bb_strtol(buffer, NULL, 10);
288 *(long *)member = n;
289 }
290#endif
291 if (*def == 'm') {
292 char **members;
293 int i = tokenize(buffer, ',');
294
295
296
297
298
299
300 members = (char **)
301 ( ((intptr_t)S.tokenize_end + sizeof(members[0]))
302 & -(intptr_t)sizeof(members[0])
303 );
304 ((struct group *)result)->gr_mem = members;
305 while (--i >= 0) {
306 if (buffer[0]) {
307 *members++ = buffer;
308
309 }
310 buffer += strlen(buffer) + 1;
311 }
312 *members = NULL;
313 }
314
315
316 def++;
317 if ((unsigned char)*def <= (unsigned char)' ')
318 break;
319 buffer += strlen(buffer) + 1;
320 }
321
322 if (errno)
323 result = NULL;
324 return result;
325}
326
327static int massage_data_for_r_func(struct passdb *db,
328 char *buffer, size_t buflen,
329 void **result,
330 char *buf)
331{
332 void *result_buf = *result;
333 *result = NULL;
334 if (buf) {
335 if (S.string_size > buflen) {
336 errno = ERANGE;
337 } else {
338 memcpy(buffer, buf, S.string_size);
339 *result = convert_to_struct(db, buffer, result_buf);
340 }
341 free(buf);
342 }
343
344
345
346
347 return errno;
348}
349
350static void* massage_data_for_non_r_func(struct passdb *db, char *buf)
351{
352 if (!buf)
353 return NULL;
354
355 free(db->malloced);
356
357
358
359
360
361 db->malloced = buf = xrealloc(buf, db->size_of + S.string_size);
362 memmove(buf + db->size_of, buf, S.string_size);
363 return convert_to_struct(db, buf + db->size_of, buf);
364}
365
366
367
368static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos,
369 char *buffer, size_t buflen,
370 void *result)
371{
372 char *buf;
373 struct passdb *db = &get_S()->db[db_and_field_pos >> 2];
374
375 buf = parse_file(db, name, 0 );
376
377
378
379 return massage_data_for_r_func(db, buffer, buflen, result, buf);
380}
381
382int FAST_FUNC getpwnam_r(const char *name, struct passwd *struct_buf,
383 char *buffer, size_t buflen,
384 struct passwd **result)
385{
386
387
388
389
390 *result = struct_buf;
391 return getXXnam_r(name, (0 << 2) + 0, buffer, buflen, result);
392}
393#if ENABLE_USE_BB_SHADOW
394int FAST_FUNC getspnam_r(const char *name, struct spwd *struct_buf, char *buffer, size_t buflen,
395 struct spwd **result)
396{
397 *result = struct_buf;
398 return getXXnam_r(name, (2 << 2) + 0, buffer, buflen, result);
399}
400#endif
401
402#ifdef UNUSED
403
404
405static int FAST_FUNC getXXent_r(uintptr_t db_idx, char *buffer, size_t buflen,
406 void *result)
407{
408 char *buf;
409 struct passdb *db = &get_S()->db[db_idx];
410
411 if (!db->fp) {
412 db->fp = fopen_for_read(db->filename);
413 if (!db->fp) {
414 return errno;
415 }
416 close_on_exec_on(fileno(db->fp));
417 }
418
419 buf = parse_common(db->fp, db, NULL, -1);
420 if (!buf && !errno)
421 errno = ENOENT;
422 return massage_data_for_r_func(db, buffer, buflen, result, buf);
423}
424
425int FAST_FUNC getpwent_r(struct passwd *struct_buf, char *buffer, size_t buflen,
426 struct passwd **result)
427{
428 *result = struct_buf;
429 return getXXent_r(0, buffer, buflen, result);
430}
431#endif
432
433
434
435static void* FAST_FUNC getXXent(uintptr_t db_idx)
436{
437 char *buf;
438 struct passdb *db = &get_S()->db[db_idx];
439
440 if (!db->fp) {
441 db->fp = fopen_for_read(db->filename);
442 if (!db->fp) {
443 return NULL;
444 }
445 close_on_exec_on(fileno(db->fp));
446 }
447
448 buf = parse_common(db->fp, db, NULL, -1);
449 return massage_data_for_non_r_func(db, buf);
450}
451
452struct passwd* FAST_FUNC getpwent(void)
453{
454 return getXXent(0);
455}
456
457
458
459static void* FAST_FUNC getXXnam(const char *name, unsigned db_and_field_pos)
460{
461 char *buf;
462 struct passdb *db = &get_S()->db[db_and_field_pos >> 2];
463
464 buf = parse_file(db, name, db_and_field_pos & 3);
465 return massage_data_for_non_r_func(db, buf);
466}
467
468struct passwd* FAST_FUNC getpwnam(const char *name)
469{
470 return getXXnam(name, (0 << 2) + 0);
471}
472struct group* FAST_FUNC getgrnam(const char *name)
473{
474 return getXXnam(name, (1 << 2) + 0);
475}
476struct passwd* FAST_FUNC getpwuid(uid_t id)
477{
478 return getXXnam(utoa(id), (0 << 2) + 2);
479}
480struct group* FAST_FUNC getgrgid(gid_t id)
481{
482 return getXXnam(utoa(id), (1 << 2) + 2);
483}
484
485
486
487void FAST_FUNC endpwent(void)
488{
489 if (has_S && S.db[0].fp) {
490 fclose(S.db[0].fp);
491 S.db[0].fp = NULL;
492 }
493}
494void FAST_FUNC setpwent(void)
495{
496 if (has_S && S.db[0].fp) {
497 rewind(S.db[0].fp);
498 }
499}
500void FAST_FUNC endgrent(void)
501{
502 if (has_S && S.db[1].fp) {
503 fclose(S.db[1].fp);
504 S.db[1].fp = NULL;
505 }
506}
507
508
509
510static gid_t* FAST_FUNC getgrouplist_internal(int *ngroups_ptr,
511 const char *user, gid_t gid)
512{
513 FILE *fp;
514 gid_t *group_list;
515 int ngroups;
516
517
518 group_list = xzalloc(8 * sizeof(group_list[0]));
519 group_list[0] = gid;
520 ngroups = 1;
521
522 fp = fopen_for_read(_PATH_GROUP);
523 if (fp) {
524 struct passdb *db = &get_S()->db[1];
525 char *buf;
526 while ((buf = parse_common(fp, db, NULL, -1)) != NULL) {
527 char **m;
528 struct group group;
529 if (!convert_to_struct(db, buf, &group))
530 goto next;
531 if (group.gr_gid == gid)
532 goto next;
533 for (m = group.gr_mem; *m; m++) {
534 if (strcmp(*m, user) != 0)
535 continue;
536 group_list = xrealloc_vector(group_list, 3, ngroups);
537 group_list[ngroups++] = group.gr_gid;
538 goto next;
539 }
540 next:
541 free(buf);
542 }
543 fclose(fp);
544 }
545 *ngroups_ptr = ngroups;
546 return group_list;
547}
548
549int FAST_FUNC initgroups(const char *user, gid_t gid)
550{
551 int ngroups;
552 gid_t *group_list = getgrouplist_internal(&ngroups, user, gid);
553
554 ngroups = setgroups(ngroups, group_list);
555 free(group_list);
556 return ngroups;
557}
558
559int FAST_FUNC getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
560{
561 int ngroups_old = *ngroups;
562 gid_t *group_list = getgrouplist_internal(ngroups, user, gid);
563
564 if (*ngroups <= ngroups_old) {
565 ngroups_old = *ngroups;
566 memcpy(groups, group_list, ngroups_old * sizeof(groups[0]));
567 } else {
568 ngroups_old = -1;
569 }
570 free(group_list);
571 return ngroups_old;
572}
573