답변:
PAM을 사용하는 것이 가장 좋습니다. 작은 C 코드를 작성하거나 python-pam 패키지를 설치하고 python-pam 패키지와 함께 제공되는 python 스크립트를 사용할 수 있습니다. 보다/usr/share/doc/python-pam/examples/pamtest.py
/usr/share/doc/packages/python-pam/examples/pamtest.py
스크립트를 사용하여 PAM을 사용하는 시스템에서 자격 증명을 테스트 할 수 있습니다 인증을 위해 python-pam 패키지 (python 필요)에 포함되어 있으며 일부 배포판에서는 전체 경로가 /usr/share/doc/python-pam/examples/pamtest.py
입니다.
사용자가 로그인 할 수 있는지 테스트하는 올바른 방법은 실제로 해당 사용자로 로그인하는 것입니다.
따라서 내가 추천하는 것은 CGI 스크립트를 사용 expect
하여 실행 su
하고 암호를 전달한 다음 실행해야하는 명령을 실행하는 것입니다. 다음은이 작업을 수행하는 expect 스크립트 초안입니다 (경고 : 절대적으로 테스트되지 않았으며 기대에 유창하지 않습니다). (내가 쓴 경우 사용자 이름, 암호 및 명령에 대체 bob
, swordfish
과 somecommand
); 정확하게 인용하십시오.
spawn "/bin/su" "bob"
expect "Password:"
send "swordfish\r"
expect "^\\$"
send "somecommand"
expect -re "^\\$"
send "exit\r"
expect eof
su
CGI 프로세스 자체에서 수행해야하는 작업 과 같이 계층을 통해 명령을 실제로 실행하지 않으려면 expect 명령을 실행 true
하고 반환 상태가 0인지 확인하십시오.
또 다른 방법은 Python의 PAM 바인딩을 통해 응용 프로그램에서 직접 PAM 을 사용하는 것 입니다.
su -c true bob && echo success
스와 인수로 암호를 허용하지 않는 것이 부끄러운
su
CGI 스크립트에서 테스트 했으며 작동하려면 터미널이 필요합니다.
/bin/true
것입니다.
보다 구체적으로 대답하려면 : "호스트의 등록 된 사용자에 대해 지정된 사용자 이름 및 비밀번호 조합을 테스트하는 bash 스크립트를 작성할 수 있습니까?"
예.
#!/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
shadow
그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (openssl이 지원하는 알고리즘)과 비밀번호 저장 위치 ( /etc/shadow
예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수도 있다고 가정합니다.
여기에 인용 된 'C', 'Python'PAM 솔루션이 있습니다.
#!/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();
루트 액세스 권한이 있고 md5 비밀번호를 사용 중이고 비밀번호를 비교해야하는 경우 perl Crypt :: PasswdMD5 모듈을 사용할 수 있습니다 . / etc / shadow에서 MD5 해시를 가져와 $ 1 $를 벗기고 나머지 $로 나눕니다. 필드 1 = 소금, 필드 2 = 암호화 된 텍스트. 그런 다음 텍스트 입력을 CGI에 해시하고 암호화 된 텍스트와 비교하고 Bob은 삼촌입니다.
#!/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/\$1\$([^\$].+)\$(.*)$/;
my $pass = unix_md5_crypt($plain, $salt);
if ( "$check" eq "$pass" ) {
print "OK","\n";
} else {
print "ERR","\n";
}
shadow
그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (MD5 및 bcrypt 또는 기타 권장 알고리즘이 아님)과 비밀번호 저장 위치 ( /etc/shadow
예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수 있다고 가정합니다.
검색 후 스크립트에서 사용할 수있는이 C 프로그램을 작성했습니다.
#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;
}
}
다음과 같이 컴파일하십시오.
gcc -Wall password_check.c /usr/lib/libcrypt.a -o check_passwd
당신은 그것을 사용할 수 있습니다
sudo ./check_passwd <user> <password> && echo "success" || echo "failure"
shadow
그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (openssl이 지원하는 알고리즘)과 비밀번호 저장 위치 ( /etc/shadow
예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수도 있다고 가정합니다. PAM을 사용하면 그 일을 알고 있습니다.
파이썬에서 CGI를 사용한다고 언급 했으므로 Apache를 httpd 서버로 사용한다고 가정하는 것이 적합합니다. 그렇다면 프로그램의 인증 프로세스를 Apache에 맡기고 인증 된 사용자 만 cgi 스크립트 / 프로그램을 실행하도록하십시오.
Apache에서 인증을 수행 할 수있는 충분한 모듈이 있으며, 실제로 원하는 인증 메커니즘의 종류에 따라 다릅니다. 질문에서 인용 한 방법은 / etc / passwd, shadow 파일을 기반으로하는 로컬 호스트 계정 인증과 관련이있는 것 같습니다. 이것에 관한 나의 빠른 검색에 오는 모듈은 mod_auth_shadow
입니다. 장점은 권한있는 사용자 (권한 포트 80에서 실행)가 사용자 / 비밀번호를 인증 할 수있게하고 필요한 경우 사용자 대신 인증 된 정보를 사용하여 사용자 대신 명령을 실행할 수 있다는 것입니다.
시작하기에 좋은 링크 :
http://adam.shand.net/archives/2008/apache_tips_and_tricks/#index5h2
http://mod-auth-shadow.sourceforge.net/
http://www.howtoforge.com/apache_mod_auth_shadow_debian_ubuntu
또 다른 방법은 인증 된 사용자 대신 프로세스 (cgi 프로그램)를 실행하는 Apache의 SuEXEc 모듈을 사용하는 것입니다.
PAM을 사용하는이 코드는 저에게 효과적이었습니다.
#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;
}
호스트에 로그인하기 위해 스크립트가 필요한 경우 가장 좋은 방법은 호스트간에 ssh 키를 구성하는 것입니다.
링크 : http://pkeck.myweb.uga.edu/ssh/
나는 이것을 페이지에서 거의 들었다.
먼저, 두 개의 UNIX 시스템에 서둘러 OpenSSH를 설치하십시오. 이것은 내가 알 수있는 한 기본적으로 DSA 키와 SSH2를 사용하는 것이 가장 좋습니다. 내가 본 다른 모든 하우투는 RSA 키와 SSH1을 다루는 것처럼 보이며, 지침이 놀랍게도 SSH2와 작동하지 않습니다. 각 머신에서 ssh somemachine.example.com을 입력하고 일반 비밀번호로 연결하십시오. 홈 디렉토리에 적절한 perms와 함께 .ssh 디렉토리가 작성됩니다. 비밀 키를 사용하려는 기본 컴퓨터에서 (둘러 말해 보자)
ssh-keygen -t dsa
비밀 암호를 입력하라는 메시지가 표시됩니다. 이것이 기본 ID 키인 경우 올바른 암호를 사용해야합니다. 이것이 제대로 작동하면 .ssh 디렉토리에 id_dsa와 id_dsa.pub라는 두 파일이 생깁니다. 참고 : 암호 문구를 입력하라는 메시지가 표시되면 Enter 키를 누르면 암호 문구가없는 키를 만들 수 있습니다. 이것은 신원 키에 대한 나쁜 생각 ™이므로 수행하지 마십시오! 암호없이 키를 사용하려면 아래를 참조하십시오.
scp ~/.ssh/id_dsa.pub burly:.ssh/authorized_keys2
id_dsa.pub 파일을 authorized_keys2라는 이름으로 다른 호스트의 .ssh 디렉토리에 복사하십시오. 이제 ssh 키를 받아 들일 준비가되었습니다. 사용할 키를 알려주는 방법은 무엇입니까? ssh-add 명령이이를 수행합니다. 테스트를 위해
ssh-agent sh -c 'ssh-add < /dev/null && bash'
그러면 ssh-agent가 시작되고 기본 ID가 추가되고 (암호를 입력하라는 메시지가 표시됨) bash 쉘이 생성됩니다. 이 새로운 쉘에서 다음을 수행 할 수 있어야합니다.
ssh burly
로그인 할 수 있어야합니다
login
프로그램 뒤의 코드를 볼 수있을 것 입니다.