pwd_grp.c 24 KB

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