5508bc48328760474c68fddf776ec1f62c7aeb06
[platform/core/appfw/rpc-port.git] / src / stub-internal.cc
1 /*
2  * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <aul.h>
18 #include <aul_rpc_port.h>
19 #include <dlog.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22
23 #include <utility>
24 #include <vector>
25
26 #include "aul-internal.hh"
27 #include "debug-port-internal.hh"
28 #include "include/rpc-port.h"
29 #include "log-private.hh"
30 #include "peer-cred-internal.hh"
31 #include "request-internal.hh"
32 #include "response-internal.hh"
33 #include "stub-internal.hh"
34
35 namespace rpc_port {
36 namespace internal {
37 namespace {
38
39 constexpr const char kPortTypeMain[] = "main";
40 constexpr const char kPortTypeDelegate[] = "delegate";
41 constexpr uid_t kRegularUidMin = 5000;
42
43 int ReceiveRequest(ClientSocket* client, Request** request) {
44   size_t size = 0;
45   int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
46   if (ret != 0) {
47     _E("Receive() is failed. error(%d)", ret);
48     return -1;
49   }
50
51   std::vector<uint8_t> buf(size);
52   ret = client->Receive(buf.data(), size);
53   if (ret != 0) {
54     _E("Receive() is failed. error(%d)", ret);
55     return -1;
56   }
57
58   tizen_base::Parcel parcel(buf.data(), buf.size());
59   *request = new (std::nothrow) Request();
60   if (*request == nullptr) {
61     _E("Out of memory");
62     return -1;
63   }
64
65   parcel.ReadParcelable(*request);
66   return 0;
67 }
68
69 int SendResponse(ClientSocket* client, const Response& response) {
70   tizen_base::Parcel parcel;
71   parcel.WriteParcelable(const_cast<Response&>(response));
72   size_t size = parcel.GetDataSize();
73   int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
74   if (ret != 0) {
75     _E("Send() is failed. error(%d)", ret);
76     return -1;
77   }
78
79   ret = client->Send(parcel.GetData(), size);
80   if (ret != 0) {
81     _E("Send() is failed. error(%d)", ret);
82     return -1;
83   }
84
85   return 0;
86 }
87
88 }  // namespace
89
90 Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) {
91   _D("Stub::Stub()");
92 }
93
94 Stub::~Stub() {
95   std::lock_guard<std::recursive_mutex> lock(GetMutex());
96   _D("Stub::~Stub");
97   for (auto& p : ports_) {
98     if (!p->IsDelegate())
99       DebugPort::RemoveSession(p->GetFd());
100   }
101
102   listener_ = nullptr;
103   server_.reset();
104 }
105
106 int Stub::Listen(IEventListener* ev, int fd) {
107   if (ev == nullptr)
108     return RPC_PORT_ERROR_INVALID_PARAMETER;
109
110   if (listener_ != nullptr) {
111     _E("Already listening!");
112     return RPC_PORT_ERROR_INVALID_PARAMETER;
113   }
114
115   std::lock_guard<std::recursive_mutex> lock(GetMutex());
116   listener_ = ev;
117   server_.reset(new Server(fd, this));
118   return server_->Listen();
119 }
120
121 void Stub::Ignore() {
122   std::lock_guard<std::recursive_mutex> lock(GetMutex());
123   listener_ = nullptr;
124 }
125
126 void Stub::AddPrivilege(const std::string& privilege) {
127   std::lock_guard<std::recursive_mutex> lock(GetMutex());
128   access_controller_.AddPrivilege(privilege);
129 }
130
131 void Stub::SetTrusted(const bool trusted) {
132   std::lock_guard<std::recursive_mutex> lock(GetMutex());
133   access_controller_.SetTrusted(trusted);
134 }
135
136 std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
137   std::lock_guard<std::recursive_mutex> lock(GetMutex());
138   for (auto& p : ports_) {
139     if (p->GetInstance() == instance && !p->IsDelegate()) {
140       return p;
141     }
142   }
143
144   return {};
145 }
146
147 std::shared_ptr<Port> Stub::FindDelegatePort(
148     const std::string& instance) const {
149   std::lock_guard<std::recursive_mutex> lock(GetMutex());
150   for (auto& p : ports_) {
151     if (p->GetInstance() == instance && p->IsDelegate()) {
152       return p;
153     }
154   }
155
156   return {};
157 }
158
159 const std::string& Stub::GetPortName() const {
160   return port_name_;
161 }
162
163 void Stub::RemoveAcceptedPorts(std::string instance) {
164   std::lock_guard<std::recursive_mutex> lock(GetMutex());
165   auto iter = ports_.begin();
166   while (iter != ports_.end()) {
167     if ((*iter)->GetInstance().compare(instance) == 0) {
168       LOGI("Close: fd(%d)", (*iter)->GetFd());
169       DebugPort::RemoveSession((*iter)->GetFd());
170       iter = ports_.erase(iter);
171     } else {
172       iter++;
173     }
174   }
175 }
176
177 gboolean Stub::AcceptedPort::OnDataReceived(GIOChannel* channel,
178     GIOCondition cond, gpointer user_data) {
179   auto* stub = static_cast<Stub*>(user_data);
180   std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
181   auto* listener = stub->listener_;
182   if (listener == nullptr) {
183     _E("Invalid context");
184     return G_SOURCE_REMOVE;
185   }
186
187   int fd = g_io_channel_unix_get_fd(channel);
188   for (auto& p : stub->ports_) {
189     if (p->GetFd() == fd && !p->IsDelegate()) {
190       char buffer[4];
191       if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
192         _W("Socket was disconnected from proxy. fd(%d)", fd);
193         listener->OnDisconnected(p->GetId(), p->GetInstance());
194         stub->RemoveAcceptedPorts(p->GetInstance());
195         Aul::NotifyRpcFinished();
196         return G_SOURCE_CONTINUE;
197       }
198
199       int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(),
200           p.get());
201       if (ret != 0) {
202         _W("Invalid protocol");
203         listener->OnDisconnected(p->GetId(), p->GetInstance());
204         stub->RemoveAcceptedPorts(p->GetInstance());
205         Aul::NotifyRpcFinished();
206         return G_SOURCE_CONTINUE;
207       }
208
209       break;
210     }
211   }
212
213   return G_SOURCE_CONTINUE;
214 }
215
216 gboolean Stub::AcceptedPort::OnSocketDisconnected(GIOChannel* channel,
217     GIOCondition cond, gpointer user_data) {
218   auto* stub = static_cast<Stub*>(user_data);
219   std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
220   auto* listener = stub->listener_;
221   if (listener == nullptr) {
222     _E("Invalid context");
223     return G_SOURCE_REMOVE;
224   }
225
226   int fd = g_io_channel_unix_get_fd(channel);
227   _W("Socket was disconnected. fd(%d)", fd);
228   for (auto& p : stub->ports_) {
229     if (p->GetFd() == fd) {
230       listener->OnDisconnected(p->GetId(), p->GetInstance());
231       stub->RemoveAcceptedPorts(p->GetInstance());
232       Aul::NotifyRpcFinished();
233       break;
234     }
235   }
236
237   return G_SOURCE_REMOVE;
238 }
239
240 void Stub::AddAcceptedPort(const std::string& sender_appid,
241     const std::string& instance, const std::string& port_type, int fd) {
242   std::lock_guard<std::recursive_mutex> lock(GetMutex());
243   if (port_type == kPortTypeMain) {
244     auto* main_port = new AcceptedPort(this, false, fd, sender_appid,
245         instance, true);
246     ports_.emplace_back(main_port);
247     return;
248   }
249
250   auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid,
251       instance, false);
252   ports_.emplace_back(delegate_port);
253
254   int main_fd = -1;
255   for (auto& p : ports_) {
256     if (p->GetId() == delegate_port->GetId() &&
257         p->GetInstance() == delegate_port->GetInstance() &&
258         p->GetFd() != delegate_port->GetFd()) {
259       main_fd = p->GetFd();
260       break;
261     }
262   }
263
264   _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)",
265       sender_appid.c_str(), instance.c_str(), main_fd, fd);
266   DebugPort::AddSession(port_name_, sender_appid, main_fd, fd);
267   listener_->OnConnected(sender_appid, instance);
268 }
269
270 std::recursive_mutex& Stub::GetMutex() const {
271   return mutex_;
272 }
273
274 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
275     std::string id, std::string inst, bool watch)
276     : Port(fd, std::move(id), std::move(inst)), parent_(parent),
277       is_delegate_(isDelegate) {
278   Watch(watch);
279 }
280
281 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
282     std::string id, bool watch)
283     : Port(fd, std::move(id)), parent_(parent),
284       is_delegate_(isDelegate) {
285   Watch(watch);
286 }
287
288 Stub::AcceptedPort::~AcceptedPort() {
289   if (disconn_source_ > 0)
290     g_source_remove(disconn_source_);
291
292   if (source_ > 0)
293     g_source_remove(source_);
294
295   if (channel_ != nullptr)
296     g_io_channel_unref(channel_);
297 }
298
299 int Stub::AcceptedPort::Watch(bool receive) {
300   channel_ = g_io_channel_unix_new(GetFd());
301   if (channel_ == nullptr) {
302     _E("g_io_channel_unix_new() is failed");
303     return -1;
304   }
305
306   disconn_source_ = g_io_add_watch(channel_,
307       static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
308       OnSocketDisconnected, parent_);
309   if (disconn_source_ == 0) {
310     _E("g_io_add_watch() is failed");
311     return -1;
312   }
313
314   if (!receive)
315     return 0;
316
317   source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
318       OnDataReceived, parent_);
319   if (source_ == 0) {
320     _E("g_io_add_watch() is failed");
321     return -1;
322   }
323
324   return 0;
325 }
326
327 Stub::Server::Server(int fd, Stub* parent)
328     : ServerSocket(fd),
329       parent_(parent) {
330 }
331
332 Stub::Server::~Server() {
333   if (channel_)
334     g_io_channel_unref(channel_);
335
336   if (source_ > 0)
337     g_source_remove(source_);
338 }
339
340 int Stub::Server::Listen() {
341   channel_ = g_io_channel_unix_new(GetFd());
342   if (channel_ == nullptr) {
343     _E("g_io_channel_unix_new() is failed");
344     return -1;
345   }
346
347   source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
348       OnRequestReceived, parent_);
349   if (source_ == 0) {
350     _E("g_io_add_watch() is failed");
351     return -1;
352   }
353
354   return 0;
355 }
356
357 gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond,
358     gpointer user_data) {
359   auto* stub = static_cast<Stub*>(user_data);
360   std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
361   if (stub->listener_ == nullptr) {
362     _E("Invalid context");
363     return G_SOURCE_REMOVE;
364   }
365
366   std::unique_ptr<ClientSocket> client(stub->server_->Accept());
367   if (client.get() == nullptr) {
368     _E("Out of memory");
369     return G_SOURCE_CONTINUE;
370   }
371
372   Request* request = nullptr;
373   int ret = ReceiveRequest(client.get(), &request);
374   if (ret != 0)
375     return G_SOURCE_CONTINUE;
376
377   std::unique_ptr<Request> request_auto(request);
378   std::unique_ptr<PeerCred> cred(PeerCred::Get(client->GetFd()));
379   if (cred.get() == nullptr) {
380     _E("Failed to create peer credentials");
381     return G_SOURCE_CONTINUE;
382   }
383
384   std::string app_id = Aul::GetAppId(cred->GetPid());
385   int res;
386   if (cred->GetUid() >= kRegularUidMin) {
387     if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) {
388       _E("Reject request. %u:%u", cred->GetUid(), getuid());
389       res = -1;
390     } else {
391       res = stub->access_controller_.Check(client->GetFd(), app_id);
392     }
393   } else {
394     _W("Bypass access control. pid(%d), uid(%u)",
395         cred->GetPid(), cred->GetUid());
396     res = 0;
397   }
398
399   Response response(res);
400   ret = SendResponse(client.get(), response);
401   if (ret != 0)
402     return G_SOURCE_CONTINUE;
403
404   if (res != 0) {
405     _E("Access denied. fd(%d), pid(%d)", client->GetFd(), cred->GetPid());
406     return G_SOURCE_CONTINUE;
407   }
408
409   client->SetNonblock();
410   int client_fd = client->RemoveFd();
411   stub->AddAcceptedPort(app_id, request->GetInstance(), request->GetPortType(),
412       client_fd);
413   return G_SOURCE_CONTINUE;
414 }
415
416 }  // namespace internal
417 }  // namespace rpc_port