sshd_test_pw.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // sshd_test_pw.c
  5. // Wrapper to inject test password data for sshd PAM authentication
  6. //
  7. // This wrapper implements custom versions of getpwnam, getpwnam_r,
  8. // getspnam and getspnam_r. These functions first call their real
  9. // libc versions, then check if the requested user matches test user
  10. // specified in env variable TEST_USER and if so replace the password
  11. // with crypted() value of TEST_PASSWD env variable.
  12. //
  13. // Compile:
  14. // gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
  15. //
  16. // Compile with debug:
  17. // gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
  18. //
  19. // Run sshd:
  20. // LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
  21. // +build ignore
  22. #define _GNU_SOURCE
  23. #include <string.h>
  24. #include <pwd.h>
  25. #include <shadow.h>
  26. #include <dlfcn.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <stdio.h>
  30. #ifdef VERBOSE
  31. #define DEBUG(X...) fprintf(stderr, X)
  32. #else
  33. #define DEBUG(X...) while (0) { }
  34. #endif
  35. /* crypt() password */
  36. static char *
  37. pwhash(char *passwd) {
  38. return strdup(crypt(passwd, "$6$"));
  39. }
  40. /* Pointers to real functions in libc */
  41. static struct passwd * (*real_getpwnam)(const char *) = NULL;
  42. static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
  43. static struct spwd * (*real_getspnam)(const char *) = NULL;
  44. static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
  45. /* Cached test user and test password */
  46. static char *test_user = NULL;
  47. static char *test_passwd_hash = NULL;
  48. static void
  49. init(void) {
  50. /* Fetch real libc function pointers */
  51. real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
  52. real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
  53. real_getspnam = dlsym(RTLD_NEXT, "getspnam");
  54. real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
  55. /* abort if env variables are not defined */
  56. if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
  57. fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
  58. abort();
  59. }
  60. /* Fetch test user and test password from env */
  61. test_user = strdup(getenv("TEST_USER"));
  62. test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
  63. DEBUG("sshd_test_pw init():\n");
  64. DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
  65. DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
  66. DEBUG("\treal_getspnam: %p\n", real_getspnam);
  67. DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
  68. DEBUG("\tTEST_USER: '%s'\n", test_user);
  69. DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
  70. DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
  71. }
  72. static int
  73. is_test_user(const char *name) {
  74. if (test_user != NULL && strcmp(test_user, name) == 0)
  75. return 1;
  76. return 0;
  77. }
  78. /* getpwnam */
  79. struct passwd *
  80. getpwnam(const char *name) {
  81. struct passwd *pw;
  82. DEBUG("sshd_test_pw getpwnam(%s)\n", name);
  83. if (real_getpwnam == NULL)
  84. init();
  85. if ((pw = real_getpwnam(name)) == NULL)
  86. return NULL;
  87. if (is_test_user(name))
  88. pw->pw_passwd = strdup(test_passwd_hash);
  89. return pw;
  90. }
  91. /* getpwnam_r */
  92. int
  93. getpwnam_r(const char *name,
  94. struct passwd *pwd,
  95. char *buf,
  96. size_t buflen,
  97. struct passwd **result) {
  98. int r;
  99. DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
  100. if (real_getpwnam_r == NULL)
  101. init();
  102. if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
  103. return r;
  104. if (is_test_user(name))
  105. pwd->pw_passwd = strdup(test_passwd_hash);
  106. return 0;
  107. }
  108. /* getspnam */
  109. struct spwd *
  110. getspnam(const char *name) {
  111. struct spwd *sp;
  112. DEBUG("sshd_test_pw getspnam(%s)\n", name);
  113. if (real_getspnam == NULL)
  114. init();
  115. if ((sp = real_getspnam(name)) == NULL)
  116. return NULL;
  117. if (is_test_user(name))
  118. sp->sp_pwdp = strdup(test_passwd_hash);
  119. return sp;
  120. }
  121. /* getspnam_r */
  122. int
  123. getspnam_r(const char *name,
  124. struct spwd *spbuf,
  125. char *buf,
  126. size_t buflen,
  127. struct spwd **spbufp) {
  128. int r;
  129. DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
  130. if (real_getspnam_r == NULL)
  131. init();
  132. if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
  133. return r;
  134. if (is_test_user(name))
  135. spbuf->sp_pwdp = strdup(test_passwd_hash);
  136. return r;
  137. }