[英]Python fabric passing root password as command line argument doesn't work
[英]Change Unix password from command line over Python/Fabric
我想在遠程Ubuntu 10.4
盒子上用面料更新我的密碼。
我希望我的fabfile.py
看起來像這樣:
def update_password(old_pw, new_pw):
# Connects over ssh with a public key authentication
run("some_passwd_cmd --old %s --new %s" % (old_pw, new_pd))
不幸的是,我知道的唯一命令是讓密碼更改為passwd
,而在Ubuntu 10.4上似乎沒有任何方法可以將新(或舊)密碼作為passwd
的參數傳遞。
可以使用什么命令通過fabric
在Ubuntu 10.4上更改用戶密碼?
編輯 :我已經看過usermod -p
,這可能會有效,但手冊頁不建議這樣做。
編輯 :由於某種原因, usermod -p
無法通過結構工作。
同樣,我嘗試了一個(有點不安全)mikej的答案,確實解決了這個問題:
# connecting & running as root.
from fabric.api import *
from fabric.contrib import files
files.append("%s\n%s" % (passwd, passwd), '.pw.tmp')
# .pw.tmp:
# PASSWD
# PASSWD
run("passwd %s < .pw.tmp" % user)
run("rm .pw.tmp")
這不是一個非常優雅的解決方案,但它的工作原理。
謝謝你的閱讀。
布賴恩
您可以使用echo
例如將新密碼和舊密碼提供給passwd
echo -e "oldpass\\nnewpass\\nnewpass" | passwd
( echo
的-e
選項可以解釋反斜杠轉義,因此換行符被解釋為這樣)
訣竅是使用usermod
和Python的crypt
組合來更改密碼:
from crypt import crypt
from getpass import getpass
from fabric.api import *
def change_password(user):
password = getpass('Enter a new password for user %s:' % user)
crypted_password = crypt(password, 'salt')
sudo('usermod --password %s %s' % (crypted_password, user), pty=False)
我在Ubuntu 11.04上使用chpasswd
fabric.api.sudo('echo %s:%s | chpasswd' % (user, pass))
注意:通常此模式不起作用:
$ sudo echo bla | restricted_command
因為只有'echo'獲得了提升權限,而不是'restricted_command'。
但是,這里有效,因為當fabric.api.sudo使用shell = True(默認值)進行caled時,fabric會像這樣組裝命令:
$ sudo -S -p <sudo_prompt> /bin/bash -l -c "<command>"
sudo生成一個新的shell(/ bin / bash),以root權限運行,然后該升級的shell運行該命令。
出於興趣,我必須在一組Solaris機器上執行類似的任務(添加大量用戶,設置其密碼)。 Solaris usermod沒有--password選項,所以在過去我使用Expect來做這件事,但編寫Expect腳本可能很痛苦。
所以這次我要使用Python的crypt.crypt,直接編輯/ etc / shadow(當然還有備份)。 http://docs.python.org/release/2.6.1/library/crypt.html
評論者建議使用管道傳輸的各種回聲咒語。 AFAIK這將永遠不會工作,因為passwd被編程為忽略來自stdin的輸入並且僅接受來自交互式tty的輸入。 見http://en.wikipedia.org/wiki/Expect
我對其他方法沒有運氣。 以為我會分享我用於一次性一次性拋棄腳本的方法。
它使用自動應答器在提示符下鍵入密碼。 然后我立即使所有密碼到期,以便用戶有機會選擇自己的密碼。
這不是最安全的方法,但根據您的使用情況,它可能很有用。
from collections import namedtuple
from getpass import getpass
import hashlib
from invoke import Responder
import uuid
from fabric import Connection, Config
User = namedtuple('UserRecord', ('name', 'password'))
def set_passwords(conn, user):
print(f'Setting password for user, {user.name}')
responder = Responder(
pattern=r'(?:Enter|Retype) new UNIX password:',
response=f'{user.password}\n',
)
result = conn.sudo(f'passwd {user.name}', warn=True, hide='both',
user='root', pty=True, watchers = [responder])
if result.exited is not 0:
print(f'Error, could not set password for user, "{user.name}". command: '
f'{result.command}; exit code: {result.exited}; stderr: '
f'{result.stderr}')
else:
print(f'Successfully set password for {user.name}')
def expire_passwords(conn, user):
print(f'Expiring password for user, {user.name}')
cmd = f'passwd --expire {user.name}'
result = conn.sudo(cmd, warn=True, user='root')
if result.exited is not 0:
print(f'Error, could not expire password for user, "{user.name}". '
f'command: {result.command}; exit code: {result.exited}; stderr: '
f'{result.stderr}')
else:
print(f'Successfully expired password for {user.name}')
def gen_password(seed_string):
# Don't roll your own crypto. This is for demonstration only and it is
# expected to only create a temporary password that requires changing upon
# initial login. I am no cryptography expert, hence this alternative
# simplified answer to the one that uses crypt, salt, etc -
# https://stackoverflow.com/a/5137688/1782641.
seed_str_enc = seed_string.encode(encoding='UTF-8')
uuid_obj = uuid.UUID(int=int(hashlib.md5(seed_str_enc).hexdigest(), 16))
return str(uuid_obj)[:8]
def some_function_that_returns_something_secret(conn):
return f'dummy-seed-{conn}'
sudo_pass = getpass('Enter your sudo password:')
config = Config(overrides={'sudo': {'password': sudo_pass}})
with Connection('vm', config=config) as vm_conn:
print(f'Making a new connection to {vm_conn.host}.')
# I usually use the sudo connection here to run a command that returns a
# reproducible string that only the sudo user could get access to be used
# for user_record.password bellow. Proceed with caution, this is not a
# recommended approach
seed = some_function_that_returns_something_secret(vm_conn)
user_record = User(name='linux_user', password=gen_password(seed))
set_passwords(vm_conn, user_record)
expire_passwords(vm_conn, user_record)
print(f'Done! Disconnecting from {vm_conn.host}.')
# So that you know the temporary password, print user_record or save to file
# `ssh linux_user@vm` and it should insist that you change password
print(user_record)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.