Как установить пароль при первом вызове команды от paramiko?

1

У меня есть один пользовательский test.

Я устанавливаю смену пароля при входе пользователя в систему с помощью команды chage.

chage -E 2012-01-25 -M 30 -d 0 -W 10 -I 5 test

Поэтому, когда я пытаюсь запустить команду ls

[root@localhost ~]# ssh test@localhost "ls"
WARNING: Your password has expired.
Password change required but no TTY available.
You have new mail in /var/spool/mail/root

Затем я пытаюсь подключиться к ssh

[root@localhost ~]# ssh test@localhost
You are required to change your password immediately (root enforced)
Last login: Tue Dec 27 09:55:55 2011 from localhost
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user test.
Changing password for test.
(current) UNIX password: 

И чем я могу установить пароль для пользователя.

Если я попытаюсь подключить их к paramiko.

In [1]: import paramiko

In [2]: ssh_conn = paramiko.SSHClient()

In [3]: ssh_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())

In [4]: ssh_conn.load_system_host_keys()

In [5]: ssh_conn.connect('n2001', username='root_acc23', password='test')

In [6]: a = ssh_conn.exec_command('ls')

In [7]: print a[2].read()
WARNING: Your password has expired.
Password change required but no TTY available.

Затем я делаю некоторые google и нахожу какое-то решение для установки нового пароля с помощью invoke_shell show. Я написал одну функцию

def chage_password_change(ssh_conn, password, curr_pass):
   '''
   If got error on login then set with interactive mode.
   '''
   interact = ssh_conn.invoke_shell()
   buff = ''
   while not buff.endswith('UNIX password: '):
       resp = interact.recv(9999)
       buff += resp
   interact.send(curr_pass + '\n')

   buff = ''
   while not buff.endswith('New password: '):
       resp = interact.recv(9999)
       buff += resp

   interact.send(password + '\n')

   buff = ''
   while not buff.endswith('Retype new password: '):
       resp = interact.recv(9999)
       buff += resp

   interact.send(password + '\n')


   interact.shutdown(2)
   if interact.exit_status_ready():
       print "EXIT :", interact.recv_exit_status()

   print "Last Password"
   print "LST :", interact.recv(-1)

Это работает в некоторых случаях, например, когда мы вводим правильный пароль с цифрами, alpa и специальной комбинацией символов.

Но когда мы вводим короткий пароль или ошибку в изменении пароля, как это

[root@localhost ~]# ssh test@localhost
You are required to change your password immediately (root enforced)
Last login: Tue Dec 27 10:41:15 2011 from localhost
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user test.
Changing password for test.
(current) UNIX password: 
New password: 
Retype new password: 
BAD PASSWORD: it is too short

В этой команде мы получили ошибку BAD PASSWORD: она слишком короткая. Это я не могу определить в своей функции. Я получаю эту ошибку, когда я interact.recv(-1) но это, как мне кажется, это stdout. Итак, есть ли способ определить, что это ошибка.

Я проверяю paramiko doc и обнаруживаю, что класс Channel имеет некоторый метод recv_stderr_ready и recv_stderr но эта ошибка не входит в эти данные.

спасибо за вашу помощь заранее.

Теги:
paramiko
change-password

3 ответа

3
Лучший ответ

Легкий ответ заключается в том, чтобы ваша функция проверяла длину пароля ДО того, как вы вызываете свою оболочку, если вы знаете, что такое отсечка. Лучшая производительность. Но если вы не знаете обреза, это не сработает.

Я не понимаю вашего описания, но если сообщение BAD PASSWORD возвращается из interactive.recv(-1), то вы знаете, что это произошло, и можете действовать соответствующим образом. Кажется, что он должен возвращаться из std err или stdout, поэтому проверьте оба. Если вы знаете, какой текст возвращается, если новый пароль был принят, вы также можете проверить это; в зависимости от того, что вы получите, сначала расскажет вам, что произошло, и ваша функция может продолжаться оттуда.

  • 2
    Спасибо @ScottHunter за ваш ответ. Я знаю, что ошибка может быть 2-3 возможных слова. Я хочу поднять ошибку, если я получаю вывод в stderr без проверки stdout. Если я должен проверить stdout и stderr на наличие ошибок, то я должен проверять каждый раз в stdout.
  • 0
    К сожалению, если stdout находится там, где пишется сообщение об ошибке, вы должны прочитать его. Сожалею.
Показать ещё 1 комментарий
1

Следующие строки могут быть проблематичными и могут вызвать некоторые ошибки:

while not buff.endswith('Retype new password: '):
      resp = interact.recv(9999)
      buff += resp // this will append the output from the shell 

исправление кода:

лучше использовать его таким образом

while not buff.endswith('Retype new password: '):
     resp = interact.recv(9999)
     buff = resp

теперь каждая итерация цикла будет анализировать текущий\обновленный, выводимый текст из оболочки.

С уважением, Эльдад

0

это также может сработать, если вы ищете метод смены пароля с истекшим сроком действия. (питон 3)

import time
from contextlib import closing
import paramiko

def wait_until_channel_endswith(channel, endswith, wait_in_seconds=15):
    """Continues execution if the specified string appears at the end of the channel

    Raises: TimeoutError if string cannot be found on the channel
    """

    timeout = time.time() + wait_in_seconds
    read_buffer = b''
    while not read_buffer.endswith(endswith):
        if channel.recv_ready():
           read_buffer += channel.recv(4096)
        elif time.time() > timeout:
            raise TimeoutError(f"Timeout while waiting for '{endswith}' on the channel")
        else:
            time.sleep(1)

def change_expired_password_over_ssh(host, username, current_password, new_password):
    """Changes expired password over SSH with paramiko"""
    with closing(paramiko.SSHClient()) as ssh_connection:
        ssh_connection.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_connection.connect(hostname=host, username=username, password=current_password)
        ssh_channel = ssh_connection.invoke_shell()

        wait_until_channel_endswith(ssh_channel, b'UNIX password: ')
        ssh_channel.send(f'{current_password}\n')

        wait_until_channel_endswith(ssh_channel, b'New password: ')
        ssh_channel.send(f'{new_password}\n')

        wait_until_channel_endswith(ssh_channel, b'Retype new password: ')
        ssh_channel.send(f'{new_password}\n')

        wait_until_channel_endswith(ssh_channel, b'all authentication tokens updated successfully.\r\n')

Использование:

change_expired_password_over_ssh('192.168.1.1', 'username', 'expired-password', 'new-password')

Ещё вопросы

Сообщество Overcoder
Наверх
Меню