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}