3
0

pwd_grp.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  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. /* We alloc space for 8 gids at a time. */
  534. group_list = (gid_t *) malloc(8*sizeof(gid_t *));
  535. if (group_list
  536. && ((grfile = fopen(_PATH_GROUP, "r")) != NULL)
  537. ) {
  538. *group_list = gid;
  539. num_groups = 1;
  540. while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
  541. assert(group.gr_mem); /* Must have at least a NULL terminator. */
  542. if (group.gr_gid != gid) {
  543. for (m = group.gr_mem; *m; m++) {
  544. if (!strcmp(*m, user)) {
  545. if (!(num_groups & 7)) {
  546. gid_t *tmp = (gid_t *)
  547. realloc(group_list,
  548. (num_groups+8) * sizeof(gid_t *));
  549. if (!tmp) {
  550. rv = -1;
  551. goto DO_CLOSE;
  552. }
  553. group_list = tmp;
  554. }
  555. group_list[num_groups++] = group.gr_gid;
  556. break;
  557. }
  558. }
  559. }
  560. }
  561. rv = setgroups(num_groups, group_list);
  562. DO_CLOSE:
  563. fclose(grfile);
  564. }
  565. /* group_list will be NULL if initial malloc failed, which may trigger
  566. * warnings from various malloc debuggers. */
  567. free(group_list);
  568. return rv;
  569. }
  570. int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
  571. {
  572. int rv = -1;
  573. if (!p || !f) {
  574. errno=EINVAL;
  575. } else {
  576. /* No extra thread locking is needed above what fprintf does. */
  577. if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
  578. p->pw_name, p->pw_passwd,
  579. (unsigned long)(p->pw_uid),
  580. (unsigned long)(p->pw_gid),
  581. p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
  582. ) {
  583. rv = 0;
  584. }
  585. }
  586. return rv;
  587. }
  588. int putgrent(const struct group *__restrict p, FILE *__restrict f)
  589. {
  590. static const char format[] ALIGN1 = ",%s";
  591. char **m;
  592. const char *fmt;
  593. int rv = -1;
  594. if (!p || !f) { /* Sigh... glibc checks. */
  595. errno=EINVAL;
  596. } else {
  597. if (fprintf(f, "%s:%s:%lu:",
  598. p->gr_name, p->gr_passwd,
  599. (unsigned long)(p->gr_gid)) >= 0
  600. ) {
  601. fmt = format + 1;
  602. assert(p->gr_mem);
  603. m = p->gr_mem;
  604. do {
  605. if (!*m) {
  606. if (fputc('\n', f) >= 0) {
  607. rv = 0;
  608. }
  609. break;
  610. }
  611. if (fprintf(f, fmt, *m) < 0) {
  612. break;
  613. }
  614. ++m;
  615. fmt = format;
  616. } while (1);
  617. }
  618. }
  619. return rv;
  620. }
  621. #if ENABLE_USE_BB_SHADOW
  622. static const unsigned char _sp_off[] ALIGN1 = {
  623. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  624. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  625. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  626. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  627. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  628. offsetof(struct spwd, sp_expire) /* 7 - not a char ptr */
  629. };
  630. int putspent(const struct spwd *p, FILE *stream)
  631. {
  632. static const char ld_format[] ALIGN1 = "%ld:";
  633. const char *f;
  634. long x;
  635. int i;
  636. int rv = -1;
  637. /* Unlike putpwent and putgrent, glibc does not check the args. */
  638. if (fprintf(stream, "%s:%s:", p->sp_namp,
  639. (p->sp_pwdp ? p->sp_pwdp : "")) < 0
  640. ) {
  641. goto DO_UNLOCK;
  642. }
  643. for (i = 0; i < sizeof(_sp_off); i++) {
  644. f = ld_format;
  645. x = *(const long *)(((const char *) p) + _sp_off[i]);
  646. if (x == -1) {
  647. f += 3;
  648. }
  649. if (fprintf(stream, f, x) < 0) {
  650. goto DO_UNLOCK;
  651. }
  652. }
  653. if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
  654. goto DO_UNLOCK;
  655. }
  656. if (fputc('\n', stream) > 0) {
  657. rv = 0;
  658. }
  659. DO_UNLOCK:
  660. return rv;
  661. }
  662. #endif
  663. /**********************************************************************/
  664. /* Internal uClibc functions. */
  665. /**********************************************************************/
  666. static const unsigned char pw_off[] ALIGN1 = {
  667. offsetof(struct passwd, pw_name), /* 0 */
  668. offsetof(struct passwd, pw_passwd), /* 1 */
  669. offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
  670. offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
  671. offsetof(struct passwd, pw_gecos), /* 4 */
  672. offsetof(struct passwd, pw_dir), /* 5 */
  673. offsetof(struct passwd, pw_shell) /* 6 */
  674. };
  675. static int bb__parsepwent(void *data, char *line)
  676. {
  677. char *endptr;
  678. char *p;
  679. int i;
  680. i = 0;
  681. do {
  682. p = ((char *) ((struct passwd *) data)) + pw_off[i];
  683. if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
  684. *((char **) p) = line;
  685. if (i==6) {
  686. return 0;
  687. }
  688. /* NOTE: glibc difference - glibc allows omission of
  689. * ':' seperators after the gid field if all remaining
  690. * entries are empty. We require all separators. */
  691. line = strchr(line, ':');
  692. if (!line) {
  693. break;
  694. }
  695. } else {
  696. unsigned long t = strtoul(line, &endptr, 10);
  697. /* Make sure we had at least one digit, and that the
  698. * failing char is the next field seperator ':'. See
  699. * glibc difference note above. */
  700. /* TODO: Also check for leading whitespace? */
  701. if ((endptr == line) || (*endptr != ':')) {
  702. break;
  703. }
  704. line = endptr;
  705. if (i & 1) { /* i == 3 -- gid */
  706. *((gid_t *) p) = t;
  707. } else { /* i == 2 -- uid */
  708. *((uid_t *) p) = t;
  709. }
  710. }
  711. *line++ = 0;
  712. ++i;
  713. } while (1);
  714. return -1;
  715. }
  716. /**********************************************************************/
  717. static const unsigned char gr_off[] ALIGN1 = {
  718. offsetof(struct group, gr_name), /* 0 */
  719. offsetof(struct group, gr_passwd), /* 1 */
  720. offsetof(struct group, gr_gid) /* 2 - not a char ptr */
  721. };
  722. static int bb__parsegrent(void *data, char *line)
  723. {
  724. char *endptr;
  725. char *p;
  726. int i;
  727. char **members;
  728. char *end_of_buf;
  729. end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
  730. i = 0;
  731. do {
  732. p = ((char *) ((struct group *) data)) + gr_off[i];
  733. if (i < 2) {
  734. *((char **) p) = line;
  735. line = strchr(line, ':');
  736. if (!line) {
  737. break;
  738. }
  739. *line++ = 0;
  740. ++i;
  741. } else {
  742. *((gid_t *) p) = strtoul(line, &endptr, 10);
  743. /* NOTE: glibc difference - glibc allows omission of the
  744. * trailing colon when there is no member list. We treat
  745. * this as an error. */
  746. /* Make sure we had at least one digit, and that the
  747. * failing char is the next field seperator ':'. See
  748. * glibc difference note above. */
  749. if ((endptr == line) || (*endptr != ':')) {
  750. break;
  751. }
  752. i = 1; /* Count terminating NULL ptr. */
  753. p = endptr;
  754. if (p[1]) { /* We have a member list to process. */
  755. /* Overwrite the last ':' with a ',' before counting.
  756. * This allows us to test for initial ',' and adds
  757. * one ',' so that the ',' count equals the member
  758. * count. */
  759. *p = ',';
  760. do {
  761. /* NOTE: glibc difference - glibc allows and trims leading
  762. * (but not trailing) space. We treat this as an error. */
  763. /* NOTE: glibc difference - glibc allows consecutive and
  764. * trailing commas, and ignores "empty string" users. We
  765. * treat this as an error. */
  766. if (*p == ',') {
  767. ++i;
  768. *p = 0; /* nul-terminate each member string. */
  769. if (!*++p || (*p == ',') || isspace(*p)) {
  770. goto ERR;
  771. }
  772. }
  773. } while (*++p);
  774. }
  775. /* Now align (p+1), rounding up. */
  776. /* Assumes sizeof(char **) is a power of 2. */
  777. members = (char **)( (((intptr_t) p) + sizeof(char **))
  778. & ~((intptr_t)(sizeof(char **) - 1)) );
  779. if (((char *)(members + i)) > end_of_buf) { /* No space. */
  780. break;
  781. }
  782. ((struct group *) data)->gr_mem = members;
  783. if (--i) {
  784. p = endptr; /* Pointing to char prior to first member. */
  785. do {
  786. *members++ = ++p;
  787. if (!--i) break;
  788. while (*++p) {}
  789. } while (1);
  790. }
  791. *members = NULL;
  792. return 0;
  793. }
  794. } while (1);
  795. ERR:
  796. return -1;
  797. }
  798. /**********************************************************************/
  799. #if ENABLE_USE_BB_SHADOW
  800. static const unsigned char sp_off[] ALIGN1 = {
  801. offsetof(struct spwd, sp_namp), /* 0 */
  802. offsetof(struct spwd, sp_pwdp), /* 1 */
  803. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  804. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  805. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  806. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  807. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  808. offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
  809. offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
  810. };
  811. static int bb__parsespent(void *data, char * line)
  812. {
  813. char *endptr;
  814. char *p;
  815. int i;
  816. i = 0;
  817. do {
  818. p = ((char *) ((struct spwd *) data)) + sp_off[i];
  819. if (i < 2) {
  820. *((char **) p) = line;
  821. line = strchr(line, ':');
  822. if (!line) {
  823. break;
  824. }
  825. } else {
  826. *((long *) p) = (long) strtoul(line, &endptr, 10);
  827. if (endptr == line) {
  828. *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
  829. }
  830. line = endptr;
  831. if (i == 8) {
  832. if (!*endptr) {
  833. return 0;
  834. }
  835. break;
  836. }
  837. if (*endptr != ':') {
  838. break;
  839. }
  840. }
  841. *line++ = 0;
  842. ++i;
  843. } while (1);
  844. return EINVAL;
  845. }
  846. #endif
  847. /**********************************************************************/
  848. /* Reads until if EOF, or until if finds a line which fits in the buffer
  849. * and for which the parser function succeeds.
  850. *
  851. * Returns 0 on success and ENOENT for end-of-file (glibc concession).
  852. */
  853. static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
  854. char *__restrict line_buff, size_t buflen, FILE *f)
  855. {
  856. int line_len;
  857. int skip;
  858. int rv = ERANGE;
  859. if (buflen < PWD_BUFFER_SIZE) {
  860. errno = rv;
  861. } else {
  862. skip = 0;
  863. do {
  864. if (!fgets(line_buff, buflen, f)) {
  865. if (feof(f)) {
  866. rv = ENOENT;
  867. }
  868. break;
  869. }
  870. line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
  871. if (line_buff[line_len] == '\n') {
  872. line_buff[line_len] = 0;
  873. } else if (line_len + 2 == buflen) { /* line too long */
  874. ++skip;
  875. continue;
  876. }
  877. if (skip) {
  878. --skip;
  879. continue;
  880. }
  881. /* NOTE: glibc difference - glibc strips leading whitespace from
  882. * records. We do not allow leading whitespace. */
  883. /* Skip empty lines, comment lines, and lines with leading
  884. * whitespace. */
  885. if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
  886. if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
  887. /* The group entry parsing function needs to know where
  888. * the end of the buffer is so that it can construct the
  889. * group member ptr table. */
  890. ((struct group *) data)->gr_name = line_buff + buflen;
  891. }
  892. if (!parserfunc(data, line_buff)) {
  893. rv = 0;
  894. break;
  895. }
  896. }
  897. } while (1);
  898. }
  899. return rv;
  900. }