auth-passwd.c revision 322341
187189Spdeuskar/* $OpenBSD: auth-passwd.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
287189Spdeuskar/*
3146662Stackerman * Author: Tatu Ylonen <ylo@cs.hut.fi>
487189Spdeuskar * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
587189Spdeuskar *                    All rights reserved
6103895Spdeuskar * Password authentication.  This file contains the functions to check whether
7103895Spdeuskar * the password is valid for the user.
887189Spdeuskar *
9103895Spdeuskar * As far as I am concerned, the code I have written for this software
10103895Spdeuskar * can be used freely for any purpose.  Any derived versions of this
1187189Spdeuskar * software must be clearly marked as such, and if the derived work is
12103895Spdeuskar * incompatible with the protocol description in the RFC file, it must be
13103895Spdeuskar * called by a name other than "ssh" or "Secure Shell".
14103895Spdeuskar *
1587189Spdeuskar * Copyright (c) 1999 Dug Song.  All rights reserved.
1687189Spdeuskar * Copyright (c) 2000 Markus Friedl.  All rights reserved.
17103895Spdeuskar *
18103895Spdeuskar * Redistribution and use in source and binary forms, with or without
1987189Spdeuskar * modification, are permitted provided that the following conditions
2087189Spdeuskar * are met:
2187189Spdeuskar * 1. Redistributions of source code must retain the above copyright
2287189Spdeuskar *    notice, this list of conditions and the following disclaimer.
23103895Spdeuskar * 2. Redistributions in binary form must reproduce the above copyright
24103895Spdeuskar *    notice, this list of conditions and the following disclaimer in the
25103895Spdeuskar *    documentation and/or other materials provided with the distribution.
26103895Spdeuskar *
27103895Spdeuskar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28103895Spdeuskar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29103895Spdeuskar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30103895Spdeuskar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3187189Spdeuskar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3287189Spdeuskar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3387189Spdeuskar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3490628Spdeuskar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3590628Spdeuskar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36150968Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37150968Sglebius */
38150968Sglebius
39150968Sglebius#include "includes.h"
4087189Spdeuskar
4187189Spdeuskar#include <sys/types.h>
4287189Spdeuskar
4387189Spdeuskar#include <pwd.h>
4487189Spdeuskar#include <stdio.h>
4587189Spdeuskar#include <string.h>
4687189Spdeuskar#include <stdarg.h>
4787189Spdeuskar
4887189Spdeuskar#include "packet.h"
4987189Spdeuskar#include "buffer.h"
5087189Spdeuskar#include "log.h"
51152740Sglebius#include "misc.h"
5287189Spdeuskar#include "servconf.h"
5387189Spdeuskar#include "key.h"
5487189Spdeuskar#include "hostfile.h"
5587189Spdeuskar#include "auth.h"
5687189Spdeuskar#include "auth-options.h"
5787189Spdeuskar
5887189Spdeuskarextern Buffer loginmsg;
5987189Spdeuskarextern ServerOptions options;
6087189Spdeuskar
6187189Spdeuskar#ifdef HAVE_LOGIN_CAP
6287189Spdeuskarextern login_cap_t *lc;
63112472Spdeuskar#endif
6487189Spdeuskar
6587189Spdeuskar
66108229Spdeuskar#define DAY		(24L * 60 * 60) /* 1 day in seconds */
67146662Stackerman#define TWO_WEEKS	(2L * 7 * DAY)	/* 2 weeks in seconds */
68146662Stackerman
69146662Stackerman#define MAX_PASSWORD_LEN	1024
70146662Stackerman
71146662Stackermanvoid
72146662Stackermandisable_forwarding(void)
73146662Stackerman{
74146662Stackerman	no_port_forwarding_flag = 1;
75146662Stackerman	no_agent_forwarding_flag = 1;
76146662Stackerman	no_x11_forwarding_flag = 1;
77146662Stackerman}
78146662Stackerman
79146662Stackerman/*
80146662Stackerman * Tries to authenticate the user using password.  Returns true if
81146662Stackerman * authentication succeeds.
82146662Stackerman */
83146662Stackermanint
84146662Stackermanauth_password(Authctxt *authctxt, const char *password)
85146662Stackerman{
86146662Stackerman	struct passwd * pw = authctxt->pw;
87146662Stackerman	int result, ok = authctxt->valid;
88146662Stackerman#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
89146662Stackerman	static int expire_checked = 0;
90146662Stackerman#endif
91146662Stackerman
92146662Stackerman	if (strlen(password) > MAX_PASSWORD_LEN)
93146662Stackerman		return 0;
94146662Stackerman
95146662Stackerman#ifndef HAVE_CYGWIN
96146662Stackerman	if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
97146662Stackerman		ok = 0;
98146662Stackerman#endif
99146662Stackerman	if (*password == '\0' && options.permit_empty_passwd == 0)
100146662Stackerman		return 0;
101146662Stackerman
102146662Stackerman#ifdef KRB5
103146662Stackerman	if (options.kerberos_authentication == 1) {
104146662Stackerman		int ret = auth_krb5_password(authctxt, password);
105146662Stackerman		if (ret == 1 || ret == 0)
106146662Stackerman			return ret && ok;
107146662Stackerman		/* Fall back to ordinary passwd authentication. */
108146662Stackerman	}
109146662Stackerman#endif
110152740Sglebius#ifdef HAVE_CYGWIN
111152740Sglebius	{
112152740Sglebius		HANDLE hToken = cygwin_logon_user(pw, password);
113152740Sglebius
114152740Sglebius		if (hToken == INVALID_HANDLE_VALUE)
115152740Sglebius			return 0;
116152740Sglebius		cygwin_set_impersonation_token(hToken);
117152740Sglebius		return ok;
118146662Stackerman	}
119146662Stackerman#endif
120152740Sglebius#ifdef USE_PAM
121146662Stackerman	if (options.use_pam)
122108229Spdeuskar		return (sshpam_auth_passwd(authctxt, password) && ok);
123108229Spdeuskar#endif
12487189Spdeuskar#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
12587189Spdeuskar	if (!expire_checked) {
12687189Spdeuskar		expire_checked = 1;
12787189Spdeuskar		if (auth_shadow_pwexpired(authctxt))
12887189Spdeuskar			authctxt->force_pwchange = 1;
12987189Spdeuskar	}
13087189Spdeuskar#endif
13197785Spdeuskar	result = sys_auth_passwd(authctxt, password);
13287189Spdeuskar	if (authctxt->force_pwchange)
13387189Spdeuskar		disable_forwarding();
13487189Spdeuskar	return (result && ok);
13587189Spdeuskar}
13687189Spdeuskar
13793914Spdeuskar#ifdef BSD_AUTH
13893914Spdeuskarstatic void
13993914Spdeuskarwarn_expiry(Authctxt *authctxt, auth_session_t *as)
14093914Spdeuskar{
141153729Sglebius	char buf[256];
142153729Sglebius	quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime;
14392739Salfred
14492739Salfred	pwwarntime = acwarntime = TWO_WEEKS;
145153729Sglebius
146112472Spdeuskar	pwtimeleft = auth_check_change(as);
14792739Salfred	actimeleft = auth_check_expire(as);
14892739Salfred#ifdef HAVE_LOGIN_CAP
149120364Ssam	if (authctxt->valid) {
15092739Salfred		pwwarntime = login_getcaptime(lc, "password-warn", TWO_WEEKS,
15192739Salfred		    TWO_WEEKS);
15293914Spdeuskar		acwarntime = login_getcaptime(lc, "expire-warn", TWO_WEEKS,
15392739Salfred		    TWO_WEEKS);
15493914Spdeuskar	}
15592739Salfred#endif
15692739Salfred	if (pwtimeleft != 0 && pwtimeleft < pwwarntime) {
15793914Spdeuskar		daysleft = pwtimeleft / DAY + 1;
15892739Salfred		snprintf(buf, sizeof(buf),
15993914Spdeuskar		    "Your password will expire in %lld day%s.\n",
16092739Salfred		    daysleft, daysleft == 1 ? "" : "s");
16193914Spdeuskar		buffer_append(&loginmsg, buf, strlen(buf));
16292739Salfred	}
16393914Spdeuskar	if (actimeleft != 0 && actimeleft < acwarntime) {
16493914Spdeuskar		daysleft = actimeleft / DAY + 1;
16592739Salfred		snprintf(buf, sizeof(buf),
16692739Salfred		    "Your account will expire in %lld day%s.\n",
16792739Salfred		    daysleft, daysleft == 1 ? "" : "s");
16892739Salfred		buffer_append(&loginmsg, buf, strlen(buf));
16993914Spdeuskar	}
17093914Spdeuskar}
171107242Sluigi
172153474Syongariint
173153474Syongarisys_auth_passwd(Authctxt *authctxt, const char *password)
174153474Syongari{
17592739Salfred	struct passwd *pw = authctxt->pw;
176112472Spdeuskar	auth_session_t *as;
177108229Spdeuskar	static int expire_checked = 0;
178102452Spdeuskar
179108229Spdeuskar	as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
180108229Spdeuskar	    (char *)password);
181108229Spdeuskar	if (as == NULL)
18292739Salfred		return (0);
18392739Salfred	if (auth_getstate(as) & AUTH_PWEXPIRED) {
18492739Salfred		auth_close(as);
18592739Salfred		disable_forwarding();
18692739Salfred		authctxt->force_pwchange = 1;
187108229Spdeuskar		return (1);
188106649Spdeuskar	} else {
189112472Spdeuskar		if (!expire_checked) {
190140859Syar			expire_checked = 1;
191137609Srwatson			warn_expiry(authctxt, as);
192112472Spdeuskar		}
193112472Spdeuskar		return (auth_close(as));
194112472Spdeuskar	}
195112472Spdeuskar}
196112472Spdeuskar#elif !defined(CUSTOM_SYS_AUTH_PASSWD)
197121106Sdeischenint
198114554Spdeuskarsys_auth_passwd(Authctxt *authctxt, const char *password)
199114554Spdeuskar{
200114554Spdeuskar	struct passwd *pw = authctxt->pw;
201115878Spdeuskar	char *encrypted_password;
202115878Spdeuskar
203115878Spdeuskar	/* Just use the supplied fake password if authctxt is invalid */
204115878Spdeuskar	char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
205152225Syongari
206119509Spdeuskar	/* Check for users with no password. */
207119509Spdeuskar	if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
208118314Sjdp		return (1);
209118314Sjdp
210118314Sjdp	/* Encrypt the candidate password using the proper salt. */
211118314Sjdp	encrypted_password = xcrypt(password,
212150789Sglebius	    (pw_password[0] && pw_password[1]) ? pw_password : "xx");
213150789Sglebius
214150789Sglebius	/*
21597785Spdeuskar	 * Authentication is accepted if the encrypted passwords
21687189Spdeuskar	 * are identical.
21787189Spdeuskar	 */
21887189Spdeuskar	return encrypted_password != NULL &&
21987189Spdeuskar	    strcmp(encrypted_password, pw_password) == 0;
22087189Spdeuskar}
22197785Spdeuskar#endif
22297785Spdeuskar