2015-06-03 8 views
0

В моей организации у нас много Mac, работающих под управлением ОС X Yosemite. Каждая из этих машин имеет учетную запись по умолчанию, которую наша ИТ-команда может использовать для доступа к машине для предоставления ИТ-помощи. Мы хотим периодически менять пароль в этой учетной записи, и, по мере роста количества маков в организации, мы хотим найти способ автоматизации этой задачи.heisenbug: pexpect и изменение паролей на Mac OS X по ssh

Я написал скрипт на Python с использованием pexpect, который SSH в каждой машине и выполнить dscl изменить пароль входа в систему, то SSH в каждой машине, чтобы запустить security изменить пароль Войти брелка.

Эти методы являются частью класса, который имеет старые и новые пароли, хранящиеся в old_password и new_password атрибуты:

def _change_login_password(self, host): 
    """Change the login password of a machine. 

    Returns True on success, False on failure. 
    """ 

    try: 
     child = pexpect.spawn(
      "ssh [email protected]{} dscl . passwd /Users/default".format(host)) 
     child.expect("Password:") 
     child.sendline(self.old_password) 
     child.expect("New Password: ") 
     child.sendline(self.new_password) 
     child.expect(
      "Permission denied. Please enter user's old password:") 
     child.sendline(self.old_password) 
     child.close() 

     return not child.exitstatus 

    except pexpect.TIMEOUT: 
     return False 

def _change_keychain_password(self, host, login_password): 
    """Change the keychain password of a machine. 

    Changes the keychain password to match the login password. 

    Returns True on success, False on failure. 
    """ 

    try: 
     child = pexpect.spawn(
      "ssh [email protected]{} security set-keychain-password" 
      " login.keychain".format(host)) 
     child.expect("Password:") 
     child.sendline(login_password) 
     child.expect("Old Password: ") 
     child.sendline(self.old_password) 
     child.expect("New Password: ") 
     child.sendline(login_password) 
     child.expect("Retype New Password: ") 
     child.sendline(login_password) 
     child.close() 

     return not child.exitstatus 

    except pexpect.TIMEOUT: 
     return False 

Эти методы, как сбой в тестировании против моей OS X Yosemite работы ноутбука. Каждая команда, выполняемая над ssh, возвращает ненулевой статус выхода, а пароли на ноутбуке не изменяются.

... однако, когда я вставляю точку останова pdb в начале любого из методов, а затем выполняем метод в отладчике без каких-либо изменений, статус выхода становится 0, а пароль на ноутбуке изменяется.

Heisenbug.

Вставка утверждений печати вокруг звонков pexpect иногда также приводит к успешному выполнению метода.

я уже экспериментировал с pexepectdelaybeforesend атрибут, который добавляет задержку перед sendline посылает полезную нагрузку в дочерний процесс, думая о том, что время задержки в вмешалась в отладчик, возможно, был вопрос, но это не исправить проблема.

Кто-нибудь знает, где я могу смотреть дальше? Некоторые из моих коллег подозревают, что это может быть проблемой tty. Кто-нибудь знает, как pdb может повлиять на среду и заставить эти команды преуспеть, или что происходит с ОС X?

+0

Вы пытались использовать 'ssh -t'? – robertklep

+0

Я только что попробовал -ttt. Нет кубиков – geekofalltrades

ответ

0

Ах, вот что. При ближайшем рассмотрении оба процесса выходили со статусом 130, который соответствует Ctrl + C. Мне нужно было добавить expect(pexpect.EOF) в оба метода до close, чтобы у них был шанс закончить, прежде чем он был отключен.

def _change_login_password(self, host): 
    """Change the login password of a machine. 

    Returns True on success, False on failure. 
    """ 

    try: 
     child = pexpect.spawn(
      "ssh -ttt [email protected]{} dscl . passwd /Users/default".format(host)) 
     child.expect("Password:") 
     child.sendline(self.old_password) 
     child.expect("New Password: ") 
     child.sendline(self.new_password) 
     child.expect(
      "Permission denied. Please enter user's old password:") 
     child.sendline(self.old_password) 
     child.expect(pexpect.EOF) # Wait for EOF. 
     child.close() 

     return not child.exitstatus 

    except pexpect.TIMEOUT: 
     return False 

    def _change_keychain_password(self, host, login_password): 
    """Change the keychain password of a machine. 

    Changes the keychain password to match the login password. 

    Returns True on success, False on failure. 
    """ 

    try: 
     child = pexpect.spawn(
      "ssh -ttt [email protected]{} security set-keychain-password" 
      " login.keychain".format(host)) 
     child.expect("Password:") 
     child.sendline(login_password) 
     child.expect("Old Password: ") 
     child.sendline(self.old_password) 
     child.expect("New Password: ") 
     child.sendline(login_password) 
     child.expect("Retype New Password: ") 
     child.sendline(login_password) 
     child.expect(pexpect.EOF) # Wait for EOF. 
     child.close() 

     return not child.exitstatus 

    except pexpect.TIMEOUT: 
     return False 

Я также, как это было предложено robertklep, использовали ssh -t (на самом деле ssh -ttt, так что я штопала хорошо получить эту TTY). Комбинация обоих из них устранила проблему, и теперь я с радостью меняю пароли на ssh.