隐藏终端上的密码输入

Hit*_*t's 53 c linux

我想用它来掩盖我的密码*.我使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

小智 47

在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*/
Run Code Online (Sandbox Code Playgroud)

getpass()函数首先禁用回显和终端特殊字符的所有处理(例如中断字符,通常是Control-C).

然后它打印由prompt指向的字符串,并读取一行输入,返回以null结尾的输入字符串,并删除尾随的换行符作为其函数结果.

谷歌搜索getpass()有一个GNU实现的引用(应该在大多数Linux发行版中)和一些示例代码,如果需要,可以实现自己的

http://www.gnu.org/s/hello/manual/libc/getpass.html

他们推出自己的例子:

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

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;
}
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以使用此作为基础修改它以显示星号.

  • 根据man getpass功能已经过时:"这个功能已经过时了.不要使用它." (11认同)

Dav*_*ica 11

getch依赖和避免过时getpass,推荐的方法是通过termios使用禁用终端ECHO .经过几次搜索找到一个固定的灵活密码例程后,我很惊讶很少有人单独使用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    */
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

示例输出

$ ./bin/getpasswd2

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

 Enter password:
 you entered   : abcdef  (6 chars)
Run Code Online (Sandbox Code Playgroud)


Del*_*ani 9

的功能getch(这是一个非标准的,视窗函数)可以与该代码进行仿真:

#include <termios.h>
#include <unistd.h>
int getch() {
    struct termios oldt, newt;
    int ch;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}
Run Code Online (Sandbox Code Playgroud)

请注意,您的方法并不完美 - 最好使用像ncurses或其他终端库这样的东西来处理这些事情.


Sus*_*Pal 6

您可以通过getch()这种方式在Linux上创建自己的功能.

int getch() {
    struct termios oldtc, newtc;
    int ch;
    tcgetattr(STDIN_FILENO, &oldtc);
    newtc = oldtc;
    newtc.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newtc);
    ch=getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldtc);
    return ch;
}
Run Code Online (Sandbox Code Playgroud)

演示代码:

int main(int argc, char **argv) {
    int ch;
    printf("Press x to exit.\n\n");
    for (;;) {
        ch = getch();
        printf("ch = %c (%d)\n", ch, ch);
        if(ch == 'x')
              break;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)