7fdc5883959e2763d47fa4438c2215ffb5599c3f
[platform/core/appfw/pkgmgr-info.git] / src / server / cynara_checker / cynara_checker.cc
1 /*
2  * Copyright (c) 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 "cynara_checker.hh"
18
19 #include <cynara-creds-socket.h>
20 #include <cynara-session.h>
21 #include <dlog.h>
22 #include <glib-unix.h>
23
24 #include <cstdlib>
25 #include <memory>
26 #include <mutex>
27
28 #include "utils/logging.hh"
29
30 #include "pkgmgrinfo_private.h"
31
32 namespace pkgmgr_server {
33
34 void CynaraChecker::Init() {
35   cynara_async_initialize(&cynara_, nullptr, StatusCb, nullptr);
36 }
37
38 void CynaraChecker::Fini() {
39   if (cynara_sid_)
40     g_source_remove(cynara_sid_);
41
42   if (cynara_ != nullptr)
43     cynara_async_finish(cynara_);
44 }
45
46 CynaraChecker& CynaraChecker::GetInst() {
47   static CynaraChecker inst;
48   return inst;
49 }
50
51 void CynaraChecker::ReplyCb(cynara_check_id id, cynara_async_call_cause cause,
52     int resp, void* data) {
53   auto runner = static_cast<Runner*>(data);
54   auto& inst = CynaraChecker::GetInst();
55   switch (cause) {
56   case CYNARA_CALL_CAUSE_ANSWER: {
57     if (resp != CYNARA_API_ACCESS_ALLOWED)
58       break;
59
60     auto it = inst.cynara_id_map_.find(id);
61     if (it == inst.cynara_id_map_.end()) {
62       LOG(ERROR) << "Invalid request";
63       break;
64     }
65
66     LOG(DEBUG) << "Allowed request";
67     runner->QueueRequest(it->second);
68     inst.cynara_id_map_.erase(it);
69
70     break;
71   }
72   case CYNARA_CALL_CAUSE_CANCEL:
73   case CYNARA_CALL_CAUSE_FINISH:
74   case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
75   default:
76     LOG(ERROR) << "Cynara: resp: not answer";
77     break;
78   }
79 }
80
81 gboolean CynaraChecker::ProcessCb(gint fd, GIOCondition cond, gpointer data) {
82   auto& inst = CynaraChecker::GetInst();
83   if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
84     inst.cynara_sid_ = 0;
85     return G_SOURCE_REMOVE;
86   }
87
88   int ret = cynara_async_process(inst.cynara_);
89   if (ret != CYNARA_API_SUCCESS)
90     LOG(ERROR) << "process error " << ret;
91
92   return G_SOURCE_CONTINUE;
93 }
94
95 void CynaraChecker::StatusCb(int old_fd, int new_fd,
96     cynara_async_status status, void* data) {
97   auto& inst = CynaraChecker::GetInst();
98   if (old_fd != -1) {
99     if (inst.cynara_sid_) {
100       g_source_remove(inst.cynara_sid_);
101       inst.cynara_sid_ = 0;
102     }
103   }
104
105   if (new_fd != -1) {
106     auto cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
107     if (status == CYNARA_STATUS_FOR_RW)
108       cond |= G_IO_OUT;
109
110     inst.cynara_sid_ = g_unix_fd_add(new_fd, static_cast<GIOCondition>(cond),
111         ProcessCb, data);
112   }
113 }
114
115 void CynaraChecker::CheckPrivilege(Runner* runner,
116     const std::shared_ptr<PkgRequest>& req,
117     const std::vector<std::string>& privileges) {
118   if (privileges.empty() || req->GetSenderUID() < REGULAR_USER) {
119     LOG(DEBUG) << "Allowed request";
120     runner->QueueRequest(req);
121     return;
122   }
123
124   int ret;
125   if (cynara_ == nullptr) {
126     ret = cynara_async_initialize(&cynara_, nullptr, StatusCb, nullptr);
127     if (ret != CYNARA_API_SUCCESS) {
128       LOG(ERROR) << "Failed to initialize cynara_";
129       return;
130     }
131   }
132
133   char* smack_label;
134   ret = cynara_creds_socket_get_client(req->GetFd(), CLIENT_METHOD_SMACK,
135       &smack_label);
136   if (ret != CYNARA_API_SUCCESS) {
137     LOG(ERROR) << "Failed to get smack label";
138     return;
139   }
140
141   std::unique_ptr<char, decltype(std::free)*> lblPtr(smack_label, std::free);
142   char* session = cynara_session_from_pid(req->GetSenderPID());
143   if (session == nullptr) {
144     LOG(ERROR) << "Failed to get client session for pid:"
145         << req->GetSenderPID();
146     return;
147   }
148
149   std::unique_ptr<char, decltype(std::free)*> sessPtr(session, std::free);
150   cynara_check_id id;
151   bool check = false;
152   for (auto& priv : privileges) {
153     ret = cynara_async_create_request(cynara_, smack_label, session,
154         std::to_string(req->GetSenderUID()).c_str(), priv.c_str(),
155         &id, ReplyCb, runner);
156     if (check == false) {
157       cynara_id_map_[id] = req;
158       check = true;
159     }
160   }
161 }
162
163 }  // namespace pkgmgr_server