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