Bugzilla – Attachment 199 Details for
Bug 14
Can't change expired /etc/shadow password without PAM
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Implement password change via /bin/passwd in session.
openssh-passexpire10.patch (text/plain), 19.26 KB, created by
Darren Tucker
on 2003-01-09 23:17:19 AEDT
(
hide
)
Description:
Implement password change via /bin/passwd in session.
Filename:
MIME Type:
Creator:
Darren Tucker
Created:
2003-01-09 23:17:19 AEDT
Size:
19.26 KB
patch
obsolete
>Index: TODO >=================================================================== >RCS file: /cvs/openssh/TODO,v >retrieving revision 1.51 >diff -u -r1.51 TODO >--- TODO 5 Sep 2002 06:32:03 -0000 1.51 >+++ TODO 9 Jan 2003 12:08:52 -0000 >@@ -15,8 +15,6 @@ > > - Replacement for setproctitle() - HP-UX support only currently > >-- Handle changing passwords for the non-PAM expired password case >- > - Improve PAM support (a pam_lastlog module will cause sshd to exit) > and maybe support alternate forms of authentications like OPIE via > pam? >Index: acconfig.h >=================================================================== >RCS file: /cvs/openssh/acconfig.h,v >retrieving revision 1.146 >diff -u -r1.146 acconfig.h >--- acconfig.h 7 Jan 2003 04:18:33 -0000 1.146 >+++ acconfig.h 9 Jan 2003 12:08:52 -0000 >@@ -25,6 +25,9 @@ > /* from environment and PATH */ > #undef LOGIN_PROGRAM_FALLBACK > >+/* Path to passwd program */ >+#undef PASSWD_PROGRAM_PATH >+ > /* Define if your password has a pw_class field */ > #undef HAVE_PW_CLASS_IN_PASSWD > >Index: auth-pam.c >=================================================================== >RCS file: /cvs/openssh/auth-pam.c,v >retrieving revision 1.54 >diff -u -r1.54 auth-pam.c >--- auth-pam.c 28 Jul 2002 20:24:08 -0000 1.54 >+++ auth-pam.c 9 Jan 2003 12:08:52 -0000 >@@ -60,7 +60,7 @@ > /* states for do_pam_conversation() */ > enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN; > /* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */ >-static int password_change_required = 0; >+extern int password_change_required; > /* remember whether the last pam_authenticate() succeeded or not */ > static int was_authenticated = 0; > >@@ -260,12 +260,7 @@ > case PAM_NEW_AUTHTOK_REQD: > message_cat(&__pam_msg, use_privsep ? > NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG); >- /* flag that password change is necessary */ >- password_change_required = 1; >- /* disallow other functionality for now */ >- no_port_forwarding_flag |= 2; >- no_agent_forwarding_flag |= 2; >- no_x11_forwarding_flag |= 2; >+ flag_password_change_required(); > break; > #endif > default: >Index: auth-passwd.c >=================================================================== >RCS file: /cvs/openssh/auth-passwd.c,v >retrieving revision 1.48 >diff -u -r1.48 auth-passwd.c >--- auth-passwd.c 25 Sep 2002 23:14:16 -0000 1.48 >+++ auth-passwd.c 9 Jan 2003 12:08:53 -0000 >@@ -42,6 +42,11 @@ > #include "log.h" > #include "servconf.h" > #include "auth.h" >+#include "buffer.h" >+#include "misc.h" >+#include "channels.h" >+#include "monitor_wrap.h" >+#include "auth-options.h" > > #if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) > /* Don't need any of these headers for the PAM or SIA cases */ >@@ -81,9 +86,9 @@ > #endif /* !USE_PAM && !HAVE_OSF_SIA */ > > extern ServerOptions options; >-#ifdef WITH_AIXAUTHENTICATE >-extern char *aixloginmsg; >-#endif >+extern Buffer login_message; >+extern int password_change_required; >+pid_t password_change_pid; /* pid used to reset forwarding flags */ > > /* > * Tries to authenticate the user using password. Returns true if >@@ -123,6 +128,7 @@ > /* deny if no user. */ > if (pw == NULL) > return 0; >+ buffer_init(&login_message); > #ifndef HAVE_CYGWIN > if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES) > return 0; >@@ -149,13 +155,25 @@ > #endif > #ifdef WITH_AIXAUTHENTICATE > authsuccess = (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0); >+ aix_remove_embedded_newlines(authmsg); > >- if (authsuccess) >+ if (authsuccess) { >+ char *msg; >+ >+ debug("authenticate() succeeded for user %s: %.100s", >+ pw->pw_name, authmsg); > /* We don't have a pty yet, so just label the line as "ssh" */ > if (loginsuccess(authctxt->user, >- get_canonical_hostname(options.verify_reverse_mapping), >- "ssh", &aixloginmsg) < 0) >- aixloginmsg = NULL; >+ get_canonical_hostname(options.verify_reverse_mapping), >+ "ssh", &msg) < 0) >+ msg = NULL; >+ buffer_append(&login_message, msg, strlen(msg)); >+ } else { >+ debug("AIX authenticate() failed for user %s: %.100s", >+ pw->pw_name, authmsg); >+ } >+ if (authmsg) >+ xfree(authmsg); > > return(authsuccess); > #endif >@@ -232,4 +250,109 @@ > /* Authentication is accepted if the encrypted passwords are identical. */ > return (strcmp(encrypted_password, pw_password) == 0); > #endif /* !USE_PAM && !HAVE_OSF_SIA */ >+} >+ >+/* >+ * Perform generic password change via tty. Like do_pam_chauthtok(), >+ * it throws a fatal error if the password can't be changed. >+ */ >+int >+do_tty_change_password(struct passwd *pw) >+{ >+ pid_t pid; >+ int status; >+ mysig_t old_signal; >+ >+ old_signal = mysignal(SIGCHLD, SIG_DFL); >+ >+ if ((pid = fork()) == -1) >+ fatal("Couldn't fork: %s", strerror(errno)); >+ >+ if (pid == 0) { >+ setuid(pw->pw_uid); >+ if (geteuid() == 0) >+ execl(PASSWD_PROGRAM_PATH, "passwd", pw->pw_name, >+ (char *)NULL); >+ else >+ execl(PASSWD_PROGRAM_PATH, "passwd", (char *)NULL); >+ >+ /* execl shouldn't return */ >+ fatal("Couldn't exec %s", PASSWD_PROGRAM_PATH); >+ exit(1); >+ } >+ >+ if (waitpid(pid, &status, 0) == -1) >+ fatal("Couldn't wait for child: %s", strerror(errno)); >+ mysignal(SIGCHLD, old_signal); >+ >+ /* >+ * passwd sometimes returns 0 when the password has not been changed >+ * so we re-test via getpwnamallow >+ */ >+ if (WIFEXITED(status) && (WEXITSTATUS(status) == 0) && >+ PRIVSEP(getpwnamallow(pw->pw_name)) != NULL) { >+ debug("password changed sucessfully"); >+ flag_password_change_successful(); >+ return 1; >+ } else { >+ fatal("Failed to change password for %s, passwd returned %d", >+ pw->pw_name, status); >+ return 0; >+ } >+} >+ >+/* >+ * Because an expired password is changed after forking to exec the user's >+ * shell, restoring the port forwarding flags is done by sending a >+ * USR1 signal to the parent after the password is changed successfully. >+ */ >+void >+flag_password_change_required(void) >+{ >+ debug("%s disabling forwarding flags", __func__); >+ /* flag that password change is necessary */ >+ password_change_required = 1; >+ >+ /* disallow other functionality for now */ >+ no_port_forwarding_flag |= 2; >+ no_agent_forwarding_flag |= 2; >+ no_x11_forwarding_flag |= 2; >+ >+ /* set handler to reset flags */ >+ password_change_pid = getpid(); >+ mysignal(SIGUSR1, password_change_successful_handler); >+} >+ >+/* >+ * password change successful, tell parent to restore port >+ * forwarding flags >+ */ >+void >+flag_password_change_successful(void) >+{ >+ debug("%s signalling parent to reset forwarding flags", __func__); >+ kill(password_change_pid, SIGUSR1); >+ >+ /* reset flags in local process too */ >+ password_change_required = 0; >+ no_port_forwarding_flag &= ~2; >+ no_agent_forwarding_flag &= ~2; >+ no_x11_forwarding_flag &= ~2; >+} >+ >+/* >+ * signal handler to reset change flags >+ */ >+void >+password_change_successful_handler(int sig) >+{ >+ debug("%s restoring port forwarding flags", __func__); >+ mysignal(SIGUSR1, SIG_DFL); /* unset handler */ >+ >+ password_change_required = 0; >+ no_port_forwarding_flag &= ~2; >+ no_agent_forwarding_flag &= ~2; >+ no_x11_forwarding_flag &= ~2; >+ if (!no_port_forwarding_flag && options.allow_tcp_forwarding) >+ channel_permit_all_opens(); > } >Index: auth.c >=================================================================== >RCS file: /cvs/openssh/auth.c,v >retrieving revision 1.66 >diff -u -r1.66 auth.c >--- auth.c 9 Jan 2003 04:04:28 -0000 1.66 >+++ auth.c 9 Jan 2003 12:08:53 -0000 >@@ -58,6 +58,8 @@ > /* Debugging messages */ > Buffer auth_debug; > int auth_debug_init; >+extern int password_change_required; >+extern Buffer expire_message; > > /* > * Check if the user is allowed to log in via ssh. If user is listed >@@ -75,9 +77,6 @@ > const char *hostname = NULL, *ipaddr = NULL, *passwd; > char *shell; > int i; >-#ifdef WITH_AIXAUTHENTICATE >- char *loginmsg; >-#endif /* WITH_AIXAUTHENTICATE */ > #if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) > struct spwd *spw; > #if !defined(USE_PAM) && defined(HAS_SHADOW_EXPIRE) >@@ -222,27 +221,58 @@ > * PermitRootLogin to control logins via ssh), or if running as > * non-root user (since loginrestrictions will always fail). > */ >- if ( (pw->pw_uid != 0) && (geteuid() == 0) && >- loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &loginmsg) != 0) { >+ if ( (pw->pw_uid != 0) && (geteuid() == 0) ) { > int loginrestrict_errno = errno; >+ char *msg; > >- if (loginmsg && *loginmsg) { >- /* Remove embedded newlines (if any) */ >- char *p; >- for (p = loginmsg; *p; p++) { >- if (*p == '\n') >- *p = ' '; >+ /* check for AIX account restrictions */ >+ if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg) != 0) { >+ if (msg && *msg) { >+ aix_remove_embedded_newlines(msg); >+ log("Login restricted for %s: %.100s", >+ pw->pw_name, msg); >+ xfree(msg); > } >- /* Remove trailing newline */ >- *--p = '\0'; >- log("Login restricted for %s: %.100s", pw->pw_name, >- loginmsg); >- } >- /* Don't fail if /etc/nologin set */ >- if (!(loginrestrict_errno == EPERM && >- stat(_PATH_NOLOGIN, &st) == 0)) >- return 0; >+ >+ /* Don't fail if /etc/nologin set */ >+ if (!(loginrestrict_errno == EPERM && >+ stat(_PATH_NOLOGIN, &st) == 0)) >+ return 0; >+ } > } >+ >+ /* >+ * Check AIX password expiry. Only check when running as root. >+ * Unpriv'ed users can't access /etc/security/passwd or >+ * /etc/security/user so passwdexpired will always fail. >+ */ >+ if (geteuid() == 0) { >+ char *msg; >+ int passexpcode; >+ >+ passexpcode = passwdexpired(pw->pw_name, &msg); >+ buffer_append(&expire_message, msg, strlen(msg)); >+ if (msg && *msg) >+ aix_remove_embedded_newlines(msg); >+ debug("AIX passwdexpired returned %d, msg %.100s", >+ passexpcode, msg); >+ >+ switch (passexpcode) { >+ case 0: /* success, password not expired */ >+ break; >+ case 1: /* expired, password change required */ >+ flag_password_change_required(); >+ break; >+ default: /* only admin can change (2) or other error (-1) */ >+ log("Password can't be changed for user %s: %.100s", >+ pw->pw_name, msg); >+ if (msg) >+ xfree(msg); >+ return 0; >+ } >+ if (msg) >+ xfree(msg); >+ } > #endif /* WITH_AIXAUTHENTICATE */ > > /* We found no reason not to let this user try to log on... */ >@@ -508,6 +538,7 @@ > #endif > struct passwd *pw; > >+ buffer_init(&expire_message); > pw = getpwnam(user); > if (pw == NULL) { > log("Illegal user %.100s from %.100s", >Index: auth.h >=================================================================== >RCS file: /cvs/openssh/auth.h,v >retrieving revision 1.44 >diff -u -r1.44 auth.h >--- auth.h 27 Sep 2002 03:26:01 -0000 1.44 >+++ auth.h 9 Jan 2003 12:08:53 -0000 >@@ -101,6 +101,7 @@ > > int auth_rhosts_rsa(struct passwd *, char *, Key *); > int auth_password(Authctxt *, const char *); >+int do_tty_change_password(struct passwd *pw); > int auth_rsa(struct passwd *, BIGNUM *); > int auth_rsa_challenge_dialog(Key *); > BIGNUM *auth_rsa_generate_challenge(Key *); >@@ -183,6 +184,8 @@ > void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); > void auth_debug_send(void); > void auth_debug_reset(void); >+ >+void password_change_successful_handler(int); > > #define AUTH_FAIL_MAX 6 > #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) >Index: configure.ac >=================================================================== >RCS file: /cvs/openssh/configure.ac,v >retrieving revision 1.97 >diff -u -r1.97 configure.ac >--- configure.ac 9 Jan 2003 01:22:59 -0000 1.97 >+++ configure.ac 9 Jan 2003 12:08:55 -0000 >@@ -41,6 +41,13 @@ > fi > fi > >+AC_PATH_PROG(PASSWD_PROGRAM_PATH, passwd) >+if test ! -z "$PASSWD_PROGRAM_PATH" ; then >+ AC_DEFINE_UNQUOTED(PASSWD_PROGRAM_PATH, "$PASSWD_PROGRAM_PATH") >+else >+ AC_MSG_ERROR([*** passwd command not found - check config.log ***]) >+fi >+ > if test -z "$LD" ; then > LD=$CC > fi >Index: servconf.c >=================================================================== >RCS file: /cvs/openssh/servconf.c,v >retrieving revision 1.97 >diff -u -r1.97 servconf.c >--- servconf.c 5 Sep 2002 04:35:15 -0000 1.97 >+++ servconf.c 9 Jan 2003 12:08:55 -0000 >@@ -123,6 +123,8 @@ > options->client_alive_count_max = -1; > options->authorized_keys_file = NULL; > options->authorized_keys_file2 = NULL; >+ options->passwd_expire_warn_days = -1; >+ options->forced_passwd_change = -1; > > /* Needs to be accessable in many places */ > use_privsep = -1; >@@ -255,6 +257,10 @@ > } > if (options->authorized_keys_file == NULL) > options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; >+ if (options->passwd_expire_warn_days == -1) >+ options->passwd_expire_warn_days = 14; >+ if (options->forced_passwd_change == -1) >+ options->forced_passwd_change = 1; > > /* Turn privilege separation on by default */ > if (use_privsep == -1) >@@ -302,6 +308,7 @@ > sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, > sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, > sUsePrivilegeSeparation, >+ sPasswordExpireWarningDays, sForcedPasswdChange, > sDeprecated > } ServerOpCodes; > >@@ -380,6 +387,8 @@ > { "authorizedkeysfile", sAuthorizedKeysFile }, > { "authorizedkeysfile2", sAuthorizedKeysFile2 }, > { "useprivilegeseparation", sUsePrivilegeSeparation}, >+ { "passwordexpirewarningdays", sPasswordExpireWarningDays}, >+ { "forcedpasswdchange", sForcedPasswdChange}, > { NULL, sBadOption } > }; > >@@ -908,6 +917,14 @@ > case sClientAliveCountMax: > intptr = &options->client_alive_count_max; > goto parse_int; >+ >+ case sPasswordExpireWarningDays: >+ intptr = &options->passwd_expire_warn_days; >+ goto parse_int; >+ >+ case sForcedPasswdChange: >+ intptr = &options->forced_passwd_change; >+ goto parse_flag; > > case sDeprecated: > log("%s line %d: Deprecated option %s", >Index: servconf.h >=================================================================== >RCS file: /cvs/openssh/servconf.h,v >retrieving revision 1.50 >diff -u -r1.50 servconf.h >--- servconf.h 1 Aug 2002 01:28:39 -0000 1.50 >+++ servconf.h 9 Jan 2003 12:08:55 -0000 >@@ -132,6 +132,9 @@ > char *authorized_keys_file; /* File containing public keys */ > char *authorized_keys_file2; > int pam_authentication_via_kbd_int; >+ int passwd_expire_warn_days; >+ int acct_expire_warn_days; >+ int forced_passwd_change; > } ServerOptions; > > void initialize_server_options(ServerOptions *); >Index: session.c >=================================================================== >RCS file: /cvs/openssh/session.c,v >retrieving revision 1.227 >diff -u -r1.227 session.c >--- session.c 7 Jan 2003 06:38:59 -0000 1.227 >+++ session.c 9 Jan 2003 12:08:57 -0000 >@@ -102,10 +102,9 @@ > /* data */ > #define MAX_SESSIONS 10 > Session sessions[MAX_SESSIONS]; >- >-#ifdef WITH_AIXAUTHENTICATE >-char *aixloginmsg; >-#endif /* WITH_AIXAUTHENTICATE */ >+Buffer expire_message; /* "password will expire/has expired" messages */ >+Buffer login_message; /* message to be displayed after login */ >+int password_change_required = 0; > > #ifdef HAVE_LOGIN_CAP > login_cap_t *lc; >@@ -456,10 +455,11 @@ > #if defined(USE_PAM) > do_pam_session(s->pw->pw_name, NULL); > do_pam_setcred(1); >- if (is_pam_password_change_required()) >+#endif /* USE_PAM */ >+ >+ if (password_change_required) > packet_disconnect("Password change required but no " > "TTY available"); >-#endif /* USE_PAM */ > > /* Fork the child. */ > if ((pid = fork()) == 0) { >@@ -723,6 +723,7 @@ > socklen_t fromlen; > struct sockaddr_storage from; > struct passwd * pw = s->pw; >+ int password_changed = 0; > pid_t pid = getpid(); > > /* >@@ -746,16 +747,23 @@ > options.verify_reverse_mapping), > (struct sockaddr *)&from, fromlen); > >-#ifdef USE_PAM > /* > * If password change is needed, do it now. > * This needs to occur before the ~/.hushlogin check. > */ >+#ifdef USE_PAM > if (is_pam_password_change_required()) { > print_pam_messages(); >- do_pam_chauthtok(); >+ if (!use_privsep) >+ do_pam_chauthtok(); > } > #endif >+ buffer_append(&expire_message, "\0", 1); >+ if (options.forced_passwd_change && password_change_required) { >+ puts((char *)buffer_ptr(&expire_message)); >+ do_tty_change_password(pw); >+ password_changed = 1; >+ } > > if (check_quietlogin(s, command)) > return; >@@ -764,10 +772,12 @@ > if (!is_pam_password_change_required()) > print_pam_messages(); > #endif /* USE_PAM */ >-#ifdef WITH_AIXAUTHENTICATE >- if (aixloginmsg && *aixloginmsg) >- printf("%s\n", aixloginmsg); >-#endif /* WITH_AIXAUTHENTICATE */ >+ if (!password_changed) >+ printf("%s", (char *)buffer_ptr(&expire_message)); >+ >+ /* display post-login message */ >+ buffer_append(&login_message, "\0", 1); >+ puts((char *)buffer_ptr(&login_message)); > > #ifndef NO_SSH_LASTLOG > if (options.print_lastlog && s->last_login_time != 0) { >Index: sshd_config >=================================================================== >RCS file: /cvs/openssh/sshd_config,v >retrieving revision 1.55 >diff -u -r1.55 sshd_config >--- sshd_config 27 Sep 2002 03:21:58 -0000 1.55 >+++ sshd_config 9 Jan 2003 12:08:57 -0000 >@@ -55,6 +55,8 @@ > # To disable tunneled clear text passwords, change to no here! > #PasswordAuthentication yes > #PermitEmptyPasswords no >+#ForcedPasswdChange yes >+#PasswordExpireWarningDays 14 > > # Change to no to disable s/key passwords > #ChallengeResponseAuthentication yes >Index: sshd_config.5 >=================================================================== >RCS file: /cvs/openssh/sshd_config.5,v >retrieving revision 1.12 >diff -u -r1.12 sshd_config.5 >--- sshd_config.5 19 Sep 2002 01:51:22 -0000 1.12 >+++ sshd_config.5 9 Jan 2003 12:08:57 -0000 >@@ -206,6 +206,10 @@ > If the pattern takes the form USER@HOST then USER and HOST > are separately checked, restricting logins to particular > users from particular hosts. >+.It Cm ForcedPasswdChange >+Specifies whether or not a password change will be forced when the >+password is expired. The default is >+.Dq yes . > .It Cm GatewayPorts > Specifies whether remote hosts are allowed to connect to ports > forwarded for the client. >@@ -431,6 +435,12 @@ > Specifies whether password authentication is allowed. > The default is > .Dq yes . >+.It Cm PasswordExpireWarningDays >+If the password will expire in less than the specified number of days, a >+warning will be printed at login. Note that on some platforms (eg AIX) >+this specified by the operating system and this parameter is ignored. >+The default is >+.Dq 14 . > .It Cm PermitEmptyPasswords > When password authentication is allowed, it specifies whether the > server allows login to accounts with empty password strings. >Index: openbsd-compat/port-aix.c >=================================================================== >RCS file: /cvs/openssh/openbsd-compat/port-aix.c,v >retrieving revision 1.6 >diff -u -r1.6 port-aix.c >--- openbsd-compat/port-aix.c 7 Jul 2002 02:17:36 -0000 1.6 >+++ openbsd-compat/port-aix.c 9 Jan 2003 12:08:57 -0000 >@@ -52,5 +52,25 @@ > xfree(cp); > } > >-#endif /* _AIX */ >+#ifdef WITH_AIXAUTHENTICATE >+/* >+ * Remove embedded newlines in string (if any). >+ * Used before logging messages returned by AIX authentication functions >+ * so the message is logged on one line. >+ */ >+void >+aix_remove_embedded_newlines(char *p) >+{ >+ if (p == NULL) >+ return; >+ >+ for (; *p; p++) { >+ if (*p == '\n') >+ *p = ' '; >+ } >+ /* Remove trailing newline */ >+ *--p = '\0'; >+} >+#endif /* WITH_AIXAUTHENTICATE */ > >+#endif /* _AIX */ >Index: openbsd-compat/port-aix.h >=================================================================== >RCS file: /cvs/openssh/openbsd-compat/port-aix.h,v >retrieving revision 1.6 >diff -u -r1.6 port-aix.h >--- openbsd-compat/port-aix.h 7 Jul 2002 02:17:36 -0000 1.6 >+++ openbsd-compat/port-aix.h 9 Jan 2003 12:08:57 -0000 >@@ -26,4 +26,5 @@ > > #ifdef _AIX > void aix_usrinfo(struct passwd *pw); >+void aix_remove_embedded_newlines(char *); > #endif /* _AIX */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 14
:
5
|
199
|
200
|
201
|
205
|
215
|
234
|
240
|
248
|
278
|
540
|
541
|
542
|
543
|
544