Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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/gnubby_auth_handler_posix.h" | |
| 6 | |
| 7 #include <unistd.h> | |
| 8 #include <utility> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/file_util.h" | |
| 13 #include "base/lazy_instance.h" | |
| 14 #include "base/stl_util.h" | |
| 15 #include "base/strings/string_number_conversions.h" | |
| 16 #include "base/strings/string_split.h" | |
| 17 #include "base/values.h" | |
| 18 #include "net/socket/unix_domain_socket_posix.h" | |
| 19 #include "remoting/base/logging.h" | |
| 20 #include "remoting/host/gnubby_util.h" | |
| 21 #include "remoting/proto/control.pb.h" | |
| 22 #include "remoting/protocol/client_stub.h" | |
| 23 | |
| 24 namespace remoting { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 // The name of the socket to listen for gnubby requests on. | |
| 29 base::LazyInstance<base::FilePath>::Leaky g_gnubby_socket_name = | |
| 30 LAZY_INSTANCE_INITIALIZER; | |
| 31 | |
| 32 // STL predicate to match by a StreamListenSocket pointer. | |
| 33 class CompareSocket { | |
| 34 public: | |
| 35 explicit CompareSocket(net::StreamListenSocket* socket) : socket_(socket) {} | |
| 36 | |
| 37 bool operator()(const std::pair<int, net::StreamListenSocket*> element) | |
| 38 const { | |
| 39 return socket_ == element.second; | |
| 40 } | |
| 41 | |
| 42 private: | |
| 43 net::StreamListenSocket* socket_; | |
| 44 }; | |
| 45 | |
| 46 // Socket authentication function that only allows connections from callers with | |
| 47 // the current uid. | |
| 48 bool MatchUid(uid_t user_id, gid_t) { | |
| 49 bool allowed = user_id == getuid(); | |
| 50 if (!allowed) | |
| 51 HOST_LOG << "Refused socket connection from uid " << user_id; | |
| 52 return allowed; | |
| 53 } | |
| 54 | |
| 55 // Returns true if the request data is complete (has at least as many bytes as | |
| 56 // indicated by the size in the first four bytes plus four for the first bytes). | |
| 57 bool IsRequestComplete(const char* data, int data_len) { | |
| 58 if (data_len < 4) | |
| 59 return false; | |
| 60 int expected_length = ((data[0] & 255) << 24) + ((data[1] & 255) << 16) + | |
| 61 ((data[2] & 255) << 8) + (data[3] & 255) + 4; | |
| 62 return expected_length <= data_len; | |
| 63 } | |
| 64 | |
| 65 } // namespace | |
| 66 | |
| 67 GnubbyAuthHandlerPosix::GnubbyAuthHandlerPosix( | |
| 68 protocol::ClientStub* client_stub) | |
| 69 : client_stub_(client_stub), last_connection_id_(0) { | |
| 70 DCHECK(client_stub_); | |
| 71 } | |
| 72 | |
| 73 GnubbyAuthHandlerPosix::~GnubbyAuthHandlerPosix() { | |
| 74 STLDeleteValues(&active_sockets_); | |
| 75 } | |
| 76 | |
| 77 // static | |
| 78 scoped_ptr<GnubbyAuthHandler> GnubbyAuthHandler::Create( | |
| 79 protocol::ClientStub* client_stub) { | |
| 80 return scoped_ptr<GnubbyAuthHandler>(new GnubbyAuthHandlerPosix(client_stub)); | |
| 81 } | |
| 82 | |
| 83 // static | |
| 84 void GnubbyAuthHandler::SetGnubbySocketName( | |
| 85 const base::FilePath& gnubby_socket_name) { | |
| 86 g_gnubby_socket_name.Get() = gnubby_socket_name; | |
| 87 } | |
| 88 | |
| 89 void GnubbyAuthHandlerPosix::DeliverClientMessage(const std::string& message) { | |
| 90 DCHECK(CalledOnValidThread()); | |
| 91 | |
| 92 std::vector<std::string> values; | |
| 93 base::SplitString(message, ' ', &values); | |
|
Sergey Ulanov
2014/02/14 07:31:59
This will also split the third component that is i
psj
2014/02/15 00:01:34
Done.
| |
| 94 | |
| 95 if (values[0] == "control") { | |
| 96 if (values[1] == "auth-v1") { | |
| 97 CreateAuthorizationSocket(); | |
| 98 } | |
| 99 } else if (values[0] == "data") { | |
| 100 int connection_id = 0; | |
| 101 base::StringToInt(values[1], &connection_id); | |
| 102 | |
| 103 ActiveSockets::iterator iter = active_sockets_.find(connection_id); | |
| 104 if (iter != active_sockets_.end()) { | |
| 105 HOST_LOG << "Sending gnubby response"; | |
| 106 | |
| 107 std::string reply; | |
| 108 GetGnubbyResponseFromJson(values[2], &reply); | |
|
Sergey Ulanov
2014/02/14 07:31:59
You need to verify that |values| contains at least
psj
2014/02/15 00:01:34
Ack
| |
| 109 | |
| 110 iter->second->Send(reply); | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 void GnubbyAuthHandlerPosix::DeliverHostDataMessage(int connection_id, | |
| 116 const std::string& data) | |
| 117 const { | |
| 118 DCHECK(CalledOnValidThread()); | |
| 119 | |
| 120 protocol::ExtensionMessage message; | |
| 121 message.set_type("gnubby-auth"); | |
| 122 message.set_data("data " + base::IntToString(connection_id) + " " + data); | |
| 123 | |
| 124 client_stub_->DeliverHostMessage(message); | |
| 125 } | |
| 126 | |
| 127 bool GnubbyAuthHandlerPosix::HasActiveSocketForTesting( | |
| 128 net::StreamListenSocket* socket) const { | |
| 129 return std::find_if(active_sockets_.begin(), | |
| 130 active_sockets_.end(), | |
| 131 CompareSocket(socket)) != active_sockets_.end(); | |
| 132 } | |
| 133 | |
| 134 void GnubbyAuthHandlerPosix::DidAccept( | |
| 135 net::StreamListenSocket* server, | |
| 136 scoped_ptr<net::StreamListenSocket> socket) { | |
| 137 DCHECK(CalledOnValidThread()); | |
| 138 | |
| 139 active_sockets_[++last_connection_id_] = socket.release(); | |
| 140 } | |
| 141 | |
| 142 void GnubbyAuthHandlerPosix::DidRead(net::StreamListenSocket* socket, | |
| 143 const char* data, | |
| 144 int len) { | |
| 145 DCHECK(CalledOnValidThread()); | |
| 146 | |
| 147 ActiveSockets::iterator socket_iter = std::find_if( | |
| 148 active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket)); | |
| 149 if (socket_iter != active_sockets_.end()) { | |
| 150 int connection_id = socket_iter->first; | |
| 151 | |
| 152 ActiveRequests::iterator request_iter = | |
| 153 active_requests_.find(connection_id); | |
| 154 if (request_iter != active_requests_.end()) { | |
| 155 std::vector<char>& saved_vector = request_iter->second; | |
| 156 saved_vector.insert(saved_vector.end(), data, data + len); | |
| 157 | |
| 158 if (IsRequestComplete(saved_vector.data(), saved_vector.size())) { | |
| 159 ProcessGnubbyRequest( | |
| 160 connection_id, saved_vector.data(), saved_vector.size()); | |
| 161 active_requests_.erase(request_iter); | |
| 162 } | |
| 163 } else if (IsRequestComplete(data, len)) { | |
| 164 ProcessGnubbyRequest(connection_id, data, len); | |
| 165 } else { | |
| 166 active_requests_[connection_id] = std::vector<char>(data, data + len); | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void GnubbyAuthHandlerPosix::DidClose(net::StreamListenSocket* socket) { | |
| 172 DCHECK(CalledOnValidThread()); | |
| 173 | |
| 174 ActiveSockets::iterator iter = std::find_if( | |
| 175 active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket)); | |
| 176 if (iter != active_sockets_.end()) { | |
| 177 active_requests_.erase(iter->first); | |
| 178 | |
| 179 delete iter->second; | |
| 180 active_sockets_.erase(iter); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 void GnubbyAuthHandlerPosix::CreateAuthorizationSocket() { | |
| 185 DCHECK(CalledOnValidThread()); | |
| 186 | |
| 187 if (!g_gnubby_socket_name.Get().empty()) { | |
| 188 // If the file already exists, a socket in use error is returned. | |
| 189 base::DeleteFile(g_gnubby_socket_name.Get(), false); | |
| 190 | |
| 191 HOST_LOG << "Listening for gnubby requests on " | |
| 192 << g_gnubby_socket_name.Get().value(); | |
| 193 | |
| 194 auth_socket_ = net::UnixDomainSocket::CreateAndListen( | |
| 195 g_gnubby_socket_name.Get().value(), this, base::Bind(MatchUid)); | |
| 196 if (!auth_socket_.get()) { | |
| 197 LOG(ERROR) << "Failed to open socket for gnubby requests"; | |
| 198 } | |
| 199 } else { | |
| 200 HOST_LOG << "No gnubby socket name specified"; | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 void GnubbyAuthHandlerPosix::ProcessGnubbyRequest(int connection_id, | |
| 205 const char* data, | |
| 206 int data_len) { | |
| 207 std::string json; | |
| 208 if (GetJsonFromGnubbyRequest(data, data_len, &json)) { | |
| 209 HOST_LOG << "Received gnubby request"; | |
| 210 DeliverHostDataMessage(connection_id, json); | |
| 211 } else { | |
| 212 LOG(ERROR) << "Could not decode gnubby request"; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 } // namespace remoting | |
| OLD | NEW |