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