New PAM kbd-int diff

Damien Miller djm at mindrot.org
Tue Jul 2 12:31:08 EST 2002


Below is a new PAM kbd-int diff based on FreeBSD's code. This code makes
PAM kbd-int work with privilege separation.

Contrary to what I have previously stated - it *does* handle multiple
prompts. What it does not handle is multiple passes through the PAM
conversation function, which would be required for expired password
changing.

I would really appreciate some additional eyes over the monitor code as
I would like to get PAM kbd-int+privsep working.

-d

Index: auth.h
===================================================================
RCS file: /var/cvs/openssh/auth.h,v
retrieving revision 1.42
diff -u -r1.42 auth.h
--- auth.h	6 Jun 2002 20:52:37 -0000	1.42
+++ auth.h	2 Jul 2002 02:19:35 -0000
@@ -133,7 +133,6 @@
 #endif /* KRB5 */
 
 #include "auth-pam.h"
-#include "auth2-pam.h"
 
 Authctxt *do_authentication(void);
 Authctxt *do_authentication2(void);
Index: auth2-chall.c
===================================================================
RCS file: /var/cvs/openssh/auth2-chall.c,v
retrieving revision 1.19
diff -u -r1.19 auth2-chall.c
--- auth2-chall.c	26 Jun 2002 13:58:40 -0000	1.19
+++ auth2-chall.c	2 Jul 2002 02:19:35 -0000
@@ -40,11 +40,17 @@
 
 #ifdef BSD_AUTH
 extern KbdintDevice bsdauth_device;
+extern KbdintDevice mm_bsdauth_device;
 #else
 #ifdef SKEY
 extern KbdintDevice skey_device;
+extern KbdintDevice mm_skey_device;
 #endif
 #endif
+#ifdef USE_PAM
+extern KbdintDevice sshpam_device;
+extern KbdintDevice mm_sshpam_device;
+#endif
 
 KbdintDevice *devices[] = {
 #ifdef BSD_AUTH
@@ -54,6 +60,23 @@
 	&skey_device,
 #endif
 #endif
+#ifdef USE_PAM
+	&sshpam_device,
+#endif
+	NULL
+};
+
+KbdintDevice *mm_devices[] = {
+#ifdef BSD_AUTH
+	&mm_bsdauth_device,
+#else
+#ifdef SKEY
+	&mm_skey_device,
+#endif
+#ifdef USE_PAM
+	&mm_sshpam_device,
+#endif
+#endif
 	NULL
 };
 
@@ -320,18 +343,8 @@
 void
 privsep_challenge_enable(void)
 {
-#ifdef BSD_AUTH
-	extern KbdintDevice mm_bsdauth_device;
-#endif
-#ifdef SKEY
-	extern KbdintDevice mm_skey_device;
-#endif
-	/* As long as SSHv1 has devices[0] hard coded this is fine */
-#ifdef BSD_AUTH
-	devices[0] = &mm_bsdauth_device;
-#else
-#ifdef SKEY
-	devices[0] = &mm_skey_device;
-#endif
-#endif
+	int i;
+	
+	for(i = 0; devices[i] != NULL; i++)
+		devices[i] = mm_devices[i];
 }
Index: auth2-kbdint.c
===================================================================
RCS file: /var/cvs/openssh/auth2-kbdint.c,v
retrieving revision 1.1
diff -u -r1.1 auth2-kbdint.c
--- auth2-kbdint.c	6 Jun 2002 20:27:56 -0000	1.1
+++ auth2-kbdint.c	2 Jul 2002 02:19:35 -0000
@@ -49,10 +49,6 @@
 	if (options.challenge_response_authentication)
 		authenticated = auth2_challenge(authctxt, devs);
 
-#ifdef USE_PAM
-	if (authenticated == 0 && options.pam_authentication_via_kbd_int)
-		authenticated = auth2_pam(authctxt);
-#endif
 	xfree(devs);
 	xfree(lang);
 #ifdef HAVE_CYGWIN
