[PATCH] PAM chauthtok + Privsep

MPak at dotsconnect.com MPak at dotsconnect.com
Fri Jan 10 20:10:00 EST 2003


Could somebody give me a hint on how to use the patch for password
expiration?
I am about to start "./configure" OpenSSH35p1. I have downloaded Darren
Tucker's id#200, openssh-passwordpatch.11.
This patch has sections like "Index: acconfig.h" and "Index: auth-pam.c".
Do I need to append these sections to appropriate files in the
openssh-3.5.p1 directory?
I have searched the net but could not find an explanation on its usage for
non-developers like myself.

Also I am doing this to fix my first 3.5.p1 build which has a password
expiration problem. Is there any work around, other than rebuilding package
and reinstalling it on servers?
Thank you.
Mesut Pak



                                                                                                                          
                     Darren Tucker                                                                                        
                     <dtucker at zip.com.au>        To:      OpenSSH Devel List <openssh-unix-dev at mindrot.org>               
                     Sent by:                    cc:                                                                      
                     openssh-unix-dev-admin@     Subject:      [PATCH] PAM chauthtok + Privsep                            
                     mindrot.org                                                                                          
                                                                                                                          
                     12/21/2002 07:11 AM                                                                                  
                                                                                                                          
                                                                                                                          
                                                                                                                          


Hello All.
           Attached is an update to my previous patch to make
do_pam_chauthtok and
privsep play nicely together.

           First, a question: does anybody care about these or the password
expiration patches?

           Anyway, the "PRIVSEP(do_pam_hauthtok())" has been moved to just
after
the pty has been allocated but before it's made the controlling tty.
This allows the child running chauthtok to acquire a controlling tty so
the PAM conversation function works without modification.  The child
then runs to completion so the slave can acquire its controlling tty and
continue as normal.

Description from previous patch:
      Attached is a patch that implements password expiry with PAM and
privsep.  It works by passing a descriptor to the tty to the monitor,
which sets up a child with that tty as stdin/stdout/stderr, then runs
chauthtok().  No setuid helpers.

--
Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4  37C9 C982 80C7 8FF4 FA69
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.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       21 Dec 2002 11:39:05 -0000
@@ -42,8 +42,6 @@

 #define NEW_AUTHTOK_MSG \
           "Warning: Your password has expired, please change it now."
-#define NEW_AUTHTOK_MSG_PRIVSEP \
-          "Your password has expired, the session cannot proceed."

 static int do_pam_conversation(int num_msg, const struct pam_message
**msg,
           struct pam_response **resp, void *appdata_ptr);
@@ -186,12 +184,15 @@
                                   pam_retval, PAM_STRERROR(__pamh,
pam_retval));
           }

+/* HP-UX doesn't like credentials to be deleted. Skip and rely on pam_end
() */
+#ifndef __hpux
           if (__pamh && creds_set) {
                     pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED);
                     if (pam_retval != PAM_SUCCESS)
                               debug("Cannot delete credentials[%d]:
%.200s",
                                   pam_retval, PAM_STRERROR(__pamh,
pam_retval));
           }
+#endif

           if (__pamh) {
                     pam_retval = pam_end(__pamh, pam_retval);
@@ -256,10 +257,8 @@
                     case PAM_SUCCESS:
                               /* This is what we want */
                               break;
-#if 0
                     case PAM_NEW_AUTHTOK_REQD:
-                              message_cat(&__pam_msg, use_privsep ?
-                                  NEW_AUTHTOK_MSG_PRIVSEP :
NEW_AUTHTOK_MSG);
+                              message_cat(&__pam_msg, NEW_AUTHTOK_MSG);
                               /* flag that password change is necessary */
                               password_change_required = 1;
                               /* disallow other functionality for now */
@@ -267,7 +266,6 @@
                               no_agent_forwarding_flag |= 2;
                               no_x11_forwarding_flag |= 2;
                               break;
-#endif
                     default:
                               log("PAM rejected by account configuration
[%d]: "
                                   "%.200s", pam_retval, PAM_STRERROR
(__pamh,
@@ -301,6 +299,18 @@
           session_opened = 1;
 }

+/* Set the TTY after session is open */
+void do_pam_set_tty(const char *ttyname) {
+          int pam_retval;
+          if (ttyname != NULL) {
+                    debug("PAM setting tty to \"%.200s\"", ttyname);
+                    pam_retval = pam_set_item(__pamh, PAM_TTY, ttyname);
+                    if (pam_retval != PAM_SUCCESS)
+                              fatal("PAM set tty failed[%d]: %.200s",
+                                  pam_retval, PAM_STRERROR(__pamh,
pam_retval));
+          }
+}
+
 /* Set PAM credentials */
 void do_pam_setcred(int init)
 {
@@ -344,17 +354,15 @@
           do_pam_set_conv(&conv);

           if (password_change_required) {
-                    if (use_privsep)
-                              fatal("Password changing is currently
unsupported"
-                                  " with privilege separation");
                     pamstate = OTHER;
                     pam_retval = pam_chauthtok(__pamh,
PAM_CHANGE_EXPIRED_AUTHTOK);
                     if (pam_retval != PAM_SUCCESS)
                               fatal("PAM pam_chauthtok failed[%d]:
%.200s",
                                   pam_retval, PAM_STRERROR(__pamh,
pam_retval));
-#if 0
                     /* XXX: This would need to be done in the parent
process,
                      * but there's currently no way to pass such request.
*/
+                    password_change_required = 0;
+#if 0
                     no_port_forwarding_flag &= ~2;
                     no_agent_forwarding_flag &= ~2;
                     no_x11_forwarding_flag &= ~2;
Index: auth-pam.h
===================================================================
RCS file: /cvs/openssh/auth-pam.h,v
retrieving revision 1.16
diff -u -r1.16 auth-pam.h
--- auth-pam.h       23 Jul 2002 00:44:07 -0000          1.16
+++ auth-pam.h       21 Dec 2002 11:39:05 -0000
@@ -25,6 +25,8 @@
  */

 #include "includes.h"
+#include "channels.h"
+#include "session.h"
 #ifdef USE_PAM

 #if !defined(SSHD_PAM_SERVICE)
Index: monitor.c
===================================================================
RCS file: /cvs/openssh/monitor.c,v
retrieving revision 1.33
diff -u -r1.33 monitor.c
--- monitor.c        9 Nov 2002 15:47:49 -0000           1.33
+++ monitor.c        21 Dec 2002 11:39:06 -0000
@@ -118,6 +118,7 @@

 #ifdef USE_PAM
 int mm_answer_pam_start(int, Buffer *);
+int mm_answer_pam_chauthtok(int, Buffer *);
 #endif

 #ifdef KRB4
@@ -183,6 +184,9 @@
     {MONITOR_REQ_PTY, 0, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
     {MONITOR_REQ_TERM, 0, mm_answer_term},
+#ifdef USE_PAM
+    {MONITOR_REQ_PAM_CHAUTHTOK, 0, mm_answer_pam_chauthtok},
+#endif
     {0, 0, NULL}
 };

@@ -219,6 +223,9 @@
     {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
     {MONITOR_REQ_TERM, 0, mm_answer_term},
+#ifdef USE_PAM
+    {MONITOR_REQ_PAM_CHAUTHTOK, 0, mm_answer_pam_chauthtok},
+#endif
     {0, 0, NULL}
 };

@@ -328,6 +335,7 @@
           if (!no_pty_flag) {
                     monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
                     monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP,
1);
+                    monitor_permit(mon_dispatch,
MONITOR_REQ_PAM_CHAUTHTOK, 1);
           }

           for (;;)
@@ -746,6 +754,56 @@
           xfree(user);

           return (0);
+}
+
+int
+mm_answer_pam_chauthtok(int socket, Buffer *m)
+{
+          pid_t pid;
+          int ttyfd, status;
+          mysig_t old_signal;
+
+          old_signal = mysignal(SIGCHLD, SIG_DFL);
+
+          ttyfd = mm_receive_fd(socket);
+          debug3("%s: ttyfd=%d, ttyname=%s", __func__, ttyfd,
ttyname(ttyfd));
+
+          if ((pid = fork()) == 0) {
+                    /* acquire controlling tty */
+                    pty_make_controlling_tty(ttyfd, ttyname(ttyfd));
+
+                    /* set up stdin, stdout and stderr */
+                    if (dup2(ttyfd, 0) < 0)
+                              error("dup2 stdin: %s", strerror(errno));
+                    if (dup2(ttyfd, 1) < 0)
+                              error("dup2 stdout: %s", strerror(errno));
+                    if (dup2(ttyfd, 2) < 0)
+                              error("dup2 stderr: %s", strerror(errno));
+
+                    /* close extra descriptors */
+                    close(socket);
+                    close(ttyfd);
+
+                    /* call PAM chauthtok and return status to parent */
+                    do_pam_chauthtok();
+                    if(is_pam_password_change_required())
+                              exit(1);             /* failed */
+                    else
+                              exit(0);        /* success */
+          }
+          close(ttyfd);
+
+          if (waitpid(pid, &status, 0) == -1)
+                    fatal("Couldn't wait for child: %s", strerror(errno));
+
+          if (WEXITSTATUS(status))
+                    fatal("do_pam_chauthtok() failed, child returned %d",
status);
+
+          mysignal(SIGCHLD, old_signal);
+
+          mm_request_send(socket, MONITOR_ANS_PAM_CHAUTHTOK, m);
+
+          return 1;
 }
 #endif

Index: monitor.h
===================================================================
RCS file: /cvs/openssh/monitor.h,v
retrieving revision 1.10
diff -u -r1.10 monitor.h
--- monitor.h        27 Sep 2002 03:26:02 -0000          1.10
+++ monitor.h        21 Dec 2002 11:39:06 -0000
@@ -52,6 +52,7 @@
           MONITOR_REQ_KRB4, MONITOR_ANS_KRB4,
           MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
           MONITOR_REQ_PAM_START,
+          MONITOR_REQ_PAM_CHAUTHTOK, MONITOR_ANS_PAM_CHAUTHTOK,
           MONITOR_REQ_TERM
 };

Index: monitor_wrap.c
===================================================================
RCS file: /cvs/openssh/monitor_wrap.c,v
retrieving revision 1.20
diff -u -r1.20 monitor_wrap.c
--- monitor_wrap.c        27 Sep 2002 03:26:03 -0000          1.20
+++ monitor_wrap.c        21 Dec 2002 11:39:06 -0000
@@ -663,6 +663,31 @@

           buffer_free(&m);
 }
