#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);
}