1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//! Dependencies
//! ```
//! ssh-rs = "*"
//! ```
//!
//! Quick example:
//!
//!```
//!use std::io::{stdin, stdout, Write};
//!use std::sync::{Arc, Mutex};
//!use std::{thread, time};
//!use ssh_rs::{Channel, ChannelExec, Session, SSH};
//!fn main() {
//!     let ssh: SSH = SSH::new();
//!     // enable logging
//!     ssh.enable_log(true).unwrap();
//!     let mut session = ssh.get_session("127.0.0.1:22").unwrap();
//!     session.set_user_and_password("root".to_string(), "123456".to_string());
//!     session.connect().unwrap();
//!     exec(&mut session);
//!     shell(&mut session);
//!     // t_shell(&mut session);
//! }
//!
//! fn exec(session: &mut Session) {
//!     let exec: ChannelExec = session.open_exec().unwrap();
//!     let vec = exec.send_command("ls -all").unwrap();
//!     println!("{}", String::from_utf8(vec).unwrap());
//! }
//!
//! fn shell(session: &mut Session) {
//!     let mut shell = session.open_shell().unwrap();
//!     thread::sleep(time::Duration::from_millis(200));
//!     let vec = shell.read().unwrap();
//!     let result = String::from_utf8(vec).unwrap();
//!     println!("{}", result);
//!     shell.write(b"ls -a\r").unwrap();
//!     thread::sleep(time::Duration::from_millis(200));
//!     let vec = shell.read().unwrap();
//!     let result = String::from_utf8(vec).unwrap();
//!     println!("{}", result);
//!     shell.close().unwrap();
//! }
//!
//! fn t_shell(session: &mut Session) {
//!     let shell = session.open_shell().unwrap();
//!     let c1 = Arc::new(Mutex::new(shell));
//!     let c2 = Arc::clone(&c1);
//!     let t1 = thread::spawn( move || {
//!         loop {
//!             let x = c1.lock().unwrap().read().unwrap();
//!             if x.is_empty() { continue }
//!             stdout().write(x.as_slice()).unwrap();
//!             stdout().flush().unwrap();
//!         }
//!     });
//!
//!     let t2 = thread::spawn( move || {
//!         loop {
//!             let mut cm = String::new();
//!             stdin().read_line(&mut cm).unwrap();
//!             c2.lock().unwrap().write(cm.as_bytes()).unwrap();
//!         }
//!     });
//!
//!     t1.join().unwrap();
//!     t2.join().unwrap();
//! }
//!
//!
//!
//!```




mod packet;
mod tcp;
mod encryption;
mod session;
mod hash;
mod channel;
mod kex;
mod global;
mod channel_shell;
mod channel_exec;

pub mod error;
mod tests;
mod channel_scp;
mod config;
mod util;
mod slog;

pub use session::Session;
pub use channel::Channel;
pub use channel_shell::ChannelShell;
pub use channel_exec::ChannelExec;

use std::net::ToSocketAddrs;
use std::sync::Mutex;
use crate::config::Config;
use crate::encryption::{CURVE25519, KeyExchange, PublicKey};
use crate::encryption::rsa::RSA;
use crate::error::{SshError, SshResult};
use crate::slog::Slog;
use crate::tcp::Client;


pub struct SSH;

impl SSH {
    pub fn new() -> Self {
        Self
    }

    pub fn get_session<A: ToSocketAddrs>(self, adder: A) -> SshResult<Session> {
        util::update_client(
            Some(Mutex::new(Client::connect(adder)?))
        );
        util::update_config(
            Some(
                Mutex::new(Config::new()))
        );

        Session.set_nonblocking(true)?;
        Ok(Session)
    }

    pub fn enable_log(&self, b: bool) -> SshResult<()> {
        if b {
            Slog::default()?
        }
        Ok(())
    }
}


#[allow(dead_code)]
pub mod strings {
    pub const CLIENT_VERSION            :&'static str = "SSH-2.0-SSH_RS-0.1.3";
    pub const SSH_USERAUTH              :&'static str = "ssh-userauth";
    pub const SSH_CONNECTION            :&'static str = "ssh-connection";
    pub const PASSWORD                  :&'static str = "password";
    pub const SESSION                   :&'static str = "session";
    pub const SHELL                     :&'static str = "shell";
    pub const EXEC                      :&'static str = "exec";
    pub const SCP                       :&'static str = "scp";
    pub const PTY_REQ                   :&'static str = "pty-req";
    pub const XTERM_VAR                 :&'static str = "xterm-256color";
}

#[allow(dead_code)]
pub mod scp_arg {
    pub const SOURCE                    :&'static str = "-f";
    pub const SINK                      :&'static str = "-t";
    pub const RECURSIVE                 :&'static str = "-r";
    pub const VERBOSE                   :&'static str = "-v";
    pub const PRESERVE_TIMES            :&'static str = "-p";
    pub const QUIET                     :&'static str = "-q";
    pub const LIMIT                     :&'static str = "-l";
}


