簡體   English   中英

通過Python / Fabric從命令行更改Unix密碼

[英]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運行該命令。

使用sudo管道的另一種方法是使用sudo tee

出於興趣,我必須在一組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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM