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(
27 users_manager: &users::Manager,
28 statistics: &Statistics,
29 user: UserIdentifier,
30) -> bool {
31 if statistics
32 .permissions
33 .get_others()
34 .contains(Permission::Execute)
35 {
36 return true;
37 }
38
39 let is_user_allowed = user == UserIdentifier::ROOT || user == statistics.user;
40 if is_user_allowed
41 && statistics
42 .permissions
43 .get_user()
44 .contains(Permission::Execute)
45 {
46 return true;
47 }
48
49 let is_in_group =
50 users_manager.is_in_group(user, statistics.group).await || 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 context: &ExecutableContext,
65 statistics: &Statistics,
66 task: TaskIdentifier,
67) -> Result<Option<UserIdentifier>> {
68 if !statistics
69 .permissions
70 .get_special()
71 .get_set_user_identifier()
72 {
73 return Ok(None);
74 }
75
76 let current_user = context.task_manager.get_user(task).await?;
77
78 let new_user = statistics.user;
79
80 if current_user != users::UserIdentifier::ROOT || new_user != current_user {
81 return Err(Error::PermissionDenied);
82 }
83
84 Ok(Some(new_user))
85}
86
87pub async fn execute(
88 context: &'static ExecutableContext,
89 path: impl AsRef<Path>,
90 inputs: Vec<String>,
91 standard: Standard<'static>,
92 spawner: Option<SpawnerIdentifier>,
93) -> Result<JoinHandle<isize>> {
94 let task_instance = &context.task_manager;
95
96 let task = task_instance.get_current_task_identifier().await;
97
98 let virtual_file_system = &context.virtual_file_system;
99
100 let statistics = virtual_file_system.get_statistics(&path.as_ref()).await?;
101
102 if !is_execute_allowed(
104 context.users_manager,
105 &statistics,
106 task_instance.get_user(task).await?,
107 )
108 .await
109 {
110 return Err(Error::PermissionDenied);
111 }
112
113 let mut file = File::open(virtual_file_system, task, &path, AccessFlags::Read.into()).await?;
114
115 let new_user = get_overridden_user(context, &statistics, task).await?;
117
118 let file_name = path
119 .as_ref()
120 .get_file_name()
121 .ok_or(virtual_file_system::Error::InvalidPath)?;
122
123 let main_function: MainFunction = file.control(GET_MAIN_FUNCTION, &()).await?;
124
125 let main = main_function.ok_or(Error::FailedToGetMainFunction)?;
126
127 let (join_handle, _) = task_instance
128 .spawn(task, file_name, spawner, async move |task| {
129 if let Some(new_user) = new_user {
130 context.task_manager.set_user(task, new_user).await.unwrap();
131 }
132
133 match main(context, standard, inputs).await {
134 Ok(_) => 0_isize,
135 Err(error) => -(error.get() as isize),
136 }
137 })
138 .await?;
139
140 Ok(join_handle)
141}
142
143#[cfg(test)]
144mod tests {
145 extern crate std;
146
147 use file_system::{Permissions, Time};
148
149 use task::test;
150 use users::GroupIdentifier;
151
152 use super::*;
153
154 fn get_statistics_with_permissions(permissions: Permissions) -> Statistics {
155 Statistics::new(
156 0,
157 1,
158 0,
159 Time::new(0),
160 Time::new(0),
161 Time::new(0),
162 Time::new(0),
163 file_system::Kind::File,
164 permissions,
165 UserIdentifier::ROOT,
166 GroupIdentifier::ROOT,
167 )
168 }
169
170 #[test]
171 async fn test_is_execute_allowed() {
172 let users_manager = users::Manager::new();
173
174 let statistics = get_statistics_with_permissions(Permissions::ALL_FULL);
175 assert!(is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
176
177 let statistics = get_statistics_with_permissions(Permissions::EXECUTABLE);
178 assert!(is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
179
180 let statistics = get_statistics_with_permissions(Permissions::from_octal(0o007).unwrap());
181 assert!(is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
182
183 let statistics = get_statistics_with_permissions(Permissions::from_octal(0o070).unwrap());
184 assert!(is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
185
186 let statistics = get_statistics_with_permissions(Permissions::from_octal(0o100).unwrap());
187 assert!(is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
188
189 let statistics = get_statistics_with_permissions(Permissions::USER_READ_WRITE);
190 assert!(!is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
191
192 let statistics = get_statistics_with_permissions(Permissions::NONE);
193 assert!(!is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
194
195 let statistics = get_statistics_with_permissions(Permissions::ALL_READ_WRITE);
196 assert!(!is_execute_allowed(&users_manager, &statistics, UserIdentifier::ROOT).await);
197 }
198}