无需密码即可编写目录服务脚本

无需密码即可编写目录服务脚本

我所处的环境中,用户/组信息保存在 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 命令都是这样做的。)或者有没有其他方法可以在不以明文形式写出密码的情况下实现这一点?

答案1

只是浏览了我在 dscl 上的笔记,我已经编写了相当多的脚本。我相当肯定答案是否定的,没有办法避免提供密码。唯一的例外可能是如果您是本地机器上的 root(在您的示例中,确实如此)。[我几乎只通过网络进行更改。]

如果你使用预计或者期望,您可以将密码编码到脚本中(以可逆的方式),然后调用所需的程序。[我想出了一种对一些看似胡言乱语的东西进行编码/解码的方法,但恐怕这是通过隐蔽性来实现安全性的。]

对于使用 pexpect,类似这样的操作会起作用 [请注意,此示例使用 dscl,而不是 dsimport!(我想它可以根据您的目的进行简化;打开 dscl 子进程的日志记录命令有助于设置)]:

#!/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 组这里。不幸的是,我似乎没有写任何关于如何使用它的内容 :(

相关内容