7f21f8f9f647a0230bbef31ab753df87c0d6de47
[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 // LCOV_EXCL_START
57 int AccessController::CheckTrusted(const std::string& sender_appid) {
58   if (getuid() < kRegularUidMin)
59     return 0;
60
61   if (appid_.empty())
62     appid_ = Aul::GetAppId(getpid());
63
64   _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid.c_str());
65   pkgmgrinfo_cert_compare_result_type_e res;
66   int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(appid_.c_str(),
67       sender_appid.c_str(), getuid(), &res);
68   if (ret < 0) {
69     _E("CheckCertificate() Failed");
70     return -1;
71   }
72   if (res != PMINFO_CERT_COMPARE_MATCH) {
73     _E("CheckCertificate() Failed : Certificate Not Matched");
74     return -1;
75   }
76
77   return 0;
78 }
79 // LCOV_EXCL_STOP
80
81 int AccessController::Check(int fd, const std::string& sender_appid) {
82   Cynara cynara;
83   int ret = cynara.FetchCredsFromSocket(fd);
84   if (ret != 0)
85     return -1;
86
87   if (!privileges_.empty()) {
88     ret = CheckPrivilege(cynara);
89     if (ret != 0)
90       return ret;
91   }
92
93   if (trusted_)
94     ret = CheckTrusted(sender_appid);
95
96   return ret;
97 }
98
99 void AccessController::CheckAsync(int fd, std::string sender_appid,
100     CompleteCallback callback) {
101   /* This is for handle freed issue */
102   auto tmp_handle = new std::shared_ptr<AccessController>(shared_from_this());
103   Job job([=]() -> Job::Type {
104     if ((*tmp_handle).use_count() == 1) {
105       delete tmp_handle;  // LCOV_EXCL_LINE
106       return Job::Type::Continue;  // LCOV_EXCL_LINE
107     }
108
109     int res = Check(fd, sender_appid);
110     auto* cbdata = new std::pair<CompleteCallback, int>(
111         std::move(callback), res);
112     guint sid = g_idle_add(
113         [](gpointer data) -> gboolean {
114           auto* cb_data = static_cast<std::pair<CompleteCallback, int>*>(data);
115           auto [callback, res] = *cb_data;
116           callback(res);
117           delete cb_data;
118           return G_SOURCE_REMOVE;
119         }, cbdata);
120     if (sid == 0) {
121       _E("Failed to call g_idle_add");  // LCOV_EXCL_LINE
122       delete cbdata;  // LCOV_EXCL_LINE
123     }
124
125     delete tmp_handle;
126     return Job::Type::Continue;
127   });
128
129   CynaraThread::GetInst().Push(std::move(job));
130 }
131
132 AccessController::Cynara::Cynara()
133     : cynara_(nullptr, cynara_finish), client_(nullptr, std::free),
134     user_(nullptr, std::free) {
135   cynara* cynara_inst = nullptr;
136
137   if (cynara_initialize(&cynara_inst, NULL) != CYNARA_API_SUCCESS) {
138     _E("cynara_initialize() is failed");  // LCOV_EXCL_LINE
139   } else {
140     cynara_.reset(cynara_inst);
141   }
142 }
143
144 AccessController::Cynara::~Cynara() = default;
145
146 int AccessController::Cynara::FetchCredsFromSocket(int fd) {
147   char* user = nullptr;
148   int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user);
149   if (ret != CYNARA_API_SUCCESS) {
150     // LCOV_EXCL_START
151     char buf[128] = { 0, };
152     cynara_strerror(ret, buf, sizeof(buf));
153     _E("cynara_creds_socket_get_user() is failed. fd(%d), error(%d:%s)",
154         fd, ret, buf);
155     return -1;
156     // LCOV_EXCL_STOP
157   }
158   user_.reset(user);
159
160   char* client = nullptr;
161   ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client);
162   if (ret != CYNARA_API_SUCCESS) {
163     // LCOV_EXCL_START
164     char buf[128] = { 0, };
165     cynara_strerror(ret, buf, sizeof(buf));
166     _E("cynara_creds_socket_get_client() is failed. fd(%d), error(%d:%s)",
167         fd, ret, buf);
168     return -1;
169     // LCOV_EXCL_STOP
170   }
171   client_.reset(client);
172
173   _W("Cred client(%s), user(%s), fd(%d)", client_.get(), user_.get(), fd);
174   return 0;
175 }
176
177 // LCOV_EXCL_START
178 int AccessController::Cynara::Check(const std::string& privilege) const {
179   _D("check privilege %s", privilege.c_str());
180   if (cynara_check(cynara_.get(), client_.get(), "", user_.get(),
181       privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) {
182     _E("cynara_check() is not allowed : %s", privilege.c_str());
183     return -1;
184   }
185
186   return 0;
187 }
188 // LCOV_EXCL_STOP
189
190 }  // namespace internal
191 }  // namespace rpc_port