Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: remoting/host/gnubby_auth_handler_posix.cc

Issue 138753005: Add gnubby authentication to remoting host (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Another Windows warning Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/lazy_instance.h"
16 #include "base/stl_util.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 const int kMaxRequestLength = 4096;
29
30 const char kConnectionId[] = "connectionId";
31 const char kControlMessage[] = "control";
32 const char kControlOption[] = "option";
33 const char kDataMessage[] = "data";
34 const char kGnubbyAuthMessage[] = "gnubby-auth";
35 const char kGnubbyAuthV1[] = "auth-v1";
36 const char kJSONMessage[] = "jsonMessage";
37 const char kMessageType[] = "type";
38
39 // The name of the socket to listen for gnubby requests on.
40 base::LazyInstance<base::FilePath>::Leaky g_gnubby_socket_name =
41 LAZY_INSTANCE_INITIALIZER;
42
43 // STL predicate to match by a StreamListenSocket pointer.
44 class CompareSocket {
45 public:
46 explicit CompareSocket(net::StreamListenSocket* socket) : socket_(socket) {}
47
48 bool operator()(const std::pair<int, net::StreamListenSocket*> element)
49 const {
50 return socket_ == element.second;
51 }
52
53 private:
54 net::StreamListenSocket* socket_;
55 };
56
57 // Socket authentication function that only allows connections from callers with
58 // the current uid.
59 bool MatchUid(uid_t user_id, gid_t) {
60 bool allowed = user_id == getuid();
61 if (!allowed)
62 HOST_LOG << "Refused socket connection from uid " << user_id;
63 return allowed;
64 }
65
66 // Returns the request data length from the first four data bytes.
67 int GetRequestLength(const char* data) {
68 return ((data[0] & 255) << 24) + ((data[1] & 255) << 16) +
69 ((data[2] & 255) << 8) + (data[3] & 255) + 4;
70 }
71
72 // Returns true if the request data is complete (has at least as many bytes as
73 // indicated by the size in the first four bytes plus four for the first bytes).
74 bool IsRequestComplete(const char* data, int data_len) {
75 if (data_len < 4)
76 return false;
77 return GetRequestLength(data) <= data_len;
78 }
79
80 // Returns true if the request data size is bigger than the threshold.
81 bool IsRequestTooLarge(const char* data, int data_len, int max_len) {
82 if (data_len < 4)
83 return false;
84 return GetRequestLength(data) > max_len;
85 }
86
87 } // namespace
88
89 GnubbyAuthHandlerPosix::GnubbyAuthHandlerPosix(
90 protocol::ClientStub* client_stub)
91 : client_stub_(client_stub), last_connection_id_(0) {
92 DCHECK(client_stub_);
93 }
94
95 GnubbyAuthHandlerPosix::~GnubbyAuthHandlerPosix() {
96 STLDeleteValues(&active_sockets_);
97 }
98
99 // static
100 scoped_ptr<GnubbyAuthHandler> GnubbyAuthHandler::Create(
101 protocol::ClientStub* client_stub) {
102 return scoped_ptr<GnubbyAuthHandler>(new GnubbyAuthHandlerPosix(client_stub));
103 }
104
105 // static
106 void GnubbyAuthHandler::SetGnubbySocketName(
107 const base::FilePath& gnubby_socket_name) {
108 g_gnubby_socket_name.Get() = gnubby_socket_name;
109 }
110
111 void GnubbyAuthHandlerPosix::DeliverClientMessage(const std::string& message) {
112 DCHECK(CalledOnValidThread());
113
114 scoped_ptr<base::Value> value(base::JSONReader::Read(message));
115 base::DictionaryValue* client_message;
116 if (value && value->GetAsDictionary(&client_message)) {
117 std::string type;
118 if (!client_message->GetString(kMessageType, &type)) {
119 LOG(ERROR) << "Invalid gnubby-auth message";
120 return;
121 }
122
123 if (type == kControlMessage) {
124 std::string option;
125 if (client_message->GetString(kControlOption, &option) &&
126 option == kGnubbyAuthV1) {
127 CreateAuthorizationSocket();
128 } else {
129 LOG(ERROR) << "Invalid gnubby-auth control option";
130 }
131 } else if (type == kDataMessage) {
132 int connection_id;
133 std::string json_message;
134 if (client_message->GetInteger(kConnectionId, &connection_id) &&
135 client_message->GetString(kJSONMessage, &json_message)) {
136 ActiveSockets::iterator iter = active_sockets_.find(connection_id);
137 if (iter != active_sockets_.end()) {
138 HOST_LOG << "Sending gnubby response";
139
140 std::string response;
141 GetGnubbyResponseFromJson(json_message, &response);
142 iter->second->Send(response);
143 } else {
144 LOG(ERROR) << "Received gnubby-auth data for unknown connection";
145 }
146 } else {
147 LOG(ERROR) << "Invalid gnubby-auth data message";
148 }
149 } else {
150 LOG(ERROR) << "Unknown gnubby-auth message type: " << type;
151 }
152 }
153 }
154
155 void GnubbyAuthHandlerPosix::DeliverHostDataMessage(int connection_id,
156 const std::string& data)
157 const {
158 DCHECK(CalledOnValidThread());
159
160 base::DictionaryValue request;
161 request.SetString(kMessageType, kDataMessage);
162 request.SetInteger(kConnectionId, connection_id);
163 request.SetString(kJSONMessage, data);
164
165 std::string request_json;
166 if (!base::JSONWriter::Write(&request, &request_json)) {
167 LOG(ERROR) << "Failed to create request json";
168 return;
169 }
170
171 protocol::ExtensionMessage message;
172 message.set_type(kGnubbyAuthMessage);
173 message.set_data(request_json);
174
175 client_stub_->DeliverHostMessage(message);
176 }
177
178 bool GnubbyAuthHandlerPosix::HasActiveSocketForTesting(
179 net::StreamListenSocket* socket) const {
180 return std::find_if(active_sockets_.begin(),
181 active_sockets_.end(),
182 CompareSocket(socket)) != active_sockets_.end();
183 }
184
185 void GnubbyAuthHandlerPosix::DidAccept(
186 net::StreamListenSocket* server,
187 scoped_ptr<net::StreamListenSocket> socket) {
188 DCHECK(CalledOnValidThread());
189
190 active_sockets_[++last_connection_id_] = socket.release();
191 }
192
193 void GnubbyAuthHandlerPosix::DidRead(net::StreamListenSocket* socket,
194 const char* data,
195 int len) {
196 DCHECK(CalledOnValidThread());
197
198 ActiveSockets::iterator socket_iter = std::find_if(
199 active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket));
200 if (socket_iter != active_sockets_.end()) {
201 int connection_id = socket_iter->first;
202
203 ActiveRequests::iterator request_iter =
204 active_requests_.find(connection_id);
205 if (request_iter != active_requests_.end()) {
206 std::vector<char>& saved_vector = request_iter->second;
207 if (IsRequestTooLarge(
208 saved_vector.data(), saved_vector.size(), kMaxRequestLength)) {
209 // We can't close a StreamListenSocket; throw away everything but the
210 // size bytes.
211 saved_vector.resize(4);
212 return;
213 }
214 saved_vector.insert(saved_vector.end(), data, data + len);
215
216 if (IsRequestComplete(saved_vector.data(), saved_vector.size())) {
217 ProcessGnubbyRequest(
218 connection_id, saved_vector.data(), saved_vector.size());
219 active_requests_.erase(request_iter);
220 }
221 } else if (IsRequestComplete(data, len)) {
222 ProcessGnubbyRequest(connection_id, data, len);
223 } else {
224 if (IsRequestTooLarge(data, len, kMaxRequestLength)) {
225 // Only save the size bytes.
226 active_requests_[connection_id] = std::vector<char>(data, data + 4);
227 } else {
228 active_requests_[connection_id] = std::vector<char>(data, data + len);
229 }
230 }
231 }
232 }
233
234 void GnubbyAuthHandlerPosix::DidClose(net::StreamListenSocket* socket) {
235 DCHECK(CalledOnValidThread());
236
237 ActiveSockets::iterator iter = std::find_if(
238 active_sockets_.begin(), active_sockets_.end(), CompareSocket(socket));
239 if (iter != active_sockets_.end()) {
240 active_requests_.erase(iter->first);
241
242 delete iter->second;
243 active_sockets_.erase(iter);
244 }
245 }
246
247 void GnubbyAuthHandlerPosix::CreateAuthorizationSocket() {
248 DCHECK(CalledOnValidThread());
249
250 if (!g_gnubby_socket_name.Get().empty()) {
251 // If the file already exists, a socket in use error is returned.
252 base::DeleteFile(g_gnubby_socket_name.Get(), false);
253
254 HOST_LOG << "Listening for gnubby requests on "
255 << g_gnubby_socket_name.Get().value();
256
257 auth_socket_ = net::UnixDomainSocket::CreateAndListen(
258 g_gnubby_socket_name.Get().value(), this, base::Bind(MatchUid));
259 if (!auth_socket_.get()) {
260 LOG(ERROR) << "Failed to open socket for gnubby requests";
261 }
262 } else {
263 HOST_LOG << "No gnubby socket name specified";
264 }
265 }
266
267 void GnubbyAuthHandlerPosix::ProcessGnubbyRequest(int connection_id,
268 const char* data,
269 int data_len) {
270 std::string json;
271 if (GetJsonFromGnubbyRequest(data, data_len, &json)) {
272 HOST_LOG << "Received gnubby request";
273 DeliverHostDataMessage(connection_id, json);
274 } else {
275 LOG(ERROR) << "Could not decode gnubby request";
276 }
277 }
278
279 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/gnubby_auth_handler_posix.h ('k') | remoting/host/gnubby_auth_handler_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698