Index: auth2-pam.c
===================================================================
RCS file: /var/cvs/openssh/auth2-pam.c,v
retrieving revision 1.14
diff -u -r1.14 auth2-pam.c
--- auth2-pam.c	28 Jun 2002 16:48:12 -0000	1.14
+++ auth2-pam.c	2 Jul 2002 02:19:35 -0000
@@ -1,166 +1,382 @@
+/*-
+ * Modified from code from FreeBSD:
+ *
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/crypto/openssh/auth2-pam.c,v 1.1 2002/03/21 12:18:27 des Exp $
+ */
+
+/*
+ * XXX: todo:
+ *      - Make this module handle multiple passes through the PAM 
+ *        conversation function. Currently it exits after each reply. 
+ *        It should stick around do it can process password change 
+ *        requests, etc.
+ *     
+ *      - Conver to buffer_() API instead of SOCK_DGRAM messages
+ */
+ 
 #include "includes.h"
-RCSID("$Id: auth2-pam.c,v 1.14 2002/06/28 16:48:12 mouring Exp $");
 
 #ifdef USE_PAM
+RCSID("$Id$");
+
 #include <security/pam_appl.h>
 
 #include "ssh.h"
-#include "ssh2.h"
 #include "auth.h"
-#include "auth-pam.h"
-#include "packet.h"
 #include "xmalloc.h"
-#include "dispatch.h"
 #include "log.h"
+#include "monitor_wrap.h"
+
+extern char *__progname;
 
-static int do_pam_conversation_kbd_int(int num_msg, 
-    const struct pam_message **msg, struct pam_response **resp, 
-    void *appdata_ptr);
-void input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt);
-
-struct {
-	int finished, num_received, num_expected;
-	int *prompts;
-	struct pam_response *responses;
-} context_pam2 = {0, 0, 0, NULL};
-
-static struct pam_conv conv2 = {
-	do_pam_conversation_kbd_int,
-	NULL,
+struct sshpam_ctxt {
+	char		*user;
+	pid_t		 pid;
+	int		 sock;
+	int		 done;
 };
 
-int
-auth2_pam(Authctxt *authctxt)
+/*
+ * Send message to parent or child.
+ */
+static int
+sshpam_send(struct sshpam_ctxt *ctxt, char *fmt, ...)
 {
-	int retval = -1;
-
-	if (authctxt->user == NULL)
-		fatal("auth2_pam: internal error: no user");
+	va_list ap;
+	char *mstr, buf[2048];
+	size_t len;
+	int r;
+
+	va_start(ap, fmt);
+	len = vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+	if (len == -1 || len >= sizeof(buf))
+		fatal("sshpam_send: message too long");
+	mstr = xstrdup(buf);
+	if (ctxt->pid != 0)
+		debug2("to child: %d bytes", len);
+	r = send(ctxt->sock, mstr, len + 1, MSG_EOR);
+	free(mstr);
+	return (r);
+}
 
-	conv2.appdata_ptr = authctxt;
-	do_pam_set_conv(&conv2);
+/*
+ * Peek at first byte of next message.
+ */
+static int
+sshpam_peek(struct sshpam_ctxt *ctxt)
+{
+	char ch;
 
-	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);
+	if (recv(ctxt->sock, &ch, 1, MSG_PEEK) < 1)
+		return (-1);
+	return (ch);
+}
 
-	return retval;
+/*
+ * Receive a message from parent or child.
+ */
+static char *
+sshpam_receive(struct sshpam_ctxt *ctxt)
+{
+	char *buf;
+	size_t len;
+	ssize_t rlen;
+
+	len = 64;
+	buf = NULL;
+	do {
+		len *= 2;
+		buf = xrealloc(buf, len);
+		rlen = recv(ctxt->sock, buf, len, MSG_PEEK);
+		if (rlen < 1) {
+			xfree(buf);
+			return (NULL);
+		}
+	} while (rlen == len);
+	if (recv(ctxt->sock, buf, len, 0) != rlen) {
+		xfree(buf);
+		return (NULL);
+	}
+	if (ctxt->pid != 0)
+		debug2("from child: %s", buf);
+	return (buf);
 }
 
