[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

beginnings of a real PAM patch



Hi,

I'm the guy that's maintaining the Linux-PAM source distribution and
it has been a running sore not having a PAM patch for ssh(d).  There
is a patch in existence that provides some access to PAM for simple
password based authentication (this is distributed with the ssh rpms
on www.replay.com).  I'd like to get things going on a better patch
that better includes support for PAM within the ssh main sources.

I've attached a patch that should apply to recent releases of the ssh
source tree and provides some client and server modifications that
establish a new "PAM" authentication mode.  I'm hoping that someone
with some time and a better understanding of "configure" will help
make the patch work! :^)

It may also give people that know about ssh, but not PAM, a better
idea of what PAM can offer and initiate some discussion of whether PAM
should be adopted as an "official" authentication scheme.

Cheers

Andrew
-- 
The latest Linux-PAM source code is available from:

	http://linux.kernel.org/pub/linux/libs/pam/pre/
diff -urN ssh-1.2.20/README.PAM ssh-1.2.20-PAM/README.PAM
--- ssh-1.2.20/README.PAM	Wed Dec 31 16:00:00 1969
+++ ssh-1.2.20-PAM/README.PAM	Sun Sep 28 22:02:36 1997
@@ -0,0 +1,16 @@
+Notes on the integration of PAM authentication into ssh
+
+PAM represents a generic method for authentication and is dynamically
+configurable by the local system administrator.  PAM is the default
+authentication method for both Red Hat Linux and Caldera Open Linux.
+It is also supported by Solaris 2.6 and will likely appear in future
+versions of other UNIXes.
+
+This implementation of PAM requires Linux-PAM 0.59 or better.  It is
+untested against any other implementation of PAM, although it should
+compile against Solaris too.
+
+Your milage may vary...
+
+Andrew G. Morgan <morgan@transmeta.com>
+
diff -urN ssh-1.2.20/acconfig.h ssh-1.2.20-PAM/acconfig.h
--- ssh-1.2.20/acconfig.h	Tue Apr 22 17:40:06 1997
+++ ssh-1.2.20-PAM/acconfig.h	Sun Sep 28 22:42:55 1997
@@ -226,6 +226,9 @@
 /* If defines, this overrides "tty" as the terminal group. */
 #undef TTY_GROUP
 
+/* Define for PAM support */
+#undef HAVE_PAM
+
 /* Define this if you want to support Security Dynammics SecurID
    cards. */
 #undef HAVE_SECURID
diff -urN ssh-1.2.20/configure.in ssh-1.2.20-PAM/configure.in
--- ssh-1.2.20/configure.in	Tue Apr 22 17:40:06 1997
+++ ssh-1.2.20-PAM/configure.in	Sun Sep 28 21:56:46 1997
@@ -661,6 +661,11 @@
 AC_CHECK_SIZEOF(int,4)
 AC_CHECK_SIZEOF(short,2)
 
+if test -f /usr/include/security/pam_appl.h; then
+  AC_DEFINE(HAVE_PAM)
+  LIBS="$LIBS -lpam -ldl"
+fi
+
 if test -z "$no_termios"; then
   AC_CHECK_HEADERS(termios.h)
 fi
diff -urN ssh-1.2.20/log-server.c ssh-1.2.20-PAM/log-server.c
--- ssh-1.2.20/log-server.c	Tue Apr 22 17:40:08 1997
+++ ssh-1.2.20-PAM/log-server.c	Sun Sep 28 21:56:46 1997
@@ -292,6 +292,12 @@
   char buf[1024];
   va_list args;
 
+#ifdef HAVE_PAM
+  if (pamh) {
+      pam_end(pamh, PAM_ABORT);
+      pamh = NULL;
+  }
+#endif /* HAVE_PAM */
   if (log_quiet)
     exit(1);
   va_start(args, fmt);
@@ -311,6 +317,12 @@
   char buf[1024];
   va_list args;
 
