Guest User

Untitled

a guest
Jul 12th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.25 KB | None | 0 0
  1. ------------------------------------------------------------------------------
  2. -- Copyright (c) <2009>, <AuroraUX Group> --
  3. -- All rights reserved. --
  4. -- --
  5. -- Redistribution and use in source and binary forms, with or without --
  6. -- modification,are permitted provided that the following conditions are met--
  7. -- --
  8. -- * Redistributions of source code must retain the above copyright --
  9. -- notice, this list of conditions and the following disclaimer. --
  10. -- * Redistributions in binary form must reproduce the above copyright --
  11. -- notice, this list of conditions and the following disclaimer in the--
  12. -- documentation and/or other materials provided with the distribution--
  13. -- * Neither the name of the <AuroraUX Group> nor the names of its --
  14. -- contributors may be used to endorse or promote products derived --
  15. -- from this software without specific prior written permission. --
  16. -- --
  17. -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS --
  18. -- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--
  19. -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --
  20. -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR --
  21. -- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, --
  22. -- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --
  23. -- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR --
  24. -- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF --
  25. -- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING --
  26. -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --
  27. -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
  28. ------------------------------------------------------------------------------
  29.  
  30.  
  31. --
  32. -- POSIX package.
  33. with POSIX.Account.Group;
  34. with POSIX.Account.User;
  35. with POSIX.Account.DB.IO;
  36.  
  37. --
  38. -- Lace.
  39. with Lace.Text;
  40.  
  41. --
  42. -- Ada 2005.
  43. with Ada.Text_IO;
  44. with Ada.IO_Exceptions;
  45. with Ada.Strings.Fixed;
  46. with Ada.Strings.unbounded.Hash;
  47. with Ada.Containers.Hashed_Maps;
  48. with Ada.Containers.ordered_Maps;
  49. with Ada.Finalization;
  50.  
  51.  
  52. package body POSIX.Account.DB is
  53.  
  54. -- FIXME: !! Do not use "use".
  55. use Lace.Text;
  56. use Ada.Strings.Unbounded;
  57. use POSIX.Account.User;
  58. use POSIX.Account.Group;
  59. package Safe_IO renames POSIX.Account.DB.IO;
  60.  
  61.  
  62. -- Globals
  63. --
  64.  
  65.  
  66. -- User database.
  67. --
  68.  
  69. package Name_Map_of_Users is new Ada.Containers.Hashed_Maps (Unbounded_String,
  70. POSIX.Account.User.View,
  71. Ada.Strings.Unbounded.Hash, "=");
  72.  
  73. package ID_Map_of_Users is new Ada.Containers.Ordered_Maps (User_ID_t,
  74. POSIX.Account.User.View, "<", "=");
  75.  
  76. The_ID_Map_of_Users : ID_Map_of_Users .Map;
  77. The_name_Map_of_Users : Name_Map_of_Users.Map;
  78. Free_user_Id : User_ID_t;
  79.  
  80.  
  81. -- Group database
  82. --
  83.  
  84. package ID_Map_of_Groups is new Ada.Containers.Ordered_Maps (Group_Id_t,
  85. POSIX.Account.Group.view, "<", "=");
  86.  
  87. package Name_Map_of_Groups is new Ada.Containers.Hashed_Maps (Unbounded_String,
  88. POSIX.Account.Group.View,
  89. Ada.Strings.Unbounded.Hash, "=");
  90.  
  91. The_ID_Map_of_Groups : ID_Map_of_Groups.Map;
  92. The_name_Map_of_Groups : Name_Map_of_Groups.Map;
  93. Free_group_ID : Group_ID_t;
  94.  
  95. -- Utilities
  96. --
  97.  
  98. function "+" (Self : in String) return Unbounded_String
  99. renames Ada.Strings.Unbounded.To_Unbounded_String;
  100.  
  101.  
  102. function Image (Self : in Natural) return String is
  103. use Ada.Strings, Ada.Strings.Fixed;
  104. begin
  105. return Trim (Natural'Image (Self), Left);
  106. end;
  107.  
  108.  
  109. function New_Group (Named : in String) return POSIX.Account.Group.View is
  110. use POSIX.Account.Group;
  111.  
  112. The_New_Group : POSIX.Account.Group.View := New_Group (Group_Name => Named,
  113. Password => "no_password",
  114. Group_ID => Free_Group_ID);
  115. begin
  116. Free_Group_ID := Free_Group_ID + 1;
  117.  
  118. The_ID_Map_of_Groups.Include (The_New_Group.ID, The_New_Group);
  119. The_Name_Map_of_Groups.Include (+Named, The_New_Group);
  120.  
  121. return The_New_Group;
  122. end;
  123.  
  124.  
  125. function New_Group (Named : in String; Password : in String;
  126. ID : in Group_ID_t) return POSIX.Account.Group.View is
  127.  
  128. use POSIX.Account.Group;
  129.  
  130. the_new_Group : POSIX.Account.Group.view := POSIX.Account.Group.New_Group (group_name => Named,
  131. password => Password,
  132. group_id => Id);
  133. begin
  134. the_id_Map_of_groups .include (the_new_Group.Id, the_new_Group);
  135. the_name_Map_of_Groups.include (+Named, the_new_Group);
  136.  
  137. return the_new_Group;
  138. end;
  139.  
  140.  
  141. function demand_Group (Named : in POSIX.Group_Name_t) return POSIX.Account.Group.view
  142. is
  143. begin
  144. return the_name_Map_of_Groups.Element (+Named);
  145. exception
  146. when constraint_Error => -- group not found
  147. -- FIXME: Ask first !
  148. return new_Group (Named); -- so create it
  149. end;
  150.  
  151.  
  152. procedure rid_Group (the_Group : POSIX.Account.Group.View)
  153. is
  154. use POSIX.Account.Group;
  155. begin
  156. the_name_Map_of_groups.delete (+the_Group.Name);
  157. the_id_Map_of_groups .delete (the_Group.Id);
  158. end;
  159.  
  160.  
  161. procedure rid_User (the_User : POSIX.account.User.view)
  162. is
  163. use POSIX.Account.User;
  164. begin
  165. the_name_Map_of_users.delete (+the_User.Name);
  166. the_id_Map_of_users .delete (the_User.Id);
  167. end;
  168.  
  169.  
  170. -- Operations
  171. --
  172.  
  173.  
  174. -- User
  175. --
  176.  
  177. procedure Add_User (Named : in POSIX.User_Name_t;
  178. Group_Name : in POSIX.Group_Name_t;
  179. Comment : in POSIX.Comment_t;
  180. Home_Path : in POSIX.Home_Directory_t;
  181. Shell_Path : in POSIX.Shell_Path_t) is
  182. begin
  183. if the_name_Map_of_users.Contains (+Named) then
  184. raise account_Exists;
  185. end if;
  186.  
  187. declare
  188. use Ada.Strings, Ada.Strings.Fixed;
  189.  
  190. the_new_Group : POSIX.Account.Group.View := Demand_Group (Group_Name);
  191. the_new_User : POSIX.Account.User.View := New_User (Named, "no_password", free_user_Id, the_new_Group.Id, the_new_Group, Comment, home_Path, Shell_Path);
  192. begin
  193. free_user_ID := free_user_ID + 1;
  194.  
  195. the_name_Map_of_users.include (+Named, the_new_User);
  196. the_id_Map_of_users .include (the_new_User.Id, the_new_User);
  197. end;
  198. end;
  199.  
  200.  
  201. procedure rid_User (Named : in POSIX.User_Name_t)
  202. is
  203. begin
  204. if not the_name_Map_of_users.Contains (+Named) then
  205. raise no_such_Account;
  206. end if;
  207.  
  208. declare
  209. the_User : POSIX.account.User.View := the_name_Map_of_users.Element (key => +Named);
  210. the_Group : POSIX.account.Group.View := the_User.Group;
  211. begin
  212. rid_Group (the_Group);
  213. rid_User (the_User);
  214. end;
  215. end rid_User;
  216.  
  217.  
  218. function All_Users return POSIX.Account.User.Views
  219. is
  220. use name_Map_of_users;
  221.  
  222. the_Users : POSIX.Account.User.Views (1 .. Integer (the_name_Map_of_users.Length));
  223. Cursor : name_Map_of_users.Cursor := the_name_Map_of_users.First;
  224. begin
  225. for Each in the_Users'range loop
  226. the_Users (Each) := Element (Cursor);
  227. next (Cursor);
  228. end loop;
  229.  
  230. return the_Users;
  231. end;
  232.  
  233.  
  234.  
  235. function User (Named : in POSIX.User_Name_t) return POSIX.Account.User.View is
  236. begin
  237. return the_name_Map_of_users.Element (+Named);
  238. exception
  239. when Constraint_Error =>
  240. raise No_such_Account;
  241. end;
  242.  
  243.  
  244. -- Groups
  245. --
  246.  
  247. procedure Add_Group (Named : in POSIX.Group_Name_t) is
  248. begin
  249. if the_name_Map_of_groups.Contains (+Named) then
  250. raise account_Exists;
  251. end if;
  252.  
  253. declare
  254. use ada.Strings, ada.Strings.Fixed;
  255.  
  256. the_new_Group : POSIX.account.Group.view := demand_Group (Named);
  257. begin
  258. -- TODO: Comment is unclear.
  259. null; -- Work is done in 'demand_Group'
  260. end;
  261. end;
  262.  
  263.  
  264. procedure rid_Group (Named : in POSIX.group_Name_t)
  265. is
  266. begin
  267. if not the_name_Map_of_groups.Contains (+Named) then
  268. raise no_such_Account;
  269. end if;
  270.  
  271. declare
  272. the_Group : POSIX.account.Group.view := the_name_Map_of_groups.Element (key => +Named);
  273. begin
  274. rid_Group (the_Group);
  275. end;
  276. end rid_Group;
  277.  
  278.  
  279. function all_Groups return POSIX.account.Group.views
  280. is
  281. use name_Map_of_groups;
  282.  
  283. the_Groups : POSIX.Account.Group.views (1 .. Integer (the_name_Map_of_users.Length));
  284. Cursor : name_Map_of_groups.Cursor := the_name_Map_of_groups.First;
  285. begin
  286. for Each in the_Groups'range loop
  287. the_Groups (Each) := Element (Cursor);
  288. next (Cursor);
  289. end loop;
  290.  
  291. return the_Groups;
  292. end;
  293.  
  294.  
  295. function Group (Named : in POSIX.group_Name_t) return POSIX.account.Group.view
  296. is
  297. begin
  298. return the_name_Map_of_groups.Element (+Named);
  299. exception
  300. when constraint_Error =>
  301. raise no_such_Account;
  302. end;
  303.  
  304.  
  305. -- Package Closure
  306. --
  307.  
  308. type package_Closure is new ada.Finalization.controlled with null record;
  309.  
  310.  
  311. procedure Finalize (Self : in out package_Closure)
  312. is
  313. use ada.text_IO, ada.Strings, ada.Strings.Fixed;
  314. begin
  315. store_group_DB:
  316. declare
  317. use id_Map_of_groups;
  318. use Ada.Strings, Ada.Strings.Fixed;
  319. use lace.Text;
  320.  
  321. the_Group : POSIX.account.Group.view;
  322. Groups_File : Ada.Text_IO.File_Type;
  323.  
  324. Cursor : id_Map_of_groups.Cursor := the_id_Map_of_groups.First;
  325. begin
  326. Safe_IO.Create_Group(File => Groups_File);
  327.  
  328. while has_Element (Cursor) loop
  329. the_Group := Element (Cursor);
  330.  
  331. put_group_file_Line:
  332. begin
  333. put (groups_File, the_Group.Name
  334. & ":" & the_Group.Password
  335. & ":" & Trim (Group_ID_t'Image (the_Group.Id), Left)
  336. & ":");
  337. begin
  338. declare
  339. the_Members : POSIX.account.group.User_views := the_Group.Members;
  340. begin
  341. for Each in the_Members'range loop
  342. if Each > 1 then
  343. put (groups_File, ",");
  344. end if;
  345.  
  346. put (groups_File, the_Members (Each).Name);
  347. end loop;
  348. end;
  349. exception
  350. -- No users exists in the users filed, so do nothing.
  351. when constraint_Error => null;
  352. end;
  353.  
  354. new_Line (groups_File);
  355. end put_group_file_Line;
  356.  
  357.  
  358. next (Cursor);
  359. end loop;
  360.  
  361. Safe_IO.Close_Group(File => Groups_File);
  362. end store_group_DB;
  363.  
  364.  
  365.  
  366. store_user_DB:
  367. declare
  368. use id_Map_of_users;
  369. use ada.text_IO, ada.Strings, ada.Strings.Fixed;
  370. use lace.Text;
  371.  
  372. the_User : POSIX.account.User.view;
  373. Passwd_File : Ada.Text_IO.File_Type;
  374. Shadow_File : Ada.Text_IO.File_Type;
  375.  
  376. Cursor : id_Map_of_users.Cursor := the_id_Map_of_users.First;
  377. begin
  378. -- FIXME: Don't just create files, ask first!
  379. Safe_IO.Create_Passwd(File => Passwd_File);
  380. Safe_IO.Create_Shadow(File => Shadow_File);
  381.  
  382. while has_Element (Cursor) loop
  383. the_User := Element (Cursor);
  384. put_Line (passwd_File, the_User.Name
  385. & ":" & the_User.Password
  386. & ":" & Trim (user_ID_t'Image (the_User.Id), Left)
  387. & ":" & Trim (group_ID_t'Image (the_User.Group.Id), Left)
  388. & ":" & the_User.Comment
  389. & ":" & the_User.home_Path
  390. & ":" & the_User.shell_Path);
  391.  
  392. declare
  393. function null_for_0_Image (Self : in Natural) return String
  394. is
  395. use ada.strings, ada.strings.Fixed;
  396. begin
  397. if Self = 0 then return "";
  398. else return Trim (Natural'Image (Self), Left);
  399. end if;
  400. end;
  401.  
  402. the_Password : a_shadow_Password := the_User.shadow_Password;
  403. begin
  404. put_Line (shadow_File, the_User.Name
  405. & ":" & to_String (the_Password.Encrypted)
  406. & ":" & Image (the_Password.last_changed_Date)
  407. & ":" & Image (the_Password.Days_until_change_allowed)
  408. & ":" & Image (the_Password.Days_before_change_required)
  409. & ":" & Image (the_Password.Days_warning_for_expiration)
  410. & ":" & null_for_0_Image (the_Password.Days_before_account_inactive)
  411. & ":" & null_for_0_Image (the_Password.Days_since_Epoch_when_account_expires)
  412. & ":");
  413. end;
  414.  
  415. next (Cursor);
  416. end loop;
  417.  
  418. Safe_IO.Close_Passwd(File => Passwd_File);
  419. Safe_IO.Close_Shadow(File => Shadow_File);
  420. end store_user_DB;
  421.  
  422. end Finalize;
  423.  
  424.  
  425. the_Closure : package_Closure;
  426.  
  427.  
  428. -- Package Elaboration
  429. --
  430.  
  431. use Ada.Text_IO; -- FIXME:
  432.  
  433. begin
  434.  
  435. parse_passwd_file_into_user_DB:
  436. declare
  437. Passwd_File : Ada.text_IO.File_type;
  438. line_Count : Natural := 0;
  439. begin
  440. Safe_IO.Open_Passwd(File => Passwd_File);
  441.  
  442. while not end_of_File (passwd_File) loop
  443. declare
  444. use lace.Text, ada.Strings.fixed;
  445.  
  446. the_Line : lace.Text.item := to_Text (get_Line (passwd_File));
  447. Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
  448. the_user_Id : user_Id_t := user_Id_t'Value (to_String (Tokens (3)));
  449.  
  450. the_User : POSIX.account.User.view;
  451. begin
  452. if Tokens'Length > 7 then
  453. raise constraint_Error with "invalid user at line" & natural'Image (line_Count) & " in file '" & passwd_Filename & "'";
  454. end if;
  455.  
  456. if the_user_Id /= user_Id_t'Last then
  457. free_user_Id := user_Id_t'max (free_user_Id, the_user_Id);
  458. end if;
  459.  
  460. the_User := new_User (user_id => the_user_Id,
  461. user_name => to_String (Tokens (1)),
  462. password => to_String (Tokens (2)),
  463. main_group_id => group_Id_t'Value (to_String (Tokens (4))),
  464. main_group => null,
  465. comment => to_String (Tokens (5)),
  466. home_path => to_String (Tokens (6)),
  467. shell_path => to_String (Tokens (7)));
  468.  
  469.  
  470. the_name_Map_of_users.include (+the_User.Name, the_User);
  471. the_id_Map_of_users .include (the_user.Id, the_User);
  472.  
  473. -- INFO: Debug Code !
  474. -- for Each in Tokens'range loop
  475. -- put_Line ("'POSIX.User_DB.User' ~ passwd token " & integer'Image (Each) & " '" & to_String (Tokens (Each)) & "'");
  476. -- end loop;
  477. end;
  478.  
  479. end loop;
  480.  
  481. Safe_IO.Close_Passwd(File => Passwd_File);
  482.  
  483. free_user_Id := free_user_Id + 1;
  484.  
  485. exception
  486. when ada.io_exceptions.Name_Error => null; -- no 'passwd' file exists, so do nothing
  487. end parse_passwd_file_into_user_DB;
  488.  
  489.  
  490.  
  491. parse_group_file_into_user_DB:
  492. declare
  493. Group_File : Ada.text_IO.File_type;
  494. line_Count : Natural := 0;
  495. begin
  496. Safe_IO.Open_Group(File => Group_File);
  497.  
  498. while not end_of_File (group_File) loop
  499. declare
  500. use POSIX.account.Group, lace.Text, ada.Strings.fixed;
  501.  
  502. the_new_Group : POSIX.account.Group.view;
  503.  
  504. the_Line : lace.Text.item := to_Text (get_Line (group_File));
  505. Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
  506. the_group_Id : group_Id_t := group_Id_t'Value (to_String (Tokens (3)));
  507. begin
  508. if Tokens'Length > 4 then
  509. raise constraint_Error with "invalid user at line" & natural'Image (line_Count) & " in file '" & Groups_Filename & "'";
  510. end if;
  511.  
  512. if the_group_Id /= group_Id_t'Last then
  513. free_group_Id := user_Id_t'max (free_group_Id, the_group_Id);
  514. end if;
  515.  
  516. the_new_Group := new_Group (named => to_String (Tokens (1)),
  517. password => to_String (Tokens (2)),
  518. id => the_group_Id);
  519. begin
  520. declare
  521. users_Field : constant String := to_String (Tokens (4));
  522. users_Text : lace.Text.item := to_Text (users_Field);
  523. user_Tokens : lace.Text.items_1k := lace.Text.Tokens (users_Text, ',');
  524.  
  525. the_User : POSIX.account.User.view;
  526. begin
  527. for Each in user_Tokens'range loop
  528. the_User := the_name_Map_of_users.Element (key => +to_String (user_Tokens (Each)));
  529. the_new_Group.add (the_User.all'access);
  530. end loop;
  531. end;
  532. end;
  533. end;
  534. end loop;
  535.  
  536. Safe_IO.Close_Group(File => Group_File);
  537.  
  538. free_group_Id := free_group_Id + 1;
  539.  
  540. exception
  541. when ada.io_exceptions.Name_Error => null; -- no 'groups' file exists, so do nothing
  542. end parse_group_file_into_user_DB;
  543.  
  544.  
  545.  
  546. resolve_all_user_main_Groups:
  547. declare
  548. use name_Map_of_users;
  549. Cursor : name_Map_of_users.Cursor := the_name_Map_of_users.First;
  550. the_User : POSIX.account.User.view;
  551. begin
  552. while has_Element (Cursor) loop
  553. the_User := Element (Cursor);
  554. -- INFO: Debug Code !
  555. -- Put_Line (the_User.Name & group_Id_t'image (the_User.main_group_Id));
  556. the_User.Group_is (the_id_Map_of_groups.Element (key => the_User.main_group_Id));
  557.  
  558. next (Cursor);
  559. end loop;
  560. end resolve_all_user_main_Groups;
  561.  
  562.  
  563. parse_shadow_file_into_user_DB:
  564. declare
  565. Shadow_File : Ada.Text_IO.File_type;
  566. line_Count : Natural := 0;
  567. begin
  568. Safe_IO.Open_Shadow(File => Shadow_File);
  569.  
  570. while not end_of_File (shadow_File) loop
  571. declare
  572. use lace.Text, ada.Strings.fixed;
  573.  
  574. the_Line : lace.Text.item := to_Text (get_Line (shadow_File));
  575. Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
  576. the_Name : unbounded_String := +to_String (Tokens (1));
  577. the_User : POSIX.account.User.view;
  578. begin
  579. if Tokens'Length > 9 then
  580. raise constraint_Error with "invalid details at line" & natural'Image (line_Count) & " in file '" & shadow_Filename & "'";
  581. end if;
  582.  
  583. -- INFO: Debug Code !
  584. -- for Each in Tokens'range loop
  585. -- put_Line ("'POSIX.User_DB.User' ~ shadow token " & integer'Image (Each) & " '" & to_String (Tokens (Each)) & "'");
  586. -- end loop;
  587.  
  588. the_User := the_name_Map_of_users.Element (key => the_Name).all'access;
  589.  
  590. declare
  591. the_shadow_Password : a_shadow_Password := the_User.shadow_Password;
  592. begin
  593.  
  594. the_shadow_Password.Encrypted := +to_String (Tokens (2));
  595. the_shadow_Password.last_changed_Date := natural'Value (to_String (Tokens (3)));
  596. the_shadow_Password.Days_until_change_allowed := natural'Value (to_String (Tokens (4)));
  597. the_shadow_Password.Days_before_change_required := natural'Value (to_String (Tokens (5)));
  598. the_shadow_Password.Days_warning_for_expiration := natural'Value (to_String (Tokens (6)));
  599.  
  600. begin
  601. the_shadow_Password.Days_before_account_inactive := natural'Value (to_String (Tokens (7)));
  602. exception
  603. when constraint_Error =>
  604. the_shadow_Password.Days_before_account_inactive := 0; -- empty token
  605. end;
  606.  
  607. begin
  608. the_shadow_Password.Days_since_Epoch_when_account_expires := natural'Value (to_String (Tokens (8)));
  609. exception
  610. when constraint_Error =>
  611. the_shadow_Password.Days_since_Epoch_when_account_expires := 0; -- empty token
  612. end;
  613.  
  614. the_User.shadow_Password_is (the_shadow_Password);
  615. end;
  616. end;
  617.  
  618. end loop;
  619.  
  620. Safe_IO.Close_Shadow (File => Shadow_File);
  621.  
  622. exception
  623. when ada.io_exceptions.Name_Error => null; -- no 'shadow' file exists, so do nothing
  624. end parse_shadow_file_into_user_DB;
  625.  
  626.  
  627. end POSIX.account.DB;
Add Comment
Please, Sign In to add comment