一,绪论
1.课题背景
Linux下有系统提供的getpass()函数,可由于写的时候太早了,只支持8位字符,同时有安全隐患(溢出!),Linux出于对密码的保密,输入的字符是不会显示到屏幕上的。在登陆函数和密码修改函数内都没有提供密码回显提示,但是此设计对于一般的桌面级应用的初级用户带来了一定的麻烦,而且,没有任何密码遗忘提示功能,一旦遗忘,只能重设,作为用户定制功能,如何在linux c下实现密码回显和提示功能的登录和密码修改模块呢。
2.参考资料
Linux编程技术详解 杜华 编著 人民邮电出版社
二,实现过程
1.首先,我编写了在windows c下的密码回显的代码
程序1.c代码如下:
#include <stdio.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
#define MIN_INPUT 0x20
#define MAX_INPUT 0x7e
/*
* 所有功能有此函数实现:
* pszPw : 保存密码的缓冲
* iMaxSize :最大的密码长度,该长度必须小于缓冲区大小。
* 返回值为TRUE为成功获取密码。总是返回TRUE
*/
int GetPassword(unsigned char* pszPw,int iMaxSize)
{
unsigned char ch;
int i=0;
int bIsEcho=TRUE;
//while( ! kbhit() && i<iMaxSize )
while( ( ch = (unsigned char)getch() ) && i < iMaxSize )
{
//ch = (unsigned char)getch();
bIsEcho=TRUE;
if ( ch == 13)
{
pszPw[i++]=0;
break;
}
else if ( ch >= MIN_INPUT && ch <= MAX_INPUT) /*所有可打印字符*/
{
pszPw[i++]=ch;
}
else if ( ch == 8 && i> 0 ) /*退格键*/
{
pszPw[i--] = 0;
bIsEcho = FALSE;
putchar( ch );
putchar( ' ' );
putchar( ch );
}
else
bIsEcho = FALSE;
If(bIsEcho)
putchar('*');
}
pszPw[i]=0;
return TRUE;
}
int main(void)
{
int iMaxSize=80;
unsigned char pw[99];
if ( GetPassword(pw,iMaxSize) == TRUE )
{
printf("/npassword=%s",pw);
}
Else
{
printf("/nCan not get the password!");
}
}
经过在虚拟机下的编译,该程序却无法执行,估计原因应该是没有相应的c类库,所以开始查阅资料
2..使用curses库
curses库是由柏克莱大学的Bill Joy及Ken Arnold所开发的。当时开发curses库的目的是为了解决程序对于不同终端的兼容性。curses库用于处理Linux/UNIX上的光标移动及屏幕显示问题。考虑到curses库的复杂性,这里只是简单地介绍一下curses库的使用。需要这方面详细信息可以查阅相关资料。
使用curses库中的函数前,需要进行必要的初始化工作。程序需要使用initscr函数来开启curses模式,在结束前调用endwin函数来关闭curses模式。代码如下:
#include <curses.h>
int main(int argc,char* argv[])
{
initscr();
…
endwin();
}
在实际使用中,出于方便的目的,往往把一些初始化的动作放置在初始化函数中,以方便调用。具体代码如下:
void initial()
{
initscr();
cbreak();
nl();
noecho();
intrflush(stdscr,FALSE);
keypad(stdscr,TRUE);
refresh();
}
代码中使用到了一些curses库的函数,含义如下。
l cbreak():调用cbreak函数后,除了“Del”和“Ctrl”键外,接受其他所有字符输入。
l nl()/nonl():输出时,换行是否作为回车字符。nl函数将换行作为回车符,而nonl数相反。
l noecho()/echo():关闭/打开输入回显功能。
l intrflush(WINDOW *win, bool bf):win为标准输出。当bf为true时输入Break,可以加快中断的响应。但是,有可能会造成屏幕输出信息的混乱。
l keypad(WINDOW *win, bool bf):win为标准输出。调用keypad函数后,将可以使用键盘上的一些特殊字符,如方向键,转化成curses.h中的特殊键。
lrefresh():重绘屏幕显示内容。在调用initscr函数后,第一次调用refresh函数会清除屏幕显示。
程序2.c给出了使用curses库实现密码输入、屏蔽输出结果的实例。具体代码如下:
//2.c使用curses实现密码输入
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
void init()
{
initscr();
cbreak();
nl();
noecho();
intrflush(stdscr,FALSE);
keypad(stdscr,TRUE);
refresh();
}
int getpasswd(char* passwd, int size)
{
int c;
int n = 0;
printw("Please Input password:");
do{
c = getch();
if (c != '/n'){
echochar('*');//printw("*");
passwd[n++] = c;
}
}while(c != '/n' && n < (size - 1));
passwd[n] = '/0';
return n;
}
int main()
{
char passwd[20];
int n;
init();
n=getpasswd(passwd, sizeof(passwd));
printw("/nYour passwd is:%s/n", passwd);
printw("Press any key continue .../n");
refresh();
getchar();
endwin();
return 0;
}
使用gcc编译该程序,获得名为2的可执行程序。注意程序中使用了curses库,因此编译时要指明该库的名称。具体编译和执行情况如下:
[program@localhost charter6]$ gcc -o 2 2.c -lcurses
[program@localhost charter6]$ ./2
Please Input password:*******
Your passwd is:afdafds
Press any key continue ...
3.使用tcgetattr函数和tcsetattr函数
经查阅资料,还有种方法,可以不使用curses库解决密码输入的回显问题。程序3.c通过使用tcgetattr函数和tcsetattr函数同样达到了目的。具体代码如下:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
//函数set_disp_mode用于控制是否开启输入回显功能
//如果option为0,则关闭回显,为1则打开回显
int set_disp_mode(int fd,int option)
{
int err;
struct termios term;
if(tcgetattr(fd,&term)==-1){
perror("Cannot get the attribution of the terminal");
return 1;
}
if(option)
term.c_lflag|=ECHOFLAGS;
else
term.c_lflag &=~ECHOFLAGS;
err=tcsetattr(fd,TCSAFLUSH,&term);
if(err==-1 && err==EINTR){
perror("Cannot set the attribution of the terminal");
return 1;
}
return 0;
}
//函数getpasswd用于获得用户输入的密码,并将其存储在指定的字符数组中
int getpasswd(char* passwd, int size)
{
int c;
int n = 0;
printf("Please Input password:");
do{
c=getchar();
if (c != '/n'|c!='/r'){
passwd[n++] = c;
}
}while(c != '/n' && c !='/r' && n < (size - 1));
passwd[n] = '/0';
return n;
}
int main()
{
char passwd[20];
//首先关闭输出回显,这样输入密码时就不会显示输入的字符信息
set_disp_mode(STDIN_FILENO,0);
//调用getpasswd函数获得用户输入的密码
getpasswd(passwd, sizeof(passwd));
printf("/nYour passwd is:%s/n", passwd);
printf("Press any key continue .../n");
set_disp_mode(STDIN_FILENO,1);
getchar();
return 0;
}
使用gcc编译3.c代码,获得名为3的可执行程序。执行该程序,得到如下的输出结果:
[program@localhost charter6]$ gcc -o 3 3.c
[program@localhost charter6]$ ./3
Please Input password:
Your passwd is:afdfasf
Press any key continue ...
[program@localhost charter6]$
三,结论
通过这个小小的程序,反映了Linux的C环境与windows下还是有一些区别的。