Linux操作系统安全登陆设计与实现

本实验使用了VMware来搭建虚拟化环境,在其之上,安装Ubuntu16.04LTS操作系统作为实验平台。

实验设计了一种Linux操作系统的动态登陆验证方式,在常规的密码验证之前先进行动态验证。实验使用向个人邮箱(QQ邮箱)发送实时验证码的方式,来实现动态验证。验证码由6至8位字符组成,字符均从数字、大小写字母、'$'、'@'中随机选取。如果连续3次错误输入验证码,系统会自动重发一个新的验证码到邮箱;验证码的有效时间为3分钟,若验证码超时失效,当用户输入失效验证码后,系统会自动重发新的验证码到邮箱。实验还针对不同用户登录,设置了使用不同的邮箱来进行验证登录,使用root用户设置用户对应的邮箱地址,普通用户无权限进行修改。实验使用的编程语言是Linux环境下的C语言。

1. 环境/工具配置

1.1 pam编译环境配置

使用命令sudo apt-get install libpam0g-dev下载安装软件包libpam0g-dev。

1.2 email环境配置

此处可以参考Ubuntu 使用命令向QQ邮箱发送邮件

使用命令sudo apt-get install heirloom-mailx下载安装软件包heirloom-mailx。安装成功之后,需要修改配置文件/etc/s-nail.rc,因为需要授权码来实现邮箱本地登录,所以要先去QQ邮箱打开SMTP服务并获取授权码(如下图)。

然后使用命令vim /etc/s-nail.rc打开文件进行编辑。添加如下图语句。

其中,from表示发件人,这里为了简单,与收件人设为相同的账号;smtp=smtps是服务器及端口号;smtp-auth标识登录操作;smtp-auth-user是收件人的邮箱;smtp-auth-password是获取的授权码。

 

2. 代码实现

代码附在最后,这里说一下函数说明。

函数

函数说明

int pam_sm_setcred()

认证管理:设置用户证书

int pam_sm_authenticate()

认证管理:认证用户

int pam_sm_acct_mgmt()

账号管理

int pam_sm_open_session()

会话管理:打开会话

int pam_sm_close_session()

会话管理:关闭会话

int pam_sm_chauthtok()

口令管理:设置口令

 

3. 编译与配置

(1)使用命令gcc -o MySecureLogin.so -shared -fPIC MySecureLogin.c –lpam对源文件进行编译。

(2)将得到的文件MySecureLogin.so文件复制至/lib/x86_64-linux-gnu/security目录下。

(3)修改配置文件/etc/pam.d/login,在文件中添加语句auth required MySecureLogin.so

(4)修改配置文件/etc/pam.d/lightdm,在文件首行添加语句auth requisite MySecureLogin.so

最后,需要建立文件/etc/user_email,按照以下格式填写信息。

用户名 邮箱地址
如:user 123456789@qq.com

 

4. 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <sys/time.h>
#include <sys/types.h>

int myloginVerify(pam_handle_t *pamh){
    int retval;
	char shell[300]; // 存储发送邮件的命令
	int len = 6; // 验证码长度默认为6位,下面再更新
	char *tip = "Verification Code"; // 提示信息
	char ver_code[10];  // 存储生成的验证码
	char *input_code; // 存储输入的验证码
	int r;
	
	// 随机字符库
	char al[] = {'0','1','2','3','4','5','6','7','8','9',
		'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
		'o','p','q','r','s','t','u','v','w','x','y','z',
		'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
		'O','P','Q','R','S','T','U','V','W','X','Y','Z',
		'$','@'};
	struct timespec time1 = {0, 0};
	clock_gettime(CLOCK_REALTIME, &time1);
	srand(time1.tv_nsec);
	len = 6 + rand() % 3; // 验证码长度随机为6~8位
	
	for (int i = 0; i < len; i++){ // 生成随机数
		struct timespec time1 = {0, 0};
		clock_gettime(CLOCK_REALTIME, &time1);
		srand(time1.tv_nsec);
		r = rand() % 64;
		ver_code[i] = al[r];
	}
	
	/* 通过用户名获取邮箱地址 */
	FILE *fp;
	const void *user;
	pam_get_item(pamh, PAM_USER, &user);
	char u_name[20], u_email[20];
	if (!(fp = fopen("/etc/user_email", "r")))
		return 1;
	while (~fscanf(fp, "%s %s", u_name, u_email)){
		if (strcmp(u_name, (char*)user) == 0)
			break;
	}
	
	/* 用System()调用系统命令来发送邮件 */
	char *head = "echo \'You are loging in to Ubuntu. The verification code is ";		
	char *foot = " and the validity period is 3 minutes.\' | mail -s \'Ubuntu Login\' ";
	strcat(shell, head);
	strcat(shell, ver_code);
	strcat(shell, foot);
	strcat(shell, u_email);
	system(shell); // 发送邮件
	
	struct timeval t_send, t_input;
	gettimeofday(&t_send, NULL); // 获取发送邮件后的时间戳
	
	int error = 0; // 验证码错误输入次数
	int flag = 1;
	/* 连续3次输入错误,将重新获取验证码 */
	while (error < 3) {
		flag = 1;
		// 读入输入的验证码
		retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &input_code, "%s", tip);
		if (retval != PAM_SUCCESS){
		    return 0;
		}
		gettimeofday(&t_input, NULL); // 获取输入完后的时间戳
		if (t_input.tv_sec - t_send.tv_sec > 180) // 超过3分钟,验证码失效
			return 0;
		
		if (strlen(input_code) != len) { // 检验验证码的长度
			error++;
			continue;
		}
		for (int i = 0; i < len; i++){ // 匹配验证码
			if (ver_code[i] != input_code[i]){
				flag = 0;
				break;
			}
		}
		if (flag == 1) // 验证成功
			return 1;
	}
	return 0; // 错误3次,此轮验证失败
}	

int Verify(pam_handle_t *pamh){
    if(!myloginVerify(pamh))
        return PAM_CONV_ERR;
    return PAM_SUCCESS;
}

/* 认证管理:设置用户证明 */
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ){
    return PAM_SUCCESS;
}

/* 认证管理:认证用户 */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ){
    int retval;
    const char* pUsername;
    retval = pam_get_user(pamh, &pUsername, NULL);

    printf("begin call hotdoorpam %s\n", pUsername);
    if (retval != PAM_SUCCESS){
        printf("pam_get_user failed\n");
        return retval;
    }
    if(!strcasecmp("root",pUsername)) {
        printf("root user!\n");
    }
    else {
        printf("normal user!\n");
    }

    return Verify(pamh);
}

/* 账号管理 */
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv){
    return PAM_SUCCESS;
}

/* 会话管理:打开会话 */
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,int argc, const char **argv){
    return PAM_SUCCESS;
}

/* 会话管理:关闭会话 */
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,int argc, const char **argv){
    return PAM_SUCCESS;
}

/* 口令管理 设置口令*/
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,int argc, const char **argv){
    return PAM_SUCCESS;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牧心.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值