4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
6 * Contact: Rafal Krypa <r.krypa@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
27 #include <sys/smack.h>
33 #include "privilege-control.h"
35 /* TODO: implement such function in libsmack instead */
36 int smack_label_is_valid(const char *smack_label)
38 SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s",
39 __func__, smack_label);
43 if(!smack_label || smack_label[0] == '\0' || smack_label[0] == '-')
46 for(i = 0; smack_label[i]; ++i) {
47 if(i >= SMACK_LABEL_LEN)
49 switch(smack_label[i]) {
64 SECURE_C_LOGE("Invalid SMACK label %s", smack_label);
69 int set_exec_label(const char *label, const char *path)
73 if(stat(path, &st) < 0) {
74 SECURE_C_LOGE("stat failed for %s (Error = %s)", path, strerror(errno));
75 return PC_ERR_FILE_OPERATION;
78 // check if it's a link
79 if((st.st_mode & S_IFLNK) != 0) {
80 SECURE_C_LOGD("%s is a symbolic link", path);
81 char* target AUTO_FREE;
82 target = realpath(path, NULL);
84 SECURE_C_LOGE("getting link target for %s failed (Error = %s)",
85 path, strerror(errno));
86 return PC_ERR_FILE_OPERATION;
89 if(stat(target, &st) < 0) {
90 SECURE_C_LOGE("stat failed for %s (Error = %s)", target, strerror(errno));
91 return PC_ERR_FILE_OPERATION;
94 if((st.st_mode & (S_IXUSR | S_IFREG)) != (S_IXUSR | S_IFREG)) {
95 SECURE_C_LOGE("%s is not a regular executable file.", target);
96 return PC_ERR_FILE_OPERATION;
98 } else if((st.st_mode & (S_IXUSR | S_IFREG)) != (S_IXUSR | S_IFREG)) {
99 SECURE_C_LOGE("%s is not a regular executable file nor a symbolic link.", path);
100 return PC_ERR_FILE_OPERATION;
103 SECURE_C_LOGD("smack_lsetlabel (label: %s (type: SMACK_LABEL_EXEC), path: %s)",
105 if (smack_lsetlabel(path, label, SMACK_LABEL_EXEC) != 0) {
106 SECURE_C_LOGE("smack_lsetlabel failed.");
107 return PC_ERR_FILE_OPERATION;
109 return PC_OPERATION_SUCCESS;
113 int tokenize_rule(const char *const s_rule,
118 char tmp_s_dump[2] = "\0";
121 ret = sscanf(s_rule, "%" TOSTRING(SMACK_LABEL_LEN) "s%*[ \t\n\r]%" TOSTRING(SMACK_LABEL_LEN)
122 "s%*[ \t\n\r]%" TOSTRING(ACC_LEN) "s%1s", s_subject, s_object,s_access,
126 C_LOGE("RDB: Failed to tokenize the rule: <%s>. %d tokens needed, %d found.",
128 return PC_ERR_INVALID_OPERATION;
131 return PC_OPERATION_SUCCESS;
135 bool is_wildcard(const char *const s_label)
137 return !strcmp(s_label, "~ALL_APPS~") ||
138 !strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~") ||
139 !strcmp(s_label, "~PUBLIC_PATH~") ||
140 !strcmp(s_label, "~GROUP_PATH~") ||
141 !strcmp(s_label, "~SETTINGS_PATH~") ||
142 !strcmp(s_label, "~NPRUNTIME_PATH~");
146 int parse_rule(const char *const s_rule,
151 int ret = PC_OPERATION_SUCCESS;
152 char tmp_s_subject[SMACK_LABEL_LEN + 1];
153 char tmp_s_object[SMACK_LABEL_LEN + 1];
154 char tmp_s_access[ACC_LEN + 1];
156 bool b_subject_is_template;
157 bool b_object_is_template;
160 ret = tokenize_rule(s_rule, tmp_s_subject, tmp_s_object, tmp_s_access);
161 if(ret != PC_OPERATION_SUCCESS) return ret;
163 // Check SMACK_APP_LABEL_TEMPLATE
164 b_subject_is_template = (bool) !strcmp(tmp_s_subject, SMACK_APP_LABEL_TEMPLATE);
165 b_object_is_template = (bool) !strcmp(tmp_s_object, SMACK_APP_LABEL_TEMPLATE);
166 if((b_subject_is_template && b_object_is_template) ||
167 (!b_subject_is_template && !b_object_is_template)) {
168 C_LOGE("RDB: Incorrect rule format in rule: %s", s_rule);
169 ret = PC_ERR_INVALID_PARAM;
173 // Check label validity and copy rules
174 if(b_subject_is_template) {
176 if(!smack_label_is_valid(tmp_s_object) &&
177 !is_wildcard(tmp_s_object)) {
178 C_LOGE("RDB: Incorrect subject label: %s", tmp_s_object);
181 strcpy(s_label, tmp_s_object);
182 if(pi_is_reverse != NULL) *pi_is_reverse = 0;
183 } else if(b_object_is_template) {
185 if(!smack_label_is_valid(tmp_s_subject) &&
186 !is_wildcard(tmp_s_subject)) {
187 C_LOGE("RDB: Incorrect subject label: %s", tmp_s_subject);
190 strcpy(s_label, tmp_s_subject);
191 if(pi_is_reverse != NULL) *pi_is_reverse = 1;
193 strcpy(s_access, tmp_s_access);
195 return PC_OPERATION_SUCCESS;
199 int validate_all_rules(const char *const *const pp_permissions_list)
202 char s_label[SMACK_LABEL_LEN + 1];
203 char s_access[ACC_LEN + 1];
205 // Parse and check rules.
206 for(i = 0; pp_permissions_list[i] != NULL; ++i) {
207 // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
209 // Ignore empty lines
210 if(strspn(pp_permissions_list[i], " \t\n")
211 == strlen(pp_permissions_list[i]))
214 if(parse_rule(pp_permissions_list[i], s_label, s_access, NULL)
215 != PC_OPERATION_SUCCESS) {
216 C_LOGE("RDB: Invalid parameter");
217 return PC_ERR_INVALID_PARAM;
220 // Check the other label
221 if(!is_wildcard(s_label) &&
222 !smack_label_is_valid(s_label)) {
223 C_LOGE("RDB: Incorrect object label: %s", s_label);
224 return PC_ERR_INVALID_PARAM;
228 return PC_OPERATION_SUCCESS;
231 /* Auto cleanup stuff */
243 void fclosep(FILE **f)
249 void smack_freep(struct smack_accesses **smack)
251 smack_accesses_free(*smack);
254 void fts_closep(FTS **f)
261 static int load_smack_from_file_generic(const char *app_id, struct smack_accesses **smack, int *fd, char **path, bool is_early)
263 /* Notice that app_id is ignored when flag is_early is set.
264 * It's because all of the "early rules" (for all apps) should
265 * be in one common file: SMACK_STARTUP_RULES_FILE
267 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
273 if(0 > asprintf(path, "%s", SMACK_STARTUP_RULES_FILE)) {
275 C_LOGE("asprintf failed.");
276 return PC_ERR_MEM_OPERATION;
279 ret = smack_file_name(app_id, path);
280 if(ret != PC_OPERATION_SUCCESS)
284 if(smack_accesses_new(smack)) {
285 C_LOGE("smack_accesses_new failed.");
286 return PC_ERR_MEM_OPERATION;
289 *fd = open(*path, O_CREAT | O_RDWR, 0644);
291 C_LOGE("file open failed (error: %s)", strerror(errno));
292 return PC_ERR_FILE_OPERATION;
295 if(flock(*fd, LOCK_EX)) {
296 C_LOGE("flock failed");
297 return PC_ERR_INVALID_OPERATION;
300 if(smack_accesses_add_from_file(*smack, *fd)) {
301 C_LOGE("smack_accesses_add_from_file failed.");
302 return PC_ERR_INVALID_OPERATION;
305 /* Rewind the file */
306 if(lseek(*fd, 0, SEEK_SET) == -1) {
307 C_LOGE("lseek failed.");
308 return PC_ERR_FILE_OPERATION;
311 return PC_OPERATION_SUCCESS;
314 int load_smack_from_file(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
316 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
319 return load_smack_from_file_generic(app_id, smack, fd, path, 0);
322 int load_smack_from_file_early(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
324 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
327 return load_smack_from_file_generic(app_id, smack, fd, path, 1);
330 int smack_mark_file_name(const char *app_id, char **path)
332 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
335 if(asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
336 C_LOGE("asprintf failed.");
338 return PC_ERR_MEM_OPERATION;
341 return PC_OPERATION_SUCCESS;
344 bool file_exists(const char *path)
346 SECURE_C_LOGD("Entering function: %s. Params: path=%s",
349 SECURE_C_LOGD("Opening file %s.", path);
350 FILE *file = fopen(path, "r");
358 int smack_file_name(const char *app_id, char **path)
360 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
363 if(asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
364 C_LOGE("asprintf failed.");
366 return PC_ERR_MEM_OPERATION;
369 return PC_OPERATION_SUCCESS;
372 inline int have_smack(void)
374 SECURE_C_LOGD("Entering function: %s.", __func__);
376 static int have_smack = -1;
378 if(-1 == have_smack) {
379 if(NULL == smack_smackfs_path()) {
380 C_LOGD("Libprivilege-control: no smack found on phone");
383 C_LOGD("Libprivilege-control: found smack on phone");
391 inline const char* app_type_name(app_type_t app_type)
393 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
397 case PERM_APP_TYPE_WRT:
398 C_LOGD("App type = WRT");
400 case PERM_APP_TYPE_OSP:
401 C_LOGD("App type = OSP");
403 case PERM_APP_TYPE_WRT_PARTNER:
404 C_LOGD("App type = WRT_partner");
405 return "WRT_partner";
406 case PERM_APP_TYPE_WRT_PLATFORM:
407 C_LOGD("App type = WRT_platform");
408 return "WRT_platform";
409 case PERM_APP_TYPE_OSP_PARTNER:
410 C_LOGD("App type = OSP_partner");
411 return "OSP_partner";
412 case PERM_APP_TYPE_OSP_PLATFORM:
413 C_LOGD("App type = OSP_platform");
414 return "OSP_platform";
415 case PERM_APP_TYPE_EFL:
416 C_LOGD("App type = EFL");
419 C_LOGD("App type = other");
424 inline const char* app_type_group_name(app_type_t app_type)
426 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
430 case PERM_APP_TYPE_WRT:
431 case PERM_APP_TYPE_WRT_PARTNER:
432 case PERM_APP_TYPE_WRT_PLATFORM:
433 C_LOGD("App type group name = WRT");
435 case PERM_APP_TYPE_OSP:
436 case PERM_APP_TYPE_OSP_PARTNER:
437 case PERM_APP_TYPE_OSP_PLATFORM:
438 C_LOGD("App type group name = OST");
440 case PERM_APP_TYPE_EFL:
441 C_LOGD("App type = EFL");
448 const char* app_path_type_name(app_path_type_t app_path_type)
450 SECURE_C_LOGD("Entering function %s. Params: app_path_type=%d", __func__, app_path_type);
452 switch(app_path_type) {
453 case PERM_APP_PATH_GROUP:
455 case PERM_APP_PATH_PUBLIC:
456 return "PUBLIC_PATH";
457 case PERM_APP_PATH_SETTINGS:
458 return "SETTINGS_PATH";
459 case PERM_APP_PATH_NPRUNTIME:
460 return "NPRUNTIME_PATH";
461 case PERM_APP_PATH_PRIVATE:
462 case PERM_APP_PATH_ANY_LABEL:
464 // App path type not stored in the database, return NULL;
470 * This function changes permission URI to basename for file name.
471 * For e.g. from http://tizen.org/privilege/contact.read will be
472 * created basename : org.tizen.privilege.contact.read
474 int base_name_from_perm(const char *s_perm, char **ps_name)
476 SECURE_C_LOGD("Entering function: %s. Params: perm=%s",
479 iri_t *piri_parsed = NULL;
480 char *pc_rest_slash = NULL;
482 piri_parsed = iri_parse(s_perm);
483 if (piri_parsed == NULL || piri_parsed->host == NULL) {
484 SECURE_C_LOGE("Bad permission format : %s", s_perm);
485 iri_destroy(piri_parsed);
486 return PC_ERR_INVALID_PARAM;
489 ssize_t i_host_size = strlen(piri_parsed->host);
490 ssize_t i_path_start = 0;
491 char * pc_host_dot = NULL;
493 if(piri_parsed->path) {
494 pc_host_dot = strrchr(piri_parsed->host, '.');
495 i_path_start = i_host_size;
498 int ret = asprintf(ps_name, "%s%s%.*s%s",
499 pc_host_dot ? pc_host_dot + 1 : "",
500 pc_host_dot ? "." : "",
501 pc_host_dot ? pc_host_dot - piri_parsed->host : i_host_size,
503 piri_parsed->path ? piri_parsed->path : "");
505 C_LOGE("asprintf failed");
506 iri_destroy(piri_parsed);
507 return PC_ERR_MEM_OPERATION;
510 pc_rest_slash = *ps_name + i_path_start;
511 while ((pc_rest_slash = strchr(pc_rest_slash, '/'))) {
512 *pc_rest_slash = '.';
515 iri_destroy(piri_parsed);
516 return PC_OPERATION_SUCCESS;