+#ifdef HAVE_PAM
+  if (pamh) {
+      pam_end(pamh, PAM_ABORT);
+      pamh = NULL;
+  }
+#endif /* HAVE_PAM */
   if (log_quiet)
     exit(1);
   va_start(args, fmt);
diff -urN ssh-1.2.20/readconf.c ssh-1.2.20-PAM/readconf.c
--- ssh-1.2.20/readconf.c	Tue Apr 22 17:40:11 1997
+++ ssh-1.2.20-PAM/readconf.c	Sun Sep 28 22:17:12 1997
@@ -145,7 +145,8 @@
   oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
   oBatchMode, oStrictHostKeyChecking, oCompression, oCompressionLevel,
   oKeepAlives, oUsePriviledgedPort, oKerberosAuthentication,
-  oKerberosTgtPassing, oClearAllForwardings, oNumberOfPasswordPrompts
+  oKerberosTgtPassing, oClearAllForwardings, oNumberOfPasswordPrompts,
+  oPAMAuthentication
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -188,6 +189,7 @@
   { "kerberostgtpassing", oKerberosTgtPassing },
   { "clearallforwardings", oClearAllForwardings },
   { "numberofpasswordprompts", oNumberOfPasswordPrompts },
+  { "pamauthentication", oPAMAuthentication },
   { NULL, 0 }
 };
 
@@ -301,6 +303,10 @@
       intptr = &options->password_authentication;
       goto parse_flag;
       
+    case oPAMAuthentication:
+      intptr = &options->pam_authentication;
+      goto parse_flag;
+      
     case oRSAAuthentication:
       intptr = &options->rsa_authentication;
       goto parse_flag;
@@ -621,6 +627,7 @@
   options->kerberos_tgt_passing = -1;
   options->tis_authentication = -1;
   options->password_authentication = -1;
+  options->pam_authentication = -1;
   options->rhosts_rsa_authentication = -1;
   options->fallback_to_rsh = -1;
   options->use_rsh = -1;
diff -urN ssh-1.2.20/readconf.h ssh-1.2.20-PAM/readconf.h
--- ssh-1.2.20/readconf.h	Tue Apr 22 17:40:15 1997
+++ ssh-1.2.20-PAM/readconf.h	Sun Sep 28 21:56:46 1997
@@ -73,6 +73,7 @@
   int kerberos_authentication;	/* Try Kerberos authentication. */
   int kerberos_tgt_passing;	/* Try Kerberos tgt passing. */
   int tis_authentication;	/* Try TIS authsrv authentication. */
+    int pam_authentication;     /* Try PAM authentication */
   int password_authentication;	/* Try password authentication. */
   int fallback_to_rsh;		/* Use rsh if cannot connect with ssh. */
   int use_rsh;			/* Always use rsh (don\'t try ssh). */
diff -urN ssh-1.2.20/readpass.c ssh-1.2.20-PAM/readpass.c
--- ssh-1.2.20/readpass.c	Tue Apr 22 17:40:13 1997
+++ ssh-1.2.20-PAM/readpass.c	Sun Sep 28 21:56:46 1997
@@ -73,6 +73,61 @@
   kill(getpid(), sig);
 }
 
