Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced pam support #30

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <security/pam_appl.h>
#elif defined (HAVE_PAM_PAM_APPL_H)
#include <pam/pam_appl.h>
#endif
#endif

#endif /* DROPBEAR_INCLUDES_H_ */
6 changes: 2 additions & 4 deletions svr-auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
87 changes: 70 additions & 17 deletions svr-authpam.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@

#if DROPBEAR_SVR_PAM_AUTH

#if defined(HAVE_SECURITY_PAM_APPL_H)
#include <security/pam_appl.h>
#elif defined (HAVE_PAM_PAM_APPL_H)
#include <pam/pam_appl.h>
#endif

struct UserDataS {
char* user;
char* passwd;
Expand Down Expand Up @@ -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;
Expand All @@ -207,24 +201,31 @@ 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", NULL, &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;
}

/* 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",
rc, pam_strerror(pamHandlep, rc));
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
Expand All @@ -236,37 +237,89 @@ 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;
}

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,
"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;
}

/* 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.pw_name,
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);
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions svr-chansession.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {

Expand Down