Fix Cynara policy setting, use Smack label as app identifier
[platform/core/security/security-manager.git] / src / server / service / service.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        service.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 security-manager service.
24  */
25
26 #include <dpl/log/log.h>
27 #include <dpl/serialization.h>
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <pwd.h>
32 #include <limits.h>
33 #include <cstring>
34
35 #include "service.h"
36 #include "protocols.h"
37 #include "security-manager.h"
38 #include "smack-common.h"
39 #include "smack-rules.h"
40 #include "smack-labels.h"
41 #include "privilege_db.h"
42 #include "cynara.h"
43
44 namespace SecurityManager {
45
46 const InterfaceID IFACE = 1;
47
48
49 Service::Service()
50 {
51 }
52
53 GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription()
54 {
55     return ServiceDescriptionVector {
56         {SERVICE_SOCKET, "security-manager", IFACE},
57     };
58 }
59
60 void Service::accept(const AcceptEvent &event)
61 {
62     LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock <<
63              " ConnectionID.counter: " << event.connectionID.counter <<
64              " ServiceID: " << event.interfaceID);
65
66     auto &info = m_connectionInfoMap[event.connectionID.counter];
67     info.interfaceID = event.interfaceID;
68 }
69
70 void Service::write(const WriteEvent &event)
71 {
72     LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
73              " Size: " << event.size <<
74              " Left: " << event.left);
75
76     if (event.left == 0)
77         m_serviceManager->Close(event.connectionID);
78 }
79
80 void Service::process(const ReadEvent &event)
81 {
82     LogDebug("Read event for counter: " << event.connectionID.counter);
83     auto &info = m_connectionInfoMap[event.connectionID.counter];
84     info.buffer.Push(event.rawBuffer);
85
86     // We can get several requests in one package.
87     // Extract and process them all
88     while (processOne(event.connectionID, info.buffer, info.interfaceID));
89 }
90
91 void Service::close(const CloseEvent &event)
92 {
93     LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
94     m_connectionInfoMap.erase(event.connectionID.counter);
95 }
96
97 static bool getPeerUserID(int sock, uid_t *uid) {
98     struct ucred cr;
99     socklen_t len = sizeof (cr);
100     if (!uid) {
101         return false;
102     }
103     if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
104         *uid = cr.uid;
105         return true;
106     }
107     return false;
108 }
109
110 bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
111                                   InterfaceID interfaceID)
112 {
113     LogDebug("Iteration begin. Interface = " << interfaceID);
114
115     //waiting for all data
116     if (!buffer.Ready()) {
117         return false;
118     }
119
120     MessageBuffer send;
121     bool retval = false;
122
123     uid_t uid;
124
125     if(!getPeerUserID(conn.sock, &uid)) {
126         LogError("Closing socket because of error: unable to get peer's uid");
127         m_serviceManager->Close(conn);
128         return false;
129     }
130
131     if (IFACE == interfaceID) {
132         Try {
133             // deserialize API call type
134             int call_type_int;
135             Deserialization::Deserialize(buffer, call_type_int);
136             SecurityModuleCall call_type = static_cast<SecurityModuleCall>(call_type_int);
137
138             switch (call_type) {
139                 case SecurityModuleCall::APP_INSTALL:
140                     LogDebug("call_type: SecurityModuleCall::APP_INSTALL");
141                     processAppInstall(buffer, send, uid);
142                     break;
143                 case SecurityModuleCall::APP_UNINSTALL:
144                     LogDebug("call_type: SecurityModuleCall::APP_UNINSTALL");
145                     processAppUninstall(buffer, send, uid);
146                     break;
147                 case SecurityModuleCall::APP_GET_PKGID:
148                     processGetPkgId(buffer, send);
149                     break;
150                 default:
151                     LogError("Invalid call: " << call_type_int);
152                     Throw(ServiceException::InvalidAction);
153             }
154             // if we reach this point, the protocol is OK
155             retval = true;
156         } Catch (MessageBuffer::Exception::Base) {
157             LogError("Broken protocol.");
158         } Catch (ServiceException::Base) {
159             LogError("Broken protocol.");
160         } catch (std::exception &e) {
161             LogError("STD exception " << e.what());
162         } catch (...) {
163             LogError("Unknown exception");
164         }
165     }
166     else {
167         LogError("Wrong interface");
168     }
169
170     if (retval) {
171         //send response
172         m_serviceManager->Write(conn, send.Pop());
173     } else {
174         LogError("Closing socket because of error");
175         m_serviceManager->Close(conn);
176     }
177
178     return retval;
179 }
180
181 static inline bool isSubDir(const char *parent, const char *subdir)
182 {
183     while (*parent && *subdir)
184         if (*parent++ != *subdir++)
185             return false;
186
187     return (*subdir == '/');
188 }
189
190 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
191 {
192     if (uid == 0)
193         return true;
194
195     struct passwd *pwd;
196     do {
197         errno = 0;
198         pwd = getpwuid(uid);
199         if (!pwd && errno != EINTR) {
200             LogError("getpwuid failed with '" << uid
201                     << "' as paramter: " << strerror(errno));
202             return false;
203         }
204     } while (!pwd);
205
206     std::unique_ptr<char, std::function<void(void*)>> home(
207         realpath(pwd->pw_dir, NULL), free);
208     if (!home.get()) {
209             LogError("realpath failed with '" << pwd->pw_dir
210                     << "' as paramter: " << strerror(errno));
211             return false;
212     }
213
214     for (const auto &appPath : req.appPaths) {
215         std::unique_ptr<char, std::function<void(void*)>> real_path(
216             realpath(appPath.first.c_str(), NULL), free);
217         if (!real_path.get()) {
218             LogError("realpath failed with '" << appPath.first.c_str()
219                     << "' as paramter: " << strerror(errno));
220             return false;
221         }
222         LogDebug("Requested path is '" << appPath.first.c_str()
223                 << "'. User's HOME is '" << pwd->pw_dir << "'");
224         if (!isSubDir(home.get(), real_path.get())) {
225             LogWarning("User's apps may have registered folders only in user's home dir");
226             return false;
227         }
228
229         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
230         if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
231             LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
232             return false;
233         }
234     }
235     return true;
236 }
237
238 bool Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
239 {
240     bool pkgIdIsNew = false;
241     std::vector<std::string> addedPermissions;
242     std::vector<std::string> removedPermissions;
243
244     // deserialize request data
245     app_inst_req req;
246     Deserialization::Deserialize(buffer, req.appId);
247     Deserialization::Deserialize(buffer, req.pkgId);
248     Deserialization::Deserialize(buffer, req.privileges);
249     Deserialization::Deserialize(buffer, req.appPaths);
250
251     if(!installRequestAuthCheck(req, uid)) {
252         LogError("Request from uid " << uid << " for app installation denied");
253         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
254         return false;
255     }
256
257     std::string smackLabel;
258     if (!generateAppLabel(req.pkgId, smackLabel)) {
259         LogError("Cannot generate Smack label for package: " << req.pkgId);
260         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
261         return false;
262     }
263
264     LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
265             << ", generated smack label: " << smackLabel);
266
267     // create null terminated array of strings for permissions
268     std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
269     for (size_t i = 0; i < req.privileges.size(); ++i) {
270         LogDebug("  Permission = " << req.privileges[i]);
271         pp_permissions[i] = req.privileges[i].c_str();
272     }
273     pp_permissions[req.privileges.size()] = nullptr;
274
275     try {
276         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
277         std::string uidstr = uid ? std::to_string(static_cast<unsigned int>(uid))
278                              : CYNARA_ADMIN_WILDCARD;
279
280         LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
281                  << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
282
283         m_privilegeDb.BeginTransaction();
284         m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
285         m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
286         m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges);
287         m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
288         CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
289                                          newPkgPrivileges);
290         m_privilegeDb.CommitTransaction();
291         LogDebug("Application installation commited to database");
292     } catch (const PrivilegeDb::Exception::InternalError &e) {
293         m_privilegeDb.RollbackTransaction();
294         LogError("Error while saving application info to database: " << e.DumpToString());
295         goto error_label;
296     } catch (const CynaraException::Base &e) {
297         m_privilegeDb.RollbackTransaction();
298         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
299         goto error_label;
300     } catch (const std::bad_alloc &e) {
301         m_privilegeDb.RollbackTransaction();
302         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
303         goto error_label;
304     }
305
306     // register paths
307     for (const auto &appPath : req.appPaths) {
308         const std::string &path = appPath.first;
309         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
310         int result = setupPath(req.pkgId, path, pathType);
311
312         if (!result) {
313             LogError("setupPath() failed");
314             goto error_label;
315         }
316     }
317
318     if (pkgIdIsNew) {
319         LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
320         if (!SmackRules::installPackageRules(req.pkgId)) {
321             LogError("Failed to apply package-specific smack rules");
322             goto error_label;
323         }
324     }
325
326     // success
327     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
328     return true;
329
330 error_label:
331     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
332     return false;
333 }
334
335 bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
336 {
337     // deserialize request data
338     std::string appId;
339     std::string pkgId;
340     std::string smackLabel;
341     bool appExists = true;
342     bool removePkg = false;
343
344     Deserialization::Deserialize(buffer, appId);
345
346     try {
347         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
348
349         m_privilegeDb.BeginTransaction();
350         if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
351             LogWarning("Application " << appId <<
352                 " not found in database while uninstalling");
353             m_privilegeDb.RollbackTransaction();
354             appExists = false;
355         } else {
356             if (!generateAppLabel(pkgId, smackLabel)) {
357                 LogError("Cannot generate Smack label for package: " << pkgId);
358                 goto error_label;
359             }
360
361             std::string uidstr = uid ? std::to_string(static_cast<unsigned int>(uid))
362                                  : CYNARA_ADMIN_WILDCARD;
363
364             LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
365                      << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
366
367             m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
368             m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector<std::string>());
369             m_privilegeDb.RemoveApplication(appId, uid, removePkg);
370             m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
371             CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
372                                              newPkgPrivileges);
373             m_privilegeDb.CommitTransaction();
374             LogDebug("Application uninstallation commited to database");
375         }
376     } catch (const PrivilegeDb::Exception::InternalError &e) {
377         m_privilegeDb.RollbackTransaction();
378         LogError("Error while removing application info from database: " << e.DumpToString());
379         goto error_label;
380     } catch (const CynaraException::Base &e) {
381         m_privilegeDb.RollbackTransaction();
382         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
383         goto error_label;
384     } catch (const std::bad_alloc &e) {
385         m_privilegeDb.RollbackTransaction();
386         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
387         goto error_label;
388     }
389
390     if (appExists) {
391
392         if (removePkg) {
393             LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
394             if (!SmackRules::uninstallPackageRules(pkgId)) {
395                 LogError("Error on uninstallation of package-specific smack rules");
396                 goto error_label;
397             }
398         }
399     }
400
401     // success
402     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
403     return true;
404
405 error_label:
406     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
407     return false;
408 }
409
410 bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
411 {
412     // deserialize request data
413     std::string appId;
414     std::string pkgId;
415
416     Deserialization::Deserialize(buffer, appId);
417     LogDebug("appId: " << appId);
418
419     try {
420         if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
421             LogWarning("Application " << appId << " not found in database");
422             Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
423             return false;
424         } else {
425             LogDebug("pkgId: " << pkgId);
426         }
427     } catch (const PrivilegeDb::Exception::InternalError &e) {
428         LogError("Error while getting pkgId from database: " << e.DumpToString());
429         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
430         return false;
431     }
432
433      // success
434     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
435     Serialization::Serialize(send, pkgId);
436     return true;
437 }
438
439 } // namespace SecurityManager