]> andersk Git - openssh.git/commitdiff
- (djm) Added patch from Nalin Dahyabhai <nalin@redhat.com> to enable
authordjm <djm>
Sun, 3 Dec 2000 00:51:51 +0000 (00:51 +0000)
committerdjm <djm>
Sun, 3 Dec 2000 00:51:51 +0000 (00:51 +0000)
   PAM authentication using KbdInteractive.
 - (djm) Added another TODO

ChangeLog
Makefile.in
TODO
auth-pam.c
auth-pam.h
auth.h
auth2-pam.c [new file with mode: 0644]
auth2-pam.h [new file with mode: 0644]
auth2.c
ssh.h

index a3b829515b98367e1512b5e412b57d6245820629..f598574cc60413892afd76dff85e3dab23a5a3e3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,6 +29,9 @@
     [sshd.c]
     sshd -D, startup w/o deamon(), for monitoring scripts or inittab;
     from handler@sub-rosa.com and eric@urbanrange.com; ok niels@
+ - (djm) Added patch from Nalin Dahyabhai <nalin@redhat.com> to enable
+   PAM authentication using KbdInteractive.
+ - (djm) Added another TODO
 
 20001202
  - (bal) Backed out of part of Alain St-Denis' loginrec.c patch.
index 3e7d7a89b5084db66ad811934e4d1246b4ad22a8..1e5d4105ad1e3cbb0c1990c28170971290aa896c 100644 (file)
@@ -42,7 +42,7 @@ LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daem
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
 
-SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-skey.o auth2-skey.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-skey.o auth2-skey.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
 
 TROFFMAN       = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 sftp-server.8
 CATMAN         = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 sftp-server.0
diff --git a/TODO b/TODO
index de51b3b0727facc6bacf58c796c2a25384076b56..318212ddc824ae01370f54665595d7392ca5885c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -19,6 +19,8 @@ Programming:
   select() under Linux is not as nice as others, and two the children
   of the shell are not killed on exiting the shell.
 
+- Build an automated test suite
+
 Documentation:
 - More and better
 
index a9cd459a7355a8503630bedc0b60aa30114124fa..ea62a774875dcec68058868ea8e35f44d58cb6aa 100644 (file)
@@ -50,10 +50,26 @@ static const char *pampasswd = NULL;
 static char *pam_msg = NULL;
 
 /* states for pamconv() */
-typedef enum { INITIAL_LOGIN, OTHER } pamstates;
-static pamstates pamstate = INITIAL_LOGIN;
+enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
 /* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */
 static int password_change_required = 0;
+/* remember whether the last pam_authenticate() succeeded or not */
+static int was_authenticated = 0;
+
+/* accessor which allows us to switch conversation structs according to
+ * the authentication method being used */
+void pam_set_conv(struct pam_conv *conv)
+{
+       pam_set_item(pamh, PAM_CONV, conv);
+}
+
+/* start an authentication run */
+int do_pam_authenticate(int flags)
+{
+       int retval = pam_authenticate(pamh, flags);
+       was_authenticated = (retval == PAM_SUCCESS);
+       return retval;
+}
 
 /*
  * PAM conversation function.
@@ -163,6 +179,8 @@ int auth_pam_password(struct passwd *pw, const char *password)
        extern ServerOptions options;
        int pam_retval;
 
+       pam_set_conv(&conv);
+
        /* deny if no user. */
        if (pw == NULL)
                return 0;
@@ -174,7 +192,7 @@ int auth_pam_password(struct passwd *pw, const char *password)
        pampasswd = password;
        
        pamstate = INITIAL_LOGIN;
-       pam_retval = pam_authenticate(pamh, 0);
+       pam_retval = do_pam_authenticate(0);
        if (pam_retval == PAM_SUCCESS) {
                debug("PAM Password authentication accepted for user \"%.100s\"", 
                        pw->pw_name);
@@ -256,8 +274,13 @@ void do_pam_setcred(void)
        debug("PAM establishing creds");
        pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
        if (pam_retval != PAM_SUCCESS) {
-               fatal("PAM setcred failed[%d]: %.200s", 
-                       pam_retval, PAM_STRERROR(pamh, pam_retval));
+               if(was_authenticated) {
+                       fatal("PAM setcred failed[%d]: %.200s", 
+                               pam_retval, PAM_STRERROR(pamh, pam_retval));
+               } else {
+                       debug("PAM setcred failed[%d]: %.200s", 
+                               pam_retval, PAM_STRERROR(pamh, pam_retval));
+               }
        }
 }
 
