Вы можете легко извлечь зашифрованный пароль с помощью awk. Затем вам нужно извлечь префикс $algorithm$salt$
(при условии, что в этой системе не используется традиционный DES, что сильно не рекомендуется, потому что в наши дни его можно перебрать).
correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}
Для проверки пароля базовая функция C есть crypt
, но нет стандартной команды оболочки для доступа к ней.
В командной строке вы можете использовать однострочник Perl для вызова crypt
пароля.
supplied=$(echo "$password" |
perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …
Так как это не может быть сделано в чисто инструментальных оболочках, если у вас есть доступный Perl, вы можете сделать все это в Perl. (Или Python, Ruby, ... все, что у вас есть, которое может вызвать crypt
функцию.) Предупреждение, непроверенный код.
#!/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);
}
На встроенной системе без Perl я бы использовал небольшую специализированную C-программу. Предупреждение, набранное прямо в браузере, я даже не пытался скомпилировать. Это предназначено для иллюстрации необходимых шагов, а не как надежная реализация!
/* 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);
}
Другой подход заключается в использовании существующей программы, такой как su
или login
. На самом деле, если вы можете, было бы идеально устроить так, чтобы веб-приложение могло выполнять все, что ему нужно su -c somecommand username
. Трудность здесь заключается в том, чтобы ввести пароль su
; это требует терминала. Обычный инструмент для эмуляции терминала - ожидаемый , но это большая зависимость для встроенной системы. Кроме того, хотя он su
находится в BusyBox, он часто опускается, поскольку для многих его применений требуется, чтобы двоичный файл BusyBox был установлен как root. Тем не менее, если вы можете сделать это, это самый надежный подход с точки зрения безопасности.