Use o exemplo JSch sudo e Channel.setPty para executar o comando sudo no host remoto

Eu usei o exemplo do JSch Sudo sob o seguinte link:

http://www.jcraft.com/jsch/examples/Sudo.java.html

E mudei um pouco e me livrei de todos os diálogos, já que tenho que usá-lo para instâncias do EC2 usando o PuTTY.

Agora meu código se parece com isso:

import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; import java.io.*; public class sudo{ public static void main(String[] arg){ try{ JSch jsch=new JSch(); String host=null; if(arg.length>0){ host=arg[0]; } String privateKey = "my private key.pem"; jsch.addIdentity(privateKey, ""); Session session=jsch.getSession("ec2-user", "xx.xx.xx.xx", 22); session.setPassword(""); java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); String command="sudo mkdir /data"; String sudo_pass=""; Channel channel=session.openChannel("exec"); // man sudo // -S The -S (stdin) option causes sudo to read the password from the // standard input instead of the terminal device. // -p The -p (prompt) option allows you to override the default // password prompt and use a custom one. ((ChannelExec)channel).setCommand("sudo -S -p '' "+command); InputStream in=channel.getInputStream(); OutputStream out=channel.getOutputStream(); ((ChannelExec)channel).setErrStream(System.err); channel.connect(); out.write((sudo_pass+"\n").getBytes()); out.flush(); byte[] tmp=new byte[1024]; while(true){ while(in.available()>0){ int i=in.read(tmp, 0, 1024); if(i<0)break; System.out.print(new String(tmp, 0, i)); } if(channel.isClosed()){ System.out.println("exit-status: "+channel.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } channel.disconnect(); session.disconnect(); } catch(Exception e){ System.out.println(e); } } } 

Mas estou recebendo o erro

desculpe você deve ter um tty para executar o sudo

Eu também tentei usar ((ChannelExec) channel).setPty(true) mas eu posso executar o programa uma vez, mas da próxima vez, para mesma instância EC2, recebo o seguinte erro, mas para a nova instância funciona bem pela primeira vez novamente.

 com.jcraft.jsch.JSchException: Session.connect: java.io.IOException: End of IO Stream Read sudo mkdir /data Exception in thread "main" com.jcraft.jsch.JSchException: session is down at com.jcraft.jsch.Session.openChannel(Session.java:791) 

E então eu também não pude ssh o host remoto da linha de comando também.

Alguém pode por favor me orientar que o que eu preciso fazer para executar o comando sudo no host remoto.

Eu tenho código semelhante em um projeto que estou trabalhando e estava recebendo o mesmo erro. Eu resolvi isso usando o setPty(true) como você fez.

Eu acho que você está recebendo este erro porque você não fecha os streams em seu código. Se você estiver usando o Java 1.7, poderá usar um bloco de resources da seguinte maneira:

 try( InputStream in=channel.getInputStream() ) { try( OutputStream out = channel.getOutputStream() ) { ... } } 

ou o teste … finalmente bloqueia o padrão das versões anteriores.

Depois de definir

 ((ChannelExec) channel).setPty(true) 

o problema relatado no meu código foi resolvido.

Por padrão, o SUDO está configurado para exigir um TTY. Ou seja, espera-se que o SUDO seja executado a partir de um shell de login.

Isso é provavelmente porque seu arquivo / etc / sudoers (ou qualquer arquivo incluído) possui:

 Defaults requiretty 

Mas a opção -S no sudo fará com que ela seja lida a partir da input Padrão.

 -S The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device. The pass- word must be followed by a newline character. 

Jsch explora o mesmo e tenta enviar a senha. Se você quiser que o Jsch funcione sem solicitar a senha, você precisa desativar o requiretty do arquivo sudoers … usando o comando visudo da seguinte forma

 Defaults !requiretty 

ou

 #Defaults requiretty