index 73f68ec2d584e26e09b936eb353e970e81ba01e5..ca261afeb6bfbb76f2ac9ec90450ca51dacd6704 100644 (file)
@@ -7,11 +7,13 @@ void start_pam(struct passwd *pw);
 void finish_pam(void);
 int auth_pam_password(struct passwd *pw, const char *password);
 char **fetch_pam_environment(void);
+int do_pam_authenticate(int flags);
 int do_pam_account(char *username, char *remote_user);
 void do_pam_session(char *username, const char *ttyname);
 void do_pam_setcred(void);
 void print_pam_messages(void);
 int pam_password_change_required(void);
 void do_pam_chauthtok(void);
+void pam_set_conv(struct pam_conv *);
 
 #endif /* USE_PAM */
diff --git a/auth.h b/auth.h
index c4a8ac54407a67811efd5712a8d4a6bc3c813613..ef392ace5ca6e60850492f294542ef33e364503a 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -34,6 +34,9 @@ struct Authctxt {
        struct passwd *pw;
 };
 
+#include "auth-pam.h"
+#include "auth2-pam.h"
+
 void   do_authentication(void);
 void   do_authentication2(void);
 
diff --git a/auth2-pam.c b/auth2-pam.c
new file mode 100644 (file)
index 0000000..a760214
--- /dev/null
@@ -0,0 +1,170 @@
+#include "includes.h"
+RCSID("$Id$");
+
+#ifdef USE_PAM
+#include "ssh.h"
+#include "ssh2.h"
+#include "auth.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "dispatch.h"
+#include <security/pam_appl.h>
+
+struct {
+       int finished, num_received, num_expected;
+       int *prompts;
+       struct pam_response *responses;
+} context_pam2 = {0, 0, 0, NULL};
+
+static int do_conversation2(int num_msg, const struct pam_message **msg,
+                           struct pam_response **resp, void *appdata_ptr);
+
+static struct pam_conv
+conv2 = {
+       do_conversation2,
+       NULL,
+};
+
+void input_userauth_info_response_pam(int type, int plen, void *ctxt);
+
+int
+auth2_pam(Authctxt *authctxt)
+{
+       int retval = -1;
+       char *method = "PAM";
+
+       if (authctxt->user == NULL)
+               fatal("auth2_pam: internal error: no user");
+
+       if (authctxt->valid) {
+               conv2.appdata_ptr = authctxt;
+               pam_set_conv(&conv2);
+       }
+
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
+                    &input_userauth_info_response_pam);
+       retval = (do_pam_authenticate(0) == PAM_SUCCESS);
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+
+       userauth_log(authctxt, retval, method);
+
+       return retval;
+}
+
+static int
+do_conversation2(int num_msg, const struct pam_message **msg,
+                struct pam_response **resp, void *appdata_ptr)
+{
+       int echo = 0, i = 0, j = 0, done = 0;
+       char *tmp = NULL, *text = NULL;
+
+       context_pam2.finished = 0;
+       context_pam2.num_received = 0;
+       context_pam2.num_expected = 0;
+       context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
+       context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
+       memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
+
+       packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
+       packet_put_cstring("");                         /* Name */
+       packet_put_cstring("");                         /* Instructions */
+       packet_put_cstring("");                         /* Language */
+       for (i = 0, j = 0; i < num_msg; i++) {
+               if(((*msg)[i].msg_style == PAM_PROMPT_ECHO_ON) ||
+                  ((*msg)[i].msg_style == PAM_PROMPT_ECHO_OFF) ||
+                  (i == num_msg - 1)) {
+                       j++;
+               }
+       }
+       packet_put_int(j);                              /* Number of prompts. */
+       context_pam2.num_expected = j;
+       for (i = 0, j = 0; i < num_msg; i++) {
+               switch((*msg)[i].msg_style) {
+                       case PAM_PROMPT_ECHO_ON:
+                               echo = 1;
+                               break;
+                       case PAM_PROMPT_ECHO_OFF:
+                               echo = 0;
+                               break;
+                       default:
+                               echo = 0;
+                               break;
+               }
+               if(text) {
+                       tmp = xmalloc(strlen(text) + strlen((*msg)[i].msg) + 2);
+                       strcpy(tmp, text);
+                       strcat(tmp, "\n");
+                       strcat(tmp, (*msg)[i].msg);
+                       xfree(text);
+                       text = tmp;
+                       tmp = NULL;
+               } else {
+                       text = xstrdup((*msg)[i].msg);
+               }
+               if(((*msg)[i].msg_style == PAM_PROMPT_ECHO_ON) ||
+                  ((*msg)[i].msg_style == PAM_PROMPT_ECHO_OFF) ||
+                  (i == num_msg - 1)) {
+                       debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
+                             j, i, text);
+                       context_pam2.prompts[j++] = i;
+                       packet_put_cstring(text);
+                       packet_put_char(echo);
+                       xfree(text);
+                       text = NULL;
+               }
+       }
+       packet_send();
+       packet_write_wait();
+
+       /* Grabbing control of execution and spinning until we get what
+        * we want is probably rude, but it seems to work properly, and
+        * the client *should* be in lock-step with us, so the loop should
+        * only be traversed once. */
+       while(context_pam2.finished == 0) {
+               done = 1;
+               dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
+               if(context_pam2.finished == 0) {
+                       debug("extra packet during conversation");
+               }
+       }
+
+       if(context_pam2.num_received == context_pam2.num_expected) {
+               *resp = context_pam2.responses;
+               return PAM_SUCCESS;
+       } else {
+               return PAM_CONV_ERR;
+       }
+}
+
+void
+input_userauth_info_response_pam(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       unsigned int nresp = 0, rlen = 0, i = 0;
+       char *resp;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_info_response_pam: no authentication context");
+
+       if (authctxt->attempt++ >= AUTH_FAIL_MAX)
+               packet_disconnect("too many failed userauth_requests");
+
+       nresp = packet_get_int();       /* Number of responses. */
+       debug("got %d responses", nresp);
+
+       for (i = 0; i < nresp; i++) {
+               int j = context_pam2.prompts[i];
+               resp = packet_get_string(&rlen);
+               debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
+               context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
+               context_pam2.responses[j].resp = xstrdup(resp);
+               xfree(resp);
+               context_pam2.num_received++;
+       }
+
+       context_pam2.finished = 1;
+
+       packet_done();
+}
+
+#endif
diff --git a/auth2-pam.h b/auth2-pam.h
new file mode 100644 (file)
index 0000000..db7aaae
--- /dev/null
@@ -0,0 +1,6 @@
+#include "includes.h"
+#ifdef USE_PAM
+
+int    auth2_pam(Authctxt *authctxt);
+
+#endif /* USE_PAM */
diff --git a/auth2.c b/auth2.c
index 46bf07c806506d231be1527d7c6cd5910aa78123..8e8edf920db6d83f862e38939a875ebd34a2ff9e 100644 (file)
--- a/auth2.c
+++ b/auth2.c
@@ -400,10 +400,15 @@ userauth_kbdint(Authctxt *authctxt)
        packet_done();
 
        debug("keyboard-interactive language %s devs %s", lang, devs);
+#ifdef USE_PAM
+       if (authenticated == 0)
+               authenticated = auth2_pam(authctxt);
+#endif
 #ifdef SKEY
        /* XXX hardcoded, we should look at devs */
-       if (options.skey_authentication != 0)
-               authenticated = auth2_skey(authctxt);
+       if (authenticated == 0)
+               if (options.skey_authentication != 0)
+                       authenticated = auth2_skey(authctxt);
 #endif
        xfree(lang);
        xfree(devs);
diff --git a/ssh.h b/ssh.h
index 2c2afd5a001b1f61ba59e32887c4516538bdd5d3..996b504a4369c389b697e02779f0d932bff89c51 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -558,8 +558,4 @@ int auth_skey_password(struct passwd * pw, const char *password);
 /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;
 
-#ifdef USE_PAM
-#include "auth-pam.h"
-#endif /* USE_PAM */
-
 #endif                         /* SSH_H */
This page took 0.062054 seconds and 5 git commands to generate.