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