ssh_test_server/
command.rs

1use 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        // just enter
34        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}