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