+#ifdef HAVE_PAM
+/* Read a prompted string with echo turned _on_ from tty or stdin */
+
+char *read_visible(uid_t uid, const char *prompt, int from_stdin)
+{
+    char buf[1000], *cp;
+    FILE *f;
+
+    if (from_stdin) {
+	f = stdin;
+    } else {
+	f = fopen("/dev/tty", "r");
+	if (f == NULL) {
+	    fatal("No terminal available for input.");
+	}
+    }
+
+    /* this is a quick hack. we should do something a little more
+       like the code in read_passphrase */
+    i = strlen(prompt);
+    i = (i>=sizeof(buf)) ? sizeof(buf)-1:i ;
+    buf[i] = '\0';
+    while (i-->0) {
+	if (isprint(prompt[i]) || isspace(prompt[i]))
+	    buf[i] = prompt[i];
+	else
+	    buf[i] = '?';
+    }
+
+    /* display prompt */
+    fflush(stdout);
+    fprintf(stderr, "%s", buf);
+    fflush(stderr);
+
+    /* read input */
+    if (fgets(buf, sizeof(buf), f) == NULL) {
+	fatal("Aborted.");
+    }
+
+    /* remove trailing newline */
+    if (strchr(buf, '\n'))
+	*strchr(buf, '\n') = 0;
+
+    /* Allocate a copy of the passphrase. */
+    cp = xstrdup(buf);
+
+    /* clean up */
+    memset(buf, 0, sizeof(buf));
+    if (f != stdin)
+	fclose(f);
+
+    return cp;
+}
+#endif /* HAVE_PAM */
+
 /* Reads a passphrase from /dev/tty with echo turned off.  Returns the 
    passphrase (allocated with xmalloc).  Exits if EOF is encountered. 
    The passphrase if read from stdin if from_stdin is true (as is the
diff -urN ssh-1.2.20/servconf.c ssh-1.2.20-PAM/servconf.c
--- ssh-1.2.20/servconf.c	Tue Apr 22 17:40:08 1997
+++ ssh-1.2.20-PAM/servconf.c	Sun Sep 28 22:20:17 1997
@@ -88,6 +88,7 @@
   options->tis_authentication = -1;
   options->allow_tcp_forwarding = -1;
   options->password_authentication = -1;
+  options->pam_authentication = -1;
   options->permit_empty_passwd = -1;
   options->use_login = -1;
   options->silent_deny = -1;
@@ -169,6 +170,8 @@
     options->tis_authentication = 0;
   if (options->password_authentication == -1)
     options->password_authentication = 1;
+  if (options->pam_authentication == -1)
+    options->pam_authentication = 1;
   if (options->permit_empty_passwd == -1)
     options->permit_empty_passwd = 1;
   if (options->use_login == -1)
@@ -194,7 +197,7 @@
   sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sPidFile,
   sForcedPasswd, sUmask, sSilentDeny, sIdleTimeout, sUseLogin,
   sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTgtPassing,
-  sAllowTcpForwarding
+  sAllowTcpForwarding, sPAMAuthentication
 } ServerOpCodes;
 
 /* Textual representation of the tokens. */
@@ -239,6 +242,7 @@
   { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
   { "kerberostgtpassing", sKerberosTgtPassing },
   { "allowtcpforwarding", sAllowTcpForwarding },
+  { "pamauthentication", sPAMAuthentication },
   { NULL, 0 }
 };
 
@@ -498,6 +502,10 @@
 	  goto parse_flag;
 	  
 	case sPasswordAuthentication:
+	  intptr = &options->password_authentication;
+	  goto parse_flag;
+
+	case sPAMAuthentication:
 	  intptr = &options->password_authentication;
 	  goto parse_flag;
 
diff -urN ssh-1.2.20/servconf.h ssh-1.2.20-PAM/servconf.h
--- ssh-1.2.20/servconf.h	Tue Apr 22 17:40:16 1997
+++ ssh-1.2.20-PAM/servconf.h	Sun Sep 28 22:21:15 1997
@@ -78,6 +78,7 @@
   int kerberos_tgt_passing;	/* If true, permit Kerberos tgt passing. */
   int allow_tcp_forwarding;
   int tis_authentication;	/* If true, permit TIS authsrv auth. */
+    int pam_authentication;       /* if true, permit PAM authentication */
   int password_authentication;  /* If true, permit password authentication. */
   int permit_empty_passwd;      /* If false, do not permit empty passwords. */
   int use_login;		/* Use /bin/login if possible */
