jester47 has asked for the wisdom of the Perl Monks concerning the following question:

I am able to log in to the remote host via putty and using my account I am able to 'sudo su' without a problem. However when I try to do it using my code it errors out with "PROCESS_MUX_NEW_SESSION: tcgetattr: Inappropriate ioctl for device" message. I have been able to get the code to work with Net::Expect but I would like to avoid using expect in this context. The ssh connection establishes without a problem, and the scp works well.

The code works through a series of hosts listed in a file, and for each host available it SCPs a file to that host, and then runs a script that requires elevated privileges and uses the information in the file that was SCPed.

So two things to look at here:

1. Is my code for executing the sudo command correct? Am I missing something specific to OpenSSH?

2. I have seen it suggested in many places that "ssh -t" be used. However I have not found how to designate the -t in the Net::OpenSSH->new operators. How would one do this?

The "sudo" block is pretty much a cut and paste from the CPAN OpenSSH documentation. Things I have tried in the "sudo" block:

Removed the STDIN entry, removed the prompt modificaitons, with and without the STDIN, tried it as a straight "sudo su" command. Suggestions appreciated...

Here is my code. There may be some typos, and if it looks like a variable is missing, it will be because I tried to take out all the "trash" variables that no longer have any meaning and various print statements that help follow the flow when running. The names are changed to protect the guilty:

#!/usr/bin/perl use strict; use warnings; use DateTime; #for some functionality that will come later. use Net::OpenSSH; my $cur_ip; my $cur_name; my $user = "deryoosername"; my $pass = "derpassverden"; my $sudo_pass = "dersoodoopass"; my $target_file = "target-ip-name.txt"; open (TARLIST, $target_file) or die "Can't open file: $!"; while (<TARLIST>) { chomp; ($cur_ip, $cur_name) = split /\t/; $cur_name =~ s/[\s]+//g; print "$cur_ip\t"; print "$cur_name\n"; my $ssh = Net::OpenSSH->new($cur_ip, user=>$user, password=> +$pass, timeout=>2); next if $ssh_error and print "Can't SSH to host $cur_name\n" + . $ssh->error . "\n"; my $remotepath = "/Pathto/remote/new.filename"; my $localpath = "/localdir/fileto.move $ssh->scp_put($localpath, $remotepath); my $file_list = $ssh->capture("ls -l"); print "$file_list\n"; my @sudo_out = $ssh->capture({stdin_data => "$sudo_pass\n"}, 'sudo', '-Sk', '-p', '', '--', 'su'); } close TARLIST;
  • Comment on Sudo with Net::OpenSSH fails with PROCESS_MUX_NEW_SESSION: tcgetattr: Inappropriate ioctl for device
  • Download Code

Replies are listed 'Best First'.
Re: Sudo with Net::OpenSSH fails with PROCESS_MUX_NEW_SESSION: tcgetattr: Inappropriate ioctl for device
by salva (Canon) on Apr 23, 2015 at 08:00 UTC
    The way to get a get a tty attached to the remote process is to pass tty => 1 when calling Net::OpenSSH methods. For instance:
    my $file_list = $ssh->capture({tty => 1}, "ls -l");
    In any case, interacting with sudo is almost an art. There are too many different versions with different capabilities still in use, and then, there were several (minor) bugs related to tty handling on OpenSSH client that have been fixed only on recent releases.

    In the end, the only approach that is guaranteed to works in all the cases is using Expect, because you have a tty in both sides (ssh handles that without issues) and you are not using new and fancy sudo features. The downside is that using Expect is a PITA.

    In summary, read the documentation for the version of sudo installed on the remote machine. Check if all the flags used by the sample code are available. Try doing it from the command line. Also, try asking Net::OpenSSH/ssh to allocate a tty on the remote side. If everything fails, go for Expect (but combined with Net::OpenSSH as explained in the docs, don't use Net::SSH::Expect that is quite buggy!).

    Net::OpenSSH also has a debugging mode that could give you some hint about what is going wrong:

    $Net::OpenSSH::debug = -1;