Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ------------------------------------------------------------------------------
- -- Copyright (c) <2009>, <AuroraUX Group> --
- -- All rights reserved. --
- -- --
- -- Redistribution and use in source and binary forms, with or without --
- -- modification,are permitted provided that the following conditions are met--
- -- --
- -- * Redistributions of source code must retain the above copyright --
- -- notice, this list of conditions and the following disclaimer. --
- -- * Redistributions in binary form must reproduce the above copyright --
- -- notice, this list of conditions and the following disclaimer in the--
- -- documentation and/or other materials provided with the distribution--
- -- * Neither the name of the <AuroraUX Group> nor the names of its --
- -- contributors may be used to endorse or promote products derived --
- -- from this software without specific prior written permission. --
- -- --
- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS --
- -- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--
- -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --
- -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR --
- -- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, --
- -- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --
- -- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR --
- -- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF --
- -- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING --
- -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --
- -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
- ------------------------------------------------------------------------------
- --
- -- POSIX package.
- with POSIX.Account.Group;
- with POSIX.Account.User;
- with POSIX.Account.DB.IO;
- --
- -- Lace.
- with Lace.Text;
- --
- -- Ada 2005.
- with Ada.Text_IO;
- with Ada.IO_Exceptions;
- with Ada.Strings.Fixed;
- with Ada.Strings.unbounded.Hash;
- with Ada.Containers.Hashed_Maps;
- with Ada.Containers.ordered_Maps;
- with Ada.Finalization;
- package body POSIX.Account.DB is
- -- FIXME: !! Do not use "use".
- use Lace.Text;
- use Ada.Strings.Unbounded;
- use POSIX.Account.User;
- use POSIX.Account.Group;
- package Safe_IO renames POSIX.Account.DB.IO;
- -- Globals
- --
- -- User database.
- --
- package Name_Map_of_Users is new Ada.Containers.Hashed_Maps (Unbounded_String,
- POSIX.Account.User.View,
- Ada.Strings.Unbounded.Hash, "=");
- package ID_Map_of_Users is new Ada.Containers.Ordered_Maps (User_ID_t,
- POSIX.Account.User.View, "<", "=");
- The_ID_Map_of_Users : ID_Map_of_Users .Map;
- The_name_Map_of_Users : Name_Map_of_Users.Map;
- Free_user_Id : User_ID_t;
- -- Group database
- --
- package ID_Map_of_Groups is new Ada.Containers.Ordered_Maps (Group_Id_t,
- POSIX.Account.Group.view, "<", "=");
- package Name_Map_of_Groups is new Ada.Containers.Hashed_Maps (Unbounded_String,
- POSIX.Account.Group.View,
- Ada.Strings.Unbounded.Hash, "=");
- The_ID_Map_of_Groups : ID_Map_of_Groups.Map;
- The_name_Map_of_Groups : Name_Map_of_Groups.Map;
- Free_group_ID : Group_ID_t;
- -- Utilities
- --
- function "+" (Self : in String) return Unbounded_String
- renames Ada.Strings.Unbounded.To_Unbounded_String;
- function Image (Self : in Natural) return String is
- use Ada.Strings, Ada.Strings.Fixed;
- begin
- return Trim (Natural'Image (Self), Left);
- end;
- function New_Group (Named : in String) return POSIX.Account.Group.View is
- use POSIX.Account.Group;
- The_New_Group : POSIX.Account.Group.View := New_Group (Group_Name => Named,
- Password => "no_password",
- Group_ID => Free_Group_ID);
- begin
- Free_Group_ID := Free_Group_ID + 1;
- The_ID_Map_of_Groups.Include (The_New_Group.ID, The_New_Group);
- The_Name_Map_of_Groups.Include (+Named, The_New_Group);
- return The_New_Group;
- end;
- function New_Group (Named : in String; Password : in String;
- ID : in Group_ID_t) return POSIX.Account.Group.View is
- use POSIX.Account.Group;
- the_new_Group : POSIX.Account.Group.view := POSIX.Account.Group.New_Group (group_name => Named,
- password => Password,
- group_id => Id);
- begin
- the_id_Map_of_groups .include (the_new_Group.Id, the_new_Group);
- the_name_Map_of_Groups.include (+Named, the_new_Group);
- return the_new_Group;
- end;
- function demand_Group (Named : in POSIX.Group_Name_t) return POSIX.Account.Group.view
- is
- begin
- return the_name_Map_of_Groups.Element (+Named);
- exception
- when constraint_Error => -- group not found
- -- FIXME: Ask first !
- return new_Group (Named); -- so create it
- end;
- procedure rid_Group (the_Group : POSIX.Account.Group.View)
- is
- use POSIX.Account.Group;
- begin
- the_name_Map_of_groups.delete (+the_Group.Name);
- the_id_Map_of_groups .delete (the_Group.Id);
- end;
- procedure rid_User (the_User : POSIX.account.User.view)
- is
- use POSIX.Account.User;
- begin
- the_name_Map_of_users.delete (+the_User.Name);
- the_id_Map_of_users .delete (the_User.Id);
- end;
- -- Operations
- --
- -- User
- --
- procedure Add_User (Named : in POSIX.User_Name_t;
- Group_Name : in POSIX.Group_Name_t;
- Comment : in POSIX.Comment_t;
- Home_Path : in POSIX.Home_Directory_t;
- Shell_Path : in POSIX.Shell_Path_t) is
- begin
- if the_name_Map_of_users.Contains (+Named) then
- raise account_Exists;
- end if;
- declare
- use Ada.Strings, Ada.Strings.Fixed;
- the_new_Group : POSIX.Account.Group.View := Demand_Group (Group_Name);
- 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);
- begin
- free_user_ID := free_user_ID + 1;
- the_name_Map_of_users.include (+Named, the_new_User);
- the_id_Map_of_users .include (the_new_User.Id, the_new_User);
- end;
- end;
- procedure rid_User (Named : in POSIX.User_Name_t)
- is
- begin
- if not the_name_Map_of_users.Contains (+Named) then
- raise no_such_Account;
- end if;
- declare
- the_User : POSIX.account.User.View := the_name_Map_of_users.Element (key => +Named);
- the_Group : POSIX.account.Group.View := the_User.Group;
- begin
- rid_Group (the_Group);
- rid_User (the_User);
- end;
- end rid_User;
- function All_Users return POSIX.Account.User.Views
- is
- use name_Map_of_users;
- the_Users : POSIX.Account.User.Views (1 .. Integer (the_name_Map_of_users.Length));
- Cursor : name_Map_of_users.Cursor := the_name_Map_of_users.First;
- begin
- for Each in the_Users'range loop
- the_Users (Each) := Element (Cursor);
- next (Cursor);
- end loop;
- return the_Users;
- end;
- function User (Named : in POSIX.User_Name_t) return POSIX.Account.User.View is
- begin
- return the_name_Map_of_users.Element (+Named);
- exception
- when Constraint_Error =>
- raise No_such_Account;
- end;
- -- Groups
- --
- procedure Add_Group (Named : in POSIX.Group_Name_t) is
- begin
- if the_name_Map_of_groups.Contains (+Named) then
- raise account_Exists;
- end if;
- declare
- use ada.Strings, ada.Strings.Fixed;
- the_new_Group : POSIX.account.Group.view := demand_Group (Named);
- begin
- -- TODO: Comment is unclear.
- null; -- Work is done in 'demand_Group'
- end;
- end;
- procedure rid_Group (Named : in POSIX.group_Name_t)
- is
- begin
- if not the_name_Map_of_groups.Contains (+Named) then
- raise no_such_Account;
- end if;
- declare
- the_Group : POSIX.account.Group.view := the_name_Map_of_groups.Element (key => +Named);
- begin
- rid_Group (the_Group);
- end;
- end rid_Group;
- function all_Groups return POSIX.account.Group.views
- is
- use name_Map_of_groups;
- the_Groups : POSIX.Account.Group.views (1 .. Integer (the_name_Map_of_users.Length));
- Cursor : name_Map_of_groups.Cursor := the_name_Map_of_groups.First;
- begin
- for Each in the_Groups'range loop
- the_Groups (Each) := Element (Cursor);
- next (Cursor);
- end loop;
- return the_Groups;
- end;
- function Group (Named : in POSIX.group_Name_t) return POSIX.account.Group.view
- is
- begin
- return the_name_Map_of_groups.Element (+Named);
- exception
- when constraint_Error =>
- raise no_such_Account;
- end;
- -- Package Closure
- --
- type package_Closure is new ada.Finalization.controlled with null record;
- procedure Finalize (Self : in out package_Closure)
- is
- use ada.text_IO, ada.Strings, ada.Strings.Fixed;
- begin
- store_group_DB:
- declare
- use id_Map_of_groups;
- use Ada.Strings, Ada.Strings.Fixed;
- use lace.Text;
- the_Group : POSIX.account.Group.view;
- Groups_File : Ada.Text_IO.File_Type;
- Cursor : id_Map_of_groups.Cursor := the_id_Map_of_groups.First;
- begin
- Safe_IO.Create_Group(File => Groups_File);
- while has_Element (Cursor) loop
- the_Group := Element (Cursor);
- put_group_file_Line:
- begin
- put (groups_File, the_Group.Name
- & ":" & the_Group.Password
- & ":" & Trim (Group_ID_t'Image (the_Group.Id), Left)
- & ":");
- begin
- declare
- the_Members : POSIX.account.group.User_views := the_Group.Members;
- begin
- for Each in the_Members'range loop
- if Each > 1 then
- put (groups_File, ",");
- end if;
- put (groups_File, the_Members (Each).Name);
- end loop;
- end;
- exception
- -- No users exists in the users filed, so do nothing.
- when constraint_Error => null;
- end;
- new_Line (groups_File);
- end put_group_file_Line;
- next (Cursor);
- end loop;
- Safe_IO.Close_Group(File => Groups_File);
- end store_group_DB;
- store_user_DB:
- declare
- use id_Map_of_users;
- use ada.text_IO, ada.Strings, ada.Strings.Fixed;
- use lace.Text;
- the_User : POSIX.account.User.view;
- Passwd_File : Ada.Text_IO.File_Type;
- Shadow_File : Ada.Text_IO.File_Type;
- Cursor : id_Map_of_users.Cursor := the_id_Map_of_users.First;
- begin
- -- FIXME: Don't just create files, ask first!
- Safe_IO.Create_Passwd(File => Passwd_File);
- Safe_IO.Create_Shadow(File => Shadow_File);
- while has_Element (Cursor) loop
- the_User := Element (Cursor);
- put_Line (passwd_File, the_User.Name
- & ":" & the_User.Password
- & ":" & Trim (user_ID_t'Image (the_User.Id), Left)
- & ":" & Trim (group_ID_t'Image (the_User.Group.Id), Left)
- & ":" & the_User.Comment
- & ":" & the_User.home_Path
- & ":" & the_User.shell_Path);
- declare
- function null_for_0_Image (Self : in Natural) return String
- is
- use ada.strings, ada.strings.Fixed;
- begin
- if Self = 0 then return "";
- else return Trim (Natural'Image (Self), Left);
- end if;
- end;
- the_Password : a_shadow_Password := the_User.shadow_Password;
- begin
- put_Line (shadow_File, the_User.Name
- & ":" & to_String (the_Password.Encrypted)
- & ":" & Image (the_Password.last_changed_Date)
- & ":" & Image (the_Password.Days_until_change_allowed)
- & ":" & Image (the_Password.Days_before_change_required)
- & ":" & Image (the_Password.Days_warning_for_expiration)
- & ":" & null_for_0_Image (the_Password.Days_before_account_inactive)
- & ":" & null_for_0_Image (the_Password.Days_since_Epoch_when_account_expires)
- & ":");
- end;
- next (Cursor);
- end loop;
- Safe_IO.Close_Passwd(File => Passwd_File);
- Safe_IO.Close_Shadow(File => Shadow_File);
- end store_user_DB;
- end Finalize;
- the_Closure : package_Closure;
- -- Package Elaboration
- --
- use Ada.Text_IO; -- FIXME:
- begin
- parse_passwd_file_into_user_DB:
- declare
- Passwd_File : Ada.text_IO.File_type;
- line_Count : Natural := 0;
- begin
- Safe_IO.Open_Passwd(File => Passwd_File);
- while not end_of_File (passwd_File) loop
- declare
- use lace.Text, ada.Strings.fixed;
- the_Line : lace.Text.item := to_Text (get_Line (passwd_File));
- Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
- the_user_Id : user_Id_t := user_Id_t'Value (to_String (Tokens (3)));
- the_User : POSIX.account.User.view;
- begin
- if Tokens'Length > 7 then
- raise constraint_Error with "invalid user at line" & natural'Image (line_Count) & " in file '" & passwd_Filename & "'";
- end if;
- if the_user_Id /= user_Id_t'Last then
- free_user_Id := user_Id_t'max (free_user_Id, the_user_Id);
- end if;
- the_User := new_User (user_id => the_user_Id,
- user_name => to_String (Tokens (1)),
- password => to_String (Tokens (2)),
- main_group_id => group_Id_t'Value (to_String (Tokens (4))),
- main_group => null,
- comment => to_String (Tokens (5)),
- home_path => to_String (Tokens (6)),
- shell_path => to_String (Tokens (7)));
- the_name_Map_of_users.include (+the_User.Name, the_User);
- the_id_Map_of_users .include (the_user.Id, the_User);
- -- INFO: Debug Code !
- -- for Each in Tokens'range loop
- -- put_Line ("'POSIX.User_DB.User' ~ passwd token " & integer'Image (Each) & " '" & to_String (Tokens (Each)) & "'");
- -- end loop;
- end;
- end loop;
- Safe_IO.Close_Passwd(File => Passwd_File);
- free_user_Id := free_user_Id + 1;
- exception
- when ada.io_exceptions.Name_Error => null; -- no 'passwd' file exists, so do nothing
- end parse_passwd_file_into_user_DB;
- parse_group_file_into_user_DB:
- declare
- Group_File : Ada.text_IO.File_type;
- line_Count : Natural := 0;
- begin
- Safe_IO.Open_Group(File => Group_File);
- while not end_of_File (group_File) loop
- declare
- use POSIX.account.Group, lace.Text, ada.Strings.fixed;
- the_new_Group : POSIX.account.Group.view;
- the_Line : lace.Text.item := to_Text (get_Line (group_File));
- Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
- the_group_Id : group_Id_t := group_Id_t'Value (to_String (Tokens (3)));
- begin
- if Tokens'Length > 4 then
- raise constraint_Error with "invalid user at line" & natural'Image (line_Count) & " in file '" & Groups_Filename & "'";
- end if;
- if the_group_Id /= group_Id_t'Last then
- free_group_Id := user_Id_t'max (free_group_Id, the_group_Id);
- end if;
- the_new_Group := new_Group (named => to_String (Tokens (1)),
- password => to_String (Tokens (2)),
- id => the_group_Id);
- begin
- declare
- users_Field : constant String := to_String (Tokens (4));
- users_Text : lace.Text.item := to_Text (users_Field);
- user_Tokens : lace.Text.items_1k := lace.Text.Tokens (users_Text, ',');
- the_User : POSIX.account.User.view;
- begin
- for Each in user_Tokens'range loop
- the_User := the_name_Map_of_users.Element (key => +to_String (user_Tokens (Each)));
- the_new_Group.add (the_User.all'access);
- end loop;
- end;
- end;
- end;
- end loop;
- Safe_IO.Close_Group(File => Group_File);
- free_group_Id := free_group_Id + 1;
- exception
- when ada.io_exceptions.Name_Error => null; -- no 'groups' file exists, so do nothing
- end parse_group_file_into_user_DB;
- resolve_all_user_main_Groups:
- declare
- use name_Map_of_users;
- Cursor : name_Map_of_users.Cursor := the_name_Map_of_users.First;
- the_User : POSIX.account.User.view;
- begin
- while has_Element (Cursor) loop
- the_User := Element (Cursor);
- -- INFO: Debug Code !
- -- Put_Line (the_User.Name & group_Id_t'image (the_User.main_group_Id));
- the_User.Group_is (the_id_Map_of_groups.Element (key => the_User.main_group_Id));
- next (Cursor);
- end loop;
- end resolve_all_user_main_Groups;
- parse_shadow_file_into_user_DB:
- declare
- Shadow_File : Ada.Text_IO.File_type;
- line_Count : Natural := 0;
- begin
- Safe_IO.Open_Shadow(File => Shadow_File);
- while not end_of_File (shadow_File) loop
- declare
- use lace.Text, ada.Strings.fixed;
- the_Line : lace.Text.item := to_Text (get_Line (shadow_File));
- Tokens : lace.Text.items_1k := lace.Text.Tokens (the_Line, ':');
- the_Name : unbounded_String := +to_String (Tokens (1));
- the_User : POSIX.account.User.view;
- begin
- if Tokens'Length > 9 then
- raise constraint_Error with "invalid details at line" & natural'Image (line_Count) & " in file '" & shadow_Filename & "'";
- end if;
- -- INFO: Debug Code !
- -- for Each in Tokens'range loop
- -- put_Line ("'POSIX.User_DB.User' ~ shadow token " & integer'Image (Each) & " '" & to_String (Tokens (Each)) & "'");
- -- end loop;
- the_User := the_name_Map_of_users.Element (key => the_Name).all'access;
- declare
- the_shadow_Password : a_shadow_Password := the_User.shadow_Password;
- begin
- the_shadow_Password.Encrypted := +to_String (Tokens (2));
- the_shadow_Password.last_changed_Date := natural'Value (to_String (Tokens (3)));
- the_shadow_Password.Days_until_change_allowed := natural'Value (to_String (Tokens (4)));
- the_shadow_Password.Days_before_change_required := natural'Value (to_String (Tokens (5)));
- the_shadow_Password.Days_warning_for_expiration := natural'Value (to_String (Tokens (6)));
- begin
- the_shadow_Password.Days_before_account_inactive := natural'Value (to_String (Tokens (7)));
- exception
- when constraint_Error =>
- the_shadow_Password.Days_before_account_inactive := 0; -- empty token
- end;
- begin
- the_shadow_Password.Days_since_Epoch_when_account_expires := natural'Value (to_String (Tokens (8)));
- exception
- when constraint_Error =>
- the_shadow_Password.Days_since_Epoch_when_account_expires := 0; -- empty token
- end;
- the_User.shadow_Password_is (the_shadow_Password);
- end;
- end;
- end loop;
- Safe_IO.Close_Shadow (File => Shadow_File);
- exception
- when ada.io_exceptions.Name_Error => null; -- no 'shadow' file exists, so do nothing
- end parse_shadow_file_into_user_DB;
- end POSIX.account.DB;
Add Comment
Please, Sign In to add comment