Fix: disallow installing apps with the same id in different packages
[platform/core/security/security-manager.git] / src / client / client-security-manager.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  *      Security Manager library header
19  */
20 /*
21  * @file        client-security-manager.cpp
22  * @author      Pawel Polawski <p.polawski@samsung.com>
23  * @author      Rafal Krypa <r.krypa@samsung.com>
24  * @version     1.0
25  * @brief       This file contain client side implementation of security-manager API
26  */
27
28 #include <cstdio>
29 #include <utility>
30
31 #include <unistd.h>
32 #include <grp.h>
33 #include <dirent.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/xattr.h>
37 #include <sys/smack.h>
38 #include <sys/capability.h>
39
40 #include <dpl/log/log.h>
41 #include <dpl/exception.h>
42
43 #include <message-buffer.h>
44 #include <client-common.h>
45 #include <protocols.h>
46 #include <smack-common.h>
47 #include <service_impl.h>
48 #include <file-lock.h>
49
50 #include <security-manager.h>
51
52 /**
53  * Mapping of lib_retcode error codes to theirs strings equivalents
54  */
55 static std::map<enum lib_retcode, std::string> lib_retcode_string_map = {
56     {SECURITY_MANAGER_SUCCESS, "Success"},
57     {SECURITY_MANAGER_ERROR_UNKNOWN, "Unknown error"},
58     {SECURITY_MANAGER_ERROR_INPUT_PARAM, "Invalid function parameter was given"},
59     {SECURITY_MANAGER_ERROR_MEMORY, "Memory allocation error"},
60     {SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE, "Incomplete data in application request"},
61     {SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED, "User does not have sufficient "
62                                                    "rigths to perform an operation"}
63 };
64
65 SECURITY_MANAGER_API
66 const char *security_manager_strerror(enum lib_retcode rc)
67 {
68     try {
69         return lib_retcode_string_map.at(rc).c_str();
70     } catch (const std::out_of_range &e) {
71         return "Unknown error code";
72     }
73 }
74
75 SECURITY_MANAGER_API
76 int security_manager_app_inst_req_new(app_inst_req **pp_req)
77 {
78     if (!pp_req)
79         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
80
81     try {
82         *pp_req = new app_inst_req;
83     } catch (std::bad_alloc& ex) {
84         return SECURITY_MANAGER_ERROR_MEMORY;
85     }
86     (*pp_req)->uid = geteuid();
87
88     return SECURITY_MANAGER_SUCCESS;
89 }
90
91 SECURITY_MANAGER_API
92 void security_manager_app_inst_req_free(app_inst_req *p_req)
93 {
94     delete p_req;
95 }
96
97 SECURITY_MANAGER_API
98 int security_manager_app_inst_req_set_uid(app_inst_req *p_req,
99                                           const uid_t uid)
100 {
101     if (!p_req)
102         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
103
104     p_req->uid = uid;
105
106     return SECURITY_MANAGER_SUCCESS;
107 }
108
109 SECURITY_MANAGER_API
110 int security_manager_app_inst_req_set_app_id(app_inst_req *p_req, const char *app_id)
111 {
112     if (!p_req || !app_id)
113         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
114
115     p_req->appId = app_id;
116
117     return SECURITY_MANAGER_SUCCESS;
118 }
119
120 SECURITY_MANAGER_API
121 int security_manager_app_inst_req_set_pkg_id(app_inst_req *p_req, const char *pkg_id)
122 {
123     if (!p_req || !pkg_id)
124         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
125
126     p_req->pkgId = pkg_id;
127
128     return SECURITY_MANAGER_SUCCESS;
129 }
130
131 SECURITY_MANAGER_API
132 int security_manager_app_inst_req_add_privilege(app_inst_req *p_req, const char *privilege)
133 {
134     if (!p_req || !privilege)
135         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
136
137     p_req->privileges.push_back(privilege);
138
139     return SECURITY_MANAGER_SUCCESS;
140 }
141
142 SECURITY_MANAGER_API
143 int security_manager_app_inst_req_add_path(app_inst_req *p_req, const char *path, const int path_type)
144 {
145     if (!p_req || !path || (path_type < 0) || (path_type >= SECURITY_MANAGER_ENUM_END))
146         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
147
148     p_req->appPaths.push_back(std::make_pair(path, path_type));
149
150     return SECURITY_MANAGER_SUCCESS;
151 }
152
153 SECURITY_MANAGER_API
154 int security_manager_app_install(const app_inst_req *p_req)
155 {
156     using namespace SecurityManager;
157
158     return try_catch([&] {
159         //checking parameters
160         if (!p_req)
161             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
162         if (p_req->appId.empty() || p_req->pkgId.empty())
163             return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
164
165         bool offlineMode;
166         int retval;
167
168         try {
169             SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE);
170             if ((offlineMode = serviceLock.Locked())) {
171                 LogInfo("Working in offline mode.");
172                 retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid());
173             }
174         } catch (const SecurityManager::FileLocker::Exception::Base &e) {
175             offlineMode = false;
176         }
177         if (!offlineMode) {
178             MessageBuffer send, recv;
179
180             //put data into buffer
181             Serialization::Serialize(send, (int)SecurityModuleCall::APP_INSTALL);
182             Serialization::Serialize(send, p_req->appId);
183             Serialization::Serialize(send, p_req->pkgId);
184             Serialization::Serialize(send, p_req->privileges);
185             Serialization::Serialize(send, p_req->appPaths);
186             Serialization::Serialize(send, p_req->uid);
187
188             //send buffer to server
189             retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
190             if (retval != SECURITY_MANAGER_API_SUCCESS) {
191                 LogError("Error in sendToServer. Error code: " << retval);
192                 return SECURITY_MANAGER_ERROR_UNKNOWN;
193             }
194
195             //receive response from server
196             Deserialization::Deserialize(recv, retval);
197         }
198         switch(retval) {
199             case SECURITY_MANAGER_API_SUCCESS:
200                 return SECURITY_MANAGER_SUCCESS;
201             case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED:
202                 return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
203             case SECURITY_MANAGER_API_ERROR_INPUT_PARAM:
204                 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
205             default:
206                 return SECURITY_MANAGER_ERROR_UNKNOWN;
207         }
208
209     });
210 }
211
212 SECURITY_MANAGER_API
213 int security_manager_app_uninstall(const app_inst_req *p_req)
214 {
215     using namespace SecurityManager;
216     MessageBuffer send, recv;
217
218     return try_catch([&] {
219         //checking parameters
220         if (!p_req)
221             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
222         if (p_req->appId.empty())
223             return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
224
225         //put data into buffer
226         Serialization::Serialize(send, (int)SecurityModuleCall::APP_UNINSTALL);
227         Serialization::Serialize(send, p_req->appId);
228
229         //send buffer to server
230         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
231         if (retval != SECURITY_MANAGER_API_SUCCESS) {
232             LogError("Error in sendToServer. Error code: " << retval);
233             return SECURITY_MANAGER_ERROR_UNKNOWN;
234         }
235
236         //receive response from server
237         Deserialization::Deserialize(recv, retval);
238         if (retval != SECURITY_MANAGER_API_SUCCESS)
239             return SECURITY_MANAGER_ERROR_UNKNOWN;
240
241         return SECURITY_MANAGER_SUCCESS;;
242     });
243 }
244
245 SECURITY_MANAGER_API
246 int security_manager_get_app_pkgid(char **pkg_id, const char *app_id)
247 {
248     using namespace SecurityManager;
249     MessageBuffer send, recv;
250
251     LogDebug("security_manager_get_app_pkgid() called");
252
253     return try_catch([&] {
254         //checking parameters
255
256         if (app_id == NULL) {
257             LogError("security_manager_app_get_pkgid: app_id is NULL");
258             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
259         }
260
261         if (pkg_id == NULL) {
262             LogError("security_manager_app_get_pkgid: pkg_id is NULL");
263             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
264         }
265
266         //put data into buffer
267         Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_PKGID));
268         Serialization::Serialize(send, std::string(app_id));
269
270         //send buffer to server
271         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
272         if (retval != SECURITY_MANAGER_API_SUCCESS) {
273             LogDebug("Error in sendToServer. Error code: " << retval);
274             return SECURITY_MANAGER_ERROR_UNKNOWN;
275         }
276
277         //receive response from server
278         Deserialization::Deserialize(recv, retval);
279         if (retval != SECURITY_MANAGER_API_SUCCESS)
280             return SECURITY_MANAGER_ERROR_UNKNOWN;
281
282         std::string pkgIdString;
283         Deserialization::Deserialize(recv, pkgIdString);
284         if (pkgIdString.empty()) {
285             LogError("Unexpected empty pkgId");
286             return SECURITY_MANAGER_ERROR_UNKNOWN;
287         }
288
289         *pkg_id = strdup(pkgIdString.c_str());
290         if (*pkg_id == NULL) {
291             LogError("Failed to allocate memory for pkgId");
292             return SECURITY_MANAGER_ERROR_MEMORY;
293         }
294
295         return SECURITY_MANAGER_SUCCESS;
296     });
297 }
298
299 static bool setup_smack(const char *label)
300 {
301     int labelSize = strlen(label);
302
303     // Set Smack label for open socket file descriptors
304
305     std::unique_ptr<DIR, std::function<int(DIR*)>> dir(
306         opendir("/proc/self/fd"), closedir);
307     if (!dir.get()) {
308         LogError("Unable to read list of open file descriptors: " <<
309             strerror(errno));
310         return SECURITY_MANAGER_ERROR_UNKNOWN;
311     }
312
313     do {
314         errno = 0;
315         struct dirent *dirEntry = readdir(dir.get());
316         if (dirEntry == nullptr) {
317             if (errno == 0) // NULL return value also signals end of directory
318                 break;
319
320             LogError("Unable to read list of open file descriptors: " <<
321                 strerror(errno));
322             return SECURITY_MANAGER_ERROR_UNKNOWN;
323         }
324
325         // Entries with numerical names specify file descriptors, ignore the rest
326         if (!isdigit(dirEntry->d_name[0]))
327             continue;
328
329         struct stat statBuf;
330         int fd = atoi(dirEntry->d_name);
331         int ret = fstat(fd, &statBuf);
332         if (ret != 0) {
333             LogWarning("fstat failed on file descriptor " << fd << ": " <<
334                 strerror(errno));
335             continue;
336         }
337         if (S_ISSOCK(statBuf.st_mode)) {
338             ret = fsetxattr(fd, XATTR_NAME_SMACKIPIN, label, labelSize, 0);
339             if (ret != 0) {
340                 LogError("Setting Smack label failed on file descriptor " <<
341                     fd << ": " << strerror(errno));
342                 return SECURITY_MANAGER_ERROR_UNKNOWN;
343             }
344
345             ret = fsetxattr(fd, XATTR_NAME_SMACKIPOUT, label, labelSize, 0);
346             if (ret != 0) {
347                 LogError("Setting Smack label failed on file descriptor " <<
348                     fd << ": " << strerror(errno));
349                 return SECURITY_MANAGER_ERROR_UNKNOWN;
350             }
351         }
352     } while (true);
353
354     // Set Smack label of current process
355     smack_set_label_for_self(label);
356
357     return SECURITY_MANAGER_SUCCESS;
358 }
359
360 SECURITY_MANAGER_API
361 int security_manager_set_process_label_from_appid(const char *app_id)
362 {
363     char *pkg_id;
364     int ret;
365     std::string appLabel;
366
367     LogDebug("security_manager_set_process_label_from_appid() called");
368
369     if (smack_smackfs_path() == NULL)
370         return SECURITY_MANAGER_SUCCESS;
371
372     ret = security_manager_get_app_pkgid(&pkg_id, app_id);
373     if (ret != SECURITY_MANAGER_SUCCESS) {
374         return ret;
375     }
376
377     if (SecurityManager::generateAppLabel(std::string(pkg_id), appLabel)) {
378         ret = setup_smack(appLabel.c_str());
379         if (ret != SECURITY_MANAGER_SUCCESS) {
380             LogError("Failed to set smack label " << appLabel << " for current process");
381         }
382     }
383     else {
384         ret = SECURITY_MANAGER_ERROR_UNKNOWN;
385     }
386
387     free(pkg_id);
388     return ret;
389 }
390
391 SECURITY_MANAGER_API
392 int security_manager_set_process_groups_from_appid(const char *app_id)
393 {
394     using namespace SecurityManager;
395     MessageBuffer send, recv;
396     int ret;
397
398     LogDebug("security_manager_set_process_groups_from_appid() called");
399
400     return try_catch([&] {
401         //checking parameters
402
403         if (app_id == nullptr) {
404             LogError("app_id is NULL");
405             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
406         }
407
408         //put data into buffer
409         Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_GROUPS));
410         Serialization::Serialize(send, std::string(app_id));
411
412         //send buffer to server
413         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
414         if (retval != SECURITY_MANAGER_API_SUCCESS) {
415             LogDebug("Error in sendToServer. Error code: " << retval);
416             return SECURITY_MANAGER_ERROR_UNKNOWN;
417         }
418
419         //receive response from server
420         Deserialization::Deserialize(recv, retval);
421         if (retval != SECURITY_MANAGER_API_SUCCESS)
422             return SECURITY_MANAGER_ERROR_UNKNOWN;
423
424         //How many new groups?
425         int newGroupsCnt;
426         Deserialization::Deserialize(recv, newGroupsCnt);
427
428         //And how many groups do we belong to already?
429         int oldGroupsCnt;
430         ret = getgroups(0, nullptr);
431         if (ret == -1) {
432             LogError("Unable to get list of current supplementary groups: " <<
433                 strerror(errno));
434             return SECURITY_MANAGER_ERROR_UNKNOWN;
435         }
436         oldGroupsCnt = ret;
437
438         //Allocate an array for both old and new groups gids
439         std::unique_ptr<gid_t[]> groups(new gid_t[oldGroupsCnt + newGroupsCnt]);
440         if (!groups.get()) {
441             LogError("Memory allocation failed.");
442             return SECURITY_MANAGER_ERROR_MEMORY;
443         }
444
445         //Get the old groups from process
446         ret = getgroups(oldGroupsCnt, groups.get());
447         if (ret == -1) {
448             LogError("Unable to get list of current supplementary groups: " <<
449                 strerror(errno));
450             return SECURITY_MANAGER_ERROR_UNKNOWN;
451         }
452
453         //Get the new groups from server response
454         for (int i = 0; i < newGroupsCnt; ++i) {
455             gid_t gid;
456             Deserialization::Deserialize(recv, gid);
457             groups.get()[oldGroupsCnt + i] = gid;
458             LogDebug("Adding process to group " << gid);
459         }
460
461         //Apply the modified groups list
462         ret = setgroups(oldGroupsCnt + newGroupsCnt, groups.get());
463         if (ret == -1) {
464             LogError("Unable to get list of current supplementary groups: " <<
465                 strerror(errno));
466             return SECURITY_MANAGER_ERROR_UNKNOWN;
467         }
468
469         return SECURITY_MANAGER_SUCCESS;
470     });
471 }
472
473 SECURITY_MANAGER_API
474 int security_manager_drop_process_privileges(void)
475 {
476     LogDebug("security_manager_drop_process_privileges() called");
477
478     int ret;
479     cap_t cap = cap_init();
480     if (!cap) {
481         LogError("Unable to allocate capability object");
482         return SECURITY_MANAGER_ERROR_MEMORY;
483     }
484
485     ret = cap_clear(cap);
486     if (ret) {
487         LogError("Unable to initialize capability object");
488         cap_free(cap);
489         return SECURITY_MANAGER_ERROR_UNKNOWN;
490     }
491
492     ret = cap_set_proc(cap);
493     if (ret) {
494         LogError("Unable to drop process capabilities");
495         cap_free(cap);
496         return SECURITY_MANAGER_ERROR_UNKNOWN;
497     }
498
499     cap_free(cap);
500     return SECURITY_MANAGER_SUCCESS;
501 }
502
503 SECURITY_MANAGER_API
504 int security_manager_prepare_app(const char *app_id)
505 {
506     LogDebug("security_manager_prepare_app() called");
507     int ret;
508
509     ret = security_manager_set_process_label_from_appid(app_id);
510     if (ret != SECURITY_MANAGER_SUCCESS)
511         return ret;
512
513     ret = security_manager_set_process_groups_from_appid(app_id);
514     if (ret != SECURITY_MANAGER_SUCCESS)
515         return ret;
516
517     ret = security_manager_drop_process_privileges();
518     return ret;
519 }