pam_authorization_factory_posix.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/channel_authenticator.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PamAuthorizer : public protocol::Authenticator { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~PamAuthorizer(); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // protocol::Authenticator interface. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual State state() const OVERRIDE; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual RejectionReason rejection_reason() const OVERRIDE; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void ProcessMessage(const buzz::XmlElement* message, 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& resume_callback) OVERRIDE; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual scoped_ptr<protocol::ChannelAuthenticator> 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateChannelAuthenticator() const OVERRIDE; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MaybeCheckLocalLogin(); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsLocalLoginAllowed(); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnMessageProcessed(const base::Closure& resume_callback); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int PamConversation(int num_messages, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct pam_message** messages, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct pam_response** responses, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* context); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::Authenticator> underlying_; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { NOT_CHECKED, ALLOWED, DISALLOWED } local_login_status_; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::PamAuthorizer(scoped_ptr<protocol::Authenticator> underlying) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : underlying_(underlying.Pass()), 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_login_status_(NOT_CHECKED) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::~PamAuthorizer() { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)protocol::Authenticator::State PamAuthorizer::state() const { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (local_login_status_ == DISALLOWED) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return REJECTED; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return underlying_->state(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)protocol::Authenticator::RejectionReason 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::rejection_reason() const { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (local_login_status_ == DISALLOWED) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_CREDENTIALS; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return underlying_->rejection_reason(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PamAuthorizer::ProcessMessage(const buzz::XmlElement* message, 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& resume_callback) { 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |underlying_| is owned, so Unretained() is safe here. 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) underlying_->ProcessMessage(message, base::Bind( 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &PamAuthorizer::OnMessageProcessed, 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this), resume_callback)); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PamAuthorizer::OnMessageProcessed(const base::Closure& resume_callback) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MaybeCheckLocalLogin(); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) resume_callback.Run(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<buzz::XmlElement> PamAuthorizer::GetNextMessage() { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<buzz::XmlElement> result(underlying_->GetNextMessage()); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MaybeCheckLocalLogin(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result.Pass(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<protocol::ChannelAuthenticator> 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizer::CreateChannelAuthenticator() const { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return underlying_->CreateChannelAuthenticator(); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PamAuthorizer::MaybeCheckLocalLogin() { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (local_login_status_ == NOT_CHECKED && state() == ACCEPTED) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_login_status_ = IsLocalLoginAllowed() ? ALLOWED : DISALLOWED; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PamAuthorizer::IsLocalLoginAllowed() { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string username; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Environment::Create()->GetVar("USER", &username)) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct pam_conv conv = { PamConversation, NULL }; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pam_handle_t* handle = NULL; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = pam_start("chrome-remote-desktop", username.c_str(), 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &conv, &handle); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == PAM_SUCCESS) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = pam_acct_mgmt(handle, 0); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pam_end(handle, result); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Local login check for " << username 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << (result == PAM_SUCCESS ? " succeeded." : " failed."); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result == PAM_SUCCESS; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PamAuthorizer::PamConversation(int num_messages, 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct pam_message** messages, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct pam_response** responses, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* context) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assume we're only being asked to log messages, in which case our response 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to be free()-able zero-initialized memory. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *responses = static_cast<struct pam_response*>( 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) calloc(num_messages, sizeof(struct pam_response))); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't expect this function to be called. Since we have no easy way 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of returning a response, we consider it to be an error if we're asked 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for one and abort. Informational and error messages are logged. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < num_messages; ++i) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct pam_message* message = messages[i]; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (message->msg_style) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case PAM_ERROR_MSG: 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "PAM conversation error message: " << message->msg; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case PAM_TEXT_INFO: 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "PAM conversation message: " << message->msg; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(FATAL) << "Unexpected PAM conversation response required: " 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << message->msg << "; msg_style = " << message->msg_style; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PAM_SUCCESS; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::PamAuthorizationFactory( 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::AuthenticatorFactory> underlying) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : underlying_(underlying.Pass()) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::~PamAuthorizationFactory() { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<protocol::Authenticator> 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PamAuthorizationFactory::CreateAuthenticator( 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& local_jid, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& remote_jid, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const buzz::XmlElement* first_message) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::Authenticator> authenticator( 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) underlying_->CreateAuthenticator(local_jid, remote_jid, first_message)); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return scoped_ptr<protocol::Authenticator>( 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new PamAuthorizer(authenticator.Pass())); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 175