unix_chkpwd.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * This program is designed to run setuid(root) or with sufficient
  3. * privilege to read all of the unix password databases. It is designed
  4. * to provide a mechanism for the current user (defined by this
  5. * process's uid) to verify their own password.
  6. *
  7. * The password is read from the standard input. The exit status of
  8. * this program indicates whether the user is authenticated or not.
  9. *
  10. * Copyright information is located at the end of the file.
  11. *
  12. */
  13. #include "config.h"
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <syslog.h>
  18. #include <unistd.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <pwd.h>
  22. #include <shadow.h>
  23. #include <signal.h>
  24. #include <time.h>
  25. #include <errno.h>
  26. #ifdef HAVE_LIBAUDIT
  27. #include <libaudit.h>
  28. #endif
  29. #include <security/_pam_types.h>
  30. #include <security/_pam_macros.h>
  31. #include "passverify.h"
  32. #include "pam_inline.h"
  33. static int _check_expiry(const char *uname)
  34. {
  35. struct spwd *spent;
  36. struct passwd *pwent;
  37. int retval;
  38. int daysleft;
  39. retval = get_account_info(uname, &pwent, &spent);
  40. if (retval != PAM_SUCCESS) {
  41. helper_log_err(LOG_ERR, "could not obtain user info (%s)", uname);
  42. printf("-1\n");
  43. return retval;
  44. }
  45. if (spent == NULL) {
  46. printf("-1\n");
  47. return retval;
  48. }
  49. retval = check_shadow_expiry(spent, &daysleft);
  50. printf("%d\n", daysleft);
  51. return retval;
  52. }
  53. #ifdef HAVE_LIBAUDIT
  54. static int _audit_log(int type, const char *uname, int rc)
  55. {
  56. int audit_fd;
  57. audit_fd = audit_open();
  58. if (audit_fd < 0) {
  59. /* You get these error codes only when the kernel doesn't have
  60. * audit compiled in. */
  61. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  62. errno == EAFNOSUPPORT)
  63. return PAM_SUCCESS;
  64. helper_log_err(LOG_CRIT, "audit_open() failed: %m");
  65. return PAM_AUTH_ERR;
  66. }
  67. rc = audit_log_acct_message(audit_fd, type, NULL, "PAM:unix_chkpwd",
  68. uname, -1, NULL, NULL, NULL, rc == PAM_SUCCESS);
  69. if (rc == -EPERM && geteuid() != 0) {
  70. rc = 0;
  71. }
  72. audit_close(audit_fd);
  73. return rc < 0 ? PAM_AUTH_ERR : PAM_SUCCESS;
  74. }
  75. #endif
  76. int main(int argc, char *argv[])
  77. {
  78. char pass[PAM_MAX_RESP_SIZE + 1];
  79. char *option;
  80. int npass, nullok;
  81. int blankpass = 0;
  82. int retval = PAM_AUTH_ERR;
  83. char *user;
  84. char *passwords[] = { pass };
  85. /*
  86. * Catch or ignore as many signal as possible.
  87. */
  88. setup_signals();
  89. /*
  90. * we establish that this program is running with non-tty stdin.
  91. * this is to discourage casual use. It does *NOT* prevent an
  92. * intruder from repeatadly running this program to determine the
  93. * password of the current user (brute force attack, but one for
  94. * which the attacker must already have gained access to the user's
  95. * account).
  96. */
  97. if (isatty(STDIN_FILENO) || argc != 3 ) {
  98. helper_log_err(LOG_NOTICE
  99. ,"inappropriate use of Unix helper binary [UID=%d]"
  100. ,getuid());
  101. #ifdef HAVE_LIBAUDIT
  102. _audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
  103. #endif
  104. fprintf(stderr
  105. ,"This binary is not designed for running in this way\n"
  106. "-- the system administrator has been informed\n");
  107. sleep(10); /* this should discourage/annoy the user */
  108. return PAM_SYSTEM_ERR;
  109. }
  110. /*
  111. * Determine what the current user's name is.
  112. * We must thus skip the check if the real uid is 0.
  113. */
  114. if (getuid() == 0) {
  115. user=argv[1];
  116. }
  117. else {
  118. user = getuidname(getuid());
  119. /* if the caller specifies the username, verify that user
  120. matches it */
  121. if (user == NULL || strcmp(user, argv[1])) {
  122. user = argv[1];
  123. /* no match -> permanently change to the real user and proceed */
  124. if (setuid(getuid()) != 0)
  125. return PAM_AUTH_ERR;
  126. }
  127. }
  128. option=argv[2];
  129. if (strcmp(option, "chkexpiry") == 0)
  130. /* Check account information from the shadow file */
  131. return _check_expiry(argv[1]);
  132. /* read the nullok/nonull option */
  133. else if (strcmp(option, "nullok") == 0)
  134. nullok = 1;
  135. else if (strcmp(option, "nonull") == 0)
  136. nullok = 0;
  137. else {
  138. #ifdef HAVE_LIBAUDIT
  139. _audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
  140. #endif
  141. return PAM_SYSTEM_ERR;
  142. }
  143. /* read the password from stdin (a pipe from the pam_unix module) */
  144. npass = pam_read_passwords(STDIN_FILENO, 1, passwords);
  145. if (npass != 1) { /* is it a valid password? */
  146. helper_log_err(LOG_DEBUG, "no password supplied");
  147. *pass = '\0';
  148. }
  149. if (*pass == '\0') {
  150. blankpass = 1;
  151. }
  152. retval = helper_verify_password(user, pass, nullok);
  153. memset(pass, '\0', PAM_MAX_RESP_SIZE); /* clear memory of the password */
  154. /* return pass or fail */
  155. if (retval != PAM_SUCCESS) {
  156. if (!nullok || !blankpass) {
  157. /* no need to log blank pass test */
  158. #ifdef HAVE_LIBAUDIT
  159. if (getuid() != 0)
  160. _audit_log(AUDIT_USER_AUTH, user, PAM_AUTH_ERR);
  161. #endif
  162. helper_log_err(LOG_NOTICE, "password check failed for user (%s)", user);
  163. }
  164. /* if helper_verify_password() returned PAM_USER_UNKNOWN, the
  165. most appropriate error to propagate to
  166. _unix_verify_password() is PAM_AUTHINFO_UNAVAIL; otherwise
  167. return general failure */
  168. if (retval == PAM_USER_UNKNOWN)
  169. return PAM_AUTHINFO_UNAVAIL;
  170. else
  171. return PAM_AUTH_ERR;
  172. } else {
  173. if (getuid() != 0) {
  174. #ifdef HAVE_LIBAUDIT
  175. return _audit_log(AUDIT_USER_AUTH, user, PAM_SUCCESS);
  176. #else
  177. return PAM_SUCCESS;
  178. #endif
  179. }
  180. return PAM_SUCCESS;
  181. }
  182. }
  183. /*
  184. * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
  185. * Copyright (c) Red Hat, Inc., 2007,2008. All rights reserved
  186. *
  187. * Redistribution and use in source and binary forms, with or without
  188. * modification, are permitted provided that the following conditions
  189. * are met:
  190. * 1. Redistributions of source code must retain the above copyright
  191. * notice, and the entire permission notice in its entirety,
  192. * including the disclaimer of warranties.
  193. * 2. Redistributions in binary form must reproduce the above copyright
  194. * notice, this list of conditions and the following disclaimer in the
  195. * documentation and/or other materials provided with the distribution.
  196. * 3. The name of the author may not be used to endorse or promote
  197. * products derived from this software without specific prior
  198. * written permission.
  199. *
  200. * ALTERNATIVELY, this product may be distributed under the terms of
  201. * the GNU Public License, in which case the provisions of the GPL are
  202. * required INSTEAD OF the above restrictions. (This clause is
  203. * necessary due to a potential bad interaction between the GPL and
  204. * the restrictions contained in a BSD-style copyright.)
  205. *
  206. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  207. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  208. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  209. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  210. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  211. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  212. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  213. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  214. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  215. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  216. * OF THE POSSIBILITY OF SUCH DAMAGE.
  217. */