1220137Strasz/* $OpenBSD: auth-passwd.c,v 1.43 2007/09/21 08:15:29 djm Exp $ */ 2220137Strasz/* 3220137Strasz * Author: Tatu Ylonen <ylo@cs.hut.fi> 4220137Strasz * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5220137Strasz * All rights reserved 6220137Strasz * Password authentication. This file contains the functions to check whether 7220137Strasz * the password is valid for the user. 8220137Strasz * 9220137Strasz * As far as I am concerned, the code I have written for this software 10220137Strasz * can be used freely for any purpose. Any derived versions of this 11220137Strasz * software must be clearly marked as such, and if the derived work is 12220137Strasz * incompatible with the protocol description in the RFC file, it must be 13220137Strasz * called by a name other than "ssh" or "Secure Shell". 14220137Strasz * 15220137Strasz * Copyright (c) 1999 Dug Song. All rights reserved. 16220137Strasz * Copyright (c) 2000 Markus Friedl. All rights reserved. 17220137Strasz * 18220137Strasz * Redistribution and use in source and binary forms, with or without 19220137Strasz * modification, are permitted provided that the following conditions 20220137Strasz * are met: 21220137Strasz * 1. Redistributions of source code must retain the above copyright 22220137Strasz * notice, this list of conditions and the following disclaimer. 23220137Strasz * 2. Redistributions in binary form must reproduce the above copyright 24220137Strasz * notice, this list of conditions and the following disclaimer in the 25220137Strasz * documentation and/or other materials provided with the distribution. 26220137Strasz * 27220137Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28220137Strasz * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29220137Strasz * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30220137Strasz * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31220137Strasz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32220137Strasz * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33220137Strasz * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34220137Strasz * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35220137Strasz * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36242139Strasz * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37220137Strasz */ 38220137Strasz 39228430Savg#include "includes.h" 40220137Strasz 41220137Strasz#include <sys/types.h> 42220137Strasz 43220137Strasz#include <pwd.h> 44220137Strasz#include <stdio.h> 45220137Strasz#include <string.h> 46220137Strasz#include <stdarg.h> 47220137Strasz 48220137Strasz#include "packet.h" 49220137Strasz#include "buffer.h" 50220137Strasz#include "log.h" 51220137Strasz#include "servconf.h" 52220137Strasz#include "key.h" 53220137Strasz#include "hostfile.h" 54242139Strasz#include "auth.h" 55220137Strasz#include "auth-options.h" 56242139Strasz 57220137Straszextern Buffer loginmsg; 58220137Straszextern ServerOptions options; 59220137Strasz 60242139Strasz#ifdef HAVE_LOGIN_CAP 61220137Straszextern login_cap_t *lc; 62220137Strasz#endif 63220137Strasz 64220137Strasz 65220137Strasz#define DAY (24L * 60 * 60) /* 1 day in seconds */ 66220137Strasz#define TWO_WEEKS (2L * 7 * DAY) /* 2 weeks in seconds */ 67220137Strasz 68220137Straszvoid 69220137Straszdisable_forwarding(void) 70242139Strasz{ 71242139Strasz no_port_forwarding_flag = 1; 72242139Strasz no_agent_forwarding_flag = 1; 73242139Strasz no_x11_forwarding_flag = 1; 74242139Strasz} 75242139Strasz 76242139Strasz/* 77242139Strasz * Tries to authenticate the user using password. Returns true if 78242139Strasz * authentication succeeds. 79242139Strasz */ 80242139Straszint 81242139Straszauth_password(Authctxt *authctxt, const char *password) 82242139Strasz{ 83242139Strasz struct passwd * pw = authctxt->pw; 84242139Strasz int result, ok = authctxt->valid; 85242139Strasz#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) 86242139Strasz static int expire_checked = 0; 87220137Strasz#endif 88220137Strasz 89220137Strasz#ifndef HAVE_CYGWIN 90220137Strasz if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES) 91220137Strasz ok = 0; 92220137Strasz#endif 93220137Strasz if (*password == '\0' && options.permit_empty_passwd == 0) 94220137Strasz return 0; 95220137Strasz 96220137Strasz#ifdef KRB5 97220137Strasz if (options.kerberos_authentication == 1) { 98220137Strasz int ret = auth_krb5_password(authctxt, password); 99220137Strasz if (ret == 1 || ret == 0) 100220137Strasz return ret && ok; 101220137Strasz /* Fall back to ordinary passwd authentication. */ 102220137Strasz } 103220137Strasz#endif 104220137Strasz#ifdef HAVE_CYGWIN 105220137Strasz { 106220137Strasz HANDLE hToken = cygwin_logon_user(pw, password); 107220137Strasz 108220137Strasz if (hToken == INVALID_HANDLE_VALUE) 109220137Strasz return 0; 110220137Strasz cygwin_set_impersonation_token(hToken); 111220137Strasz return ok; 112220137Strasz } 113220137Strasz#endif 114220137Strasz#ifdef USE_PAM 115220137Strasz if (options.use_pam) 116220137Strasz return (sshpam_auth_passwd(authctxt, password) && ok); 117220137Strasz#endif 118220137Strasz#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) 119220137Strasz if (!expire_checked) { 120220137Strasz expire_checked = 1; 121220137Strasz if (auth_shadow_pwexpired(authctxt)) 122220137Strasz authctxt->force_pwchange = 1; 123220137Strasz } 124220137Strasz#endif 125220137Strasz result = sys_auth_passwd(authctxt, password); 126224036Strasz if (authctxt->force_pwchange) 127220137Strasz disable_forwarding(); 128220137Strasz return (result && ok); 129220137Strasz} 130220137Strasz 131220137Strasz#ifdef BSD_AUTH 132220137Straszstatic void 133220137Straszwarn_expiry(Authctxt *authctxt, auth_session_t *as) 134220137Strasz{ 135220137Strasz char buf[256]; 136220137Strasz quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime; 137220137Strasz 138220137Strasz pwwarntime = acwarntime = TWO_WEEKS; 139220137Strasz 140220137Strasz pwtimeleft = auth_check_change(as); 141220137Strasz actimeleft = auth_check_expire(as); 142220137Strasz#ifdef HAVE_LOGIN_CAP 143220137Strasz if (authctxt->valid) { 144220137Strasz pwwarntime = login_getcaptime(lc, "password-warn", TWO_WEEKS, 145220137Strasz TWO_WEEKS); 146220137Strasz acwarntime = login_getcaptime(lc, "expire-warn", TWO_WEEKS, 147220137Strasz TWO_WEEKS); 148220137Strasz } 149220137Strasz#endif 150220137Strasz if (pwtimeleft != 0 && pwtimeleft < pwwarntime) { 151220137Strasz daysleft = pwtimeleft / DAY + 1; 152220137Strasz snprintf(buf, sizeof(buf), 153220137Strasz "Your password will expire in %lld day%s.\n", 154220137Strasz daysleft, daysleft == 1 ? "" : "s"); 155220137Strasz buffer_append(&loginmsg, buf, strlen(buf)); 156220137Strasz } 157220137Strasz if (actimeleft != 0 && actimeleft < acwarntime) { 158220137Strasz daysleft = actimeleft / DAY + 1; 159220137Strasz snprintf(buf, sizeof(buf), 160220137Strasz "Your account will expire in %lld day%s.\n", 161220137Strasz daysleft, daysleft == 1 ? "" : "s"); 162220137Strasz buffer_append(&loginmsg, buf, strlen(buf)); 163220137Strasz } 164242139Strasz} 165242139Strasz 166242139Straszint 167220137Straszsys_auth_passwd(Authctxt *authctxt, const char *password) 168242139Strasz{ 169242139Strasz struct passwd *pw = authctxt->pw; 170242139Strasz auth_session_t *as; 171242139Strasz static int expire_checked = 0; 172242139Strasz 173242139Strasz as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh", 174242139Strasz (char *)password); 175242139Strasz if (as == NULL) 176242139Strasz return (0); 177242139Strasz if (auth_getstate(as) & AUTH_PWEXPIRED) { 178242139Strasz auth_close(as); 179242139Strasz disable_forwarding(); 180242139Strasz authctxt->force_pwchange = 1; 181242139Strasz return (1); 182242139Strasz } else { 183242139Strasz if (!expire_checked) { 184242139Strasz expire_checked = 1; 185242139Strasz warn_expiry(authctxt, as); 186242139Strasz } 187242139Strasz return (auth_close(as)); 188242139Strasz } 189242139Strasz} 190242139Strasz#elif !defined(CUSTOM_SYS_AUTH_PASSWD) 191242139Straszint 192242139Straszsys_auth_passwd(Authctxt *authctxt, const char *password) 193242139Strasz{ 194242139Strasz struct passwd *pw = authctxt->pw; 195242139Strasz char *encrypted_password; 196242139Strasz 197242139Strasz /* Just use the supplied fake password if authctxt is invalid */ 198242139Strasz char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; 199242139Strasz 200242139Strasz /* Check for users with no password. */ 201242139Strasz if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) 202242139Strasz return (1); 203242139Strasz 204242139Strasz /* Encrypt the candidate password using the proper salt. */ 205242139Strasz encrypted_password = xcrypt(password, 206242139Strasz (pw_password[0] && pw_password[1]) ? pw_password : "xx"); 207242139Strasz 208242139Strasz /* 209242139Strasz * Authentication is accepted if the encrypted passwords 210242139Strasz * are identical. 211242139Strasz */ 212242139Strasz return encrypted_password != NULL && 213242139Strasz strcmp(encrypted_password, pw_password) == 0; 214242139Strasz} 215242139Strasz#endif 216242139Strasz