blob: 2eb9d9dd1d0890a4d9946aa5708d0c19ad6e1e71 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02002/* Copyright (C) 2003 Manuel Novoa III
Eric Andersen9615a082004-07-15 12:53:49 +00003 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02004 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersen9615a082004-07-15 12:53:49 +00005 */
6
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007/* Nov 6, 2003 Initial version.
Eric Andersen9615a082004-07-15 12:53:49 +00008 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02009 * NOTE: This implementation is quite strict about requiring all
Eric Andersen9615a082004-07-15 12:53:49 +000010 * 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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020014 * TODO:
Rob Landley06ec8cf2006-03-03 19:02:50 +000015 * Move to dynamic allocation of (currently statically allocated)
Eric Andersen9615a082004-07-15 12:53:49 +000016 * buffers; especially for the group-related functions since
17 * large group member lists will cause error returns.
Eric Andersen9615a082004-07-15 12:53:49 +000018 */
19
Rob Landleyea224be2006-06-18 20:20:07 +000020#include "libbb.h"
Eric Andersen9615a082004-07-15 12:53:49 +000021#include <assert.h>
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000022
Eric Andersen9615a082004-07-15 12:53:49 +000023/**********************************************************************/
Rob Landley06ec8cf2006-03-03 19:02:50 +000024/* Sizes for statically allocated buffers. */
Eric Andersen9615a082004-07-15 12:53:49 +000025
26/* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
27 * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
28#define PWD_BUFFER_SIZE 256
29#define GRP_BUFFER_SIZE 256
30
31/**********************************************************************/
32/* Prototypes for internal functions. */
33
Denys Vlasenko17fcd722010-03-31 12:37:43 +020034static int bb__pgsreader(
35 int FAST_FUNC (*parserfunc)(void *d, char *line),
36 void *data,
37 char *__restrict line_buff,
38 size_t buflen,
39 FILE *f);
Eric Andersen9615a082004-07-15 12:53:49 +000040
Denys Vlasenko17fcd722010-03-31 12:37:43 +020041static int FAST_FUNC bb__parsepwent(void *pw, char *line);
42static int FAST_FUNC bb__parsegrent(void *gr, char *line);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000043#if ENABLE_USE_BB_SHADOW
Denys Vlasenko17fcd722010-03-31 12:37:43 +020044static int FAST_FUNC bb__parsespent(void *sp, char *line);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000045#endif
46
Eric Andersen9615a082004-07-15 12:53:49 +000047/**********************************************************************/
Denis Vlasenko2c91efb2007-06-18 10:08:27 +000048/* We avoid having big global data. */
49
50struct statics {
51 /* Smaller things first */
52 struct passwd getpwuid_resultbuf;
53 struct group getgrgid_resultbuf;
54 struct passwd getpwnam_resultbuf;
55 struct group getgrnam_resultbuf;
56
57 char getpwuid_buffer[PWD_BUFFER_SIZE];
58 char getgrgid_buffer[GRP_BUFFER_SIZE];
59 char getpwnam_buffer[PWD_BUFFER_SIZE];
60 char getgrnam_buffer[GRP_BUFFER_SIZE];
61#if 0
62 struct passwd fgetpwent_resultbuf;
63 struct group fgetgrent_resultbuf;
64 struct spwd fgetspent_resultbuf;
65 char fgetpwent_buffer[PWD_BUFFER_SIZE];
66 char fgetgrent_buffer[GRP_BUFFER_SIZE];
67 char fgetspent_buffer[PWD_BUFFER_SIZE];
68#endif
69#if 0 //ENABLE_USE_BB_SHADOW
70 struct spwd getspuid_resultbuf;
71 struct spwd getspnam_resultbuf;
72 char getspuid_buffer[PWD_BUFFER_SIZE];
73 char getspnam_buffer[PWD_BUFFER_SIZE];
74#endif
75// Not converted - too small to bother
76//pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
77//FILE *pwf /*= NULL*/;
78//FILE *grf /*= NULL*/;
79//FILE *spf /*= NULL*/;
80#if 0
81 struct passwd getpwent_pwd;
82 struct group getgrent_gr;
83 char getpwent_line_buff[PWD_BUFFER_SIZE];
84 char getgrent_line_buff[GRP_BUFFER_SIZE];
85#endif
86#if 0 //ENABLE_USE_BB_SHADOW
87 struct spwd getspent_spwd;
88 struct spwd sgetspent_spwd;
89 char getspent_line_buff[PWD_BUFFER_SIZE];
90 char sgetspent_line_buff[PWD_BUFFER_SIZE];
91#endif
92};
93
94static struct statics *ptr_to_statics;
95
96static struct statics *get_S(void)
97{
98 if (!ptr_to_statics)
99 ptr_to_statics = xzalloc(sizeof(*ptr_to_statics));
100 return ptr_to_statics;
101}
102
103/* Always use in this order, get_S() must be called first */
104#define RESULTBUF(name) &((S = get_S())->name##_resultbuf)
105#define BUFFER(name) (S->name##_buffer)
106
107/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000108/* For the various fget??ent_r funcs, return
109 *
110 * 0: success
111 * ENOENT: end-of-file encountered
112 * ERANGE: buflen too small
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000113 * other error values possible. See bb__pgsreader.
Eric Andersen9615a082004-07-15 12:53:49 +0000114 *
115 * Also, *result == resultbuf on success and NULL on failure.
116 *
117 * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
118 * We do not, as it really isn't an error if we reach the end-of-file.
119 * Doing so is analogous to having fgetc() set errno on EOF.
120 */
121/**********************************************************************/
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000122
Eric Andersen9615a082004-07-15 12:53:49 +0000123int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
124 char *__restrict buffer, size_t buflen,
125 struct passwd **__restrict result)
126{
127 int rv;
128
129 *result = NULL;
130
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000131 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000132 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000133 *result = resultbuf;
134 }
135
136 return rv;
137}
138
Eric Andersen9615a082004-07-15 12:53:49 +0000139int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
140 char *__restrict buffer, size_t buflen,
141 struct group **__restrict result)
142{
143 int rv;
144
145 *result = NULL;
146
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000147 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000148 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000149 *result = resultbuf;
150 }
151
152 return rv;
153}
154
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000155#if ENABLE_USE_BB_SHADOW
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200156#ifdef UNUSED_FOR_NOW
Eric Andersen9615a082004-07-15 12:53:49 +0000157int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
158 char *__restrict buffer, size_t buflen,
159 struct spwd **__restrict result)
160{
161 int rv;
162
163 *result = NULL;
164
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000165 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000166 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000167 *result = resultbuf;
168 }
169
170 return rv;
171}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000172#endif
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200173#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000174
Eric Andersen9615a082004-07-15 12:53:49 +0000175/**********************************************************************/
176/* For the various fget??ent funcs, return NULL on failure and a
Rob Landley06ec8cf2006-03-03 19:02:50 +0000177 * pointer to the appropriate struct (statically allocated) on success.
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000178 * TODO: audit & stop using these in bbox, they pull in static buffers */
Eric Andersen9615a082004-07-15 12:53:49 +0000179/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000180
Denys Vlasenko55301292010-03-31 12:38:17 +0200181#ifdef UNUSED_SINCE_WE_AVOID_STATIC_BUFS
Eric Andersen9615a082004-07-15 12:53:49 +0000182struct passwd *fgetpwent(FILE *stream)
183{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000184 struct statics *S;
185 struct passwd *resultbuf = RESULTBUF(fgetpwent);
186 char *buffer = BUFFER(fgetpwent);
Eric Andersen9615a082004-07-15 12:53:49 +0000187 struct passwd *result;
188
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000189 fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000190 return result;
191}
192
Eric Andersen9615a082004-07-15 12:53:49 +0000193struct group *fgetgrent(FILE *stream)
194{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000195 struct statics *S;
196 struct group *resultbuf = RESULTBUF(fgetgrent);
197 char *buffer = BUFFER(fgetgrent);
Eric Andersen9615a082004-07-15 12:53:49 +0000198 struct group *result;
199
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000200 fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000201 return result;
202}
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000203#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000204
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000205#if ENABLE_USE_BB_SHADOW
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200206#ifdef UNUSED_SINCE_WE_AVOID_STATIC_BUFS
Eric Andersen9615a082004-07-15 12:53:49 +0000207struct spwd *fgetspent(FILE *stream)
208{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000209 struct statics *S;
210 struct spwd *resultbuf = RESULTBUF(fgetspent);
211 char *buffer = BUFFER(fgetspent);
Eric Andersen9615a082004-07-15 12:53:49 +0000212 struct spwd *result;
213
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000214 fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000215 return result;
216}
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000217#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000218
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200219#ifdef UNUSED_FOR_NOW
Eric Andersen9615a082004-07-15 12:53:49 +0000220int sgetspent_r(const char *string, struct spwd *result_buf,
221 char *buffer, size_t buflen, struct spwd **result)
222{
223 int rv = ERANGE;
224
225 *result = NULL;
226
227 if (buflen < PWD_BUFFER_SIZE) {
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200228 DO_ERANGE:
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200229 errno = rv;
Eric Andersen9615a082004-07-15 12:53:49 +0000230 goto DONE;
231 }
232
233 if (string != buffer) {
234 if (strlen(string) >= buflen) {
235 goto DO_ERANGE;
236 }
237 strcpy(buffer, string);
238 }
239
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000240 rv = bb__parsespent(result_buf, buffer);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000241 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000242 *result = result_buf;
243 }
244
245 DONE:
246 return rv;
247}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000248#endif
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200249#endif /* ENABLE_USE_BB_SHADOW */
Eric Andersen9615a082004-07-15 12:53:49 +0000250
Eric Andersen9615a082004-07-15 12:53:49 +0000251/**********************************************************************/
252
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000253#define GETXXKEY_R_FUNC getpwnam_r
254#define GETXXKEY_R_PARSER bb__parsepwent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000255#define GETXXKEY_R_ENTTYPE struct passwd
256#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000257#define GETXXKEY_R_KEYTYPE const char *__restrict
258#define GETXXKEY_R_PATHNAME _PATH_PASSWD
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000259#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000260
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000261#define GETXXKEY_R_FUNC getgrnam_r
262#define GETXXKEY_R_PARSER bb__parsegrent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000263#define GETXXKEY_R_ENTTYPE struct group
264#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000265#define GETXXKEY_R_KEYTYPE const char *__restrict
266#define GETXXKEY_R_PATHNAME _PATH_GROUP
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000267#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000268
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000269#if ENABLE_USE_BB_SHADOW
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000270#define GETXXKEY_R_FUNC getspnam_r
271#define GETXXKEY_R_PARSER bb__parsespent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000272#define GETXXKEY_R_ENTTYPE struct spwd
273#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000274#define GETXXKEY_R_KEYTYPE const char *__restrict
275#define GETXXKEY_R_PATHNAME _PATH_SHADOW
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000276#include "pwd_grp_internal.c"
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000277#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000278
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000279#define GETXXKEY_R_FUNC getpwuid_r
280#define GETXXKEY_R_PARSER bb__parsepwent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000281#define GETXXKEY_R_ENTTYPE struct passwd
282#define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000283#define GETXXKEY_R_KEYTYPE uid_t
284#define GETXXKEY_R_PATHNAME _PATH_PASSWD
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000285#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000286
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000287#define GETXXKEY_R_FUNC getgrgid_r
288#define GETXXKEY_R_PARSER bb__parsegrent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000289#define GETXXKEY_R_ENTTYPE struct group
290#define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000291#define GETXXKEY_R_KEYTYPE gid_t
292#define GETXXKEY_R_PATHNAME _PATH_GROUP
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000293#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000294
295/**********************************************************************/
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000296/* TODO: audit & stop using these in bbox, they pull in static buffers */
Eric Andersen9615a082004-07-15 12:53:49 +0000297
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000298/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000299struct passwd *getpwuid(uid_t uid)
300{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000301 struct statics *S;
302 struct passwd *resultbuf = RESULTBUF(getpwuid);
303 char *buffer = BUFFER(getpwuid);
Eric Andersen9615a082004-07-15 12:53:49 +0000304 struct passwd *result;
305
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000306 getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000307 return result;
308}
309
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000310/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000311struct group *getgrgid(gid_t gid)
312{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000313 struct statics *S;
314 struct group *resultbuf = RESULTBUF(getgrgid);
315 char *buffer = BUFFER(getgrgid);
Eric Andersen9615a082004-07-15 12:53:49 +0000316 struct group *result;
317
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000318 getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000319 return result;
320}
321
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000322#if 0 //ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000323/* This function is non-standard and is currently not built. It seems
324 * to have been created as a reentrant version of the non-standard
325 * functions getspuid. Why getspuid was added, I do not know. */
Eric Andersen9615a082004-07-15 12:53:49 +0000326int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
327 char *__restrict buffer, size_t buflen,
328 struct spwd **__restrict result)
329{
330 int rv;
331 struct passwd *pp;
332 struct passwd password;
333 char pwd_buff[PWD_BUFFER_SIZE];
334
335 *result = NULL;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000336 rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp);
337 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000338 rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
339 }
340
341 return rv;
342}
343
Eric Andersen9615a082004-07-15 12:53:49 +0000344/* This function is non-standard and is currently not built.
345 * Why it was added, I do not know. */
Eric Andersen9615a082004-07-15 12:53:49 +0000346struct spwd *getspuid(uid_t uid)
347{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000348 struct statics *S;
349 struct spwd *resultbuf = RESULTBUF(getspuid);
350 char *buffer = BUFFER(getspuid);
Eric Andersen9615a082004-07-15 12:53:49 +0000351 struct spwd *result;
352
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000353 getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000354 return result;
355}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000356#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000357
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000358/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000359struct passwd *getpwnam(const char *name)
360{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000361 struct statics *S;
362 struct passwd *resultbuf = RESULTBUF(getpwnam);
363 char *buffer = BUFFER(getpwnam);
Eric Andersen9615a082004-07-15 12:53:49 +0000364 struct passwd *result;
365
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000366 getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000367 return result;
368}
369
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000370/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000371struct group *getgrnam(const char *name)
372{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000373 struct statics *S;
374 struct group *resultbuf = RESULTBUF(getgrnam);
375 char *buffer = BUFFER(getgrnam);
Eric Andersen9615a082004-07-15 12:53:49 +0000376 struct group *result;
377
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000378 getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000379 return result;
380}
381
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000382#if 0 //ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000383struct spwd *getspnam(const char *name)
384{
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000385 struct statics *S;
386 struct spwd *resultbuf = RESULTBUF(getspnam);
387 char *buffer = BUFFER(getspnam);
Eric Andersen9615a082004-07-15 12:53:49 +0000388 struct spwd *result;
389
Denis Vlasenko2c91efb2007-06-18 10:08:27 +0000390 getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result);
Eric Andersen9615a082004-07-15 12:53:49 +0000391 return result;
392}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000393#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000394
Eric Andersen9615a082004-07-15 12:53:49 +0000395/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000396
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000397/* FIXME: we don't have such CONFIG_xx - ?! */
398
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000399#if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
400static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
401# define LOCK pthread_mutex_lock(&mylock)
402# define UNLOCK pthread_mutex_unlock(&mylock);
403#else
404# define LOCK ((void) 0)
405# define UNLOCK ((void) 0)
406#endif
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000407
Eric Andersen9615a082004-07-15 12:53:49 +0000408static FILE *pwf /*= NULL*/;
409void setpwent(void)
410{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000411 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000412 if (pwf) {
413 rewind(pwf);
414 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000415 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000416}
417
418void endpwent(void)
419{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000420 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000421 if (pwf) {
422 fclose(pwf);
423 pwf = NULL;
424 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000425 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000426}
427
428
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000429int getpwent_r(struct passwd *__restrict resultbuf,
Eric Andersen9615a082004-07-15 12:53:49 +0000430 char *__restrict buffer, size_t buflen,
431 struct passwd **__restrict result)
432{
433 int rv;
434
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000435 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000436 *result = NULL; /* In case of error... */
437
438 if (!pwf) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000439 pwf = fopen_for_read(_PATH_PASSWD);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000440 if (!pwf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000441 rv = errno;
442 goto ERR;
443 }
444 }
445
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000446 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000447 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000448 *result = resultbuf;
449 }
450
451 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000452 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000453 return rv;
454}
455
Eric Andersen9615a082004-07-15 12:53:49 +0000456static FILE *grf /*= NULL*/;
457void setgrent(void)
458{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000459 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000460 if (grf) {
461 rewind(grf);
462 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000463 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000464}
465
466void endgrent(void)
467{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000468 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000469 if (grf) {
470 fclose(grf);
471 grf = NULL;
472 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000473 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000474}
475
476int getgrent_r(struct group *__restrict resultbuf,
477 char *__restrict buffer, size_t buflen,
478 struct group **__restrict result)
479{
480 int rv;
481
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000482 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000483 *result = NULL; /* In case of error... */
484
485 if (!grf) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000486 grf = fopen_for_read(_PATH_GROUP);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000487 if (!grf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000488 rv = errno;
489 goto ERR;
490 }
491 }
492
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000493 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000494 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000495 *result = resultbuf;
496 }
497
498 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000499 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000500 return rv;
501}
502
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200503#ifdef UNUSED_FOR_NOW
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000504#if ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000505static FILE *spf /*= NULL*/;
506void setspent(void)
507{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000508 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000509 if (spf) {
510 rewind(spf);
511 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000512 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000513}
514
515void endspent(void)
516{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000517 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000518 if (spf) {
519 fclose(spf);
520 spf = NULL;
521 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000522 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000523}
524
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000525int getspent_r(struct spwd *resultbuf, char *buffer,
Eric Andersen9615a082004-07-15 12:53:49 +0000526 size_t buflen, struct spwd **result)
527{
528 int rv;
529
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000530 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000531 *result = NULL; /* In case of error... */
532
533 if (!spf) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000534 spf = fopen_for_read(_PATH_SHADOW);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000535 if (!spf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000536 rv = errno;
537 goto ERR;
538 }
539 }
540
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000541 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000542 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000543 *result = resultbuf;
544 }
545
546 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000547 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000548 return rv;
549}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000550#endif
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200551#endif /* UNUSED_FOR_NOW */
Eric Andersen9615a082004-07-15 12:53:49 +0000552
Denys Vlasenko55301292010-03-31 12:38:17 +0200553#ifdef UNUSED_SINCE_WE_AVOID_STATIC_BUFS
Eric Andersen9615a082004-07-15 12:53:49 +0000554struct passwd *getpwent(void)
555{
556 static char line_buff[PWD_BUFFER_SIZE];
557 static struct passwd pwd;
558 struct passwd *result;
559
560 getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
561 return result;
562}
563
Eric Andersen9615a082004-07-15 12:53:49 +0000564struct group *getgrent(void)
565{
566 static char line_buff[GRP_BUFFER_SIZE];
567 static struct group gr;
568 struct group *result;
569
570 getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
571 return result;
572}
573
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200574#if ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000575struct spwd *getspent(void)
576{
577 static char line_buff[PWD_BUFFER_SIZE];
578 static struct spwd spwd;
579 struct spwd *result;
580
581 getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
582 return result;
583}
584
Eric Andersen9615a082004-07-15 12:53:49 +0000585struct spwd *sgetspent(const char *string)
586{
587 static char line_buff[PWD_BUFFER_SIZE];
588 static struct spwd spwd;
589 struct spwd *result;
590
591 sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
592 return result;
593}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000594#endif
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200595#endif /* UNUSED_SINCE_WE_AVOID_STATIC_BUFS */
Eric Andersen9615a082004-07-15 12:53:49 +0000596
Denis Vlasenko22284262008-09-18 00:56:24 +0000597static gid_t *getgrouplist_internal(int *ngroups_ptr, const char *user, gid_t gid)
Eric Andersen9615a082004-07-15 12:53:49 +0000598{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000599 FILE *grfile;
Eric Andersen9615a082004-07-15 12:53:49 +0000600 gid_t *group_list;
Denis Vlasenko22284262008-09-18 00:56:24 +0000601 int ngroups;
Eric Andersen9615a082004-07-15 12:53:49 +0000602 struct group group;
603 char buff[PWD_BUFFER_SIZE];
604
Denis Vlasenko22284262008-09-18 00:56:24 +0000605 /* We alloc space for 8 gids at a time. */
606 group_list = xmalloc(8 * sizeof(group_list[0]));
607 group_list[0] = gid;
608 ngroups = 1;
609
Denis Vlasenko5415c852008-07-21 23:05:26 +0000610 grfile = fopen_for_read(_PATH_GROUP);
Denis Vlasenko22284262008-09-18 00:56:24 +0000611 if (grfile) {
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000612 while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
Denis Vlasenko22284262008-09-18 00:56:24 +0000613 char **m;
Eric Andersen9615a082004-07-15 12:53:49 +0000614 assert(group.gr_mem); /* Must have at least a NULL terminator. */
Denis Vlasenko22284262008-09-18 00:56:24 +0000615 if (group.gr_gid == gid)
616 continue;
617 for (m = group.gr_mem; *m; m++) {
618 if (strcmp(*m, user) != 0)
619 continue;
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200620 group_list = xrealloc_vector(group_list, /*8=2^3:*/ 3, ngroups);
Denis Vlasenko22284262008-09-18 00:56:24 +0000621 group_list[ngroups++] = group.gr_gid;
622 break;
Eric Andersen9615a082004-07-15 12:53:49 +0000623 }
624 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000625 fclose(grfile);
Eric Andersen9615a082004-07-15 12:53:49 +0000626 }
Denis Vlasenko22284262008-09-18 00:56:24 +0000627 *ngroups_ptr = ngroups;
628 return group_list;
629}
Eric Andersen9615a082004-07-15 12:53:49 +0000630
Denis Vlasenko22284262008-09-18 00:56:24 +0000631int initgroups(const char *user, gid_t gid)
632{
633 int ngroups;
634 gid_t *group_list = getgrouplist_internal(&ngroups, user, gid);
635
Denis Vlasenko22284262008-09-18 00:56:24 +0000636 ngroups = setgroups(ngroups, group_list);
637 free(group_list);
638 return ngroups;
639}
640
Denis Vlasenko22284262008-09-18 00:56:24 +0000641int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
642{
643 int ngroups_old = *ngroups;
644 gid_t *group_list = getgrouplist_internal(ngroups, user, gid);
645
646 if (*ngroups <= ngroups_old) {
647 ngroups_old = *ngroups;
648 memcpy(groups, group_list, ngroups_old * sizeof(groups[0]));
649 } else {
650 ngroups_old = -1;
651 }
652 free(group_list);
653 return ngroups_old;
Eric Andersen9615a082004-07-15 12:53:49 +0000654}
655
Denys Vlasenko55301292010-03-31 12:38:17 +0200656#ifdef UNUSED_SINCE_WE_AVOID_STATIC_BUFS
Eric Andersen9615a082004-07-15 12:53:49 +0000657int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
658{
659 int rv = -1;
660
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200661#if 0
662 /* glibc does this check */
Eric Andersen9615a082004-07-15 12:53:49 +0000663 if (!p || !f) {
Denis Vlasenko92305822008-03-20 15:12:58 +0000664 errno = EINVAL;
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200665 return rv;
666 }
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200667#endif
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200668
669 /* No extra thread locking is needed above what fprintf does. */
670 if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
671 p->pw_name, p->pw_passwd,
672 (unsigned long)(p->pw_uid),
673 (unsigned long)(p->pw_gid),
674 p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
675 ) {
676 rv = 0;
Eric Andersen9615a082004-07-15 12:53:49 +0000677 }
678
679 return rv;
680}
681
Eric Andersen9615a082004-07-15 12:53:49 +0000682int putgrent(const struct group *__restrict p, FILE *__restrict f)
683{
Eric Andersen9615a082004-07-15 12:53:49 +0000684 int rv = -1;
685
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200686#if 0
687 /* glibc does this check */
688 if (!p || !f) {
Denis Vlasenko92305822008-03-20 15:12:58 +0000689 errno = EINVAL;
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200690 return rv;
691 }
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200692#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000693
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200694 if (fprintf(f, "%s:%s:%lu:",
695 p->gr_name, p->gr_passwd,
696 (unsigned long)(p->gr_gid)) >= 0
697 ) {
698 static const char format[] ALIGN1 = ",%s";
Eric Andersen9615a082004-07-15 12:53:49 +0000699
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200700 char **m;
701 const char *fmt;
Eric Andersen9615a082004-07-15 12:53:49 +0000702
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200703 fmt = format + 1;
704
705 assert(p->gr_mem);
706 m = p->gr_mem;
707
708 while (1) {
709 if (!*m) {
710 if (fputc('\n', f) >= 0) {
711 rv = 0;
Eric Andersen9615a082004-07-15 12:53:49 +0000712 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200713 break;
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200714 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200715 if (fprintf(f, fmt, *m) < 0) {
716 break;
717 }
718 m++;
719 fmt = format;
Eric Andersen9615a082004-07-15 12:53:49 +0000720 }
Eric Andersen9615a082004-07-15 12:53:49 +0000721 }
722
723 return rv;
724}
Denys Vlasenko55301292010-03-31 12:38:17 +0200725#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000726
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000727#if ENABLE_USE_BB_SHADOW
Denys Vlasenko05d1a322010-04-02 12:12:43 +0200728#ifdef UNUSED_FOR_NOW
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200729static const unsigned char put_sp_off[] ALIGN1 = {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000730 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
731 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
732 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
733 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
734 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
735 offsetof(struct spwd, sp_expire) /* 7 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000736};
737
738int putspent(const struct spwd *p, FILE *stream)
739{
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200740 const char *fmt;
Denis Vlasenko87468852007-04-13 23:22:00 +0000741 long x;
Eric Andersen9615a082004-07-15 12:53:49 +0000742 int i;
743 int rv = -1;
744
745 /* Unlike putpwent and putgrent, glibc does not check the args. */
746 if (fprintf(stream, "%s:%s:", p->sp_namp,
747 (p->sp_pwdp ? p->sp_pwdp : "")) < 0
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000748 ) {
Eric Andersen9615a082004-07-15 12:53:49 +0000749 goto DO_UNLOCK;
750 }
751
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200752 for (i = 0; i < sizeof(put_sp_off); i++) {
753 fmt = "%ld:";
754 x = *(long *)((char *)p + put_sp_off[i]);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000755 if (x == -1) {
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200756 fmt += 3;
Eric Andersen9615a082004-07-15 12:53:49 +0000757 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200758 if (fprintf(stream, fmt, x) < 0) {
Eric Andersen9615a082004-07-15 12:53:49 +0000759 goto DO_UNLOCK;
760 }
761 }
762
763 if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
764 goto DO_UNLOCK;
765 }
766
Rob Landley25413bf2005-10-08 02:23:22 +0000767 if (fputc('\n', stream) > 0) {
Eric Andersen9615a082004-07-15 12:53:49 +0000768 rv = 0;
769 }
770
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200771 DO_UNLOCK:
Eric Andersen9615a082004-07-15 12:53:49 +0000772 return rv;
773}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000774#endif
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200775#endif /* USE_BB_SHADOW */
Eric Andersen9615a082004-07-15 12:53:49 +0000776
Eric Andersen9615a082004-07-15 12:53:49 +0000777/**********************************************************************/
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200778/* Internal functions */
Eric Andersen9615a082004-07-15 12:53:49 +0000779/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000780
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000781static const unsigned char pw_off[] ALIGN1 = {
782 offsetof(struct passwd, pw_name), /* 0 */
783 offsetof(struct passwd, pw_passwd), /* 1 */
784 offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
785 offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
786 offsetof(struct passwd, pw_gecos), /* 4 */
787 offsetof(struct passwd, pw_dir), /* 5 */
788 offsetof(struct passwd, pw_shell) /* 6 */
Eric Andersen9615a082004-07-15 12:53:49 +0000789};
790
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200791static int FAST_FUNC bb__parsepwent(void *data, char *line)
Eric Andersen9615a082004-07-15 12:53:49 +0000792{
793 char *endptr;
794 char *p;
795 int i;
796
797 i = 0;
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200798 while (1) {
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200799 p = (char *) data + pw_off[i];
Eric Andersen9615a082004-07-15 12:53:49 +0000800
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200801 if (i < 2 || i > 3) {
Eric Andersen9615a082004-07-15 12:53:49 +0000802 *((char **) p) = line;
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200803 if (i == 6) {
Eric Andersen9615a082004-07-15 12:53:49 +0000804 return 0;
805 }
806 /* NOTE: glibc difference - glibc allows omission of
807 * ':' seperators after the gid field if all remaining
808 * entries are empty. We require all separators. */
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000809 line = strchr(line, ':');
810 if (!line) {
Eric Andersen9615a082004-07-15 12:53:49 +0000811 break;
812 }
813 } else {
814 unsigned long t = strtoul(line, &endptr, 10);
815 /* Make sure we had at least one digit, and that the
816 * failing char is the next field seperator ':'. See
817 * glibc difference note above. */
818 /* TODO: Also check for leading whitespace? */
819 if ((endptr == line) || (*endptr != ':')) {
820 break;
821 }
822 line = endptr;
823 if (i & 1) { /* i == 3 -- gid */
824 *((gid_t *) p) = t;
825 } else { /* i == 2 -- uid */
826 *((uid_t *) p) = t;
827 }
828 }
829
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200830 *line++ = '\0';
831 i++;
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200832 } /* while (1) */
Eric Andersen9615a082004-07-15 12:53:49 +0000833
834 return -1;
835}
836
Eric Andersen9615a082004-07-15 12:53:49 +0000837/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000838
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000839static const unsigned char gr_off[] ALIGN1 = {
840 offsetof(struct group, gr_name), /* 0 */
841 offsetof(struct group, gr_passwd), /* 1 */
842 offsetof(struct group, gr_gid) /* 2 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000843};
844
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200845static int FAST_FUNC bb__parsegrent(void *data, char *line)
Eric Andersen9615a082004-07-15 12:53:49 +0000846{
847 char *endptr;
848 char *p;
849 int i;
850 char **members;
851 char *end_of_buf;
852
853 end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
854 i = 0;
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200855 while (1) {
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200856 p = (char *) data + gr_off[i];
Eric Andersen9615a082004-07-15 12:53:49 +0000857
858 if (i < 2) {
859 *((char **) p) = line;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000860 line = strchr(line, ':');
861 if (!line) {
Eric Andersen9615a082004-07-15 12:53:49 +0000862 break;
863 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200864 *line++ = '\0';
865 i++;
Eric Andersen9615a082004-07-15 12:53:49 +0000866 } else {
867 *((gid_t *) p) = strtoul(line, &endptr, 10);
868
869 /* NOTE: glibc difference - glibc allows omission of the
870 * trailing colon when there is no member list. We treat
871 * this as an error. */
872
873 /* Make sure we had at least one digit, and that the
874 * failing char is the next field seperator ':'. See
875 * glibc difference note above. */
876 if ((endptr == line) || (*endptr != ':')) {
877 break;
878 }
879
880 i = 1; /* Count terminating NULL ptr. */
881 p = endptr;
882
883 if (p[1]) { /* We have a member list to process. */
884 /* Overwrite the last ':' with a ',' before counting.
Denys Vlasenko8d22ca82010-03-31 14:43:58 +0200885 * This allows us to (1) test for initial ','
886 * and (2) adds one ',' so that the number of commas
887 * equals the member count. */
Eric Andersen9615a082004-07-15 12:53:49 +0000888 *p = ',';
889 do {
890 /* NOTE: glibc difference - glibc allows and trims leading
891 * (but not trailing) space. We treat this as an error. */
892 /* NOTE: glibc difference - glibc allows consecutive and
893 * trailing commas, and ignores "empty string" users. We
894 * treat this as an error. */
895 if (*p == ',') {
896 ++i;
897 *p = 0; /* nul-terminate each member string. */
898 if (!*++p || (*p == ',') || isspace(*p)) {
899 goto ERR;
900 }
901 }
902 } while (*++p);
903 }
904
905 /* Now align (p+1), rounding up. */
906 /* Assumes sizeof(char **) is a power of 2. */
907 members = (char **)( (((intptr_t) p) + sizeof(char **))
908 & ~((intptr_t)(sizeof(char **) - 1)) );
909
910 if (((char *)(members + i)) > end_of_buf) { /* No space. */
911 break;
912 }
913
914 ((struct group *) data)->gr_mem = members;
915
916 if (--i) {
917 p = endptr; /* Pointing to char prior to first member. */
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200918 while (1) {
Eric Andersen9615a082004-07-15 12:53:49 +0000919 *members++ = ++p;
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200920 if (!--i)
921 break;
922 while (*++p)
923 continue;
924 }
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000925 }
Eric Andersen9615a082004-07-15 12:53:49 +0000926 *members = NULL;
927
928 return 0;
929 }
Denys Vlasenko9e59e272010-03-31 10:31:51 +0200930 } /* while (1) */
Eric Andersen9615a082004-07-15 12:53:49 +0000931
932 ERR:
933 return -1;
934}
935
Eric Andersen9615a082004-07-15 12:53:49 +0000936/**********************************************************************/
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000937
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000938#if ENABLE_USE_BB_SHADOW
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000939static const unsigned char sp_off[] ALIGN1 = {
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200940 offsetof(struct spwd, sp_namp), /* 0: char* */
941 offsetof(struct spwd, sp_pwdp), /* 1: char* */
942 offsetof(struct spwd, sp_lstchg), /* 2: long */
943 offsetof(struct spwd, sp_min), /* 3: long */
944 offsetof(struct spwd, sp_max), /* 4: long */
945 offsetof(struct spwd, sp_warn), /* 5: long */
946 offsetof(struct spwd, sp_inact), /* 6: long */
947 offsetof(struct spwd, sp_expire), /* 7: long */
948 offsetof(struct spwd, sp_flag) /* 8: unsigned long */
Eric Andersen9615a082004-07-15 12:53:49 +0000949};
950
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200951static int FAST_FUNC bb__parsespent(void *data, char *line)
Eric Andersen9615a082004-07-15 12:53:49 +0000952{
953 char *endptr;
954 char *p;
955 int i;
956
957 i = 0;
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200958 while (1) {
959 p = (char *) data + sp_off[i];
Eric Andersen9615a082004-07-15 12:53:49 +0000960 if (i < 2) {
961 *((char **) p) = line;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000962 line = strchr(line, ':');
963 if (!line) {
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200964 break; /* error */
Eric Andersen9615a082004-07-15 12:53:49 +0000965 }
966 } else {
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200967 *((long *) p) = strtoul(line, &endptr, 10);
Eric Andersen9615a082004-07-15 12:53:49 +0000968 if (endptr == line) {
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200969 *((long *) p) = -1L;
Eric Andersen9615a082004-07-15 12:53:49 +0000970 }
Eric Andersen9615a082004-07-15 12:53:49 +0000971 line = endptr;
Eric Andersen9615a082004-07-15 12:53:49 +0000972 if (i == 8) {
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200973 if (*line != '\0') {
974 break; /* error */
Eric Andersen9615a082004-07-15 12:53:49 +0000975 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200976 return 0; /* all ok */
Eric Andersen9615a082004-07-15 12:53:49 +0000977 }
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200978 if (*line != ':') {
979 break; /* error */
Eric Andersen9615a082004-07-15 12:53:49 +0000980 }
Eric Andersen9615a082004-07-15 12:53:49 +0000981 }
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200982 *line++ = '\0';
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200983 i++;
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200984 }
Eric Andersen9615a082004-07-15 12:53:49 +0000985
986 return EINVAL;
987}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000988#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000989
Eric Andersen9615a082004-07-15 12:53:49 +0000990/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000991
Denys Vlasenko05d1a322010-04-02 12:12:43 +0200992/* Reads until EOF, or until it finds a line which fits in the buffer
Eric Andersen9615a082004-07-15 12:53:49 +0000993 * and for which the parser function succeeds.
994 *
Denys Vlasenko05d1a322010-04-02 12:12:43 +0200995 * Returns 0 on success and ENOENT for end-of-file (glibc convention).
Eric Andersen9615a082004-07-15 12:53:49 +0000996 */
Denys Vlasenko17fcd722010-03-31 12:37:43 +0200997static int bb__pgsreader(
998 int FAST_FUNC (*parserfunc)(void *d, char *line),
999 void *data,
1000 char *__restrict line_buff,
1001 size_t buflen,
1002 FILE *f)
Eric Andersen9615a082004-07-15 12:53:49 +00001003{
Eric Andersen9615a082004-07-15 12:53:49 +00001004 int skip;
1005 int rv = ERANGE;
1006
1007 if (buflen < PWD_BUFFER_SIZE) {
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +00001008 errno = rv;
Denys Vlasenko57dc3c72010-03-31 10:24:37 +02001009 return rv;
1010 }
1011
1012 skip = 0;
1013 while (1) {
1014 if (!fgets(line_buff, buflen, f)) {
1015 if (feof(f)) {
1016 rv = ENOENT;
1017 }
1018 break;
1019 }
1020
1021 {
1022 int line_len = strlen(line_buff) - 1;
1023 if (line_len >= 0 && line_buff[line_len] == '\n') {
1024 line_buff[line_len] = '\0';
1025 } else
1026 if (line_len + 2 == buflen) {
1027 /* A start (or continuation) of overlong line */
1028 skip = 1;
1029 continue;
1030 } /* else: a last line in the file, and it has no '\n' */
1031 }
1032
1033 if (skip) {
1034 /* This "line" is a remainder of overlong line, ignore */
1035 skip = 0;
1036 continue;
1037 }
1038
1039 /* NOTE: glibc difference - glibc strips leading whitespace from
1040 * records. We do not allow leading whitespace. */
1041
1042 /* Skip empty lines, comment lines, and lines with leading
1043 * whitespace. */
1044 if (line_buff[0] != '\0' && line_buff[0] != '#' && !isspace(line_buff[0])) {
1045 if (parserfunc == bb__parsegrent) {
1046 /* Do evil group hack:
1047 * The group entry parsing function needs to know where
1048 * the end of the buffer is so that it can construct the
1049 * group member ptr table. */
1050 ((struct group *) data)->gr_name = line_buff + buflen;
1051 }
1052 if (parserfunc(data, line_buff) == 0) {
1053 rv = 0;
Eric Andersen9615a082004-07-15 12:53:49 +00001054 break;
1055 }
Denys Vlasenko57dc3c72010-03-31 10:24:37 +02001056 }
1057 } /* while (1) */
Eric Andersen9615a082004-07-15 12:53:49 +00001058
1059 return rv;
1060}