[auth-passwd.c auth.h pathnames.h session.c]
     support for password change; ok dtucker@
     (set password-dead=1w in login.conf to use this).
     In -Portable, this is currently only platforms using bsdauth.
This commit is contained in:
Darren Tucker 2004-02-06 16:24:31 +11:00
parent 819d4526ca
commit 23bc8d0bff
7 changed files with 147 additions and 66 deletions

View File

@ -12,6 +12,12 @@
- (dtucker) [openbsd-compat/port-aix.c openbsd-compat/port-aix.h] Bug #796: - (dtucker) [openbsd-compat/port-aix.c openbsd-compat/port-aix.h] Bug #796:
Restore previous authdb setting after auth calls. Fixes problems with Restore previous authdb setting after auth calls. Fixes problems with
setpcred failing on accounts that use AFS or NIS password registries. setpcred failing on accounts that use AFS or NIS password registries.
- (dtucker) OpenBSD CVS Sync
- markus@cvs.openbsd.org 2004/01/30 09:48:57
[auth-passwd.c auth.h pathnames.h session.c]
support for password change; ok dtucker@
(set password-dead=1w in login.conf to use this).
In -Portable, this is currently only platforms using bsdauth.
20040129 20040129
- (dtucker) OpenBSD CVS Sync regress/ - (dtucker) OpenBSD CVS Sync regress/
@ -1797,4 +1803,4 @@
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
Report from murple@murple.net, diagnosis from dtucker@zip.com.au Report from murple@murple.net, diagnosis from dtucker@zip.com.au
$Id: ChangeLog,v 1.3211 2004/02/06 05:18:47 dtucker Exp $ $Id: ChangeLog,v 1.3212 2004/02/06 05:24:31 dtucker Exp $

View File

@ -1,4 +1,4 @@
/* $Id: acconfig.h,v 1.172 2004/01/23 11:03:10 dtucker Exp $ */ /* $Id: acconfig.h,v 1.173 2004/02/06 05:24:31 dtucker Exp $ */
/* /*
* Copyright (c) 1999-2003 Damien Miller. All rights reserved. * Copyright (c) 1999-2003 Damien Miller. All rights reserved.
@ -65,6 +65,9 @@
/* from environment and PATH */ /* from environment and PATH */
#undef LOGIN_PROGRAM_FALLBACK #undef LOGIN_PROGRAM_FALLBACK
/* Full path of your "passwd" program */
#undef _PATH_PASSWD_PROG
/* Define if your password has a pw_class field */ /* Define if your password has a pw_class field */
#undef HAVE_PW_CLASS_IN_PASSWD #undef HAVE_PW_CLASS_IN_PASSWD

View File

