pwd_grp.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  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. #ifdef THIS_ONE_IS_UNUSED
  337. /* This one doesn't use static buffers */
  338. int getpw(uid_t uid, char *buf)
  339. {
  340. struct passwd resultbuf;
  341. struct passwd *result;
  342. char buffer[PWD_BUFFER_SIZE];
  343. if (!buf) {
  344. errno = EINVAL;
  345. } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
  346. if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
  347. resultbuf.pw_name, resultbuf.pw_passwd,
  348. (unsigned long)(resultbuf.pw_uid),
  349. (unsigned long)(resultbuf.pw_gid),
  350. resultbuf.pw_gecos, resultbuf.pw_dir,
  351. resultbuf.pw_shell) >= 0
  352. ) {
  353. return 0;
  354. }
  355. }
  356. return -1;
  357. }
  358. #endif
  359. /**********************************************************************/
  360. /* FIXME: we don't have such CONFIG_xx - ?! */
  361. #if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
  362. static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
  363. # define LOCK pthread_mutex_lock(&mylock)
  364. # define UNLOCK pthread_mutex_unlock(&mylock);
  365. #else
  366. # define LOCK ((void) 0)
  367. # define UNLOCK ((void) 0)
  368. #endif
  369. static FILE *pwf /*= NULL*/;
  370. void setpwent(void)
  371. {
  372. LOCK;
  373. if (pwf) {
  374. rewind(pwf);
  375. }
  376. UNLOCK;
  377. }
  378. void endpwent(void)
  379. {
  380. LOCK;
  381. if (pwf) {
  382. fclose(pwf);
  383. pwf = NULL;
  384. }
  385. UNLOCK;
  386. }
  387. int getpwent_r(struct passwd *__restrict resultbuf,
  388. char *__restrict buffer, size_t buflen,
  389. struct passwd **__restrict result)
  390. {
  391. int rv;
  392. LOCK;
  393. *result = NULL; /* In case of error... */
  394. if (!pwf) {
  395. pwf = fopen_for_read(_PATH_PASSWD);
  396. if (!pwf) {
  397. rv = errno;
  398. goto ERR;
  399. }
  400. }
  401. rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
  402. if (!rv) {
  403. *result = resultbuf;
  404. }
  405. ERR:
  406. UNLOCK;
  407. return rv;
  408. }
  409. static FILE *grf /*= NULL*/;
  410. void setgrent(void)
  411. {
  412. LOCK;
  413. if (grf) {
  414. rewind(grf);
  415. }
  416. UNLOCK;
  417. }
  418. void endgrent(void)
  419. {
  420. LOCK;
  421. if (grf) {
  422. fclose(grf);
  423. grf = NULL;
  424. }
  425. UNLOCK;
  426. }
  427. int getgrent_r(struct group *__restrict resultbuf,
  428. char *__restrict buffer, size_t buflen,
  429. struct group **__restrict result)
  430. {
  431. int rv;
  432. LOCK;
  433. *result = NULL; /* In case of error... */
  434. if (!grf) {
  435. grf = fopen_for_read(_PATH_GROUP);
  436. if (!grf) {
  437. rv = errno;
  438. goto ERR;
  439. }
  440. }
  441. rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
  442. if (!rv) {
  443. *result = resultbuf;
  444. }
  445. ERR:
  446. UNLOCK;
  447. return rv;
  448. }
  449. #if ENABLE_USE_BB_SHADOW
  450. static FILE *spf /*= NULL*/;
  451. void setspent(void)
  452. {
  453. LOCK;
  454. if (spf) {
  455. rewind(spf);
  456. }
  457. UNLOCK;
  458. }
  459. void endspent(void)
  460. {
  461. LOCK;
  462. if (spf) {
  463. fclose(spf);
  464. spf = NULL;
  465. }
  466. UNLOCK;
  467. }
  468. int getspent_r(struct spwd *resultbuf, char *buffer,
  469. size_t buflen, struct spwd **result)
  470. {
  471. int rv;
  472. LOCK;
  473. *result = NULL; /* In case of error... */
  474. if (!spf) {
  475. spf = fopen_for_read(_PATH_SHADOW);
  476. if (!spf) {
  477. rv = errno;
  478. goto ERR;
  479. }
  480. }
  481. rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
  482. if (!rv) {
  483. *result = resultbuf;
  484. }
  485. ERR:
  486. UNLOCK;
  487. return rv;
  488. }
  489. #endif
  490. #if 0
  491. struct passwd *getpwent(void)
  492. {
  493. static char line_buff[PWD_BUFFER_SIZE];
  494. static struct passwd pwd;
  495. struct passwd *result;
  496. getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
  497. return result;
  498. }
  499. struct group *getgrent(void)
  500. {
  501. static char line_buff[GRP_BUFFER_SIZE];
  502. static struct group gr;
  503. struct group *result;
  504. getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
  505. return result;
  506. }
  507. #endif
  508. #if 0 //ENABLE_USE_BB_SHADOW
  509. struct spwd *getspent(void)
  510. {
  511. static char line_buff[PWD_BUFFER_SIZE];
  512. static struct spwd spwd;
  513. struct spwd *result;
  514. getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
  515. return result;
  516. }
  517. struct spwd *sgetspent(const char *string)
  518. {
  519. static char line_buff[PWD_BUFFER_SIZE];
  520. static struct spwd spwd;
  521. struct spwd *result;
  522. sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
  523. return result;
  524. }
  525. #endif
  526. static gid_t *getgrouplist_internal(int *ngroups_ptr, const char *user, gid_t gid)
  527. {
  528. FILE *grfile;
  529. gid_t *group_list;
  530. int ngroups;
  531. struct group group;
  532. char buff[PWD_BUFFER_SIZE];
  533. /* We alloc space for 8 gids at a time. */
  534. group_list = xmalloc(8 * sizeof(group_list[0]));
  535. group_list[0] = gid;
  536. ngroups = 1;
  537. grfile = fopen_for_read(_PATH_GROUP);
  538. if (grfile) {
  539. while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
  540. char **m;
  541. assert(group.gr_mem); /* Must have at least a NULL terminator. */
  542. if (group.gr_gid == gid)
  543. continue;
  544. for (m = group.gr_mem; *m; m++) {
  545. if (strcmp(*m, user) != 0)
  546. continue;
  547. group_list = xrealloc_vector(group_list, 3, ngroups);
  548. group_list[ngroups++] = group.gr_gid;
  549. break;
  550. }
  551. }
  552. fclose(grfile);
  553. }
  554. *ngroups_ptr = ngroups;
  555. return group_list;
  556. }
  557. int initgroups(const char *user, gid_t gid)
  558. {
  559. int ngroups;
  560. gid_t *group_list = getgrouplist_internal(&ngroups, user, gid);
  561. ngroups = setgroups(ngroups, group_list);
  562. free(group_list);
  563. return ngroups;
  564. }
  565. int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
  566. {
  567. int ngroups_old = *ngroups;
  568. gid_t *group_list = getgrouplist_internal(ngroups, user, gid);
  569. if (*ngroups <= ngroups_old) {
  570. ngroups_old = *ngroups;
  571. memcpy(groups, group_list, ngroups_old * sizeof(groups[0]));
  572. } else {
  573. ngroups_old = -1;
  574. }
  575. free(group_list);
  576. return ngroups_old;
  577. }
  578. int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
  579. {
  580. int rv = -1;
  581. if (!p || !f) {
  582. errno = EINVAL;
  583. } else {
  584. /* No extra thread locking is needed above what fprintf does. */
  585. if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
  586. p->pw_name, p->pw_passwd,
  587. (unsigned long)(p->pw_uid),
  588. (unsigned long)(p->pw_gid),
  589. p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
  590. ) {
  591. rv = 0;
  592. }
  593. }
  594. return rv;
  595. }
  596. int putgrent(const struct group *__restrict p, FILE *__restrict f)
  597. {
  598. static const char format[] ALIGN1 = ",%s";
  599. char **m;
  600. const char *fmt;
  601. int rv = -1;
  602. if (!p || !f) { /* Sigh... glibc checks. */
  603. errno = EINVAL;
  604. } else {
  605. if (fprintf(f, "%s:%s:%lu:",
  606. p->gr_name, p->gr_passwd,
  607. (unsigned long)(p->gr_gid)) >= 0
  608. ) {
  609. fmt = format + 1;
  610. assert(p->gr_mem);
  611. m = p->gr_mem;
  612. do {
  613. if (!*m) {
  614. if (fputc('\n', f) >= 0) {
  615. rv = 0;
  616. }
  617. break;
  618. }
  619. if (fprintf(f, fmt, *m) < 0) {
  620. break;
  621. }
  622. ++m;
  623. fmt = format;
  624. } while (1);
  625. }
  626. }
  627. return rv;
  628. }
  629. #if ENABLE_USE_BB_SHADOW
  630. static const unsigned char _sp_off[] ALIGN1 = {
  631. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  632. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  633. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  634. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  635. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  636. offsetof(struct spwd, sp_expire) /* 7 - not a char ptr */
  637. };
  638. int putspent(const struct spwd *p, FILE *stream)
  639. {
  640. static const char ld_format[] ALIGN1 = "%ld:";
  641. const char *f;
  642. long x;
  643. int i;
  644. int rv = -1;
  645. /* Unlike putpwent and putgrent, glibc does not check the args. */
  646. if (fprintf(stream, "%s:%s:", p->sp_namp,
  647. (p->sp_pwdp ? p->sp_pwdp : "")) < 0
  648. ) {
  649. goto DO_UNLOCK;
  650. }
  651. for (i = 0; i < sizeof(_sp_off); i++) {
  652. f = ld_format;
  653. x = *(const long *)(((const char *) p) + _sp_off[i]);
  654. if (x == -1) {
  655. f += 3;
  656. }
  657. if (fprintf(stream, f, x) < 0) {
  658. goto DO_UNLOCK;
  659. }
  660. }
  661. if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
  662. goto DO_UNLOCK;
  663. }
  664. if (fputc('\n', stream) > 0) {
  665. rv = 0;
  666. }
  667. DO_UNLOCK:
  668. return rv;
  669. }
  670. #endif
  671. /**********************************************************************/
  672. /* Internal uClibc functions. */
  673. /**********************************************************************/
  674. static const unsigned char pw_off[] ALIGN1 = {
  675. offsetof(struct passwd, pw_name), /* 0 */
  676. offsetof(struct passwd, pw_passwd), /* 1 */
  677. offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
  678. offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
  679. offsetof(struct passwd, pw_gecos), /* 4 */
  680. offsetof(struct passwd, pw_dir), /* 5 */
  681. offsetof(struct passwd, pw_shell) /* 6 */
  682. };
  683. static int bb__parsepwent(void *data, char *line)
  684. {
  685. char *endptr;
  686. char *p;
  687. int i;
  688. i = 0;
  689. do {
  690. p = (char *) data + pw_off[i];
  691. if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
  692. *((char **) p) = line;
  693. if (i==6) {
  694. return 0;
  695. }
  696. /* NOTE: glibc difference - glibc allows omission of
  697. * ':' seperators after the gid field if all remaining
  698. * entries are empty. We require all separators. */
  699. line = strchr(line, ':');
  700. if (!line) {
  701. break;
  702. }
  703. } else {
  704. unsigned long t = strtoul(line, &endptr, 10);
  705. /* Make sure we had at least one digit, and that the
  706. * failing char is the next field seperator ':'. See
  707. * glibc difference note above. */
  708. /* TODO: Also check for leading whitespace? */
  709. if ((endptr == line) || (*endptr != ':')) {
  710. break;
  711. }
  712. line = endptr;
  713. if (i & 1) { /* i == 3 -- gid */
  714. *((gid_t *) p) = t;
  715. } else { /* i == 2 -- uid */
  716. *((uid_t *) p) = t;
  717. }
  718. }
  719. *line++ = 0;
  720. ++i;
  721. } while (1);
  722. return -1;
  723. }
  724. /**********************************************************************/
  725. static const unsigned char gr_off[] ALIGN1 = {
  726. offsetof(struct group, gr_name), /* 0 */
  727. offsetof(struct group, gr_passwd), /* 1 */
  728. offsetof(struct group, gr_gid) /* 2 - not a char ptr */
  729. };
  730. static int bb__parsegrent(void *data, char *line)
  731. {
  732. char *endptr;
  733. char *p;
  734. int i;
  735. char **members;
  736. char *end_of_buf;
  737. end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
  738. i = 0;
  739. do {
  740. p = (char *) data + gr_off[i];
  741. if (i < 2) {
  742. *((char **) p) = line;
  743. line = strchr(line, ':');
  744. if (!line) {
  745. break;
  746. }
  747. *line++ = 0;
  748. ++i;
  749. } else {
  750. *((gid_t *) p) = strtoul(line, &endptr, 10);
  751. /* NOTE: glibc difference - glibc allows omission of the
  752. * trailing colon when there is no member list. We treat
  753. * this as an error. */
  754. /* Make sure we had at least one digit, and that the
  755. * failing char is the next field seperator ':'. See
  756. * glibc difference note above. */
  757. if ((endptr == line) || (*endptr != ':')) {
  758. break;
  759. }
  760. i = 1; /* Count terminating NULL ptr. */
  761. p = endptr;
  762. if (p[1]) { /* We have a member list to process. */
  763. /* Overwrite the last ':' with a ',' before counting.
  764. * This allows us to test for initial ',' and adds
  765. * one ',' so that the ',' count equals the member
  766. * count. */
  767. *p = ',';
  768. do {
  769. /* NOTE: glibc difference - glibc allows and trims leading
  770. * (but not trailing) space. We treat this as an error. */
  771. /* NOTE: glibc difference - glibc allows consecutive and
  772. * trailing commas, and ignores "empty string" users. We
  773. * treat this as an error. */
  774. if (*p == ',') {
  775. ++i;
  776. *p = 0; /* nul-terminate each member string. */
  777. if (!*++p || (*p == ',') || isspace(*p)) {
  778. goto ERR;
  779. }
  780. }
  781. } while (*++p);
  782. }
  783. /* Now align (p+1), rounding up. */
  784. /* Assumes sizeof(char **) is a power of 2. */
  785. members = (char **)( (((intptr_t) p) + sizeof(char **))
  786. & ~((intptr_t)(sizeof(char **) - 1)) );
  787. if (((char *)(members + i)) > end_of_buf) { /* No space. */
  788. break;
  789. }
  790. ((struct group *) data)->gr_mem = members;
  791. if (--i) {
  792. p = endptr; /* Pointing to char prior to first member. */
  793. do {
  794. *members++ = ++p;
  795. if (!--i) break;
  796. while (*++p) {}
  797. } while (1);
  798. }
  799. *members = NULL;
  800. return 0;
  801. }
  802. } while (1);
  803. ERR:
  804. return -1;
  805. }
  806. /**********************************************************************/
  807. #if ENABLE_USE_BB_SHADOW
  808. static const unsigned char sp_off[] ALIGN1 = {
  809. offsetof(struct spwd, sp_namp), /* 0 */
  810. offsetof(struct spwd, sp_pwdp), /* 1 */
  811. offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
  812. offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
  813. offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
  814. offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
  815. offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
  816. offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
  817. offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
  818. };
  819. static int bb__parsespent(void *data, char *line)
  820. {
  821. char *endptr;
  822. char *p;
  823. int i;
  824. i = 0;
  825. while (1) {
  826. p = (char *) data + sp_off[i];
  827. if (i < 2) {
  828. *((char **) p) = line;
  829. line = strchr(line, ':');
  830. if (!line) {
  831. break;
  832. }
  833. } else {
  834. *((long *) p) = strtoul(line, &endptr, 10);
  835. if (endptr == line) {
  836. *((long *) p) = (i != 8) ? -1L : (long)(~0UL);
  837. }
  838. line = endptr;
  839. if (i == 8) {
  840. if (!*endptr) {
  841. return 0;
  842. }
  843. break;
  844. }
  845. if (*endptr != ':') {
  846. break;
  847. }
  848. }
  849. *line++ = '\0';
  850. ++i;
  851. }
  852. return EINVAL;
  853. }
  854. #endif
  855. /**********************************************************************/
  856. /* Reads until if EOF, or until if finds a line which fits in the buffer
  857. * and for which the parser function succeeds.
  858. *
  859. * Returns 0 on success and ENOENT for end-of-file (glibc concession).
  860. */
  861. static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
  862. char *__restrict line_buff, size_t buflen, FILE *f)
  863. {
  864. int line_len;
  865. int skip;
  866. int rv = ERANGE;
  867. if (buflen < PWD_BUFFER_SIZE) {
  868. errno = rv;
  869. } else {
  870. skip = 0;
  871. do {
  872. if (!fgets(line_buff, buflen, f)) {
  873. if (feof(f)) {
  874. rv = ENOENT;
  875. }
  876. break;
  877. }
  878. line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
  879. if (line_buff[line_len] == '\n') {
  880. line_buff[line_len] = 0;
  881. } else if (line_len + 2 == buflen) { /* line too long */
  882. ++skip;
  883. continue;
  884. }
  885. if (skip) {
  886. --skip;
  887. continue;
  888. }
  889. /* NOTE: glibc difference - glibc strips leading whitespace from
  890. * records. We do not allow leading whitespace. */
  891. /* Skip empty lines, comment lines, and lines with leading
  892. * whitespace. */
  893. if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
  894. if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
  895. /* The group entry parsing function needs to know where
  896. * the end of the buffer is so that it can construct the
  897. * group member ptr table. */
  898. ((struct group *) data)->gr_name = line_buff + buflen;
  899. }
  900. if (!parserfunc(data, line_buff)) {
  901. rv = 0;
  902. break;
  903. }
  904. }
  905. } while (1);
  906. }
  907. return rv;
  908. }