executable/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5mod arguments_parser;
6#[cfg(feature = "building")]
7mod building;
8mod error;
9mod standard;
10mod traits;
11
12pub use arguments_parser::*;
13#[cfg(feature = "building")]
14pub use building::*;
15pub use error::*;
16pub use file_system as exported_file_system;
17pub use standard::*;
18pub use task as exported_task;
19pub use traits::*;
20pub use virtual_file_system as exported_virtual_file_system;
21
22use alloc::{string::String, vec::Vec};
23use file_system::{AccessFlags, Path, Permission, Statistics};
24use task::{JoinHandle, SpawnerIdentifier, TaskIdentifier};
25use users::UserIdentifier;
26use virtual_file_system::File;
27
28async fn is_execute_allowed(statistics: &Statistics, user: UserIdentifier) -> bool {
29    if statistics
30        .permissions
31        .get_others()
32        .contains(Permission::Execute)
33    {
34        return true;
35    }
36
37    let is_user_allowed = user == UserIdentifier::ROOT || user == statistics.user;
38    if is_user_allowed
39        && statistics
40            .permissions
41            .get_user()
42            .contains(Permission::Execute)
43    {
44        return true;
45    }
46
47    let is_in_group = users::get_instance()
48        .is_in_group(user, statistics.group)
49        .await
50        || user == UserIdentifier::ROOT;
51    if (is_in_group)
52        && statistics
53            .permissions
54            .get_group()
55            .contains(Permission::Execute)
56    {
57        return true;
58    }
59
60    false
61}
62
63async fn get_overridden_user(
64    statistics: &Statistics,
65    task: TaskIdentifier,
66) -> Result<Option<UserIdentifier>> {
67    if !statistics
68        .permissions
69        .get_special()
70        .get_set_user_identifier()
71    {
72        return Ok(None);
73    }
74
75    let current_user = task::get_instance().get_user(task).await?;
76
77    let new_user = statistics.user;
78
79    if current_user != users::UserIdentifier::ROOT || new_user != current_user {
80        return Err(Error::PermissionDenied);
81    }
82
83    Ok(Some(new_user))
84}
85
86pub async fn execute(
87    path: impl AsRef<Path>,
88    inputs: Vec<String>,
89    standard: Standard,
90    spawner: Option<SpawnerIdentifier>,
91) -> Result<JoinHandle<isize>> {
92    let task_instance = task::get_instance();
93
94    let task = task_instance.get_current_task_identifier().await;
95
96    let virtual_file_system = virtual_file_system::get_instance();
97
98    let statistics = virtual_file_system.get_statistics(&path.as_ref()).await?;
99
100    // - Check the executable bit
101    if !is_execute_allowed(&statistics, task_instance.get_user(task).await?).await {
102        return Err(Error::PermissionDenied);
103    }
104
105    let mut file = File::open(virtual_file_system, task, &path, AccessFlags::Read.into()).await?;
106
107    // - Check if the user can override the user identifier
108    let new_user = get_overridden_user(&statistics, task).await?;
109
110    let file_name = path
111        .as_ref()
112        .get_file_name()
113        .ok_or(virtual_file_system::Error::InvalidPath)?;
114
115    let main_function: MainFunction = file.control(GET_MAIN_FUNCTION, &()).await?;
116
117    let main = main_function.ok_or(Error::FailedToGetMainFunction)?;
118
119    let (join_handle, _) = task_instance
120        .spawn(task, file_name, spawner, async move |task| {
121            if let Some(new_user) = new_user {
122                task::get_instance().set_user(task, new_user).await.unwrap();
123            }
124
125            match main(standard, inputs).await {
126                Ok(_) => 0_isize,
127                Err(error) => -(error.get() as isize),
128            }
129        })
130        .await?;
131
132    Ok(join_handle)
133}
134
135#[cfg(test)]
136mod tests {
137    extern crate std;
138
139    use file_system::{Permissions, Time};
140
141    use task::test;
142    use users::GroupIdentifier;
143
144    use super::*;
145
146    fn get_statistics_with_permissions(permissions: Permissions) -> Statistics {
147        Statistics::new(
148            0,
149            1,
150            0,
151            Time::new(0),
152            Time::new(0),
153            Time::new(0),
154            Time::new(0),
155            file_system::Kind::File,
156            permissions,
157            UserIdentifier::ROOT,
158            GroupIdentifier::ROOT,
159        )
160    }
161
162    #[test]
163    async fn test_is_execute_allowed() {
164        users::initialize();
165
166        let statistics = get_statistics_with_permissions(Permissions::ALL_FULL);
167        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
168
169        let statistics = get_statistics_with_permissions(Permissions::EXECUTABLE);
170        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
171
172        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o007).unwrap());
173        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
174
175        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o070).unwrap());
176        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
177
178        let statistics = get_statistics_with_permissions(Permissions::from_octal(0o100).unwrap());
179        assert!(is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
180
181        let statistics = get_statistics_with_permissions(Permissions::USER_READ_WRITE);
182        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
183
184        let statistics = get_statistics_with_permissions(Permissions::NONE);
185        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
186
187        let statistics = get_statistics_with_permissions(Permissions::ALL_READ_WRITE);
188        assert!(!is_execute_allowed(&statistics, UserIdentifier::ROOT).await);
189    }
190}