Caros colegas consertadores de sistema,
um amigo administrador me fez a seguinte pergunta:
Em vários elementos e servidores de rede, ele está usando autenticação remota em um servidor TACACS+. Em alguns desses dispositivos proprietários, a autenticação solicita apenas um banco de dados de autenticação local se o método remoto retornar "servidor de autenticação indisponível" (inacessível, expirado). Se o servidor de autenticação remotoédisponível e retornar uma resposta negativa, a caixa em questão considera isso pelo valor nominal e não tenta autenticar em um banco de dados de usuário local.
Agora... em uma máquina baseada em Linux, ele gostaria de obter o mesmo comportamento. E ele não consegue. O sistema operacional Linux primeiro tenta a autenticação remota, mas após uma resposta negativa clara (o servidor responde "falha de autenticação, essas credenciais não são válidas") ele segue em frente e também tenta o banco de dados local.
Eu entendi que a autenticação remota TACACS+ é organizada por um bom módulo PAM chamado pam_tacplus. Lendo sobre o PAM em geral, parece que percebi que o pam_tacplus não é o culpado. Em vez disso, o comportamento observado é apenas a forma como o PAM funciona como um todo. Se for esse o caso, uma solução direta provavelmente envolveria a adição de uma opção global configurável à base de código do PAM, e talvez palavras-chave/sintaxe específicas do arquivo de configuração do PAM, para modificar o comportamento na direção desejada.
Quaisquer notas adicionais sobre este tópico são bem-vindas :-)
Responder1
...com base em leituras adicionais, deixe-me sugerir uma resposta. Quaisquer acréscimos ou correções são obviamente e calorosamente bem-vindos.
Em primeiro lugar, descobri que isso é antigointrodução ao PAM. Provavelmente não perdeu sua inteligência afiada ao longo dos anos.
Se eu der uma olhada nos bastidores, os valores de retorno do módulo de autenticação sãodocumentado na documentação oficial do linux-pam.
Na lista, posso ver um retval promissor chamado PAM_AUTHINFO_UNAVAIL .
Na verdade definido emlibpam/include/security/_pam_types.h.
#define PAM_SUCCESS 0
#define PAM_AUTHINFO_UNAVAIL 9
#define _PAM_RETURN_VALUES 32
Parece haver uma definição conflitante de PAM_AUTHINFO_UNAVAIL emlibpam/include/security/_pam_compat.h
# define PAM_AUTHINFO_UNAVAIL 12
- provavelmente seguro ignorar.
O arquivo de origemlibpam/pam_dispatch.c contém uma função chave chamada _pam_dispatch_aux()que realmente percorre a pilha de módulos de autenticação registrados e atua de acordo com seus valores de retorno. E acontece que ele não faz muito com base no "retval" diretamente, possivelmente contendo PAM_AUTHINFO_UNAVAIL
. Ele responde diretamente a alguns valores específicos de "uso especial interno" de retval
, mas não possui tratamento especial para PAM_AUTHINFO_UNAVAIL
. retval
não é um valor de retorno por _pam_dispatch_aux()
si só: em vez disso, retval
é apenas uma variável local declarada dentro do loop for(;;) que percorre a pilha de módulos de autenticação registrados, onde o bloco local retval
coleta o valor de retorno do módulo específico. O loop stackwalking na verdade toma decisões importantes com base em outras variáveis: uma delas derivada, chamada action
, e a outra é um membro da estrutura chamado impression
"retornado" pelos módulos por referência. Então, talvez, afinal, possa ser influenciado pelo próprio código do módulo?
Na verdade, isso action
foi retirado de uma "tabela de pesquisa de ações",
indexado poro retval
- aha!
action = h->actions[cached_retval];
A tabela de ações é definida pelo módulo? Mas como, se as macros _PAM_ACTION_* são #definidas emlibpam/pam_private.h?
Acontece que a tabela actions[] éinicializado de forma genéricapor uma função chamada _pam_parse_conf_file()
em libpam/pam_handlers.c
, que faz umcomparação direta de strings(correspondência) em palavras-chave como
required
, requisite
, optional
, sufficient
.
E, atualmente, toda a tabela possui 32 posições (veja a definição de macro citada acima) que ficamatacado inicializadopara _PAM_ACTION_UNDEF antes de analisar a entrada de configuração do módulo específico. As "palavras-chave de força" individuais remapeiam retval
as palavras-chave individuais para ações desejadas específicas.
Então: parece bastante óbvio, por exemplo, inspirar-se nisso:
} 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);
}
e adicione algo como
} 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); // !!!
}
E, aparentemente, pam_tacplusnos ajuda nesse caminho.
Certamente seria bom se o mesmo efeito pudesse ser alcançado pela sintaxe existente do arquivo de configuração do PAM, sem a necessidade de hackear o código-fonte.