15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/pam_authorization_factory_posix.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <security/pam_appl.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "remoting/base/logging.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "remoting/host/username.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/channel_authenticator.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PamAuthorizer : public protocol::Authenticator {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~PamAuthorizer();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // protocol::Authenticator interface.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual State state() const OVERRIDE;
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual bool started() const OVERRIDE;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual RejectionReason rejection_reason() const OVERRIDE;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ProcessMessage(const buzz::XmlElement* message,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const base::Closure& resume_callback) OVERRIDE;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual scoped_ptr<protocol::ChannelAuthenticator>
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateChannelAuthenticator() const OVERRIDE;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void MaybeCheckLocalLogin();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsLocalLoginAllowed();
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnMessageProcessed(const base::Closure& resume_callback);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int PamConversation(int num_messages,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const struct pam_message** messages,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             struct pam_response** responses,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             void* context);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<protocol::Authenticator> underlying_;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum { NOT_CHECKED, ALLOWED, DISALLOWED } local_login_status_;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : underlying_(underlying.Pass()),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_login_status_(NOT_CHECKED) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::~PamAuthorizer() {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)protocol::Authenticator::State PamAuthorizer::state() const {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_login_status_ == DISALLOWED) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return REJECTED;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return underlying_->state();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool PamAuthorizer::started() const {
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return underlying_->started();
68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)protocol::Authenticator::RejectionReason
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::rejection_reason() const {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_login_status_ == DISALLOWED) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return INVALID_CREDENTIALS;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return underlying_->rejection_reason();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PamAuthorizer::ProcessMessage(const buzz::XmlElement* message,
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const base::Closure& resume_callback) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |underlying_| is owned, so Unretained() is safe here.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  underlying_->ProcessMessage(message, base::Bind(
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &PamAuthorizer::OnMessageProcessed,
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Unretained(this), resume_callback));
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PamAuthorizer::OnMessageProcessed(const base::Closure& resume_callback) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeCheckLocalLogin();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resume_callback.Run();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<buzz::XmlElement> PamAuthorizer::GetNextMessage() {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<buzz::XmlElement> result(underlying_->GetNextMessage());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeCheckLocalLogin();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.Pass();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<protocol::ChannelAuthenticator>
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::CreateChannelAuthenticator() const {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return underlying_->CreateChannelAuthenticator();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PamAuthorizer::MaybeCheckLocalLogin() {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_login_status_ == NOT_CHECKED && state() == ACCEPTED) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_login_status_ = IsLocalLoginAllowed() ? ALLOWED : DISALLOWED;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PamAuthorizer::IsLocalLoginAllowed() {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string username = GetUsername();
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (username.empty()) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct pam_conv conv = { PamConversation, NULL };
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pam_handle_t* handle = NULL;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = pam_start("chrome-remote-desktop", username.c_str(),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &conv, &handle);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == PAM_SUCCESS) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = pam_acct_mgmt(handle, 0);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pam_end(handle, result);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  HOST_LOG << "Local login check for " << username
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << (result == PAM_SUCCESS ? " succeeded." : " failed.");
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == PAM_SUCCESS;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PamAuthorizer::PamConversation(int num_messages,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const struct pam_message** messages,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   struct pam_response** responses,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   void* context) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Assume we're only being asked to log messages, in which case our response
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to be free()-able zero-initialized memory.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *responses = static_cast<struct pam_response*>(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      calloc(num_messages, sizeof(struct pam_response)));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't expect this function to be called. Since we have no easy way
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of returning a response, we consider it to be an error if we're asked
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for one and abort. Informational and error messages are logged.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < num_messages; ++i) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const struct pam_message* message = messages[i];
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (message->msg_style) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PAM_ERROR_MSG:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "PAM conversation error message: " << message->msg;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PAM_TEXT_INFO:
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        HOST_LOG << "PAM conversation message: " << message->msg;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(FATAL) << "Unexpected PAM conversation response required: "
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << message->msg << "; msg_style = " << message->msg_style;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PAM_SUCCESS;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::PamAuthorizationFactory(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<protocol::AuthenticatorFactory> underlying)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : underlying_(underlying.Pass()) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::~PamAuthorizationFactory() {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<protocol::Authenticator>
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::CreateAuthenticator(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& local_jid,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& remote_jid,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const buzz::XmlElement* first_message) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<protocol::Authenticator> authenticator(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      underlying_->CreateAuthenticator(local_jid, remote_jid, first_message));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<protocol::Authenticator>(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new PamAuthorizer(authenticator.Pass()));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
180