logo

checkpassword-ng

Uniform password checking interface for applications

chkpw.c (1785B)


  1. // checkpassword-ng: Uniform password checking interface for applications
  2. // Copyright © 2021 checkpassword-ng Authors <https://hacktivis.me/git/checkpassword-ng>
  3. // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
  4. #define _POSIX_C_SOURCE 200809L
  5. #include "chkpw.h"
  6. #include <assert.h> /* assert */
  7. #include <errno.h> /* errno */
  8. #include <pwd.h> /* getpwnam */
  9. #include <stdio.h> /* sprintf() */
  10. #include <string.h> /* strerror, strcmp */
  11. #include <unistd.h> /* crypt, sleep */
  12. #ifdef __GLIBC__
  13. // GNU's Not POSIX
  14. #include <crypt.h>
  15. #endif
  16. #ifdef __linux__
  17. // I love linux extensions (no)
  18. #include <shadow.h> /* getspnam */
  19. #endif
  20. char strerror_buf[1024];
  21. struct chkpw_extra
  22. {
  23. // intentionally left blank
  24. } chkpw_extra;
  25. static void
  26. safe_strerror(char *desc, int errnum)
  27. {
  28. char *err = strerror(errnum);
  29. snprintf(strerror_buf, 1024, "%s: %s", desc, err);
  30. }
  31. char *
  32. chkpw_shadow(const char *username, const char *password, struct chkpw_extra *chkpw_extra)
  33. {
  34. (void)chkpw_extra;
  35. char *pw_hash = "";
  36. struct passwd *pwent = getpwnam(username);
  37. if(!pwent)
  38. {
  39. safe_strerror("getpwnam", errno);
  40. return strerror_buf;
  41. }
  42. assert(pwent->pw_passwd);
  43. pw_hash = pwent->pw_passwd;
  44. if(strcmp(pw_hash, "") == 0)
  45. {
  46. return CHKPW_EMPTY;
  47. }
  48. if(strcmp(pw_hash, "x") == 0)
  49. {
  50. #ifdef __linux__
  51. struct spwd *swent = getspnam(username);
  52. if(!swent)
  53. {
  54. safe_strerror("getspnam", errno);
  55. return strerror_buf;
  56. }
  57. pw_hash = swent->sp_pwdp;
  58. #else /* __linux__ */
  59. return "Invalid password entry";
  60. #endif
  61. }
  62. char *chk_hash = crypt(password, pw_hash);
  63. if(chk_hash == NULL)
  64. {
  65. safe_strerror("crypt", errno);
  66. return strerror_buf;
  67. }
  68. if(strcmp(chk_hash, pw_hash) == 0)
  69. {
  70. return CHKPW_VALID;
  71. }
  72. else
  73. {
  74. sleep(2);
  75. return CHKPW_INVALID;
  76. }
  77. assert(1);
  78. }