1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 //! task
16 #![allow(missing_docs)]
17 
18 use crate::daemon_lib::{auth, daemon_unity};
19 
20 use crate::daemon_lib::shell::*;
21 
22 use crate::daemon_lib::daemon_app::{self, AppTaskMap, DaemonAppTask};
23 use crate::daemon_lib::sys_para::*;
24 use crate::utils::hdc_log::*;
25 use crate::common::forward::{self, ForwardTaskMap, HdcForward};
26 use crate::common::hdcfile::{self, FileTaskMap, HdcFile};
27 use crate::common::jdwp;
28 use crate::config::*;
29 use crate::transfer;
30 
31 use std::io::{self, Error, ErrorKind};
32 
33 async fn daemon_shell_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
34     match task_message.command {
35         HdcCommand::ShellInit => {
36             let pty_task = PtyTask::new(
37                 session_id,
38                 task_message.channel_id,
39                 None,
40                 HdcCommand::KernelEchoRaw,
41             );
42             PtyMap::put(session_id, task_message.channel_id, pty_task).await;
43         }
44         HdcCommand::UnityExecute => {
45             match String::from_utf8(task_message.payload) {
46                 Ok(cmd_str) => {
47                     let shell_execute_task: ShellExecuteTask = ShellExecuteTask::new(
48                         session_id,
49                         task_message.channel_id,
50                         cmd_str,
51                         HdcCommand::KernelEchoRaw,
52                     );
53 
54                     ShellExecuteMap::put(session_id, task_message.channel_id, shell_execute_task).await;
55                 },
56                 Err(_) => {
57                     crate::common::hdctransfer::echo_client(
58                         session_id,
59                         task_message.channel_id,
60                         "only support utf-8 chars",
61                         MessageLevel::Fail,
62                     )
63                     .await;
64                     let message = TaskMessage {
65                         channel_id: task_message.channel_id,
66                         command: HdcCommand::KernelChannelClose,
67                         payload: [1].to_vec(),
68                     };
69                     let _ = daemon_channel_close(message, session_id).await;
70                     return Err(Error::new(ErrorKind::Other, "Get an FromUtf8Error"));
71                 }
72             }
73         }
74         _ => {
75             let channel_id = task_message.channel_id;
76             if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
77                 let _ = &pty_task.tx.send(task_message.payload.clone()).await;
78                 if task_message.payload[..].contains(&0x4_u8) {
79                     PtyMap::del(session_id, channel_id).await;
80                 }
81                 return Ok(());
82             } else {
83                 return Err(Error::new(ErrorKind::Other, "invalid channel id"));
84             }
85         }
86     }
87     Ok(())
88 }
89 
90 async fn remove_task(session_id: u32, channel_id: u32) {
91     jdwp::stop_task(session_id, channel_id).await;
92     AppTaskMap::remove(session_id, channel_id).await;
93     FileTaskMap::remove(session_id, channel_id).await;
94     forward::free_channel_task(session_id, channel_id).await;
95     // shell & hilog task
96     if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
97         let _ = &pty_task.tx.send(vec![0x04_u8]).await;
98         PtyMap::del(session_id, channel_id).await;
99     }
100     ShellExecuteMap::del(session_id, channel_id).await;
101 }
102 
103 async fn daemon_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
104     // task stop:
105     crate::debug!(
106         "daemon_channel_close session_id {session_id}, channel_id {}",
107         task_message.channel_id
108     );
109 
110     remove_task(session_id, task_message.channel_id).await;
111 
112     if task_message.payload[0] > 0 {
113         let message = TaskMessage {
114             channel_id: task_message.channel_id,
115             command: HdcCommand::KernelChannelClose,
116             payload: vec![task_message.payload[0] - 1],
117         };
118         transfer::put(session_id, message).await;
119     }
120     Ok(())
121 }
122 
123 async fn daemon_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
124     match task_message.command {
125         HdcCommand::AppCheck | HdcCommand::AppUninstall => {
126             if !AppTaskMap::exsit(session_id, task_message.channel_id).await {
127                 let task = DaemonAppTask::new(session_id, task_message.channel_id);
128                 AppTaskMap::put(session_id, task_message.channel_id, task).await;
129             }
130             daemon_app::command_dispatch(
131                 session_id,
132                 task_message.channel_id,
133                 task_message.command,
134                 &task_message.payload,
135                 task_message.payload.len() as u16,
136             )
137             .await;
138             return Ok(());
139         }
140         HdcCommand::AppBegin | HdcCommand::AppData => {
141             daemon_app::command_dispatch(
142                 session_id,
143                 task_message.channel_id,
144                 task_message.command,
145                 &task_message.payload,
146                 task_message.payload.len() as u16,
147             )
148             .await;
149             return Ok(());
150         }
151         HdcCommand::FileMode | HdcCommand::FileCheck | HdcCommand::FileInit => {
152             if !FileTaskMap::exsit(session_id, task_message.channel_id).await {
153                 let mut task = HdcFile::new(session_id, task_message.channel_id);
154                 task.transfer.server_or_daemon = false;
155                 FileTaskMap::put(session_id, task_message.channel_id, task).await;
156             }
157 
158             hdcfile::command_dispatch(
159                 session_id,
160                 task_message.channel_id,
161                 task_message.command,
162                 &task_message.payload,
163                 task_message.payload.len() as u16,
164             )
165             .await;
166             return Ok(());
167         }
168         HdcCommand::ForwardInit | HdcCommand::ForwardCheck => {
169             let mut task = HdcForward::new(session_id, task_message.channel_id, false);
170             task.transfer.server_or_daemon = false;
171             ForwardTaskMap::update(session_id, task_message.channel_id, task).await;
172             forward::command_dispatch(
173                 session_id,
174                 task_message.channel_id,
175                 task_message.command,
176                 &task_message.payload,
177                 task_message.payload.len() as u16,
178             )
179             .await;
180             return Ok(());
181         }
182         HdcCommand::ForwardCheckResult
183         | HdcCommand::ForwardActiveSlave
184         | HdcCommand::ForwardActiveMaster
185         | HdcCommand::ForwardData
186         | HdcCommand::ForwardFreeContext => {
187             forward::command_dispatch(
188                 session_id,
189                 task_message.channel_id,
190                 task_message.command,
191                 &task_message.payload,
192                 task_message.payload.len() as u16,
193             )
194             .await;
195             return Ok(());
196         }
197         HdcCommand::FileBegin
198         | HdcCommand::FileData
199         | HdcCommand::FileFinish
200         | HdcCommand::DirMode => {
201             hdcfile::command_dispatch(
202                 session_id,
203                 task_message.channel_id,
204                 task_message.command,
205                 &task_message.payload,
206                 task_message.payload.len() as u16,
207             )
208             .await;
209             return Ok(());
210         }
211         HdcCommand::UnityRunmode
212         | HdcCommand::UnityReboot
213         | HdcCommand::UnityRemount
214         | HdcCommand::UnityRootrun
215         | HdcCommand::JdwpList
216         | HdcCommand::JdwpTrack => {
217             daemon_unity::command_dispatch(
218                 session_id,
219                 task_message.channel_id,
220                 task_message.command,
221                 &task_message.payload,
222                 task_message.payload.len() as u16,
223             )
224             .await;
225             return Ok(());
226         }
227         _ => {
228             crate::error!(
229                 "other tasks, cmd {:?}. session_id {session_id}, channel_id {}",
230                 task_message.command,
231                 task_message.channel_id
232             );
233         }
234     }
235 
236     Ok(())
237 }
238 
239 async fn daemon_hilog_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
240     let cmd = if task_message.payload.len() == 1 && task_message.payload[0] == 104 {
241         // payload is 'h'
242         "hilog -h"
243     } else {
244         // blank or unknown payload, ignore
245         "hilog"
246     }
247     .to_string();
248     let pty_task = PtyTask::new(
249         session_id,
250         task_message.channel_id,
251         Some(cmd),
252         HdcCommand::KernelEchoRaw,
253     );
254     PtyMap::put(session_id, task_message.channel_id, pty_task).await;
255     Ok(())
256 }
257 
258 async fn daemon_bug_report_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
259     let pty_task = PtyTask::new(
260         session_id,
261         task_message.channel_id,
262         Some("hidumper".to_string()),
263         HdcCommand::UnityBugreportData,
264     );
265     PtyMap::put(session_id, task_message.channel_id, pty_task).await;
266     Ok(())
267 }
268 
get_control_permissionnull269 fn get_control_permission(param: &str) -> bool {
270     let (_, control_value) = get_dev_item(param, "_");
271     if control_value.trim().to_lowercase() == "false" {
272         return false;
273     }
274     true
275 }
276 
check_controlnull277 fn check_control(command: HdcCommand) -> bool {
278     let mut control_param = "";
279     match command {
280         HdcCommand::UnityRunmode
281         | HdcCommand::UnityReboot
282         | HdcCommand::UnityRemount
283         | HdcCommand::UnityRootrun
284         | HdcCommand::ShellInit
285         | HdcCommand::ShellData
286         | HdcCommand::UnityExecute
287         | HdcCommand::UnityHilog
288         | HdcCommand::UnityBugreportInit
289         | HdcCommand::JdwpList
290         | HdcCommand::JdwpTrack => {
291             control_param = ENV_SHELL_CONTROL;
292         }
293         HdcCommand::FileInit
294         | HdcCommand::FileCheck
295         | HdcCommand::FileData
296         | HdcCommand::FileBegin
297         | HdcCommand::FileFinish
298         | HdcCommand::AppCheck
299         | HdcCommand::AppData
300         | HdcCommand::AppUninstall => {
301             control_param = ENV_FILE_CONTROL;
302         }
303         HdcCommand::ForwardInit
304         | HdcCommand::ForwardCheck
305         | HdcCommand::ForwardCheckResult
306         | HdcCommand::ForwardActiveSlave
307         | HdcCommand::ForwardActiveMaster
308         | HdcCommand::ForwardData
309         | HdcCommand::ForwardFreeContext => {
310             control_param = ENV_FPORT_CONTROL;
311         }
312         _ => {}
313     }
314     // (_, run_debug) = crate::utils::get_dev_item(param);
315     if !control_param.is_empty() && !get_control_permission(control_param) {
316         return false;
317     }
318     true
319 }
320 
321 pub async fn dispatch_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
322     let cmd = task_message.command;
323     let special_cmd =
324         (cmd == HdcCommand::KernelHandshake) || (cmd == HdcCommand::KernelChannelClose);
325     let auth_ok = auth::AuthStatusMap::get(session_id).await == auth::AuthStatus::Ok;
326 
327     if !auth_ok && !special_cmd {
328         crate::error!("auth status is nok, cannt accept cmd: {}", cmd as u32);
329         crate::common::hdctransfer::echo_client(
330             session_id,
331             task_message.channel_id,
332             auth::get_auth_msg(session_id).await.as_str(),
333             MessageLevel::Fail,
334         )
335         .await;
336         transfer::put(
337             session_id,
338             auth::make_channel_close_message(task_message.channel_id).await,
339         )
340         .await;
341         return Err(Error::new(
342             ErrorKind::Other,
343             format!("auth status is nok, cannt accept cmd: {}", cmd as u32),
344         ));
345     }
346     if !check_control(task_message.command) {
347         crate::common::hdctransfer::echo_client(
348             session_id,
349             task_message.channel_id,
350             "debugging is not allowed",
351             MessageLevel::Fail,
352         )
353         .await;
354         crate::common::hdctransfer::transfer_task_finish(task_message.channel_id, session_id).await;
355         crate::debug!(
356             "check_permission param false: {}",
357             task_message.command as u32
358         );
359 
360         return Ok(());
361     }
362     match task_message.command {
363         HdcCommand::KernelHandshake => auth::handshake_task(task_message, session_id).await,
364         HdcCommand::UnityHilog => daemon_hilog_task(task_message, session_id).await,
365         HdcCommand::UnityBugreportInit => daemon_bug_report_task(task_message, session_id).await,
366         HdcCommand::ShellInit | HdcCommand::ShellData | HdcCommand::UnityExecute => {
367             daemon_shell_task(task_message, session_id).await
368         }
369         HdcCommand::KernelChannelClose => daemon_channel_close(task_message, session_id).await,
370         HdcCommand::FileInit
371         | HdcCommand::FileCheck
372         | HdcCommand::FileData
373         | HdcCommand::FileBegin
374         | HdcCommand::FileFinish
375         | HdcCommand::FileMode
376         | HdcCommand::DirMode
377         | HdcCommand::AppCheck
378         | HdcCommand::AppData
379         | HdcCommand::AppUninstall
380         | HdcCommand::ForwardInit
381         | HdcCommand::ForwardCheck
382         | HdcCommand::ForwardCheckResult
383         | HdcCommand::ForwardActiveSlave
384         | HdcCommand::ForwardActiveMaster
385         | HdcCommand::ForwardData
386         | HdcCommand::ForwardFreeContext
387         | HdcCommand::UnityRunmode
388         | HdcCommand::UnityReboot
389         | HdcCommand::UnityRemount
390         | HdcCommand::UnityRootrun
391         | HdcCommand::JdwpList
392         | HdcCommand::JdwpTrack => daemon_file_task(task_message, session_id).await,
393         HdcCommand::KernelWakeupSlavetask => Ok(()),
394         _ => Err(Error::new(
395             ErrorKind::Other,
396             format!("unknown command: {}", task_message.command as u32),
397         )),
398     }
399 }