Add CynaraThread
[platform/core/appfw/rpc-port.git] / src / ac-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 <cynara-creds-socket.h>
19 #include <cynara-error.h>
20 #include <dlog.h>
21 #include <pkgmgr-info.h>
22
23 #include <utility>
24
25 #include "ac-internal.hh"
26 #include "aul-internal.hh"
27 #include "log-private.hh"
28 #include "cynara_thread.hh"
29
30 namespace rpc_port {
31 namespace internal {
32 namespace {
33
34 constexpr const uid_t kRegularUidMin = 5000;
35
36 }  // namespace
37
38 void AccessController::AddPrivilege(std::string privilege) {
39   privileges_.push_back(std::move(privilege));
40 }
41
42 void AccessController::SetTrusted(const bool trusted) {
43   trusted_ = trusted;
44 }
45
46 int AccessController::CheckPrivilege(const Cynara& c) {
47   for (auto& privilege : privileges_) {
48     if (c.Check(privilege) != 0) {
49       return -1;
50     }
51   }
52
53   return 0;
54 }
55
56 int AccessController::CheckTrusted(const std::string& sender_appid) {
57   if (getuid() < kRegularUidMin)
58     return 0;
59
60   if (appid_.empty())
61     appid_ = Aul::GetAppId(getpid());
62
63   _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid.c_str());
64   pkgmgrinfo_cert_compare_result_type_e res;
65   int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(appid_.c_str(),
66       sender_appid.c_str(), getuid(), &res);
67   if (ret < 0) {
68     _E("CheckCertificate() Failed");
69     return -1;
70   }
71   if (res != PMINFO_CERT_COMPARE_MATCH) {
72     _E("CheckCertificate() Failed : Certificate Not Matched");
73     return -1;
74   }
75
76   return 0;
77 }
78
79 int AccessController::Check(int fd, const std::string& sender_appid) {
80   Cynara cynara;
81   int ret = cynara.FetchCredsFromSocket(fd);
82   if (ret != 0)
83     return -1;
84
85   if (!privileges_.empty()) {
86     ret = CheckPrivilege(cynara);
87     if (ret != 0)
88       return ret;
89   }
90
91   if (trusted_)
92     ret = CheckTrusted(sender_appid);
93
94   return ret;
95 }
96
97 void AccessController::CheckAsync(int fd, std::string sender_appid,
98     CompleteCallback callback) {
99   Job job([=]() -> Job::Type {
100     int res = Check(fd, sender_appid);
101     auto* cbdata = new std::pair<CompleteCallback, int>(callback, res);
102     if (callback != nullptr) {
103       g_idle_add(
104           [](gpointer data) -> gboolean {
105             auto* cbdata = static_cast<std::pair<CompleteCallback, int>*>(data);
106             auto [callback, res] = *cbdata;
107             callback(res);
108             delete (cbdata);
109             return G_SOURCE_REMOVE;
110           }, cbdata);
111     }
112
113     return Job::Type::Continue;
114   });
115
116   CynaraThread::GetInst().Push(std::move(job));
117 }
118
119 AccessController::Cynara::Cynara()
120     : cynara_(nullptr, cynara_finish), client_(nullptr, std::free),
121     user_(nullptr, std::free) {
122   cynara* cynara_inst = nullptr;
123
124   if (cynara_initialize(&cynara_inst, NULL) != CYNARA_API_SUCCESS) {
125     _E("cynara_initialize() is failed");  // LCOV_EXL_LINE
126   } else {
127     cynara_.reset(cynara_inst);
128   }
129 }
130
131 AccessController::Cynara::~Cynara() = default;
132
133 int AccessController::Cynara::FetchCredsFromSocket(int fd) {
134   char* user = nullptr;
135   int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user);
136   if (ret != CYNARA_API_SUCCESS) {
137     char buf[128] = { 0, };
138     cynara_strerror(ret, buf, sizeof(buf));
139     _E("cynara_creds_socket_get_user() is failed. fd(%d), error(%d:%s)",
140         fd, ret, buf);
141     return -1;
142   }
143   user_.reset(user);
144
145   char* client = nullptr;
146   ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client);
147   if (ret != CYNARA_API_SUCCESS) {
148     char buf[128] = { 0, };
149     cynara_strerror(ret, buf, sizeof(buf));
150     _E("cynara_creds_socket_get_client() is failed. fd(%d), error(%d:%s)",
151         fd, ret, buf);
152     return -1;
153   }
154   client_.reset(client);
155
156   _D("Cred client(%s), user(%s)", client_.get(), user_.get());
157   return 0;
158 }
159
160 int AccessController::Cynara::Check(const std::string& privilege) const {
161   _D("check privilege %s", privilege.c_str());
162   if (cynara_check(cynara_.get(), client_.get(), "", user_.get(),
163       privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) {
164     _E("cynara_check() is not allowed : %s", privilege.c_str());
165     return -1;
166   }
167
168   return 0;
169 }
170
171 }  // namespace internal
172 }  // namespace rpc_port