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