+/*
+ * Conversation function for child process.
+ */
 static int
-do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
-    struct pam_response **resp, void *appdata_ptr)
+sshpam_child_conv(int n,
+	 const struct pam_message **msg,
+	 struct pam_response **resp,
+	 void *data)
 {
-	int i, j, done;
-	char *text;
+	struct sshpam_ctxt *ctxt;
+	int i;
 
-	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);
-
-	text = NULL;
-	for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
-		int style = PAM_MSG_MEMBER(msg, i, msg_style);
-		switch (style) {
-		case PAM_PROMPT_ECHO_ON:
+	ctxt = data;
+	if (n <= 0 || n > PAM_MAX_NUM_MSG)
+		return (PAM_CONV_ERR);
+	if ((*resp = calloc(n, sizeof(struct pam_response))) == NULL)
+		return (PAM_BUF_ERR);
+	for (i = 0; i < n; ++i) {
+		resp[i]->resp_retcode = 0;
+		resp[i]->resp = NULL;
+		switch (msg[i]->msg_style) {
 		case PAM_PROMPT_ECHO_OFF:
-			context_pam2.num_expected++;
+			sshpam_send(ctxt, "p%s", msg[i]->msg);
+			resp[i]->resp = sshpam_receive(ctxt);
+			break;
+		case PAM_PROMPT_ECHO_ON:
+			sshpam_send(ctxt, "P%s", msg[i]->msg);
+			resp[i]->resp = sshpam_receive(ctxt);
 			break;
-		case PAM_TEXT_INFO:
 		case PAM_ERROR_MSG:
-		default:
-			/* Capture all these messages to be sent at once */
-			message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
+			/*sshpam_send(ctxt, "e%s", msg[i]->msg);*/
 			break;
+		case PAM_TEXT_INFO:
+			/*sshpam_send(ctxt, "i%s", msg[i]->msg);*/
+			break;
+		default:
+			goto fail;
 		}
 	}
-
-	if (context_pam2.num_expected == 0)
-		return PAM_SUCCESS;
-
-	packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
-	packet_put_cstring("");	/* Name */
-	packet_put_cstring("");	/* Instructions */
-	packet_put_cstring("");	/* Language */
-	packet_put_int(context_pam2.num_expected);
-	
-	for (i = 0, j = 0; i < num_msg; i++) {
-		int style = PAM_MSG_MEMBER(msg, i, msg_style);
-		
-		/* Skip messages which don't need a reply */
-		if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
-			continue;
-		
-		context_pam2.prompts[j++] = i;
-		if (text) {
-			message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
-			packet_put_cstring(text);
-			text = NULL;
-		} else
-			packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
-		packet_put_char(style == PAM_PROMPT_ECHO_ON);
+	return (PAM_SUCCESS);
+ fail:
+	while (i--) {
+		if (resp[i]->resp) {
+			memset(resp[i]->resp, '\0', strlen(resp[i]->resp));
+			free(resp[i]->resp);
+		}
 	}
-	packet_send();
-	packet_write_wait();
+	free(*resp);
+	*resp = NULL;
+	return (PAM_CONV_ERR);
+}
 
+/*
+ * Child process.
+ */
+static void *
+sshpam_child(struct sshpam_ctxt *ctxt)
+{
+	struct pam_conv conv = { sshpam_child_conv, ctxt };
+	pam_handle_t *sshpamh;
+	int err;
+
+	err = pam_start(SSHD_PAM_SERVICE, ctxt->user, &conv, &sshpamh);
+	if (err != PAM_SUCCESS)
+		goto auth_fail;
+	err = pam_authenticate(sshpamh, 0);
+	if (err != PAM_SUCCESS)
+		goto auth_fail;
+	err = pam_acct_mgmt(sshpamh, 0);
+	if (err != PAM_SUCCESS)
+		goto auth_fail;
+#if 0
 	/*
-	 * 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.
+	 * Can't switch this on until we can handle multiple passes through
+	 * the conversation function
 	 */
-	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;
+	err = pam_acct_mgmt(sshpamh, 0);
+	if (err == PAM_NEW_AUTHTOK_REQD)
+		err = pam_chauthtok(sshpamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+	if (err != PAM_SUCCESS)
+		goto auth_fail;
+#endif
+	sshpam_send(ctxt, "=OK");
+	pam_end(sshpamh, err);
+	exit(0);
+
+ auth_fail:
+	sshpam_send(ctxt, "!%s", pam_strerror(sshpamh, err));
+	pam_end(sshpamh, err);
+	exit(0);
 }
 
-void
-input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt)
+void *
+sshpam_init_ctx(Authctxt *authctxt)
 {
-	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");
+	struct sshpam_ctxt *ctxt;
+	int socks[2];
+	int i;
+
+	debug3("PAM kbd-int init ctx");
+
+	ctxt = xmalloc(sizeof *ctxt);
+	ctxt->user = xstrdup(authctxt->user);
+	ctxt->done = 0;
+	if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, socks) == -1) {
+		error("%s: failed create sockets: %s",
+		    __func__, strerror(errno));
+		xfree(ctxt);
+		return (NULL);
+	}
+	if ((ctxt->pid = fork()) == -1) {
+		error("%s: failed to fork auth-pam child: %s",
+		    __func__, strerror(errno));
+		close(socks[0]);
+		close(socks[1]);
+		xfree(ctxt);
+		return (NULL);
+	}
+	if (ctxt->pid == 0) {
+		/* close everything except our end of the pipe */
+		ctxt->sock = socks[1];
+		for (i = 0; i < getdtablesize(); ++i)
+			if (i != ctxt->sock)
+				close(i);
+		sshpam_child(ctxt);
+		/* not reached */
+		exit(1);
+	}
+	ctxt->sock = socks[0];
+	close(socks[1]);
+	return (ctxt);
+}
 
