通常,我们在切换计算机用户时,会需要输入密码。在Linux命令行下,密码不可见;在Windows下,密码显示的则是··········
的一串小黑点,或者登陆某一网站账号时密码为********
的一串星号,其目的都是来隐藏密码。而这种密码的显示方式怎样是怎样实现的呢,今天,我就用C语言在Linux下简单实现一下。
一、输入密码不回显:
1、首先,我们需要了解几个函数以及结构体:
(1)、结构体struct termios:
struct termios{
tcflag_t c_iflag;/*input modes输入模式标志*/
tcflag_t c_oflag;/*output modes输出模式标志*/
tcflag_t c_cflag;/*contol modes控制模式标志*/
tcflag_t c_lflag;/*local modes本地模式标志*/
cc_t c_cc[NCCS];/*contol chars控制字符*/
};
/*这是一个标准终端接口的结构体,其中5个成员中我们会用到c_lflag这个本地模式*/
/*
c_lflag会用到的几个参数:
ECHO//显示输入字符
ICANON//使用标准输入输出
*/
(2)tcsetattr()与tcgetattr()函数:
函数原型:
#include<termios.h>
int tcgetattr(int fd,struct termios * termios_p);//获取终端参数
int tcsetattr(int fd,int optional_actions,const struct termios *termios_p);//设置终端参数
tcgetattr()函数:
返回值:成功返回0,失败返回-1,失败时接口设置errno标识
参数:
/*
fd为终端文件描述符:
0表示stdin
1表示stdout
2表示stderr
termios_p为结构体struct termios*类型指针,其指向的空间用来存储tcgetatrr()函数获取到的fd的的参数。
*/
tcsetattr()函数:
返回值:成功返回0,失败返回-1并设置errno
参数:
fd与tcgetattr()函数一样,为终端文件描述符
optional_actions则是用来控制修改后设置的参数起作用的时间(有3个):
TCSANOW //立即生效
TCSADRAIN //等待所有数据传输完毕后生效
TCSAFLUSH //等待所有数据传输完毕并且清空输入输出缓存区后生效
termios_p存放新的重新设置的参数的结构体变量
2、代码实现:
#include <stdio.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
int main()
{
struct termios old, new;//old保存当前的终端参数,new用来保存修改后的终端参数
tcgetattr(0, &old);//将tcgetattr()获取到的stdin(标准输入流)的参数存到old中
new = old;//将该参数复制一份到new中
new.c_lflag &= ~( ECHO | ICANON);//修改new中的ECHO和ICANON参数,使得new为不回显输入内容
tcsetattr(0, TCSANOW ,&new);//将修改后的new设置为stdin的新的参数,并立即生效
char buf[20] = {0};
int i = 0;
while( (strncmp("redhat", buf, 6)) && i<5){
memset(buf, 0, 20);//每次重新输入以前都要清空一次buf
fgets(buf, 20, stdin);
i++;
}
if(i>=5){
printf("密码输入错误超过5次,登录失败!\n");
printf("buf: %s\n", buf);
}
else{
printf("登陆成功!\n");
}
tcsetattr(0, TCSANOW, &old);//登陆成功后恢复原有终端参数,正常回显
return 0;
}
二、输入密码时显示**********
1、实现:
只要搞清了不回显的实现方式,相较于不回显,显示****
就比较简单了,代码如下:
# include<stdio.h>
# include<termios.h>
# include<string.h>
# include<unistd.h>
int main(void)
{
struct termios old,new;
tcgetattr(0,&old);
new = old;
new.c_lflag &= ~(ECHO|ICANON);
char passwd_stdin[20]={0};
char passwd_true[]="hello";
char ch;
int i=0;
while(1)
{
tcsetattr(0, TCSANOW, &new);//进入循环将stdin设置为不回显状态
scanf("%c",&ch);//在不回显状态下输入密码
tcsetattr(0, TCSANOW, &old);//每次输入一个密码的字符就恢复正常回显状态
if(i==20 || ch == '\n')//输入回车符表示密码输入完毕,退出循环;或者超出密码长度退出循环
break;
passwd_stdin[i] = ch;//将输入的单个字符依次存入数组中
printf("*");//在回显状态下输出*
i++;
}
/*比较从终端输入的密码与设定好的密码是否相同,相同打印一些信息,表示登陆成功;不同做出一些操作,对非正常登陆作出保护性措施*/
if(!strcmp(passwd_stdin,passwd_true)){
printf("登陆成功!\n");
system("cat passwd.c");
}
else{
printf("登录失败!\n");
//system("shutdown -h now");
}
return 0;
}
2、运行结果:
成功:
失败: