Index: remoting/host/user_auth_pam.cc |
diff --git a/remoting/host/user_auth_pam.cc b/remoting/host/user_auth_pam.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d6a3f625a5e1b602757f7444219c54111bce9ece |
--- /dev/null |
+++ b/remoting/host/user_auth_pam.cc |
@@ -0,0 +1,136 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/host/user_auth_pam.h" |
+ |
+#include <security/pam_appl.h> |
+#include <stdlib.h> |
+#include <string> |
+ |
+namespace remoting { |
+ |
+// Private Implementation pattern to avoid leaking PAM types, and the |
+// conversation function, into the header file. |
+class UserAuthPamPimpl { |
+ public: |
+ explicit UserAuthPamPimpl(UserAuthPam* user_auth_pam); |
+ ~UserAuthPamPimpl(); |
+ 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, |
Sergey Ulanov
2011/02/11 19:35:20
Capital C. Function names and class names must alw
|
+ const struct pam_message** msg, |
+ struct pam_response** resp, |
+ void* appdata_ptr); |
+ |
+ UserAuthPam* user_auth_pam_; |
+ pam_handle_t* pam_handle_; |
+ |
+ // Store these for the PAM conversation function. |
+ std::string username_; |
+ std::string password_; |
+}; |
+ |
+UserAuthPamPimpl::UserAuthPamPimpl(UserAuthPam* user_auth_pam) |
+ : user_auth_pam_(user_auth_pam) { |
+} |
+ |
+UserAuthPamPimpl::~UserAuthPamPimpl() { |
+} |
+ |
+bool UserAuthPamPimpl::Authenticate(const std::string& username, |
+ const std::string& password) { |
+ username_ = username; |
+ password_ = password; |
+ struct pam_conv c; |
+ c.conv = convFunction; |
+ c.appdata_ptr = static_cast<void*>(this); |
+ // TODO(lambroslambrou): Allow PAM service name to be configurable. |
+ if (pam_start("chromoting", username_.c_str(), &c, &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 UserAuthPamPimpl::convFunction(int num_msg, |
+ const struct pam_message** msg, |
+ struct pam_response** resp, |
+ void* appdata_ptr) { |
+ if (num_msg <= 0) |
+ return PAM_CONV_ERR; |
+ UserAuthPamPimpl* user_auth = |
+ reinterpret_cast<UserAuthPamPimpl*>(appdata_ptr); |
+ // Must allocate with malloc(), as the calling PAM module will |
+ // release the memory with free(). |
+ struct pam_response* resp_tmp = reinterpret_cast<struct pam_response*>( |
+ malloc(num_msg * sizeof(struct 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. |
+ struct pam_response& r = resp_tmp[count]; |
+ r.resp_retcode = 0; |
+ r.resp = NULL; |
+ switch (msg[count]->msg_style) { |
+ case PAM_PROMPT_ECHO_ON: |
+ r.resp = strdup(user_auth->username_.c_str()); |
+ if (r.resp == NULL) |
+ raise_error = true; |
+ break; |
+ case PAM_PROMPT_ECHO_OFF: |
+ r.resp = strdup(user_auth->password_.c_str()); |
+ if (r.resp == NULL) |
+ raise_error = true; |
+ break; |
+ case PAM_TEXT_INFO: |
+ // No response needed, 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; |
+ } |
+} |
+ |
+UserAuthPam::UserAuthPam() |
+ : pimpl_(new UserAuthPamPimpl(this)) { |
+} |
+ |
+UserAuthPam::~UserAuthPam() { |
+} |
+ |
+bool UserAuthPam::Authenticate(const std::string& username, |
+ const std::string& password) { |
+ return pimpl_->Authenticate(username, password); |
+} |
+ |
+} // namespace remoting |