d4b27cac165fa1b21a57fb3e4ce0a72d5cb6d0bb
[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     Deserialization::Deserialize(buffer, req.uid);
278
279     std::string uidstr;
280     if ((!uid) && (req.uid))
281         uid = req.uid;
282     checkGlobalUser(uid, uidstr);
283
284     if(!installRequestAuthCheck(req, uid)) {
285         LogError("Request from uid " << uid << " for app installation denied");
286         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
287         return false;
288     }
289
290     std::string smackLabel;
291     if (!generateAppLabel(req.pkgId, smackLabel)) {
292         LogError("Cannot generate Smack label for package: " << req.pkgId);
293         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
294         return false;
295     }
296
297     LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
298             << ", generated smack label: " << smackLabel);
299
300     // create null terminated array of strings for permissions
301     std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
302     for (size_t i = 0; i < req.privileges.size(); ++i) {
303         LogDebug("  Permission = " << req.privileges[i]);
304         pp_permissions[i] = req.privileges[i].c_str();
305     }
306     pp_permissions[req.privileges.size()] = nullptr;
307
308     try {
309         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
310
311         LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
312                  << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
313
314         PrivilegeDb::getInstance().BeginTransaction();
315         PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
316         PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
317         PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
318         PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
319         CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
320                                          newPkgPrivileges);
321         PrivilegeDb::getInstance().CommitTransaction();
322         LogDebug("Application installation commited to database");
323     } catch (const PrivilegeDb::Exception::IOError &e) {
324         LogError("Cannot access application database: " << e.DumpToString());
325         goto error_label;
326     } catch (const PrivilegeDb::Exception::InternalError &e) {
327         PrivilegeDb::getInstance().RollbackTransaction();
328         LogError("Error while saving application info to database: " << e.DumpToString());
329         goto error_label;
330     } catch (const CynaraException::Base &e) {
331         PrivilegeDb::getInstance().RollbackTransaction();
332         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
333         goto error_label;
334     } catch (const std::bad_alloc &e) {
335         PrivilegeDb::getInstance().RollbackTransaction();
336         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
337         goto error_label;
338     }
339
340     // register paths
341     for (const auto &appPath : req.appPaths) {
342         const std::string &path = appPath.first;
343         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
344         int result = setupPath(req.pkgId, path, pathType);
345
346         if (!result) {
347             LogError("setupPath() failed");
348             goto error_label;
349         }
350     }
351
352     if (pkgIdIsNew) {
353         LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
354         if (!SmackRules::installPackageRules(req.pkgId)) {
355             LogError("Failed to apply package-specific smack rules");
356             goto error_label;
357         }
358     }
359
360     // success
361     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
362     return true;
363
364 error_label:
365     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
366     return false;
367 }
368
369 bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
370 {
371     // deserialize request data
372     std::string appId;
373     std::string pkgId;
374     std::string smackLabel;
375     bool appExists = true;
376     bool removePkg = false;
377
378     Deserialization::Deserialize(buffer, appId);
379     std::string uidstr;
380     checkGlobalUser(uid, uidstr);
381
382     try {
383         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
384
385         PrivilegeDb::getInstance().BeginTransaction();
386         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
387             LogWarning("Application " << appId <<
388                 " not found in database while uninstalling");
389             PrivilegeDb::getInstance().RollbackTransaction();
390             appExists = false;
391         } else {
392
393             LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
394                      << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
395
396             if (!generateAppLabel(pkgId, smackLabel)) {
397                 LogError("Cannot generate Smack label for package: " << pkgId);
398                 goto error_label;
399             }
400
401             PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
402             PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
403             PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
404             PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
405             CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
406                                              newPkgPrivileges);
407             PrivilegeDb::getInstance().CommitTransaction();
408             LogDebug("Application uninstallation commited to database");
409         }
410     } catch (const PrivilegeDb::Exception::IOError &e) {
411         LogError("Cannot access application database: " << e.DumpToString());
412         goto error_label;
413     } catch (const PrivilegeDb::Exception::InternalError &e) {
414         PrivilegeDb::getInstance().RollbackTransaction();
415         LogError("Error while removing application info from database: " << e.DumpToString());
416         goto error_label;
417     } catch (const CynaraException::Base &e) {
418         PrivilegeDb::getInstance().RollbackTransaction();
419         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
420         goto error_label;
421     } catch (const std::bad_alloc &e) {
422         PrivilegeDb::getInstance().RollbackTransaction();
423         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
424         goto error_label;
425     }
426
427     if (appExists) {
428
429         if (removePkg) {
430             LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
431             if (!SmackRules::uninstallPackageRules(pkgId)) {
432                 LogError("Error on uninstallation of package-specific smack rules");
433                 goto error_label;
434             }
435         }
436     }
437
438     // success
439     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
440     return true;
441
442 error_label:
443     Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
444     return false;
445 }
446
447 bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
448 {
449     // deserialize request data
450     std::string appId;
451     std::string pkgId;
452
453     Deserialization::Deserialize(buffer, appId);
454     LogDebug("appId: " << appId);
455
456     try {
457         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
458             LogWarning("Application " << appId << " not found in database");
459             Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
460             return false;
461         } else {
462             LogDebug("pkgId: " << pkgId);
463         }
464     } catch (const PrivilegeDb::Exception::Base &e) {
465         LogError("Error while getting pkgId from database: " << e.DumpToString());
466         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
467         return false;
468     }
469
470      // success
471     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
472     Serialization::Serialize(send, pkgId);
473     return true;
474 }
475
476 bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid)
477 {
478     std::unordered_set<gid_t> gids;
479
480     try {
481         std::string appId;
482         std::string pkgId;
483         std::string smackLabel;
484         std::string uidStr = std::to_string(uid);
485         std::string pidStr = std::to_string(pid);
486
487         Deserialization::Deserialize(buffer, appId);
488         LogDebug("appId: " << appId);
489
490         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
491             LogWarning("Application " << appId << " not found in database");
492             Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
493             return false;
494         }
495         LogDebug("pkgId: " << pkgId);
496
497         if (!generateAppLabel(pkgId, smackLabel)) {
498              LogError("Cannot generate Smack label for package: " << pkgId);
499             Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
500             return false;
501         }
502         LogDebug("smack label: " << smackLabel);
503
504         std::vector<std::string> privileges;
505         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
506         /*there is also a need of checking, if privilege is granted to all users*/
507         size_t tmp = privileges.size();
508         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
509         /*privileges needs to be sorted and with no duplications - for cynara sake*/
510         std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
511         privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
512
513         for (const auto &privilege : privileges) {
514             std::vector<std::string> gidsTmp;
515             PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
516             if (!gidsTmp.empty()) {
517                 LogDebug("Considering privilege " << privilege << " with " <<
518                     gidsTmp.size() << " groups assigned");
519                 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
520                     for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
521                     {
522                         struct group *grp = getgrnam(group.c_str());
523                         if (grp == NULL) {
524                                 LogError("No such group: " << group.c_str());
525                                 return;
526                         }
527                         gids.insert(grp->gr_gid);
528                     });
529                     LogDebug("Cynara allowed, adding groups");
530                 } else
531                     LogDebug("Cynara denied, not adding groups");
532             }
533         }
534     } catch (const PrivilegeDb::Exception::Base &e) {
535         LogError("Database error: " << e.DumpToString());
536         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
537         return false;
538     } catch (const CynaraException::Base &e) {
539         LogError("Error while querying Cynara for permissions: " << e.DumpToString());
540         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
541         return false;
542     } catch (const std::bad_alloc &e) {
543         LogError("Memory allocation failed: " << e.what());
544         Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY);
545         return false;
546     }
547
548     // success
549     Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
550     Serialization::Serialize(send, static_cast<int>(gids.size()));
551     for (const auto &gid : gids) {
552         Serialization::Serialize(send, gid);
553     }
554     return true;
555 }
556
557
558 } // namespace SecurityManager