-	nresp = packet_get_int();	/* Number of responses. */
-	debug("got %d responses", nresp);
+int
+sshpam_query(void *ctx, char **name, char **info,
+    u_int *num, char ***prompts, u_int **echo_on)
+{
+	struct sshpam_ctxt *ctxt = ctx;
+	char *msg;
 
+	debug3("PAM kbd-int query");
 
-	if (nresp != context_pam2.num_expected)
-		fatal("%s: Received incorrect number of responses "
-		    "(expected %d, received %u)", __func__, 
-		    context_pam2.num_expected, nresp);
+	if ((msg = sshpam_receive(ctxt)) == NULL)
+		return (-1);
+	*name = xstrdup("");
+	*info = xstrdup("");
+	*prompts = xmalloc(sizeof(char *));
+	*echo_on = xmalloc(sizeof(u_int));
+	switch (*msg) {
+	case 'P':			/* Prompt with echo */
+	case 'p':			/* Prompt without echo */
+		*num = 1;
+		**prompts = xstrdup(msg + 1);
+		**echo_on = (*msg == 'P');
+		break;
+	case '=':			/* Result */
+		*num = 0;
+		**echo_on = 0;
+		ctxt->done = 1;
+		break;
+	case '!':			/* Error */
+		error("%s", msg + 1);
+	default:
+		*num = 0;
+		**echo_on = 0;
+		xfree(msg);
+		ctxt->done = -1;
+		return (-1);
+	}
+	xfree(msg);
+	return (0);
+}
 
