Como escrevo um teste para o login do sistema?

9

Eu escrevi um script CGI em Python que invoca os comandos bash , e ele precisa testar um login bem-sucedido no host.

Como escrevo um teste para isso?

Por exemplo, posso criar um script bash que testa uma combinação de nome de usuário e senha em relação ao usuário registrado no host?

    
por jcubic 11.01.2012 / 01:43

9 respostas

8

O uso do PAM é a melhor solução. Você pode escrever um pequeno código C, ou instalar o pacote python-pam e usar um script python que vem com o pacote python-pam. Veja /usr/share/doc/python-pam/examples/pamtest.py

    
por 11.01.2012 / 11:32
5

A abordagem correta para testar se um usuário pode efetuar login é realmente efetuar login como esse usuário.

Então, o que recomendo é que o script CGI use expect para executar su , passar uma senha e execute o comando que deve ser executado. Aqui está um rascunho de um script de expectativa que faz exatamente isso (aviso: absolutamente não testado, e eu não sou fluente em esperar). Substitua o nome de usuário, senha e comando (onde eu escrevi bob , swordfish e somecommand ); não se esqueça de citar corretamente.

spawn "/bin/su" "bob"
expect "Password:"
send "swordfish\r"
expect "^\$"
send "somecommand"
expect -re "^\$"
send "exit\r"
expect eof

Se você realmente não quer executar o comando através de uma camada de su (por exemplo, porque o que você faz tem que ser executado pelo próprio processo CGI), então use esperar para executar o comando true e verifique se o status de retorno é 0.

Outra abordagem seria usar o PAM diretamente no seu aplicativo, por meio de Ligação do PAM do Python .

    
por 12.01.2012 / 02:04
2

Para responder mais especificamente: "É possível criar um script bash que testará uma combinação de nome de usuário e senha em relação ao usuário registrado no host?"

Sim.

#!/bin/bash
uid='id -u'

if [ $uid -ne 0 ]; then 
    echo "You must be root to run this"
    exit 1
fi

if [ $# -lt 1 ]; then
    echo "You must supply a username to check - ($# supplied)"
    exit 1
fi

username=$1
salt='grep $username /etc/shadow | awk -F: ' {print substr($2,4,8)}''

if [ "$salt" != "" ]; then

        newpass='openssl passwd -1 -salt $salt'
        grep $username  /etc/shadow | grep -q  $newpass && echo "Success" || echo "Failure"

fi
    
por 11.01.2012 / 05:55
2

Existe uma solução PAM 'C', 'Python' citada aqui, deixe-me colocar a perl também: -)

Fonte: link ?

#!/usr/bin/perl

  use Authen::PAM;
  use POSIX qw(ttyname);

  $service = "login";
  $username = "foo";
  $password = "bar";
  $tty_name = ttyname(fileno(STDIN));

  sub my_conv_func {
    my @res;
    while ( @_ ) {
        my $code = shift;
        my $msg = shift;
        my $ans = "";

        $ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
        $ans = $password if ($code == PAM_PROMPT_ECHO_OFF() );

        push @res, (PAM_SUCCESS(),$ans);
    }
    push @res, PAM_SUCCESS();
    return @res;
  }

  ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
         die "Error code $pamh during PAM init!";

  $res = $pamh->pam_set_item(PAM_TTY(), $tty_name);
  $res = $pamh->pam_authenticate;
  print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
    
por 11.01.2012 / 12:36
1

Se você tem acesso root, e está usando senhas md5, e você só precisa comparar senhas, então você pode usar o perl Módulo Crypt :: PasswdMD5 . Pegue o MD5 Hash de / etc / shadow, tire $ 1 $ e depois divida os $ restantes. Campo 1 = Sal, Campo 2 = texto criptografado. Em seguida, insira o texto em seu CGI, compare com o texto criptografado e com Bob, seu tio.

#!/usr/bin/env perl

use Crypt::PasswdMD5;

my $user                = $ARGV[0];
my $plain               = $ARGV[1];
my $check               = qx{ grep $user /etc/shadow | cut -d: -f2 };
chomp($check);
my($salt,$md5txt)       = $check =~ m/\\$([^\$].+)\$(.*)$/;
my $pass                = unix_md5_crypt($plain, $salt);

if ( "$check" eq "$pass" ) {
        print "OK","\n";
} else {
        print "ERR","\n";
}
    
por 11.01.2012 / 07:53
0

Depois de alguma pesquisa eu escrevi este programa C que pode ser usado a partir do script

#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <crypt.h>
#include <unistd.h>
#include <libgen.h>

int main(int argc, char **argv) {
    struct spwd *pwd;
    if (argc != 3) {
        printf("usage:\n\t%s [username] [password]\n", basename(argv[0]));
        return 1;
    } else if (getuid() == 0) {
        pwd = getspnam(argv[1]);
        return strcmp(crypt(argv[2], pwd->sp_pwdp), pwd->sp_pwdp);
    } else {
        printf("You need to be root\n");
        return 1;
    }
}

