summaryrefslogtreecommitdiffstats
path: root/remoting/host/user_authenticator_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'remoting/host/user_authenticator_linux.cc')
-rw-r--r--remoting/host/user_authenticator_linux.cc124
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();