ssh_test_server/
command.rs1use crate::session::ProgramsMap;
2use crate::{SshExecuteContext, UsersMap};
3use russh::server::Handle;
4use russh::{ChannelId, CryptoVec};
5use tracing::debug;
6
7async fn send_stderr(channel: ChannelId, handle: &Handle, msg: &str) {
8 let mut stderr = CryptoVec::from_slice(msg.as_bytes());
9 stderr.push(b'\r');
10 stderr.push(b'\n');
11 handle.extended_data(channel, 1, stderr).await.unwrap();
12}
13
14async fn send_stdout(channel: ChannelId, handle: &Handle, msg: &str) {
15 let mut stdout = CryptoVec::from_slice(msg.as_bytes());
16 stdout.push(b'\r');
17 stdout.push(b'\n');
18 handle.data(channel, stdout).await.unwrap();
19}
20
21pub async fn execute_command(
22 command: Vec<u8>,
23 channel: ChannelId,
24 handle: &Handle,
25 session_user: &str,
26 users: &UsersMap,
27 programs: &ProgramsMap,
28) {
29 let cmd = String::from_utf8_lossy(&command);
30 let mut cmdline = cmd.to_string();
31 let mut parse = cmdline_words_parser::parse_posix(&mut cmdline);
32 let Some(program) = parse.next() else {
33 return;
35 };
36 let args: Vec<_> = parse.collect();
37
38 debug!("command: {cmd}, program {program} args: {args:?}");
39
40 if let Some(handler) = programs.get(program) {
41 let context = SshExecuteContext {
42 users,
43 current_user: session_user,
44 };
45
46 let r = handler(&context, program, &args);
47
48 if !r.stderr.is_empty() {
49 send_stderr(channel, handle, &r.stderr).await;
50 }
51 if !r.stdout.is_empty() {
52 send_stdout(channel, handle, &r.stdout).await;
53 }
54
55 handle
56 .exit_status_request(channel, r.status_code)
57 .await
58 .unwrap();
59 } else if program == "echo" {
60 let mut stdout = String::new();
61 for a in args {
62 stdout.push_str(a);
63 }
64 send_stdout(channel, handle, &stdout).await;
65 handle.exit_status_request(channel, 0).await.unwrap();
66 } else if program == "change_password" {
67 match args.first() {
68 Some(new_password) => {
69 {
70 let mut users = users.lock().unwrap();
71 let user = users.get_mut(session_user).unwrap();
72 user.set_password(new_password);
73 }
74 send_stdout(channel, handle, "password changed").await;
75 handle.exit_status_request(channel, 0).await.unwrap();
76 }
77 None => {
78 send_stdout(
79 channel,
80 handle,
81 "no password Usage: change_password <new_password>",
82 )
83 .await;
84 handle.exit_status_request(channel, 1).await.unwrap();
85 }
86 }
87 } else if program == "exit" {
88 handle.exit_status_request(channel, 0).await.unwrap();
89 handle.close(channel).await.unwrap();
90 } else {
91 let msg = format!("{program}: command not found");
92 send_stderr(channel, handle, &msg).await;
93 handle.exit_status_request(channel, 127).await.unwrap();
94 }
95}