-	if (nresp > 100)
-		fatal("%s: too many replies", __func__);
+int
+sshpam_respond(void *ctx, u_int num, char **resp)
+{
+	struct sshpam_ctxt *ctxt = ctx;
+	char *msg;
 
-	for (i = 0; i < nresp; i++) {
-		int j = context_pam2.prompts[i];
+	debug3("PAM kbd-int %d responses", num);
 
-		resp = packet_get_string(&rlen);
-		context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
-		context_pam2.responses[j].resp = xstrdup(resp);
-		xfree(resp);
-		context_pam2.num_received++;
+	debug2(__func__);
+	switch (ctxt->done) {
+	case 1:
+		return (0);	
+	case 0:
+		break;
+	default:
+		return (-1);
+	}
+	if (num != 1) {
+		error("expected one response, got %u", num);
+		return (-1);
 	}
+	sshpam_send(ctxt, "%s", *resp);
+	switch (sshpam_peek(ctxt)) {
+	case 'P':			/* Prompt with echo */
+	case 'p':			/* Prompt with no echo */
+		return (1);
+	case '=':			/* Result */
+		msg = sshpam_receive(ctxt);
+		xfree(msg);
+		ctxt->done = 1;
+		return (0);
+	default:			/* Error */
+		msg = sshpam_receive(ctxt);
+		if (*msg == '!')
+			error("%s", msg + 1);
+		xfree(msg);
+		ctxt->done = -1;
+		return (-1);
+	}
+}
+
+void
+sshpam_free_ctx(void *ctxtp)
+{
+	struct sshpam_ctxt *ctxt = ctxtp;
 
-	context_pam2.finished = 1;
+	debug3("Freeing PAM kbd-int ctx");
 
-	packet_check_eom();
+	close(ctxt->sock);
+	kill(ctxt->pid, SIGHUP);
+	/* XXX: wait()? */
+	xfree(ctxt->user);
+	xfree(ctxt);
 }
-#endif
+
+KbdintDevice sshpam_device = {
+	"pam",
+	sshpam_init_ctx,
+	sshpam_query,
+	sshpam_respond,
+	sshpam_free_ctx
+};
+
+KbdintDevice mm_sshpam_device = {
+	"pam",
+	mm_sshpam_init_ctx,
+	mm_sshpam_query,
+	mm_sshpam_respond,
+	mm_sshpam_free_ctx
+};
+
+#endif /* USE_PAM */
Index: auth2-pam.h
===================================================================
RCS file: auth2-pam.h
diff -N auth2-pam.h
--- auth2-pam.h	9 Feb 2001 01:55:36 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,8 +0,0 @@
-/* $Id: auth2-pam.h,v 1.2 2001/02/09 01:55:36 djm Exp $ */
-
-#include "includes.h"
-#ifdef USE_PAM
-
-int	auth2_pam(Authctxt *authctxt);
-
-#endif /* USE_PAM */
Index: auth2.c
===================================================================
RCS file: /var/cvs/openssh/auth2.c,v
retrieving revision 1.107
diff -u -r1.107 auth2.c
--- auth2.c	21 Jun 2002 06:21:11 -0000	1.107
+++ auth2.c	2 Jul 2002 02:19:35 -0000
@@ -85,10 +85,6 @@
 	/* challenge-response is implemented via keyboard interactive */
 	if (options.challenge_response_authentication)
 		options.kbd_interactive_authentication = 1;
-	if (options.pam_authentication_via_kbd_int)
-		options.kbd_interactive_authentication = 1;
-	if (use_privsep)
-		options.pam_authentication_via_kbd_int = 0;
 
 	dispatch_init(&dispatch_protocol_error);
 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
Index: monitor.c
===================================================================
RCS file: /var/cvs/openssh/monitor.c,v
retrieving revision 1.22
diff -u -r1.22 monitor.c
--- monitor.c	27 Jun 2002 00:12:58 -0000	1.22
+++ monitor.c	2 Jul 2002 02:19:36 -0000
@@ -118,6 +118,17 @@
 
 #ifdef USE_PAM
 int mm_answer_pam_start(int, Buffer *);
+int mm_answer_sshpam_init_ctx(int, Buffer *);
+int mm_answer_sshpamquery(int, Buffer *);
+int mm_answer_sshpamrespond(int, Buffer *);
+int mm_answer_sshpam_free_ctx(int, Buffer *);
+
+static void *sshpam_auth_ctxt = NULL; /* Local state for PAM kbd-int device */
+
+extern void *sshpam_init_ctx(Authctxt *);
+extern int sshpam_query(void *, char **, char **, u_int *, char ***, u_int **);
+extern int sshpam_respond(void *, u_int , char **);
+extern void sshpam_free_ctx(void *);
 #endif
 
 static Authctxt *authctxt;
@@ -155,7 +166,11 @@
     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
 #ifdef USE_PAM
+    {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_sshpam_init_ctx},
     {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAMQUERY, MON_ISAUTH, mm_answer_sshpamquery},
+    {MONITOR_REQ_PAMRESPOND, MON_AUTH, mm_answer_sshpamrespond},
+    {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE, mm_answer_sshpam_free_ctx},
 #endif
 #ifdef BSD_AUTH
     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
@@ -199,6 +214,13 @@
 #ifdef USE_PAM
     {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
 #endif
+#ifdef USE_PAM
+    {MONITOR_REQ_PAM_INIT_CTX, 0, mm_answer_sshpam_init_ctx},
+    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAMQUERY, MON_ISAUTH, mm_answer_sshpamquery},
+    {MONITOR_REQ_PAMRESPOND, MON_AUTH, mm_answer_sshpamrespond},
+    {MONITOR_REQ_PAM_FREE_CTX, 0, mm_answer_sshpam_free_ctx},
+#endif
     {0, 0, NULL}
 };
 