@ -42,11 +42,21 @@ RCSID("$OpenBSD: auth-passwd.c,v 1.30 2003/11/04 08:54:09 djm Exp $");
#include "log.h" #include "log.h"
#include "servconf.h" #include "servconf.h"
#include "auth.h" #include "auth.h"
#include "auth-options.h"
#ifdef WITH_AIXAUTHENTICATE #ifdef WITH_AIXAUTHENTICATE
# include "canohost.h" # include "canohost.h"
#endif #endif
extern ServerOptions options; extern ServerOptions options;
int sys_auth_passwd(Authctxt *, const char *);
static void
disable_forwarding(void)
{
no_port_forwarding_flag = 1;
no_agent_forwarding_flag = 1;
no_x11_forwarding_flag = 1;
}
/* /*
* Tries to authenticate the user using password. Returns true if * Tries to authenticate the user using password. Returns true if
@ -66,17 +76,21 @@ auth_password(Authctxt *authctxt, const char *password)
return 0; return 0;
#if defined(HAVE_OSF_SIA) #if defined(HAVE_OSF_SIA)
/*
* XXX: any reason this is before krb? could be moved to
* sys_auth_passwd()? -dt
*/
return auth_sia_password(authctxt, password) && ok; return auth_sia_password(authctxt, password) && ok;
#else #endif
# ifdef KRB5 #ifdef KRB5
if (options.kerberos_authentication == 1) { if (options.kerberos_authentication == 1) {
int ret = auth_krb5_password(authctxt, password); int ret = auth_krb5_password(authctxt, password);
if (ret == 1 || ret == 0) if (ret == 1 || ret == 0)
return ret && ok; return ret && ok;
/* Fall back to ordinary passwd authentication. */ /* Fall back to ordinary passwd authentication. */
} }
# endif #endif
# ifdef HAVE_CYGWIN #ifdef HAVE_CYGWIN
if (is_winnt) { if (is_winnt) {
HANDLE hToken = cygwin_logon_user(pw, password); HANDLE hToken = cygwin_logon_user(pw, password);
@ -85,41 +99,57 @@ auth_password(Authctxt *authctxt, const char *password)
cygwin_set_impersonation_token(hToken); cygwin_set_impersonation_token(hToken);
return ok; return ok;
} }
# endif #endif
# ifdef WITH_AIXAUTHENTICATE return (sys_auth_passwd(authctxt, password) && ok);
if (aix_authenticate(pw->pw_name, password, }
get_canonical_hostname(options.use_dns)) == 0)
return 0; #ifdef BSD_AUTH
else int
return ok; sys_auth_passwd(Authctxt *authctxt, const char *password)
# endif {
# ifdef BSD_AUTH struct passwd *pw = authctxt->pw;
if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh", auth_session_t *as;
(char *)password) == 0)
return 0; as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
else (char *)password);
return ok; if (auth_getstate(as) & AUTH_PWEXPIRED) {
# else auth_close(as);
{ disable_forwarding();
authctxt->force_pwchange = 1;
return (1);
} else {
return (auth_close(as));
}
}
#elif defined(WITH_AIXAUTHENTICATE)
int
sys_auth_passwd(Authctxt *authctxt, const char *password)
{
return (aix_authenticate(authctxt->pw->pw_name, password,
get_canonical_hostname(options.use_dns)));
}
#else
int
sys_auth_passwd(Authctxt *authctxt, const char *password)
{
struct passwd *pw = authctxt->pw;
char *encrypted_password;
/* Just use the supplied fake password if authctxt is invalid */ /* Just use the supplied fake password if authctxt is invalid */
char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
/* Check for users with no password. */ /* Check for users with no password. */
if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
return ok; return (1);
else {
/* Encrypt the candidate password using the proper salt. */ /* Encrypt the candidate password using the proper salt. */
char *encrypted_password = xcrypt(password, encrypted_password = xcrypt(password,
(pw_password[0] && pw_password[1]) ? pw_password : "xx"); (pw_password[0] && pw_password[1]) ? pw_password : "xx");
/* /*
* Authentication is accepted if the encrypted passwords * Authentication is accepted if the encrypted passwords
* are identical. * are identical.
*/ */
return (strcmp(encrypted_password, pw_password) == 0) && ok; return (strcmp(encrypted_password, pw_password) == 0);
}
}
# endif
#endif /* !HAVE_OSF_SIA */
} }
#endif

1
auth.h
View File

