From d4129929c66efc312c7ee1e2bdd4fcd6238f8644 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Tue, 24 May 2016 17:42:08 -0500 Subject: [PATCH 1/4] pam: set username and rhost PAM_USER and PAM_RHOST are standard and expected by some modules --- svr-authpam.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/svr-authpam.c b/svr-authpam.c index ac8e5ece6..05bf2db33 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -211,12 +211,19 @@ void svr_auth_pam() { userData.passwd = password; /* Init pam */ - if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + if ((rc = pam_start("sshd", ses.authstate.pw_name, &pamConv, &pamHandlep)) != PAM_SUCCESS) { dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s", rc, pam_strerror(pamHandlep, rc)); goto cleanup; } + /* many pam modules expect RHOST */ + if ((rc = pam_set_item(pamHandlep, PAM_RHOST, svr_ses.remotehost)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + /* just to set it to something */ if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh")) != PAM_SUCCESS) { dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s", From 2d9ddc8a7b0d317df36a3a50c24cd11ac3d58323 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Tue, 24 May 2016 17:47:32 -0500 Subject: [PATCH 2/4] pam: always try auth (even invalid users) * allows modules like tally and shield to work * remote username is logged (instead of blank when invalid) --- svr-auth.c | 6 ++---- svr-authpam.c | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/svr-auth.c b/svr-auth.c index 4dc280c4f..8f56504c8 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -191,10 +191,8 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { - if (valid_user) { - svr_auth_pam(); - goto out; - } + svr_auth_pam(); + goto out; } } #endif diff --git a/svr-authpam.c b/svr-authpam.c index 05bf2db33..f94203b83 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -207,11 +207,11 @@ void svr_auth_pam() { /* used to pass data to the PAM conversation function - don't bother with * strdup() etc since these are touched only by our own conversation * function (above) which takes care of it */ - userData.user = ses.authstate.pw_name; + userData.user = ses.authstate.username; userData.passwd = password; /* Init pam */ - if ((rc = pam_start("sshd", ses.authstate.pw_name, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + if ((rc = pam_start("sshd", ses.authstate.username, &pamConv, &pamHandlep)) != PAM_SUCCESS) { dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s", rc, pam_strerror(pamHandlep, rc)); goto cleanup; @@ -243,7 +243,7 @@ void svr_auth_pam() { rc, pam_strerror(pamHandlep, rc)); dropbear_log(LOG_WARNING, "Bad PAM password attempt for '%s' from %s", - ses.authstate.pw_name, + ses.authstate.username, svr_ses.addrstring); send_msg_userauth_failure(0, 1); goto cleanup; @@ -254,7 +254,7 @@ void svr_auth_pam() { rc, pam_strerror(pamHandlep, rc)); dropbear_log(LOG_WARNING, "Bad PAM password attempt for '%s' from %s", - ses.authstate.pw_name, + ses.authstate.username, svr_ses.addrstring); send_msg_userauth_failure(0, 1); goto cleanup; @@ -262,7 +262,7 @@ void svr_auth_pam() { /* successful authentication */ dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s", - ses.authstate.pw_name, + ses.authstate.username, svr_ses.addrstring); send_msg_userauth_success(); From 9accdb28259f60f541f8b4b2d70665e63cd39493 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Tue, 24 May 2016 19:58:08 -0500 Subject: [PATCH 3/4] pam: session, env, credential support --- auth.h | 7 +++++ includes.h | 8 ++++++ svr-authpam.c | 68 +++++++++++++++++++++++++++++++++++++++-------- svr-chansession.c | 8 ++++++ 4 files changed, 80 insertions(+), 11 deletions(-) diff --git a/auth.h b/auth.h index fb3a75446..db0f72e1a 100644 --- a/auth.h +++ b/auth.h @@ -40,6 +40,8 @@ void send_msg_userauth_banner(buffer *msg); void svr_auth_password(void); void svr_auth_pubkey(void); void svr_auth_pam(void); +void svr_auth_pam_cleanup(void); +void svr_auth_pam_env(void); #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT int svr_pubkey_allows_agentfwd(void); @@ -122,6 +124,11 @@ struct AuthState { #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT struct PubKeyOptions* pubkey_options; #endif +#if DROPBEAR_SVR_PAM_AUTH + pam_handle_t* pam_handle; + unsigned pam_sesopen : 1; + unsigned pam_credset : 1; +#endif }; #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT diff --git a/includes.h b/includes.h index f91a2c2f0..f40f6110f 100644 --- a/includes.h +++ b/includes.h @@ -177,4 +177,12 @@ typedef u_int32_t uint32_t; # define UNUSED(x) x #endif +#if DROPBEAR_SVR_PAM_AUTH +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include +#elif defined (HAVE_PAM_PAM_APPL_H) +#include +#endif +#endif + #endif /* DROPBEAR_INCLUDES_H_ */ diff --git a/svr-authpam.c b/svr-authpam.c index f94203b83..78dc5108f 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -33,12 +33,6 @@ #if DROPBEAR_SVR_PAM_AUTH -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined (HAVE_PAM_PAM_APPL_H) -#include -#endif - struct UserDataS { char* user; char* passwd; @@ -186,7 +180,7 @@ void svr_auth_pam() { &userData /* submitted to pamvConvFunc as appdata_ptr */ }; - pam_handle_t* pamHandlep = NULL; + pam_handle_t* pamHandlep = ses.authstate.pam_handle; char * password = NULL; unsigned int passwordlen; @@ -249,7 +243,9 @@ void svr_auth_pam() { goto cleanup; } - if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { + if ((rc = pam_acct_mgmt(pamHandlep, 0)) == PAM_NEW_AUTHTOK_REQD) + rc = pam_chauthtok(pamHandlep, PAM_CHANGE_EXPIRED_AUTHTOK); + if (rc != PAM_SUCCESS) { dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s", rc, pam_strerror(pamHandlep, rc)); dropbear_log(LOG_WARNING, @@ -260,20 +256,70 @@ void svr_auth_pam() { goto cleanup; } + /* establish requested credentials */ + if ((rc = pam_setcred(pamHandlep, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_setcred() failed, rc=%d, %s", + rc, pam_strerror(pamHandlep, rc)); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + /* open session */ + if ((rc = pam_open_session(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_open_session() failed, rc=%d, %s", + rc, pam_strerror(pamHandlep, rc)); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + /* successful authentication */ dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s", ses.authstate.username, svr_ses.addrstring); + + ses.authstate.pam_sesopen = 1; send_msg_userauth_success(); + goto cleanupok; cleanup: + svr_auth_pam_cleanup(); + +cleanupok: if (password != NULL) { m_burn(password, passwordlen); m_free(password); } - if (pamHandlep != NULL) { - TRACE(("pam_end")) - (void) pam_end(pamHandlep, 0 /* pam_status */); +} + +void svr_auth_pam_cleanup() { + int rc = PAM_SUCCESS; + + if (ses.authstate.pam_handle != NULL) { + if (ses.authstate.pam_sesopen) { + if ((rc = pam_close_session(ses.authstate.pam_handle, PAM_SILENT)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_close_session() failed, rc=%d, %s", + rc, pam_strerror(ses.authstate.pam_handle, rc)); + } + ses.authstate.pam_sesopen = 0; + } + if (ses.authstate.pam_credset) { + if ((rc = pam_setcred(ses.authstate.pam_handle, PAM_DELETE_CRED)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_setcred() failed, rc=%d, %s", + rc, pam_strerror(ses.authstate.pam_handle, rc)); + } + ses.authstate.pam_credset = 0; + } + } + TRACE(("pam_end")) + (void) pam_end(ses.authstate.pam_handle, 0); +} + +void svr_auth_pam_env() { + char **pam_envlist, **pam_env; + if ((pam_envlist = pam_getenvlist(ses.authstate.pam_handle)) != NULL) { + for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { + putenv(*pam_env); + } } } diff --git a/svr-chansession.c b/svr-chansession.c index 6dbc8ad72..5bfb1bd35 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -323,6 +323,10 @@ static void closechansess(struct Channel *channel) { svr_agentcleanup(chansess); #endif +#if DROPBEAR_SVR_PAM_AUTH + svr_auth_pam_cleanup(); +#endif + /* clear child pid entries */ for (i = 0; i < svr_ses.childpidsize; i++) { if (svr_ses.childpids[i].chansess == chansess) { @@ -927,6 +931,10 @@ static void execchild(void *user_data) { #endif /* HAVE_CLEARENV */ #endif /* DEBUG_VALGRIND */ +#if DROPBEAR_SVR_PAM_AUTH + svr_auth_pam_env(chansess); +#endif + /* We can only change uid/gid as root ... */ if (getuid() == 0) { From fa178a2b1f8494cf057024a6a9e740941a042938 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Tue, 24 May 2016 17:32:12 -0500 Subject: [PATCH 4/4] pam: avoid HAVE_PAM_FAIL_DELAY redefine linux pam already defines HAVE_PAM_FAIL_DELAY --- configure.ac | 2 +- svr-authpam.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 893b9041b..5a64c8e02 100644 --- a/configure.ac +++ b/configure.ac @@ -157,7 +157,7 @@ AC_ARG_ENABLE(pam, if test "x$enableval" = "xyes"; then AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***])) AC_MSG_NOTICE(Enabling PAM) - AC_CHECK_FUNCS(pam_fail_delay) + AC_CHECK_FUNC(pam_fail_delay, [AC_DEFINE(WITH_PAM_FAIL_DELAY,1,[Define 1 if pam_fail_delay available])]) else AC_DEFINE(DISABLE_PAM,, Use PAM) AC_MSG_NOTICE(Disabling PAM) diff --git a/svr-authpam.c b/svr-authpam.c index 78dc5108f..51545c399 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -225,7 +225,7 @@ void svr_auth_pam() { goto cleanup; } -#ifdef HAVE_PAM_FAIL_DELAY +#ifdef WITH_PAM_FAIL_DELAY /* We have our own random delay code already, disable PAM's */ (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); #endif