È possibile estrarre facilmente la password crittografata con awk. È quindi necessario estrarre il prefisso $algorithm$salt$(supponendo che questo sistema non stia utilizzando il tradizionale DES, che è fortemente deprecato perché al giorno d'oggi può essere forzato).
correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}
Per il controllo della password, la funzione C sottostante è crypt, ma non esiste un comando shell standard per accedervi.
Sulla riga di comando, è possibile utilizzare un one-liner Perl per richiamare cryptla password.
supplied=$(echo "$password" |
perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …
Dato che questo non può essere fatto con strumenti shell puri, se hai Perl disponibile, potresti anche fare tutto in Perl. (O Python, Ruby, ... qualunque cosa tu abbia a disposizione che può chiamare la cryptfunzione.) Avviso, codice non testato.
#!/usr/bin/env perl
use warnings;
use strict;
my @pwent = getpwnam($ARGV[0]);
if (!@pwent) {die "Invalid username: $ARGV[0]\n";}
my $supplied = <STDIN>;
chomp($supplied);
if (crypt($supplied, $pwent[1]) eq $pwent[1]) {
exit(0);
} else {
print STDERR "Invalid password for $ARGV[0]\n";
exit(1);
}
Su un sistema embedded senza Perl, utilizzerei un piccolo programma C dedicato. Attenzione, digitato direttamente nel browser, non ho nemmeno provato a compilare. Questo ha lo scopo di illustrare i passaggi necessari, non come un'implementazione robusta!
/* Usage: echo password | check_password username */
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <shadow.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char password[100];
struct spwd shadow_entry;
char *p, *correct, *supplied, *salt;
if (argc < 2) return 2;
/* Read the password from stdin */
p = fgets(password, sizeof(password), stdin);
if (p == NULL) return 2;
*p = 0;
/* Read the correct hash from the shadow entry */
shadow_entry = getspnam(username);
if (shadow_entry == NULL) return 1;
correct = shadow_entry->sp_pwdp;
/* Extract the salt. Remember to free the memory. */
salt = strdup(correct);
if (salt == NULL) return 2;
p = strchr(salt + 1, '$');
if (p == NULL) return 2;
p = strchr(p + 1, '$');
if (p == NULL) return 2;
p[1] = 0;
/*Encrypt the supplied password with the salt and compare the results*/
supplied = crypt(password, salt);
if (supplied == NULL) return 2;
return !!strcmp(supplied, correct);
}
Un approccio diverso consiste nell'utilizzare un programma esistente come suo login. In effetti, se puoi, sarebbe l'ideale organizzare l'applicazione web per eseguire tutto ciò di cui ha bisogno su -c somecommand username. La difficoltà qui è di fornire la password a su; questo richiede un terminale. Si prevede il solito strumento per emulare un terminale , ma è una grande dipendenza per un sistema incorporato. Inoltre, mentre suè in BusyBox, viene spesso omesso perché molti dei suoi usi richiedono che il binario BusyBox sia setuid root. Tuttavia, se riesci a farlo, questo è l'approccio più solido dal punto di vista della sicurezza.