@HUST张友东 work@taobao zyd_com@126.com
分类: LINUX
2011-01-20 10:36:00
实现linux登录验证的程序,要考虑两个部分,第一是用户名、密码的输入;第二是用户、密码的验证,关于第二部分的机制已经在http://blog168.chinaunix.net/space.php?uid=20196318&do=blog&id=94771中讲到。
而第一部分的难点则在于如何在输入密码时不回显输入的字符,这就需要更改终端的属性,涉及终端IO的编程,主要用到tcgetattr和setattr两个函数,通过取消终端的ECHO标记,即可禁用终端回显,在密码输入处理之后,要记得恢复终端原来的属性,避免影响到其它的进程。
终端IO处理大致过程如下:
struct termios ts, ots;
/* 禁用终端回显 */
ts.c_lflag &= ~ECHO;
ts.c_lflag |= ECHONL;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts);
/* 在这里插入输入密码的代码 */
/* 恢复终端原来的属性 */
tcsetattr(STDIN_FILENO, TCSANOW, &ots);
实例:(为方便coding,输入与认证一同处理,使用gets存在缓冲区溢出的隐患,应使用getline或gets,使用时要注意去掉末尾的换行符)
#include
#include
#include
#include
#include
#include
#define AUTH_SIZE 1024
int main(int argc, char* argv[])
{
struct termios ts, ots;
char userbuf[AUTH_SIZE];
char passbuf[AUTH_SIZE];
tcgetattr(STDIN_FILENO, &ts);
ots = ts;
printf("Login:");
fflush(stdout);
gets(userbuf);
/* 禁用终端回显 */
ts.c_lflag &= ~ECHO;
ts.c_lflag |= ECHONL;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts);
printf("Password:");
fflush(stdout);
gets(passbuf);
struct spwd *sp = getspnam(userbuf);
if(sp == NULL) {
printf("set sp error\n");
}
/* 验证用户名、密码的正确性 */
if(!strcmp(sp->sp_pwdp, (char*)crypt(passbuf, sp->sp_pwdp))) {
printf("correct\n");
}
else {
printf("user or password error\n");
}
/* 恢复终端原来的属性 */
tcsetattr(STDIN_FILENO, TCSANOW, &ots);
return 0;
}