Implement setting process label for the given application
[platform/core/security/security-manager.git] / src / server / service / installer.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18 /*
19  * @file        installer.cpp
20  * @author      Michal Witanowski <m.witanowski@samsung.com>
21  * @author      Jacek Bukarewicz <j.bukarewicz@samsung.com>
22  * @author      Rafal Krypa <r.krypa@samsung.com>
23  * @brief       Implementation of installer service.
24  */
25
26 #include <dpl/log/log.h>
27 #include <dpl/serialization.h>
28
29 #include <privilege-control.h>
30
31 #include "installer.h"
32 #include "protocols.h"
33 #include "security-manager.h"
34 #include "smack-common.h"
35 #include "smack-rules.h"
36 #include "smack-labels.h"
37 #include "privilege_db.h"
38
39 namespace SecurityManager {
40
41 const InterfaceID INSTALLER_IFACE = 0;
42
43
44 InstallerService::InstallerService()
45 {
46 }
47
48 GenericSocketService::ServiceDescriptionVector InstallerService::GetServiceDescription()
49 {
50     return ServiceDescriptionVector {
51         {SERVICE_SOCKET_INSTALLER, "security-manager::installer", INSTALLER_IFACE},
52     };
53 }
54
55 void InstallerService::accept(const AcceptEvent &event)
56 {
57     LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock <<
58              " ConnectionID.counter: " << event.connectionID.counter <<
59              " ServiceID: " << event.interfaceID);
60
61     auto &info = m_connectionInfoMap[event.connectionID.counter];
62     info.interfaceID = event.interfaceID;
63 }
64
65 void InstallerService::write(const WriteEvent &event)
66 {
67     LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
68              " Size: " << event.size <<
69              " Left: " << event.left);
70
71     if (event.left == 0)
72         m_serviceManager->Close(event.connectionID);
73 }
74
75 void InstallerService::process(const ReadEvent &event)
76 {
77     LogDebug("Read event for counter: " << event.connectionID.counter);
78     auto &info = m_connectionInfoMap[event.connectionID.counter];
79     info.buffer.Push(event.rawBuffer);
80
81     // We can get several requests in one package.
82     // Extract and process them all
83     while (processOne(event.connectionID, info.buffer, info.interfaceID));
84 }
85
86 void InstallerService::close(const CloseEvent &event)
87 {
88     LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
89     m_connectionInfoMap.erase(event.connectionID.counter);
90 }
91
92 bool InstallerService::processOne(const ConnectionID &conn, MessageBuffer &buffer,
93                                   InterfaceID interfaceID)
94 {
95     LogDebug("Iteration begin. Interface = " << interfaceID);
96
97     //waiting for all data
98     if (!buffer.Ready()) {
99         return false;
100     }
101
102     MessageBuffer send;
103     bool retval = false;
104
105     if (INSTALLER_IFACE == interfaceID) {
106         Try {
107             // deserialize API call type
108             int call_type_int;
109             Deserialization::Deserialize(buffer, call_type_int);
110             SecurityModuleCall call_type = static_cast<SecurityModuleCall>(call_type_int);
111
112             switch (call_type) {
113                 case SecurityModuleCall::APP_INSTALL:
114                     processAppInstall(buffer, send);
115                     break;
116                 case SecurityModuleCall::APP_UNINSTALL:
117                     processAppUninstall(buffer, send);
118                     break;
119                 case SecurityModuleCall::APP_GET_PKGID:
120                     processGetPkgId(buffer, send);
121                     break;
122                 default:
123                     LogError("Invalid call: " << call_type_int);
124                     Throw(InstallerException::InvalidAction);
125             }
126             // if we reach this point, the protocol is OK
127             retval = true;
128         } Catch (MessageBuffer::Exception::Base) {
129             LogError("Broken protocol.");
130         } Catch (InstallerException::Base) {
131             LogError("Broken protocol.");
132         } catch (std::exception &e) {
133             LogError("STD exception " << e.what());
134         } catch (...) {
135             LogError("Unknown exception");
136         }
137     }
138     else {
139         LogError("Wrong interface");
140     }
141
142     if (retval) {
143         //send response
144         m_serviceManager->Write(conn, send.Pop());
145     } else {
146         LogError("Closing socket because of error");
147         m_serviceManager->Close(conn);
148     }
149
150     return retval;
151 }
152
153 bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &send)
154 {
155     bool pkgIdIsNew = false;
156     std::vector<std::string> addedPermissions;
157     std::vector<std::string> removedPermissions;
158
159     // deserialize request data
160     app_inst_req req;
161     Deserialization::Deserialize(buffer, req.appId);
162     Deserialization::Deserialize(buffer, req.pkgId);
163     Deserialization::Deserialize(buffer, req.privileges);
164     Deserialization::Deserialize(buffer, req.appPaths);
165
166     LogDebug("appId: " << req.appId);
167     LogDebug("pkgId: " << req.pkgId);
168
169     std::string smackLabel;
170     if (!generateAppLabel(req.pkgId, smackLabel)) {
171         LogError("Cannot generate Smack label for package");
172         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
173         return false;
174     }
175     LogDebug("Smack label: " << smackLabel);
176
177     // create null terminated array of strigns for permissions
178     std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
179     for (size_t i = 0; i < req.privileges.size(); ++i) {
180         LogDebug("Permission = " << req.privileges[i]);
181         pp_permissions[i] = req.privileges[i].c_str();
182     }
183     pp_permissions[req.privileges.size()] = nullptr;
184
185     // start database transaction
186     int result = perm_begin();
187     LogDebug("perm_begin() returned " << result);
188     if (PC_OPERATION_SUCCESS != result) {
189         // libprivilege is locked
190         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
191         return false;
192     }
193
194     result = perm_app_install(smackLabel.c_str());
195     LogDebug("perm_app_install() returned " << result);
196     if (PC_OPERATION_SUCCESS != result) {
197         // libprivilege error
198         goto error_label;
199     }
200
201     result = perm_app_enable_permissions(smackLabel.c_str(), APP_TYPE_WGT,
202                                          pp_permissions.get(), true);
203     LogDebug("perm_app_enable_permissions() returned " << result);
204     if (PC_OPERATION_SUCCESS != result) {
205         // libprivilege error
206         goto error_label;
207     }
208
209     try {
210         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
211
212         m_privilegeDb.BeginTransaction();
213         m_privilegeDb.GetPkgPrivileges(req.pkgId, oldPkgPrivileges);
214         m_privilegeDb.AddApplication(req.appId, req.pkgId, pkgIdIsNew);
215         m_privilegeDb.UpdateAppPrivileges(req.appId, req.privileges);
216         m_privilegeDb.GetPkgPrivileges(req.pkgId, newPkgPrivileges);
217         // TODO: configure Cynara rules based on oldPkgPrivileges and newPkgPrivileges
218         m_privilegeDb.CommitTransaction();
219         LogDebug("Application installation commited to database");
220     } catch (const PrivilegeDb::Exception::InternalError &e) {
221         m_privilegeDb.RollbackTransaction();
222         LogError("Error while saving application info to database: " << e.DumpToString());
223         goto error_label;
224     }
225
226     // register paths
227     for (const auto &appPath : req.appPaths) {
228         const std::string &path = appPath.first;
229         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
230         result = setupPath(req.pkgId, path, pathType);
231
232         if (!result) {
233             LogDebug("setupPath() failed ");
234             goto error_label;
235         }
236     }
237
238     if (pkgIdIsNew) {
239         LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
240         if (!SmackRules::installPackageRules(req.pkgId)) {
241             LogError("Failed to apply package-specific smack rules");
242             goto error_label;
243         }
244     }
245
246     // finish database transaction
247     result = perm_end();
248     LogDebug("perm_end() returned " << result);
249     if (PC_OPERATION_SUCCESS != result) {
250         if (pkgIdIsNew)
251             if (!SmackRules::uninstallPackageRules(req.pkgId))
252                 LogWarning("Failed to rollback package-specific smack rules");
253
254         // error in libprivilege-control
255         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
256         return false;
257     }
258
259     // success
260     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
261     return true;
262
263 error_label:
264     // rollback failed transaction before exiting
265     result = perm_rollback();
266     LogDebug("perm_rollback() returned " << result);
267     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
268     return false;
269 }
270
271 bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send)
272 {
273     // deserialize request data
274     std::string appId;
275     std::string pkgId;
276     std::string smackLabel;
277     bool appExists = true;
278     bool removePkg = false;
279
280     Deserialization::Deserialize(buffer, appId);
281     LogDebug("appId: " << appId);
282
283     int result = perm_begin();
284     LogDebug("perm_begin() returned " << result);
285     if (PC_OPERATION_SUCCESS != result) {
286         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
287         return false;
288     }
289
290     try {
291         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
292
293         m_privilegeDb.BeginTransaction();
294         if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
295             LogWarning("Application " << appId <<
296                 " not found in database while uninstalling");
297             m_privilegeDb.RollbackTransaction();
298             appExists = false;
299         } else {
300             LogDebug("pkgId: " << pkgId);
301
302             if (!generateAppLabel(pkgId, smackLabel)) {
303                 LogError("Cannot generate Smack label for package");
304                 goto error_label;
305             }
306             LogDebug("Smack label: " << smackLabel);
307
308             m_privilegeDb.GetPkgPrivileges(pkgId, oldPkgPrivileges);
309             m_privilegeDb.UpdateAppPrivileges(appId, std::vector<std::string>());
310             m_privilegeDb.RemoveApplication(appId, removePkg);
311             m_privilegeDb.GetPkgPrivileges(pkgId, newPkgPrivileges);
312             // TODO: configure Cynara rules based on oldPkgPrivileges and newPkgPrivileges
313             m_privilegeDb.CommitTransaction();
314             LogDebug("Application uninstallation commited to database");
315         }
316     } catch (const PrivilegeDb::Exception::InternalError &e) {
317         m_privilegeDb.RollbackTransaction();
318         LogError("Error while removing application info from database: " << e.DumpToString());
319         goto error_label;
320     }
321
322     if (appExists) {
323         result = perm_app_uninstall(smackLabel.c_str());
324         LogDebug("perm_app_uninstall() returned " << result);
325         if (PC_OPERATION_SUCCESS != result) {
326             // error in libprivilege-control
327             goto error_label;
328         }
329
330         if (removePkg) {
331             LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
332             if (!SmackRules::uninstallPackageRules(pkgId)) {
333                 LogError("Error on uninstallation of package-specific smack rules");
334                 goto error_label;
335             }
336         }
337     }
338
339     // finish database transaction
340     result = perm_end();
341     LogDebug("perm_end() returned " << result);
342     if (PC_OPERATION_SUCCESS != result) {
343         // error in libprivilege-control
344         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
345         return false;
346     }
347
348     // success
349     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
350     return true;
351
352 error_label:
353     // rollback failed transaction before exiting
354     result = perm_rollback();
355     LogDebug("perm_rollback() returned " << result);
356     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
357     return false;
358 }
359
360 bool InstallerService::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
361 {
362     // deserialize request data
363     std::string appId;
364     std::string pkgId;
365
366     Deserialization::Deserialize(buffer, appId);
367     LogDebug("appId: " << appId);
368
369     try {
370         if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
371             LogWarning("Application " << appId << " not found in database");
372             Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
373             return false;
374         } else {
375             LogDebug("pkgId: " << pkgId);
376         }
377     } catch (const PrivilegeDb::Exception::InternalError &e) {
378         LogError("Error while getting pkgId from database: " << e.DumpToString());
379         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
380         return false;
381     }
382
383      // success
384     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
385     Serialization::Serialize(send, pkgId);
386     return true;
387 }
388
389 } // namespace SecurityManager