Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / remoting / host / pam_authorization_factory_posix.cc
1 // Copyright (c) 2012 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/pam_authorization_factory_posix.h"
6
7 #include <security/pam_appl.h>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/environment.h"
12 #include "remoting/base/logging.h"
13 #include "remoting/host/username.h"
14 #include "remoting/protocol/channel_authenticator.h"
15 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
16
17 namespace remoting {
18
19 namespace {
20 class PamAuthorizer : public protocol::Authenticator {
21  public:
22   PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying);
23   virtual ~PamAuthorizer();
24
25   // protocol::Authenticator interface.
26   virtual State state() const OVERRIDE;
27   virtual bool started() const OVERRIDE;
28   virtual RejectionReason rejection_reason() const OVERRIDE;
29   virtual void ProcessMessage(const buzz::XmlElement* message,
30                               const base::Closure& resume_callback) OVERRIDE;
31   virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
32   virtual scoped_ptr<protocol::ChannelAuthenticator>
33       CreateChannelAuthenticator() const OVERRIDE;
34
35  private:
36   void MaybeCheckLocalLogin();
37   bool IsLocalLoginAllowed();
38   void OnMessageProcessed(const base::Closure& resume_callback);
39
40   static int PamConversation(int num_messages,
41                              const struct pam_message** messages,
42                              struct pam_response** responses,
43                              void* context);
44
45   scoped_ptr<protocol::Authenticator> underlying_;
46   enum { NOT_CHECKED, ALLOWED, DISALLOWED } local_login_status_;
47 };
48 }  // namespace
49
50 PamAuthorizer::PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying)
51     : underlying_(underlying.Pass()),
52       local_login_status_(NOT_CHECKED) {
53 }
54
55 PamAuthorizer::~PamAuthorizer() {
56 }
57
58 protocol::Authenticator::State PamAuthorizer::state() const {
59   if (local_login_status_ == DISALLOWED) {
60     return REJECTED;
61   } else {
62     return underlying_->state();
63   }
64 }
65
66 bool PamAuthorizer::started() const {
67   return underlying_->started();
68 }
69
70 protocol::Authenticator::RejectionReason
71 PamAuthorizer::rejection_reason() const {
72   if (local_login_status_ == DISALLOWED) {
73     return INVALID_CREDENTIALS;
74   } else {
75     return underlying_->rejection_reason();
76   }
77 }
78
79 void PamAuthorizer::ProcessMessage(const buzz::XmlElement* message,
80                                    const base::Closure& resume_callback) {
81   // |underlying_| is owned, so Unretained() is safe here.
82   underlying_->ProcessMessage(message, base::Bind(
83       &PamAuthorizer::OnMessageProcessed,
84       base::Unretained(this), resume_callback));
85 }
86
87 void PamAuthorizer::OnMessageProcessed(const base::Closure& resume_callback) {
88   MaybeCheckLocalLogin();
89   resume_callback.Run();
90 }
91
92 scoped_ptr<buzz::XmlElement> PamAuthorizer::GetNextMessage() {
93   scoped_ptr<buzz::XmlElement> result(underlying_->GetNextMessage());
94   MaybeCheckLocalLogin();
95   return result.Pass();
96 }
97
98 scoped_ptr<protocol::ChannelAuthenticator>
99 PamAuthorizer::CreateChannelAuthenticator() const {
100   return underlying_->CreateChannelAuthenticator();
101 }
102
103 void PamAuthorizer::MaybeCheckLocalLogin() {
104   if (local_login_status_ == NOT_CHECKED && state() == ACCEPTED) {
105     local_login_status_ = IsLocalLoginAllowed() ? ALLOWED : DISALLOWED;
106   }
107 }
108
109 bool PamAuthorizer::IsLocalLoginAllowed() {
110   std::string username = GetUsername();
111   if (username.empty()) {
112     return false;
113   }
114   struct pam_conv conv = { PamConversation, NULL };
115   pam_handle_t* handle = NULL;
116   int result = pam_start("chrome-remote-desktop", username.c_str(),
117                          &conv, &handle);
118   if (result == PAM_SUCCESS) {
119     result = pam_acct_mgmt(handle, 0);
120   }
121   pam_end(handle, result);
122
123   HOST_LOG << "Local login check for " << username
124             << (result == PAM_SUCCESS ? " succeeded." : " failed.");
125
126   return result == PAM_SUCCESS;
127 }
128
129 int PamAuthorizer::PamConversation(int num_messages,
130                                    const struct pam_message** messages,
131                                    struct pam_response** responses,
132                                    void* context) {
133   // Assume we're only being asked to log messages, in which case our response
134   // need to be free()-able zero-initialized memory.
135   *responses = static_cast<struct pam_response*>(
136       calloc(num_messages, sizeof(struct pam_response)));
137
138   // We don't expect this function to be called. Since we have no easy way
139   // of returning a response, we consider it to be an error if we're asked
140   // for one and abort. Informational and error messages are logged.
141   for (int i = 0; i < num_messages; ++i) {
142     const struct pam_message* message = messages[i];
143     switch (message->msg_style) {
144       case PAM_ERROR_MSG:
145         LOG(ERROR) << "PAM conversation error message: " << message->msg;
146         break;
147       case PAM_TEXT_INFO:
148         HOST_LOG << "PAM conversation message: " << message->msg;
149         break;
150       default:
151         LOG(FATAL) << "Unexpected PAM conversation response required: "
152                    << message->msg << "; msg_style = " << message->msg_style;
153     }
154   }
155   return PAM_SUCCESS;
156 }
157
158
159 PamAuthorizationFactory::PamAuthorizationFactory(
160     scoped_ptr<protocol::AuthenticatorFactory> underlying)
161     : underlying_(underlying.Pass()) {
162 }
163
164 PamAuthorizationFactory::~PamAuthorizationFactory() {
165 }
166
167 scoped_ptr<protocol::Authenticator>
168 PamAuthorizationFactory::CreateAuthenticator(
169     const std::string& local_jid,
170     const std::string& remote_jid,
171     const buzz::XmlElement* first_message) {
172   scoped_ptr<protocol::Authenticator> authenticator(
173       underlying_->CreateAuthenticator(local_jid, remote_jid, first_message));
174   return scoped_ptr<protocol::Authenticator>(
175       new PamAuthorizer(authenticator.Pass()));
176 }
177
178
179 }  // namespace remoting