@@ -731,6 +753,100 @@
 
 	xfree(user);
 
+	monitor_permit(mon_dispatch, MONITOR_REQ_PAM_INIT_CTX, 1);
+
+	return (0);
+}
+
+int
+mm_answer_sshpam_init_ctx(int socket, Buffer *m)
+{
+	debug3("%s: entering", __func__);
+
+	if (sshpam_auth_ctxt == NULL)
+		sshpam_auth_ctxt = sshpam_init_ctx(authctxt);
+
+	monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
+
+	return (0);
+}
+
+int
+mm_answer_sshpamquery(int socket, Buffer *m)
+{
+	char *name, *infotxt;
+	u_int numprompts;
+	u_int *echo_on;
+	char **prompts;
+	int res;
+
+	if (sshpam_auth_ctxt == NULL)
+		fatal("%s: No PAM kbd-int auth context", __func__);
+
+	res = sshpam_query(sshpam_auth_ctxt, &name, &infotxt, &numprompts,
+	    &prompts, &echo_on);
+
+	if (res != -1)
+		debug3("%s: challenge %s", __func__, prompts[0]);
+
+	buffer_clear(m);
+	buffer_put_int(m, res);
+	if (res != -1)
+		buffer_put_cstring(m, prompts[0]);
+
+	debug3("%s: sending PAM challenge res: %d", __func__, res);
+	mm_request_send(socket, MONITOR_ANS_PAMQUERY, m);
+
+	if (res != -1) {
+		xfree(name);
+		xfree(infotxt);
+		xfree(prompts);
+		xfree(echo_on);
+	}
+
+	return (0);
+}
+
+int
+mm_answer_sshpamrespond(int socket, Buffer *m)
+{
+	char *response, *rs[1];
+	int authok;
+
+	if (sshpam_auth_ctxt == NULL)
+		fatal("%s: No PAM kbd-int auth context", __func__);
+
+	response = buffer_get_string(m, NULL);
+	rs[0] = response;
+	
+	authok = sshpam_respond(sshpam_auth_ctxt, 1, rs);
+	debug3("%s: <%s> = <%d>", __func__, response, authok);
+	xfree(response);
+
+	buffer_clear(m);
+	buffer_put_int(m, authok);
+
+	debug3("%s: sending authenticated: %d", __func__, authok == 0);
+	mm_request_send(socket, MONITOR_ANS_PAMRESPOND, m);
+
+	auth_method = "pam";
+
+	sshpam_free_ctx(sshpam_auth_ctxt);
+	sshpam_auth_ctxt = NULL;
+
+	return (authok == 0);
+}
+
+
+int
+mm_answer_sshpam_free_ctx(int socket, Buffer *m)
+{
+	debug3("%s: entering", __func__);
+
+	if (sshpam_auth_ctxt != NULL)
+		sshpam_free_ctx(sshpam_auth_ctxt);
+
+	sshpam_auth_ctxt = NULL;
 	return (0);
 }
 #endif
