diff options
author | dinoex <dinoex@FreeBSD.org> | 2003-09-26 11:17:29 +0800 |
---|---|---|
committer | dinoex <dinoex@FreeBSD.org> | 2003-09-26 11:17:29 +0800 |
commit | 40ec4b875109295f6c6d407884d265c41bd48e9f (patch) | |
tree | 7058ed963be9fb3ddeaa6b12eac6da7acda9797e /security | |
parent | 8ac1d5419b7e5565c98f9d3f9bf291195971204e (diff) | |
download | freebsd-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/Makefile | 2 | ||||
-rw-r--r-- | security/openssh/files/auth-pam.c | 790 | ||||
-rw-r--r-- | security/openssh/files/auth-pam.h | 61 | ||||
-rw-r--r-- | security/openssh/files/auth2-pam.c | 422 | ||||
-rw-r--r-- | security/openssh/files/patch-auth-chall.c | 36 |
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; ++ } + } |