Você compila com:

gcc -Wall password_check.c /usr/lib/libcrypt.a -o check_passwd

Você pode usá-lo como

sudo ./check_passwd <user> <password> && echo "success" || echo "failure"
    
por 11.01.2012 / 10:48
0

Como você mencionou que está usando CGI em python, provavelmente é apropriado assumir que você está usando o Apache como servidor httpd. Se assim for, deixe o processo de autenticação do seu programa para o Apache e deixe que as pessoas autenticadas executem seus scripts / programas cgi.

Existem amplos módulos que podem fazer autenticação para você no Apache, isso realmente depende do tipo de mecanismo de autenticação que você está procurando. A maneira como você citou a questão parece estar relacionada à autenticação da conta de host local baseada em / etc / passwd, arquivos de sombra. O módulo que vem à minha pesquisa rápida sobre isso é mod_auth_shadow . Vantagem é que você está permitindo que alguém autoritário (em execução na porta de privilégio 80) autentique o usuário / senha para você e você pode confiar em informações autenticadas do usuário para executar os comandos em nome do usuário, se necessário.

bons links para começar:

link

link

link

Outra abordagem é usar o módulo SuEXEc do Apache, que executa processos (programas cgi) em nome do usuário autenticado.

    
por 12.01.2012 / 10:52
0

Esse código usando o PAM funcionou para mim:

#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <string.h>

// Define custom PAM conversation function
int custom_converation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr)
{
    // Provide password for the PAM conversation response that was passed into appdata_ptr
    struct pam_response* reply = (struct pam_response* )malloc(sizeof(struct pam_response));
    reply[0].resp = (char*)appdata_ptr;
    reply[0].resp_retcode = 0;

    *resp = reply;

    return PAM_SUCCESS;
}

int main (int argc, char* argv[]) 
{
    if (argc > 2)
    {
        // Set up a custom PAM conversation passing in authentication password
        char* password = (char*)malloc(strlen(argv[2]) + 1);
        strcpy(password, argv[2]);        
        struct pam_conv pamc = { custom_converation, password };
        pam_handle_t* pamh; 
        int retval;

        // Start PAM - just associate with something simple like the "whoami" command
        if ((retval = pam_start("whoami", argv[1], &pamc, &pamh)) == PAM_SUCCESS)
        {
            // Authenticate the user
            if ((retval = pam_authenticate(pamh, 0)) == PAM_SUCCESS) 
                fprintf(stdout, "OK\n"); 
            else 
                fprintf(stderr, "FAIL: pam_authentication failed.\n"); 

            // All done
            pam_end(pamh, 0); 
            return retval; 
        }
        else
        {
            fprintf(stderr, "FAIL: pam_start failed.\n"); 
            return retval;
        }
    }

    fprintf(stderr, "FAIL: expected two arguments for user name and password.\n"); 
    return 1; 
}
    
por 02.09.2014 / 15:10
-3

A melhor coisa que você pode fazer, se precisar de um script para acessar um host, é configurar uma chave ssh entre os hosts.

Link: link

Eu praticamente tirei isso da página

Primeiro, instale o OpenSSH em duas máquinas UNIX, difíceis e volumosas. Isso funciona melhor usando chaves DSA e SSH2 por padrão, tanto quanto eu posso dizer. Todos os outros HOWTOs que vi parecem lidar com chaves RSA e SSH1, e as instruções não surpreendentemente funcionam com o SSH2. Em cada máquina, digite ssh somemachine.example.com e faça uma conexão com sua senha normal. Isso criará um diretório .ssh em seu diretório pessoal com os perms apropriados. Na sua máquina principal, onde você quer que suas chaves secretas vivam (digamos, hurly), digite

ssh-keygen -t dsa

Isso solicitará uma senha secreta. Se esta for sua chave de identidade primária, use uma boa frase-senha. Se isso funcionar corretamente, você obterá dois arquivos chamados id_dsa e id_dsa.pub em seu diretório .ssh. Nota: é possível apenas pressionar a tecla enter quando for solicitada uma frase secreta, que fará uma chave sem frase-senha. Esta é uma idéia ruim para uma chave de identidade, então não faça isso! Veja abaixo os usos de chaves sem frases secretas.

scp ~/.ssh/id_dsa.pub burly:.ssh/authorized_keys2

Copie o arquivo id_dsa.pub para o diretório .ssh do outro host com o nome authorized_keys2. Agora, o corpulento está pronto para aceitar sua chave ssh. Como dizer quais teclas usar? O comando ssh-add fará isso. Para um teste, digite

ssh-agent sh -c 'ssh-add < /dev/null && bash'

Isso iniciará o ssh-agent, adicionará sua identidade padrão (solicitando sua frase secreta) e gerará um shell bash. A partir deste novo shell você deve ser capaz de:

ssh burly

Você deve conseguir fazer login

    
por 11.01.2012 / 04:01