@@ -1149,6 +1265,10 @@
 
 	/* Turn on permissions for getpwnam */
 	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+#ifdef USE_PAM
+	monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
+#endif
 
 	return (0);
 }
Index: monitor.h
===================================================================
RCS file: /var/cvs/openssh/monitor.h,v
retrieving revision 1.8
diff -u -r1.8 monitor.h
--- monitor.h	11 Jun 2002 16:42:49 -0000	1.8
+++ monitor.h	2 Jul 2002 02:19:36 -0000
@@ -39,6 +39,10 @@
 	MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
 	MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
 	MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+	MONITOR_REQ_PAM_INIT_CTX, 
+	MONITOR_REQ_PAMQUERY, MONITOR_ANS_PAMQUERY,
+	MONITOR_REQ_PAMRESPOND, MONITOR_ANS_PAMRESPOND,
+	MONITOR_REQ_PAM_FREE_CTX,
 	MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
 	MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
 	MONITOR_REQ_KEYEXPORT,
Index: monitor_wrap.c
===================================================================
RCS file: /var/cvs/openssh/monitor_wrap.c,v
retrieving revision 1.13
diff -u -r1.13 monitor_wrap.c
--- monitor_wrap.c	27 Jun 2002 00:23:03 -0000	1.13
+++ monitor_wrap.c	2 Jul 2002 02:19:36 -0000
@@ -830,6 +830,85 @@
 	return ((authok == 0) ? -1 : 0);
 }
 
