Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "remoting/host/user_auth_pam.h" | |
| 6 | |
| 7 #include <security/pam_appl.h> | |
| 8 #include <stdlib.h> | |
| 9 #include <string> | |
| 10 | |
| 11 namespace remoting { | |
| 12 | |
| 13 // Private Implementation pattern to avoid leaking PAM types, and the | |
| 14 // conversation function, into the header file. | |
| 15 class UserAuthPamPimpl { | |
| 16 public: | |
| 17 explicit UserAuthPamPimpl(UserAuthPam* user_auth_pam); | |
| 18 ~UserAuthPamPimpl(); | |
| 19 bool Authenticate(const std::string& username, | |
| 20 const std::string& password); | |
| 21 | |
| 22 private: | |
| 23 // Conversation function passed to PAM as a callback. | |
| 24 static int convFn(int num_msg, const struct pam_message** msg, | |
|
Sergey Ulanov
2011/02/10 20:14:28
ConvFunction?
| |
| 25 struct pam_response** resp, void* appdata_ptr); | |
| 26 | |
| 27 UserAuthPam* user_auth_pam_; | |
| 28 pam_handle_t* pam_handle_; | |
| 29 | |
| 30 // Store these for the PAM conversation function. | |
| 31 std::string username_; | |
| 32 std::string password_; | |
| 33 }; | |
| 34 | |
| 35 UserAuthPamPimpl::UserAuthPamPimpl(UserAuthPam* user_auth_pam) | |
| 36 : user_auth_pam_(user_auth_pam) { | |
| 37 } | |
| 38 | |
| 39 UserAuthPamPimpl::~UserAuthPamPimpl() { | |
| 40 } | |
| 41 | |
| 42 bool UserAuthPamPimpl::Authenticate(const std::string& username, | |
| 43 const std::string& password) { | |
|
Sergey Ulanov
2011/02/10 20:14:28
nit: wrapped arguments should be aligned with the
| |
| 44 username_ = username; | |
| 45 password_ = password; | |
| 46 struct pam_conv c; | |
| 47 c.conv = convFn; | |
| 48 c.appdata_ptr = static_cast<void*>(this); | |
| 49 // TODO(lambroslambrou): allow PAM service name to be configurable | |
|
Sergey Ulanov
2011/02/10 20:14:28
nit: comments should be full sentences: start with
| |
| 50 if (pam_start("chromoting", username_.c_str(), &c, &pam_handle_) != | |
| 51 PAM_SUCCESS) { | |
| 52 return false; | |
| 53 } | |
| 54 | |
| 55 // TODO(lambroslambrou): move to separate thread | |
|
Sergey Ulanov
2011/02/10 20:14:28
nit: same here
| |
| 56 int pam_status = pam_authenticate(pam_handle_, 0); | |
| 57 pam_end(pam_handle_, pam_status); | |
| 58 return pam_status == PAM_SUCCESS; | |
| 59 } | |
| 60 | |
| 61 // static | |
| 62 int UserAuthPamPimpl::convFn(int num_msg, const struct pam_message** msg, | |
| 63 struct pam_response** resp, void* appdata_ptr) { | |
|
Sergey Ulanov
2011/02/10 20:14:28
nit: indent properly
| |
| 64 if (num_msg <= 0) | |
| 65 return PAM_CONV_ERR; | |
| 66 UserAuthPamPimpl* user_auth = | |
| 67 reinterpret_cast<UserAuthPamPimpl*>(appdata_ptr); | |
| 68 // Must allocate with malloc(), as the calling PAM module will | |
| 69 // release the memory with free(). | |
| 70 struct pam_response* resp_tmp = reinterpret_cast<struct pam_response*>( | |
| 71 malloc(num_msg * sizeof(struct pam_response))); | |
| 72 if (resp_tmp == NULL) | |
| 73 return PAM_CONV_ERR; | |
| 74 bool raise_error = false; | |
| 75 int count; | |
|
Sergey Ulanov
2011/02/10 20:14:28
This can be inside of for()
| |
| 76 for (count = 0; count < num_msg; count++) { | |
| 77 // Alias for readability | |
|
Sergey Ulanov
2011/02/10 20:14:28
nit: period at the end of the sentence.
| |
| 78 struct pam_response &r = resp_tmp[count]; | |
| 79 r.resp_retcode = 0; | |
| 80 r.resp = NULL; | |
| 81 switch (msg[count]->msg_style) { | |
| 82 case PAM_PROMPT_ECHO_ON: | |
| 83 r.resp = strdup(user_auth->username_.c_str()); | |
| 84 if (r.resp == NULL) | |
| 85 raise_error = true; | |
| 86 break; | |
| 87 case PAM_PROMPT_ECHO_OFF: | |
| 88 r.resp = strdup(user_auth->password_.c_str()); | |
| 89 if (r.resp == NULL) | |
| 90 raise_error = true; | |
| 91 break; | |
| 92 case PAM_TEXT_INFO: | |
| 93 // No response needed, continue with next prompt. | |
| 94 break; | |
| 95 default: | |
| 96 // Unexpected style code, so abort. | |
| 97 raise_error = true; | |
| 98 } | |
| 99 if (raise_error) | |
| 100 break; | |
| 101 } | |
| 102 | |
| 103 if (raise_error) { | |
| 104 // Not passing the response back, so free up any memory used. | |
| 105 for (int n = 0; n < count; n++) { | |
| 106 if (resp_tmp[n].resp) { | |
| 107 free(resp_tmp[n].resp); | |
| 108 } | |
| 109 } | |
| 110 free(resp_tmp); | |
| 111 return PAM_CONV_ERR; | |
| 112 } else { | |
| 113 *resp = resp_tmp; | |
| 114 return PAM_SUCCESS; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 UserAuthPam::UserAuthPam() | |
| 119 : pimpl_(new UserAuthPamPimpl(this)) { | |
| 120 } | |
| 121 | |
| 122 UserAuthPam::~UserAuthPam() { | |
| 123 } | |
| 124 | |
| 125 bool UserAuthPam::Authenticate(const std::string& username, | |
| 126 const std::string& password) { | |
| 127 return pimpl_->Authenticate(username, password); | |
| 128 } | |
| 129 | |
| 130 } // namespace remoting | |
| OLD | NEW |