Unix 不回显输入密码

本文介绍了两种在Linux环境下实现密码输入时屏幕不显示的方法:一种是使用curses库,另一种是利用tcgetattr和tcsetattr函数。这两种方法都能有效地保护用户的密码安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原帖见: http://blog.163.com/xiaolei-li/blog/static/114404451200911172155783/


在软件开发中,往往会遇到要求用户输入密码的情况。出于对密码的保密,输入的字符是不会显示到屏幕上的。例如,在登录Linux系统时,输入用户名后,输入的密码是不显示的。这里介绍两种方法来解决这一问题。

6.5.1  使用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中的特殊键。

l     refresh():重绘屏幕显示内容。在调用initscr函数后,第一次调用refresh函数会清除屏幕显示。

程序p6.3.c给出了使用curses库实现密码输入、屏蔽输出结果的实例。具体代码如下:

//p6.3.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编译该程序,获得名为p6.5的可执行程序。注意程序中使用了curses库,因此编译时要指明该库的名称。具体编译和执行情况如下:

[program@localhost charter6]$ gcc -o p6.3 p6.3.c -lcurses

[program@localhost charter6]$ ./p6.3

Please Input password:*******

Your passwd is:afdafds

Press any key continue ...

6.5.2  使用tcgetattr函数和tcsetattr函数

还有种方法,可以不使用curses库解决密码输入的回显问题。程序p6.4.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编译p6.4.c代码,获得名为p6.4的可执行程序。执行该程序,得到如下的输出结果:

[program@localhost charter6]$ gcc -o p6.4 p6.4.c

[program@localhost charter6]$ ./p6.4

Please Input password:

Your passwd is:afdfasf

Press any key continue ...

[program@localhost charter6]$

### C语言中输入回显的原因 在标准的C语言环境中,默认情况下,字符输入会显示在终端上。然而,在某些特定场景下,可能希望隐藏用户的输入,比如密码输入时。这通常通过修改终端设置来实现。 对于Linux环境下的程序,`conio.h`库并适用,因为这是Windows特有的头文件[^3]。为了实现在Linux环境下输入回显的效果,可以通过调用系统命令临时关闭终端的回显功能: ```c #include <stdio.h> #include <stdlib.h> void getPasswd(const char *prompt) { char c; int i = 0; char passwd[64]=""; printf("%s", prompt); system("stty -echo"); // 关闭输入回显 while ((c=getchar()) != '\n') { passwd[i++] = c; } passwd[i] = '\0'; system("stty echo"); // 打开输入回显 putchar('\n'); } ``` 上述代码展示了如何利用`system()`函数执行shell指令改变终端属性的方法。具体来说,`stty -echo`用于禁用按键回显;相反地,`stty echo`恢复默认行为。 ### 实现跨平台兼容性的解决方案 考虑到同操作系统之间的差异,如果想要编写能够同时适用于Windows和Unix-like系统的应用程序,则应该考虑采用更通用的方式处理这个问题。POSIX标准提供了一套接口允许开发者调整TTY设备的行为而依赖于具体的OS特性。例如,可以使用`termios`结构体中的成员变量配置新的终端模式并应用到当前会话中。 下面给出一段基于POSIX API的例子,它可以在大多数类UNIX平台上工作良好: ```c #ifdef __unix__ #include <unistd.h> /* POSIX */ #elif defined(_WIN32) #include <windows.h> /* Windows API */ #endif #include <stdio.h> #include <string.h> #include <termios.h> void disableEchoMode(int fd, struct termios* orig_termios){ tcgetattr(fd, orig_termios); /* save the terminal attributes */ struct termios raw = *orig_termios; raw.c_lflag &= ~(ECHO | ICANON); /* turn off ECHO and CANONICAL mode*/ tcsetattr(fd,TCSAFLUSH,&raw); /* apply new settings immediately */ } void restoreEchoMode(int fd, const struct termios* orig_termios){ tcsetattr(fd,TCSAFLUSH,orig_termios); /* restore original terminal attrs */ } int main(){ struct termios stored_settings; printf("Enter password:"); fflush(stdout); disableEchoMode(STDIN_FILENO, &stored_settings); char passwrd[BUFSIZ]; fgets(passwrd,sizeof(passwrd),stdin); restoreEchoMode(STDIN_FILENO, &stored_settings); puts(""); printf("You entered:%s\n",passwrd); return 0; } ``` 这段代码首先保存了原始的终端参数,接着更改这些参数以移除回显标志位(`ECHO`)以及取消缓冲区满才发送数据的要求(`ICANON`)。最后,在完成操作后再次设置了原有的状态确保后续交互恢复正常[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值