+void *
+mm_sshpam_init_ctx(struct Authctxt *authctxt)
+{
+	Buffer m;
+
+	debug3("%s: entering", __func__);
+
+	buffer_init(&m);
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m);
+
+	return (authctxt);
+}
+
+int
+mm_sshpam_query(void *ctx, char **name, char **infotxt,
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+	Buffer m;
+	int res;
+	char *challenge;
+
+	debug3("%s: entering", __func__);
+
+	buffer_init(&m);
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAMQUERY, &m);
+
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAMQUERY, &m);
+	res = buffer_get_int(&m);
+	if (res == -1) {
+		debug3("%s: no challenge", __func__);
+		buffer_free(&m);
+		return (-1);
+	}
+
+	/* Get the challenge, and format the response */
+	challenge  = buffer_get_string(&m, NULL);
+	buffer_free(&m);
+
+	debug3("%s: received challenge: %s", __func__, challenge);
+
+	mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
+
+	(*prompts)[0] = challenge;
+
+	return (0);
+}
+
+int
+mm_sshpam_respond(void *ctx, u_int numresponses, char **responses)
+{
+	Buffer m;
+	int authok;
+
+	debug3("%s: entering", __func__);
+	if (numresponses != 1)
+		return (-1);
+
+	buffer_init(&m);
+	buffer_put_cstring(&m, responses[0]);
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAMRESPOND, &m);
+
+	mm_request_receive_expect(pmonitor->m_recvfd,
+	    MONITOR_ANS_PAMRESPOND, &m);
+
+	authok = buffer_get_int(&m);
+	buffer_free(&m);
+
+	return (authok);
+}
+
+void
+mm_sshpam_free_ctx(void *ctxtp)
+{
+	/*
+	 * Dummy function to fill out KbdintDevice struct. The acutal
+	 * freeing of the ctxt is done automatically on auth completion 
+	 */
+}
+
 void
 mm_ssh1_session_id(u_char session_id[16])
 {
Index: monitor_wrap.h
===================================================================
RCS file: /var/cvs/openssh/monitor_wrap.h,v
retrieving revision 1.6
diff -u -r1.6 monitor_wrap.h
--- monitor_wrap.h	13 May 2002 01:07:42 -0000	1.6
+++ monitor_wrap.h	2 Jul 2002 02:19:36 -0000
@@ -83,6 +83,12 @@
 int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
 int mm_skey_respond(void *, u_int, char **);
 
+/* pam */
+void *mm_sshpam_init_ctx(struct Authctxt *);
+int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_sshpam_respond(void *, u_int, char **);
+void mm_sshpam_free_ctx(void *);
+
 /* zlib allocation hooks */
 
 void *mm_zalloc(struct mm_master *, u_int, u_int);
Index: servconf.c
===================================================================
RCS file: /var/cvs/openssh/servconf.c,v
retrieving revision 1.93
diff -u -r1.93 servconf.c
--- servconf.c	25 Jun 2002 03:22:04 -0000	1.93
+++ servconf.c	2 Jul 2002 02:19:36 -0000
@@ -55,10 +55,6 @@
 {
 	memset(options, 0, sizeof(*options));
 
-	/* Portable-specific options */
-	options->pam_authentication_via_kbd_int = -1;
-
-	/* Standard Options */
 	options->num_ports = 0;
 	options->ports_from_cmdline = 0;
 	options->listen_addrs = NULL;
@@ -130,11 +126,6 @@
 void
 fill_default_server_options(ServerOptions *options)
 {
-	/* Portable-specific options */
-	if (options->pam_authentication_via_kbd_int == -1)
-		options->pam_authentication_via_kbd_int = 0;
-
-	/* Standard Options */
 	if (options->protocol == SSH_PROTO_UNKNOWN)
 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
 	if (options->num_host_key_files == 0) {
@@ -271,9 +262,6 @@
 /* Keyword tokens. */
 typedef enum {
 	sBadOption,		/* == unknown option */
-	/* Portable-specific options */
-	sPAMAuthenticationViaKbdInt,
-	/* Standard Options */
 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
 	sPermitRootLogin, sLogFacility, sLogLevel,
 	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
@@ -307,9 +295,6 @@
 	const char *name;
 	ServerOpCodes opcode;
 } keywords[] = {
-	/* Portable-specific options */
-	{ "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
-	/* Standard Options */
 	{ "port", sPort },
 	{ "hostkey", sHostKeyFile },
 	{ "hostdsakey", sHostKeyFile },					/* alias */
@@ -453,12 +438,6 @@
 	charptr = NULL;
 	opcode = parse_token(arg, filename, linenum);
 	switch (opcode) {
-	/* Portable-specific options */
-	case sPAMAuthenticationViaKbdInt:
-		intptr = &options->pam_authentication_via_kbd_int;
-		goto parse_flag;
-
-	/* Standard Options */
 	case sBadOption:
 		return -1;
 	case sPort:
Index: servconf.h
===================================================================
RCS file: /var/cvs/openssh/servconf.h,v
retrieving revision 1.49
diff -u -r1.49 servconf.h
--- servconf.h	21 Jun 2002 01:09:47 -0000	1.49
+++ servconf.h	2 Jul 2002 02:19:36 -0000
@@ -130,7 +130,6 @@
 
 	char   *authorized_keys_file;	/* File containing public keys */
 	char   *authorized_keys_file2;
-	int	pam_authentication_via_kbd_int;
 }       ServerOptions;
 
 void	 initialize_server_options(ServerOptions *);
Index: sshd_config
===================================================================
RCS file: /var/cvs/openssh/sshd_config,v
retrieving revision 1.52
diff -u -r1.52 sshd_config
--- sshd_config	27 Jun 2002 16:59:51 -0000	1.52
+++ sshd_config	2 Jul 2002 02:19:36 -0000
@@ -69,10 +69,6 @@
 # Kerberos TGT Passing only works with the AFS kaserver
 #KerberosTgtPassing no
 
-# Set this to 'yes' to enable PAM keyboard-interactive authentication 
-# Warning: enabling this may bypass the setting of 'PasswordAuthentication'
-#PAMAuthenticationViaKbdInt no
-
 #X11Forwarding no
 #X11DisplayOffset 10
 #X11UseLocalhost yes





More information about the openssh-unix-dev mailing list