Check permission before setting destination path #2
[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
43 static int dp_is_exist_dir(const char *dirpath)
44 {
45         struct stat dir_state;
46         int stat_ret;
47         if (dirpath == NULL) {
48                 TRACE_ERROR("check path");
49                 return -1;
50         }
51         stat_ret = stat(dirpath, &dir_state);
52         if (stat_ret == 0 && S_ISDIR(dir_state.st_mode))
53                 return 0;
54         return -1;
55 }
56
57 static char *_dp_get_pkg_id(dp_credential cred)
58 {
59         char *app_id = NULL;
60         char *pkg_id = NULL;
61         app_context_h context;
62
63         if (app_manager_get_app_id(cred.pid, &app_id) != APP_MANAGER_ERROR_NONE) {
64                 TRACE_ERROR("Failed to get application ID");
65                 return NULL;
66         }
67
68         if (app_manager_get_app_context(app_id, &context) != APP_MANAGER_ERROR_NONE) {
69                 TRACE_ERROR("Failed to get application ID");
70                 free(app_id);
71                 return NULL;
72         }
73
74         if (app_context_get_package_id(context, &pkg_id) != APP_MANAGER_ERROR_NONE) {
75                 TRACE_ERROR("Failed to get application ID");
76                 app_context_destroy(context);
77                 free(app_id);
78                 return NULL;
79         }
80
81         app_context_destroy(context);
82         free(app_id);
83
84         return pkg_id;
85 }
86
87 static int _dp_check_dir_permission(dp_credential cred, const char *privilege)
88 {
89         FILE *fd;
90         int ret;
91         char client_smack[MAX_ARRAY_LEN + 1] = {0, };
92         char client_smack_path[MAX_ARRAY_LEN + 1] = {0, };
93         char uid[20] = {0, };
94         char *client_session = "";
95         cynara *p_cynara = NULL;
96
97         if (CYNARA_API_SUCCESS != cynara_initialize(&p_cynara, NULL)) {
98                 TRACE_ERROR("Failed to initialize cynara structure\n");
99                 return -1;
100         }
101
102         snprintf(client_smack_path, MAX_ARRAY_LEN, SECURITY_ATTRIBUTES_PATH, cred.pid);
103         fd = fopen(client_smack_path, "r");
104         if (fd == NULL) {
105                 TRACE_ERROR("Failed to open %s", client_smack_path);
106                 cynara_finish(p_cynara);
107                 return -1;
108         }
109         ret = fread(client_smack, MAX_ARRAY_LEN, 1, fd);
110         if (ferror(fd)) {
111                 TRACE_ERROR("Failed to read %s", client_smack_path);
112                 fclose(fd);
113                 cynara_finish(p_cynara);
114                 return -1;
115         }
116         fclose(fd);
117
118         snprintf(uid, sizeof(uid), "%d", cred.uid);
119
120         TRACE_DEBUG("pid: %ld, uid: %s, checked privilege:%s", cred.pid, uid, privilege);
121         ret = cynara_check(p_cynara, client_smack, client_session, uid, privilege);
122         cynara_finish(p_cynara);
123
124         return (ret == CYNARA_API_ACCESS_ALLOWED) ? 0 : -1;
125 }
126
127 int dp_is_valid_dir(dp_credential cred, const char *dirpath)
128 {
129         char default_storage[PATH_MAX + 1] = {0, };
130         char media_storage[PATH_MAX + 1] = {0, };
131         char external_storage[PATH_MAX + 1] = {0, };
132         char apps_storage[PATH_MAX + 1] = {0, };
133         char resolved_path[PATH_MAX + 1] = {0 , };
134         char *res = NULL;
135         char *pkg_id = NULL;
136         const char *temp = NULL;
137         int end = 0;
138
139         res = realpath(dirpath, NULL);
140         if (res == NULL) {
141                 TRACE_ERROR("Failed to get absolute path");
142                 return DP_ERROR_INVALID_DESTINATION;
143         }
144
145         strncpy(resolved_path, res, PATH_MAX - 1);
146         free(res);
147
148         end = strlen(resolved_path) - 1;
149         if (resolved_path[end] != '/')
150                 resolved_path[end + 1] = '/';
151
152         TRACE_INFO("%s -> %s", dirpath, resolved_path);
153
154         // Check whether directory is exist or not.
155         if (dp_is_exist_dir(resolved_path) < 0) {
156                 TRACE_ERROR("%s is not exist.", resolved_path);
157                 return DP_ERROR_INVALID_DESTINATION;
158         }
159
160         tzplatform_set_user(cred.uid);
161
162         // Check whether directory is default directory or not.
163         temp = tzplatform_getenv(TZ_USER_DOWNLOADS);
164         if (temp) {
165                 snprintf(default_storage, PATH_MAX - 1, "%s/", temp);
166                 if (strncmp(resolved_path, default_storage,
167                                         strlen(default_storage)) == 0)
168                                 return DP_ERROR_NONE;
169                 temp = NULL;
170         }
171
172         // Check permission: media storage
173         temp = tzplatform_getenv(TZ_USER_CONTENT);
174         if (temp) {
175                 snprintf(media_storage, PATH_MAX - 1, "%s/", temp);
176                 if (strncmp(resolved_path, media_storage,
177                                         strlen(media_storage)) == 0) {
178                         if (_dp_check_dir_permission(cred, MEDIA_STORAGE_PRIVILEGE) < 0) {
179                                 TRACE_ERROR("Permission denied: %s needs %s privilege",
180                                                 resolved_path, MEDIA_STORAGE_PRIVILEGE);
181                                 return DP_ERROR_INVALID_DESTINATION;
182                         }
183                         return DP_ERROR_NONE;
184                 }
185                 temp = NULL;
186         }
187
188         // Check permission: external storage
189         temp = tzplatform_getenv(TZ_SYS_STORAGE);
190         if (temp) {
191                 snprintf(external_storage, PATH_MAX - 1, "%s/", temp);
192                 if (strncmp(resolved_path, external_storage,
193                                         strlen(external_storage)) == 0) {
194                         if (_dp_check_dir_permission(cred, EXTERNAL_STORAGE_PRIVILEGE) < 0) {
195                                 TRACE_ERROR("Permission denied: %s needs %s privilege",
196                                                 resolved_path, EXTERNAL_STORAGE_PRIVILEGE);
197                                 return DP_ERROR_INVALID_DESTINATION;
198                         }
199                         return DP_ERROR_NONE;
200                 }
201                 temp = NULL;
202         }
203
204         // Check permission: private storage
205         temp = tzplatform_getenv(TZ_USER_APP);
206         if (temp) {
207                 snprintf(apps_storage, PATH_MAX - 1, "%s/", temp);
208                 if (strncmp(resolved_path, apps_storage,
209                                         strlen(apps_storage)) == 0) {
210                         pkg_id = _dp_get_pkg_id(cred);
211                         if (!pkg_id)
212                                 return DP_ERROR_INVALID_DESTINATION;
213
214                         TRACE_INFO("pkg_id: %s", pkg_id);
215                         if (strncmp(resolved_path + strlen(apps_storage) + 2,
216                                                 pkg_id, strlen(pkg_id)) != 0) {
217                                 TRACE_ERROR("Permission denied");
218                                 free(pkg_id);
219                                 return DP_ERROR_INVALID_DESTINATION;
220                         }
221                         free(pkg_id);
222                         return DP_ERROR_NONE;
223                 }
224                 temp = NULL;
225         }
226
227         return DP_ERROR_INVALID_DESTINATION;
228 }
229
230 void dp_rebuild_dir(const char *dirpath, mode_t mode)
231 {
232         if (dp_is_exist_dir(dirpath) < 0) {
233                 if (mkdir(dirpath, mode) == 0)
234                         TRACE_INFO("check directory:%s", dirpath);
235                 else
236                         TRACE_ERROR("failed to create directory:%s", dirpath);
237         }
238 }
239
240 int dp_check_permission(int clientfd, const char *pkgname)
241 {
242         int ret;
243         int result = DP_ERROR_NONE;
244         cynara *p_cynara = NULL;
245         cynara_configuration *p_conf = NULL;
246         size_t cache_size = 100;
247         const char *client_session = "";
248         char *client_smack = NULL;
249         char *uid = NULL;
250
251         TRACE_DEBUG("clientfd[%d] pkgname[%s]", clientfd, pkgname);
252         if (CYNARA_API_SUCCESS != cynara_configuration_create(&p_conf)) {
253                 TRACE_DEBUG("failed to create cynara configuration");
254                 result = DP_ERROR_PERMISSION_DENIED;
255                 goto DONE;
256         }
257
258         if (CYNARA_API_SUCCESS != cynara_configuration_set_cache_size(p_conf, cache_size)) {
259                 TRACE_DEBUG("failed to set cache size");
260                 result = DP_ERROR_PERMISSION_DENIED;
261                 goto DONE;
262         }
263
264         ret = cynara_initialize(&p_cynara, NULL);
265         if (ret != CYNARA_API_SUCCESS) {
266                 TRACE_DEBUG("failed to initialize cynara");
267                 result = DP_ERROR_PERMISSION_DENIED;
268                 goto DONE;
269         }
270
271         // Get client peer credential
272         ret = cynara_creds_socket_get_client(clientfd, CLIENT_METHOD_SMACK, &client_smack);
273         if (ret != CYNARA_API_SUCCESS) {
274                 TRACE_DEBUG("failed to createsa client identification string");
275                 result = DP_ERROR_PERMISSION_DENIED;
276                 goto DONE;
277         }
278
279         ret = cynara_creds_socket_get_user(clientfd, USER_METHOD_UID, &uid);
280         if (ret != CYNARA_API_SUCCESS) {
281                 TRACE_DEBUG("failed to create a user identification string");
282                 result = DP_ERROR_PERMISSION_DENIED;
283                 goto DONE;
284         }
285
286         // Cynara check
287         ret = cynara_check(p_cynara, client_smack, client_session, uid, DOWNLOAD_PRIVILEGE);
288         if (ret == CYNARA_API_ACCESS_ALLOWED) {
289                 TRACE_DEBUG("CYNARA_API_ACCESS_ALLOWED");
290         } else {
291                 TRACE_DEBUG("DP_ERROR_PERMISSION_DENIED");
292                 result = DP_ERROR_PERMISSION_DENIED;
293         }
294
295 DONE:
296         if (p_conf)
297                 cynara_configuration_destroy(p_conf);
298         if (p_cynara)
299                 cynara_finish(p_cynara);
300         free(client_smack);
301         free(uid);
302         return result;
303 }