Сценарии службы каталогов без паролей

Я нахожусь в среде, где информация о пользователях / группах хранится в файлах / etc / passwd и / etc / group, которые смонтированы по NFS. Это хорошо, потому что мы можем просто редактировать плоские файлы, чтобы изменить информацию о пользователе / ​​группе. Однако компьютерам с OS X в нашей установке это не очень нравится, потому что службы каталогов не реагируют на изменения этих файлов.

Поэтому я планирую настроить работу cron так, чтобы она запускалась примерно один раз в день:

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

Проблема заключается в тех двух последних аргументах в конце: user и password. Я хочу избежать написания паролей в скриптах, чтобы снизить риск их компрометации. Есть ли какой-либо способ использования dscl или dsimport без указания пароля, но вместо этого они просто используют привилегии пользователя, выполняющего команду? (Вы знаете, как это делает каждая стандартная команда Unix.) Или есть какой-то другой способ сделать это без записи паролей в открытом тексте?

1 ответ

Решение

Просто просматривал мои заметки по dscl, которые я довольно широко написал. Я вполне уверен, что ответ - нет, нет способа избежать ввода пароля. Единственное исключение может быть, если вы являетесь пользователем root в локальном окне (что, в вашем примере, действительно имеет место). [Я почти исключительно делал изменения по сети.]

Если вы используете функцию ожидаем или pexpect, вы можете закодировать пароль в сценарии (обратимым образом), а затем вызвать нужную вам программу. [Я придумал метод для кодирования / декодирования чего-то похожего на бред, но, боюсь, это безопасность через мрак.]

Для использования 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 об этом здесь. К сожалению, похоже, я ничего не написал о том, как его использовать:(

Другие вопросы по тегам