diff options
Diffstat (limited to 'remoting/host/user_authenticator_linux.cc')
-rw-r--r-- | remoting/host/user_authenticator_linux.cc | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/remoting/host/user_authenticator_linux.cc b/remoting/host/user_authenticator_linux.cc index d3b837c..b1a70cd 100644 --- a/remoting/host/user_authenticator_linux.cc +++ b/remoting/host/user_authenticator_linux.cc @@ -2,10 +2,132 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/host/user_authenticator_pam.h" +#include "remoting/host/user_authenticator.h" + +#include <security/pam_appl.h> +#include <stdlib.h> + +#include <string> + +#include "base/basictypes.h" namespace remoting { +namespace { + +// Class to perform a single PAM user authentication. +// +// TODO(lambroslambrou): As pam_authenticate() can be blocking, this needs to +// expose an asynchronous API, with pam_authenticate() called in a background +// thread. +class UserAuthenticatorPam : public UserAuthenticator { + public: + UserAuthenticatorPam() {} + virtual ~UserAuthenticatorPam() {} + virtual bool Authenticate(const std::string& username, + const std::string& password); + + private: + // Conversation function passed to PAM as a callback. + static int ConvFunction(int num_msg, + const pam_message** msg, + pam_response** resp, + void* appdata_ptr); + + // Store these for the PAM conversation function. + std::string username_; + std::string password_; + + DISALLOW_COPY_AND_ASSIGN(UserAuthenticatorPam); +}; + +const char kPamServiceName[] = "chromoting"; + +bool UserAuthenticatorPam::Authenticate(const std::string& username, + const std::string& password) { + username_ = username; + password_ = password; + pam_conv conversation; + conversation.conv = ConvFunction; + conversation.appdata_ptr = static_cast<void*>(this); + // TODO(lambroslambrou): Allow PAM service name to be configurable. + pam_handle_t* pam_handle; + if (pam_start(kPamServiceName, username_.c_str(), + &conversation, &pam_handle) != PAM_SUCCESS) { + return false; + } + + // TODO(lambroslambrou): Move to separate thread. + int pam_status = pam_authenticate(pam_handle, 0); + pam_end(pam_handle, pam_status); + return pam_status == PAM_SUCCESS; +} + +// static +int UserAuthenticatorPam::ConvFunction(int num_msg, + const pam_message** msg, + pam_response** resp, + void* appdata_ptr) { + if (num_msg <= 0) + return PAM_CONV_ERR; + UserAuthenticatorPam* user_auth = + static_cast<UserAuthenticatorPam*>(appdata_ptr); + // Must allocate with malloc(), as the calling PAM module will + // release the memory with free(). + pam_response* resp_tmp = static_cast<pam_response*>( + malloc(num_msg * sizeof(pam_response))); + if (resp_tmp == NULL) + return PAM_CONV_ERR; + + bool raise_error = false; + // On exit from the loop, 'count' will hold the number of initialised items + // that the cleanup code needs to look at, in case of error. + int count; + for (count = 0; count < num_msg; count++) { + // Alias for readability. + pam_response* resp_item = &resp_tmp[count]; + resp_item->resp_retcode = 0; + resp_item->resp = NULL; + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + resp_item->resp = strdup(user_auth->username_.c_str()); + if (resp_item->resp == NULL) + raise_error = true; + break; + case PAM_PROMPT_ECHO_OFF: + resp_item->resp = strdup(user_auth->password_.c_str()); + if (resp_item->resp == NULL) + raise_error = true; + break; + case PAM_TEXT_INFO: + // No response needed, as this instructs the PAM client to display + // text to the user. Leave as NULL and continue with next prompt. + break; + default: + // Unexpected style code, so abort. + raise_error = true; + } + if (raise_error) + break; + } + + if (raise_error) { + // Not passing the response back, so free up any memory used. + for (int n = 0; n < count; n++) { + if (resp_tmp[n].resp) { + free(resp_tmp[n].resp); + } + } + free(resp_tmp); + return PAM_CONV_ERR; + } else { + *resp = resp_tmp; + return PAM_SUCCESS; + } +} + +} // namespace + // static UserAuthenticator* UserAuthenticator::Create() { return new UserAuthenticatorPam(); |