【问题标题】:Jsch and sudo commandJsch 和 sudo 命令
【发布时间】:2017-09-14 00:45:18
【问题描述】:

我正在尝试自动化一些操作,其中一项操作是切换到远程 Linux 机器上的技术用户。该过程如下所示:使用“普通”用户登录,然后切换

sudo /bin/rootsh -i -u techUser

给技术用户。

这是我正在处理的 Groovy 代码示例:

import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session
import com.jcraft.jsch.Channel
import com.jcraft.jsch.ChannelExec
import com.jcraft.jsch.JSchException

class Main {
    static void main(String[] args) {
        int responseCode = 0
        String responseText = ""
        def targetHost = "targetHost"
        def targetUser = "targetUser"
        def technicalUser= "technicalUser"
        def targetPass = "targetPass"
        def targetPort = 22
        Properties configConnection = new Properties()
        configConnection.put("StrictHostKeyChecking", "no")
        configConnection.put("PreferredAuthentications", "publickey,keyboard-interactive,password")
        JSch jsch = new JSch()
        try {
            Session targetSession = jsch.getSession(targetUser, targetHost, targetPort)
            targetSession.setPassword(targetPass)
            targetSession.setConfig(configConnection)
            targetSession.connect()
            Channel channel = targetSession.openChannel("exec")
            ((ChannelExec) channel).setCommand("echo 'targetPass' | sudo -S -p /bin/rootsh -i -u technicalUser")
            ((ChannelExec) channel).setPty(true)
            final ByteArrayOutputStream baos = new ByteArrayOutputStream()
            ((ChannelExec) channel).setErrStream(baos)
            channel.setInputStream(null)
            InputStream is = channel.getInputStream()
            channel.connect()
            byte[] tmp = new byte[1024]
            while (true) {
                while (is.available() > 0) {
                    int i = is.read(tmp, 0, 1024)
                    if (i < 0)
                        break
                    responseText = new String(tmp, 0, i)
                }
                if (channel.isClosed()) {
                    responseText = new String(baos.toByteArray())
                    responseCode = channel.getExitStatus()
                    break
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                    println("[ERROR] " + ee.getMessage())
                }
            }
            channel.disconnect()
            targetSession.disconnect()
            println("RESULT:  code: " + responseCode + ", text: \"" + responseText + "\"")
        } catch (JSchException e) {
            println("[ERROR] Exception, problem with connection: " + e.getMessage())
        }
    }
}

结果是:

RESULT:  code: 1, text: ""

当我设置为

((ChannelExec) channel).setPty(false)

结果是:

RESULT:  code: 1, text: "/bin/rootshSorry, user targetUser is not allowed to execute '/bin/bash' as technicalUser on targetHost."

当我从以下行中删除密码时:

((ChannelExec) channel).setCommand("echo '' | sudo -S -p /bin/rootsh -i -u technichalUser")

结果是:

RESULT:  code: 1, text: "/bin/rootsh/bin/rootsh
Sorry, try again.
/bin/rootsh
/bin/rootsh
sudo: pam_authenticate: Authentication information cannot be recovered"

当我设置以下命令时:

((ChannelExec) channel).setCommand("sudo -S -p /bin/rootsh -i -u technichalUser")

进程一直在运行,根本没有响应(进程可能正在等待密码)

如果有人已经解决了这样的问题或类似的问题,我真的很感激任何帮助。

【问题讨论】:

    标签: linux groovy sudo jsch


    【解决方案1】:

    你不能通过输入重定向将密码传递给sudo,至少在默认配置下是这样。

    因此,这是行不通的:

    echo 'targetPass' | sudo -S -p /bin/rootsh -i -u technicalUser` 
    

    您甚至在交互式终端中尝试过吗?我想它也不会在那里工作。


    您必须将密码写入通道输入流(在 JSch 中称为“输出流”)。

    见官方JSch Sudo example

    您可能需要启用 TTY/PTY。见Use JSch sudo example and Channel.setPty for running sudo command on remote host

    【讨论】:

    • 非常感谢您的全面解释。该项目已被取消,因此我没有继续对这个问题进行调查。我想您提供的提示会对我有所帮助,这就是为什么我将您的答案标记为解决此问题的原因。我希望您的提示对其他用户有所帮助。