3
0

pwd_grp.c 24 KB

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