Назад | Перейти на главную страницу

Написание модуля pam_python: «KeyError: getspnam (): имя не найдено»

Я использую pam_python модуль для регистрации имен пользователей и паролей, используемых при попытках SSH.

в /etc/pam.d/sshd Я добавил эту строку:

auth       requisite    pam_python.so /lib64/security/pwreveal.py

Это /lib64/security/pwreveal.py:

import crypt, spwd, syslog

def auth_log(msg):
        """Send errors to default auth log"""
        syslog.openlog(facility=syslog.LOG_AUTH)
        syslog.syslog("SSH Attack Logged: " + msg)
        syslog.closelog()

def check_pw(user, password):
        auth_log("User: " + user + " Password: " + password)
        """Check the password matches local unix password on file"""
        # try:
        hashed_pw = spwd.getspnam(user)[1]
        # except KeyError,e:
        #  return False
        return crypt.crypt(password, hashed_pw) == hashed_pw

def pam_sm_authenticate(pamh, flags, argv):
        try:
                user = pamh.get_user()
        except pamh.exception, e:
                return e.pam_result

        if not user:
                return pamh.PAM_USER_UNKNOWN

        try:
                resp = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, 'Password:'))
        except pamh.exception, e:
                return e.pam_result

        if not check_pw(user, resp.resp):
                auth_log("Remote Host: %s (%s:%s)" % (pamh.rhost, user, resp.resp))
                return pamh.PAM_AUTH_ERR

        return pamh.PAM_SUCCESS

def pam_sm_setcred(pamh, flags, argv):
        return pamh.PAM_SUCCESS

def pam_sm_acct_mgmt(pamh, flags, argv):
        return pamh.PAM_SUCCESS

def pam_sm_open_session(pamh, flags, argv):
        return pamh.PAM_SUCCESS

def pam_sm_close_session(pamh, flags, argv):
        return pamh.PAM_SUCCESS

def pam_sm_chauthtok(pamh, flags, argv):
        return pamh.PAM_SUCCESS

Это работает до некоторой степени, я вижу следующий результат в /var/log/messages после неудачной попытки SSH (в данном случае я с другого локального сервера разработки):

Mar  3 14:35:59 localhost sshd: SSH Attack Logged: Remote Host: 192.168.1.7 (root:root123)

Моя проблема в том, что независимо от того, правильна ли комбинация имени пользователя и пароля, скрипт всегда выводит одну и ту же ошибку в / var / log / secure и не может пройти аутентификацию (так что SSH фактически не работает, пока я использую этот скрипт python):

Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: Traceback (most recent call last):
Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]:  File "/lib64/security/pwreveal.py", line 32, in pam_sm_authenticate
Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]:    if not check_pw(user, resp.resp):
Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]:  File "/lib64/security/pwreveal.py", line 13, in check_pw
Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]:    hashed_pw = spwd.getspnam(user)[1]
Mar  3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: KeyError: getspnam(): name not found

Я знаю, что «spwd» - это база данных теневых паролей, и я нашел в Интернете некоторую информацию, из которой можно предположить, что в этом случае «имя не найдено» было более точно описано как «разрешение отказано». Поэтому в качестве теста я убедился, что у пользователя sshd есть доступ на чтение к / etc / shadow, но это не помогло.

Я не уверен, правильно ли я ищу. Любая помощь?

Примечание. Я понимаю, что регистрация паролей SSH нежелательна для работы на сервере. Я делаю это на коробке личного развития, доступ к которой есть только у меня. Это проект «просто для развлечения».

редактировать - в качестве теста я создал автономный скрипт Python, который просто делает следующее:

import spwd

test = spwd.getspnam("myusername")[1]

print test

Запуск этого сценария от имени пользователя root вытащил хешированный пароль для пароля myusername. Если я намеренно ошибаюсь при написании этого имени пользователя, чтобы эффективно искать имя пользователя, которого нет в теневом файле, я получаю следующую ошибку:

KeyError: 'getspnam(): name not found'

Точно такая же ошибка.

Итак, я могу предположить, что когда spwd.getspnam() запускается изнутри pwreveal.py через pam он не может найти пользователя. Хотя, когда он запускается независимо в отдельном скрипте, это возможно.

Почему это могло быть?

Я не уверен, правильно ли я понял ваш вопрос, но вы пытаетесь сказать, что трассировка вашего скрипта всегда выполняется при вызове из скрипта PAM. Вы можете смоделировать то же поведение, когда пишете недопустимого пользователя (не существующего пользователя).

Итак, начнем подробно. В KeyError исключение говорит вам, что пользователь по какой-то причине не найден в базе данных. Во втором примере это очевидно из-за того, что пользователя на самом деле нет, и это ожидаемое поведение - так работают исключения в Python, не так ли?

Ваша первоначальная проблема, скорее всего, вызвана политикой SELinux в CentOS. Нормальные процессы не умеют читать /etc/shadow. Когда вы запускаете скрипт python из-под стека pam, приостановите его и посмотрите на контексты процесса (используя ps auxfZ), вы увидите фактический контекст, который использует ваш скрипт. Вы также, скорее всего, увидите некоторые сообщения AVC в /var/log/audit/audit.log (или ausearch -m AVC) сообщая, какому процессу запрещен доступ к shadow файл.

Так как выбраться? Первая возможность - временно переключить SELinux на permissive чтобы убедиться, что это причина (setenfoce 0). Затем он должен начать работу. Но вас это не должно устраивать, и если вы хотите сделать это должным образом, вам следует попытаться настроить / написать политику для вашего скрипта, но это не впишется в формат ответа на Serverfault.