pwd_grp.c 21 KB

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