@ -52,6 +52,7 @@ struct Authctxt {
int valid; /* user exists and is allowed to login */ int valid; /* user exists and is allowed to login */
int attempt; int attempt;
int failures; int failures;
int force_pwchange;
char *user; /* username sent by the client */ char *user; /* username sent by the client */
char *service; char *service;
struct passwd *pw; /* set if 'valid' */ struct passwd *pw; /* set if 'valid' */

View File

@ -1,4 +1,4 @@
# $Id: configure.ac,v 1.192 2004/02/06 04:59:06 dtucker Exp $ # $Id: configure.ac,v 1.193 2004/02/06 05:24:31 dtucker Exp $
AC_INIT AC_INIT
AC_CONFIG_SRCDIR([ssh.c]) AC_CONFIG_SRCDIR([ssh.c])
@ -42,6 +42,11 @@ else
fi fi
fi fi
AC_PATH_PROG(PATH_PASSWD_PROG, passwd)
if test ! -z "$PATH_PASSWD_PROG" ; then
AC_DEFINE_UNQUOTED(_PATH_PASSWD_PROG, "$PATH_PASSWD_PROG")
fi
if test -z "$LD" ; then if test -z "$LD" ; then
LD=$CC LD=$CC
fi fi

View File

@ -150,6 +150,11 @@
#define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" #define _PATH_PRIVSEP_CHROOT_DIR "/var/empty"
#endif #endif
/* for passwd change */
#ifndef _PATH_PASSWD_PROG
#define _PATH_PASSWD_PROG "/usr/bin/passwd"
#endif
#ifndef _PATH_LS #ifndef _PATH_LS
#define _PATH_LS "ls" #define _PATH_LS "ls"
#endif #endif

View File

@ -33,7 +33,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: session.c,v 1.171 2004/01/13 19:23:15 markus Exp $"); RCSID("$OpenBSD: session.c,v 1.172 2004/01/30 09:48:57 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "ssh1.h" #include "ssh1.h"
@ -1303,6 +1303,22 @@ do_setusercontext(struct passwd *pw)
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
} }
static void
do_pwchange(Session *s)
{
fprintf(stderr, "WARNING: Your password has expired.\n");
if (s->ttyfd != -1) {
fprintf(stderr,
"You must change your password now and login again!\n");
execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
perror("passwd");
} else {
fprintf(stderr,
"Password change required but no TTY available.\n");
}
exit(1);
}
static void static void
launch_login(struct passwd *pw, const char *hostname) launch_login(struct passwd *pw, const char *hostname)
{ {
@ -1324,6 +1340,40 @@ launch_login(struct passwd *pw, const char *hostname)
exit(1); exit(1);
} }
static void
child_close_fds(void)
{
int i;
if (packet_get_connection_in() == packet_get_connection_out())
close(packet_get_connection_in());
else {
close(packet_get_connection_in());
close(packet_get_connection_out());
}
/*
* Close all descriptors related to channels. They will still remain
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
channel_close_all();
/*
* Close any extra file descriptors. Note that there may still be
* descriptors left by system functions. They will be closed later.
*/
endpwent();
/*
* Close any extra open file descriptors so that we don\'t have them
* hanging around in clients. Note that we want to do this after
* initgroups, because at least on Solaris 2.3 it leaves file
* descriptors open.
*/
for (i = 3; i < 64; i++)
close(i);
}
/* /*
* Performs common processing for the child, such as setting up the * Performs common processing for the child, such as setting up the
* environment, closing extra file descriptors, setting the user and group * environment, closing extra file descriptors, setting the user and group
@ -1337,11 +1387,18 @@ do_child(Session *s, const char *command)
char *argv[10]; char *argv[10];
const char *shell, *shell0, *hostname = NULL; const char *shell, *shell0, *hostname = NULL;
struct passwd *pw = s->pw; struct passwd *pw = s->pw;
u_int i;
/* remove hostkey from the child's memory */ /* remove hostkey from the child's memory */
destroy_sensitive_data(); destroy_sensitive_data();
/* Force a password change */
if (s->authctxt->force_pwchange) {
do_setusercontext(pw);
child_close_fds();
do_pwchange(s);
exit(1);
}
/* login(1) is only called if we execute the login shell */ /* login(1) is only called if we execute the login shell */
if (options.use_login && command != NULL) if (options.use_login && command != NULL)
options.use_login = 0; options.use_login = 0;
@ -1392,33 +1449,7 @@ do_child(Session *s, const char *command)
* closed before building the environment, as we call * closed before building the environment, as we call
* get_remote_ipaddr there. * get_remote_ipaddr there.
*/ */
if (packet_get_connection_in() == packet_get_connection_out()) child_close_fds();
close(packet_get_connection_in());
else {
close(packet_get_connection_in());
close(packet_get_connection_out());
}
/*
* Close all descriptors related to channels. They will still remain
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
channel_close_all();
/*
* Close any extra file descriptors. Note that there may still be
* descriptors left by system functions. They will be closed later.
*/
endpwent();
/*
* Close any extra open file descriptors so that we don\'t have them
* hanging around in clients. Note that we want to do this after
* initgroups, because at least on Solaris 2.3 it leaves file
* descriptors open.
*/
for (i = 3; i < 64; i++)
close(i);
/* /*
* Must take new environment into use so that .ssh/rc, * Must take new environment into use so that .ssh/rc,