linux登陆认证模拟

发表于:2007-06-09来源:作者:点击数: 标签:
一个很简陋的认证过程,通过用户名(或用户ID)和密码明文验证该用户是否可以登陆系统。 just for fun,没有时间完善了,不过应该比较容易扩充和增加其他的功能。 注意链接需要制定-lcrypt。如果需要一般用户同样可以使用,需要将程序setuid(需要验证/etc/s

一个很简陋的认证过程,通过用户名(或用户ID)和密码明文验证该用户是否可以登陆系统。
just for fun,没有时间完善了,不过应该比较容易扩充和增加其他的功能。
注意链接需要制定-lcrypt。如果需要一般用户同样可以使用,需要将程序setuid(需要验证/etc/shadow):
# chown root:root checkpasswd
# chmod 4755 checkpasswd

usage:
$ checkpasswd --user testuser --password testpassword --verbose
$ checkpasswd -i 1001 -p empty_passwd -v



#define    _XOPEN_SOURCE
#define _GNU_SOURCE

#include

#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
#include

typedef enum{
AUTH_TYPE_AUTO,
AUTH_TYPE_DES,
AUTH_TYPE_MD5,

NR_AUTH_TYPE
}auth_type_t;

typedef enum{
AUTH_INFO_AUTO,
AUTH_INFO_PASSWD,
AUTH_INFO_SHADOW,

NR_AUTH_INFO
}auth_info_t;

typedef struct login_info{
char* login; /* login name */
char* cname; /* cname */
char* group;
char* passwd; /* plain text password */

uid_t uid;
gid_t gid;

uint16_t auth_type;
uint16_t auth_info;
}login_info_t;

static login_info_t login_info = {
NULL, NULL, NULL, NULL, -1, -1, 0, 0,
};

static int verbose_flag;

/**
* option for getopt_long
*/
static const struct option opt_options[] = {
{"user", 1, 0, 'n'},
{"uid", 1, 0, 'u'},
{"password", 1, 0, 'p'},
{"help", 0, 0, '?'},
{"version", 0, 0, 'V'},
{"verbose", 0, 0, 'v'},
{0, 0, 0, 0},
};

static void help(void)
{
const struct option* o;

for(o = &opt_options[0]; o && o->name; o++){
fprintf(stderr, "%s\n", o->name);
}
fprintf(stderr, "\n");
}

static void version(void)
{
fprintf(stderr, "version: 0.0.1\n");
}

int verbose(const char* fmt, ...)
{
va_list ap;
int n;

if(!verbose_flag)
return 0;

va_start(ap, fmt);
n = vfprintf(stderr, fmt, ap);
va_end(ap);

return 0;
}

int auth_des(const char* plain_text, const char* key_compare)
{
char* des_key;
char salt[2] = ;

if(strlen(key_compare) < 2)
return -1;

strncpy(salt, key_compare, 2);

des_key = crypt(plain_text, salt);

if(strcmp(des_key, key_compare) == 0)
return 0;

verbose("auth DES: non-match(Wrong) password!\n");

return -1;
}

/**
* need GNU libc 2.x or higher
*/

int auth_md5(const char* plain_text, const char* key_compare)
{
char* md5_key;
const char* p;
char salt[12] = ;
int n = 0;

if(strlen(key_compare) < 3)
return -1;

if(strncmp(key_compare, "$", 3) != 0){ /* not start with "$", please confirm
to /etc/shadow file */
verbose("auth MD5: not start with \"$\"\n");
return -1;
}

p = key_compare + 3;

while(*p++){
++n;
if(!p){
verbose("auth MD5: invalid shadowed MD5 password!\n");
return -1; /* invalid shadowed md5 password */
}

if(n > 8){
break;
}
if(*p == '$'){
break;
}
}

strncpy(salt, key_compare, n + 3);
md5_key = crypt(plain_text, salt);

if(strcmp(md5_key, key_compare) == 0)
return 0;

verbose("auth MD5, non-match(Wrong) password!\n");

return -1;
}

int check_shadowed_passwd(login_info_t* login_info)
{
struct passwd* pw;
struct spwd* spw;

if(login_info->login){
spw = getspnam(login_info->login);
}else if(login_info->uid >= 0){
pw = getpwuid(login_info->uid);
if(!pw){
verbose("getpwuid [%d] failed, error: %s\n", login_info->uid,
strerror(errno));
return -1;
}
login_info->login = pw->pw_name;
spw = getspnam(pw->pw_name);
}else{
return -1;
}

if(!spw){
fprintf(stderr, "unable to read shadow passwd info: %s\n",
strerror(errno));
return -1;
}

if(login_info->auth_type == AUTH_TYPE_AUTO){
if(strncmp(spw->sp_pwdp, "$", 3) == 0){ /* GNU extension, md5 used */
return auth_md5(login_info->passwd, spw->sp_pwdp);
}else{
return auth_des(login_info->passwd, spw->sp_pwdp);
}
}else if(login_info->auth_type == AUTH_TYPE_DES){
return auth_des(login_info->passwd, spw->sp_pwdp);
}else if(login_info->auth_type == AUTH_TYPE_MD5){
return auth_md5(login_info->passwd, spw->sp_pwdp);
}else{
verbose("unknown auth type: %d\n", login_info->auth_type);
return -1;
}
}

/**
* checkpasswd
*/

int check_passwd(login_info_t* login_info)
{
struct passwd* pw;

if(login_info->login){
pw = getpwnam(login_info->login);
if(!pw){
verbose("getpwnam [%s] failed, error: %s\n", login_info->login,
strerror(errno));
return -1;
}
login_info->uid = pw->pw_uid;
}else if(login_info->uid >= 0){
pw = getpwuid(login_info->uid);
if(!pw){
verbose("getpwuid [%d] failed, error: %s\n", login_info->uid,
strerror(errno));
return -1;
}
login_info->login = pw->pw_name;
}else{
return -1;
}

if(!login_info->passwd){
verbose("no password specified!\n");
return -1;
}

if(login_info->auth_info == AUTH_INFO_AUTO){
if(strlen(pw->pw_passwd) < 2){
if(strcmp(pw->pw_passwd, "x") == 0){ /* shadow password used */
return check_shadowed_passwd(login_info);
}else{
return -1;
}
}
return auth_des(login_info->passwd, pw->pw_passwd);
}else if(login_info->auth_info == AUTH_INFO_PASSWD){
return auth_des(login_info->passwd, pw->pw_passwd);
}else if(login_info->auth_info == AUTH_INFO_SHADOW){
return check_shadowed_passwd(login_info);
}else{
verbose("unknown auth info: %d\n", login_info->auth_info);
return -1;
}
}

void handle_args(int argc, char* argv[])
{
int ch;
int option_index;

while((ch = getopt_long(argc, argv, "u:i:p:Vvh", opt_options, &option_index)) != -1){
switch(ch){
case 'u':
login_info.login = optarg;
break;
case 'i':
login_info.uid = atoi(optarg);
break;
case 'p':
login_info.passwd = optarg;
break;
case 'h':
help();
exit(0);
break;
case 'V':
version();
exit(0);
break;
case 'v':
verbose_flag = 1;
break;
case '?':
default:
help();
exit(1);
break;
}
}

if(!login_info.passwd){
fprintf(stderr, "please specifie login password\n");
help();
exit(1);
}
if(!login_info.login && !login_info.uid){
fprintf(stderr, "please specifie either login name or user id\n");
help();
exit(1);
}
}

int main(int argc, char* argv[])
{
int ret;
const char seperator[] =
"==========================================================================================\n";
int retcode = 1;

handle_args(argc, argv);

printf(seperator);

ret = check_passwd(&login_info);

if(ret < 0){
fprintf(stderr, "3[1;31mauthentication failed for user: "
"[%s], uid[%d], password: [%s]3[m\n",
login_info.login, login_info.uid, login_info.passwd);
goto quit;
}else if(ret == 0){
printf("3[1;32mauthenticated token suclearcase/" target="_blank" >ccessfully, user: "
"[%s], uid: [%d]3[m\n",
login_info.login, login_info.uid);
retcode = 0;
}else{
assert(0);
retcode = -1;
}

quit:
printf(seperator);
exit(retcode);
}



原文转自:http://www.ltesting.net