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