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}