Изменить пароль Unix из командной строки через 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
,
Какую команду можно использовать для изменения пароля пользователя в Ubuntu 10.4 через fabric
?
РЕДАКТИРОВАТЬ: я посмотрел на 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")
Это не очень элегантное решение, но оно работает.
Спасибо за чтение.
Брайан
4 ответа
Вы можете ввести новые и старые пароли в passwd
с помощью echo
например
echo -e "oldpass\\nnewpass\\nnewpass" | passwd
(-e
вариант для echo
разрешает интерпретацию обратной косой черты, поэтому переводы строки интерпретируются как таковые)
Хитрость заключается в использовании комбинации usermod
и питона 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)
Я использую chpasswd на Ubuntu 11.04
fabric.api.sudo('echo %s:%s | chpasswd' % (user, pass))
Примечание. Обычно этот шаблон не работает:
$ sudo echo bla | restricted_command
потому что только "echo" получает повышенные привилегии, а не "limited_command".
Однако здесь это работает, потому что, когда fabric.api.sudo вызывается с shell=True (по умолчанию), fabric собирает команду следующим образом:
$ sudo -S -p <sudo_prompt> /bin/bash -l -c "<command>"
sudo создает новую оболочку (/bin/bash), работающую с правами root, а затем эта расширенная оболочка запускает команду.
Другой способ создания sudo - использовать sudo tee:
Из-за интереса я должен выполнить аналогичную задачу для набора ящиков Solaris (добавить много пользователей, установить их пароль). В пользовательском модуле Solaris нет опции --password, поэтому в прошлом я использовал Expect для этого, но написание сценариев Expect может быть болезненным.
Так что в этот раз я собираюсь использовать crypt.crypt в Python, редактировать / etc / shadow напрямую (с резервными копиями, конечно). http://docs.python.org/release/2.6.1/library/crypt.html
Комментаторы предложили использовать различные заклинания эха, переданные в passwd. На самом деле, это никогда не сработает, так как 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://stackru.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)