【问题标题】:Getting a password in C without using getpass (3)?不使用 getpass (3) 在 C 中获取密码?
【发布时间】:2012-09-16 20:11:54
【问题描述】:

我可以使用getpass() 来获取密码。但是,手册页说:

此功能已过时。不使用 它。

以符合 POSIX 的方式从用户终端获取密码而不回显密码的当前方法是什么? [最初我说的是“便携”,但我的意图是避免使用过时的功能。]

【问题讨论】:

  • 没有可移植的方式 - 这在很大程度上取决于您的平台。
  • @Jerry,这不值得……尽管它是 LEGACY,但它是最便携的方式。

标签: c passwords


【解决方案1】:

您可以使用ncurses 库从标准输入中读取,而无需将结果回显到屏幕上。 (在获得任何意见之前,请致电noecho())。该库已经存在了很长时间,并且可以在各种平台上运行(可以找到 Windows 版本here

【讨论】:

  • 我做了一个简单的curses应用程序(自从我使用curses已经好几年了),发现当我执行initscr()时它清除了屏幕。可能有一些方法可以解决这个问题,但通过快速阅读手册页并不明显。
【解决方案2】:

在 Windows 上,您可能可以使用 SetConsoleMode api,描述为 here

【讨论】:

    【解决方案3】:

    根据University of Milwaukee's documentation,它已过时,因为:

    getpass() 函数不是线程安全的,因为它操作 全局信号状态。

    getpass() 函数计划从 X/Open CAE 规范的未来版本中撤消。

    【讨论】:

    • 自 2001 年起已从 POSIX/Single UNIX(X/Open 的继承者)中退出。
    • 这是一个怎样的答案?这真的应该是一个评论。
    【解决方案4】:

    这应该适用于 linux/macosx,windows 版本应该使用Get/Set ConsoleMode

    #include <stdio.h>
    #include <stdlib.h>
    #include <termios.h>
    
    int
    main(int argc, char **argv)
    {
        struct termios oflags, nflags;
        char password[64];
    
        /* disabling echo */
        tcgetattr(fileno(stdin), &oflags);
        nflags = oflags;
        nflags.c_lflag &= ~ECHO;
        nflags.c_lflag |= ECHONL;
    
        if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
            perror("tcsetattr");
            return EXIT_FAILURE;
        }
    
        printf("password: ");
        fgets(password, sizeof(password), stdin);
        password[strlen(password) - 1] = 0;
        printf("you typed '%s'\n", password);
    
        /* restore terminal */
        if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
            perror("tcsetattr");
            return EXIT_FAILURE;
        }
    
        return 0;
    }
    

    【讨论】:

    • 这对我来说似乎是最直接的方法。
    • 在尝试 stdin 之前应该先使用 /dev/tty,就像使用管道一样,stdin 将是管道内容,而不是终端输入。
    • 我不介意看到 char password[64] = {0};或者如果它是可重入的,则在使用之前的 memset
    • password[strlen(password) - 1] = 0; - 这是非常错误的。
    • password[strlen(password) - 1] = 0; 仅删除存在的换行符,否则会错误地删除密码的最后一个字符。 password[ strcspn( password, "\n" ) ] = '\0'works all the time.
    【解决方案5】:

    尽管这是一个已经回答的非常古老的问题,但这是我一直在使用的(与接受的答案非常相似):

    #include <termios.h>
    #include <cstdio>
    
    //
    // The following is a slightly modifed version taken from:
    // http://www.gnu.org/software/libc/manual/html_node/getpass.html
    //
    ssize_t my_getpass (char *prompt, 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;
    
        /* Display the prompt */
        if (prompt)
            printf("%s", prompt);
    
        /* Read the password. */
        nread = getline (lineptr, n, stream);
    
        /* Remove the carriage return */
        if (nread >= 1 && (*lineptr)[nread - 1] == '\n')
        {
            (*lineptr)[nread-1] = 0;
            nread--;
        }
        printf("\n");
    
        /* Restore terminal. */
        (void) tcsetattr (fileno (stream), TCSAFLUSH, &_old);
    
        return nread;
    }
    
    //
    // Test harness - demonstrate calling my_getpass().
    //
    int main(int argc, char *argv[])
    {
        size_t maxlen = 255;
        char pwd[maxlen];
        char *pPwd = pwd; // <-- haven't figured out how to avoid this.
    
        int count = my_getpass((char*)"Enter Password: ", &pPwd, &maxlen, stdin);
    
        printf("Size of password: %d\nPassword in plaintext: %s\n", count, pwd);
    
        return 0;
    }
    

    【讨论】:

    • 我好样的。这甚至可以让您从命令行输入密码;但是,如果您要这样做,那么您可能不想打印出密码提示。
    【解决方案6】:

    另一个简单的 Windows 解决方案。 包括“conio.h”

      for (;;) {
      int c = _getch();
      switch (c)
      {
      case '\r':
      case '\n':
      case EOF:
        _putch('\n');
        break;
    
      default:
        _putch('*'); //mask
        thePassword += char(c);
        continue;
      }
      break;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-12
      相关资源
      最近更新 更多