authentication/lib.rs
1//! # Authentication Module
2//!
3//! The Authentication module provides user and group management functionality for the Xila operating system.
4//! It handles user authentication, password hashing, and secure storage of user/group information.
5//!
6//! ## Features
7//!
8//! - **User Management**: Create, authenticate, and manage user accounts
9//! - **Group Management**: Create and manage user groups
10//! - **Password Security**: Secure password hashing using SHA-512 with salt
11//! - **File-based Storage**: Persistent storage of user and group data in JSON format
12//! - **Async Operations**: All operations are asynchronous for better performance
13//!
14//! ## Usage
15//!
16//! The module provides functionality to:
17//! - Load existing users and groups from the filesystem
18//! - Authenticate users with username/password
19//! - Create new users and groups
20//! - Change user passwords and usernames
21//! - Hash passwords securely with salt generation
22//!
23//! ## File Structure
24//!
25//! - Users are stored in `/System/Users/` directory
26//! - Groups are stored in `/System/Groups/` directory
27//! - Each user/group has their own JSON file containing their data
28//! - Random salt generation uses `/devices/random` device
29
30#![no_std]
31
32extern crate alloc;
33
34mod error;
35mod group;
36mod hash;
37mod user;
38
39use alloc::{vec, vec::Vec};
40pub use error::*;
41pub use group::*;
42pub use user::*;
43
44const READ_CHUNK_SIZE: usize = 32;
45
46/// Path to the users directory in the filesystem
47const USERS_FOLDER_PATH: &str = "/system/users";
48
49/// Path to the groups directory in the filesystem
50const GROUP_FOLDER_PATH: &str = "/system/groups";
51
52/// Path to the random device used for salt generation
53const RANDOM_DEVICE_PATH: &str = "/devices/random";
54
55/// Loads all users and groups from the filesystem into memory.
56///
57/// This function scans the `/System/Users` and `/System/Groups` directories,
58/// reads all user and group files, and adds them to the Users manager.
59/// It should be called during system initialization.
60///
61/// # Returns
62///
63/// Returns `Ok(())` if all users and groups were loaded successfully,
64/// or an `Error` if any operation failed.
65///
66/// # Errors
67///
68/// This function can return errors in the following cases:
69/// - Failed to read users or groups directory
70/// - Failed to parse user or group files
71/// - Failed to add users or groups to the Users manager
72///
73/// # Examples
74///
75/// ```rust
76/// use authentication::load_all_users_and_groups;
77///
78/// async fn example() -> Result<(), authentication::Error> {
79/// load_all_users_and_groups().await?;
80/// Ok(())
81/// }
82/// ```
83pub async fn load_all_users_and_groups() -> Result<()> {
84 use group::read_group_file;
85 use user::read_user_file;
86 use virtual_file_system::Directory;
87 // Open Xila users folder.
88 let virtual_file_system = virtual_file_system::get_instance();
89
90 let users_manager = users::get_instance();
91
92 let mut buffer: Vec<u8> = vec![];
93
94 {
95 let task = task::get_instance().get_current_task_identifier().await;
96
97 let groups_directory = Directory::open(virtual_file_system, task, GROUP_FOLDER_PATH)
98 .await
99 .map_err(Error::FailedToReadGroupDirectory)?;
100
101 // Read all groups.
102 for group_entry in groups_directory {
103 let group = if let Ok(group) =
104 read_group_file(virtual_file_system, &mut buffer, &group_entry.name).await
105 {
106 group
107 } else {
108 // ? : Log error ?
109 continue;
110 };
111
112 users_manager
113 .add_group(group.get_identifier(), group.get_name(), group.get_users())
114 .await
115 .map_err(Error::FailedToAddGroup)?;
116 }
117 }
118
119 {
120 let task = task::get_instance().get_current_task_identifier().await;
121
122 let users_directory = Directory::open(virtual_file_system, task, USERS_FOLDER_PATH)
123 .await
124 .map_err(Error::FailedToReadUsersDirectory)?;
125
126 // Read all users.
127 for user_entry in users_directory {
128 let user = if let Ok(user) =
129 read_user_file(virtual_file_system, &mut buffer, &user_entry.name).await
130 {
131 user
132 } else {
133 // ? : Log error ?
134 continue;
135 };
136
137 users_manager
138 .add_user(
139 user.get_identifier(),
140 user.get_name(),
141 user.get_primary_group(),
142 )
143 .await
144 .map_err(Error::FailedToAddUser)?;
145 }
146 }
147
148 Ok(())
149}