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