summaryrefslogtreecommitdiffstats
path: root/auth2-pam.c
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 /auth2-pam.c
parentc72745afa96a87d41a22804f48499db12d95dfcd (diff)
- (djm) Added patch from Nalin Dahyabhai <nalin@redhat.com> to enable
PAM authentication using KbdInteractive. - (djm) Added another TODO
Diffstat (limited to 'auth2-pam.c')
-rw-r--r--auth2-pam.c170
1 files changed, 170 insertions, 0 deletions
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