summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2000-12-03 11:51:51 +1100
committerDamien Miller <djm@mindrot.org>2000-12-03 11:51:51 +1100
commitb84815880e453346667d6d2b3f02904674848a7a (patch)
tree03b0870fc18ac4977e1bbf4b0db0e5e79bdcea8b
parentc72745afa96a87d41a22804f48499db12d95dfcd (diff)
- (djm) Added patch from Nalin Dahyabhai <nalin@redhat.com> to enable
PAM authentication using KbdInteractive. - (djm) Added another TODO
-rw-r--r--ChangeLog3
-rw-r--r--Makefile.in2
-rw-r--r--TODO2
-rw-r--r--auth-pam.c35
-rw-r--r--auth-pam.h2
-rw-r--r--auth.h3
-rw-r--r--auth2-pam.c170
-rw-r--r--auth2-pam.h6
-rw-r--r--auth2.c9
-rw-r--r--ssh.h4
10 files changed, 223 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index a3b82951..f598574c 100644
--- 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.
diff --git a/Makefile.in b/Makefile.in
index 3e7d7a89..1e5d4105 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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 de51b3b0..318212dd 100644
--- 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
diff --git a/auth-pam.c b/auth-pam.c
index 9c6e36af..1e077602 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -29,7 +29,7 @@
#include "xmalloc.h"
#include "servconf.h"
-RCSID("$Id: auth-pam.c,v 1.18 2000/10/14 15:08:49 stevesk Exp $");
+RCSID("$Id: auth-pam.c,v 1.19 2000/12/03 00:51:51 djm Exp $");
#define NEW_AUTHTOK_MSG \
"Warning: Your password has expired, please change it now"
@@ -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));
+ }
}
}
diff --git a/auth-pam.h b/auth-pam.h
index 73f68ec2..ca261afe 100644
--- a/auth-pam.h
+++ b/auth-pam.h
@@ -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 c4a8ac54..ef392ace 100644
--- 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
index 00000000..8ffbc244
--- /dev/null
+++ b/auth2-pam.c
@@ -0,0 +1,170 @@
+#include "includes.h"
+RCSID("$Id: auth2-pam.c,v 1.1 2000/12/03 00:51:51 djm Exp $");
+
+#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
index 00000000..db7aaae0
--- /dev/null
+++ b/auth2-pam.h
@@ -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 46bf07c8..8e8edf92 100644
--- 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 2c2afd5a..996b504a 100644
--- 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 */