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 ConvFunction(int num_msg, | |
25 const struct pam_message** msg, | |
26 struct pam_response** resp, | |
27 void* appdata_ptr); | |
28 | |
29 UserAuthPam* user_auth_pam_; | |
30 pam_handle_t* pam_handle_; | |
31 | |
32 // Store these for the PAM conversation function. | |
33 std::string username_; | |
34 std::string password_; | |
35 }; | |
36 | |
37 UserAuthPamPimpl::UserAuthPamPimpl(UserAuthPam* user_auth_pam) | |
38 : user_auth_pam_(user_auth_pam) { | |
39 } | |
40 | |
41 UserAuthPamPimpl::~UserAuthPamPimpl() { | |
42 } | |
43 | |
44 bool UserAuthPamPimpl::Authenticate(const std::string& username, | |
45 const std::string& password) { | |
46 username_ = username; | |
47 password_ = password; | |
48 struct pam_conv c; | |
49 c.conv = ConvFunction; | |
50 c.appdata_ptr = static_cast<void*>(this); | |
51 // TODO(lambroslambrou): Allow PAM service name to be configurable. | |
52 if (pam_start("chromoting", username_.c_str(), &c, &pam_handle_) != | |
53 PAM_SUCCESS) { | |
54 return false; | |
55 } | |
56 | |
57 // TODO(lambroslambrou): Move to separate thread. | |
58 int pam_status = pam_authenticate(pam_handle_, 0); | |
59 pam_end(pam_handle_, pam_status); | |
60 return pam_status == PAM_SUCCESS; | |
61 } | |
62 | |
63 // static | |
64 int UserAuthPamPimpl::ConvFunction(int num_msg, | |
65 const struct pam_message** msg, | |
awong
2011/02/15 01:05:28
Since this is c++, we don't need to explicitly tag
Lambros
2011/02/15 15:16:35
Done.
| |
66 struct pam_response** resp, | |
67 void* appdata_ptr) { | |
68 if (num_msg <= 0) | |
69 return PAM_CONV_ERR; | |
70 UserAuthPamPimpl* user_auth = | |
71 reinterpret_cast<UserAuthPamPimpl*>(appdata_ptr); | |
72 // Must allocate with malloc(), as the calling PAM module will | |
73 // release the memory with free(). | |
74 struct pam_response* resp_tmp = reinterpret_cast<struct pam_response*>( | |
awong
2011/02/15 01:05:28
Use a scoped_ptr_malloc<> to hold the result?
Lambros
2011/02/15 15:16:35
I had a go at this, but I found it more trouble th
| |
75 malloc(num_msg * sizeof(struct pam_response))); | |
76 if (resp_tmp == NULL) | |
77 return PAM_CONV_ERR; | |
78 bool raise_error = false; | |
79 // On exit from the loop, 'count' will hold the number of initialised items | |
80 // that the cleanup code needs to look at, in case of error. | |
81 int count; | |
82 for (count = 0; count < num_msg; count++) { | |
83 // Alias for readability. | |
84 struct pam_response& r = resp_tmp[count]; | |
awong
2011/02/15 01:05:28
Please avoid single-letter variable names.
Also,
Lambros
2011/02/15 15:16:35
Done.
| |
85 r.resp_retcode = 0; | |
86 r.resp = NULL; | |
87 switch (msg[count]->msg_style) { | |
88 case PAM_PROMPT_ECHO_ON: | |
89 r.resp = strdup(user_auth->username_.c_str()); | |
90 if (r.resp == NULL) | |
91 raise_error = true; | |
92 break; | |
93 case PAM_PROMPT_ECHO_OFF: | |
94 r.resp = strdup(user_auth->password_.c_str()); | |
95 if (r.resp == NULL) | |
96 raise_error = true; | |
97 break; | |
98 case PAM_TEXT_INFO: | |
99 // No response needed, continue with next prompt. | |
awong
2011/02/15 01:05:28
Explain why no response is needed...
Lambros
2011/02/15 15:16:35
Done. I've added a little bit more to the comment
| |
100 break; | |
101 default: | |
102 // Unexpected style code, so abort. | |
103 raise_error = true; | |
104 } | |
105 if (raise_error) | |
106 break; | |
107 } | |
108 | |
109 if (raise_error) { | |
110 // Not passing the response back, so free up any memory used. | |
111 for (int n = 0; n < count; n++) { | |
112 if (resp_tmp[n].resp) { | |
113 free(resp_tmp[n].resp); | |
114 } | |
115 } | |
116 free(resp_tmp); | |
117 return PAM_CONV_ERR; | |
118 } else { | |
119 *resp = resp_tmp; | |
120 return PAM_SUCCESS; | |
121 } | |
122 } | |
123 | |
124 UserAuthPam::UserAuthPam() : pimpl_(new UserAuthPamPimpl(this)) { | |
125 } | |
126 | |
127 UserAuthPam::~UserAuthPam() { | |
128 } | |
129 | |
130 bool UserAuthPam::Authenticate(const std::string& username, | |
131 const std::string& password) { | |
132 return pimpl_->Authenticate(username, password); | |
133 } | |
134 | |
135 } // namespace remoting | |
OLD | NEW |