From fe5e26324d268c67c45e8a51b11998372b6c18db Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 20 Jan 2005 14:29:03 +1100 Subject: - (dtucker) [auth-pam.c] Bug #971: Prevent leaking information about user existence via keyboard-interactive/pam, in conjunction with previous auth2-chall.c change; with Colin Watson and djm. --- ChangeLog | 5 ++- auth-pam.c | 147 +++++++++++++++++++++++++++++-------------------------------- 2 files changed, 74 insertions(+), 78 deletions(-) diff --git a/ChangeLog b/ChangeLog index d6761159..4506b529 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,9 @@ behaviour for bsdauth is maintained by checking authctxt->valid in the bsdauth driver. Note that any third-party kbdint drivers will now need to be able to handle responses for invalid logins. ok markus@ + - (dtucker) [auth-pam.c] Bug #971: Prevent leaking information about user + existence via keyboard-interactive/pam, in conjunction with previous + auth2-chall.c change; with Colin Watson and djm. 20041102 - (dtucker) [configure.ac includes.h] Bug #947: Fix compile error on HP-UX @@ -1674,4 +1677,4 @@ - (djm) Trim deprecated options from INSTALL. Mention UsePAM - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu -$Id: ChangeLog,v 1.3517.2.3 2005/01/20 03:27:39 dtucker Exp $ +$Id: ChangeLog,v 1.3517.2.4 2005/01/20 03:29:03 dtucker Exp $ diff --git a/auth-pam.c b/auth-pam.c index a1b26cc5..caffd7c7 100644 --- a/auth-pam.c +++ b/auth-pam.c @@ -47,7 +47,7 @@ /* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ #include "includes.h" -RCSID("$Id: auth-pam.c,v 1.118 2004/10/16 08:52:44 djm Exp $"); +RCSID("$Id: auth-pam.c,v 1.114.2.1 2005/01/20 03:29:04 dtucker Exp $"); #ifdef USE_PAM #if defined(HAVE_SECURITY_PAM_APPL_H) @@ -186,6 +186,7 @@ static int sshpam_account_status = -1; static char **sshpam_env = NULL; static Authctxt *sshpam_authctxt = NULL; static const char *sshpam_password = NULL; +static char badpw[] = "\b\n\r\177INCORRECT"; /* Some PAM implementations don't implement this */ #ifndef HAVE_PAM_GETENVLIST @@ -490,51 +491,6 @@ sshpam_null_conv(int n, struct pam_message **msg, static struct pam_conv null_conv = { sshpam_null_conv, NULL }; -static int -sshpam_store_conv(int n, struct pam_message **msg, - struct pam_response **resp, void *data) -{ - struct pam_response *reply; - int i; - size_t len; - - debug3("PAM: %s called with %d messages", __func__, n); - *resp = NULL; - - if (n <= 0 || n > PAM_MAX_NUM_MSG) - return (PAM_CONV_ERR); - - if ((reply = malloc(n * sizeof(*reply))) == NULL) - return (PAM_CONV_ERR); - memset(reply, 0, n * sizeof(*reply)); - - for (i = 0; i < n; ++i) { - switch (PAM_MSG_MEMBER(msg, i, msg_style)) { - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: - len = strlen(PAM_MSG_MEMBER(msg, i, msg)); - buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); - buffer_append(&loginmsg, "\n", 1 ); - reply[i].resp_retcode = PAM_SUCCESS; - break; - default: - goto fail; - } - } - *resp = reply; - return (PAM_SUCCESS); - - fail: - for(i = 0; i < n; i++) { - if (reply[i].resp != NULL) - xfree(reply[i].resp); - } - xfree(reply); - return (PAM_CONV_ERR); -} - -static struct pam_conv store_conv = { sshpam_store_conv, NULL }; - void sshpam_cleanup(void) { @@ -572,7 +528,7 @@ sshpam_init(Authctxt *authctxt) } debug("PAM: initializing for \"%s\"", user); sshpam_err = - pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); + pam_start(SSHD_PAM_SERVICE, user, &null_conv, &sshpam_handle); sshpam_authctxt = authctxt; if (sshpam_err != PAM_SUCCESS) { @@ -654,7 +610,7 @@ sshpam_query(void *ctx, char **name, char **info, size_t plen; u_char type; char *msg; - size_t len, mlen; + size_t len; debug3("PAM: %s entering", __func__); buffer_init(&buffer); @@ -667,27 +623,22 @@ sshpam_query(void *ctx, char **name, char **info, while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { type = buffer_get_char(&buffer); msg = buffer_get_string(&buffer, NULL); - mlen = strlen(msg); switch (type) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: *num = 1; - len = plen + mlen + 1; + len = plen + strlen(msg) + 1; **prompts = xrealloc(**prompts, len); - strlcpy(**prompts + plen, msg, len - plen); - plen += mlen; + plen += snprintf(**prompts + plen, len, "%s", msg); **echo_on = (type == PAM_PROMPT_ECHO_ON); xfree(msg); return (0); case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* accumulate messages */ - len = plen + mlen + 2; + len = plen + strlen(msg) + 2; **prompts = xrealloc(**prompts, len); - strlcpy(**prompts + plen, msg, len - plen); - plen += mlen; - strlcat(**prompts + plen, "\n", len - plen); - plen++; + plen += snprintf(**prompts + plen, len, "%s\n", msg); xfree(msg); break; case PAM_SUCCESS: @@ -701,6 +652,12 @@ sshpam_query(void *ctx, char **name, char **info, **prompts = NULL; } if (type == PAM_SUCCESS) { + if (!sshpam_authctxt->valid || + (sshpam_authctxt->pw->pw_uid == 0 && + options.permit_root_login != PERMIT_YES)) + fatal("Internal error: PAM auth " + "succeeded when it should have " + "failed"); import_environments(&buffer); *num = 0; **echo_on = 0; @@ -746,7 +703,12 @@ sshpam_respond(void *ctx, u_int num, char **resp) return (-1); } buffer_init(&buffer); - buffer_put_cstring(&buffer, *resp); + if (sshpam_authctxt->valid && + (sshpam_authctxt->pw->pw_uid != 0 || + options.permit_root_login == PERMIT_YES)) + buffer_put_cstring(&buffer, *resp); + else + buffer_put_cstring(&buffer, badpw); if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { buffer_free(&buffer); return (-1); @@ -809,13 +771,11 @@ finish_pam(void) u_int do_pam_account(void) { - debug("%s: called", __func__); if (sshpam_account_status != -1) return (sshpam_account_status); sshpam_err = pam_acct_mgmt(sshpam_handle, 0); - debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, - pam_strerror(sshpam_handle, sshpam_err)); + debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err); if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { sshpam_account_status = 0; @@ -845,7 +805,7 @@ void do_pam_setcred(int init) { sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, - (const void *)&store_conv); + (const void *)&null_conv); if (sshpam_err != PAM_SUCCESS) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); @@ -946,6 +906,51 @@ do_pam_chauthtok(void) pam_strerror(sshpam_handle, sshpam_err)); } +static int +sshpam_store_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct pam_response *reply; + int i; + size_t len; + + debug3("PAM: %s called with %d messages", __func__, n); + *resp = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + + if ((reply = malloc(n * sizeof(*reply))) == NULL) + return (PAM_CONV_ERR); + memset(reply, 0, n * sizeof(*reply)); + + for (i = 0; i < n; ++i) { + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + len = strlen(PAM_MSG_MEMBER(msg, i, msg)); + buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); + buffer_append(&loginmsg, "\n", 1 ); + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + goto fail; + } + } + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + return (PAM_CONV_ERR); +} + +static struct pam_conv store_conv = { sshpam_store_conv, NULL }; + void do_pam_session(void) { @@ -956,21 +961,10 @@ do_pam_session(void) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); sshpam_err = pam_open_session(sshpam_handle, 0); - if (sshpam_err == PAM_SUCCESS) - sshpam_session_open = 1; - else { - sshpam_session_open = 0; - disable_forwarding(); - error("PAM: pam_open_session(): %s", + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: pam_open_session(): %s", pam_strerror(sshpam_handle, sshpam_err)); - } - -} - -int -is_pam_session_open(void) -{ - return sshpam_session_open; + sshpam_session_open = 1; } /* @@ -1093,7 +1087,6 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) { int flags = (options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0); - static char badpw[] = "\b\n\r\177INCORRECT"; if (!options.use_pam || sshpam_handle == NULL) fatal("PAM: %s called when PAM disabled or failed to " -- cgit v1.2.3