Autenticação do PAM
A primeira coisa que se deve ter em mente sobre o Pluggable Authentication Modules (PAM) é que ele não é um aplicativo ou protocolo propriamente dito. É uma coleção de bibliotecas que os aplicativos podem ter sido compilados para utilizar. Se um aplicativo está habilitado para o PAM, a sua política de segurança pode ser configurada por um administrador do sistema sem modificação ou upgrade do aplicativo em si. Muitas ferramentas do Linux, principalmente daemons e servidores, estão habilitadas para o PAM.
Uma forma rápida de verificar se uma determinada ferramenta provavelmente está habilitada para o PAM é usar ldd para ver quais bibliotecas ele usa. Por exemplo, para saber se o meu utilitário de login está habilitado para o PAM:
Listagem 13. O meu login está habilitado para o PAM?
% ldd /bin/login | grep libpam
libpam.so.0 => /lib/libpam.so.0 (0xb7fa8000)
libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb7fa5000)
|
O uso de libpam.so e libpam_misc.so por login não garante totalmente que os recursos do PAM realmente estão sendo usados de forma correta por essa ferramenta, mas é uma boa indicação. Da mesma forma, para saber se os meus servidores Apache e FTP estão habilitados para o PAM:
Listagem 14. E os servidores Apache e FTP?
% ldd /usr/sbin/apache2 | grep libpam
% ldd /bin/login | grep libpam
libpam.so.0 => /lib/libpam.so.0 (0xb7fa8000)
libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb7fa5000)
|
Dessa forma, eu fico sabendo que a minha instalação específica do Apache não está habilitada para o PAM (embora existam versões disponíveis que incluam isso).
Para verificar de forma mais detalhada se o PAM está funcionando totalmente com uma determinada ferramenta, é possível criar um arquivo de configuração do PAM referente ao programa. Por exemplo, para testar o utilitário de login, pode-se criar um arquivo /etc/pam.d/login (mas observe que ele provavelmente já existe no seu sistema com uma configuração mais significativa — portanto, não apague a cópia já existente):
Listagem 15. Verificando o login para o PAM com etc/pam.d/login
auth required pam_permit.so
auth required pam_warn.so
|
A execução de um login adequadamente habilitado para o PAM permitirá que qualquer pessoa faça login, mas registrará a ação no log do sistema. Se syslog mostra uma entrada, o PAM está habilitado para o aplicativo. Os leitores observarão que essa talvez seja a pior configuração possível para login desde que dá a qualquer pessoa acesso de shell. Após perceber isso, saiba que o PAM deve ser configurado com cuidado.
O PAM trabalha com diversos tipos de arquivos de configuração. A maioria das bibliotecas de libpam.so são compiladas no modo "use melhor se estiver disponível, mas aceite o pior". No entanto, também é possível que uma biblioteca do PAM esteja compilada como "use o melhor, mas também verifique o pior." Deixe-me explicar isso.
A forma preferencial atual de configurar o PAM é com os arquivos no diretório /etc/pam.d/ com nomes iguais aos serviços cuja segurança eles descrevem. Um estilo mais antigo e menos recomendável utilizava um único arquivo, /etc/pam.conf, para configurar a política de segurança para todos os aplicativos. Do ponto de vista da possibilidade de manutenção, é mais fácil trabalhar com os arquivos de configuração por aplicativo, e eles também podem ter links simbólicos (symlinks) para "duplicar" uma política de segurança de um aplicativo para outro. Os dois arquivos de configuração parecem basicamente iguais. O arquivo único /etc/pam.conf contém linhas desta forma:
Listagem 16. Os dois arquivos de configuração contêm
<service> <module-type> <control-flag> <module-path> <args>
|
Nos arquivos de configuração por aplicativo, o primeiro campo é omitido, já que é igual ao nome do arquivo. No estilo antigo, a configuração de login somente para teste que vimos é assim:
Listagem 17. /etc/pam.conf
login auth required pam_permit.so
login auth required pam_warn.so
|
O campo <module-type> pode ter um de quatro valores:
-
auth(autenticação), -
account(permissões que não são de autenticação baseadas no sistema de status do usuário), -
session(realiza ações antes/depois do uso do serviço) e -
password(tokens de atualização da autenticação do usuário).
O campo <control-flag> é usado para "empilhar" módulos, algo que dá a você um controle muito sutil referente a quando um método é necessário, se ele é realizado e quando algum outro tipo de fallback é aceitável. Suas opções são
-
required, -
requisite, -
sufficient, -
optionale -
include.
Abordarei as opções no próximo painel.
O <module-path> nós vimos nos exemplos; ele nomeia uma biblioteca compartilhada no local esperado do módulo, se não é fornecido nenhum caminho, ou em um local explícito se ele começa com "/". Por exemplo, na Listagem 17, você pode ter especificado /lib/security/pam_warn.so. O <args> pode ser qualquer coisa, dependendo do que é necessário para o módulo configurar a sua operação, embora alguns argumentos genéricos devam ser suportados pela maioria dos módulos PAM. Observe que os módulos PAM são extensíveis. Se alguém escreve um novo módulo PAM, é possível simplesmente soltá-lo em /lib/security e todos os seus aplicativos poderão usá-lo depois que os arquivos de configuração deles estiverem atualizados para indicar isso.
Um exemplo de permissão do PAM
Para ver como o <control-flag> funciona, vamos desenvolver um exemplo moderadamente complexo. A primeira coisa a fazer é criar um serviço OTHER especial. Se isso existir e nenhuma política do PAM estiver definida para um serviço, usa-se a política de OTHER. Um padrão seguro pode ser parecido com a Listagem 18:
Listagem 18. /etc/pam.d/other
auth required pam_warn.so
auth required pam_deny.so
@include safe-account
@include safe-password
@include safe-session
|
Nesse exemplo, uma tentativa de autenticação primeiro é registrada no syslog e, em seguida, é negada. As instruções @include simplesmente incluem conteúdo de outros lugares, como /etc/pam.d/safe-account e amigos, onde essas definições "seguras" podem conter instruções semelhantes de "advertir e depois negar" para os outros <module-type>.
Agora vamos configurar o acesso ao nosso aplicativo hipotético classified-db. Devido à grande preocupação com o acesso, para que um usuário utilize esse aplicativo, ele tem que fornecer uma impressão digital ou passar pela identificação da retina e também inserir uma senha. No entanto, a senha pode estar armazenada nas configurações locais /etc/passwd e /etc/shadow ou disponível por meio de um de dois servidores de banco de dados externos disponíveis.
Nenhum dos módulos de segurança que eu usei nesse exemplo existe de verdade (até onde eu sei), com exceção de pam_unix.so , que é o acesso por senha antigo no estilo UNIX.
Listagem 19. /etc/pam.d/classified-db
auth optional pam_unix.so
auth optional pam_database1.so try_first_pass
auth optional pam_database2.so use_first_pass
auth requisite pam_somepasswd.so
auth sufficient pam_fingerprint.so master=file1 7points
auth required pam_retinaprint.so
|
O fluxo dessa configuração é moderadamente complexo. Primeiro, tentamos a autenticação de senha por três tipos de módulo optional . Já que eles são optional, a falha em um deles não interrompe o processo de autenticação nem o cumpre. A senha de autenticação padrão do UNIX é tentada primeiro (o usuário tem que inserir uma senha). Depois disso, verificamos as senhas em database1, mas primeiro usamos o argumento de módulo genérico try_first_pass para ver se a senha do UNIX é igual à do banco de dados; solicitamos a senha adicional somente se ela não é. No entanto, com database2 , só tentamos autenticar usando a senha do UNIX que o usuário inseriu (argumento genérico use_first_pass).
Depois de fazer verificações em alguns sistemas de senha optional , usamos um hipotético pam_somepasswd.so que precisa determinar se alguma das verificações de senha anterior foi bem-sucedida (talvez usando um semáforo — mas a forma de fazer isso fica aberta para módulos hipotéticos). A questão é que, como essa verificação é requisite, caso ela falhe, nenhuma autenticação posterior é realizada e a falha é relatada.
As duas últimas verificações de autenticação (caso sejam atingidas) são sufficient. Ou seja, o preenchimento de uma delas retorna um status de sucesso geral para o aplicativo de chamada. Portanto, primeiro tentamos uma verificação de impressão digital usando pam_fingerprint.so (observe que alguns argumentos hipotéticos são passados para o módulo). Somente se isso falhar — talvez por causa da ausência de um scanner de impressão digital ou uma impressão digital inválida — tenta-se a identificação pela retina. Da mesma forma, se a identificação pela retina for bem-sucedida, esse fato é sufficient. Contudo, somente para demonstrar todos os sinalizadores, na verdade, usamos required aqui; isso significa que, mesmo com uma verificação de retina bem-sucedida, continuaríamos verificando outros métodos (mas neste exemplo não há mais nenhum — portanto sufficient faria a mesma coisa).
Também há uma forma de especificar sinalizadores compostos mais ajustados para <control-flag> usando conjuntos entre colchetes de [value1=action1 ...] , mas geralmente as palavras-chave básicas são suficientes.