aboutsummaryrefslogtreecommitdiffstats
path: root/security/openssh-portable
diff options
context:
space:
mode:
authordinoex <dinoex@FreeBSD.org>2003-09-26 10:42:39 +0800
committerdinoex <dinoex@FreeBSD.org>2003-09-26 10:42:39 +0800
commit8ac1d5419b7e5565c98f9d3f9bf291195971204e (patch)
tree4ae0129b69b4ac704df5f54e56f1311ea9ea0291 /security/openssh-portable
parent250c7a84410f76ffb6bfb6969c66bce9749e271b (diff)
downloadfreebsd-ports-gnome-8ac1d5419b7e5565c98f9d3f9bf291195971204e.tar.gz
freebsd-ports-gnome-8ac1d5419b7e5565c98f9d3f9bf291195971204e.tar.zst
freebsd-ports-gnome-8ac1d5419b7e5565c98f9d3f9bf291195971204e.zip
- Security Fix in PAM handling
Obtained from: des
Diffstat (limited to 'security/openssh-portable')
-rw-r--r--security/openssh-portable/Makefile4
-rw-r--r--security/openssh-portable/files/auth2-pam-freebsd.c444
-rw-r--r--security/openssh-portable/files/patch-auth-chall.c36
-rw-r--r--security/openssh-portable/files/patch-auth-pam.c91
-rw-r--r--security/openssh-portable/files/patch-auth-pam.h13
5 files changed, 508 insertions, 80 deletions
diff --git a/security/openssh-portable/Makefile b/security/openssh-portable/Makefile
index 85ccd9cbafde..a6927bc37185 100644
--- a/security/openssh-portable/Makefile
+++ b/security/openssh-portable/Makefile
@@ -7,7 +7,7 @@
PORTNAME= openssh
PORTVERSION= 3.6.1p2
-PORTREVISION= 4
+PORTREVISION= 5
CATEGORIES= security ipv6
MASTER_SITES= ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/ \
ftp://carroll.cac.psu.edu/pub/OpenBSD/OpenSSH/portable/
@@ -16,8 +16,6 @@ PKGNAMESUFFIX?= -portable
MAINTAINER= dinoex@FreeBSD.org
COMMENT= The portable version of OpenBSD's OpenSSH
-FORBIDDEN= Security Problem with PAM
-
MAN1= sftp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 scp.1 ssh.1
MLINKS= ssh.1 slogin.1
MAN5= ssh_config.5 sshd_config.5
diff --git a/security/openssh-portable/files/auth2-pam-freebsd.c b/security/openssh-portable/files/auth2-pam-freebsd.c
index 624021171258..5bf4d734dd34 100644
--- a/security/openssh-portable/files/auth2-pam-freebsd.c
+++ b/security/openssh-portable/files/auth2-pam-freebsd.c
@@ -15,9 +15,6 @@
* 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
@@ -33,35 +30,96 @@
*/
#include "includes.h"
-RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh-portable/files/Attic/auth2-pam-freebsd.c,v 1.4 2002-10-17 04:40:20 dinoex Exp $");
+RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh-portable/files/Attic/auth2-pam-freebsd.c,v 1.5 2003-09-26 02:42:39 dinoex Exp $");
#ifdef USE_PAM
#include <security/pam_appl.h>
#include "auth.h"
+#include "auth-pam.h"
#include "buffer.h"
#include "bufaux.h"
+#include "canohost.h"
#include "log.h"
#include "monitor_wrap.h"
#include "msg.h"
#include "packet.h"
+#include "readpass.h"
+#include "servconf.h"
#include "ssh2.h"
#include "xmalloc.h"
+#ifdef USE_POSIX_THREADS
+#include <pthread.h>
+#else
+/*
+ * Simulate threads with processes.
+ */
+typedef pid_t pthread_t;
+
+static void
+pthread_exit(void *value __unused)
+{
+ _exit(0);
+}
+
+static int
+pthread_create(pthread_t *thread, const void *attr __unused,
+ void *(*thread_start)(void *), void *arg)
+{
+ pid_t pid;
+
+ switch ((pid = fork())) {
+ case -1:
+ error("fork(): %s", strerror(errno));
+ return (-1);
+ case 0:
+ thread_start(arg);
+ _exit(1);
+ default:
+ *thread = pid;
+ return (0);
+ }
+}
+
+static int
+pthread_cancel(pthread_t thread)
+{
+ return (kill(thread, SIGTERM));
+}
+
+static int
+pthread_join(pthread_t thread, void **value __unused)
+{
+ int status;
+
+ waitpid(thread, &status, 0);
+ return (status);
+}
+#endif
+
+
+static pam_handle_t *pam_handle;
+static int pam_err;
+static int pam_authenticated;
+static int pam_new_authtok_reqd;
+static int pam_session_open;
+static int pam_cred_established;
+
struct pam_ctxt {
- char *pam_user;
- pid_t pam_pid;
- int pam_sock;
+ pthread_t pam_thread;
+ int pam_psock;
+ int pam_csock;
int pam_done;
};
static void pam_free_ctx(void *);
/*
- * Conversation function for child process.
+ * Conversation function for authentication thread.
*/
static int
-pam_child_conv(int n,
+pam_thread_conv(int n,
const struct pam_message **msg,
struct pam_response **resp,
void *data)
@@ -76,32 +134,32 @@ pam_child_conv(int n,
*resp = xmalloc(n * sizeof **resp);
buffer_init(&buffer);
for (i = 0; i < n; ++i) {
- resp[i]->resp_retcode = 0;
- resp[i]->resp = NULL;
+ (*resp)[i].resp_retcode = 0;
+ (*resp)[i].resp = NULL;
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
buffer_put_cstring(&buffer, msg[i]->msg);
- ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
- ssh_msg_recv(ctxt->pam_sock, &buffer);
+ ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
+ ssh_msg_recv(ctxt->pam_csock, &buffer);
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
goto fail;
- resp[i]->resp = buffer_get_string(&buffer, NULL);
+ (*resp)[i].resp = buffer_get_string(&buffer, NULL);
break;
case PAM_PROMPT_ECHO_ON:
buffer_put_cstring(&buffer, msg[i]->msg);
- ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
- ssh_msg_recv(ctxt->pam_sock, &buffer);
+ ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
+ ssh_msg_recv(ctxt->pam_csock, &buffer);
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
goto fail;
- resp[i]->resp = buffer_get_string(&buffer, NULL);
+ (*resp)[i].resp = buffer_get_string(&buffer, NULL);
break;
case PAM_ERROR_MSG:
buffer_put_cstring(&buffer, msg[i]->msg);
- ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
+ ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
break;
case PAM_TEXT_INFO:
buffer_put_cstring(&buffer, msg[i]->msg);
- ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
+ ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
break;
default:
goto fail;
@@ -111,8 +169,6 @@ pam_child_conv(int n,
buffer_free(&buffer);
return (PAM_SUCCESS);
fail:
- while (i)
- xfree(resp[--i]);
xfree(*resp);
*resp = NULL;
buffer_free(&buffer);
@@ -120,51 +176,119 @@ pam_child_conv(int n,
}
/*
- * Child process.
+ * Authentication thread.
*/
static void *
-pam_child(struct pam_ctxt *ctxt)
+pam_thread(void *ctxtp)
{
+ struct pam_ctxt *ctxt = ctxtp;
Buffer buffer;
- struct pam_conv pam_conv;
- pam_handle_t *pamh;
- int pam_err;
+ struct pam_conv pam_conv = { pam_thread_conv, ctxt };
+
+#ifndef USE_POSIX_THREADS
+ {
+ const char *pam_user;
- pam_conv.conv = pam_child_conv;
- pam_conv.appdata_ptr = ctxt;
+ pam_get_item(pam_handle, PAM_USER, (const void **)&pam_user);
+ setproctitle("%s [pam]", pam_user);
+ }
+#endif
buffer_init(&buffer);
- setproctitle("%s [pam]", ctxt->pam_user);
- pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh);
+ pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
if (pam_err != PAM_SUCCESS)
goto auth_fail;
- pam_err = pam_authenticate(pamh, 0);
+ pam_err = pam_authenticate(pam_handle, 0);
if (pam_err != PAM_SUCCESS)
goto auth_fail;
- pam_err = pam_acct_mgmt(pamh, 0);
- if (pam_err != PAM_SUCCESS)
+ pam_err = pam_acct_mgmt(pam_handle, 0);
+ if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
goto auth_fail;
buffer_put_cstring(&buffer, "OK");
- ssh_msg_send(ctxt->pam_sock, PAM_SUCCESS, &buffer);
+ ssh_msg_send(ctxt->pam_csock, pam_err, &buffer);
buffer_free(&buffer);
- pam_end(pamh, pam_err);
- exit(0);
+ pthread_exit(NULL);
auth_fail:
- buffer_put_cstring(&buffer, pam_strerror(pamh, pam_err));
- ssh_msg_send(ctxt->pam_sock, PAM_AUTH_ERR, &buffer);
+ buffer_put_cstring(&buffer,
+ pam_strerror(pam_handle, pam_err));
+ ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
buffer_free(&buffer);
- pam_end(pamh, pam_err);
- exit(0);
+ pthread_exit(NULL);
}
static void
-pam_cleanup(void *ctxtp)
+pam_thread_cleanup(void *ctxtp)
{
struct pam_ctxt *ctxt = ctxtp;
- int status;
- close(ctxt->pam_sock);
- kill(ctxt->pam_pid, SIGHUP);
- waitpid(ctxt->pam_pid, &status, 0);
+ pthread_cancel(ctxt->pam_thread);
+ pthread_join(ctxt->pam_thread, NULL);
+ close(ctxt->pam_psock);
+ close(ctxt->pam_csock);
+}
+
+static int
+pam_null_conv(int n,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *data)
+{
+
+ return (PAM_CONV_ERR);
+}
+
+static struct pam_conv null_conv = { pam_null_conv, NULL };
+
+static void
+pam_cleanup(void *arg)
+{
+ (void)arg;
+ debug("PAM: cleanup");
+ pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
+ if (pam_cred_established) {
+ pam_setcred(pam_handle, PAM_DELETE_CRED);
+ pam_cred_established = 0;
+ }
+ if (pam_session_open) {
+ pam_close_session(pam_handle, PAM_SILENT);
+ pam_session_open = 0;
+ }
+ pam_authenticated = pam_new_authtok_reqd = 0;
+ pam_end(pam_handle, pam_err);
+ pam_handle = NULL;
+}
+
+static int
+pam_init(const char *user)
+{
+ extern ServerOptions options;
+ extern u_int utmp_len;
+ const char *pam_rhost, *pam_user;
+
+ if (pam_handle != NULL) {
+ /* We already have a PAM context; check if the user matches */
+ pam_err = pam_get_item(pam_handle,
+ PAM_USER, (const void **)&pam_user);
+ if (pam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
+ return (0);
+ fatal_remove_cleanup(pam_cleanup, NULL);
+ pam_end(pam_handle, pam_err);
+ pam_handle = NULL;
+ }
+ debug("PAM: initializing for \"%s\"", user);
+ pam_err = pam_start("sshd", user, &null_conv, &pam_handle);
+ if (pam_err != PAM_SUCCESS)
+ return (-1);
+ pam_rhost = get_remote_name_or_ip(utmp_len,
+ options.verify_reverse_mapping);
+ debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
+ pam_err = pam_set_item(pam_handle, PAM_RHOST, pam_rhost);
+ if (pam_err != PAM_SUCCESS) {
+ pam_end(pam_handle, pam_err);
+ pam_handle = NULL;
+ return (-1);
+ }
+ fatal_add_cleanup(pam_cleanup, NULL);
+ return (0);
}
static void *
@@ -172,38 +296,33 @@ pam_init_ctx(Authctxt *authctxt)
{
struct pam_ctxt *ctxt;
int socks[2];
- int i;
+
+ /* Initialize PAM */
+ if (pam_init(authctxt->user) == -1) {
+ error("PAM: initialization failed");
+ return (NULL);
+ }
ctxt = xmalloc(sizeof *ctxt);
- ctxt->pam_user = xstrdup(authctxt->user);
ctxt->pam_done = 0;
+
+ /* Start the authentication thread */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
- error("%s: failed create sockets: %s",
- __func__, strerror(errno));
+ error("PAM: failed create sockets: %s", strerror(errno));
xfree(ctxt);
return (NULL);
}
- if ((ctxt->pam_pid = fork()) == -1) {
- error("%s: failed to fork auth-pam child: %s",
- __func__, strerror(errno));
+ ctxt->pam_psock = socks[0];
+ ctxt->pam_csock = socks[1];
+ if (pthread_create(&ctxt->pam_thread, NULL, pam_thread, ctxt) == -1) {
+ error("PAM: failed to start authentication thread: %s",
+ strerror(errno));
close(socks[0]);
close(socks[1]);
xfree(ctxt);
return (NULL);
}
- if (ctxt->pam_pid == 0) {
- /* close everything except our end of the pipe */
- ctxt->pam_sock = socks[1];
- for (i = 3; i < getdtablesize(); ++i)
- if (i != ctxt->pam_sock)
- close(i);
- pam_child(ctxt);
- /* not reached */
- exit(1);
- }
- ctxt->pam_sock = socks[0];
- close(socks[1]);
- fatal_add_cleanup(pam_cleanup, ctxt);
+ fatal_add_cleanup(pam_thread_cleanup, ctxt);
return (ctxt);
}
@@ -224,7 +343,7 @@ pam_query(void *ctx, char **name, char **info,
**prompts = NULL;
plen = 0;
*echo_on = xmalloc(sizeof(u_int));
- while (ssh_msg_recv(ctxt->pam_sock, &buffer) == 0) {
+ while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
type = buffer_get_char(&buffer);
msg = buffer_get_string(&buffer, NULL);
switch (type) {
@@ -243,6 +362,9 @@ pam_query(void *ctx, char **name, char **info,
plen += sprintf(**prompts + plen, "%s", msg);
xfree(msg);
break;
+ case PAM_NEW_AUTHTOK_REQD:
+ pam_new_authtok_reqd = 1;
+ /* FALLTHROUGH */
case PAM_SUCCESS:
case PAM_AUTH_ERR:
if (**prompts != NULL) {
@@ -264,7 +386,7 @@ pam_query(void *ctx, char **name, char **info,
xfree(msg);
return (0);
}
- error("%s", msg);
+ error("PAM: %s", msg);
default:
*num = 0;
**echo_on = 0;
@@ -283,22 +405,23 @@ pam_respond(void *ctx, u_int num, char **resp)
struct pam_ctxt *ctxt = ctx;
char *msg;
- debug2(__func__);
+ debug2("PAM: %s", __func__);
switch (ctxt->pam_done) {
case 1:
- return (0);
+ pam_authenticated = 1;
+ return (0);
case 0:
break;
default:
return (-1);
}
if (num != 1) {
- error("expected one response, got %u", num);
+ error("PAM: expected one response, got %u", num);
return (-1);
}
buffer_init(&buffer);
buffer_put_cstring(&buffer, *resp);
- ssh_msg_send(ctxt->pam_sock, PAM_AUTHTOK, &buffer);
+ ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer);
buffer_free(&buffer);
return (1);
}
@@ -307,14 +430,16 @@ static void
pam_free_ctx(void *ctxtp)
{
struct pam_ctxt *ctxt = ctxtp;
- int status;
- fatal_remove_cleanup(pam_cleanup, ctxt);
- close(ctxt->pam_sock);
- kill(ctxt->pam_pid, SIGHUP);
- waitpid(ctxt->pam_pid, &status, 0);
- xfree(ctxt->pam_user);
+ fatal_remove_cleanup(pam_thread_cleanup, ctxt);
+ pam_thread_cleanup(ctxtp);
xfree(ctxt);
+ /*
+ * We don't call pam_cleanup() here because we may need the PAM
+ * handle at a later stage, e.g. when setting up a session. It's
+ * still on the cleanup list, so pam_end() *will* be called before
+ * the server process terminates.
+ */
}
KbdintDevice pam_device = {
@@ -333,4 +458,169 @@ KbdintDevice mm_pam_device = {
mm_pam_free_ctx
};
+/*
+ * This replaces auth-pam.c
+ */
+void
+start_pam(const char *user)
+{
+ if (pam_init(user) == -1)
+ fatal("PAM: initialisation failed");
+}
+
+void
+finish_pam(void)
+{
+ fatal_remove_cleanup(pam_cleanup, NULL);
+ pam_cleanup(NULL);
+}
+
+int
+do_pam_account(const char *user, const char *ruser)
+{
+ /* XXX */
+ return (1);
+}
+
+void
+do_pam_session(const char *user, const char *tty)
+{
+ pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: failed to set PAM_CONV: %s",
+ pam_strerror(pam_handle, pam_err));
+ debug("PAM: setting PAM_TTY to \"%s\"", tty);
+ pam_err = pam_set_item(pam_handle, PAM_TTY, tty);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: failed to set PAM_TTY: %s",
+ pam_strerror(pam_handle, pam_err));
+ pam_err = pam_open_session(pam_handle, 0);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: pam_open_session(): %s",
+ pam_strerror(pam_handle, pam_err));
+ pam_session_open = 1;
+}
+
+void
+do_pam_setcred(int init)
+{
+ pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: failed to set PAM_CONV: %s",
+ pam_strerror(pam_handle, pam_err));
+ if (init) {
+ debug("PAM: establishing credentials");
+ pam_err = pam_setcred(pam_handle, PAM_ESTABLISH_CRED);
+ } else {
+ debug("PAM: reinitializing credentials");
+ pam_err = pam_setcred(pam_handle, PAM_REINITIALIZE_CRED);
+ }
+ if (pam_err == PAM_SUCCESS) {
+ pam_cred_established = 1;
+ return;
+ }
+ if (pam_authenticated)
+ fatal("PAM: pam_setcred(): %s",
+ pam_strerror(pam_handle, pam_err));
+ else
+ debug("PAM: pam_setcred(): %s",
+ pam_strerror(pam_handle, pam_err));
+}
+
+int
+is_pam_password_change_required(void)
+{
+ return (pam_new_authtok_reqd);
+}
+
+static int
+pam_chauthtok_conv(int n,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *data)
+{
+ char input[PAM_MAX_MSG_SIZE];
+ int i;
+
+ if (n <= 0 || n > PAM_MAX_NUM_MSG)
+ return (PAM_CONV_ERR);
+ *resp = xmalloc(n * sizeof **resp);
+ for (i = 0; i < n; ++i) {
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ (*resp)[i].resp =
+ read_passphrase(msg[i]->msg, RP_ALLOW_STDIN);
+ (*resp)[i].resp_retcode = PAM_SUCCESS;
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ fputs(msg[i]->msg, stderr);
+ fgets(input, sizeof input, stdin);
+ (*resp)[i].resp = xstrdup(input);
+ (*resp)[i].resp_retcode = PAM_SUCCESS;
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ fputs(msg[i]->msg, stderr);
+ (*resp)[i].resp_retcode = PAM_SUCCESS;
+ break;
+ default:
+ goto fail;
+ }
+ }
+ return (PAM_SUCCESS);
+ fail:
+ xfree(*resp);
+ *resp = NULL;
+ return (PAM_CONV_ERR);
+}
+
+/*
+ * XXX this should be done in the authentication phase, but ssh1 doesn't
+ * support that
+ */
+void
+do_pam_chauthtok(void)
+{
+ struct pam_conv pam_conv = { pam_chauthtok_conv, NULL };
+
+ if (use_privsep)
+ fatal("PAM: chauthtok not supprted with privsep");
+ pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: failed to set PAM_CONV: %s",
+ pam_strerror(pam_handle, pam_err));
+ debug("PAM: changing password");
+ pam_err = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_err != PAM_SUCCESS)
+ fatal("PAM: pam_chauthtok(): %s",
+ pam_strerror(pam_handle, pam_err));
+}
+
+void
+print_pam_messages(void)
+{
+ /* XXX */
+}
+
+char **
+fetch_pam_environment(void)
+{
+#ifdef HAVE_PAM_GETENVLIST
+ debug("PAM: retrieving environment");
+ return (pam_getenvlist(pam_handle));
+#else
+ return (NULL);
+#endif
+}
+
+void
+free_pam_environment(char **env)
+{
+ char **envp;
+
+ for (envp = env; *envp; envp++)
+ xfree(*envp);
+ xfree(env);
+}
+
#endif /* USE_PAM */
diff --git a/security/openssh-portable/files/patch-auth-chall.c b/security/openssh-portable/files/patch-auth-chall.c
new file mode 100644
index 000000000000..067fd559451b
--- /dev/null
+++ b/security/openssh-portable/files/patch-auth-chall.c
@@ -0,0 +1,36 @@
+--- auth-chall.c Tue Jun 5 20:56:17 2001
++++ cvs-current/auth-chall.c Wed Sep 24 20:24:27 2003
+@@ -76,7 +77,33 @@
+ return 0;
+ resp[0] = (char *)response;
+ res = device->respond(authctxt->kbdintctxt, 1, resp);
++ if (res == 1) {
++ /* postponed - send a null query just in case */
++ char *name, *info, **prompts;
++ u_int i, numprompts, *echo_on;
++
++ res = device->query(authctxt->kbdintctxt, &name, &info,
++ &numprompts, &prompts, &echo_on);
++ if (res == 0) {
++ for (i = 0; i < numprompts; i++)
++ xfree(prompts[i]);
++ xfree(prompts);
++ xfree(name);
++ xfree(echo_on);
++ xfree(info);
++ }
++ /* if we received more prompts, we're screwed */
++ res = (res == 0 && numprompts == 0) ? 0 : -1;
++ }
+ device->free_ctx(authctxt->kbdintctxt);
+ authctxt->kbdintctxt = NULL;
+ return res ? 0 : 1;
++}
++void
++abandon_challenge_response(Authctxt *authctxt)
++{
++ if (authctxt->kbdintctxt != NULL) {
++ device->free_ctx(authctxt->kbdintctxt);
++ authctxt->kbdintctxt = NULL;
++ }
+ }
diff --git a/security/openssh-portable/files/patch-auth-pam.c b/security/openssh-portable/files/patch-auth-pam.c
new file mode 100644
index 000000000000..70f9e9053e15
--- /dev/null
+++ b/security/openssh-portable/files/patch-auth-pam.c
@@ -0,0 +1,91 @@
+--- auth-pam.c.orig Tue Apr 29 11:12:08 2003
++++ auth-pam.c Thu Sep 25 22:42:45 2003
+@@ -228,7 +228,7 @@
+ }
+
+ /* Do account management using PAM */
+-int do_pam_account(char *username, char *remote_user)
++int old_do_pam_account(const char *username, const char *remote_user)
+ {
+ int pam_retval;
+
+@@ -271,7 +271,7 @@
+ }
+
+ /* Do PAM-specific session initialisation */
+-void do_pam_session(char *username, const char *ttyname)
++void old_do_pam_session(const char *username, const char *ttyname)
+ {
+ int pam_retval;
+
+@@ -294,7 +294,7 @@
+ }
+
+ /* Set PAM credentials */
+-void do_pam_setcred(int init)
++void old_do_pam_setcred(int init)
+ {
+ int pam_retval;
+
+@@ -318,7 +318,7 @@
+ }
+
+ /* accessor function for file scope static variable */
+-int is_pam_password_change_required(void)
++int old_is_pam_password_change_required(void)
+ {
+ return password_change_required;
+ }
+@@ -329,7 +329,7 @@
+ * session is established and the user's pty is connected to
+ * stdin/stdout/stderr.
+ */
+-void do_pam_chauthtok(void)
++void old_do_pam_chauthtok(void)
+ {
+ int pam_retval;
+
+@@ -357,14 +357,14 @@
+ }
+
+ /* Cleanly shutdown PAM */
+-void finish_pam(void)
++void old_finish_pam(void)
+ {
+ do_pam_cleanup_proc(NULL);
+ fatal_remove_cleanup(&do_pam_cleanup_proc, NULL);
+ }
+
+ /* Start PAM authentication for specified account */
+-void start_pam(const char *user)
++void old_start_pam(const char *user)
+ {
+ int pam_retval;
+ extern ServerOptions options;
+@@ -404,7 +404,7 @@
+ }
+
+ /* Return list of PAM environment strings */
+-char **fetch_pam_environment(void)
++char **old_fetch_pam_environment(void)
+ {
+ #ifdef HAVE_PAM_GETENVLIST
+ return(pam_getenvlist(__pamh));
+@@ -413,7 +413,7 @@
+ #endif /* HAVE_PAM_GETENVLIST */
+ }
+
+-void free_pam_environment(char **env)
++void old_free_pam_environment(char **env)
+ {
+ int i;
+
+@@ -425,7 +425,7 @@
+
+ /* Print any messages that have been generated during authentication */
+ /* or account checking to stderr */
+-void print_pam_messages(void)
++void old_print_pam_messages(void)
+ {
+ if (__pam_msg != NULL)
+ fputs(__pam_msg, stderr);
diff --git a/security/openssh-portable/files/patch-auth-pam.h b/security/openssh-portable/files/patch-auth-pam.h
new file mode 100644
index 000000000000..efa2803ed0c1
--- /dev/null
+++ b/security/openssh-portable/files/patch-auth-pam.h
@@ -0,0 +1,13 @@
+--- auth-pam.h Tue Jul 23 02:44:07 2002
++++ cvs-current/auth-pam.h Sat Dec 14 14:52:39 2002
+@@ -37,8 +38,8 @@
+ char **fetch_pam_environment(void);
+ void free_pam_environment(char **env);
+ int do_pam_authenticate(int flags);
+-int do_pam_account(char *username, char *remote_user);
+-void do_pam_session(char *username, const char *ttyname);
++int do_pam_account(const char *username, const char *remote_user);
++void do_pam_session(const char *username, const char *ttyname);
+ void do_pam_setcred(int init);
+ void print_pam_messages(void);
+ int is_pam_password_change_required(void);