auth-passwd.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* $OpenBSD: auth-passwd.c,v 1.47 2018/07/09 21:26:02 markus Exp $ */
  2. /*
  3. * Author: Tatu Ylonen <ylo@cs.hut.fi>
  4. * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  5. * All rights reserved
  6. * Password authentication. This file contains the functions to check whether
  7. * the password is valid for the user.
  8. *
  9. * As far as I am concerned, the code I have written for this software
  10. * can be used freely for any purpose. Any derived versions of this
  11. * software must be clearly marked as such, and if the derived work is
  12. * incompatible with the protocol description in the RFC file, it must be
  13. * called by a name other than "ssh" or "Secure Shell".
  14. *
  15. * Copyright (c) 1999 Dug Song. All rights reserved.
  16. * Copyright (c) 2000 Markus Friedl. All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions
  20. * are met:
  21. * 1. Redistributions of source code must retain the above copyright
  22. * notice, this list of conditions and the following disclaimer.
  23. * 2. Redistributions in binary form must reproduce the above copyright
  24. * notice, this list of conditions and the following disclaimer in the
  25. * documentation and/or other materials provided with the distribution.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  28. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  29. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  30. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  32. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  33. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  34. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  35. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  36. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. */
  38. #include "includes.h"
  39. #include <sys/types.h>
  40. #include <pwd.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include <stdarg.h>
  44. #include "packet.h"
  45. #include "sshbuf.h"
  46. #include "ssherr.h"
  47. #include "log.h"
  48. #include "misc.h"
  49. #include "servconf.h"
  50. #include "sshkey.h"
  51. #include "hostfile.h"
  52. #include "auth.h"
  53. #include "auth-options.h"
  54. extern struct sshbuf *loginmsg;
  55. extern ServerOptions options;
  56. #ifdef HAVE_LOGIN_CAP
  57. extern login_cap_t *lc;
  58. #endif
  59. #define DAY (24L * 60 * 60) /* 1 day in seconds */
  60. #define TWO_WEEKS (2L * 7 * DAY) /* 2 weeks in seconds */
  61. #define MAX_PASSWORD_LEN 1024
  62. /*
  63. * Tries to authenticate the user using password. Returns true if
  64. * authentication succeeds.
  65. */
  66. int
  67. auth_password(struct ssh *ssh, const char *password)
  68. {
  69. Authctxt *authctxt = ssh->authctxt;
  70. struct passwd *pw = authctxt->pw;
  71. int result, ok = authctxt->valid;
  72. #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
  73. static int expire_checked = 0;
  74. #endif
  75. if (strlen(password) > MAX_PASSWORD_LEN)
  76. return 0;
  77. #ifndef HAVE_CYGWIN
  78. if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
  79. ok = 0;
  80. #endif
  81. if (*password == '\0' && options.permit_empty_passwd == 0)
  82. return 0;
  83. #ifdef KRB5
  84. if (options.kerberos_authentication == 1) {
  85. int ret = auth_krb5_password(authctxt, password);
  86. if (ret == 1 || ret == 0)
  87. return ret && ok;
  88. /* Fall back to ordinary passwd authentication. */
  89. }
  90. #endif
  91. #ifdef HAVE_CYGWIN
  92. {
  93. HANDLE hToken = cygwin_logon_user(pw, password);
  94. if (hToken == INVALID_HANDLE_VALUE)
  95. return 0;
  96. cygwin_set_impersonation_token(hToken);
  97. return ok;
  98. }
  99. #endif
  100. #ifdef USE_PAM
  101. if (options.use_pam)
  102. return (sshpam_auth_passwd(authctxt, password) && ok);
  103. #endif
  104. #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
  105. if (!expire_checked) {
  106. expire_checked = 1;
  107. if (auth_shadow_pwexpired(authctxt))
  108. authctxt->force_pwchange = 1;
  109. }
  110. #endif
  111. result = sys_auth_passwd(ssh, password);
  112. if (authctxt->force_pwchange)
  113. auth_restrict_session(ssh);
  114. return (result && ok);
  115. }
  116. #ifdef BSD_AUTH
  117. static void
  118. warn_expiry(Authctxt *authctxt, auth_session_t *as)
  119. {
  120. int r;
  121. quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime;
  122. pwwarntime = acwarntime = TWO_WEEKS;
  123. pwtimeleft = auth_check_change(as);
  124. actimeleft = auth_check_expire(as);
  125. #ifdef HAVE_LOGIN_CAP
  126. if (authctxt->valid) {
  127. pwwarntime = login_getcaptime(lc, "password-warn", TWO_WEEKS,
  128. TWO_WEEKS);
  129. acwarntime = login_getcaptime(lc, "expire-warn", TWO_WEEKS,
  130. TWO_WEEKS);
  131. }
  132. #endif
  133. if (pwtimeleft != 0 && pwtimeleft < pwwarntime) {
  134. daysleft = pwtimeleft / DAY + 1;
  135. if ((r = sshbuf_putf(loginmsg,
  136. "Your password will expire in %lld day%s.\n",
  137. daysleft, daysleft == 1 ? "" : "s")) != 0)
  138. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  139. }
  140. if (actimeleft != 0 && actimeleft < acwarntime) {
  141. daysleft = actimeleft / DAY + 1;
  142. if ((r = sshbuf_putf(loginmsg,
  143. "Your account will expire in %lld day%s.\n",
  144. daysleft, daysleft == 1 ? "" : "s")) != 0)
  145. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  146. }
  147. }
  148. int
  149. sys_auth_passwd(struct ssh *ssh, const char *password)
  150. {
  151. Authctxt *authctxt = ssh->authctxt;
  152. auth_session_t *as;
  153. static int expire_checked = 0;
  154. as = auth_usercheck(authctxt->pw->pw_name, authctxt->style, "auth-ssh",
  155. (char *)password);
  156. if (as == NULL)
  157. return (0);
  158. if (auth_getstate(as) & AUTH_PWEXPIRED) {
  159. auth_close(as);
  160. auth_restrict_session(ssh);
  161. authctxt->force_pwchange = 1;
  162. return (1);
  163. } else {
  164. if (!expire_checked) {
  165. expire_checked = 1;
  166. warn_expiry(authctxt, as);
  167. }
  168. return (auth_close(as));
  169. }
  170. }
  171. #elif !defined(CUSTOM_SYS_AUTH_PASSWD)
  172. int
  173. sys_auth_passwd(struct ssh *ssh, const char *password)
  174. {
  175. Authctxt *authctxt = ssh->authctxt;
  176. struct passwd *pw = authctxt->pw;
  177. char *encrypted_password, *salt = NULL;
  178. /* Just use the supplied fake password if authctxt is invalid */
  179. char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
  180. if (pw_password == NULL)
  181. return 0;
  182. /* Check for users with no password. */
  183. if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
  184. return (1);
  185. /*
  186. * Encrypt the candidate password using the proper salt, or pass a
  187. * NULL and let xcrypt pick one.
  188. */
  189. if (authctxt->valid && pw_password[0] && pw_password[1])
  190. salt = pw_password;
  191. encrypted_password = xcrypt(password, salt);
  192. /*
  193. * Authentication is accepted if the encrypted passwords
  194. * are identical.
  195. */
  196. return encrypted_password != NULL &&
  197. strcmp(encrypted_password, pw_password) == 0;
  198. }
  199. #endif