Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interact on Mac doesn't print what's being typed #48

Open
psymole opened this issue Oct 11, 2022 · 9 comments
Open

Interact on Mac doesn't print what's being typed #48

psymole opened this issue Oct 11, 2022 · 9 comments
Labels
bash question Further information is requested

Comments

@psymole
Copy link

psymole commented Oct 11, 2022

Hi,
I'm trying to use expectrl to interact with a ssh password prompt on macOS (vers 12 if it matters)
everything works but after the ssh session gets initialized the user input is not "printed" on the command line.
Input is being passed to the ssh session, but it is invisible to the user.
Example:

netadmin@CO-90062106: ______________<--- command is not visible

Desktop/
Documents/
Downloads/
Library/
Movies/
Music/
Pictures/
Public/

But it produces the expected return when return is pressed.

This code reproduces the issue

use expectrl::{check, spawn, stream::stdin::Stdin, Error};
use std::io::{stdout, Write};

fn main() {
    let command = format!("ssh netadmin@localhost");
    let password = "123xxx";
    let mut sh = spawn("bash").expect(&format!("Unknown command: {:?}", command));
    writeln!(sh, "{}", command).unwrap();

    println!("Now you're in interacting mode");
    println!("To return control back to main type CTRL-] combination");
    let mut stdin = Stdin::open().expect("Failed to create stdin");

    sh.expect("Password:").unwrap();
    sh.send_line(password).unwrap();

    sh.interact(&mut stdin, stdout())
        .spawn()
        .expect("Failed to start interact");

    stdin.close().expect("Failed to close a stdin");

    println!("we keep dong things");
}
@zhiburt
Copy link
Owner

zhiburt commented Oct 12, 2022

Hi @psymole

Thank you for opening the issue.

I don't have mac unfortunately so it will take me a while to debug.
But it seems to be a known issue.

Which I am not sure why even exists.
It's something with bash, sh etc.

That's said....
I've just noticed on linux it can be fixed by this command; (must work on mac too)
Put it before getting into interact mode.

    sh.send_line("stty echo").unwrap();

Perhaps I need to investigate it further.

ref: #10

@zhiburt zhiburt added question Further information is requested bash labels Oct 12, 2022
@psymole
Copy link
Author

psymole commented Oct 12, 2022

@zhiburt
Thank you for replying so quickly. I genuinely understand that not having a target platform must may debugging more difficult. I'm very new a rust but If there are any tests you'd like me to run I'll give it a go.

Your suggestion worked when I placed it before running SSH. Thanks a lot.

For what it is worth, I didn't see the issue on my Ubuntu 22.04 test machine. I can spawn bash and then ssh. Or ssh directly, and in both cases the user's input is visible.

A couple of questions if you don't mind.

  1. Can you think of a work a round that would work if I spawn ssh directly?
    2 If I need to spawn bash and then call ssh, Is there a way of terminating both processes when a user types "exit"?

Again thanks for all the help.

@zhiburt
Copy link
Owner

zhiburt commented Oct 12, 2022

For what it is worth, I didn't see the issue on my Ubuntu 22.04 test machine. I can spawn bash and then ssh. Or ssh directly, and in both cases the user's input is visible.

Really?
Interesting, because on my machine it doesn't work as well 😅.
Could you check out bash version (bash --version)?

Can you think of a work a round that would work if I spawn ssh directly?

But doesn't it work if you would call spawn("ssh netadmin@localhost")

If I need to spawn bash and then call ssh, Is there a way of terminating both processes when a user types "exit"?

I bet it could be possible somehow through bash using exec for example. (not an expert here).

But sticking to your snippet you can just call sh.exit(true) after interact is finished it will stop the bash session.

@psymole
Copy link
Author

psymole commented Oct 12, 2022

Thanks!
Let me try to clarify a bit.
On Linux.
This works fine. (I get ssh in, and I can see what I type)

fn main() {
    println!("Hello, world!");
    let password = "thepassword.";
    let command = format!("ssh admin@localhost");
    let mut sh = spawn(&command).expect(&format!("Unknown command: {:?}", command));

    println!("Now you're in interacting mode");
    println!("To return control back to main type CTRL-] combination");

    let mut stdin = Stdin::open().expect("Failed to create stdin");
    sh.expect("password:").unwrap();
    sh.send_line(password).unwrap();

    sh.interact(&mut stdin, stdout())
        .spawn()
        .expect("Failedsd to start interact");

    stdin.close().expect("Failed to close a stdin");

    println!("we keep dong things");
}

bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
---------Distro-----------
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04

If I run the previous snippet on a Mac; I get SSH, but I cannot see what I type.
To work around that on the mac, I tried it (spawning bash first) like this.

fn main() {
    println!("Hello, world!");
    let password = "thepassword.";
    let command = format!("ssh netadmin@localhost");
    
    // Mac---v
    let mut sh = spawn("bash").expect(&format!("Unknown command: {:?}", command));
    writeln!(sh, "{}", command).unwrap();
    
    println!("Now you're in interacting mode");
    println!("To return control back to main type CTRL-] combination");

    let mut stdin = Stdin::open().expect("Failed to create stdin");
    sh.expect("password:").unwrap();
    sh.send_line(password).unwrap();

    sh.interact(&mut stdin, stdout())
        .spawn()
        .expect("Failedsd to start interact");

    stdin.close().expect("Failed to close a stdin");

    println!("we keep dong things");
}

But it still didn't work until I added your "workaround"

.
.
.
    // Mac---v
    let mut sh = spawn("bash").expect(&format!("Unknown command: {:?}", command));
    
    // Work around
    sh.send_line("stty echo").unwrap();
    // end workaround.
    
    writeln!(sh, "{}", command).unwrap();
    
    println!("Now you're in interacting mode");
    .
    .

Trying to spawn("ssh admin@localhost") on the mac always produces the same issue. Can't see what I type.

macOS 12
bash --version
GNU bash, version 5.2.2(1)-release (x86_64-apple-darwin21.6.0) <-- from macbrew
Zsh on the mac with the same issues.

Thanks

@psymole
Copy link
Author

psymole commented Oct 12, 2022

But sticking to your snippet you can just call sh.exit(true) after interact is finished it will stop the bash session.

Interact won't finish until I stop the bash session that I spawned, Correct?

Rust main > Spawn bash session (interact) > Spawn SSH session.
------------------------------------------------- ^ (I want to go back to Rust main when the SSH session ends.)

@zhiburt
Copy link
Owner

zhiburt commented Oct 13, 2022

Interact won't finish until I stop the bash session that I spawned, Correct?

Rust main > Spawn bash session (interact) > Spawn SSH session.
------------------------------------------------- ^ (I want to go back to Rust main when the SSH session ends.)

Now I see what the issue is.

I guess it can be done in may ways.
The one I picture is.

    let mut sh = spawn("bash").expect(&format!("Unknown command: {:?}", command));
    writeln!(sh, "exec {}", command).unwrap();

@zhiburt
Copy link
Owner

zhiburt commented Oct 13, 2022

On Linux.
This works fine. (I get ssh in, and I can see what I type)

That's interesting.
Could you try to run this snippet? (On my machine it doesn't prints back. The same version of bash)

use std::io::stdout;

use expectrl::{spawn, stream::stdin::Stdin};

fn main() {
    let mut sh = spawn("bash").unwrap();

    sh.send_line("echo Hello World").unwrap();
    sh.expect("Hello World").unwrap();

    let mut stdin = Stdin::open().expect("Failed to create stdin");
    sh.interact(&mut stdin, stdout())
        .spawn()
        .expect("Failedsd to start interact");

    stdin.close().expect("Failed to close a stdin");

    println!("Done");
}

@psymole
Copy link
Author

psymole commented Oct 13, 2022

Hey ran the snippet on my Ubutnu 22.04 vm, and it worked fine, no problem printing back.
please let me know if you think it would help running it on bare metal.

Screen Shot 2022-10-13 at 12 22 30 PM

@zhiburt
Copy link
Owner

zhiburt commented Oct 13, 2022

Hey ran the snippet on my Ubutnu 22.04 vm, and it worked fine, no problem printing back.
please let me know if you think it would help running it on bare metal.

Thank you
That's interesting cause as I said on my machine it doesn't.

Could you try a different terminal? (like alacritty)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bash question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants