Merge "Change CA certificate bundle and path for TV" into tizen
[platform/framework/web/download-provider.git] / provider / download-provider-security.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <sys/statfs.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <limits.h>
25
26 #include <download-provider.h>
27 #include <download-provider-log.h>
28 #include <download-provider-utils.h>
29
30 #include <cynara-client.h>
31 #include <cynara-client-async.h>
32 #include <cynara-creds-socket.h>
33 #include <cynara-creds-dbus.h>
34
35 #include <app_manager.h>
36 #include <tzplatform_config.h>
37
38 #include "download-provider-security.h"
39
40 #define MAX_ARRAY_LEN 1024
41 #define SECURITY_ATTRIBUTES_PATH "/proc/%d/attr/current"
42 #define TEMP_DIR "/tmp/"
43 #define LEGACY_USER_APP "/opt/usr/apps/"
44
45 static int dp_is_exist_dir(const char *dirpath)
46 {
47         struct stat dir_state;
48         int stat_ret;
49         if (dirpath == NULL) {
50                 TRACE_ERROR("check path");
51                 return -1;
52         }
53         stat_ret = stat(dirpath, &dir_state);
54         if (stat_ret == 0 && S_ISDIR(dir_state.st_mode))
55                 return 0;
56         return -1;
57 }
58
59 static char *_dp_get_pkg_id(dp_credential cred)
60 {
61         char *app_id = NULL;
62         char *pkg_id = NULL;
63         app_info_h app_info = NULL;
64
65         if (app_manager_get_app_id(cred.pid, &app_id) != APP_MANAGER_ERROR_NONE) {
66                 TRACE_ERROR("Failed to get application ID");
67                 return NULL;
68         }
69
70         if (app_info_create(app_id, &app_info) != APP_MANAGER_ERROR_NONE) {
71                 TRACE_ERROR("Failed to create app_info");
72                 free(app_id);
73                 return NULL;
74         }
75
76         if (app_info_get_package(app_info, &pkg_id) != APP_MANAGER_ERROR_NONE) {
77                 TRACE_ERROR("Failed to get package ID");
78                 app_info_destroy(app_info);
79                 free(app_id);
80                 free(pkg_id);
81                 return NULL;
82         }
83
84         app_info_destroy(app_info);
85         free(app_id);
86
87         return pkg_id;
88 }
89
90 static int _dp_check_dir_permission(dp_credential cred, const char *privilege)
91 {
92         FILE *fd;
93         int ret;
94         char client_smack[MAX_ARRAY_LEN + 1] = {0, };
95         char client_smack_path[MAX_ARRAY_LEN + 1] = {0, };
96         char uid[20] = {0, };
97         char *client_session = "";
98         cynara *p_cynara = NULL;
99
100         if (CYNARA_API_SUCCESS != cynara_initialize(&p_cynara, NULL)) {
101                 TRACE_ERROR("Failed to initialize cynara structure\n");
102                 return -1;
103         }
104
105         snprintf(client_smack_path, MAX_ARRAY_LEN, SECURITY_ATTRIBUTES_PATH, cred.pid);
106         fd = fopen(client_smack_path, "r");
107         if (fd == NULL) {
108                 TRACE_ERROR("Failed to open %s", client_smack_path);
109                 cynara_finish(p_cynara);
110                 return -1;
111         }
112         ret = fread(client_smack, 1, MAX_ARRAY_LEN, fd);
113         if (ferror(fd)) {
114                 TRACE_ERROR("Failed to read %s", client_smack_path);
115                 fclose(fd);
116                 cynara_finish(p_cynara);
117                 return -1;
118         }
119         fclose(fd);
120         client_smack[ret] = '\0';
121
122         snprintf(uid, sizeof(uid), "%d", cred.uid);
123
124         TRACE_DEBUG("pid: %d, uid: %s, checked privilege:%s", cred.pid, uid, privilege);
125         ret = cynara_check(p_cynara, client_smack, client_session, uid, privilege);
126         cynara_finish(p_cynara);
127
128         return (ret == CYNARA_API_ACCESS_ALLOWED) ? 0 : -1;
129 }
130
131 int dp_is_valid_dir(dp_credential cred, const char *dirpath)
132 {
133         char default_storage[PATH_MAX + 1] = {0, };
134         char media_storage[PATH_MAX + 1] = {0, };
135         char external_storage[PATH_MAX + 1] = {0, };
136         char apps_storage[PATH_MAX + 1] = {0, };
137         char resolved_path[PATH_MAX + 1] = {0 , };
138         char *res = NULL;
139         char *pkg_id = NULL;
140         const char *temp = NULL;
141         int end = 0;
142
143         res = realpath(dirpath, NULL);
144         if (res == NULL) {
145                 TRACE_ERROR("Failed to get absolute path");
146                 return DP_ERROR_INVALID_DESTINATION;
147         }
148
149         strncpy(resolved_path, res, PATH_MAX - 1);
150         free(res);
151
152         end = strlen(resolved_path) - 1;
153         if (resolved_path[end] != '/')
154                 resolved_path[end + 1] = '/';
155
156         TRACE_INFO("%s -> %s", dirpath, resolved_path);
157
158         // Check whether directory is exist or not.
159         if (dp_is_exist_dir(resolved_path) < 0) {
160                 TRACE_ERROR("%s is not exist.", resolved_path);
161                 return DP_ERROR_INVALID_DESTINATION;
162         }
163
164         // Check whether directory is temporary directory or not.
165         if (strncmp(resolved_path, TEMP_DIR, strlen(TEMP_DIR)) == 0)
166                 return DP_ERROR_NONE;
167
168         tzplatform_set_user(cred.uid);
169
170         // Check whether directory is default directory or not.
171         temp = tzplatform_getenv(TZ_USER_DOWNLOADS);
172         if (temp) {
173                 snprintf(default_storage, PATH_MAX - 1, "%s/", temp);
174                 if (strncmp(resolved_path, default_storage,
175                                         strlen(default_storage)) == 0)
176                                 return DP_ERROR_NONE;
177                 temp = NULL;
178         }
179
180         // Check permission: media storage
181         temp = tzplatform_getenv(TZ_USER_CONTENT);
182         if (temp) {
183                 snprintf(media_storage, PATH_MAX - 1, "%s/", temp);
184                 if (strncmp(resolved_path, media_storage,
185                                         strlen(media_storage)) == 0) {
186                         if (_dp_check_dir_permission(cred, MEDIA_STORAGE_PRIVILEGE) < 0) {
187                                 TRACE_ERROR("Permission denied: %s needs %s privilege",
188                                                 resolved_path, MEDIA_STORAGE_PRIVILEGE);
189                                 return DP_ERROR_INVALID_DESTINATION;
190                         }
191                         return DP_ERROR_NONE;
192                 }
193                 temp = NULL;
194         }
195
196         // Check permission: external storage
197         temp = tzplatform_getenv(TZ_SYS_STORAGE);
198         if (temp) {
199                 snprintf(external_storage, PATH_MAX - 1, "%s/", temp);
200                 if (strncmp(resolved_path, external_storage,
201                                         strlen(external_storage)) == 0) {
202                         if (_dp_check_dir_permission(cred, EXTERNAL_STORAGE_PRIVILEGE) < 0) {
203                                 TRACE_ERROR("Permission denied: %s needs %s privilege",
204                                                 resolved_path, EXTERNAL_STORAGE_PRIVILEGE);
205                                 return DP_ERROR_INVALID_DESTINATION;
206                         }
207                         return DP_ERROR_NONE;
208                 }
209                 temp = NULL;
210         }
211
212         // Check permission: private storage
213         if (strncmp(resolved_path, LEGACY_USER_APP, strlen(LEGACY_USER_APP)) == 0) {
214                 // Some applications use a legacy app path.
215                 snprintf(apps_storage, PATH_MAX - 1, "%s", LEGACY_USER_APP);
216         } else {
217                 temp = tzplatform_getenv(TZ_USER_APP);
218                 snprintf(apps_storage, PATH_MAX - 1, "%s/", temp);
219                 temp = NULL;
220         }
221
222         if (strlen(apps_storage) > 0) {
223                 if (strncmp(resolved_path, apps_storage,
224                                         strlen(apps_storage)) == 0) {
225                         pkg_id = _dp_get_pkg_id(cred);
226                         if (!pkg_id)
227                                 return DP_ERROR_INVALID_DESTINATION;
228
229                         TRACE_INFO("pkg_id: %s", pkg_id);
230                         if (strncmp(resolved_path + strlen(apps_storage),
231                                                 pkg_id, strlen(pkg_id)) != 0) {
232                                 TRACE_ERROR("Permission denied");
233                                 free(pkg_id);
234                                 return DP_ERROR_INVALID_DESTINATION;
235                         }
236                         free(pkg_id);
237                         return DP_ERROR_NONE;
238                 }
239         }
240
241         // Check whether directory is shared directory or not.
242         temp = tzplatform_getenv(TZ_USER_SHARE);
243         if (temp) {
244                 if (strncmp(resolved_path, temp,
245                                         strlen(temp)) == 0)
246                         return DP_ERROR_NONE;
247                 temp = NULL;
248         }
249
250         return DP_ERROR_INVALID_DESTINATION;
251 }
252
253 void dp_rebuild_dir(const char *dirpath, mode_t mode)
254 {
255         if (dp_is_exist_dir(dirpath) < 0) {
256                 if (mkdir(dirpath, mode) == 0)
257                         TRACE_INFO("check directory:%s", dirpath);
258                 else
259                         TRACE_ERROR("failed to create directory:%s", dirpath);
260         }
261 }
262
263 int dp_check_permission(int clientfd, const char *pkgname)
264 {
265         int ret;
266         int result = DP_ERROR_NONE;
267         cynara *p_cynara = NULL;
268         cynara_configuration *p_conf = NULL;
269         size_t cache_size = 100;
270         const char *client_session = "";
271         char *client_smack = NULL;
272         char *uid = NULL;
273
274         TRACE_DEBUG("clientfd[%d] pkgname[%s]", clientfd, pkgname);
275         if (CYNARA_API_SUCCESS != cynara_configuration_create(&p_conf)) {
276                 TRACE_DEBUG("failed to create cynara configuration");
277                 result = DP_ERROR_PERMISSION_DENIED;
278                 goto DONE;
279         }
280
281         if (CYNARA_API_SUCCESS != cynara_configuration_set_cache_size(p_conf, cache_size)) {
282                 TRACE_DEBUG("failed to set cache size");
283                 result = DP_ERROR_PERMISSION_DENIED;
284                 goto DONE;
285         }
286
287         ret = cynara_initialize(&p_cynara, NULL);
288         if (ret != CYNARA_API_SUCCESS) {
289                 TRACE_DEBUG("failed to initialize cynara");
290                 result = DP_ERROR_PERMISSION_DENIED;
291                 goto DONE;
292         }
293
294         // Get client peer credential
295         ret = cynara_creds_socket_get_client(clientfd, CLIENT_METHOD_SMACK, &client_smack);
296         if (ret != CYNARA_API_SUCCESS) {
297                 TRACE_DEBUG("failed to createsa client identification string");
298                 result = DP_ERROR_PERMISSION_DENIED;
299                 goto DONE;
300         }
301
302         ret = cynara_creds_socket_get_user(clientfd, USER_METHOD_UID, &uid);
303         if (ret != CYNARA_API_SUCCESS) {
304                 TRACE_DEBUG("failed to create a user identification string");
305                 result = DP_ERROR_PERMISSION_DENIED;
306                 goto DONE;
307         }
308
309         // Cynara check
310         ret = cynara_check(p_cynara, client_smack, client_session, uid, DOWNLOAD_PRIVILEGE);
311         if (ret == CYNARA_API_ACCESS_ALLOWED) {
312                 TRACE_DEBUG("CYNARA_API_ACCESS_ALLOWED");
313         } else {
314                 TRACE_DEBUG("DP_ERROR_PERMISSION_DENIED");
315                 result = DP_ERROR_PERMISSION_DENIED;
316         }
317
318 DONE:
319         if (p_conf)
320                 cynara_configuration_destroy(p_conf);
321         if (p_cynara)
322                 cynara_finish(p_cynara);
323         free(client_smack);
324         free(uid);
325         return result;
326 }