Дорогие коллеги по системным работам,
друг-администратор задал мне следующий вопрос:
На ряде сетевых элементов и серверов он использует удаленную аутентификацию на сервере TACACS +. На некоторых таких проприетарных устройствах аутентификация запрашивает локальную базу данных аутентификации только в том случае, если удаленный метод возвращает «сервер аутентификации недоступен» (недоступен, истекло время ожидания). Если удаленный сервер аутентификации доступен и возвращает отрицательный ответ, рассматриваемый ящик принимает это за чистую монету и не пытается выполнить аутентификацию в локальной базе данных пользователей.
Теперь ... Коробка на базе Linux, он хотел бы добиться такого же поведения. А он, похоже, не может. ОС Linux сначала пытается выполнить удаленную аутентификацию, но при явном отрицательном ответе (сервер отвечает «ошибка аутентификации, это недействительные учетные данные») она продолжает и просто пытается также локальную базу данных.
Я понял, что удаленный TACACS + auth организован красивым модулем PAM, называемым pam_tacplus. Читая о PAM в целом, я, кажется, понял, что pam_tacplus не виноват. Скорее наблюдаемое поведение - это просто способ работы PAM в целом. В этом случае прямое решение, вероятно, должно будет включать добавление настраиваемой глобальной опции в базу кода PAM и, возможно, определенных ключевых слов / синтаксиса файла конфигурации PAM, чтобы изменить поведение в желаемом направлении.
Любые дальнейшие примечания по приветствуются в этой теме: -)
... исходя из дальнейшего чтения, позвольте мне предложить ответ. Любые дополнения или исправления приветствуются.
Во-первых, я нашел это старое введение в PAM. Вероятно, за эти годы он не потерял ни капли остроты своего ума.
Если я загляну внутрь, то узнаю, что возвращаемые значения модуля auth задокументированы в официальной документации linux-pam.
В списке я вижу многообещающий retval под названием PAM_AUTHINFO_UNAVAIL.
Фактически определено в libpam/include/security/_pam_types.h .
#define PAM_SUCCESS 0
#define PAM_AUTHINFO_UNAVAIL 9
#define _PAM_RETURN_VALUES 32
По-видимому, существует конфликтующее определение PAM_AUTHINFO_UNAVAIL в libpam/include/security/_pam_compat.h
# define PAM_AUTHINFO_UNAVAIL 12
— вероятно, его можно игнорировать.
Исходный файл libpam/pam_dispatch.c содержит ключевую функцию с именем
_pam_dispatch_aux(), который фактически проходит по стеку зарегистрированных модулей аутентификации и действует в соответствии с их возвращаемыми значениями.
И, оказывается, на основе "ретваля" напрямую он мало что делает,
возможно, содержит PAM_AUTHINFO_UNAVAIL
. Он напрямую реагирует на некоторые конкретные значения «внутреннего специального использования» retval
, но не имеет специальной обработки для PAM_AUTHINFO_UNAVAIL
. retval
не является возвращаемым значением самого _pam_dispatch_aux()
: скорее retval
— это просто локальная переменная, объявленная внутри цикла for(;;), которая проходит стек зарегистрированных модулей аутентификации, где локальный блок retval
собирает возвращаемое значение конкретного модуля.
Цикл обхода стека на самом деле принимает важные решения на основе других переменных: одна из них является производной, называемой action
, а другая является членом структуры, называемой impression
, «возвращаемой» модулями по ссылке. .Так может на это все-таки повлиял собственный код модуля?
На самом деле получается, что действие
берется из "справочной таблицы действий",
проиндексировано the retval
- ага!
action = h->actions[cached_retval];
Таблица действий определяется модулем? Но как, если макросы _PAM_ACTION_* определены в libpam/pam_private.h ?
Получается, что таблица action[] инициализирована универсальным образом функция с именем _pam_parse_conf_file()
в libpam/pam_handlers.c
,
который выполняет прямое сравнение строк (сопоставление) по ключевым словам, таким как
обязательно
,обязательно
,необязательно
,достаточно
.
И вся таблица в настоящее время имеет 32 позиции (см. приведенное выше определение макроса), которые оптом инициализируются в _PAM_ACTION_UNDEF перед синтаксическим анализом записи конфигурации для конкретного модуля. Затем отдельные «ключевые слова силы» переназначают отдельные retval
на конкретные желаемые действия.
Итак: кажется довольно очевидным, например, вдохновитесь этим:
} else if (!strcasecmp("required", tok)) {
D(("*PAM_F_REQUIRED*"));
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
_pam_set_default_control(actions, _PAM_ACTION_BAD);
} else if (!strcasecmp("sufficient", tok)) {
D(("*PAM_F_SUFFICIENT*"));
actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
}
и добавьте что-то вроде
} else if (!strcasecmp("reqd_if_avail", tok)) {
D(("*PAM_F_REQD_IF_AVAIL*"));
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
actions[PAM_AUTHINFO_UNAVAIL] = _PAM_ACTION_IGNORE; // !!!!!!!!!!
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; // ?
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
_pam_set_default_control(actions, _PAM_ACTION_BAD); // !!!
}
И, видимо, pam_tacplus помогает нам на этом пути.
Было бы, конечно, хорошо, если бы можно было добиться того же эффекта существующим синтаксисом конфигурационного файла PAM без необходимости взлома исходного кода.