+
+/*
+ * Privsep chauthtok works by passing a descriptor to the session's
+ * stdin/stdout to the monitor, which then sets up a child with this
+ * descriptor as stdin, stdout and controlling terminal, then calls
+ * chauthtok()
+ *
+ * This MUST be called before the session has acquired its controlling
+ * tty or the chauthtok child will not be able to acquire it and
+ * will fail.
+ */
+
+void
+mm_do_pam_chauthtok(void)
+{
+          int result;
+          Buffer m;
+
+          buffer_init(&m);
+          mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_CHAUTHTOK,
&m);
+          mm_send_fd(pmonitor->m_recvfd, STDIN_FILENO);
+          mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_CHAUTHTOK, &m);
+
+          buffer_free(&m);
+}
 #endif /* USE_PAM */

 /* Request process termination */
Index: monitor_wrap.h
===================================================================
RCS file: /cvs/openssh/monitor_wrap.h,v
retrieving revision 1.9
diff -u -r1.9 monitor_wrap.h
--- monitor_wrap.h        27 Sep 2002 03:26:04 -0000          1.9
+++ monitor_wrap.h        21 Dec 2002 11:39:06 -0000
@@ -57,6 +57,7 @@

 #ifdef USE_PAM
 void mm_start_pam(char *);
+void mm_pam_chauthtok(void);
 #endif

 void mm_terminate(void);
Index: session.c
===================================================================
RCS file: /cvs/openssh/session.c,v
retrieving revision 1.222
diff -u -r1.222 session.c
--- session.c        26 Sep 2002 00:38:50 -0000          1.222
+++ session.c        21 Dec 2002 11:39:07 -0000
@@ -454,7 +454,6 @@
           session_proctitle(s);

 #if defined(USE_PAM)
-          do_pam_session(s->pw->pw_name, NULL);
           do_pam_setcred(1);
           if (is_pam_password_change_required())
                     packet_disconnect("Password change required but no "
@@ -581,7 +580,7 @@
           ttyfd = s->ttyfd;

 #if defined(USE_PAM)
-          do_pam_session(s->pw->pw_name, s->tty);
+          do_pam_set_tty(s->tty);
           do_pam_setcred(1);
 #endif

@@ -594,9 +593,6 @@
                     /* Close the master side of the pseudo tty. */
                     close(ptyfd);

-                    /* Make the pseudo tty our controlling tty. */
-                    pty_make_controlling_tty(&ttyfd, s->tty);
-
                     /* Redirect stdin/stdout/stderr from the pseudo tty.
*/
                     if (dup2(ttyfd, 0) < 0)
                               error("dup2 stdin: %s", strerror(errno));
@@ -608,6 +604,24 @@
                     /* Close the extra descriptor for the pseudo tty. */
                     close(ttyfd);

+#ifdef USE_PAM
+                    /*
+                     * If password change is needed, do it now.
+                     * For privsep, this needs to occur before we acquire
a
+                     * controlling tty.
+                     */
+                    print_pam_messages();
+                    if (use_privsep  && is_pam_password_change_required())
+                              PRIVSEP(do_pam_chauthtok());
+#endif
+                    /* Make the pseudo tty our controlling tty. */
+                    pty_make_controlling_tty(&ttyfd, s->tty);
+
+                    /* without privsep, chauthtok requires a controlling
tty */
+                    if (!use_privsep)
+                              do_pam_chauthtok();
+
+
                     /* record login, etc. similar to login(1) */
 #ifndef HAVE_OSF_SIA
                     if (!(options.use_login && command == NULL)) {
@@ -746,16 +760,6 @@
                         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.
-           */
-          if (is_pam_password_change_required()) {
-                    print_pam_messages();
-                    do_pam_chauthtok();
-          }
-#endif

           if (check_quietlogin(s, command))
                     return;
@@ -1238,6 +1242,12 @@
                      * Reestablish them here.
                      */
                     do_pam_setcred(0);
+
+                    /*
+                     * We need to open the session here because PAM on
HP-UX does not
+                     * work after the call to permanently_set_uid.
+                     */
+                    do_pam_session(pw->pw_name,NULL);
 # endif /* USE_PAM */
 # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) ||
defined(WITH_IRIX_ARRAY)
                     irix_setusercontext(pw);







More information about the openssh-unix-dev mailing list