在脚本中通过`subprocess.POPEN`将密码传递给KLOG
我正在写的一系列应用程序需要用户能够通过 KLOG 认证来读取文件系统。有些功能要求用户必须有 KLOG 令牌(也就是需要认证),而有些则不需要。我写了一个简单的 Python 装饰器,这样我就可以在我的模块中整理“你必须 KLOG 认证”的功能。
# this decorator is defined in ``mymodule.utils.decorators``
def require_klog(method):
def require_klog_wrapper(*args, **kwargs):
# run the ``tokens`` program to see if we have KLOG tokens
out = subprocess.Popen('tokens', stdout=subprocess.PIPE)
# the tokens (if any) are located in lines 4:n-1
tokens_list = out.stdout.readlines()[3:-1]
if tokens_list == []:
# this is where I launch KLOG (if the user is not authenticated)
subprocess.Popen('klog')
out = method(*args, **kwargs)
return out
return require_klog_wrapper
# once the decorator is defined, any function can use it as follows:
from mymodule.utils.decorators import require_klog
@require_klog
def my_function():
# do something (if not KLOGed, it SHUOLD ask for the password... but it does not!)
这其实很简单。问题出在我尝试应用以下逻辑时:“如果用户没有 KLOG 认证,就运行 KLOG 并询问密码”。
我使用 subprocess.Popen('klog')
来实现这个功能,终端确实会弹出输入密码的提示。但是,当我输入密码时,密码会在终端上显示出来,更糟糕的是,按下回车后什么也没有发生。
编辑:
在 Alex 快速且正确的回应后,我解决了这个问题,步骤如下:
- 我删除了模块目录下所有的
*.pyc
文件(是的,这确实有影响) - 我使用
getpass.getpass()
来把密码存储在一个本地变量中 - 我用
-pipe
选项调用 KLOG 命令 - 我通过管道的
write
方法将本地存储的密码传递给管道
下面是修正后的装饰器:
def require_klog(method):
def require_klog_wrapper(*args, **kwargs):
# run the ``tokens`` program to see if we have KLOG tokens
out = subprocess.Popen('tokens', stdout=subprocess.PIPE)
# the tokens (if any) are located in lines 4:n-1
tokens_list = out.stdout.readlines()[3:-1]
if tokens_list == []:
args = ['klog', '-pipe']
# this is the custom pwd prompt
pwd = getpass.getpass('Type in your AFS password: ')
pipe = subprocess.Popen(args, stdin=subprocess.PIPE)
# here is where the password is sent to the program
pipe.stdin.write(pwd)
return method(*args, **kwargs)
return require_klog_wrapper
1 个回答
2
看起来,你的脚本(或者它后面启动的其他东西)和运行 klog
的子进程在争抢 /dev/tty
这个资源,而子进程输掉了这场竞争(毕竟,你没有调用从 subprocess.Popen
返回的对象的 wait
方法,这样就无法确保在继续之前等它结束,所以出现某种竞争条件也不奇怪)。
如果 wait
不够用,我会通过在 Python 代码中加入
pwd = getpass.getpass('password:')
(当然,最上面要有 import getpass
),然后用 -pipe
参数运行 klog
,并设置 stdin=subprocess.PIPE
,接着把 pwd
写入这个管道(通过调用从 subprocess.Popen
返回的对象的 communicate 方法)。