哪些命令會更改 Open Directory 密碼?
我將 Open Directory 理解為 OpenLDAP + SASL(密碼伺服器)+ Kerberos。OpenLDAP 似乎遵循 SASL 進行身份驗證;我不知道 Kerberos。
我想從腳本更改使用者密碼,最好是遠端更改,並且我希望正確更改密碼。(即,在任何情況下,我都不希望使用者擁有不同的密碼,具體取決於他們對進入 Open Directory 的三個服務中的哪一個進行身份驗證。)
我可以在
dsimport
未綁定到目錄的機器上通過網路進行操作,但是,當您嘗試導入密碼時(儘管將 AuthType 設置為 dsAuthMethodStandard:dsAuthClearText),它僅在密碼尚未被輸入的情況下才有效之前設定的。(我相信可以設置 Crypt 密碼,但我擔心這意味著只有 OD 的 LDAP 部分會知道目前密碼。)除了啟動與伺服器的 ssh 會話並在那裡更改密碼之外,我還能做些什麼嗎?如果我這樣做,是否有任何命令可以讓我在一行上指定多個使用者及其新密碼?
哪些命令可以更改所有打開的目錄密碼,有沒有更喜歡的?
apropos password
給了我這些有趣的結果:
- kpasswd(1) - 更改使用者的 Kerberos 密碼
- ldappasswd(1) - 更改 LDAP 條目的密碼
- lppasswd(1) - 添加、更改或刪除摘要密碼
- passwd(1) - 修改使用者密碼
- pwpolicy(8) - 獲取和設置密碼策略
- saslpasswd2(8) - 設置使用者的 sasl 密碼
- slappasswd(8) - OpenLDAP 密碼實用程序
我會看一些手冊頁,我覺得這
pwpolicy
是最好的選擇,但我很想知道使用這些手冊是否有任何微妙之處(例如,不要更改 Kerberos 密碼無需更改 LDAP 和 SASL 密碼),並且如果它們中的任何一個在沒有 ssh 會話的情況下遠端工作。
我遇到的最方便的答案是將 passwd 命令與 dscl 結合使用。這是互動式會話的輸出(密碼由星號替換):
$ dscl -u diradmin -p ces Password: > cd /LDAPv3/127.0.0.1/ /LDAPv3/127.0.0.1 > auth diradmin ***** /LDAPv3/127.0.0.1 > passwd Users/Atwo807 ***** /LDAPv3/127.0.0.1 > passwd Users/Atwo249 ***** /LDAPv3/127.0.0.1 > passwd Users/doesnotexist foobar passwd: Invalid Path <dscl_cmd> DS Error: -14009 (eDSUnknownNodeName) /LDAPv3/127.0.0.1 > exit Goodbye
這是一個用於進行更改的python腳本。您將需要 pexpect 模組(
sudo easy_install pexpect
應該為您獲取它;我認為您不需要安裝開發工具)。#!/usr/bin/env python import pexpect def ChangePasswords(host, path, diradmin, diradmin_password, user_passwords, record_type='Users'): """Changes passwords in a Open Directory or similar directory service. host = the dns name or IP of the computer hosting the directory path = the pathname to the directory (ex. '/LDAPv3/127.0.0.1') diradmin = the directory administrator's shortname (ex. 'diradmin') diradmin_password = the directory administrator's password user_passwords = a dictionary mapping record names (typically, user's short names) onto their new password record_type = the sort of records you are updating. Typically 'Users' Returns a tuple. The first entry is a list of all records (users) who failed to update. The second entry is a list of all records (users) who successfully updated. """ failed_list = [] succeeded_list = [] prompt = " > " child = pexpect.spawn("dscl -u %s -p %s" % (diradmin, host)) if not (ReplyOnGoodResult(child, "Password:", diradmin_password) and ReplyOnGoodResult(child, prompt, "cd %s" % path) and ReplyOnGoodResult(child, prompt, "auth %s %s" % (diradmin, diradmin_password)) and ReplyOnGoodResult(child, prompt, None)): print "Failed to log in and authenticate" failed_list = user_passwords.keys() return (failed_list, succeeded_list) # We are now logged in, and have a prompt waiting for us expected_list = [ pexpect.EOF, pexpect.TIMEOUT, '(?i)error', 'Invalid Path', prompt ] desired_index = len(expected_list) - 1 for record_name in user_passwords: #print "Updating password for %s" % record_name, child.sendline("passwd %s/%s %s" % (record_type, record_name, user_passwords[record_name])) if child.expect(expected_list) == desired_index: #print ": Succeeded" succeeded_list.append(record_name) else: #print ": Failed" failed_list.append(record_name) child.expect(prompt) child.sendline("exit") child.expect(pexpect.EOF) return (failed_list, succeeded_list) def ReplyOnGoodResult(child, desired, reply): """Helps analyze the results as we try to set passwords. child = a pexpect child process desired = The value we hope to see reply = text to send if we get the desired result (or None for no reply) If we do get the desired result, we send the reply and return true. If not, we return false.""" expectations = [ pexpect.EOF, pexpect.TIMEOUT, '(?i)error', desired ] desired_index = len(expectations) - 1 index = child.expect(expectations) if index == desired_index: if reply: child.sendline(reply) return True else: return False
您可以按如下方式使用它:
# This example assumes that you have named the script given above 'pwchange.py' # and that it is in the current working directory import pwchange (failed, succeeded) = pwchange.ChangePasswords("ces", "/LDAPv3/127.0.0.1", "diradmin", "******", { 'Atwo807' : '*****', 'Atwo249' : '*****', 'Nonexist' : 'foobar', 'Bad' : 'bad' }) print failed, succeeded ['Bad', 'Nonexist'] ['Atwo249', 'Atwo807']