繁体   English   中英

“ssh sudo -u user -i”的 subprocess.Popen 失败并显示“sudo:抱歉,你必须有一个 tty 才能运行 sudo”

[英]subprocess.Popen for “ssh sudo -u user -i” is failing with “sudo: sorry, you must have a tty to run sudo”

我想通过 ssh 进入远程服务器,更改用户然后执行脚本。 我正在使用subprocess来执行此操作,但似乎sudo -u userB -i没有更改用户。

HOST = 'remote_server'
USER = 'userA'
CMD = ' whoami; sudo -u userB -i; whoami'

ssh = subprocess.Popen(['ssh', '{}@{}'.format(USER, HOST),CMD],
                            shell=False,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
result = ssh.stdout.readlines()   
if not result:
    err = ssh.stderr.readlines()
    print('ERROR: {}'.format(err))
else:
    print "success"
    print(result) 

$ success
$ ['userA\n', 'userA\n']

当我用CMD ='sudo -u userB -i && whoami'替换时,出现此错误:

错误:['sudo:抱歉,你必须有一个 tty 才能运行 sudo\\n']

在终端上,我可以执行无密码 ssh, sudo -u userB -i && whoami

目标系统上的sudo被配置为需要终端仿真 这样做通常是为了防止您尝试实施的那种自动化。 在尝试绕过该限制之前,请咨询您的服务器管理员。 要么不需要限制,然后管理员可以为您关闭它。 或者限制是有原因的,管理员不会因为您试图绕过它而感到高兴。

可以通过从sudoers文件中删除requiretty选项来关闭限制(默认情况下该选项是关闭的)。


要使ssh对其命令行上提供的命令使用终端仿真,您需要使用-t switch 但是要让-t真正发挥作用,您首先需要从终端运行ssh 由于subprocess.Popen不是终端,您将获得:

不会分配伪终端,因为 stdin 不是终端

要绕过它,您必须使用双-t开关: -tt

将此行插入远程服务器上的/etc/sudoers将解决此问题:

Defaults    !requiretty

我会用一个小的 C 程序来解决这个问题,并给它 suid 权限,即

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// #include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]){
    setuid(0);//su
    char *cmd="/usr/sbin/hddtemp";
    char *arg[]={(char *)"hddtemp",(char *)"--numeric"};
    #define array_size(x) (sizeof(x)/sizeof(*x))
    int size=array_size(arg);
    size_t i,n=size+argc;
    char **args=malloc((n)*sizeof(char*));
    if(args==NULL)return 255;
    for(i=0;i<size;i++){
        args[i]=malloc(strlen(arg[i])+1);
        if(args[i]==NULL)return 255;
        strcpy(args[i],arg[i]);
    }
    for(i=0;i<argc-1;i++){
        args[size+i]=malloc(strlen(argv[i+1])+1);
        if(args[size+i]==NULL)return 255;
        strcpy(args[size+i],argv[i+1]);
    }
    // printf ("total args %2zu\n",i);
    // for(i=0;i<n;i++)printf ("args[%2zu] : %s\n",i,args[i]);
    execv(cmd,args);
    return 1;
}

首先,编译:

gcc -Wall program.c -o program

然后, chown 和 chmod 到

chown 0:userB program
chmod 4750 program

而且,如果您不需要将硬编码参数与传递的参数混合,则可以使用以下命令:

#include <unistd.h>
int main(int argc,char *argv[]){
    setuid(1000); //user id of userB
    char *cmd="/usr/bin/whoami";
    execv(cmd,argv);
    return 1; // indicate error if execv() didn't succeed.
}

通常,每个管理员都会建议您不要向/etc/suders添加例外,并且有充分的理由。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM