3
0

pwd_grp.c 24 KB

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