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