diff -urN ssh-1.2.20/ssh.h ssh-1.2.20-PAM/ssh.h
--- ssh-1.2.20/ssh.h	Tue Apr 22 17:40:16 1997
+++ ssh-1.2.20-PAM/ssh.h	Sun Sep 28 21:56:46 1997
@@ -302,6 +302,9 @@
 #define SSH_AUTH_RESERVED_7	14
 #define SSH_AUTH_RESERVED_8	15
 
+/* This is for testing now.  I hope this patch becomes "official" - AGM */
+#define SSH_AUTH_PAM            SSH_AUTH_RESERVED_1
+
 /* If you add new methods add them after this using random number between 16-31
    so if someone else adds also new methods you dont use same number. */
 
@@ -379,6 +382,19 @@
    use some random number between 64-127 so if someone else adds something else
    you dont use same numbers */
 
+/* PAM extensions - for interactive server-client authentication */
+
+#define SSH_CMSG_AUTH_PAM_RESERVED              90
+#define SSH_CMSG_AUTH_PAM_START                 91
+#define SSH_CMSG_AUTH_PAM_CONTINUE              92
+#define SSH_CMSG_AUTH_PAM_INPUT                 93
+#define SSH_SMSG_PAM_TEXT_INFO                  94
+#define SSH_SMSG_PAM_ERROR_MSG                  95
+#define SSH_SMSG_PAM_PROMPT_ECHO_ON             96
+#define SSH_SMSG_PAM_PROMPT_ECHO_OFF            97
+#define SSH_SMSG_PAM_BINARY_PROMPT              98
+#define SSH_SMSG_PAM_BINARY_REQUEST             99
+#define SSH_SMSG_PAM_RESERVED                  100
 
 /* define this and debug() will print local hostname */
 #define LOCAL_HOSTNAME_IN_DEBUG 1
@@ -518,6 +534,19 @@
    If this needs to use an auxiliary program to read the passphrase,
    this will run it with the given uid using userfile. */
 char *read_passphrase(uid_t uid, const char *prompt, int from_stdin);
+
+#ifdef HAVE_PAM
+#include <security/pam_appl.h>
+
+/* Reads input from /dev/tty or stdin with echo turned on. Returns the
+   user input (allocated with xmalloc).  Exits (fatal) if EOF is read.
+   If from_stdin is true, the input will be read from stdin instead.
+   If no input file is available, it will terminate the program with
+   fatal.  Note, at this time there is no X-input method */
+char *read_visible(uid_t uid, const char *prompt, int from_stdin);
+
+extern pam_handle_t *pamh;
+#endif /* HAVE_PAM */
 
 /* Reads a yes/no confirmation from /dev/tty.  Exits if EOF or "no" is
    encountered. */
diff -urN ssh-1.2.20/sshconnect.c ssh-1.2.20-PAM/sshconnect.c
--- ssh-1.2.20/sshconnect.c	Tue Apr 22 17:40:11 1997
+++ ssh-1.2.20-PAM/sshconnect.c	Sun Sep 28 21:56:46 1997
@@ -1600,6 +1600,69 @@
     packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
 		      type);
 
