Skip to main content

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::*;
42use task::TaskIdentifier;
43pub use user::*;
44use virtual_file_system::VirtualFileSystem;
45
46const READ_CHUNK_SIZE: usize = 32;
47
48/// Path to the users directory in the filesystem
49const USERS_FOLDER_PATH: &str = "/system/users";
50
51/// Path to the groups directory in the filesystem
52const GROUP_FOLDER_PATH: &str = "/system/groups";
53
54/// Path to the random device used for salt generation
55const RANDOM_DEVICE_PATH: &str = "/devices/random";
56
57/// The dependencies required by authentication operations.
58pub struct Context<'a> {
59    pub virtual_file_system: &'a VirtualFileSystem,
60    pub task_manager: &'a task::Manager,
61    pub users_manager: &'a users::Manager,
62    pub task: TaskIdentifier,
63}
64
65/// Loads all users and groups from the filesystem into memory.
66///
67/// This function scans the `/System/Users` and `/System/Groups` directories,
68/// reads all user and group files, and adds them to the Users manager.
69/// It should be called during system initialization.
70///
71/// # Returns
72///
73/// Returns `Ok(())` if all users and groups were loaded successfully,
74/// or an `Error` if any operation failed.
75///
76/// # Errors
77///
78/// This function can return errors in the following cases:
79/// - Failed to read users or groups directory
80/// - Failed to parse user or group files
81/// - Failed to add users or groups to the Users manager
82///
83/// # Examples
84///
85/// ```rust
86/// use authentication::load_all_users_and_groups;
87///
88/// async fn example() -> Result<(), authentication::Error> {
89///     load_all_users_and_groups().await?;
90///     Ok(())
91/// }
92/// ```
93pub async fn load_all_users_and_groups(context: &Context<'_>) -> Result<()> {
94    use group::read_group_file;
95    use user::read_user_file;
96    use virtual_file_system::Directory;
97    // Open Xila users folder.
98    let virtual_file_system = context.virtual_file_system;
99    let users_manager = context.users_manager;
100
101    let mut buffer: Vec<u8> = vec![];
102
103    {
104        let task = context.task;
105
106        let groups_directory = Directory::open(virtual_file_system, task, GROUP_FOLDER_PATH)
107            .await
108            .map_err(Error::FailedToReadGroupDirectory)?;
109
110        // Read all groups.
111        for group_entry in groups_directory {
112            let group =
113                if let Ok(group) = read_group_file(context, &mut buffer, &group_entry.name).await {
114                    group
115                } else {
116                    // ? : Log error ?
117                    continue;
118                };
119
120            users_manager
121                .add_group(group.get_identifier(), group.get_name(), group.get_users())
122                .await
123                .map_err(Error::FailedToAddGroup)?;
124        }
125    }
126
127    {
128        let task = context.task;
129
130        let users_directory = Directory::open(virtual_file_system, task, USERS_FOLDER_PATH)
131            .await
132            .map_err(Error::FailedToReadUsersDirectory)?;
133
134        // Read all users.
135        for user_entry in users_directory {
136            let user =
137                if let Ok(user) = read_user_file(context, &mut buffer, &user_entry.name).await {
138                    user
139                } else {
140                    // ? : Log error ?
141                    continue;
142                };
143
144            users_manager
145                .add_user(
146                    user.get_identifier(),
147                    user.get_name(),
148                    user.get_primary_group(),
149                )
150                .await
151                .map_err(Error::FailedToAddUser)?;
152        }
153    }
154
155    Ok(())
156}