aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authordinoex <dinoex@FreeBSD.org>2003-09-26 11:17:29 +0800
committerdinoex <dinoex@FreeBSD.org>2003-09-26 11:17:29 +0800
commit40ec4b875109295f6c6d407884d265c41bd48e9f (patch)
tree7058ed963be9fb3ddeaa6b12eac6da7acda9797e /security
parent8ac1d5419b7e5565c98f9d3f9bf291195971204e (diff)
downloadfreebsd-ports-gnome-40ec4b875109295f6c6d407884d265c41bd48e9f.tar.gz
freebsd-ports-gnome-40ec4b875109295f6c6d407884d265c41bd48e9f.tar.zst
freebsd-ports-gnome-40ec4b875109295f6c6d407884d265c41bd48e9f.zip
- Security Fix in PAM handling
Obtained from: des
Diffstat (limited to 'security')
-rw-r--r--security/openssh/Makefile2
-rw-r--r--security/openssh/files/auth-pam.c790
-rw-r--r--security/openssh/files/auth-pam.h61
-rw-r--r--security/openssh/files/auth2-pam.c422
-rw-r--r--security/openssh/files/patch-auth-chall.c36
5 files changed, 409 insertions, 902 deletions
diff --git a/security/openssh/Makefile b/security/openssh/Makefile
index 6686b2d10311..ae7d3c5aa7d3 100644
--- a/security/openssh/Makefile
+++ b/security/openssh/Makefile
@@ -21,8 +21,6 @@ PATCHFILES= openbsd28_${PORTVERSION}.patch
MAINTAINER= dinoex@FreeBSD.org
COMMENT= OpenBSD's secure shell client and server (remote login program)
-FORBIDDEN= Security Problem with PAM
-
USE_OPENSSL= yes
WRKSRC= ${WRKDIR}/ssh
diff --git a/security/openssh/files/auth-pam.c b/security/openssh/files/auth-pam.c
index 66fb3870eb5d..fe9570f92a10 100644
--- a/security/openssh/files/auth-pam.c
+++ b/security/openssh/files/auth-pam.c
@@ -25,44 +25,41 @@
#include "includes.h"
#ifdef USE_PAM
-#include <security/pam_appl.h>
-#include "ssh.h"
#include "xmalloc.h"
#include "log.h"
-#include "servconf.h"
-#include "readpass.h"
-#include "canohost.h"
#include "auth.h"
+#include "auth-options.h"
#include "auth-pam.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "readpass.h"
-RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $");
+extern char *__progname;
-#define NEW_AUTHTOK_MSG \
- "Warning: Your password has expired, please change it now"
+extern int use_privsep;
-#define SSHD_PAM_SERVICE "sshd"
-#define PAM_STRERROR(a, b) pam_strerror((a), (b))
+RCSID("$Id: auth-pam.c,v 1.55 2003/01/22 04:42:26 djm Exp $");
+
+#define NEW_AUTHTOK_MSG \
+ "Warning: Your password has expired, please change it now."
+#define NEW_AUTHTOK_MSG_PRIVSEP \
+ "Your password has expired, the session cannot proceed."
-/* Callbacks */
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr);
-void do_pam_cleanup_proc(void *context);
-void pam_msg_cat(const char *msg);
+ struct pam_response **resp, void *appdata_ptr);
/* module-local variables */
static struct pam_conv conv = {
- do_pam_conversation,
+ (int (*)())do_pam_conversation,
NULL
};
-static pam_handle_t *pamh = NULL;
-static const char *pampasswd = NULL;
-static char *pam_msg = NULL;
-extern ServerOptions options;
+static char *__pam_msg = NULL;
+static pam_handle_t *__pamh = NULL;
+static const char *__pampasswd = NULL;
/* states for do_pam_conversation() */
-typedef enum { INITIAL_LOGIN, OTHER } pamstates;
-static pamstates pamstate = INITIAL_LOGIN;
-/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */
+enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
+/* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */
static int password_change_required = 0;
/* remember whether the last pam_authenticate() succeeded or not */
static int was_authenticated = 0;
@@ -71,13 +68,19 @@ static int was_authenticated = 0;
static int session_opened = 0;
static int creds_set = 0;
-/*
- * accessor which allows us to switch conversation structs according to
- * the authentication method being used
- */
+/* accessor which allows us to switch conversation structs according to
+ * the authentication method being used */
void do_pam_set_conv(struct pam_conv *conv)
{
- pam_set_item(pamh, 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;
}
/*
@@ -86,10 +89,10 @@ void do_pam_set_conv(struct pam_conv *conv)
*
* INITIAL_LOGIN mode simply feeds the password from the client into
* PAM in response to PAM_PROMPT_ECHO_OFF, and collects output
- * messages with pam_msg_cat(). This is used during initial
+ * messages with into __pam_msg. This is used during initial
* authentication to bypass the normal PAM password prompt.
*
- * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1)
+ * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase()
* and outputs messages to stderr. This mode is used if pam_chauthtok()
* is called to update expired passwords.
*/
@@ -101,52 +104,68 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg,
char buf[1024];
/* PAM will free this later */
- reply = malloc(num_msg * sizeof(*reply));
- if (reply == NULL)
- return PAM_CONV_ERR;
+ reply = xmalloc(num_msg * sizeof(*reply));
for (count = 0; count < num_msg; count++) {
- switch ((*msg)[count].msg_style) {
+ if (pamstate == INITIAL_LOGIN) {
+ /*
+ * We can't use stdio yet, queue messages for
+ * printing later
+ */
+ switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
case PAM_PROMPT_ECHO_ON:
- if (pamstate == INITIAL_LOGIN) {
- free(reply);
- return PAM_CONV_ERR;
- } else {
- fputs((*msg)[count].msg, stderr);
- fgets(buf, sizeof(buf), stdin);
- reply[count].resp = xstrdup(buf);
- reply[count].resp_retcode = PAM_SUCCESS;
- break;
- }
+ xfree(reply);
+ return PAM_CONV_ERR;
case PAM_PROMPT_ECHO_OFF:
- if (pamstate == INITIAL_LOGIN) {
- if (pampasswd == NULL) {
- free(reply);
- return PAM_CONV_ERR;
- }
- reply[count].resp = xstrdup(pampasswd);
- } else {
- reply[count].resp =
- xstrdup(read_passphrase((*msg)[count].msg, 1));
+ if (__pampasswd == NULL) {
+ xfree(reply);
+ return PAM_CONV_ERR;
}
+ reply[count].resp = xstrdup(__pampasswd);
reply[count].resp_retcode = PAM_SUCCESS;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
- if ((*msg)[count].msg != NULL) {
- if (pamstate == INITIAL_LOGIN)
- pam_msg_cat((*msg)[count].msg);
- else {
- fputs((*msg)[count].msg, stderr);
- fputs("\n", stderr);
- }
+ if (PAM_MSG_MEMBER(msg, count, msg) != NULL) {
+ message_cat(&__pam_msg,
+ PAM_MSG_MEMBER(msg, count, msg));
}
reply[count].resp = xstrdup("");
reply[count].resp_retcode = PAM_SUCCESS;
break;
default:
- free(reply);
+ xfree(reply);
+ return PAM_CONV_ERR;
+ }
+ } else {
+ /*
+ * stdio is connected, so interact directly
+ */
+ switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
+ case PAM_PROMPT_ECHO_ON:
+ fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
+ fgets(buf, sizeof(buf), stdin);
+ reply[count].resp = xstrdup(buf);
+ reply[count].resp_retcode = PAM_SUCCESS;
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[count].resp =
+ read_passphrase(PAM_MSG_MEMBER(msg, count,
+ msg), RP_ALLOW_STDIN);
+ reply[count].resp_retcode = PAM_SUCCESS;
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ if (PAM_MSG_MEMBER(msg, count, msg) != NULL)
+ fprintf(stderr, "%s\n",
+ PAM_MSG_MEMBER(msg, count, msg));
+ reply[count].resp = xstrdup("");
+ reply[count].resp_retcode = PAM_SUCCESS;
+ break;
+ default:
+ xfree(reply);
return PAM_CONV_ERR;
+ }
}
}
@@ -158,61 +177,52 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg,
/* Called at exit to cleanly shutdown PAM */
void do_pam_cleanup_proc(void *context)
{
- int pam_retval;
+ int pam_retval = PAM_SUCCESS;
- if (pamh != NULL && session_opened) {
- pam_retval = pam_close_session(pamh, 0);
- if (pam_retval != PAM_SUCCESS) {
- log("Cannot close PAM session[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ if (__pamh && session_opened) {
+ pam_retval = pam_close_session(__pamh, 0);
+ if (pam_retval != PAM_SUCCESS)
+ log("Cannot close PAM session[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
}
- if (pamh != NULL && creds_set) {
- pam_retval = pam_setcred(pamh, PAM_DELETE_CRED);
- if (pam_retval != PAM_SUCCESS) {
+ if (__pamh && creds_set) {
+ pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED);
+ if (pam_retval != PAM_SUCCESS)
debug("Cannot delete credentials[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
}
- if (pamh != NULL) {
- pam_retval = pam_end(pamh, pam_retval);
- if (pam_retval != PAM_SUCCESS) {
- log("Cannot release PAM authentication[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ if (__pamh) {
+ pam_retval = pam_end(__pamh, pam_retval);
+ if (pam_retval != PAM_SUCCESS)
+ log("Cannot release PAM authentication[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
}
}
/* Attempt password authentation using PAM */
int auth_pam_password(Authctxt *authctxt, const char *password)
{
- struct passwd *pw = authctxt->pw;
+ extern ServerOptions options;
int pam_retval;
+ struct passwd *pw = authctxt->pw;
do_pam_set_conv(&conv);
- /* deny if no user. */
- if (pw == NULL)
- return 0;
- if (pw->pw_uid == 0 && options.permit_root_login == 2)
- return 0;
- if (*password == '\0' && options.permit_empty_passwd == 0)
- return 0;
+ __pampasswd = password;
- pampasswd = password;
-
pamstate = INITIAL_LOGIN;
- pam_retval = pam_authenticate(pamh, 0);
- was_authenticated = (pam_retval == PAM_SUCCESS);
+ pam_retval = do_pam_authenticate(
+ options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0);
if (pam_retval == PAM_SUCCESS) {
- debug("PAM Password authentication accepted for user \"%.100s\"",
- pw->pw_name);
+ debug("PAM Password authentication accepted for "
+ "user \"%.100s\"", pw->pw_name);
return 1;
} else {
- debug("PAM Password authentication for \"%.100s\" failed[%d]: %s",
- pw->pw_name, pam_retval, PAM_STRERROR(pamh, pam_retval));
+ debug("PAM Password authentication for \"%.100s\" "
+ "failed[%d]: %s", pw->pw_name, pam_retval,
+ PAM_STRERROR(__pamh, pam_retval));
return 0;
}
}
@@ -223,41 +233,40 @@ int do_pam_account(char *username, char *remote_user)
int pam_retval;
do_pam_set_conv(&conv);
-
- debug("PAM setting rhost to \"%.200s\"",
- get_canonical_hostname(options.verify_reverse_mapping));
- pam_retval = pam_set_item(pamh, PAM_RHOST,
- get_canonical_hostname(options.verify_reverse_mapping));
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM set rhost failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
- if (remote_user != NULL) {
+ if (remote_user) {
debug("PAM setting ruser to \"%.200s\"", remote_user);
- pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user);
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM set ruser failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ pam_retval = pam_set_item(__pamh, PAM_RUSER, remote_user);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM set ruser failed[%d]: %.200s", pam_retval,
+ PAM_STRERROR(__pamh, pam_retval));
}
- pam_retval = pam_acct_mgmt(pamh, 0);
+ pam_retval = pam_acct_mgmt(__pamh, 0);
+ debug2("pam_acct_mgmt() = %d", pam_retval);
switch (pam_retval) {
case PAM_SUCCESS:
/* This is what we want */
break;
+#if 0
case PAM_NEW_AUTHTOK_REQD:
- pam_msg_cat(NEW_AUTHTOK_MSG);
+ message_cat(&__pam_msg, use_privsep ?
+ NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
/* flag that password change is necessary */
password_change_required = 1;
+ /* disallow other functionality for now */
+ no_port_forwarding_flag |= 2;
+ no_agent_forwarding_flag |= 2;
+ no_x11_forwarding_flag |= 2;
break;
+#endif
default:
- log("PAM rejected by account configuration[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
+ log("PAM rejected by account configuration[%d]: "
+ "%.200s", pam_retval, PAM_STRERROR(__pamh,
+ pam_retval));
return(0);
}
-
+
return(1);
}
@@ -270,54 +279,55 @@ void do_pam_session(char *username, const char *ttyname)
if (ttyname != NULL) {
debug("PAM setting tty to \"%.200s\"", ttyname);
- pam_retval = pam_set_item(pamh, PAM_TTY, ttyname);
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM set tty failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ pam_retval = pam_set_item(__pamh, PAM_TTY, ttyname);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM set tty failed[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
}
- debug("do_pam_session: euid %u, uid %u", geteuid(), getuid());
- pam_retval = pam_open_session(pamh, 0);
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM session setup failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ pam_retval = pam_open_session(__pamh, 0);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM session setup failed[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
session_opened = 1;
}
-/* Set PAM credentials */
-void do_pam_setcred(void)
+/* Set PAM credentials */
+void do_pam_setcred(int init)
{
int pam_retval;
+ if (__pamh == NULL)
+ return;
+
do_pam_set_conv(&conv);
-
+
debug("PAM establishing creds");
- pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ pam_retval = pam_setcred(__pamh,
+ init ? PAM_ESTABLISH_CRED : PAM_REINITIALIZE_CRED);
if (pam_retval != PAM_SUCCESS) {
if (was_authenticated)
fatal("PAM setcred failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
else
debug("PAM setcred failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
} else
creds_set = 1;
}
/* accessor function for file scope static variable */
-int pam_password_change_required(void)
+int is_pam_password_change_required(void)
{
return password_change_required;
}
-/*
+/*
* Have user change authentication token if pam_acct_mgmt() indicated
* it was expired. This needs to be called after an interactive
* session is established and the user's pty is connected to
- * stdin/stout/stderr.
+ * stdin/stdout/stderr.
*/
void do_pam_chauthtok(void)
{
@@ -326,17 +336,23 @@ void do_pam_chauthtok(void)
do_pam_set_conv(&conv);
if (password_change_required) {
+ if (use_privsep)
+ fatal("Password changing is currently unsupported"
+ " with privilege separation");
pamstate = OTHER;
- /*
- * XXX: should we really loop forever?
- */
- do {
- pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
- if (pam_retval != PAM_SUCCESS) {
- log("PAM pam_chauthtok failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
- } while (pam_retval != PAM_SUCCESS);
+ pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM pam_chauthtok failed[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
+#if 0
+ /* XXX: This would need to be done in the parent process,
+ * but there's currently no way to pass such request. */
+ no_port_forwarding_flag &= ~2;
+ no_agent_forwarding_flag &= ~2;
+ no_x11_forwarding_flag &= ~2;
+ if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+ channel_permit_all_opens();
+#endif
}
}
@@ -348,478 +364,92 @@ void finish_pam(void)
}
/* Start PAM authentication for specified account */
-void start_pam(struct passwd *pw)
+void start_pam(const char *user)
{
int pam_retval;
+ extern ServerOptions options;
+ extern u_int utmp_len;
+ const char *rhost;
- debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
+ debug("Starting up PAM with username \"%.200s\"", user);
- pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv, &pamh);
+ pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &__pamh);
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM initialisation failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM initialisation failed[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
+ rhost = get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping);
+ debug("PAM setting rhost to \"%.200s\"", rhost);
+
+ pam_retval = pam_set_item(__pamh, PAM_RHOST, rhost);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM set rhost failed[%d]: %.200s", pam_retval,
+ PAM_STRERROR(__pamh, pam_retval));
#ifdef PAM_TTY_KLUDGE
/*
* Some PAM modules (e.g. pam_time) require a TTY to operate,
- * and will fail in various stupid ways if they don't get one.
+ * and will fail in various stupid ways if they don't get one.
* sshd doesn't set the tty until too late in the auth process and may
* not even need one (for tty-less connections)
- * Kludge: Set a fake PAM_TTY
+ * Kludge: Set a fake PAM_TTY
*/
- pam_retval = pam_set_item(pamh, PAM_TTY, "ssh");
- if (pam_retval != PAM_SUCCESS) {
- fatal("PAM set tty failed[%d]: %.200s",
- pam_retval, PAM_STRERROR(pamh, pam_retval));
- }
+ pam_retval = pam_set_item(__pamh, PAM_TTY, "NODEVssh");
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM set tty failed[%d]: %.200s",
+ pam_retval, PAM_STRERROR(__pamh, pam_retval));
#endif /* PAM_TTY_KLUDGE */
fatal_add_cleanup(&do_pam_cleanup_proc, NULL);
}
-/* Return list of PAM enviornment strings */
+/* Return list of PAM environment strings */
char **fetch_pam_environment(void)
{
#ifdef HAVE_PAM_GETENVLIST
- return(pam_getenvlist(pamh));
+ return(pam_getenvlist(__pamh));
#else /* HAVE_PAM_GETENVLIST */
return(NULL);
#endif /* HAVE_PAM_GETENVLIST */
}
-/* Print any messages that have been generated during authentication */
-/* or account checking to stderr */
-void print_pam_messages(void)
-{
- if (pam_msg != NULL)
- fputs(pam_msg, stderr);
-}
-
-/* Append a message to the PAM message buffer */
-void pam_msg_cat(const char *msg)
+void free_pam_environment(char **env)
{
- char *p;
- size_t new_msg_len;
- size_t pam_msg_len;
-
- new_msg_len = strlen(msg);
-
- if (pam_msg) {
- pam_msg_len = strlen(pam_msg);
- pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2);
- p = pam_msg + pam_msg_len;
- } else {
- pam_msg = p = xmalloc(new_msg_len + 2);
- }
-
- memcpy(p, msg, new_msg_len);
- p[new_msg_len] = '\n';
- p[new_msg_len + 1] = '\0';
-}
-
-struct inverted_pam_userdata {
- /*
- * Pipe for telling whether we are doing conversation or sending
- * authentication results.
- */
- int statefd[2];
- int challengefd[2];
- int responsefd[2];
-
- /* Whether we have sent off our challenge */
- int state;
-};
-
-#define STATE_CONV 1
-#define STATE_AUTH_OK 2
-#define STATE_AUTH_FAIL 3
-
-int
-ssh_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp,
- void *userdata) {
int i;
- FILE *reader;
- char buf[1024];
- struct pam_response *reply = NULL;
- char state_to_write = STATE_CONV; /* One char to write */
- struct inverted_pam_userdata *ud = userdata;
- char *response = NULL;
-
- /* The stdio functions are more convenient for the read half */
- reader = fdopen(ud->responsefd[0], "rb");
- if (reader == NULL)
- goto protocol_failure;
-
- reply = malloc(num_msg * sizeof(struct pam_response));
- if (reply == NULL)
- return PAM_CONV_ERR;
-
- if (write(ud->statefd[1], &state_to_write, 1) != 1)
- goto protocol_failure;
-
- /*
- * Re-package our data and send it off to our better half (the actual SSH
- * process)
- */
- if (write(ud->challengefd[1], buf,
- sprintf(buf, "%d\n", num_msg)) == -1)
- goto protocol_failure;
- for (i = 0; i < num_msg; i++) {
- if (write(ud->challengefd[1], buf,
- sprintf(buf, "%d\n", msg[i]->msg_style)) == -1)
- goto protocol_failure;
- if (write(ud->challengefd[1], buf,
- sprintf(buf, "%d\n", strlen(msg[i]->msg))) == -1)
- goto protocol_failure;
- if (write(ud->challengefd[1], msg[i]->msg,
- strlen(msg[i]->msg)) == -1)
- goto protocol_failure;
- }
- /*
- * Read back responses. These may not be as nice as we want, as the SSH
- * protocol isn't exactly a perfect fit with PAM.
- */
- for (i = 0; i < num_msg; i++) {
- char buf[1024];
- char *endptr;
- size_t len; /* Length of the response */
-
- switch (msg[i]->msg_style) {
- case PAM_PROMPT_ECHO_OFF:
- case PAM_PROMPT_ECHO_ON:
- if (fgets(buf, sizeof(buf), reader) == NULL)
- goto protocol_failure;
- len = (size_t)strtoul(buf, &endptr, 10);
- /* The length is supposed to stand on a line by itself */
- if (endptr == NULL || *endptr != '\n')
- goto protocol_failure;
- response = malloc(len+1);
- if (response == NULL)
- goto protocol_failure;
- if (fread(response, len, 1, reader) != 1)
- goto protocol_failure;
- response[len] = '\0';
- reply[i].resp = response;
- response = NULL;
- break;
- default:
- reply[i].resp = NULL;
- break;
- }
+ if (env != NULL) {
+ for (i = 0; env[i] != NULL; i++)
+ xfree(env[i]);
}
- *resp = reply;
- return PAM_SUCCESS;
- protocol_failure:
- free(reply);
- return PAM_CONV_ERR;
}
-void
-ipam_free_cookie(struct inverted_pam_cookie *cookie) {
- struct inverted_pam_userdata *ud;
- int i;
-
- if (cookie == NULL)
- return;
- ud = cookie->userdata;
- cookie->userdata = NULL;
- /* Free userdata if allocated */
- if (ud) {
- /* Close any opened file descriptors */
- if (ud->statefd[0] != -1)
- close(ud->statefd[0]);
- if (ud->statefd[1] != -1)
- close(ud->statefd[1]);
- if (ud->challengefd[0] != -1)
- close(ud->challengefd[0]);
- if (ud->challengefd[1] != -1)
- close(ud->challengefd[1]);
- if (ud->responsefd[0] != -1)
- close(ud->responsefd[0]);
- if (ud->responsefd[1] != -1)
- close(ud->responsefd[1]);
- free(ud);
- ud = NULL;
- }
- /* Now free the normal cookie */
- if (cookie->pid != 0 && cookie->pid != -1) {
- int status;
-
- /* XXX Use different signal? */
- kill(cookie->pid, SIGKILL);
- waitpid(cookie->pid, &status, 0);
- }
- for (i = 0; i < cookie->num_msg; i++) {
- if (cookie->resp && cookie->resp[i]) {
- free(cookie->resp[i]->resp);
- free(cookie->resp[i]);
- }
- if (cookie->msg && cookie->msg[i]) {
- free((void *)cookie->msg[i]->msg);
- free(cookie->msg[i]);
- }
- }
- free(cookie->msg);
- free(cookie->resp);
- free(cookie);
+/* Print any messages that have been generated during authentication */
+/* or account checking to stderr */
+void print_pam_messages(void)
+{
+ if (__pam_msg != NULL)
+ fputs(__pam_msg, stderr);
}
-/*
- * Do first half of PAM authentication - this comes to the point where
- * you get a message to send to the user.
- */
-struct inverted_pam_cookie *
-ipam_start_auth(const char *service, const char *username) {
- struct inverted_pam_cookie *cookie;
- struct inverted_pam_userdata *ud;
- static struct pam_conv conv = {
- ssh_conv,
- NULL
- };
- const char *rhost;
+/* Append a message to buffer */
+void message_cat(char **p, const char *a)
+{
+ char *cp;
+ size_t new_len;
- cookie = malloc(sizeof(*cookie));
- if (cookie == NULL)
- return NULL;
- cookie->state = 0;
- /* Set up the cookie so ipam_freecookie can be used on it */
- cookie->num_msg = 0;
- cookie->msg = NULL;
- cookie->resp = NULL;
- cookie->pid = -1;
-
- ud = calloc(sizeof(*ud), 1);
- if (ud == NULL) {
- free(cookie);
- return NULL;
- }
- cookie->userdata = ud;
- ud->statefd[0] = ud->statefd[1] = -1;
- ud->challengefd[0] = ud->challengefd[1] = -1;
- ud->responsefd[0] = ud->responsefd[1] = -1;
-
- if (pipe(ud->statefd) != 0) {
- ud->statefd[0] = ud->statefd[1] = -1;
- ipam_free_cookie(cookie);
- return NULL;
- }
- if (pipe(ud->challengefd) != 0) {
- ud->challengefd[0] = ud->challengefd[1] = -1;
- ipam_free_cookie(cookie);
- return NULL;
- }
- if (pipe(ud->responsefd) != 0) {
- ud->responsefd[0] = ud->responsefd[1] = -1;
- ipam_free_cookie(cookie);
- return NULL;
- }
- rhost = get_canonical_hostname(options.verify_reverse_mapping);
- cookie->pid = fork();
- if (cookie->pid == -1) {
- ipam_free_cookie(cookie);
- return NULL;
- } else if (cookie->pid != 0) {
- int num_msgs; /* Number of messages from PAM */
- char *endptr;
- char buf[1024];
- FILE *reader;
- size_t num_msg;
- int i;
- char state; /* Which state did the connection just enter? */
-
- /* We are the parent - wait for a call to the communications
- function to turn up, or the challenge to be finished */
- if (read(ud->statefd[0], &state, 1) != 1) {
- ipam_free_cookie(cookie);
- return NULL;
- }
- cookie->state = state;
- switch (state) {
- case STATE_CONV:
- /* We are running the conversation function */
- /* The stdio functions are more convenient for read */
- reader = fdopen(ud->challengefd[0], "r");
- if (reader == NULL) {
- ipam_free_cookie(cookie);
- return NULL;
- }
- if (fgets(buf, 4, reader) == NULL) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- num_msg = (size_t)strtoul(buf, &endptr, 10);
- /* The length is supposed to stand on a line by itself */
- if (endptr == NULL || *endptr != '\n') {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- cookie->msg =
- malloc(sizeof(struct pam_message *) * num_msg);
- cookie->resp =
- malloc(sizeof(struct pam_response *) * num_msg);
- if (cookie->msg == NULL || cookie->resp == NULL) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- for (i = 0; i < num_msg; i++) {
- cookie->msg[i] =
- malloc(sizeof(struct pam_message));
- cookie->resp[i] =
- malloc(sizeof(struct pam_response));
- if (cookie->msg[i] == NULL ||
- cookie->resp[i] == NULL) {
- for (;;) {
- free(cookie->msg[i]);
- free(cookie->resp[i]);
- if (i == 0)
- break;
- i--;
- }
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- cookie->msg[i]->msg = NULL;
- cookie->resp[i]->resp = NULL;
- cookie->resp[i]->resp_retcode = 0;
- }
- /* Set up so the above will be freed on failure */
- cookie->num_msg = num_msg;
- /*
- * We have a an allocated response and message for
- * each of the entries in the PAM structure - transfer
- * the data sent to the conversation function over.
- */
- for (i = 0; i < num_msg; i++) {
- size_t len;
-
- if (fgets(buf, sizeof(buf), reader) == NULL) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- cookie->msg[i]->msg_style =
- (size_t)strtoul(buf, &endptr, 10);
- if (endptr == NULL || *endptr != '\n') {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- if (fgets(buf, sizeof(buf), reader) == NULL) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- len = (size_t)strtoul(buf, &endptr, 10);
- if (endptr == NULL || *endptr != '\n') {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- cookie->msg[i]->msg = malloc(len + 1);
- if (cookie->msg[i]->msg == NULL) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- if (fread((char *)cookie->msg[i]->msg, len, 1, reader) !=
- 1) {
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- *(char *)&(cookie->msg[i]->msg[len]) = '\0';
- }
- break;
- case STATE_AUTH_OK:
- case STATE_AUTH_FAIL:
- break;
- default:
- /* Internal failure, somehow */
- fclose(reader);
- ipam_free_cookie(cookie);
- return NULL;
- }
- return cookie;
- } else {
- /* We are the child */
- pam_handle_t *pamh=NULL;
- int retval;
- char state;
-
- conv.appdata_ptr = ud;
- retval = pam_start(service, username, &conv, &pamh);
- fprintf(stderr, "pam_start returned %d\n", retval);
- if (retval == PAM_SUCCESS)
- retval = pam_set_item(pamh, PAM_RHOST, rhost);
- /* Is user really user? */
- if (retval == PAM_SUCCESS)
- retval = pam_authenticate(pamh, 0);
- /* permitted access? */
- if (retval == PAM_SUCCESS)
- retval = pam_acct_mgmt(pamh, 0);
- /* This is where we have been authorized or not. */
-
- /* Be conservative - flag as auth failure if we can't close */
- /*
- * XXX This is based on example code from Linux-PAM -
- * but can it really be correct to pam_end if
- * pam_start failed?
- */
- if (pam_end(pamh, retval) != PAM_SUCCESS)
- retval = PAM_AUTH_ERR;
-
- /* Message to parent */
- state = retval == PAM_SUCCESS ? STATE_AUTH_OK : STATE_AUTH_FAIL;
- if (write(ud->statefd[1], &state, 1) != 1) {
- _exit(1);
- }
- /* FDs will be closed, so further communication will stop */
- _exit(0);
- }
-}
+ new_len = strlen(a);
-/*
- * Do second half of PAM authentication - cookie should now be filled
- * in with the response to the challenge.
- */
+ if (*p) {
+ size_t len = strlen(*p);
-int
-ipam_complete_auth(struct inverted_pam_cookie *cookie) {
- int i;
- char buf[1024];
- struct inverted_pam_userdata *ud = cookie->userdata;
- char state;
-
- /* Send over our responses */
- for (i = 0; i < cookie->num_msg; i++) {
- if (cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_ON &&
- cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
- continue;
- if (write(ud->responsefd[1], buf,
- sprintf(buf, "%d\n", strlen(cookie->resp[i]->resp))) == -1) {
- ipam_free_cookie(cookie);
- return 0;
- }
- if (write(ud->responsefd[1], cookie->resp[i]->resp,
- strlen(cookie->resp[i]->resp)) == -1) {
- ipam_free_cookie(cookie);
- return 0;
- }
- }
- /* Find out what state we are changing to */
- if (read(ud->statefd[0], &state, 1) != 1) {
- ipam_free_cookie(cookie);
- return 0;
- }
-
- return state == STATE_AUTH_OK ? 1 : 0;
+ *p = xrealloc(*p, new_len + len + 2);
+ cp = *p + len;
+ } else
+ *p = cp = xmalloc(new_len + 2);
+
+ memcpy(cp, a, new_len);
+ cp[new_len] = '\n';
+ cp[new_len + 1] = '\0';
}
#endif /* USE_PAM */
diff --git a/security/openssh/files/auth-pam.h b/security/openssh/files/auth-pam.h
index 887ccfcafef6..45628a3de7f3 100644
--- a/security/openssh/files/auth-pam.h
+++ b/security/openssh/files/auth-pam.h
@@ -1,39 +1,50 @@
+/* $Id: auth-pam.h,v 1.16 2002/07/23 00:44:07 stevesk Exp $ */
+/* $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth-pam.h,v 1.2 2003-09-26 03:17:29 dinoex Exp $ */
+
/*
- * OpenSSH PAM authentication support.
+ * Copyright (c) 2000 Damien Miller. All rights reserved.
+ *
+ * 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.
*
- * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth-pam.h,v 1.1 2002-06-24 22:57:13 dinoex Exp $
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*/
-#ifndef AUTH_PAM_H
-#define AUTH_PAM_H
+
#include "includes.h"
#ifdef USE_PAM
-#include "auth.h"
-#include <pwd.h> /* For struct passwd */
+#if !defined(SSHD_PAM_SERVICE)
+# define SSHD_PAM_SERVICE __progname
+#endif
-void start_pam(struct passwd *pw);
+void start_pam(const char *user);
void finish_pam(void);
int auth_pam_password(Authctxt *authctxt, const char *password);
char **fetch_pam_environment(void);
-int do_pam_account(char *username, char *remote_user);
-void do_pam_session(char *username, const char *ttyname);
-void do_pam_setcred(void);
+void free_pam_environment(char **env);
+int do_pam_authenticate(int flags);
+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 pam_password_change_required(void);
+int is_pam_password_change_required(void);
void do_pam_chauthtok(void);
-
-struct inverted_pam_cookie {
- int state; /* Which state have we reached? */
- pid_t pid; /* PID of child process */
-
- /* Only valid in state STATE_CONV */
- int num_msg; /* Number of messages */
- struct pam_message **msg; /* Message structures */
- struct pam_response **resp; /* Response structures */
- struct inverted_pam_userdata *userdata;
-};
-void ipam_free_cookie(struct inverted_pam_cookie *cookie);
-struct inverted_pam_cookie *ipam_start_auth(const char *, const char *);
+void do_pam_set_conv(struct pam_conv *);
+void message_cat(char **p, const char *a);
#endif /* USE_PAM */
-#endif /* AUTH_PAM_H */
diff --git a/security/openssh/files/auth2-pam.c b/security/openssh/files/auth2-pam.c
index 38c53ef93aa3..ac28fb2451c9 100644
--- a/security/openssh/files/auth2-pam.c
+++ b/security/openssh/files/auth2-pam.c
@@ -1,333 +1,165 @@
-/*-
- * 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: /tmp/pcvs/ports/security/openssh/files/Attic/auth2-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $
- */
-
-#ifdef USE_PAM
#include "includes.h"
-RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth2-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $");
+RCSID("$Id: auth2-pam.c,v 1.15 2003/01/08 01:37:03 djm Exp $");
+#ifdef USE_PAM
#include <security/pam_appl.h>
+#include "ssh.h"
+#include "ssh2.h"
#include "auth.h"
-#include "log.h"
+#include "auth-pam.h"
+#include "packet.h"
#include "xmalloc.h"
+#include "dispatch.h"
+#include "log.h"
-struct pam_ctxt {
- char *pam_user;
- pid_t pam_pid;
- int pam_sock;
- int pam_done;
-};
+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);
-static void pam_free_ctx(void *);
+struct {
+ int finished, num_received, num_expected;
+ int *prompts;
+ struct pam_response *responses;
+} context_pam2 = {0, 0, 0, NULL};
-/*
- * Send message to parent or child.
- */
-static int
-pam_send(struct pam_ctxt *ctxt, char *fmt, ...)
-{
- va_list ap;
- char *mstr;
- size_t len;
- int r;
-
- va_start(ap, fmt);
- len = vasprintf(&mstr, fmt, ap);
- va_end(ap);
- if (mstr == NULL)
- exit(1);
- if (ctxt->pam_pid != 0)
- debug2("to child: %s", mstr);
- r = send(ctxt->pam_sock, mstr, len + 1, MSG_EOR);
- free(mstr);
- return (r);
-}
+static struct pam_conv conv2 = {
+ do_pam_conversation_kbd_int,
+ NULL,
+};
-/*
- * Peek at first byte of next message.
- */
-static int
-pam_peek(struct pam_ctxt *ctxt)
+int
+auth2_pam(Authctxt *authctxt)
{
- char ch;
+ int retval = -1;
- if (recv(ctxt->pam_sock, &ch, 1, MSG_PEEK) < 1)
- return (-1);
- return (ch);
-}
+ if (authctxt->user == NULL)
+ fatal("auth2_pam: internal error: no user");
-/*
- * Receive a message from parent or child.
- */
-static char *
-pam_receive(struct pam_ctxt *ctxt)
-{
- char *buf;
- size_t len;
- ssize_t rlen;
+ conv2.appdata_ptr = authctxt;
+ do_pam_set_conv(&conv2);
- len = 64;
- buf = NULL;
- do {
- len *= 2;
- buf = xrealloc(buf, len);
- rlen = recv(ctxt->pam_sock, buf, len, MSG_PEEK);
- if (rlen < 1) {
- xfree(buf);
- return (NULL);
- }
- } while (rlen == len);
- if (recv(ctxt->pam_sock, buf, len, 0) != rlen) {
- xfree(buf);
- return (NULL);
- }
- if (ctxt->pam_pid != 0)
- debug2("from child: %s", buf);
- return (buf);
+ 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);
+
+ return retval;
}
-/*
- * Conversation function for child process.
- */
static int
-pam_child_conv(int n,
- const struct pam_message **msg,
- struct pam_response **resp,
- void *data)
+do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
{
- struct pam_ctxt *ctxt;
- int i;
-
- ctxt = data;
- if (n <= 0 || n > PAM_MAX_NUM_MSG)
- return (PAM_CONV_ERR);
- if ((*resp = calloc(n, sizeof **resp)) == 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:
- pam_send(ctxt, "p%s", msg[i]->msg);
- resp[i]->resp = pam_receive(ctxt);
- break;
+ int i, j, done;
+ char *text;
+
+ 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:
- pam_send(ctxt, "P%s", msg[i]->msg);
- resp[i]->resp = pam_receive(ctxt);
- break;
- case PAM_ERROR_MSG:
- /*pam_send(ctxt, "e%s", msg[i]->msg);*/
+ case PAM_PROMPT_ECHO_OFF:
+ context_pam2.num_expected++;
break;
case PAM_TEXT_INFO:
- /*pam_send(ctxt, "i%s", msg[i]->msg);*/
- break;
+ case PAM_ERROR_MSG:
default:
- goto fail;
+ /* Capture all these messages to be sent at once */
+ message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
+ break;
}
}
- return (PAM_SUCCESS);
- fail:
- while (i)
- free(resp[--i]);
- free(*resp);
- *resp = NULL;
- return (PAM_CONV_ERR);
-}
-/*
- * Child process.
- */
-static void *
-pam_child(struct pam_ctxt *ctxt)
-{
- struct pam_conv pam_conv = { pam_child_conv, ctxt };
- pam_handle_t *pamh;
- int pam_err;
+ 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);
+ }
+ 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");
+ }
- pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh);
- if (pam_err != PAM_SUCCESS)
- goto auth_fail;
- pam_err = pam_authenticate(pamh, 0);
- if (pam_err != PAM_SUCCESS)
- goto auth_fail;
- pam_send(ctxt, "=OK");
- pam_end(pamh, pam_err);
- exit(0);
- auth_fail:
- pam_send(ctxt, "!%s", pam_strerror(pamh, pam_err));
- pam_end(pamh, pam_err);
- exit(0);
+ if (context_pam2.num_received == context_pam2.num_expected) {
+ *resp = context_pam2.responses;
+ return PAM_SUCCESS;
+ } else
+ return PAM_CONV_ERR;
}
-static void *
-pam_init_ctx(Authctxt *authctxt)
+void
+input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt)
{
- struct pam_ctxt *ctxt;
- int socks[2];
- int i;
+ Authctxt *authctxt = ctxt;
+ unsigned int nresp = 0, rlen = 0, i = 0;
+ char *resp;
- ctxt = xmalloc(sizeof *ctxt);
- ctxt->pam_user = xstrdup(authctxt->user);
- ctxt->pam_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->pam_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->pam_pid == 0) {
- /* close everything except our end of the pipe */
- ctxt->pam_sock = socks[1];
- for (i = 0; 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]);
- return (ctxt);
-}
+ if (authctxt == NULL)
+ fatal("input_userauth_info_response_pam: no authentication context");
-static int
-pam_query(void *ctx, char **name, char **info,
- u_int *num, char ***prompts, u_int **echo_on)
-{
- struct pam_ctxt *ctxt = ctx;
- char *msg;
+ nresp = packet_get_int(); /* Number of responses. */
+ debug("got %d responses", nresp);
- if ((msg = pam_receive(ctxt)) == NULL)
- return (-1);
- *name = xstrdup("");
- *info = xstrdup("");
- *prompts = xmalloc(sizeof(char *));
- *echo_on = xmalloc(sizeof(u_int));
- switch (*msg) {
- case 'P':
- **echo_on = 1;
- case 'p':
- *num = 1;
- **prompts = xstrdup(msg + 1);
- **echo_on = (*msg == 'P');
- break;
- case '=':
- *num = 0;
- **echo_on = 0;
- ctxt->pam_done = 1;
- break;
- case '!':
- error("%s", msg + 1);
- default:
- *num = 0;
- **echo_on = 0;
- xfree(msg);
- ctxt->pam_done = -1;
- return (-1);
- }
- xfree(msg);
- return (0);
-}
-static int
-pam_respond(void *ctx, u_int num, char **resp)
-{
- struct pam_ctxt *ctxt = ctx;
- char *msg;
+ if (nresp != context_pam2.num_expected)
+ fatal("%s: Received incorrect number of responses "
+ "(expected %d, received %u)", __func__,
+ context_pam2.num_expected, nresp);
- debug2(__func__);
- switch (ctxt->pam_done) {
- case 1:
- return (0);
- case 0:
- break;
- default:
- return (-1);
- }
- if (num != 1) {
- error("expected one response, got %u", num);
- return (-1);
- }
- pam_send(ctxt, "%s", *resp);
- switch (pam_peek(ctxt)) {
- case 'P':
- case 'p':
- return (1);
- case '=':
- msg = pam_receive(ctxt);
- xfree(msg);
- ctxt->pam_done = 1;
- return (0);
- default:
- msg = pam_receive(ctxt);
- if (*msg == '!')
- error("%s", msg + 1);
- xfree(msg);
- ctxt->pam_done = -1;
- return (-1);
- }
-}
+ if (nresp > 100)
+ fatal("%s: too many replies", __func__);
-static void
-pam_free_ctx(void *ctxtp)
-{
- struct pam_ctxt *ctxt = ctxtp;
- int status;
+ for (i = 0; i < nresp; i++) {
+ int j = context_pam2.prompts[i];
- close(ctxt->pam_sock);
- kill(ctxt->pam_pid, SIGHUP);
- waitpid(ctxt->pam_pid, &status, 0);
- xfree(ctxt->pam_user);
- xfree(ctxt);
-}
+ resp = packet_get_string(&rlen);
+ context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
+ context_pam2.responses[j].resp = resp;
+ context_pam2.num_received++;
+ }
-KbdintDevice pam_device = {
- "pam",
- pam_init_ctx,
- pam_query,
- pam_respond,
- pam_free_ctx
-};
+ context_pam2.finished = 1;
-#endif /* USE_PAM */
+ packet_check_eom();
+}
+#endif
diff --git a/security/openssh/files/patch-auth-chall.c b/security/openssh/files/patch-auth-chall.c
new file mode 100644
index 000000000000..067fd559451b
--- /dev/null
+++ b/security/openssh/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;
++ }
+ }