Utilice JSch sudo example y Channel.setPty para ejecutar el comando sudo en el host remoto

He usado el ejemplo de JSch Sudo en el siguiente enlace:

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

Y lo cambié un poco y me deshice de todos los diálogos ya que tengo que usarlo para instancias EC2 que usan PuTTY.

Ahora mi código se ve así:

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); } } } 

Pero estoy obteniendo el error

lo siento, debes tener un tty para ejecutar sudo

También traté de usar ((ChannelExec) channel).setPty(true) pero puedo ejecutar el progtwig una vez, pero la próxima vez, para la misma instancia EC2, obtengo el siguiente error pero para la nueva instancia funciona bien por primera vez.

 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) 

Y luego tampoco pude desconectar el host remoto desde la línea de comandos también.

¿Puede alguien por favor guiarme que lo que tengo que hacer para ejecutar el comando sudo en el host remoto.

Tengo un código similar en un proyecto en el que estoy trabajando y recibía el mismo error. setPty(true) esto usando setPty(true) como lo hiciste.

Creo que recibes este error porque no cierras las transmisiones en tu código. Si está utilizando Java 1.7, puede usar un bloque de recursos de la siguiente manera:

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

o el bash … finalmente bloquea el patrón de las versiones anteriores.

Después de la configuración

 ((ChannelExec) channel).setPty(true) 

el problema informado tiene en mi código resuelto.

De manera predeterminada, SUDO está configurado para requerir un TTY. Es decir, se espera que SUDO se ejecute desde un shell de inicio de sesión.

Eso es probablemente porque su archivo / etc / sudoers (o cualquier archivo que incluye) tiene:

 Defaults requiretty 

Pero la opción -S en sudo lo hará leer desde la entrada Estándar.

 -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 explota lo mismo e intenta enviar la contraseña. Si desea que Jsch funcione sin solicitar la contraseña, debe deshabilitar el requiretty del archivo sudoers … usando el comando visudo de la siguiente manera

 Defaults !requiretty 

o

 #Defaults requiretty