blob: 7a8a2374507ac67368837810fec061c35c2fb7e5 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Eric Andersen9615a082004-07-15 12:53:49 +00002/* Copyright (C) 2003 Manuel Novoa III
3 *
Rob Landley25413bf2005-10-08 02:23:22 +00004 * Licensed under GPL v2, or later. See file LICENSE in this tarball.
Eric Andersen9615a082004-07-15 12:53:49 +00005 */
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:
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.
18 *
19 */
20
Rob Landleyea224be2006-06-18 20:20:07 +000021#include "libbb.h"
Eric Andersen9615a082004-07-15 12:53:49 +000022#include <features.h>
Eric Andersen9615a082004-07-15 12:53:49 +000023#include <assert.h>
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000024
Eric Andersen9615a082004-07-15 12:53:49 +000025#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/**********************************************************************/
Rob Landley06ec8cf2006-03-03 19:02:50 +000036/* Sizes for statically allocated buffers. */
Eric Andersen9615a082004-07-15 12:53:49 +000037
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
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000046static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000047 char *__restrict line_buff, size_t buflen, FILE *f);
Eric Andersen9615a082004-07-15 12:53:49 +000048
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000049static int bb__parsepwent(void *pw, char *line);
50static int bb__parsegrent(void *gr, char *line);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000051#if ENABLE_USE_BB_SHADOW
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000052static int bb__parsespent(void *sp, char *line);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000053#endif
54
Eric Andersen9615a082004-07-15 12:53:49 +000055/**********************************************************************/
56/* For the various fget??ent_r funcs, return
57 *
58 * 0: success
59 * ENOENT: end-of-file encountered
60 * ERANGE: buflen too small
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000061 * other error values possible. See bb__pgsreader.
Eric Andersen9615a082004-07-15 12:53:49 +000062 *
63 * Also, *result == resultbuf on success and NULL on failure.
64 *
65 * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
66 * We do not, as it really isn't an error if we reach the end-of-file.
67 * Doing so is analogous to having fgetc() set errno on EOF.
68 */
69/**********************************************************************/
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +000070
Eric Andersen9615a082004-07-15 12:53:49 +000071int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
72 char *__restrict buffer, size_t buflen,
73 struct passwd **__restrict result)
74{
75 int rv;
76
77 *result = NULL;
78
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000079 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000080 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +000081 *result = resultbuf;
82 }
83
84 return rv;
85}
86
Eric Andersen9615a082004-07-15 12:53:49 +000087int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
88 char *__restrict buffer, size_t buflen,
89 struct group **__restrict result)
90{
91 int rv;
92
93 *result = NULL;
94
Denis Vlasenkocb04ff52006-12-30 21:11:57 +000095 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +000096 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +000097 *result = resultbuf;
98 }
99
100 return rv;
101}
102
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000103#if ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000104int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
105 char *__restrict buffer, size_t buflen,
106 struct spwd **__restrict result)
107{
108 int rv;
109
110 *result = NULL;
111
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000112 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, stream);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000113 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000114 *result = resultbuf;
115 }
116
117 return rv;
118}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000119#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000120
Eric Andersen9615a082004-07-15 12:53:49 +0000121/**********************************************************************/
122/* For the various fget??ent funcs, return NULL on failure and a
Rob Landley06ec8cf2006-03-03 19:02:50 +0000123 * pointer to the appropriate struct (statically allocated) on success.
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000124 * TODO: audit & stop using these in bbox, they pull in static buffers */
Eric Andersen9615a082004-07-15 12:53:49 +0000125/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000126
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000127#if 0
Eric Andersen9615a082004-07-15 12:53:49 +0000128struct passwd *fgetpwent(FILE *stream)
129{
130 static char buffer[PWD_BUFFER_SIZE];
131 static struct passwd resultbuf;
132 struct passwd *result;
133
134 fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
135 return result;
136}
137
Eric Andersen9615a082004-07-15 12:53:49 +0000138struct group *fgetgrent(FILE *stream)
139{
140 static char buffer[GRP_BUFFER_SIZE];
141 static struct group resultbuf;
142 struct group *result;
143
144 fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
145 return result;
146}
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000147#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000148
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000149#if ENABLE_USE_BB_SHADOW
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000150#if 0
Eric Andersen9615a082004-07-15 12:53:49 +0000151struct spwd *fgetspent(FILE *stream)
152{
153 static char buffer[PWD_BUFFER_SIZE];
154 static struct spwd resultbuf;
155 struct spwd *result;
156
157 fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
158 return result;
159}
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000160#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000161
Eric Andersen9615a082004-07-15 12:53:49 +0000162int sgetspent_r(const char *string, struct spwd *result_buf,
163 char *buffer, size_t buflen, struct spwd **result)
164{
165 int rv = ERANGE;
166
167 *result = NULL;
168
169 if (buflen < PWD_BUFFER_SIZE) {
170 DO_ERANGE:
171 errno=rv;
172 goto DONE;
173 }
174
175 if (string != buffer) {
176 if (strlen(string) >= buflen) {
177 goto DO_ERANGE;
178 }
179 strcpy(buffer, string);
180 }
181
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000182 rv = bb__parsespent(result_buf, buffer);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000183 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000184 *result = result_buf;
185 }
186
187 DONE:
188 return rv;
189}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000190#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000191
Eric Andersen9615a082004-07-15 12:53:49 +0000192/**********************************************************************/
193
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000194#define GETXXKEY_R_FUNC getpwnam_r
195#define GETXXKEY_R_PARSER bb__parsepwent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000196#define GETXXKEY_R_ENTTYPE struct passwd
197#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000198#define GETXXKEY_R_KEYTYPE const char *__restrict
199#define GETXXKEY_R_PATHNAME _PATH_PASSWD
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000200#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000201
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000202#define GETXXKEY_R_FUNC getgrnam_r
203#define GETXXKEY_R_PARSER bb__parsegrent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000204#define GETXXKEY_R_ENTTYPE struct group
205#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000206#define GETXXKEY_R_KEYTYPE const char *__restrict
207#define GETXXKEY_R_PATHNAME _PATH_GROUP
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000208#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000209
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000210#if ENABLE_USE_BB_SHADOW
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000211#define GETXXKEY_R_FUNC getspnam_r
212#define GETXXKEY_R_PARSER bb__parsespent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000213#define GETXXKEY_R_ENTTYPE struct spwd
214#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000215#define GETXXKEY_R_KEYTYPE const char *__restrict
216#define GETXXKEY_R_PATHNAME _PATH_SHADOW
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000217#include "pwd_grp_internal.c"
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000218#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000219
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000220#define GETXXKEY_R_FUNC getpwuid_r
221#define GETXXKEY_R_PARSER bb__parsepwent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000222#define GETXXKEY_R_ENTTYPE struct passwd
223#define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000224#define GETXXKEY_R_KEYTYPE uid_t
225#define GETXXKEY_R_PATHNAME _PATH_PASSWD
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000226#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000227
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000228#define GETXXKEY_R_FUNC getgrgid_r
229#define GETXXKEY_R_PARSER bb__parsegrent
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000230#define GETXXKEY_R_ENTTYPE struct group
231#define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000232#define GETXXKEY_R_KEYTYPE gid_t
233#define GETXXKEY_R_PATHNAME _PATH_GROUP
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000234#include "pwd_grp_internal.c"
Eric Andersen9615a082004-07-15 12:53:49 +0000235
236/**********************************************************************/
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000237/* TODO: audit & stop using these in bbox, they pull in static buffers */
Eric Andersen9615a082004-07-15 12:53:49 +0000238
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000239/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000240struct passwd *getpwuid(uid_t uid)
241{
242 static char buffer[PWD_BUFFER_SIZE];
243 static struct passwd resultbuf;
244 struct passwd *result;
245
246 getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
247 return result;
248}
249
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000250/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000251struct group *getgrgid(gid_t gid)
252{
253 static char buffer[GRP_BUFFER_SIZE];
254 static struct group resultbuf;
255 struct group *result;
256
257 getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
258 return result;
259}
260
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000261#if 0 //ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000262/* This function is non-standard and is currently not built. It seems
263 * to have been created as a reentrant version of the non-standard
264 * functions getspuid. Why getspuid was added, I do not know. */
Eric Andersen9615a082004-07-15 12:53:49 +0000265int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
266 char *__restrict buffer, size_t buflen,
267 struct spwd **__restrict result)
268{
269 int rv;
270 struct passwd *pp;
271 struct passwd password;
272 char pwd_buff[PWD_BUFFER_SIZE];
273
274 *result = NULL;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000275 rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp);
276 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000277 rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
278 }
279
280 return rv;
281}
282
Eric Andersen9615a082004-07-15 12:53:49 +0000283/* This function is non-standard and is currently not built.
284 * Why it was added, I do not know. */
Eric Andersen9615a082004-07-15 12:53:49 +0000285struct spwd *getspuid(uid_t uid)
286{
287 static char buffer[PWD_BUFFER_SIZE];
288 static struct spwd resultbuf;
289 struct spwd *result;
290
291 getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
292 return result;
293}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000294#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000295
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000296/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000297struct passwd *getpwnam(const char *name)
298{
299 static char buffer[PWD_BUFFER_SIZE];
300 static struct passwd resultbuf;
301 struct passwd *result;
302
303 getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
304 return result;
305}
306
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000307/* This one has many users */
Eric Andersen9615a082004-07-15 12:53:49 +0000308struct group *getgrnam(const char *name)
309{
310 static char buffer[GRP_BUFFER_SIZE];
311 static struct group resultbuf;
312 struct group *result;
313
314 getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
315 return result;
316}
317
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000318#if 0 //ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000319struct spwd *getspnam(const char *name)
320{
321 static char buffer[PWD_BUFFER_SIZE];
322 static struct spwd resultbuf;
323 struct spwd *result;
324
325 getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
326 return result;
327}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000328#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000329
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000330/* This one doesn't use static buffers */
Eric Andersen9615a082004-07-15 12:53:49 +0000331int getpw(uid_t uid, char *buf)
332{
333 struct passwd resultbuf;
334 struct passwd *result;
335 char buffer[PWD_BUFFER_SIZE];
336
337 if (!buf) {
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000338 errno = EINVAL;
Eric Andersen9615a082004-07-15 12:53:49 +0000339 } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
340 if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
341 resultbuf.pw_name, resultbuf.pw_passwd,
342 (unsigned long)(resultbuf.pw_uid),
343 (unsigned long)(resultbuf.pw_gid),
344 resultbuf.pw_gecos, resultbuf.pw_dir,
345 resultbuf.pw_shell) >= 0
346 ) {
347 return 0;
348 }
349 }
350
351 return -1;
352}
353
Eric Andersen9615a082004-07-15 12:53:49 +0000354/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000355
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000356/* FIXME: we don't have such CONFIG_xx - ?! */
357
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000358#if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
359static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
360# define LOCK pthread_mutex_lock(&mylock)
361# define UNLOCK pthread_mutex_unlock(&mylock);
362#else
363# define LOCK ((void) 0)
364# define UNLOCK ((void) 0)
365#endif
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000366
Eric Andersen9615a082004-07-15 12:53:49 +0000367static FILE *pwf /*= NULL*/;
368void setpwent(void)
369{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000370 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000371 if (pwf) {
372 rewind(pwf);
373 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000374 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000375}
376
377void endpwent(void)
378{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000379 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000380 if (pwf) {
381 fclose(pwf);
382 pwf = NULL;
383 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000384 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000385}
386
387
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000388int getpwent_r(struct passwd *__restrict resultbuf,
Eric Andersen9615a082004-07-15 12:53:49 +0000389 char *__restrict buffer, size_t buflen,
390 struct passwd **__restrict result)
391{
392 int rv;
393
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000394 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000395 *result = NULL; /* In case of error... */
396
397 if (!pwf) {
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000398 pwf = fopen(_PATH_PASSWD, "r");
399 if (!pwf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000400 rv = errno;
401 goto ERR;
402 }
403 }
404
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000405 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000406 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000407 *result = resultbuf;
408 }
409
410 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000411 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000412 return rv;
413}
414
Eric Andersen9615a082004-07-15 12:53:49 +0000415static FILE *grf /*= NULL*/;
416void setgrent(void)
417{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000418 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000419 if (grf) {
420 rewind(grf);
421 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000422 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000423}
424
425void endgrent(void)
426{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000427 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000428 if (grf) {
429 fclose(grf);
430 grf = NULL;
431 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000432 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000433}
434
435int getgrent_r(struct group *__restrict resultbuf,
436 char *__restrict buffer, size_t buflen,
437 struct group **__restrict result)
438{
439 int rv;
440
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000441 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000442 *result = NULL; /* In case of error... */
443
444 if (!grf) {
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000445 grf = fopen(_PATH_GROUP, "r");
446 if (!grf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000447 rv = errno;
448 goto ERR;
449 }
450 }
451
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000452 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000453 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000454 *result = resultbuf;
455 }
456
457 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000458 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000459 return rv;
460}
461
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000462#if ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000463static FILE *spf /*= NULL*/;
464void setspent(void)
465{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000466 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000467 if (spf) {
468 rewind(spf);
469 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000470 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000471}
472
473void endspent(void)
474{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000475 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000476 if (spf) {
477 fclose(spf);
478 spf = NULL;
479 }
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000480 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000481}
482
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000483int getspent_r(struct spwd *resultbuf, char *buffer,
Eric Andersen9615a082004-07-15 12:53:49 +0000484 size_t buflen, struct spwd **result)
485{
486 int rv;
487
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000488 LOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000489 *result = NULL; /* In case of error... */
490
491 if (!spf) {
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000492 spf = fopen(_PATH_SHADOW, "r");
493 if (!spf) {
Eric Andersen9615a082004-07-15 12:53:49 +0000494 rv = errno;
495 goto ERR;
496 }
497 }
498
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000499 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000500 if (!rv) {
Eric Andersen9615a082004-07-15 12:53:49 +0000501 *result = resultbuf;
502 }
503
504 ERR:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000505 UNLOCK;
Eric Andersen9615a082004-07-15 12:53:49 +0000506 return rv;
507}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000508#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000509
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000510#if 0
Eric Andersen9615a082004-07-15 12:53:49 +0000511struct passwd *getpwent(void)
512{
513 static char line_buff[PWD_BUFFER_SIZE];
514 static struct passwd pwd;
515 struct passwd *result;
516
517 getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
518 return result;
519}
520
Eric Andersen9615a082004-07-15 12:53:49 +0000521struct group *getgrent(void)
522{
523 static char line_buff[GRP_BUFFER_SIZE];
524 static struct group gr;
525 struct group *result;
526
527 getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
528 return result;
529}
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000530#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000531
Denis Vlasenko5df955f2007-03-13 13:01:14 +0000532#if 0 //ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000533struct spwd *getspent(void)
534{
535 static char line_buff[PWD_BUFFER_SIZE];
536 static struct spwd spwd;
537 struct spwd *result;
538
539 getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
540 return result;
541}
542
Eric Andersen9615a082004-07-15 12:53:49 +0000543struct spwd *sgetspent(const char *string)
544{
545 static char line_buff[PWD_BUFFER_SIZE];
546 static struct spwd spwd;
547 struct spwd *result;
548
549 sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
550 return result;
551}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000552#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000553
Eric Andersen9615a082004-07-15 12:53:49 +0000554int initgroups(const char *user, gid_t gid)
555{
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000556 FILE *grfile;
Eric Andersen9615a082004-07-15 12:53:49 +0000557 gid_t *group_list;
558 int num_groups, rv;
559 char **m;
560 struct group group;
561 char buff[PWD_BUFFER_SIZE];
562
563 rv = -1;
564
565 /* We alloc space for 8 gids at a time. */
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000566 group_list = (gid_t *) malloc(8*sizeof(gid_t *));
567 if (group_list
568 && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
569 ) {
Eric Andersen9615a082004-07-15 12:53:49 +0000570 *group_list = gid;
571 num_groups = 1;
572
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000573 while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
Eric Andersen9615a082004-07-15 12:53:49 +0000574 assert(group.gr_mem); /* Must have at least a NULL terminator. */
575 if (group.gr_gid != gid) {
576 for (m=group.gr_mem ; *m ; m++) {
577 if (!strcmp(*m, user)) {
578 if (!(num_groups & 7)) {
579 gid_t *tmp = (gid_t *)
580 realloc(group_list,
581 (num_groups+8) * sizeof(gid_t *));
582 if (!tmp) {
583 rv = -1;
584 goto DO_CLOSE;
585 }
586 group_list = tmp;
587 }
588 group_list[num_groups++] = group.gr_gid;
589 break;
590 }
591 }
592 }
593 }
594
595 rv = setgroups(num_groups, group_list);
596 DO_CLOSE:
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000597 fclose(grfile);
Eric Andersen9615a082004-07-15 12:53:49 +0000598 }
599
600 /* group_list will be NULL if initial malloc failed, which may trigger
601 * warnings from various malloc debuggers. */
602 free(group_list);
603 return rv;
604}
605
Eric Andersen9615a082004-07-15 12:53:49 +0000606int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
607{
608 int rv = -1;
609
610 if (!p || !f) {
611 errno=EINVAL;
612 } else {
613 /* No extra thread locking is needed above what fprintf does. */
614 if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
615 p->pw_name, p->pw_passwd,
616 (unsigned long)(p->pw_uid),
617 (unsigned long)(p->pw_gid),
618 p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
619 ) {
620 rv = 0;
621 }
622 }
623
624 return rv;
625}
626
Eric Andersen9615a082004-07-15 12:53:49 +0000627int putgrent(const struct group *__restrict p, FILE *__restrict f)
628{
629 static const char format[] = ",%s";
630 char **m;
631 const char *fmt;
632 int rv = -1;
633
634 if (!p || !f) { /* Sigh... glibc checks. */
635 errno=EINVAL;
636 } else {
637 if (fprintf(f, "%s:%s:%lu:",
638 p->gr_name, p->gr_passwd,
639 (unsigned long)(p->gr_gid)) >= 0
640 ) {
641
642 fmt = format + 1;
643
644 assert(p->gr_mem);
645 m = p->gr_mem;
646
647 do {
648 if (!*m) {
Rob Landley25413bf2005-10-08 02:23:22 +0000649 if (fputc('\n', f) >= 0) {
Eric Andersen9615a082004-07-15 12:53:49 +0000650 rv = 0;
651 }
652 break;
653 }
654 if (fprintf(f, fmt, *m) < 0) {
655 break;
656 }
657 ++m;
658 fmt = format;
659 } while (1);
660
661 }
662
663 }
664
665 return rv;
666}
667
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000668#if ENABLE_USE_BB_SHADOW
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000669static const unsigned char _sp_off[] = {
Eric Andersen9615a082004-07-15 12:53:49 +0000670 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000671 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000672 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000673 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
674 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
675 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000676};
677
678int putspent(const struct spwd *p, FILE *stream)
679{
680 static const char ld_format[] = "%ld:";
681 const char *f;
682 long int x;
683 int i;
684 int rv = -1;
685
686 /* Unlike putpwent and putgrent, glibc does not check the args. */
687 if (fprintf(stream, "%s:%s:", p->sp_namp,
688 (p->sp_pwdp ? p->sp_pwdp : "")) < 0
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000689 ) {
Eric Andersen9615a082004-07-15 12:53:49 +0000690 goto DO_UNLOCK;
691 }
692
Bernhard Reutner-Fischer30c7de02005-10-28 11:21:40 +0000693 for (i=0 ; i < sizeof(_sp_off) ; i++) {
Eric Andersen9615a082004-07-15 12:53:49 +0000694 f = ld_format;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000695 x = *(const long int *)(((const char *) p) + _sp_off[i]);
696 if (x == -1) {
Eric Andersen9615a082004-07-15 12:53:49 +0000697 f += 3;
698 }
699 if (fprintf(stream, f, x) < 0) {
700 goto DO_UNLOCK;
701 }
702 }
703
704 if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
705 goto DO_UNLOCK;
706 }
707
Rob Landley25413bf2005-10-08 02:23:22 +0000708 if (fputc('\n', stream) > 0) {
Eric Andersen9615a082004-07-15 12:53:49 +0000709 rv = 0;
710 }
711
712DO_UNLOCK:
713 return rv;
714}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000715#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000716
Eric Andersen9615a082004-07-15 12:53:49 +0000717/**********************************************************************/
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000718/* Internal uClibc functions. */
Eric Andersen9615a082004-07-15 12:53:49 +0000719/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000720
721static const unsigned char pw_off[] = {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000722 offsetof(struct passwd, pw_name), /* 0 */
Eric Andersen9615a082004-07-15 12:53:49 +0000723 offsetof(struct passwd, pw_passwd), /* 1 */
724 offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000725 offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000726 offsetof(struct passwd, pw_gecos), /* 4 */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000727 offsetof(struct passwd, pw_dir), /* 5 */
728 offsetof(struct passwd, pw_shell) /* 6 */
Eric Andersen9615a082004-07-15 12:53:49 +0000729};
730
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000731static int bb__parsepwent(void *data, char *line)
Eric Andersen9615a082004-07-15 12:53:49 +0000732{
733 char *endptr;
734 char *p;
735 int i;
736
737 i = 0;
738 do {
739 p = ((char *) ((struct passwd *) data)) + pw_off[i];
740
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000741 if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
Eric Andersen9615a082004-07-15 12:53:49 +0000742 *((char **) p) = line;
743 if (i==6) {
744 return 0;
745 }
746 /* NOTE: glibc difference - glibc allows omission of
747 * ':' seperators after the gid field if all remaining
748 * entries are empty. We require all separators. */
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000749 line = strchr(line, ':');
750 if (!line) {
Eric Andersen9615a082004-07-15 12:53:49 +0000751 break;
752 }
753 } else {
754 unsigned long t = strtoul(line, &endptr, 10);
755 /* Make sure we had at least one digit, and that the
756 * failing char is the next field seperator ':'. See
757 * glibc difference note above. */
758 /* TODO: Also check for leading whitespace? */
759 if ((endptr == line) || (*endptr != ':')) {
760 break;
761 }
762 line = endptr;
763 if (i & 1) { /* i == 3 -- gid */
764 *((gid_t *) p) = t;
765 } else { /* i == 2 -- uid */
766 *((uid_t *) p) = t;
767 }
768 }
769
770 *line++ = 0;
771 ++i;
772 } while (1);
773
774 return -1;
775}
776
Eric Andersen9615a082004-07-15 12:53:49 +0000777/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000778
779static const unsigned char gr_off[] = {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000780 offsetof(struct group, gr_name), /* 0 */
Eric Andersen9615a082004-07-15 12:53:49 +0000781 offsetof(struct group, gr_passwd), /* 1 */
782 offsetof(struct group, gr_gid) /* 2 - not a char ptr */
783};
784
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000785static int bb__parsegrent(void *data, char *line)
Eric Andersen9615a082004-07-15 12:53:49 +0000786{
787 char *endptr;
788 char *p;
789 int i;
790 char **members;
791 char *end_of_buf;
792
793 end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
794 i = 0;
795 do {
796 p = ((char *) ((struct group *) data)) + gr_off[i];
797
798 if (i < 2) {
799 *((char **) p) = line;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000800 line = strchr(line, ':');
801 if (!line) {
Eric Andersen9615a082004-07-15 12:53:49 +0000802 break;
803 }
804 *line++ = 0;
805 ++i;
806 } else {
807 *((gid_t *) p) = strtoul(line, &endptr, 10);
808
809 /* NOTE: glibc difference - glibc allows omission of the
810 * trailing colon when there is no member list. We treat
811 * this as an error. */
812
813 /* Make sure we had at least one digit, and that the
814 * failing char is the next field seperator ':'. See
815 * glibc difference note above. */
816 if ((endptr == line) || (*endptr != ':')) {
817 break;
818 }
819
820 i = 1; /* Count terminating NULL ptr. */
821 p = endptr;
822
823 if (p[1]) { /* We have a member list to process. */
824 /* Overwrite the last ':' with a ',' before counting.
825 * This allows us to test for initial ',' and adds
826 * one ',' so that the ',' count equals the member
827 * count. */
828 *p = ',';
829 do {
830 /* NOTE: glibc difference - glibc allows and trims leading
831 * (but not trailing) space. We treat this as an error. */
832 /* NOTE: glibc difference - glibc allows consecutive and
833 * trailing commas, and ignores "empty string" users. We
834 * treat this as an error. */
835 if (*p == ',') {
836 ++i;
837 *p = 0; /* nul-terminate each member string. */
838 if (!*++p || (*p == ',') || isspace(*p)) {
839 goto ERR;
840 }
841 }
842 } while (*++p);
843 }
844
845 /* Now align (p+1), rounding up. */
846 /* Assumes sizeof(char **) is a power of 2. */
847 members = (char **)( (((intptr_t) p) + sizeof(char **))
848 & ~((intptr_t)(sizeof(char **) - 1)) );
849
850 if (((char *)(members + i)) > end_of_buf) { /* No space. */
851 break;
852 }
853
854 ((struct group *) data)->gr_mem = members;
855
856 if (--i) {
857 p = endptr; /* Pointing to char prior to first member. */
858 do {
859 *members++ = ++p;
860 if (!--i) break;
861 while (*++p) {}
862 } while (1);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000863 }
Eric Andersen9615a082004-07-15 12:53:49 +0000864 *members = NULL;
865
866 return 0;
867 }
868 } while (1);
869
870 ERR:
871 return -1;
872}
873
Eric Andersen9615a082004-07-15 12:53:49 +0000874/**********************************************************************/
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000875
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000876#if ENABLE_USE_BB_SHADOW
Eric Andersen9615a082004-07-15 12:53:49 +0000877static const unsigned char sp_off[] = {
878 offsetof(struct spwd, sp_namp), /* 0 */
879 offsetof(struct spwd, sp_pwdp), /* 1 */
880 offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000881 offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000882 offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000883 offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
884 offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
885 offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
886 offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
Eric Andersen9615a082004-07-15 12:53:49 +0000887};
888
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000889static int bb__parsespent(void *data, char * line)
Eric Andersen9615a082004-07-15 12:53:49 +0000890{
891 char *endptr;
892 char *p;
893 int i;
894
895 i = 0;
896 do {
897 p = ((char *) ((struct spwd *) data)) + sp_off[i];
898 if (i < 2) {
899 *((char **) p) = line;
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000900 line = strchr(line, ':');
901 if (!line) {
Eric Andersen9615a082004-07-15 12:53:49 +0000902 break;
903 }
904 } else {
Eric Andersen9615a082004-07-15 12:53:49 +0000905 *((long *) p) = (long) strtoul(line, &endptr, 10);
906
907 if (endptr == line) {
908 *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
909 }
910
911 line = endptr;
912
913 if (i == 8) {
914 if (!*endptr) {
915 return 0;
916 }
917 break;
918 }
919
920 if (*endptr != ':') {
921 break;
922 }
923
924 }
925
926 *line++ = 0;
927 ++i;
928 } while (1);
929
930 return EINVAL;
931}
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000932#endif
Eric Andersen9615a082004-07-15 12:53:49 +0000933
Eric Andersen9615a082004-07-15 12:53:49 +0000934/**********************************************************************/
Eric Andersen9615a082004-07-15 12:53:49 +0000935
936/* Reads until if EOF, or until if finds a line which fits in the buffer
937 * and for which the parser function succeeds.
938 *
939 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
940 */
941
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000942static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
Eric Andersen9615a082004-07-15 12:53:49 +0000943 char *__restrict line_buff, size_t buflen, FILE *f)
944{
945 int line_len;
946 int skip;
947 int rv = ERANGE;
948
949 if (buflen < PWD_BUFFER_SIZE) {
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000950 errno = rv;
Eric Andersen9615a082004-07-15 12:53:49 +0000951 } else {
952 skip = 0;
953 do {
Rob Landley25413bf2005-10-08 02:23:22 +0000954 if (!fgets(line_buff, buflen, f)) {
955 if (feof(f)) {
Eric Andersen9615a082004-07-15 12:53:49 +0000956 rv = ENOENT;
957 }
958 break;
959 }
960
961 line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
962 if (line_buff[line_len] == '\n') {
963 line_buff[line_len] = 0;
964 } else if (line_len + 2 == buflen) { /* line too long */
965 ++skip;
966 continue;
967 }
968
969 if (skip) {
970 --skip;
971 continue;
972 }
973
974 /* NOTE: glibc difference - glibc strips leading whitespace from
975 * records. We do not allow leading whitespace. */
976
977 /* Skip empty lines, comment lines, and lines with leading
978 * whitespace. */
979 if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
Denis Vlasenkocb04ff52006-12-30 21:11:57 +0000980 if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
Eric Andersen9615a082004-07-15 12:53:49 +0000981 /* The group entry parsing function needs to know where
982 * the end of the buffer is so that it can construct the
983 * group member ptr table. */
984 ((struct group *) data)->gr_name = line_buff + buflen;
985 }
986
Denis Vlasenko7fa0fca2006-12-28 21:33:30 +0000987 if (!parserfunc(data, line_buff)) {
Eric Andersen9615a082004-07-15 12:53:49 +0000988 rv = 0;
989 break;
990 }
991 }
992 } while (1);
993
994 }
995
996 return rv;
997}