auth-passwd.c revision 149753
157429Smarkm/*
257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
457429Smarkm *                    All rights reserved
557429Smarkm * Password authentication.  This file contains the functions to check whether
657429Smarkm * the password is valid for the user.
765674Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1365674Skris *
1465674Skris * Copyright (c) 1999 Dug Song.  All rights reserved.
1565674Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1665674Skris *
1765674Skris * Redistribution and use in source and binary forms, with or without
1865674Skris * modification, are permitted provided that the following conditions
1965674Skris * are met:
2065674Skris * 1. Redistributions of source code must retain the above copyright
2165674Skris *    notice, this list of conditions and the following disclaimer.
2265674Skris * 2. Redistributions in binary form must reproduce the above copyright
2365674Skris *    notice, this list of conditions and the following disclaimer in the
2465674Skris *    documentation and/or other materials provided with the distribution.
2565674Skris *
2665674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2765674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2865674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2965674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3065674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3165674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3265674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3365674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3465674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3565674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3657429Smarkm */
3757429Smarkm
3857429Smarkm#include "includes.h"
39149753SdesRCSID("$OpenBSD: auth-passwd.c,v 1.34 2005/07/19 15:32:26 otto Exp $");
4099748SdesRCSID("$FreeBSD: head/crypto/openssh/auth-passwd.c 149753 2005-09-03 07:04:25Z des $");
4157429Smarkm
4257429Smarkm#include "packet.h"
43147005Sdes#include "buffer.h"
4476262Sgreen#include "log.h"
4557429Smarkm#include "servconf.h"
4676262Sgreen#include "auth.h"
47126277Sdes#include "auth-options.h"
4876262Sgreen
49147005Sdesextern Buffer loginmsg;
50124211Sdesextern ServerOptions options;
51124211Sdes
52147005Sdes#ifdef HAVE_LOGIN_CAP
53147005Sdesextern login_cap_t *lc;
54147005Sdes#endif
55147005Sdes
56147005Sdes
57147005Sdes#define DAY		(24L * 60 * 60) /* 1 day in seconds */
58147005Sdes#define TWO_WEEKS	(2L * 7 * DAY)	/* 2 weeks in seconds */
59147005Sdes
60126277Sdesvoid
61126277Sdesdisable_forwarding(void)
62126277Sdes{
63126277Sdes	no_port_forwarding_flag = 1;
64126277Sdes	no_agent_forwarding_flag = 1;
65126277Sdes	no_x11_forwarding_flag = 1;
66126277Sdes}
67126277Sdes
6857429Smarkm/*
6957429Smarkm * Tries to authenticate the user using password.  Returns true if
7057429Smarkm * authentication succeeds.
7157429Smarkm */
7265674Skrisint
7376262Sgreenauth_password(Authctxt *authctxt, const char *password)
7457429Smarkm{
7576262Sgreen	struct passwd * pw = authctxt->pw;
76147005Sdes	int result, ok = authctxt->valid;
77137019Sdes#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
78126277Sdes	static int expire_checked = 0;
79137019Sdes#endif
8057429Smarkm
8198941Sdes#ifndef HAVE_CYGWIN
82126277Sdes	if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
83124211Sdes		ok = 0;
8498941Sdes#endif
8557429Smarkm	if (*password == '\0' && options.permit_empty_passwd == 0)
8657429Smarkm		return 0;
87113911Sdes
88126277Sdes#ifdef KRB5
8973400Sassar	if (options.kerberos_authentication == 1) {
9092559Sdes		int ret = auth_krb5_password(authctxt, password);
9192559Sdes		if (ret == 1 || ret == 0)
92124211Sdes			return ret && ok;
9357565Smarkm		/* Fall back to ordinary passwd authentication. */
9457565Smarkm	}
95126277Sdes#endif
96126277Sdes#ifdef HAVE_CYGWIN
9798941Sdes	if (is_winnt) {
9898941Sdes		HANDLE hToken = cygwin_logon_user(pw, password);
9998941Sdes
10098941Sdes		if (hToken == INVALID_HANDLE_VALUE)
10198941Sdes			return 0;
10298941Sdes		cygwin_set_impersonation_token(hToken);
103124211Sdes		return ok;
10498941Sdes	}
105126277Sdes#endif
106137019Sdes#ifdef USE_PAM
107137019Sdes	if (options.use_pam)
108137019Sdes		return (sshpam_auth_passwd(authctxt, password) && ok);
109137019Sdes#endif
110126277Sdes#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
111126277Sdes	if (!expire_checked) {
112126277Sdes		expire_checked = 1;
113147005Sdes		if (auth_shadow_pwexpired(authctxt))
114126277Sdes			authctxt->force_pwchange = 1;
115126277Sdes	}
116126277Sdes#endif
117147005Sdes	result = sys_auth_passwd(authctxt, password);
118147005Sdes	if (authctxt->force_pwchange)
119147005Sdes		disable_forwarding();
120147005Sdes	return (result && ok);
121126277Sdes}
122124211Sdes
123126277Sdes#ifdef BSD_AUTH
124147005Sdesstatic void
125147005Sdeswarn_expiry(Authctxt *authctxt, auth_session_t *as)
126147005Sdes{
127147005Sdes	char buf[256];
128147005Sdes	quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime;
129147005Sdes
130147005Sdes	pwwarntime = acwarntime = TWO_WEEKS;
131147005Sdes
132147005Sdes	pwtimeleft = auth_check_change(as);
133147005Sdes	actimeleft = auth_check_expire(as);
134147005Sdes#ifdef HAVE_LOGIN_CAP
135147005Sdes	if (authctxt->valid) {
136147005Sdes		pwwarntime = login_getcaptime(lc, "password-warn", TWO_WEEKS,
137147005Sdes		    TWO_WEEKS);
138147005Sdes		acwarntime = login_getcaptime(lc, "expire-warn", TWO_WEEKS,
139147005Sdes		    TWO_WEEKS);
140147005Sdes	}
141147005Sdes#endif
142147005Sdes	if (pwtimeleft != 0 && pwtimeleft < pwwarntime) {
143147005Sdes		daysleft = pwtimeleft / DAY + 1;
144147005Sdes		snprintf(buf, sizeof(buf),
145147005Sdes		    "Your password will expire in %lld day%s.\n",
146147005Sdes		    daysleft, daysleft == 1 ? "" : "s");
147147005Sdes		buffer_append(&loginmsg, buf, strlen(buf));
148147005Sdes	}
149147005Sdes	if (actimeleft != 0 && actimeleft < acwarntime) {
150147005Sdes		daysleft = actimeleft / DAY + 1;
151147005Sdes		snprintf(buf, sizeof(buf),
152147005Sdes		    "Your account will expire in %lld day%s.\n",
153147005Sdes		    daysleft, daysleft == 1 ? "" : "s");
154147005Sdes		buffer_append(&loginmsg, buf, strlen(buf));
155147005Sdes	}
156147005Sdes}
157147005Sdes
158126277Sdesint
159126277Sdessys_auth_passwd(Authctxt *authctxt, const char *password)
160126277Sdes{
161126277Sdes	struct passwd *pw = authctxt->pw;
162126277Sdes	auth_session_t *as;
163147005Sdes	static int expire_checked = 0;
164124211Sdes
165126277Sdes	as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
166126277Sdes	    (char *)password);
167149753Sdes	if (as == NULL)
168149753Sdes		return (0);
169126277Sdes	if (auth_getstate(as) & AUTH_PWEXPIRED) {
170126277Sdes		auth_close(as);
171126277Sdes		disable_forwarding();
172126277Sdes		authctxt->force_pwchange = 1;
173126277Sdes		return (1);
174126277Sdes	} else {
175147005Sdes		if (!expire_checked) {
176147005Sdes			expire_checked = 1;
177147005Sdes			warn_expiry(authctxt, as);
178147005Sdes		}
179126277Sdes		return (auth_close(as));
18057429Smarkm	}
181126277Sdes}
182126277Sdes#elif !defined(CUSTOM_SYS_AUTH_PASSWD)
183126277Sdesint
184126277Sdessys_auth_passwd(Authctxt *authctxt, const char *password)
185126277Sdes{
186126277Sdes	struct passwd *pw = authctxt->pw;
187126277Sdes	char *encrypted_password;
188126277Sdes
189124211Sdes	/* Just use the supplied fake password if authctxt is invalid */
190124211Sdes	char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
19198941Sdes
19257429Smarkm	/* Check for users with no password. */
193124211Sdes	if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
194126277Sdes		return (1);
19598941Sdes
196126277Sdes	/* Encrypt the candidate password using the proper salt. */
197126277Sdes	encrypted_password = xcrypt(password,
198126277Sdes	    (pw_password[0] && pw_password[1]) ? pw_password : "xx");
19998941Sdes
200126277Sdes	/*
201126277Sdes	 * Authentication is accepted if the encrypted passwords
202126277Sdes	 * are identical.
203126277Sdes	 */
204126277Sdes	return (strcmp(encrypted_password, pw_password) == 0);
20557429Smarkm}
206126277Sdes#endif
207