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