+#ifdef HAVE_PAM
+  if ((supported_authentications & (1 << SSH_AUTH_PAM))
+      && options->pam_authentication && !options->batch_mode) {
+      debug("Doing PAM negotiation");
+
+      /* initialize PAM from this end: indicate PAM_USER and PAM_RUSER */
+      packet_start(SSH_CMSG_AUTH_PAM_START);
+      packet_put_string(local_user, strlen(local_user));
+      packet_send();
+      packet_write_wait();
+
+      /* we loop now until the server is satisfied. */
+      while ((type = packet_read())) {
+	  switch (type) {
+	      char *text_info, *input=NULL;
+
+	  case SSH_SMSG_SUCCESS:
+	      return;  /* authentication has been accepted */
+	  case SSH_SMSG_FAILURE:
+	      fatal("Permission denied.");  /* we do not permit any
+					       other method to be
+					       attempted. */
+	  case SSH_SMSG_PAM_TEXT_INFO:
+	  case SSH_SMSG_PAM_ERROR_MSG:
+	      text_info = packet_get_string(NULL);
+	      error(text_info);
+	      xfree(text_info);
+	      /* indicate that it printed */
+	      packet_start(SSH_CMSG_AUTH_PAM_CONTINUE);
+	      break;
+	  case SSH_SMSG_PAM_PROMPT_ECHO_ON:
+	      text_info = packet_get_string(NULL);
+	      input = read_visible(pw->pw_uid, text_info, 0);
+	      xfree(text_info);
+	      /* return prompted-for and echoed text */
+	      packet_start(SSH_CMSG_AUTH_PAM_INPUT);
+	      packet_put_string(input, strlen(input));
+	      memset(input, 0, strlen(input));
+	      xfree(input);
+	      input = NULL;
+	      break;
+	  case SSH_SMSG_PAM_PROMPT_ECHO_OFF:
+	      text_info = packet_get_string(NULL);
+	      input = read_passphrase(pw->pw_uid, text_info, 0);
+	      xfree(text_info);
+	      /* return prompted-for but unechoed text */
+	      packet_start(SSH_CMSG_AUTH_PAM_INPUT);
+	      packet_put_string(input, strlen(input));
+	      memset(input, 0, strlen(input));
+	      xfree(input);
+	      input = NULL;
+	      break;
+	  default:
+	      packet_disconnect("Protocol error: got %d in response"
+				" to PAM auth request", type);
+	  }
+	  /* send response packet */
+	  packet_send();
+	  packet_write_wait();
+      }
+  }
+#endif /* HAVE_PAM */
+
 #ifdef KERBEROS_TGT_PASSING
   /* Try Kerberos tgt passing if the server supports it. */
   if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
diff -urN ssh-1.2.20/sshd.c ssh-1.2.20-PAM/sshd.c
--- ssh-1.2.20/sshd.c	Tue Apr 22 17:40:08 1997
+++ ssh-1.2.20-PAM/sshd.c	Sun Sep 28 21:56:46 1997
@@ -505,6 +505,107 @@
    the private key. */
 RSAPublicKey public_key;
 
