From: dtucker Date: Fri, 6 Feb 2004 05:24:31 +0000 (+0000) Subject: - markus@cvs.openbsd.org 2004/01/30 09:48:57 X-Git-Tag: V_3_8_P1~51 X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/commitdiff_plain/37656beb90eac9a7928cb9acca40b5f0b0e712fd - 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. --- diff --git a/ChangeLog b/ChangeLog index d3ddfb7c..367fce45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,12 @@ - (dtucker) [openbsd-compat/port-aix.c openbsd-compat/port-aix.h] Bug #796: Restore previous authdb setting after auth calls. Fixes problems with 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 - (dtucker) OpenBSD CVS Sync regress/ diff --git a/acconfig.h b/acconfig.h index 4c95950c..a4ae258c 100644 --- a/acconfig.h +++ b/acconfig.h @@ -65,6 +65,9 @@ /* from environment and PATH */ #undef LOGIN_PROGRAM_FALLBACK +/* Full path of your "passwd" program */ +#undef _PATH_PASSWD_PROG + /* Define if your password has a pw_class field */ #undef HAVE_PW_CLASS_IN_PASSWD diff --git a/auth-passwd.c b/auth-passwd.c index a27170cc..d12996bb 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -42,11 +42,21 @@ RCSID("$OpenBSD: auth-passwd.c,v 1.30 2003/11/04 08:54:09 djm Exp $"); #include "log.h" #include "servconf.h" #include "auth.h" +#include "auth-options.h" #ifdef WITH_AIXAUTHENTICATE # include "canohost.h" #endif 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 @@ -66,17 +76,21 @@ auth_password(Authctxt *authctxt, const char *password) return 0; #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; -#else -# ifdef KRB5 +#endif +#ifdef KRB5 if (options.kerberos_authentication == 1) { int ret = auth_krb5_password(authctxt, password); if (ret == 1 || ret == 0) return ret && ok; /* Fall back to ordinary passwd authentication. */ } -# endif -# ifdef HAVE_CYGWIN +#endif +#ifdef HAVE_CYGWIN if (is_winnt) { HANDLE hToken = cygwin_logon_user(pw, password); @@ -85,41 +99,57 @@ auth_password(Authctxt *authctxt, const char *password) cygwin_set_impersonation_token(hToken); return ok; } -# endif -# ifdef WITH_AIXAUTHENTICATE - if (aix_authenticate(pw->pw_name, password, - get_canonical_hostname(options.use_dns)) == 0) - return 0; - else - return ok; -# endif -# ifdef BSD_AUTH - if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh", - (char *)password) == 0) - return 0; - else - return ok; -# else - { +#endif + return (sys_auth_passwd(authctxt, password) && ok); +} + +#ifdef BSD_AUTH +int +sys_auth_passwd(Authctxt *authctxt, const char *password) +{ + struct passwd *pw = authctxt->pw; + auth_session_t *as; + + as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh", + (char *)password); + if (auth_getstate(as) & AUTH_PWEXPIRED) { + 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 */ char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; /* Check for users with no password. */ if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) - return ok; - else { - /* Encrypt the candidate password using the proper salt. */ - char *encrypted_password = xcrypt(password, - (pw_password[0] && pw_password[1]) ? pw_password : "xx"); + return (1); - /* - * Authentication is accepted if the encrypted passwords - * are identical. - */ - return (strcmp(encrypted_password, pw_password) == 0) && ok; - } + /* Encrypt the candidate password using the proper salt. */ + encrypted_password = xcrypt(password, + (pw_password[0] && pw_password[1]) ? pw_password : "xx"); - } -# endif -#endif /* !HAVE_OSF_SIA */ + /* + * Authentication is accepted if the encrypted passwords + * are identical. + */ + return (strcmp(encrypted_password, pw_password) == 0); } +#endif diff --git a/auth.h b/auth.h index 0be1f88c..de2f1e80 100644 --- a/auth.h +++ b/auth.h @@ -52,6 +52,7 @@ struct Authctxt { int valid; /* user exists and is allowed to login */ int attempt; int failures; + int force_pwchange; char *user; /* username sent by the client */ char *service; struct passwd *pw; /* set if 'valid' */ diff --git a/configure.ac b/configure.ac index 3ff67340..7590219f 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,11 @@ else 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 LD=$CC fi diff --git a/pathnames.h b/pathnames.h index 89e22c77..edeff2de 100644 --- a/pathnames.h +++ b/pathnames.h @@ -150,6 +150,11 @@ #define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" #endif +/* for passwd change */ +#ifndef _PATH_PASSWD_PROG +#define _PATH_PASSWD_PROG "/usr/bin/passwd" +#endif + #ifndef _PATH_LS #define _PATH_LS "ls" #endif diff --git a/session.c b/session.c index 02c5dca9..5742296d 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #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 "ssh1.h" @@ -1303,6 +1303,22 @@ do_setusercontext(struct passwd *pw) 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 launch_login(struct passwd *pw, const char *hostname) { @@ -1324,6 +1340,40 @@ launch_login(struct passwd *pw, const char *hostname) 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 * environment, closing extra file descriptors, setting the user and group @@ -1337,11 +1387,18 @@ do_child(Session *s, const char *command) char *argv[10]; const char *shell, *shell0, *hostname = NULL; struct passwd *pw = s->pw; - u_int i; /* remove hostkey from the child's memory */ 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 */ if (options.use_login && command != NULL) options.use_login = 0; @@ -1392,33 +1449,7 @@ do_child(Session *s, const char *command) * closed before building the environment, as we call * get_remote_ipaddr there. */ - 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); + child_close_fds(); /* * Must take new environment into use so that .ssh/rc,