I recently posted about running SSH with sub-processes. I was pleased by the problem being solved on the first reply. While waiting for that reply it occurred to me I should probably be using an ssh crate that should prevent forking if lots of connections are spawned. I tried multiple versions of the ssh and ssh2 crates and their documentation failed for me every time. My latest try was with the example from ssh2 - Rust with the example "Run a command". I put the following in a main function like this:
fn main(){
use std::io::prelude::*;
use std::net::{TcpStream};
use ssh2::Session;
// Connect to the local SSH server
let tcp = TcpStream::connect("192.168.x.x:22").unwrap();
let sess = Session::new().unwrap();
sess.handshake(&tcp).unwrap();
sess.userauth_agent("user").unwrap();
let mut channel = sess.channel_session().unwrap();
channel.exec("ls").unwrap();
let mut s = String::new();
channel.read_to_string(&mut s).unwrap();
println!("{}", s);
println!("{}", channel.exit_status().unwrap());
}
Under the dependencies of the Cargo.toml file put the following to match what was on the documentation: ssh2 = "0.3.1"
It compiles without error, but I got the following on runtime:
$ ./target/release/ssh
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -7, msg: "Unable to send channel-open request" }', src/main.rs:13:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I tried setting the RUST_BACKTRACE variable, but got no new information. I confirmed I can login without a password to the destination machine. Both source and destination are Linux devices if that matter. I tried ssh 0.1.4, ssh2 0.8 and ssh2 0.8.2 with their documentation as well, but couldn't get any of them to work without error after error. If anyone could point me to documentation that works, or know what I'm doing wrong I'd greatly appreciate it.
Those docs are from a very old version of ssh2. Can you try the latest version, 0.8.2?
Very good point I overlooked. I should have lead with my tries from the newest version. I'm currently sick, awaiting a Covid test and pumped full of medicine. So I'm gonna blame it on that.
Here's the link I'm using from ssh2 - Rust under the "Run The Command" section looks like the following in my main function:
fn main() {
use std::io::prelude::*;
use std::net::{TcpStream};
use ssh2::Session;
// Connect to the local SSH server
let tcp = TcpStream::connect("192.168.x.x:22").unwrap();
let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_agent("user").unwrap();
let mut channel = sess.channel_session().unwrap();
channel.exec("ls").unwrap();
let mut s = String::new();
channel.read_to_string(&mut s).unwrap();
println!("{}", s);
channel.wait_close();
println!("{}", channel.exit_status().unwrap());
}
This version compiles, but gives the following warning:
warning: unused `std::result::Result` that must be used
--> src/main.rs:18:1
|
18 | channel.wait_close();
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: this `Result` may be an `Err` variant, which should be handled
Finished release [optimized] target(s) in 2m 16s
When attempting to run it I get the following:
$ ./target/release/ssh2
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -39, msg: "no auth sock variable" }', src/main.rs:11:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I'm unsure if it was overlooked, but I confirmed I can login without a password from the source to the destination machine. I was also able to eventually get this going with a subprocess in this thread without hard-coding the path to the key. If you do think its needed I don't mind trying it if you'll show me where that should go in the code. Just wanted to make sure nothing was overlooked though.
Based on your error message looks like this is where you are ignoring a result. How to fix it depends on how you want to treat errors. .unwrap() would trigger the unhelpful message you've already seen in case of error. .ok() would ignore any errors. You could alternatively (and ideally) report on what went wrong in case of error.
Okay, I tried adding the unwrap() function to the line you referred to like this:
channel.wait_close().unwrap();
I did notice there were not compiler warnings this time, but this was the output when ran:
$ ./target/release/ssh2
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -39, msg: "no auth sock variable" }', src/main.rs:13:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I couldn't seem to find any information only related to code -39, so I'm kind of in the same place I guess. Any further suggestions?
This does not necessarily mean that ssh-agent is configured and running. It might just mean that your identity key has no password. If you don't have $SSH_AUTH_SOCK in your shell's environment, then try running your program under ssh-agent explicitly, for example:
Well, now I think we're on to something! I ran ssh-agent with cargo as instructed, which I had never seen used before. It produced the following:
$ ssh-agent cargo run
Compiling cc v1.0.58
Compiling pkg-config v0.3.18
Compiling libc v0.2.74
Compiling autocfg v1.0.0
Compiling cfg-if v0.1.10
Compiling scopeguard v1.1.0
Compiling bitflags v1.2.1
Compiling smallvec v1.4.1
Compiling lock_api v0.3.4
Compiling openssl-sys v0.9.58
Compiling libz-sys v1.0.25
Compiling libssh2-sys v0.2.18
Compiling parking_lot_core v0.7.2
Compiling parking_lot v0.10.2
Compiling ssh2 v0.8.2
Compiling ssh2 v0.1.0 (/home/user/rust/ssh2)
Finished dev [unoptimized + debuginfo] target(s) in 54.05s
Running `target/debug/ssh2`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -34, msg: "no identities found in the ssh agent" }', src/main.rs:13:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
root@anger:/home/user/rust/ssh2# error: could not find `Cargo.toml` in `/home/ph33r/rust` or any parent directory
bash: Cargo.toml: command not found
bash: /home/user/rust: Is a directory
bash: error:: command not found
I checked and $SSH_AUTH_SOCK is an empty/non-existent variable on both systems.
Okay, I got excited before googling last time. I looked around and found these instructions while searching for setting the $SSH_AUTH_SOCK variable, which I assume are correct:
eval `ssh-agent -s`
ssh-add
After that I was able to get the code to run correctly. I guess I'll call these commands in a sub-process.