Mac

腳本目錄服務沒有密碼

  • December 14, 2009

我在一個環境中,使用者/組資訊保存在 NFS 掛載的 /etc/passwd 和 /etc/group 文件中。這很好,因為我們可以只編輯平面文件來更改使用者/組資訊。但是,我們設置中的 OS X 機器不太喜歡這樣,因為目錄服務不會在這些文件更改時啟動。

因此,我計劃設置一個 cron 作業來每天執行一次這樣的事情:

dsimport -g /etc/group /Local/Default O -T xDSStandardGroup -u $ADMIN_USER -p $ADMIN_PASS

問題是最後的兩個參數:使用者和密碼。我想避免在腳本中寫出密碼,以降低密碼被洩露的風險。有什麼方法可以使用 dscl 或 dsimport 而無需提供密碼,而是讓它們簡單地使用執行命令的使用者的權限?(你知道,每個標準的 Unix 命令都是這樣。)或者是否有其他方法可以在不以明文形式寫出密碼的情況下完成此操作?

只需瀏覽我在 dscl 上的筆記,我已經編寫了相當廣泛的腳本。我很確定答案是否定的,沒有辦法避免提供密碼。唯一的例外可能是您是本地機器上的 root 使用者(在您的範例中,情況確實如此)。

$$ I’ve almost exclusively done changes over the network. $$ 如果您使用expectpexpect,您可以在腳本中編碼密碼(以可逆方式),然後呼叫您需要的程序。

$$ I’ve come up with a method to encode/decode something that looks like gobbledygook, but it is security through obscurity, I’m afraid. $$ 對於使用 pexpect,這些方面的東西會起作用

$$ note that this example uses dscl, and not dsimport! (I imagine it could be simplified a fair bit for your purposed; turning on the logging command for the dscl child helps when setting things up) $$:

#!/usr/bin/env python

import pexpect
# If you don't have pexpect, you should be able to run
# 'sudo easy_install pexpect' to get it

### Fill in these variables
diradmin = "diradmin"
host = "host"
directory = '/Local/Default'   # '/LDAPv3/127.0.0.1'
# Note: it is possible to encode the data here so it is not in plain text!
password = "password"

DSCL_PROMPT = " > " # Don't change this (unless the dscl tool changes)

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

def RunDSCLCommand(dscl_child, command):
   """Issues one dscl command; returns if it succeeded or failed.

   command = the command to be sent to dscl, such as 'passwd Users/foo newpword'   
   """

   assert dscl_child is not None, "No connection successfully established"

   # We should be logged in with a prompt awaiting us
   expected_list = [ pexpect.EOF, pexpect.TIMEOUT,
                    '(?i)error', 'Invalid Path', DSCL_PROMPT ]
   desired_index = len(expected_list) - 1
   invalid_path_index = desired_index - 1

   dscl_child.sendline(command)
   reply_index = dscl_child.expect(expected_list)
   if reply_index == desired_index:
       return True

   # Find the next prompt so that on the next call to a command like this
   # one, we will know we are at a consistent starting place
   # Looking at the self.dscl_child.before will likely contain
   # the error that occured, but for now:
   dscl_child.expect(DSCL_PROMPT)

   if invalid_path_is_success and reply_index == invalid_path_index:
       # The item doesn't exist, but we will still count it
       # as a success.  (Most likely we were told to delete the item).
       return True

   # one of the error conditions was triggered
   return False


# Here is the part of the program where we start doing things

prompt = DSCL_PROMPT

dscl_child = pexpect.spawn("dscl -u %s -p %s" % (diradmin, host))
#dscl_child.logfile = file("dscl_child.log", "w") # log what is going on

success = False

if (ReplyOnGoodResult(self.dscl_child, "Password:", password) and
  ReplyOnGoodResult(self.dscl_child, prompt, "cd %s" % directory) and
  ReplyOnGoodResult(self.dscl_child, prompt, "auth %s %s" % (diradmin, password)) and
  ReplyOnGoodResult(self.dscl_child, prompt, None)):
success = True

if success:
# Now issue a command
success = RunDSCLCommand(dscl_child, 'passwd Users/foo newpword')

dscl_child.close()

我已經發布了一些我在這裡使用的程式碼;恐怕它完全不受支持(並在此處發佈到 pymacadmin 組。不幸的是,看起來我沒有寫任何關於如何使用它的內容:(

引用自:https://serverfault.com/questions/94318