shadow.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. shadow.c
  9. Abstract:
  10. This module implements support for manipulating the shadow password file.
  11. Generally applications need to have special privileges for these functions
  12. to succeed.
  13. Author:
  14. Evan Green 3-Mar-2015
  15. Environment:
  16. User Mode C Library
  17. --*/
  18. //
  19. // ------------------------------------------------------------------- Includes
  20. //
  21. #include "libcp.h"
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <shadow.h>
  25. #include <stdlib.h>
  26. //
  27. // ---------------------------------------------------------------- Definitions
  28. //
  29. //
  30. // Define the path to the shadow lock file.
  31. //
  32. #define SHADOW_LOCK_PATH "/etc/.pwd.lock"
  33. //
  34. // Define how long to wait to acquire the lock in seconds.
  35. //
  36. #define SHADOW_LOCK_TIMEOUT 15
  37. //
  38. // ------------------------------------------------------ Data Type Definitions
  39. //
  40. //
  41. // ----------------------------------------------- Internal Function Prototypes
  42. //
  43. void
  44. ClpEmptySignalHandler (
  45. int Signal
  46. );
  47. //
  48. // -------------------------------------------------------------------- Globals
  49. //
  50. //
  51. // Store a pointer to the shadow password file.
  52. //
  53. FILE *ClShadowFile;
  54. //
  55. // Store a pointer to the shared shadow information structure. There is always
  56. // a buffer after this structure that is the maximum password file line size.
  57. //
  58. struct spwd *ClShadowInformation;
  59. //
  60. // Store the file descriptor for the locked shadow password file.
  61. //
  62. int ClShadowLockDescriptor = -1;
  63. //
  64. // ------------------------------------------------------------------ Functions
  65. //
  66. LIBC_API
  67. struct spwd *
  68. getspnam (
  69. const char *UserName
  70. )
  71. /*++
  72. Routine Description:
  73. This routine searches the shadow password database for a user matching the
  74. given name, and returns information about that user's password. This
  75. routine is neither reentrant nor thread safe.
  76. Arguments:
  77. UserName - Supplies a pointer to the null terminated string containing the
  78. user name to search for.
  79. Return Value:
  80. Returns a pointer to the user password information on success. This buffer
  81. may be overwritten by subsequent calls to getspent or getspnam.
  82. NULL on failure or if the given user was not found. On failure, errno will
  83. be set to provide more information.
  84. --*/
  85. {
  86. int Result;
  87. struct spwd *ResultPointer;
  88. if (ClShadowInformation == NULL) {
  89. ClShadowInformation = malloc(
  90. sizeof(struct spwd) + USER_DATABASE_LINE_MAX);
  91. if (ClShadowInformation == NULL) {
  92. return NULL;
  93. }
  94. }
  95. ResultPointer = NULL;
  96. Result = getspnam_r(UserName,
  97. ClShadowInformation,
  98. (char *)(ClShadowInformation + 1),
  99. USER_DATABASE_LINE_MAX,
  100. &ResultPointer);
  101. if (Result != 0) {
  102. return NULL;
  103. }
  104. return ResultPointer;
  105. }
  106. LIBC_API
  107. int
  108. getspnam_r (
  109. const char *UserName,
  110. struct spwd *PasswordInformation,
  111. char *Buffer,
  112. size_t BufferSize,
  113. struct spwd **Result
  114. )
  115. /*++
  116. Routine Description:
  117. This routine searches the shadow password database for a user matching the
  118. given name, and returns information about that user's password.
  119. Arguments:
  120. UserName - Supplies a pointer to the null terminated string containing the
  121. user name to search for.
  122. PasswordInformation - Supplies a pointer where the user's password
  123. information will be returned.
  124. Buffer - Supplies a buffer used to allocate strings that the user
  125. information points to out of. The maximum size needed for this buffer
  126. can be determined with the _SC_GETPW_R_SIZE_MAX sysconf parameter.
  127. BufferSize - Supplies the size of the supplied buffer in bytes.
  128. Result - Supplies a pointer where a pointer to the user information
  129. parameter will be returned on success, or NULL will be returned if the
  130. specified user could not be found.
  131. Return Value:
  132. 0 on success.
  133. Returns an error value on failure.
  134. --*/
  135. {
  136. FILE *File;
  137. struct spwd Information;
  138. int Status;
  139. *Result = NULL;
  140. File = fopen(_PATH_SHADOW, "r");
  141. if (File == NULL) {
  142. return errno;
  143. }
  144. //
  145. // Loop through looking for an entry that matches.
  146. //
  147. while (TRUE) {
  148. Status = fgetspent_r(File, &Information, Buffer, BufferSize, Result);
  149. if (Status != 0) {
  150. *Result = NULL;
  151. break;
  152. }
  153. if (*Result == NULL) {
  154. break;
  155. }
  156. //
  157. // If the user name matches, return it.
  158. //
  159. if (strcmp(Information.sp_namp, UserName) == 0) {
  160. memcpy(PasswordInformation, &Information, sizeof(Information));
  161. *Result = PasswordInformation;
  162. break;
  163. }
  164. }
  165. if (File != NULL) {
  166. fclose(File);
  167. }
  168. return Status;
  169. }
  170. LIBC_API
  171. struct spwd *
  172. getspent (
  173. void
  174. )
  175. /*++
  176. Routine Description:
  177. This routine returns a pointer to the broken out fields of the next entry
  178. in the user database. This function is neither thread-safe nor reentrant.
  179. Arguments:
  180. None.
  181. Return Value:
  182. Returns a pointer to the next entry in the user database. The caller may
  183. not modify or free this memory, and it may be overwritten by subsequent
  184. calls to getspent.
  185. NULL if the end of the user database is reached or on error.
  186. --*/
  187. {
  188. int Result;
  189. struct spwd *ReturnPointer;
  190. if (ClShadowInformation == NULL) {
  191. ClShadowInformation = malloc(
  192. sizeof(struct spwd) + USER_DATABASE_LINE_MAX);
  193. if (ClShadowInformation == NULL) {
  194. return NULL;
  195. }
  196. }
  197. ReturnPointer = NULL;
  198. Result = getspent_r(ClShadowInformation,
  199. (char *)(ClShadowInformation + 1),
  200. USER_DATABASE_LINE_MAX,
  201. &ReturnPointer);
  202. if (Result != 0) {
  203. errno = Result;
  204. return NULL;
  205. }
  206. return ReturnPointer;
  207. }
  208. LIBC_API
  209. int
  210. getspent_r (
  211. struct spwd *Information,
  212. char *Buffer,
  213. size_t BufferSize,
  214. struct spwd **ReturnPointer
  215. )
  216. /*++
  217. Routine Description:
  218. This routine returns a pointer to the broken out fields of the next entry
  219. in the user password database. This is the reentrant version of getspent.
  220. Arguments:
  221. Information - Supplies a pointer where the user password information will
  222. be returned on success.
  223. Buffer - Supplies a pointer to the buffer where strings will be stored.
  224. BufferSize - Supplies the size of the given buffer in bytes.
  225. ReturnPointer - Supplies a pointer to a pointer to a user password
  226. information structure. On success, the information pointer parameter
  227. will be returned here.
  228. Return Value:
  229. 0 on success.
  230. ENOENT if there are no more entries.
  231. Returns an error value on failure.
  232. --*/
  233. {
  234. int Result;
  235. if (ClShadowFile == NULL) {
  236. setspent();
  237. }
  238. if (ClShadowFile == NULL) {
  239. return errno;
  240. }
  241. Result = fgetspent_r(ClShadowFile,
  242. Information,
  243. Buffer,
  244. BufferSize,
  245. ReturnPointer);
  246. return Result;
  247. }
  248. LIBC_API
  249. struct spwd *
  250. fgetspent (
  251. FILE *File
  252. )
  253. /*++
  254. Routine Description:
  255. This routine returns a pointer to the broken out fields of the next entry
  256. in the user password database.
  257. Arguments:
  258. File - Supplies a pointer to a file to read the information from.
  259. Return Value:
  260. Returns a pointer to the next entry in the user database. The caller may
  261. not modify or free this memory, and it may be overwritten by subsequent
  262. calls to getspent.
  263. NULL if the end of the user database is reached or on error.
  264. --*/
  265. {
  266. int Result;
  267. struct spwd *ReturnPointer;
  268. if (ClShadowInformation == NULL) {
  269. ClShadowInformation = malloc(
  270. sizeof(struct spwd) + USER_DATABASE_LINE_MAX);
  271. if (ClShadowInformation == NULL) {
  272. return NULL;
  273. }
  274. }
  275. ReturnPointer = NULL;
  276. Result = fgetspent_r(File,
  277. ClShadowInformation,
  278. (char *)(ClShadowInformation + 1),
  279. USER_DATABASE_LINE_MAX,
  280. &ReturnPointer);
  281. if (Result != 0) {
  282. errno = Result;
  283. return NULL;
  284. }
  285. return ReturnPointer;
  286. }
  287. LIBC_API
  288. int
  289. fgetspent_r (
  290. FILE *File,
  291. struct spwd *Information,
  292. char *Buffer,
  293. size_t BufferSize,
  294. struct spwd **ReturnPointer
  295. )
  296. /*++
  297. Routine Description:
  298. This routine returns a pointer to the broken out fields of the next entry
  299. in the user password database.
  300. Arguments:
  301. File - Supplies a pointer to a file to read the information from.
  302. Information - Supplies a pointer where the user password information will
  303. be returned on success.
  304. Buffer - Supplies a pointer to the buffer where strings will be stored.
  305. BufferSize - Supplies the size of the given buffer in bytes.
  306. ReturnPointer - Supplies a pointer to a pointer to a user password
  307. information structure. On success, the information pointer parameter
  308. will be returned here.
  309. Return Value:
  310. 0 on success.
  311. ENOENT if there are no more entries.
  312. Returns an error value on failure.
  313. --*/
  314. {
  315. PSTR Current;
  316. CHAR Line[USER_DATABASE_LINE_MAX];
  317. PSTR OriginalBuffer;
  318. size_t OriginalBufferSize;
  319. int Result;
  320. OriginalBuffer = Buffer;
  321. OriginalBufferSize = BufferSize;
  322. //
  323. // Loop trying to scan a good line.
  324. //
  325. *ReturnPointer = NULL;
  326. while (TRUE) {
  327. if (fgets(Line, sizeof(Line), File) == NULL) {
  328. if (ferror(File)) {
  329. return errno;
  330. }
  331. return 0;
  332. }
  333. Line[sizeof(Line) - 1] = '\0';
  334. Buffer = OriginalBuffer;
  335. BufferSize = OriginalBufferSize;
  336. //
  337. // Skip any spaces.
  338. //
  339. Current = Line;
  340. while (isspace(*Current) != 0) {
  341. Current += 1;
  342. }
  343. //
  344. // Skip any empty or commented lines.
  345. //
  346. if ((*Current == '\0') || (*Current == '#')) {
  347. continue;
  348. }
  349. Result = sgetspent_r(Line,
  350. Information,
  351. Buffer,
  352. BufferSize,
  353. ReturnPointer);
  354. if (Result == 0) {
  355. break;
  356. }
  357. }
  358. return 0;
  359. }
  360. LIBC_API
  361. struct spwd *
  362. sgetspent (
  363. const char *String
  364. )
  365. /*++
  366. Routine Description:
  367. This routine returns a pointer to the broken out fields of the next entry
  368. in the user database based on a shadow password file line.
  369. Arguments:
  370. String - Supplies a pointer to the shadow password line.
  371. Return Value:
  372. Returns a pointer to the next entry in the user database. The caller may
  373. not modify or free this memory, and it may be overwritten by subsequent
  374. calls to getspent.
  375. NULL if the end of the user database is reached or on error.
  376. --*/
  377. {
  378. int Result;
  379. struct spwd *ReturnPointer;
  380. if (ClShadowInformation == NULL) {
  381. ClShadowInformation = malloc(
  382. sizeof(struct spwd) + USER_DATABASE_LINE_MAX);
  383. if (ClShadowInformation == NULL) {
  384. return NULL;
  385. }
  386. }
  387. ReturnPointer = NULL;
  388. Result = sgetspent_r(String,
  389. ClShadowInformation,
  390. (char *)(ClShadowInformation + 1),
  391. USER_DATABASE_LINE_MAX,
  392. &ReturnPointer);
  393. if (Result != 0) {
  394. errno = Result;
  395. return NULL;
  396. }
  397. return ReturnPointer;
  398. }
  399. LIBC_API
  400. int
  401. sgetspent_r (
  402. const char *String,
  403. struct spwd *Information,
  404. char *Buffer,
  405. size_t BufferSize,
  406. struct spwd **ReturnPointer
  407. )
  408. /*++
  409. Routine Description:
  410. This routine returns a pointer to the broken out fields of the next entry
  411. in the user database based on a shadow password file line.
  412. Arguments:
  413. String - Supplies a pointer to the shadow password line.
  414. Information - Supplies a pointer where the user password information will
  415. be returned on success.
  416. Buffer - Supplies a pointer to the buffer where strings will be stored.
  417. BufferSize - Supplies the size of the given buffer in bytes.
  418. ReturnPointer - Supplies a pointer to a pointer to a user password
  419. information structure. On success, the information pointer parameter
  420. will be returned here.
  421. Return Value:
  422. 0 on success.
  423. ENOENT if there are no more entries.
  424. Returns an error value on failure.
  425. --*/
  426. {
  427. char *AfterScan;
  428. const char *Current;
  429. //
  430. // Loop trying to scan a good line.
  431. //
  432. *ReturnPointer = NULL;
  433. //
  434. // Skip any spaces.
  435. //
  436. Current = String;
  437. while (isspace(*Current) != 0) {
  438. Current += 1;
  439. }
  440. //
  441. // Skip any empty or commented lines.
  442. //
  443. if ((*Current == '\0') || (*Current == '#')) {
  444. return EINVAL;
  445. }
  446. //
  447. // Grab the username. Skip malformed lines.
  448. //
  449. Information->sp_namp = Buffer;
  450. while ((BufferSize != 0) && (*Current != '\0') && (*Current != ':')) {
  451. *Buffer = *Current;
  452. Buffer += 1;
  453. Current += 1;
  454. BufferSize -= 1;
  455. }
  456. if (BufferSize != 0) {
  457. *Buffer = '\0';
  458. Buffer += 1;
  459. }
  460. if (*Current != ':') {
  461. return EINVAL;
  462. }
  463. Current += 1;
  464. //
  465. // Grab the password.
  466. //
  467. Information->sp_pwdp = Buffer;
  468. while ((BufferSize != 0) && (*Current != '\0') && (*Current != ':')) {
  469. *Buffer = *Current;
  470. Buffer += 1;
  471. Current += 1;
  472. BufferSize -= 1;
  473. }
  474. if (BufferSize != 0) {
  475. *Buffer = '\0';
  476. Buffer += 1;
  477. }
  478. if (*Current != ':') {
  479. return EINVAL;
  480. }
  481. Current += 1;
  482. //
  483. // Grab the last changed days.
  484. //
  485. Information->sp_lstchg = strtol(Current, &AfterScan, 10);
  486. if (AfterScan == Current) {
  487. Information->sp_lstchg = -1;
  488. }
  489. Current = AfterScan;
  490. if (*Current != ':') {
  491. return EINVAL;
  492. }
  493. Current += 1;
  494. //
  495. // Grab the number of days before the password may be changed.
  496. //
  497. Information->sp_min = strtoul(Current, &AfterScan, 10);
  498. if (AfterScan == Current) {
  499. Information->sp_min = -1;
  500. }
  501. Current = AfterScan;
  502. if (*Current != ':') {
  503. return EINVAL;
  504. }
  505. Current += 1;
  506. //
  507. // Grab the number of days before the password must be changed.
  508. //
  509. Information->sp_max = strtoul(Current, &AfterScan, 10);
  510. if (AfterScan == Current) {
  511. Information->sp_max = -1;
  512. }
  513. Current = AfterScan;
  514. if (*Current != ':') {
  515. return EINVAL;
  516. }
  517. Current += 1;
  518. //
  519. // Grab the number of days before warning that the password should be
  520. // changed.
  521. //
  522. Information->sp_warn = strtoul(Current, &AfterScan, 10);
  523. if (AfterScan == Current) {
  524. Information->sp_warn = -1;
  525. }
  526. Current = AfterScan;
  527. if (*Current != ':') {
  528. return EINVAL;
  529. }
  530. Current += 1;
  531. //
  532. // Grab the number of days after the password expires that the account is
  533. // disabled.
  534. //
  535. Information->sp_inact = strtoul(Current, &AfterScan, 10);
  536. if (AfterScan == Current) {
  537. Information->sp_inact = -1;
  538. }
  539. Current = AfterScan;
  540. if (*Current != ':') {
  541. return EINVAL;
  542. }
  543. Current += 1;
  544. //
  545. // Grab the number of days since 1970 that an account has been disabled.
  546. //
  547. Information->sp_expire = strtoul(Current, &AfterScan, 10);
  548. if (AfterScan == Current) {
  549. Information->sp_expire = -1;
  550. }
  551. Current = AfterScan;
  552. if (*Current != ':') {
  553. return EINVAL;
  554. }
  555. Current += 1;
  556. //
  557. // Grab the reserved flags.
  558. //
  559. Information->sp_flag = strtoul(Current, &AfterScan, 0);
  560. if (AfterScan == Current) {
  561. Information->sp_flag = -1;
  562. }
  563. *ReturnPointer = Information;
  564. return 0;
  565. }
  566. LIBC_API
  567. void
  568. setspent (
  569. void
  570. )
  571. /*++
  572. Routine Description:
  573. This routine rewinds the user password shadow database handle back to the
  574. beginning of the database. The next call to getspent will return the first
  575. entry in the user database.
  576. Arguments:
  577. None.
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. if (ClShadowFile == NULL) {
  583. ClShadowFile = fopen(_PATH_SHADOW, "r");
  584. } else {
  585. fseek(ClShadowFile, 0, SEEK_SET);
  586. }
  587. return;
  588. }
  589. LIBC_API
  590. void
  591. endspent (
  592. void
  593. )
  594. /*++
  595. Routine Description:
  596. This routine closes an open handle to the user password database
  597. established with setspent or getspent.
  598. Arguments:
  599. None.
  600. Return Value:
  601. None.
  602. --*/
  603. {
  604. if (ClShadowFile != NULL) {
  605. fclose(ClShadowFile);
  606. ClShadowFile = NULL;
  607. }
  608. return;
  609. }
  610. LIBC_API
  611. int
  612. putspent (
  613. const struct spwd *Information,
  614. FILE *Stream
  615. )
  616. /*++
  617. Routine Description:
  618. This routine writes a shadow password entry into the given shadow password
  619. database file stream. This routine is neither thread safe nor reentrant.
  620. Arguments:
  621. Information - Supplies a pointer to the password information to write.
  622. Stream - Supplies a pointer to the file stream to write it out to.
  623. Return Value:
  624. 0 on success.
  625. -1 on failure, and errno will be set to contain more information.
  626. --*/
  627. {
  628. int FinalResult;
  629. flockfile(Stream);
  630. FinalResult = 0;
  631. if (fprintf(Stream, "%s:", Information->sp_namp) < 0) {
  632. FinalResult = -1;
  633. }
  634. if (Information->sp_pwdp != NULL) {
  635. if (fprintf(Stream, "%s:", Information->sp_pwdp) < 0) {
  636. FinalResult = -1;
  637. }
  638. } else {
  639. if (fputc(':', Stream) == EOF) {
  640. FinalResult = -1;
  641. }
  642. }
  643. if (Information->sp_min != (long int)-1) {
  644. if (fprintf(Stream, "%ld:", Information->sp_min) < 0) {
  645. FinalResult = -1;
  646. }
  647. } else {
  648. if (fputc(':', Stream) == EOF) {
  649. FinalResult = -1;
  650. }
  651. }
  652. if (Information->sp_max != (long int)-1) {
  653. if (fprintf(Stream, "%ld:", Information->sp_max) < 0) {
  654. FinalResult = -1;
  655. }
  656. } else {
  657. if (fputc(':', Stream) == EOF) {
  658. FinalResult = -1;
  659. }
  660. }
  661. if (Information->sp_warn != (long int)-1) {
  662. if (fprintf(Stream, "%ld:", Information->sp_warn) < 0) {
  663. FinalResult = -1;
  664. }
  665. } else {
  666. if (fputc(':', Stream) == EOF) {
  667. FinalResult = -1;
  668. }
  669. }
  670. if (Information->sp_inact != (long int)-1) {
  671. if (fprintf(Stream, "%ld:", Information->sp_inact) < 0) {
  672. FinalResult = -1;
  673. }
  674. } else {
  675. if (fputc(':', Stream) == EOF) {
  676. FinalResult = -1;
  677. }
  678. }
  679. if (Information->sp_expire != (long int)-1) {
  680. if (fprintf(Stream, "%ld:", Information->sp_expire) < 0) {
  681. FinalResult = -1;
  682. }
  683. } else {
  684. if (fputc(':', Stream) == EOF) {
  685. FinalResult = -1;
  686. }
  687. }
  688. if (Information->sp_flag != (unsigned long int)-1) {
  689. if (fprintf(Stream, "%lu", Information->sp_flag) < 0) {
  690. FinalResult = -1;
  691. }
  692. }
  693. if (fputc('\n', Stream) == EOF) {
  694. FinalResult = -1;
  695. }
  696. funlockfile(Stream);
  697. return FinalResult;
  698. }
  699. LIBC_API
  700. int
  701. lckpwdf (
  702. void
  703. )
  704. /*++
  705. Routine Description:
  706. This routine locks the shadow password database file. This routine is not
  707. multi-thread safe. This mechanism does not prevent someone from writing
  708. directly to the shadow password file, as the locks it uses are
  709. discretionary.
  710. Arguments:
  711. None.
  712. Return Value:
  713. 0 on success.
  714. -1 if the lock could not be acquired within 15 seconds, and errno may be
  715. set to contain more information.
  716. --*/
  717. {
  718. struct sigaction AlarmAction;
  719. BOOL AlarmActionSet;
  720. int Flags;
  721. struct flock Lock;
  722. sigset_t Mask;
  723. int OpenFlags;
  724. struct sigaction OriginalAlarmAction;
  725. sigset_t OriginalMask;
  726. int Result;
  727. AlarmActionSet = FALSE;
  728. //
  729. // If the lock is already held by this process, fail.
  730. //
  731. if (ClShadowLockDescriptor != -1) {
  732. return -1;
  733. }
  734. //
  735. // TODO: Add O_CLOEXEC to this.
  736. //
  737. OpenFlags = O_WRONLY | O_CREAT;
  738. ClShadowLockDescriptor = open(SHADOW_LOCK_PATH,
  739. OpenFlags,
  740. S_IRUSR | S_IWUSR);
  741. if (ClShadowLockDescriptor < 0) {
  742. return -1;
  743. }
  744. Flags = fcntl(ClShadowLockDescriptor, F_GETFD, 0);
  745. if (Flags == -1) {
  746. Result = -1;
  747. goto lckpwdfEnd;
  748. }
  749. Flags |= FD_CLOEXEC;
  750. Result = fcntl(ClShadowLockDescriptor, F_SETFD, Flags);
  751. if (Result < 0) {
  752. goto lckpwdfEnd;
  753. }
  754. //
  755. // Set an alarm handler so the signal comes in.
  756. //
  757. memset(&AlarmAction, 0, sizeof(AlarmAction));
  758. AlarmAction.sa_handler = ClpEmptySignalHandler;
  759. sigfillset(&(AlarmAction.sa_mask));
  760. AlarmAction.sa_flags = 0;
  761. Result = sigaction(SIGALRM, &AlarmAction, &OriginalAlarmAction);
  762. if (Result < 0) {
  763. goto lckpwdfEnd;
  764. }
  765. AlarmActionSet = TRUE;
  766. //
  767. // Make sure alarm is not blocked.
  768. //
  769. sigemptyset(&Mask);
  770. sigaddset(&Mask, SIGALRM);
  771. Result = sigprocmask(SIG_UNBLOCK, &Mask, &OriginalMask);
  772. if (Result < 0) {
  773. goto lckpwdfEnd;
  774. }
  775. //
  776. // Start a timer.
  777. //
  778. alarm(SHADOW_LOCK_TIMEOUT);
  779. //
  780. // Acquire the lock.
  781. //
  782. memset(&Lock, 0, sizeof(Lock));
  783. Lock.l_type = F_WRLCK;
  784. Lock.l_whence = SEEK_SET;
  785. Result = fcntl(ClShadowLockDescriptor, F_SETLKW, &Lock);
  786. //
  787. // Restore the mask.
  788. //
  789. sigprocmask(SIG_SETMASK, &OriginalMask, NULL);
  790. lckpwdfEnd:
  791. if (AlarmActionSet != FALSE) {
  792. sigaction(SIGALRM, &OriginalAlarmAction, NULL);
  793. }
  794. if (Result != 0) {
  795. if (ClShadowLockDescriptor >= 0) {
  796. close(ClShadowLockDescriptor);
  797. ClShadowLockDescriptor = -1;
  798. }
  799. }
  800. return Result;
  801. }
  802. LIBC_API
  803. int
  804. ulckpwdf (
  805. void
  806. )
  807. /*++
  808. Routine Description:
  809. This routine unlocks the shadow password file.
  810. Arguments:
  811. None.
  812. Return Value:
  813. 0 on success.
  814. -1 on failure.
  815. --*/
  816. {
  817. int Result;
  818. //
  819. // If there is no descriptor, the caller's trying to unlock something
  820. // they never locked.
  821. //
  822. if (ClShadowLockDescriptor < 0) {
  823. return -1;
  824. }
  825. Result = close(ClShadowLockDescriptor);
  826. ClShadowLockDescriptor = -1;
  827. return Result;
  828. }
  829. //
  830. // --------------------------------------------------------- Internal Functions
  831. //
  832. void
  833. ClpEmptySignalHandler (
  834. int Signal
  835. )
  836. /*++
  837. Routine Description:
  838. This routine implements an empty signal handler. This is needed when it is
  839. desired that a certain signal interrupt an operation, but that signal's
  840. default action would be to terminate.
  841. Arguments:
  842. Signal - Supplies the signal number that occurred. This is ignored.
  843. Return Value:
  844. None.
  845. --*/
  846. {
  847. return;
  848. }