pwd_grp.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. /* vi: set sw=4 ts=4: */
  2. /* Copyright (C) 2003 Manuel Novoa III
  3. *
  4. * Licensed under GPL v2, or later. See file LICENSE in this tarball.
  5. */
  6. /* Nov 6, 2003 Initial version.
  7. *
  8. * NOTE: This implementation is quite strict about requiring all
  9. * field seperators. It also does not allow leading whitespace
  10. * except when processing the numeric fields. glibc is more
  11. * lenient. See the various glibc difference comments below.
  12. *
  13. * TODO:
  14. * Move to dynamic allocation of (currently statically allocated)
  15. * buffers; especially for the group-related functions since
  16. * large group member lists will cause error returns.
  17. *
  18. */
  19. #include "libbb.h"
  20. #include <features.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <stdint.h>
  24. #include <string.h>
  25. #include <stddef.h>
  26. #include <errno.h>
  27. #include <assert.h>
  28. #include <ctype.h>
  29. #ifndef _PATH_SHADOW
  30. #define _PATH_SHADOW "/etc/shadow"
  31. #endif
  32. #ifndef _PATH_PASSWD
  33. #define _PATH_PASSWD "/etc/passwd"
  34. #endif
  35. #ifndef _PATH_GROUP
  36. #define _PATH_GROUP "/etc/group"
  37. #endif
  38. /**********************************************************************/
  39. /* Sizes for statically allocated buffers. */
  40. /* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
  41. * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
  42. #define PWD_BUFFER_SIZE 256
  43. #define GRP_BUFFER_SIZE 256
  44. /**********************************************************************/
  45. /* Prototypes for internal functions. */
  46. extern int __parsepwent(void *pw, char *line);
  47. extern int __parsegrent(void *gr, char *line);
  48. #if ENABLE_USE_BB_SHADOW
  49. extern int __parsespent(void *sp, char *line);
  50. #endif
  51. extern int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
  52. char *__restrict line_buff, size_t buflen, FILE *f);
  53. /**********************************************************************/
  54. /* For the various fget??ent_r funcs, return
  55. *
  56. * 0: success
  57. * ENOENT: end-of-file encountered
  58. * ERANGE: buflen too small
  59. * other error values possible. See __pgsreader.
  60. *
  61. * Also, *result == resultbuf on success and NULL on failure.
  62. *
  63. * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
  64. * We do not, as it really isn't an error if we reach the end-of-file.
  65. * Doing so is analogous to having fgetc() set errno on EOF.
  66. */
  67. /**********************************************************************/
  68. int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
  69. char *__restrict buffer, size_t buflen,
  70. struct passwd **__restrict result)
  71. {
  72. int rv;
  73. *result = NULL;
  74. if (!(rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, stream))) {
  75. *result = resultbuf;
  76. }
  77. return rv;
  78. }
  79. int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
  80. char *__restrict buffer, size_t buflen,
  81. struct group **__restrict result)
  82. {
  83. int rv;
  84. *result = NULL;
  85. if (!(rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, stream))) {
  86. *result = resultbuf;
  87. }
  88. return rv;
  89. }
  90. #if ENABLE_USE_BB_SHADOW
  91. int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
  92. char *__restrict buffer, size_t buflen,
  93. struct spwd **__restrict result)
  94. {
  95. int rv;
  96. *result = NULL;
  97. if (!(rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, stream))) {
  98. *result = resultbuf;
  99. }
  100. return rv;
  101. }
  102. #endif
  103. /**********************************************************************/
  104. /* For the various fget??ent funcs, return NULL on failure and a
  105. * pointer to the appropriate struct (statically allocated) on success.
  106. */
  107. /**********************************************************************/
  108. struct passwd *fgetpwent(FILE *stream)
  109. {
  110. static char buffer[PWD_BUFFER_SIZE];
  111. static struct passwd resultbuf;
  112. struct passwd *result;
  113. fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
  114. return result;
  115. }
  116. struct group *fgetgrent(FILE *stream)
  117. {
  118. static char buffer[GRP_BUFFER_SIZE];
  119. static struct group resultbuf;
  120. struct group *result;
  121. fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
  122. return result;
  123. }
  124. #if ENABLE_USE_BB_SHADOW
  125. extern int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
  126. char *__restrict buffer, size_t buflen,
  127. struct spwd **__restrict result);
  128. struct spwd *fgetspent(FILE *stream)
  129. {
  130. static char buffer[PWD_BUFFER_SIZE];
  131. static struct spwd resultbuf;
  132. struct spwd *result;
  133. fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
  134. return result;
  135. }
  136. int sgetspent_r(const char *string, struct spwd *result_buf,
  137. char *buffer, size_t buflen, struct spwd **result)
  138. {
  139. int rv = ERANGE;
  140. *result = NULL;
  141. if (buflen < PWD_BUFFER_SIZE) {
  142. DO_ERANGE:
  143. errno=rv;
  144. goto DONE;
  145. }
  146. if (string != buffer) {
  147. if (strlen(string) >= buflen) {
  148. goto DO_ERANGE;
  149. }
  150. strcpy(buffer, string);
  151. }
  152. if (!(rv = __parsespent(result_buf, buffer))) {
  153. *result = result_buf;
  154. }
  155. DONE:
  156. return rv;
  157. }
  158. #endif
  159. /**********************************************************************/
  160. #ifdef GETXXKEY_R_FUNC
  161. #error GETXXKEY_R_FUNC is already defined!
  162. #endif
  163. #define GETXXKEY_R_FUNC getpwnam_R
  164. #define GETXXKEY_R_PARSER __parsepwent
  165. #define GETXXKEY_R_ENTTYPE struct passwd
  166. #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
  167. #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
  168. #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
  169. #include "pwd_grp_internal.c"
  170. #define GETXXKEY_R_FUNC getgrnam_R
  171. #define GETXXKEY_R_PARSER __parsegrent
  172. #define GETXXKEY_R_ENTTYPE struct group
  173. #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
  174. #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
  175. #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
  176. #include "pwd_grp_internal.c"
  177. #if ENABLE_USE_BB_SHADOW
  178. #define GETXXKEY_R_FUNC getspnam_R
  179. #define GETXXKEY_R_PARSER __parsespent
  180. #define GETXXKEY_R_ENTTYPE struct spwd
  181. #define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
  182. #define DO_GETXXKEY_R_KEYTYPE const char *__restrict
  183. #define DO_GETXXKEY_R_PATHNAME _PATH_SHADOW
  184. #include "pwd_grp_internal.c"
  185. #endif
  186. #define GETXXKEY_R_FUNC getpwuid_R
  187. #define GETXXKEY_R_PARSER __parsepwent
  188. #define GETXXKEY_R_ENTTYPE struct passwd
  189. #define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
  190. #define DO_GETXXKEY_R_KEYTYPE uid_t
  191. #define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
  192. #include "pwd_grp_internal.c"
  193. #define GETXXKEY_R_FUNC getgrgid_R
  194. #define GETXXKEY_R_PARSER __parsegrent
  195. #define GETXXKEY_R_ENTTYPE struct group
  196. #define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
  197. #define DO_GETXXKEY_R_KEYTYPE gid_t
  198. #define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
  199. #include "pwd_grp_internal.c"
  200. /**********************************************************************/
  201. struct passwd *getpwuid(uid_t uid)
  202. {
  203. static char buffer[PWD_BUFFER_SIZE];
  204. static struct passwd resultbuf;
  205. struct passwd *result;
  206. getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
  207. return result;
  208. }
  209. struct group *getgrgid(gid_t gid)
  210. {
  211. static char buffer[GRP_BUFFER_SIZE];
  212. static struct group resultbuf;
  213. struct group *result;
  214. getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
  215. return result;
  216. }
  217. #if 0 //ENABLE_USE_BB_SHADOW
  218. /* This function is non-standard and is currently not built. It seems
  219. * to have been created as a reentrant version of the non-standard
  220. * functions getspuid. Why getspuid was added, I do not know. */
  221. int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
  222. char *__restrict buffer, size_t buflen,
  223. struct spwd **__restrict result)
  224. {
  225. int rv;
  226. struct passwd *pp;
  227. struct passwd password;
  228. char pwd_buff[PWD_BUFFER_SIZE];
  229. *result = NULL;
  230. if (!(rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp))) {
  231. rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
  232. }
  233. return rv;
  234. }
  235. /* This function is non-standard and is currently not built.
  236. * Why it was added, I do not know. */
  237. struct spwd *getspuid(uid_t uid)
  238. {
  239. static char buffer[PWD_BUFFER_SIZE];
  240. static struct spwd resultbuf;
  241. struct spwd *result;
  242. getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
  243. return result;
  244. }
  245. #endif
  246. struct passwd *getpwnam(const char *name)
  247. {
  248. static char buffer[PWD_BUFFER_SIZE];
  249. static struct passwd resultbuf;
  250. struct passwd *result;
  251. getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
  252. return result;
  253. }
  254. struct group *getgrnam(const char *name)
  255. {
  256. static char buffer[GRP_BUFFER_SIZE];
  257. static struct group resultbuf;
  258. struct group *result;
  259. getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
  260. return result;
  261. }
  262. #if ENABLE_USE_BB_SHADOW
  263. struct spwd *getspnam(const char *name)
  264. {
  265. static char buffer[PWD_BUFFER_SIZE];
  266. static struct spwd resultbuf;
  267. struct spwd *result;
  268. getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
  269. return result;
  270. }
  271. #endif
  272. int getpw(uid_t uid, char *buf)
  273. {
  274. struct passwd resultbuf;
  275. struct passwd *result;
  276. char buffer[PWD_BUFFER_SIZE];
  277. if (!buf) {
  278. errno=EINVAL;
  279. } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
  280. if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
  281. resultbuf.pw_name, resultbuf.pw_passwd,
  282. (unsigned long)(resultbuf.pw_uid),
  283. (unsigned long)(resultbuf.pw_gid),
  284. resultbuf.pw_gecos, resultbuf.pw_dir,
  285. resultbuf.pw_shell) >= 0
  286. ) {
  287. return 0;
  288. }
  289. }
  290. return -1;
  291. }
  292. /**********************************************************************/
  293. #if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
  294. static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
  295. # define LOCK pthread_mutex_lock(&mylock)
  296. # define UNLOCK pthread_mutex_unlock(&mylock);
  297. #else
  298. # define LOCK ((void) 0)
  299. # define UNLOCK ((void) 0)
  300. #endif
  301. static FILE *pwf /*= NULL*/;
  302. void setpwent(void)
  303. {
  304. LOCK;
  305. if (pwf) {
  306. rewind(pwf);
  307. }
  308. UNLOCK;
  309. }
  310. void endpwent(void)
  311. {
  312. LOCK;
  313. if (pwf) {
  314. fclose(pwf);
  315. pwf = NULL;
  316. }
  317. UNLOCK;
  318. }
  319. int getpwent_r(struct passwd *__restrict resultbuf,
  320. char *__restrict buffer, size_t buflen,
  321. struct passwd **__restrict result)
  322. {
  323. int rv;
  324. LOCK;
  325. *result = NULL; /* In case of error... */
  326. if (!pwf) {
  327. if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
  328. rv = errno;
  329. goto ERR;
  330. }
  331. }
  332. if (!(rv = __pgsreader(__parsepwent, resultbuf,
  333. buffer, buflen, pwf))) {
  334. *result = resultbuf;
  335. }
  336. ERR:
  337. UNLOCK;
  338. return rv;
  339. }
  340. static FILE *grf /*= NULL*/;
  341. void setgrent(void)
  342. {
  343. LOCK;
  344. if (grf) {
  345. rewind(grf);
  346. }
  347. UNLOCK;
  348. }
  349. void endgrent(void)
  350. {
  351. LOCK;
  352. if (grf) {
  353. fclose(grf);
  354. grf = NULL;
  355. }
  356. UNLOCK;
  357. }
  358. int getgrent_r(struct group *__restrict resultbuf,
  359. char *__restrict buffer, size_t buflen,
  360. struct group **__restrict result)
  361. {
  362. int rv;
  363. LOCK;
  364. *result = NULL; /* In case of error... */
  365. if (!grf) {
  366. if (!(grf = fopen(_PATH_GROUP, "r"))) {
  367. rv = errno;
  368. goto ERR;
  369. }
  370. }
  371. if (!(rv = __pgsreader(__parsegrent, resultbuf,
  372. buffer, buflen, grf))) {
  373. *result = resultbuf;
  374. }
  375. ERR:
  376. UNLOCK;
  377. return rv;
  378. }
  379. #if ENABLE_USE_BB_SHADOW
  380. static FILE *spf /*= NULL*/;
  381. void setspent(void)
  382. {
  383. LOCK;
  384. if (spf) {
  385. rewind(spf);
  386. }
  387. UNLOCK;
  388. }
  389. void endspent(void)
  390. {
  391. LOCK;
  392. if (spf) {
  393. fclose(spf);
  394. spf = NULL;
  395. }
  396. UNLOCK;
  397. }
  398. int getspent_r(struct spwd *resultbuf, char *buffer,
  399. size_t buflen, struct spwd **result)
  400. {
  401. int rv;
  402. LOCK;
  403. *result = NULL; /* In case of error... */
  404. if (!spf) {
  405. if (!(spf = fopen(_PATH_SHADOW, "r"))) {
  406. rv = errno;
  407. goto ERR;
  408. }
  409. }
  410. if (!(rv = __pgsreader(__parsespent, resultbuf,
  411. buffer, buflen, spf))) {
  412. *result = resultbuf;
  413. }
  414. ERR:
  415. UNLOCK;
  416. return rv;
  417. }
  418. #endif
  419. struct passwd *getpwent(void)
  420. {
  421. static char line_buff[PWD_BUFFER_SIZE];
  422. static struct passwd pwd;
  423. struct passwd *result;
  424. getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
  425. return result;
  426. }
  427. struct group *getgrent(void)
  428. {
  429. static char line_buff[GRP_BUFFER_SIZE];
  430. static struct group gr;
  431. struct group *result;
  432. getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
  433. return result;
  434. }
  435. #if ENABLE_USE_BB_SHADOW
  436. struct spwd *getspent(void)
  437. {
  438. static char line_buff[PWD_BUFFER_SIZE];
  439. static struct spwd spwd;
  440. struct spwd *result;
  441. getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
  442. return result;
  443. }
  444. struct spwd *sgetspent(const char *string)
  445. {
  446. static char line_buff[PWD_BUFFER_SIZE];
  447. static struct spwd spwd;
  448. struct spwd *result;
  449. sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
  450. return result;
  451. }
  452. #endif
  453. int initgroups(const char *user, gid_t gid)
  454. {
  455. FILE *grfile;
  456. gid_t *group_list;
  457. int num_groups, rv;
  458. char **m;
  459. struct group group;
  460. char buff[PWD_BUFFER_SIZE];
  461. rv = -1;
  462. /* We alloc space for 8 gids at a time. */
  463. if (((group_list = (gid_t *) malloc(8*sizeof(gid_t *))) != NULL)
  464. && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
  465. ) {
  466. *group_list = gid;
  467. num_groups = 1;
  468. while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) {
  469. assert(group.gr_mem); /* Must have at least a NULL terminator. */
  470. if (group.gr_gid != gid) {
  471. for (m=group.gr_mem ; *m ; m++) {
  472. if (!strcmp(*m, user)) {
  473. if (!(num_groups & 7)) {
  474. gid_t *tmp = (gid_t *)
  475. realloc(group_list,
  476. (num_groups+8) * sizeof(gid_t *));
  477. if (!tmp) {
  478. rv = -1;
  479. goto DO_CLOSE;
  480. }
  481. group_list = tmp;
  482. }
  483. group_list[num_groups++] = group.gr_gid;
  484. break;
  485. }
  486. }
  487. }
  488. }
  489. rv = setgroups(num_groups, group_list);
  490. DO_CLOSE:
  491. fclose(grfile);
  492. }
  493. /* group_list will be NULL if initial malloc failed, which may trigger
  494. * warnings from various malloc debuggers. */
  495. free(group_list);
  496. return rv;
  497. }
  498. int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
  499. {
  500. int rv = -1;
  501. if (!p || !f) {
  502. errno=EINVAL;
  503. } else {
  504. /* No extra thread locking is needed above what fprintf does. */
  505. if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
  506. p->pw_name, p->pw_passwd,
  507. (unsigned long)(p->pw_uid),
  508. (unsigned long)(p->pw_gid),
  509. p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
  510. ) {
  511. rv = 0;
  512. }
  513. }
  514. return rv;
  515. }
  516. int putgrent(const struct group *__restrict p, FILE *__restrict f)
  517. {
  518. static const char format[] = ",%s";
  519. char **m;
  520. const char *fmt;
  521. int rv = -1;
  522. if (!p || !f) { /* Sigh... glibc checks. */
  523. errno=EINVAL;
  524. } else {
  525. if (fprintf(f, "%s:%s:%lu:",
  526. p->gr_name, p->gr_passwd,
  527. (unsigned long)(p->gr_gid)) >= 0
  528. ) {
  529. fmt = format + 1;
  530. assert(p->gr_mem);
  531. m = p->gr_mem;
  532. do {
  533. if (!*m) {
  534. if (fputc('\n', f) >= 0) {
  535. rv = 0;
  536. }
  537. break;
  538. }
  539. if (fprintf(f, fmt, *m) < 0) {
  540. break;
  541. }
  542. ++m;
  543. fmt = format;
  544. } while (1);
  545. }
  546. }
  547. return rv;
  548. }
  549. #if ENABLE_USE_BB_SHADOW
  550. static const unsigned char _sp_off[] = {
  551. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  552. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  553. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  554. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  555. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  556. offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
  557. };
  558. int putspent(const struct spwd *p, FILE *stream)
  559. {
  560. static const char ld_format[] = "%ld:";
  561. const char *f;
  562. long int x;
  563. int i;
  564. int rv = -1;
  565. /* Unlike putpwent and putgrent, glibc does not check the args. */
  566. if (fprintf(stream, "%s:%s:", p->sp_namp,
  567. (p->sp_pwdp ? p->sp_pwdp : "")) < 0
  568. ) {
  569. goto DO_UNLOCK;
  570. }
  571. for (i=0 ; i < sizeof(_sp_off) ; i++) {
  572. f = ld_format;
  573. if ((x = *(const long int *)(((const char *) p) + _sp_off[i])) == -1) {
  574. f += 3;
  575. }
  576. if (fprintf(stream, f, x) < 0) {
  577. goto DO_UNLOCK;
  578. }
  579. }
  580. if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
  581. goto DO_UNLOCK;
  582. }
  583. if (fputc('\n', stream) > 0) {
  584. rv = 0;
  585. }
  586. DO_UNLOCK:
  587. return rv;
  588. }
  589. #endif
  590. /**********************************************************************/
  591. /* Internal uClibc functions. */
  592. /**********************************************************************/
  593. static const unsigned char pw_off[] = {
  594. offsetof(struct passwd, pw_name), /* 0 */
  595. offsetof(struct passwd, pw_passwd), /* 1 */
  596. offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
  597. offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
  598. offsetof(struct passwd, pw_gecos), /* 4 */
  599. offsetof(struct passwd, pw_dir), /* 5 */
  600. offsetof(struct passwd, pw_shell) /* 6 */
  601. };
  602. int __parsepwent(void *data, char *line)
  603. {
  604. char *endptr;
  605. char *p;
  606. int i;
  607. i = 0;
  608. do {
  609. p = ((char *) ((struct passwd *) data)) + pw_off[i];
  610. if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
  611. *((char **) p) = line;
  612. if (i==6) {
  613. return 0;
  614. }
  615. /* NOTE: glibc difference - glibc allows omission of
  616. * ':' seperators after the gid field if all remaining
  617. * entries are empty. We require all separators. */
  618. if (!(line = strchr(line, ':'))) {
  619. break;
  620. }
  621. } else {
  622. unsigned long t = strtoul(line, &endptr, 10);
  623. /* Make sure we had at least one digit, and that the
  624. * failing char is the next field seperator ':'. See
  625. * glibc difference note above. */
  626. /* TODO: Also check for leading whitespace? */
  627. if ((endptr == line) || (*endptr != ':')) {
  628. break;
  629. }
  630. line = endptr;
  631. if (i & 1) { /* i == 3 -- gid */
  632. *((gid_t *) p) = t;
  633. } else { /* i == 2 -- uid */
  634. *((uid_t *) p) = t;
  635. }
  636. }
  637. *line++ = 0;
  638. ++i;
  639. } while (1);
  640. return -1;
  641. }
  642. /**********************************************************************/
  643. static const unsigned char gr_off[] = {
  644. offsetof(struct group, gr_name), /* 0 */
  645. offsetof(struct group, gr_passwd), /* 1 */
  646. offsetof(struct group, gr_gid) /* 2 - not a char ptr */
  647. };
  648. int __parsegrent(void *data, char *line)
  649. {
  650. char *endptr;
  651. char *p;
  652. int i;
  653. char **members;
  654. char *end_of_buf;
  655. end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
  656. i = 0;
  657. do {
  658. p = ((char *) ((struct group *) data)) + gr_off[i];
  659. if (i < 2) {
  660. *((char **) p) = line;
  661. if (!(line = strchr(line, ':'))) {
  662. break;
  663. }
  664. *line++ = 0;
  665. ++i;
  666. } else {
  667. *((gid_t *) p) = strtoul(line, &endptr, 10);
  668. /* NOTE: glibc difference - glibc allows omission of the
  669. * trailing colon when there is no member list. We treat
  670. * this as an error. */
  671. /* Make sure we had at least one digit, and that the
  672. * failing char is the next field seperator ':'. See
  673. * glibc difference note above. */
  674. if ((endptr == line) || (*endptr != ':')) {
  675. break;
  676. }
  677. i = 1; /* Count terminating NULL ptr. */
  678. p = endptr;
  679. if (p[1]) { /* We have a member list to process. */
  680. /* Overwrite the last ':' with a ',' before counting.
  681. * This allows us to test for initial ',' and adds
  682. * one ',' so that the ',' count equals the member
  683. * count. */
  684. *p = ',';
  685. do {
  686. /* NOTE: glibc difference - glibc allows and trims leading
  687. * (but not trailing) space. We treat this as an error. */
  688. /* NOTE: glibc difference - glibc allows consecutive and
  689. * trailing commas, and ignores "empty string" users. We
  690. * treat this as an error. */
  691. if (*p == ',') {
  692. ++i;
  693. *p = 0; /* nul-terminate each member string. */
  694. if (!*++p || (*p == ',') || isspace(*p)) {
  695. goto ERR;
  696. }
  697. }
  698. } while (*++p);
  699. }
  700. /* Now align (p+1), rounding up. */
  701. /* Assumes sizeof(char **) is a power of 2. */
  702. members = (char **)( (((intptr_t) p) + sizeof(char **))
  703. & ~((intptr_t)(sizeof(char **) - 1)) );
  704. if (((char *)(members + i)) > end_of_buf) { /* No space. */
  705. break;
  706. }
  707. ((struct group *) data)->gr_mem = members;
  708. if (--i) {
  709. p = endptr; /* Pointing to char prior to first member. */
  710. do {
  711. *members++ = ++p;
  712. if (!--i) break;
  713. while (*++p) {}
  714. } while (1);
  715. }
  716. *members = NULL;
  717. return 0;
  718. }
  719. } while (1);
  720. ERR:
  721. return -1;
  722. }
  723. /**********************************************************************/
  724. #if ENABLE_USE_BB_SHADOW
  725. static const unsigned char sp_off[] = {
  726. offsetof(struct spwd, sp_namp), /* 0 */
  727. offsetof(struct spwd, sp_pwdp), /* 1 */
  728. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  729. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  730. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  731. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  732. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  733. offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
  734. offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
  735. };
  736. int __parsespent(void *data, char * line)
  737. {
  738. char *endptr;
  739. char *p;
  740. int i;
  741. i = 0;
  742. do {
  743. p = ((char *) ((struct spwd *) data)) + sp_off[i];
  744. if (i < 2) {
  745. *((char **) p) = line;
  746. if (!(line = strchr(line, ':'))) {
  747. break;
  748. }
  749. } else {
  750. *((long *) p) = (long) strtoul(line, &endptr, 10);
  751. if (endptr == line) {
  752. *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
  753. }
  754. line = endptr;
  755. if (i == 8) {
  756. if (!*endptr) {
  757. return 0;
  758. }
  759. break;
  760. }
  761. if (*endptr != ':') {
  762. break;
  763. }
  764. }
  765. *line++ = 0;
  766. ++i;
  767. } while (1);
  768. return EINVAL;
  769. }
  770. #endif
  771. /**********************************************************************/
  772. /* Reads until if EOF, or until if finds a line which fits in the buffer
  773. * and for which the parser function succeeds.
  774. *
  775. * Returns 0 on success and ENOENT for end-of-file (glibc concession).
  776. */
  777. int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
  778. char *__restrict line_buff, size_t buflen, FILE *f)
  779. {
  780. int line_len;
  781. int skip;
  782. int rv = ERANGE;
  783. if (buflen < PWD_BUFFER_SIZE) {
  784. errno=rv;
  785. } else {
  786. skip = 0;
  787. do {
  788. if (!fgets(line_buff, buflen, f)) {
  789. if (feof(f)) {
  790. rv = ENOENT;
  791. }
  792. break;
  793. }
  794. line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
  795. if (line_buff[line_len] == '\n') {
  796. line_buff[line_len] = 0;
  797. } else if (line_len + 2 == buflen) { /* line too long */
  798. ++skip;
  799. continue;
  800. }
  801. if (skip) {
  802. --skip;
  803. continue;
  804. }
  805. /* NOTE: glibc difference - glibc strips leading whitespace from
  806. * records. We do not allow leading whitespace. */
  807. /* Skip empty lines, comment lines, and lines with leading
  808. * whitespace. */
  809. if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
  810. if (__parserfunc == __parsegrent) { /* Do evil group hack. */
  811. /* The group entry parsing function needs to know where
  812. * the end of the buffer is so that it can construct the
  813. * group member ptr table. */
  814. ((struct group *) data)->gr_name = line_buff + buflen;
  815. }
  816. if (!__parserfunc(data, line_buff)) {
  817. rv = 0;
  818. break;
  819. }
  820. }
  821. } while (1);
  822. }
  823. return rv;
  824. }
  825. /**********************************************************************/