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