logo

skeud

Simple and portable utilities to deal with user accounts (su, login)git clone https://anongit.hacktivis.me/git/skeud.git/

common.c (2513B)


  1. // SPDX-FileCopyrightText: 2022 Haelwenn (lanodan) Monnier <contact+skeud@hacktivis.me>
  2. // SPDX-License-Identifier: MPL-2.0
  3. #define _POSIX_C_SOURCE 200809L
  4. // for explicit_bzero and termios
  5. #define _DEFAULT_SOURCE
  6. #include "common.h"
  7. #include <errno.h> // errno
  8. #include <stdio.h> // fclose, fopen, fprintf, perror, getline, fileno
  9. #include <string.h> // explicit_bzero
  10. #include <termios.h> // tcgetattr, tcsetattr
  11. #include <unistd.h> // crypt
  12. size_t
  13. smin(size_t a, size_t b)
  14. {
  15. return a < b ? a : b;
  16. }
  17. // Needs to be constant-time so the hash can't be guessed via using a rainbow-table
  18. bool
  19. hash_match(const char *a, const char *b)
  20. {
  21. /* flawfinder: ignore CWE-126 */
  22. size_t len_a = strlen(a);
  23. /* flawfinder: ignore CWE-126 */
  24. size_t len_b = strlen(b);
  25. size_t n = smin(len_a, len_b);
  26. bool ret = true;
  27. for(size_t i = 0; i < n; i++)
  28. if(a[i] != b[i]) ret = false;
  29. if(len_a != len_b)
  30. return false;
  31. else
  32. return ret;
  33. }
  34. bool
  35. skeud_crypt_check(const char *hash, const char *password)
  36. {
  37. if(!hash) return false;
  38. if(strcmp(hash, "") == 0) return false;
  39. /* flawfinder: ignore CWE-327, crypt is the only relevant function */
  40. char *chk_hash = crypt(password, hash);
  41. if(chk_hash == NULL)
  42. {
  43. perror("skeud_crypt_check: error: crypt");
  44. return false;
  45. }
  46. bool match = hash_match(hash, chk_hash);
  47. // cleanup
  48. chk_hash = crypt("", hash);
  49. return match;
  50. }
  51. ssize_t
  52. skeud_getpass(char **password)
  53. {
  54. struct termios t;
  55. size_t len = 0;
  56. ssize_t got = -1;
  57. /* flawfinder: ignore CWE-362 */
  58. FILE *tty = fopen("/dev/tty", "rb+");
  59. if(tty == NULL)
  60. {
  61. perror("skeud_getpass: error: open(\"/dev/tty\")");
  62. return got;
  63. }
  64. int tty_fd = fileno(tty);
  65. if(tty_fd < 0)
  66. {
  67. perror("skeud_getpass: error: fileno(tty)");
  68. goto getpass_end;
  69. }
  70. if(tcgetattr(tty_fd, &t) < 0)
  71. {
  72. perror("skeud_getpass: error: tcgetattr");
  73. goto getpass_end;
  74. }
  75. fprintf(tty, "Password: ");
  76. t.c_lflag &= ~ECHO;
  77. if(tcsetattr(tty_fd, TCSANOW, &t) < 0)
  78. {
  79. perror("skeud_getpass: error: tcsetattr(~ECHO)");
  80. goto getpass_end;
  81. }
  82. errno = 0;
  83. got = getline(password, &len, tty);
  84. if(got < 0)
  85. {
  86. if(errno != 0) perror("skeud_getpass: error: getline");
  87. goto getpass_clean;
  88. }
  89. fprintf(tty, "\n");
  90. (*password)[got] = 0;
  91. (*password)[got - 1] = 0;
  92. got--;
  93. getpass_clean:
  94. t.c_lflag ^= ECHO;
  95. if(tcsetattr(tty_fd, TCSANOW, &t) < 0)
  96. {
  97. perror("skeud_getpass: error: tcsetattr(ECHO)");
  98. explicit_bzero(password, got);
  99. got = -1;
  100. goto getpass_end;
  101. }
  102. getpass_end:
  103. fclose(tty);
  104. return got;
  105. }