#[allow(dead_code)]
pub mod scp_flag {
    pub const C                         :&'static str = "C";
    pub const D                         :&'static str = "D";
    pub const E                         :&'static str = "E";
    // '\0'
    pub const END                       :u8           = 0;
    pub const ERR                       :u8           = 1;
    pub const FATAL_ERR                 :u8           = 2;
}


#[allow(dead_code)]
pub mod size {
    pub const ONE_GB                    :u32    = 1073741824;
    pub const BUF_SIZE                  :usize  = 32768;
    pub const LOCAL_WINDOW_SIZE         :u32    = 2097152;
}


#[allow(dead_code)]
pub mod message {
    pub const SSH_MSG_DISCONNECT                                :u8 = 1;
    pub const SSH_MSG_IGNORE                                    :u8 = 2;
    pub const SSH_MSG_UNIMPLEMENTED                             :u8 = 3;
    pub const SSH_MSG_DEBUG                                     :u8 = 4;
    pub const SSH_MSG_SERVICE_REQUEST                           :u8 = 5;
    pub const SSH_MSG_SERVICE_ACCEPT                            :u8 = 6;
    pub const SSH_MSG_KEXINIT                                   :u8 = 20;
    pub const SSH_MSG_NEWKEYS                                   :u8 = 21;
    pub const SSH_MSG_KEX_ECDH_INIT                             :u8 = 30;
    pub const SSH_MSG_KEX_ECDH_REPLY                            :u8 = 31;
    pub const SSH_MSG_USERAUTH_REQUEST                          :u8 = 50;
    pub const SSH_MSG_USERAUTH_FAILURE                          :u8 = 51;
    pub const SSH_MSG_USERAUTH_SUCCESS                          :u8 = 52;
    pub const SSH_MSG_GLOBAL_REQUEST                            :u8 = 80;
    pub const SSH_MSG_REQUEST_SUCCESS                           :u8 = 81;
    pub const SSH_MSG_REQUEST_FAILURE                           :u8 = 82;
    pub const SSH_MSG_CHANNEL_OPEN                              :u8 = 90;
    pub const SSH_MSG_CHANNEL_OPEN_CONFIRMATION                 :u8 = 91;
    pub const SSH_MSG_CHANNEL_OPEN_FAILURE                      :u8 = 92;
    pub const SSH_MSG_CHANNEL_WINDOW_ADJUST                     :u8 = 93;
    pub const SSH_MSG_CHANNEL_DATA                              :u8 = 94;
    pub const SSH_MSG_CHANNEL_EXTENDED_DATA                     :u8 = 95;
    pub const SSH_MSG_CHANNEL_EOF                               :u8 = 96;
    pub const SSH_MSG_CHANNEL_CLOSE                             :u8 = 97;
    pub const SSH_MSG_CHANNEL_REQUEST                           :u8 = 98;
    pub const SSH_MSG_CHANNEL_SUCCESS                           :u8 = 99;
    pub const SSH_MSG_CHANNEL_FAILURE                           :u8 = 100;
}


#[allow(dead_code)]
pub mod disconnection_message {
    pub const SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT        :u8 = 1;
    pub const SSH_DISCONNECT_PROTOCOL_ERROR                     :u8 = 2;
    pub const SSH_DISCONNECT_KEY_EXCHANGE_FAILED                :u8 = 3;
    pub const SSH_DISCONNECT_RESERVED                           :u8 = 4;
    pub const SSH_DISCONNECT_MAC_ERROR                          :u8 = 5;
    pub const SSH_DISCONNECT_COMPRESSION_ERROR                  :u8 = 6;
    pub const SSH_DISCONNECT_SERVICE_NOT_AVAILABLE              :u8 = 7;
    pub const SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED     :u8 = 8;
    pub const SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE            :u8 = 9;
    pub const SSH_DISCONNECT_CONNECTION_LOST                    :u8 = 10;
    pub const SSH_DISCONNECT_BY_APPLICATION                     :u8 = 11;
    pub const SSH_DISCONNECT_TOO_MANY_CONNECTIONS               :u8 = 12;
    pub const SSH_DISCONNECT_AUTH_CANCELLED_BY_USER             :u8 = 13;
    pub const SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE     :u8 = 14;
    pub const SSH_DISCONNECT_ILLEGAL_USER_NAME                  :u8 = 15;
}


#[allow(dead_code)]
pub mod algorithms {
    pub const DH_CURVE25519_SHA256                              :&'static str = "curve25519-sha256";
    pub const DH_ECDH_SHA2_NISTP256                             :&'static str = "ecdh-sha2-nistp256";

    pub const PUBLIC_KEY_ED25519                                :&'static str = "ssh-ed25519";
    pub const PUBLIC_KEY_RSA                                    :&'static str = "ssh-rsa";

    pub const ENCRYPTION_CHACHA20_POLY1305_OPENSSH              :&'static str = "chacha20-poly1305@openssh.com";

    pub const MAC_ALGORITHMS                                    :&'static str = "none";

    pub const COMPRESSION_ALGORITHMS                            :&'static str = "none";
}