/* * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "download-provider-security.h" #define MAX_ARRAY_LEN 1024 #define SECURITY_ATTRIBUTES_PATH "/proc/%d/attr/current" #define TEMP_DIR "/tmp/" #define LEGACY_USER_APP "/opt/usr/apps/" static int dp_is_exist_dir(const char *dirpath) { struct stat dir_state; int stat_ret; if (dirpath == NULL) { TRACE_ERROR("check path"); return -1; } stat_ret = stat(dirpath, &dir_state); if (stat_ret == 0 && S_ISDIR(dir_state.st_mode)) return 0; return -1; } static char *_dp_get_pkg_id(dp_credential cred) { char *app_id = NULL; char *pkg_id = NULL; app_info_h app_info = NULL; if (app_manager_get_app_id(cred.pid, &app_id) != APP_MANAGER_ERROR_NONE) { TRACE_ERROR("Failed to get application ID"); return NULL; } if (app_info_create(app_id, &app_info) != APP_MANAGER_ERROR_NONE) { TRACE_ERROR("Failed to create app_info"); free(app_id); return NULL; } if (app_info_get_package(app_info, &pkg_id) != APP_MANAGER_ERROR_NONE) { TRACE_ERROR("Failed to get package ID"); app_info_destroy(app_info); free(app_id); free(pkg_id); return NULL; } app_info_destroy(app_info); free(app_id); return pkg_id; } static int _dp_check_dir_permission(dp_credential cred, const char *privilege) { FILE *fd; int ret; char client_smack[MAX_ARRAY_LEN + 1] = {0, }; char client_smack_path[MAX_ARRAY_LEN + 1] = {0, }; char uid[20] = {0, }; char *client_session = ""; cynara *p_cynara = NULL; if (CYNARA_API_SUCCESS != cynara_initialize(&p_cynara, NULL)) { TRACE_ERROR("Failed to initialize cynara structure\n"); return -1; } snprintf(client_smack_path, MAX_ARRAY_LEN, SECURITY_ATTRIBUTES_PATH, cred.pid); fd = fopen(client_smack_path, "r"); if (fd == NULL) { TRACE_ERROR("Failed to open %s", client_smack_path); cynara_finish(p_cynara); return -1; } ret = fread(client_smack, 1, MAX_ARRAY_LEN, fd); if (ferror(fd)) { TRACE_ERROR("Failed to read %s", client_smack_path); fclose(fd); cynara_finish(p_cynara); return -1; } fclose(fd); client_smack[ret] = '\0'; snprintf(uid, sizeof(uid), "%d", cred.uid); TRACE_DEBUG("pid: %d, uid: %s, checked privilege:%s", cred.pid, uid, privilege); ret = cynara_check(p_cynara, client_smack, client_session, uid, privilege); cynara_finish(p_cynara); return (ret == CYNARA_API_ACCESS_ALLOWED) ? 0 : -1; } int dp_is_valid_dir(dp_credential cred, const char *dirpath) { char default_storage[PATH_MAX + 1] = {0, }; char media_storage[PATH_MAX + 1] = {0, }; char external_storage[PATH_MAX + 1] = {0, }; char apps_storage[PATH_MAX + 1] = {0, }; char resolved_path[PATH_MAX + 1] = {0 , }; char *res = NULL; char *pkg_id = NULL; const char *temp = NULL; int end = 0; res = realpath(dirpath, NULL); if (res == NULL) { TRACE_ERROR("Failed to get absolute path"); return DP_ERROR_INVALID_DESTINATION; } strncpy(resolved_path, res, sizeof(resolved_path) - 1); free(res); end = strlen(resolved_path) - 1; if (resolved_path[end] != '/') resolved_path[end + 1] = '/'; TRACE_INFO("%s -> %s", dirpath, resolved_path); // Check whether directory is exist or not. if (dp_is_exist_dir(resolved_path) < 0) { TRACE_ERROR("%s is not exist.", resolved_path); return DP_ERROR_INVALID_DESTINATION; } // Check whether directory is temporary directory or not. if (strncmp(resolved_path, TEMP_DIR, strlen(TEMP_DIR)) == 0) return DP_ERROR_NONE; tzplatform_set_user(cred.uid); // Check whether directory is default directory or not. temp = tzplatform_getenv(TZ_USER_DOWNLOADS); if (temp) { snprintf(default_storage, sizeof(default_storage) - 1, "%s/", temp); if (strncmp(resolved_path, default_storage, strlen(default_storage)) == 0) return DP_ERROR_NONE; temp = NULL; } // Check permission: media storage temp = tzplatform_getenv(TZ_USER_CONTENT); if (temp) { snprintf(media_storage, sizeof(media_storage) - 1, "%s/", temp); if (strncmp(resolved_path, media_storage, strlen(media_storage)) == 0) { if (_dp_check_dir_permission(cred, MEDIA_STORAGE_PRIVILEGE) < 0) { TRACE_ERROR("Permission denied: %s needs %s privilege", resolved_path, MEDIA_STORAGE_PRIVILEGE); return DP_ERROR_INVALID_DESTINATION; } return DP_ERROR_NONE; } temp = NULL; } // Check permission: external storage temp = tzplatform_getenv(TZ_SYS_STORAGE); if (temp) { snprintf(external_storage, sizeof(external_storage) - 1, "%s/", temp); if (strncmp(resolved_path, external_storage, strlen(external_storage)) == 0) { if (_dp_check_dir_permission(cred, EXTERNAL_STORAGE_PRIVILEGE) < 0) { TRACE_ERROR("Permission denied: %s needs %s privilege", resolved_path, EXTERNAL_STORAGE_PRIVILEGE); return DP_ERROR_INVALID_DESTINATION; } return DP_ERROR_NONE; } temp = NULL; } // Check permission: private storage if (strncmp(resolved_path, LEGACY_USER_APP, strlen(LEGACY_USER_APP)) == 0) { // Some applications use a legacy app path. snprintf(apps_storage, sizeof(apps_storage) - 1, "%s", LEGACY_USER_APP); } else { temp = tzplatform_getenv(TZ_USER_APP); snprintf(apps_storage, sizeof(apps_storage) - 1, "%s/", temp); temp = NULL; } if (strlen(apps_storage) > 0) { if (strncmp(resolved_path, apps_storage, strlen(apps_storage)) == 0) { pkg_id = _dp_get_pkg_id(cred); if (!pkg_id) return DP_ERROR_INVALID_DESTINATION; TRACE_INFO("pkg_id: %s", pkg_id); if (strncmp(resolved_path + strlen(apps_storage), pkg_id, strlen(pkg_id)) != 0) { TRACE_ERROR("Permission denied"); free(pkg_id); return DP_ERROR_INVALID_DESTINATION; } free(pkg_id); return DP_ERROR_NONE; } } // Check whether directory is shared directory or not. temp = tzplatform_getenv(TZ_USER_SHARE); if (temp) { if (strncmp(resolved_path, temp, strlen(temp)) == 0) return DP_ERROR_NONE; temp = NULL; } return DP_ERROR_INVALID_DESTINATION; } void dp_rebuild_dir(const char *dirpath, mode_t mode) { if (dp_is_exist_dir(dirpath) < 0) { if (mkdir(dirpath, mode) == 0) TRACE_INFO("check directory:%s", dirpath); else TRACE_ERROR("failed to create directory:%s", dirpath); } } int dp_check_permission(int clientfd, const char *pkgname) { int ret; int result = DP_ERROR_NONE; cynara *p_cynara = NULL; cynara_configuration *p_conf = NULL; size_t cache_size = 100; const char *client_session = ""; char *client_smack = NULL; char *uid = NULL; TRACE_DEBUG("clientfd[%d] pkgname[%s]", clientfd, pkgname); if (CYNARA_API_SUCCESS != cynara_configuration_create(&p_conf)) { TRACE_DEBUG("failed to create cynara configuration"); result = DP_ERROR_PERMISSION_DENIED; goto DONE; } if (CYNARA_API_SUCCESS != cynara_configuration_set_cache_size(p_conf, cache_size)) { TRACE_DEBUG("failed to set cache size"); result = DP_ERROR_PERMISSION_DENIED; goto DONE; } ret = cynara_initialize(&p_cynara, NULL); if (ret != CYNARA_API_SUCCESS) { TRACE_DEBUG("failed to initialize cynara"); result = DP_ERROR_PERMISSION_DENIED; goto DONE; } // Get client peer credential ret = cynara_creds_socket_get_client(clientfd, CLIENT_METHOD_SMACK, &client_smack); if (ret != CYNARA_API_SUCCESS) { TRACE_DEBUG("failed to createsa client identification string"); result = DP_ERROR_PERMISSION_DENIED; goto DONE; } ret = cynara_creds_socket_get_user(clientfd, USER_METHOD_UID, &uid); if (ret != CYNARA_API_SUCCESS) { TRACE_DEBUG("failed to create a user identification string"); result = DP_ERROR_PERMISSION_DENIED; goto DONE; } // Cynara check ret = cynara_check(p_cynara, client_smack, client_session, uid, DOWNLOAD_PRIVILEGE); if (ret == CYNARA_API_ACCESS_ALLOWED) { TRACE_DEBUG("CYNARA_API_ACCESS_ALLOWED"); } else { TRACE_DEBUG("DP_ERROR_PERMISSION_DENIED"); result = DP_ERROR_PERMISSION_DENIED; } DONE: if (p_conf) cynara_configuration_destroy(p_conf); if (p_cynara) cynara_finish(p_cynara); free(client_smack); free(uid); return result; }