+#ifdef HAVE_PAM
+
+/* XXX - we should intercept the timeout alarm.. if the alarm is
+   triggered we need to return PAM_CONV_ERR and then let the
+   do_authentication loop handle the problem.
+
+   XXX - we have currently made no attempt to integrate the pam_*env*
+   calls with the environment usage of this program.  This needs
+   fixing since a number of modules use environment variables! */
+
+/* because of the way the client currently handles PAM requests, we can
+   only use the conversation mechanism during authentication */
+
+static int not_authenticating=1;
+
+static int pam_ssh_conv(int nmsg, const struct pam_message **msg,
+			struct pam_response **resp, void *app_data)
+{
+    struct pam_response *reply;
+    int i, type;
+
+    if (not_authenticating || nmsg < 1 || resp == NULL) {
+	return PAM_CONV_ERR;
+    }
+
+    reply = calloc(nmsg, sizeof(struct pam_response));
+    if (reply == NULL) {
+	return PAM_CONV_ERR;
+    }
+
+    /* loop through all of the messages */
+    for (i=0; i<nmsg; ++i) {
+	switch (msg[i].msg_style) {
+	case PAM_PROMPT_ECHO_OFF:
+	    packet_start(SSH_SMSG_PAM_PROMPT_ECHO_OFF);
+	    break;
+	case PAM_PROMPT_ECHO_ON:
+	    packet_start(SSH_SMSG_PAM_PROMPT_ECHO_ON);
+	    break;
+	case PAM_ERROR_MSG:
+	    packet_start(SSH_SMSG_PAM_ERROR_MSG);
+	    break;
+	case PAM_TEXT_INFO:
+	    packet_start(SSH_SMSG_PAM_TEXT_INFO);
+	    break;
+	default:
+	    goto conversation_failed;
+	}
+
+	packet_put_string(msg[i].msg, strlen(msg[i].msg));
+	packet_send();
+	packet_write_wait();
+	type = packet_read();
+
+	switch (msg[i].msg_style) {
+	case PAM_PROMPT_ECHO_OFF:
+	case PAM_PROMPT_ECHO_ON:
+	    if (type != SSH_CMSG_AUTH_PAM_INPUT) {
+		goto conversation_failed;
+	    }
+	    reply[i].resp = packet_get_string(NULL);
+	    break;
+	case PAM_ERROR_MSG:
+	case PAM_TEXT_INFO:
+	    if (type != SSH_CMSG_AUTH_PAM_CONTINUE) {
+		goto conversation_failed;
+	    }
+	    break;
+	default:
+	    /* how did we get here? */
+	    goto conversation_failed;
+	}
+    }
+
+    *resp = reply;
+
+    return PAM_SUCCESS;
+
+conversation_failed:
+
+    /* clean up before returning */
+    for (i=0; i<nmsg; ++i) {
+	if (reply[i].resp) {
+	    memset(reply[i].resp, 0, strlen(reply[i].resp));
+	    xfree(reply[i].resp);
+	    reply[i].resp = NULL;
+	}
+    }
+    xfree(reply);
+
+    return PAM_CONV_ERR;
+}
+
+/* conversation structure */
+static struct pam_conv ssh_pam_conv = { pam_ssh_conv, NULL };
+
+/* pam handle for current connection */
+pam_handle_t *pamh;
+
+#endif /* HAVE_PAM */
+
 /* Prototypes for various functions defined later in this file. */
 void do_connection(int privileged_port);
 void do_authentication(char *user, int privileged_port, int cipher_type);
@@ -1255,6 +1356,10 @@
 
   /* Declare supported authentication types. */
   auth_mask = 0;
+#ifdef HAVE_PAM
+  if (options.pam_authentication)
+    auth_mask |= 1 << SSH_AUTH_PAM;
+#endif /* HAVE_PAM */
   if (options.rhosts_authentication)
     auth_mask |= 1 << SSH_AUTH_RHOSTS;
   if (options.rhosts_rsa_authentication)
