隐藏终端上的密码输入

新手上路,请多包涵

我想在用 * 编写密码时屏蔽我的密码。我对这段代码使用 Linux GCC。我知道一种解决方案是使用 getch() 像这样的功能

#include <conio.h>
int main()
{
    char c,password[10];
    int i;
    while( (c=getch())!= '\n');{
        password[i] = c;
        printf("*");
        i++;
    }
    return 1;
}

但问题是 GCC 不包括 conio.h 文件,所以 getch() 对我没用。有没有人有办法解决吗?

原文由 Hit‘s 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 502
2 个回答

在 Linux 世界中,通常不使用星号进行屏蔽,通常只是关闭回显并且终端显示空白例如,如果您使用 su 或登录到虚拟终端等。

有一个库函数来处理获取密码,它不会用星号掩盖密码,但会禁用将密码回显到终端。我把它从我有的一本 linux 书里拿出来了。我相信它是posix标准的一部分

> #include <unistd.h>
> char *getpass(const char *prompt);
>
> /*Returns pointer to statically allocated input password string
> on success, or NULL on error*/
>
> ```
>
> getpass() 函数首先禁用回显和终端特殊字符(例如中断字符,通常是 Control-C)的所有处理。
>
> 然后它打印提示指向的字符串,并读取一行输入,返回以空字符结尾的输入字符串,去掉尾随的换行符,作为其函数结果。

谷歌搜索 getpass() 参考了 GNU 实现(应该在大多数 linux 发行版中)和一些示例代码,如果需要的话,可以实现你自己的

[http://www.gnu.org/s/hello/manual/libc/getpass.html](http://www.gnu.org/s/hello/manual/libc/getpass.html)

他们自己滚动的例子:

#include #include

ssize_t my_getpass (char **lineptr, size_t *n, FILE *stream) { struct termios old, new; int nread;

/* Turn echoing off and fail if we can't. */
if (tcgetattr (fileno (stream), &old) != 0)
    return -1;
new = old;
new.c_lflag &= ~ECHO;
if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
    return -1;

/* Read the password. */
nread = getline (lineptr, n, stream);

/* Restore terminal. */
(void) tcsetattr (fileno (stream), TCSAFLUSH, &old);

return nread;

}

”`

如果需要,您可以以此为基础修改它以显示星号。

原文由 matt 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果没有 getch 依赖和避免过时的 getpass ,推荐的方法是禁用终端 ECHO 通过 termios 使用。经过几次搜索以找到一个固定的灵活密码例程后,我很惊讶很少有人可以与 C 一起独立使用。而不是简单地重新编码 getch 与 termios c_lflag 选项,稍微多一点通用方法只需要添加一些内容。除了替换 getch 任何例程都应强制指定最大长度以防止溢出,如果用户尝试输入超出最大值则截断,并在以某种方式发生截断时发出警告。

下面,添加的内容将允许从任何 FILE * 输入流中读取,将长度限制为指定长度,在接受输入时提供最小的编辑(退格)能力,允许指定或完全禁用字符掩码,以及最后返回输入密码的长度。当输入的密码被截断到最大或指定长度时,添加了一条警告。

希望它对寻找类似解决方案的这个问题的其他人有用:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

#define MAXPW 32

/* read a string from fp into pw masking keypress with mask char.
getpasswd will read upto sz - 1 chars into pw, null-terminating
the resulting string. On success, the number of characters in
pw are returned, -1 otherwise.
*/
ssize_t getpasswd (char **pw, size_t sz, int mask, FILE *fp)
{
    if (!pw || !sz || !fp) return -1;       /* validate input   */
#ifdef MAXPW
    if (sz > MAXPW) sz = MAXPW;
#endif

    if (*pw == NULL) {              /* reallocate if no address */
        void *tmp = realloc (*pw, sz * sizeof **pw);
        if (!tmp)
            return -1;
        memset (tmp, 0, sz);    /* initialize memory to 0   */
        *pw =  (char*) tmp;
    }

    size_t idx = 0;         /* index, number of chars in read   */
    int c = 0;

    struct termios old_kbd_mode;    /* orig keyboard settings   */
    struct termios new_kbd_mode;

    if (tcgetattr (0, &old_kbd_mode)) { /* save orig settings   */
        fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__);
        return -1;
    }   /* copy old to new */
    memcpy (&new_kbd_mode, &old_kbd_mode, sizeof(struct termios));

    new_kbd_mode.c_lflag &= ~(ICANON | ECHO);  /* new kbd flags */
    new_kbd_mode.c_cc[VTIME] = 0;
    new_kbd_mode.c_cc[VMIN] = 1;
    if (tcsetattr (0, TCSANOW, &new_kbd_mode)) {
        fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
        return -1;
    }

    /* read chars from fp, mask if valid char specified */
    while (((c = fgetc (fp)) != '\n' && c != EOF && idx < sz - 1) ||
            (idx == sz - 1 && c == 127))
    {
        if (c != 127) {
            if (31 < mask && mask < 127)    /* valid ascii char */
                fputc (mask, stdout);
            (*pw)[idx++] = c;
        }
        else if (idx > 0) {         /* handle backspace (del)   */
            if (31 < mask && mask < 127) {
                fputc (0x8, stdout);
                fputc (' ', stdout);
                fputc (0x8, stdout);
            }
            (*pw)[--idx] = 0;
        }
    }
    (*pw)[idx] = 0; /* null-terminate   */

    /* reset original keyboard  */
    if (tcsetattr (0, TCSANOW, &old_kbd_mode)) {
        fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
        return -1;
    }

    if (idx == sz - 1 && c != '\n') /* warn if pw truncated */
        fprintf (stderr, " (%s() warning: truncated at %zu chars.)\n",
                __func__, sz - 1);

    return idx; /* number of chars in passwd    */
}

一个显示使用的简单程序如下。如果使用静态字符数组来保存密码,只需确保将指针传递给函数。

 int main (void ) {

    char pw[MAXPW] = {0};
    char *p = pw;
    FILE *fp = stdin;
    ssize_t nchr = 0;

    printf ( "\n Enter password: ");
    nchr = getpasswd (&p, MAXPW, '*', fp);
    printf ("\n you entered   : %s  (%zu chars)\n", p, nchr);

    printf ( "\n Enter password: ");
    nchr = getpasswd (&p, MAXPW, 0, fp);
    printf ("\n you entered   : %s  (%zu chars)\n\n", p, nchr);

    return 0;
}

示例输出

$ ./bin/getpasswd2

 Enter password: ******
 you entered   : 123456  (6 chars)

 Enter password:
 you entered   : abcdef  (6 chars)

原文由 David C. Rankin 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题