Index: remoting/host/gnubby_auth_handler_posix.cc |
diff --git a/remoting/host/gnubby_auth_handler_posix.cc b/remoting/host/gnubby_auth_handler_posix.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..44962cc8dd87dc4a598bbbec4d61fab6aa5a7450 |
--- /dev/null |
+++ b/remoting/host/gnubby_auth_handler_posix.cc |
@@ -0,0 +1,228 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/host/gnubby_auth_handler.h" |
+ |
+#include "base/file_util.h" |
+#include "base/json/json_reader.h" |
+#include "base/lazy_instance.h" |
+#include "base/stl_util.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/values.h" |
+#include "net/socket/unix_domain_socket_posix.h" |
+#include "remoting/base/logging.h" |
+#include "remoting/host/gnubby_util.h" |
+#include "remoting/proto/control.pb.h" |
+#include "remoting/protocol/client_stub.h" |
+ |
+namespace remoting { |
+ |
+namespace { |
+ |
+class GnubbyAuthHandlerPosix : public GnubbyAuthHandler, |
+ public base::NonThreadSafe, |
+ public net::StreamListenSocket::Delegate { |
+ public: |
+ explicit GnubbyAuthHandlerPosix(protocol::ClientStub* client_stub); |
+ virtual ~GnubbyAuthHandlerPosix(); |
+ |
+ private: |
+ // GnubbyAuthHandler interface. |
+ virtual void DeliverClientMessage(const std::string& message) OVERRIDE; |
+ virtual void DeliverHostDataMessage(int connection_id, |
+ const std::string& data) const OVERRIDE; |
+ |
+ // StreamListenSocket::Delegate interface. |
+ virtual void DidAccept(net::StreamListenSocket* server, |
+ scoped_ptr<net::StreamListenSocket> socket) OVERRIDE; |
+ virtual void DidRead(net::StreamListenSocket* socket, |
+ const char* data, |
+ int len) OVERRIDE; |
+ virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE; |
+ |
+ // Create socket for authorization. |
+ void CreateAuthorizationSocket(); |
+ |
+ // Socket used to listen for authorization requests. |
+ scoped_ptr<net::StreamListenSocket> auth_socket_; |
+ |
+ // The last assigned gnubby connection id. |
+ int last_connection_id_; |
+ |
+ // Socket and connection id pairs used to process gnubbyd requests |
+ typedef std::vector<std::pair<net::StreamListenSocket*, int> > ActiveSockets; |
+ ActiveSockets active_sockets_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GnubbyAuthHandlerPosix); |
+}; |
+ |
+// The name of the socket to listen for gnubby requests on. |
+base::LazyInstance<base::FilePath>::Leaky g_gnubby_socket_name = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+// STL predicate to match by a StreamListenSocket pointer. |
+class CompareSocket { |
+ public: |
+ explicit CompareSocket(net::StreamListenSocket* socket) : socket_(socket) {} |
+ |
+ bool operator()(const std::pair<net::StreamListenSocket*, int> element) |
+ const { |
+ return socket_ == element.first; |
+ } |
+ |
+ private: |
+ net::StreamListenSocket* socket_; |
+}; |
+ |
+// STL predicate to match by a connection id. |
+class CompareConnection { |
+ public: |
+ explicit CompareConnection(int connection_id) |
+ : connection_id_(connection_id) {} |
+ |
+ bool operator()(const std::pair<net::StreamListenSocket*, int> element) |
+ const { |
+ return connection_id_ == element.second; |
+ } |
+ |
+ private: |
+ int connection_id_; |
+}; |
+ |
+} // namespace |
+ |
+GnubbyAuthHandlerPosix::GnubbyAuthHandlerPosix( |
+ protocol::ClientStub* client_stub) |
+ : GnubbyAuthHandler(client_stub), last_connection_id_(0) {} |
+ |
+GnubbyAuthHandlerPosix::~GnubbyAuthHandlerPosix() { |
+ STLDeleteContainerPairFirstPointers(active_sockets_.begin(), |
+ active_sockets_.end()); |
+} |
+ |
+// static |
+scoped_ptr<GnubbyAuthHandler> GnubbyAuthHandler::Create( |
+ protocol::ClientStub* client_stub) { |
+ return scoped_ptr<GnubbyAuthHandler>(new GnubbyAuthHandlerPosix(client_stub)); |
+} |
+ |
+// static |
+void GnubbyAuthHandler::SetGnubbySocketName( |
+ const base::FilePath& gnubby_socket_name) { |
+ g_gnubby_socket_name.Get() = gnubby_socket_name; |
+} |
+ |
+void GnubbyAuthHandlerPosix::DeliverClientMessage(const std::string& message) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ scoped_ptr<base::Value> value(base::JSONReader::Read(message)); |
+ base::ListValue* list = NULL; |
+ bool result = value->GetAsList(&list); |
Sergey Ulanov
2014/02/11 08:20:38
value may be NULL here if |message| is not valid J
psj
2014/02/12 09:01:01
Ack
|
+ |
+ std::string auth_message_type; |
+ result = result && list->GetString(0, &auth_message_type); |
+ if (result && auth_message_type == "control") { |
+ std::string payload; |
+ result = list->GetString(1, &payload); |
+ if (result && payload == "auth-v1") { |
+ CreateAuthorizationSocket(); |
+ } |
+ } else if (result && auth_message_type == "data") { |
+ std::string connection_id_str; |
+ std::string payload; |
+ result = list->GetString(1, &connection_id_str); |
+ result = result && list->GetString(2, &payload); |
+ if (result) { |
+ int connection_id = 0; |
+ base::StringToInt(connection_id_str, &connection_id); |
+ |
+ ActiveSockets::iterator iter = |
+ std::find_if(active_sockets_.begin(), |
+ active_sockets_.end(), |
+ CompareConnection(connection_id)); |
+ if (iter != active_sockets_.end()) { |
+ HOST_LOG << "Sending gnubby response"; |
+ |
+ std::string reply; |
+ GetGnubbyResponseFromJson(payload, &reply); |
+ |
+ iter->first->Send(reply); |
+ } |
+ } |
+ } |
+} |
+ |
+void GnubbyAuthHandlerPosix::DeliverHostDataMessage(int connection_id, |
+ const std::string& data) |
+ const { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ protocol::ExtensionMessage message; |
+ message.set_type("gnubby-auth"); |
+ message.set_data("data " + base::IntToString(connection_id) + " " + data); |
+ |
+ client_stub_->DeliverHostMessage(message); |
+} |
+ |
+void GnubbyAuthHandlerPosix::DidAccept( |
+ net::StreamListenSocket* server, |
+ scoped_ptr<net::StreamListenSocket> socket) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ active_sockets_.push_back( |
+ std::make_pair(socket.release(), ++last_connection_id_)); |
+} |
+ |
+void GnubbyAuthHandlerPosix::DidRead(net::StreamListenSocket* socket, |
+ const char* data, |
+ int len) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ ActiveSockets::iterator iter = std::find_if( |
+ active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket)); |
+ if (iter != active_sockets_.end()) { |
+ std::string json; |
+ if (GetJsonFromGnubbyRequest(data, len, &json)) { |
Sergey Ulanov
2014/02/11 08:20:38
Given that the |socket| is a stream socket can it
psj
2014/02/12 09:01:01
No idea. The message easily fits in the socket rea
Sergey Ulanov
2014/02/14 07:31:59
Right. So it looks like this code will work proper
psj
2014/02/15 00:01:33
Yes, I already implemented this. See active_reques
|
+ HOST_LOG << "Received gnubby request"; |
+ DeliverHostDataMessage(iter->second, json); |
+ } else { |
+ HOST_LOG << "Could not decode blob"; |
Sergey Ulanov
2014/02/11 08:20:38
Maybe "Could not decode gnubby request" to make it
psj
2014/02/12 09:01:01
Done.
|
+ } |
+ } |
+} |
+ |
+void GnubbyAuthHandlerPosix::DidClose(net::StreamListenSocket* socket) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ ActiveSockets::iterator iter = std::find_if( |
+ active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket)); |
+ if (iter != active_sockets_.end()) { |
+ delete iter->first; |
+ active_sockets_.erase(iter); |
+ } |
+} |
+ |
+void GnubbyAuthHandlerPosix::CreateAuthorizationSocket() { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ if (!g_gnubby_socket_name.Get().empty()) { |
+ // If the file already exists, a socket in use error is returned. |
+ base::DeleteFile(g_gnubby_socket_name.Get(), false); |
+ |
+ HOST_LOG << "Listening for gnubby requests on " |
+ << g_gnubby_socket_name.Get().value(); |
+ |
+ auth_socket_ = net::UnixDomainSocket::CreateAndListen( |
+ g_gnubby_socket_name.Get().value(), |
+ this, |
+ net::UnixDomainSocket::NoAuthentication()); |
Sergey Ulanov
2014/02/11 08:20:38
Is it acceptable to allow other users on this mach
psj
2014/02/12 09:01:01
Done.
|
+ if (!auth_socket_.get()) { |
+ HOST_LOG << "Failed to open socket for gnubby requests"; |
+ } |
+ } else { |
+ HOST_LOG << "No gnubby socket name specified"; |
+ } |
+} |
+ |
+} // namespace remoting |