@@ -1749,6 +1854,81 @@
       /* Process the packet. */
       switch (type)
 	{
+#ifdef HAVE_PAM
+	case SSH_CMSG_AUTH_PAM_START:
+	{
+	    int retval, tries;
+	    char *ruser;
+
+	    pamh = NULL;
+	    retval = pam_start("ssh", user, ssh_pam_conv, &pamh);
+	    if (retval != PAM_SUCCESS) {
+		fatal("PAM error.");
+	    }
+
+	    /* we need to fill in as much info about the user as possible */
+	    ruser = packet_get_string(NULL);
+	    retval = pam_set_item(pamh, PAM_RUSER, ruser);
+	    if (retval == PAM_SUCCESS)
+		retval = pam_set_item(pamh, PAM_RHOST,
+				      get_canonical_hostname());
+	    if (retval != PAM_SUCCESS) {
+		fatal("PAM set item error.");
+	    }
+
+	    /* now we attempt to authenticate the user */
+
+	    not_authenticating=0;
+	    do {
+		retval = pam_authenticate(pamh, 0);
+		if (retval == PAM_SUCCESS) {
+		    authenticated = 1;
+		} else {
+		    if (retval == PAM_MAXTRIES || ++password_attempts > 5) {
+			pam_end(pamh, PAM_MAXTRIES);
+			pamh = NULL;
+			packet_disconnect("Too many password authentication"
+					  " attempts from %.100s@%.100s for"
+					  " user %.100s.",
+					  ruser, get_canonical_hostname(),
+					  user);
+		    }
+		}
+	    } while (!authenticated);
+
+	    /* now we test if the user is permitted to log in at this time */
+	    retval = pam_acct_mgmt(pamh, 0);
+	    if (retval != PAM_SUCCESS) {
+		switch (retval) {
+		case PAM_AUTHTOKEN_REQD: /* user's password(s) need renewing */
+		    retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+		    if (PAM_SUCCESS == retval)
+			break;                    /* password safely updated */
+		default:
+		    packet_start(SSH_SMSG_PAM_ERROR_MSG);
+		    packet_put_string("Sorry, you cannot login at this time."
+				      , 37 /* strlen() */);
+		    packet_send();
+		    packet_write_wait();
+		    pam_end(pamh, retval);
+		    packet_disconnect("Account management stopped"
+				      " attempt by %.100s@%.100s for"
+				      " user %.100s.",
+				      ruser, get_canonical_hostname(),
+				      user);
+		}
+	    }
+
+	    xfree(ruser);
+
+	    /* we have successfully logged in and are permitted to do
+	       so at this time. */
+
+	    not_authenticating=1;
+	    authentication_type = SSH_AUTH_PAM;
+	    break;
+	}
+#endif /* HAVE_PAM */
 #ifdef KERBEROS_TGT_PASSING
 #ifdef KRB5
 	case SSH_CMSG_HAVE_KERBEROS_TGT:
@@ -2222,6 +2402,19 @@
   /* Cancel the alarm we set to limit the time taken for authentication. */
   alarm(0);
 
+#ifdef HAVE_PAM
+  /* here we open a pam_session */
+
+  if (pamh) {
+      int retval;
+
+      retval = pam_open_session(pamh, 0);
+      if (retval != PAM_SUCCESS) {
+	  fatal("Failed to open session.");
+      }
+  }
+#endif /* HAVE_PAM */
+
   /* Inform the channel mechanism that we are the server side and that
      the client may request to connect to any port at all.  (The user could
      do it anyway, and we wouldn\'t know what is permitted except by the
@@ -2670,6 +2863,17 @@
     last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
 					  buf, sizeof(buf));
 
+#ifdef HAVE_PAM
+  if (pamh != NULL) {
+      int retval;
+
+      retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+      if (retval != PAM_SUCCESS) {
+	  fatal("Failed setting credentials.");
+      }
+  }
+#endif /* HAVE_PAM */
+
   /* Fork the child. */
   if ((pid = fork()) == 0)
     { 
@@ -2799,6 +3003,24 @@
   /* server_loop has closed ptyfd and fdout. */
   /* server_loop has already Released the pseudo-tty. */
 
+#ifdef HAVE_PAM
+  if (pamh != NULL) {
+      int retval;
+
+      retval = pam_setcred(pamh, PAM_DELETE_CRED);
+      if (retval != PAM_SUCCESS) {
+	  fatal("Failed deleting credentials.");
+      }
+      retval = pam_session_close(pamh, 0);
+      if (retval != PAM_SUCCESS) {
+	  fatal("Failed closing session.");
+      }
+
+      pam_end(pamh, retval);
+      pamh = NULL;
+  }
+#endif /* HAVE_PAM */
+
   /* Cancel the cleanup function. */
   fatal_remove_cleanup(pty_cleanup_proc, (void *)&cleanup_context);
 
@@ -3419,6 +3641,18 @@
 	cp = shell;
     }
   
+#ifdef HAVE_PAM
+  /* XXX - we should also have taken the environment from PAM */
+  if (pamh != NULL) {
+      pam_end(pamh, PAM_SUCCESS
+#ifdef PAM_DATA_QUIET                                  /* Linux-PAM only */
+	      | PAM_DATA_QUIET
+#endif
+	  );
+      pamh = NULL;
+  }
+#endif /* HAVE_PAM */
+
   /* If we have no command, execute the shell.  In this case, the shell name
      to be passed in argv[0] is preceded by '-' to indicate that this is
      a login shell. */

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] []