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.
28 #include <sys/smack.h>
34 #include "privilege-control.h"
36 /* TODO: implement such function in libsmack instead */
37 int smack_label_is_valid(const char *smack_label)
39 SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s",
40 __func__, smack_label);
44 if(!smack_label || smack_label[0] == '\0' || smack_label[0] == '-')
47 for(i = 0; smack_label[i]; ++i) {
48 if(i >= SMACK_LABEL_LEN)
50 switch(smack_label[i]) {
65 SECURE_C_LOGE("Invalid SMACK label %s", smack_label);
69 /* TODO: implement this function correctly using compilation flags for both Tizen IVI and Mobile */
70 const char* generate_app_label(const char *pkg_id UNUSED)
72 char *label = strdup("User");
74 C_LOGE("Cannot allocate memory for app label");
81 int set_exec_label(const char *label, const char *path)
85 if(stat(path, &st) < 0) {
86 SECURE_C_LOGE("stat failed for %s (Error = %s)", path, strerror(errno));
87 return PC_ERR_FILE_OPERATION;
90 // check if it's a link
91 if((st.st_mode & S_IFLNK) != 0) {
92 SECURE_C_LOGD("%s is a symbolic link", path);
93 char* target AUTO_FREE;
94 target = realpath(path, NULL);
96 SECURE_C_LOGE("getting link target for %s failed (Error = %s)",
97 path, strerror(errno));
98 return PC_ERR_FILE_OPERATION;
101 if(stat(target, &st) < 0) {
102 SECURE_C_LOGE("stat failed for %s (Error = %s)", target, strerror(errno));
103 return PC_ERR_FILE_OPERATION;
106 if((st.st_mode & (S_IXUSR | S_IFREG)) != (S_IXUSR | S_IFREG)) {
107 SECURE_C_LOGE("%s is not a regular executable file.", target);
108 return PC_ERR_FILE_OPERATION;
110 } else if((st.st_mode & (S_IXUSR | S_IFREG)) != (S_IXUSR | S_IFREG)) {
111 SECURE_C_LOGE("%s is not a regular executable file nor a symbolic link.", path);
112 return PC_ERR_FILE_OPERATION;
115 SECURE_C_LOGD("smack_lsetlabel (label: %s (type: SMACK_LABEL_EXEC), path: %s)",
117 if (smack_lsetlabel(path, label, SMACK_LABEL_EXEC) != 0) {
118 SECURE_C_LOGE("smack_lsetlabel failed.");
119 return PC_ERR_FILE_OPERATION;
121 return PC_OPERATION_SUCCESS;
125 int tokenize_rule(const char *const s_rule,
130 char tmp_s_dump[2] = "\0";
133 ret = sscanf(s_rule, "%" TOSTRING(SMACK_LABEL_LEN) "s%*[ \t\n\r]%" TOSTRING(SMACK_LABEL_LEN)
134 "s%*[ \t\n\r]%" TOSTRING(ACC_LEN) "s%1s", s_subject, s_object,s_access,
138 C_LOGE("RDB: Failed to tokenize the rule: <%s>. %d tokens needed, %d found.",
140 return PC_ERR_INVALID_OPERATION;
143 return PC_OPERATION_SUCCESS;
147 bool is_wildcard(const char *const s_label)
149 return !strcmp(s_label, "~ALL_APPS~") ||
150 !strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~") ||
151 !strcmp(s_label, "~PUBLIC_PATH~") ||
152 !strcmp(s_label, "~GROUP_PATH~") ||
153 !strcmp(s_label, "~SETTINGS_PATH~");
157 int parse_rule(const char *const s_rule,
162 int ret = PC_OPERATION_SUCCESS;
163 char tmp_s_subject[SMACK_LABEL_LEN + 1];
164 char tmp_s_object[SMACK_LABEL_LEN + 1];
165 char tmp_s_access[ACC_LEN + 1];
167 bool b_subject_is_template;
168 bool b_object_is_template;
171 ret = tokenize_rule(s_rule, tmp_s_subject, tmp_s_object, tmp_s_access);
172 if(ret != PC_OPERATION_SUCCESS) return ret;
174 // Check SMACK_APP_LABEL_TEMPLATE
175 b_subject_is_template = (bool) !strcmp(tmp_s_subject, SMACK_APP_LABEL_TEMPLATE);
176 b_object_is_template = (bool) !strcmp(tmp_s_object, SMACK_APP_LABEL_TEMPLATE);
177 if((b_subject_is_template && b_object_is_template) ||
178 (!b_subject_is_template && !b_object_is_template)) {
179 C_LOGE("RDB: Incorrect rule format in rule: %s", s_rule);
180 ret = PC_ERR_INVALID_PARAM;
184 // Check label validity and copy rules
185 if(b_subject_is_template) {
187 if(!smack_label_is_valid(tmp_s_object) &&
188 !is_wildcard(tmp_s_object)) {
189 C_LOGE("RDB: Incorrect subject label: %s", tmp_s_object);
192 strcpy(s_label, tmp_s_object);
193 if(pi_is_reverse != NULL) *pi_is_reverse = 0;
194 } else if(b_object_is_template) {
196 if(!smack_label_is_valid(tmp_s_subject) &&
197 !is_wildcard(tmp_s_subject)) {
198 C_LOGE("RDB: Incorrect subject label: %s", tmp_s_subject);
201 strcpy(s_label, tmp_s_subject);
202 if(pi_is_reverse != NULL) *pi_is_reverse = 1;
204 strcpy(s_access, tmp_s_access);
206 return PC_OPERATION_SUCCESS;
210 int validate_all_rules(const char *const *const pp_permissions_list)
213 char s_label[SMACK_LABEL_LEN + 1];
214 char s_access[ACC_LEN + 1];
216 // Parse and check rules.
217 for(i = 0; pp_permissions_list[i] != NULL; ++i) {
218 // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
220 // Ignore empty lines
221 if(strspn(pp_permissions_list[i], " \t\n")
222 == strlen(pp_permissions_list[i]))
225 if(parse_rule(pp_permissions_list[i], s_label, s_access, NULL)
226 != PC_OPERATION_SUCCESS) {
227 C_LOGE("RDB: Invalid parameter");
228 return PC_ERR_INVALID_PARAM;
231 // Check the other label
232 if(!is_wildcard(s_label) &&
233 !smack_label_is_valid(s_label)) {
234 C_LOGE("RDB: Incorrect object label: %s", s_label);
235 return PC_ERR_INVALID_PARAM;
239 return PC_OPERATION_SUCCESS;
242 /* Auto cleanup stuff */
254 void fclosep(FILE **f)
260 void fts_closep(FTS **f)
267 static int load_smack_from_file_generic(const char *app_id, struct smack_accesses **smack, int *fd, char **path, bool is_early)
269 /* Notice that app_id is ignored when flag is_early is set.
270 * It's because all of the "early rules" (for all apps) should
271 * be in one common file: SMACK_STARTUP_RULES_FILE
273 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
279 if(0 > asprintf(path, "%s", SMACK_STARTUP_RULES_FILE)) {
281 C_LOGE("asprintf failed.");
282 return PC_ERR_MEM_OPERATION;
285 ret = smack_file_name(app_id, path);
286 if(ret != PC_OPERATION_SUCCESS)
290 if(smack_accesses_new(smack)) {
291 C_LOGE("smack_accesses_new failed.");
292 return PC_ERR_MEM_OPERATION;
295 *fd = open(*path, O_CREAT | O_RDWR, 0644);
297 C_LOGE("file open failed (error: %s)", strerror(errno));
298 return PC_ERR_FILE_OPERATION;
301 if(flock(*fd, LOCK_EX)) {
302 C_LOGE("flock failed");
303 return PC_ERR_INVALID_OPERATION;
306 if(smack_accesses_add_from_file(*smack, *fd)) {
307 C_LOGE("smack_accesses_add_from_file failed.");
308 return PC_ERR_INVALID_OPERATION;
311 /* Rewind the file */
312 if(lseek(*fd, 0, SEEK_SET) == -1) {
313 C_LOGE("lseek failed.");
314 return PC_ERR_FILE_OPERATION;
317 return PC_OPERATION_SUCCESS;
320 int load_smack_from_file(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
322 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
325 return load_smack_from_file_generic(app_id, smack, fd, path, 0);
328 int load_smack_from_file_early(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
330 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
333 return load_smack_from_file_generic(app_id, smack, fd, path, 1);
336 int smack_mark_file_name(const char *app_id, char **path)
338 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
341 if(asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
342 C_LOGE("asprintf failed.");
344 return PC_ERR_MEM_OPERATION;
347 return PC_OPERATION_SUCCESS;
350 bool file_exists(const char *path)
352 SECURE_C_LOGD("Entering function: %s. Params: path=%s",
355 SECURE_C_LOGD("Opening file %s.", path);
356 FILE *file = fopen(path, "r");
364 int smack_file_name(const char *app_id, char **path)
366 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
369 if(asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
370 C_LOGE("asprintf failed.");
372 return PC_ERR_MEM_OPERATION;
375 return PC_OPERATION_SUCCESS;
380 SECURE_C_LOGD("Entering function: %s.", __func__);
382 static int have_smack = -1;
384 if(-1 == have_smack) {
385 if(NULL == smack_smackfs_path()) {
386 C_LOGD("Libprivilege-control: no smack found on phone");
389 C_LOGD("Libprivilege-control: found smack on phone");
397 inline const char* app_type_name(app_type_t app_type)
399 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
404 C_LOGD("App type = WRT");
407 C_LOGD("App type = OSP");
410 C_LOGD("App type = EFL");
413 C_LOGD("App type = other");
418 inline const char* app_type_group_name(app_type_t app_type)
420 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
425 C_LOGD("App type group name = WRT");
428 C_LOGD("App type group name = OST");
431 C_LOGD("App type = EFL");
439 * This function changes permission URI to basename for file name.
440 * For e.g. from http://tizen.org/privilege/contact.read will be
441 * created basename : org.tizen.privilege.contact.read
443 int base_name_from_perm(const char *s_perm, char **ps_name)
445 SECURE_C_LOGD("Entering function: %s. Params: perm=%s",
448 iri_t *piri_parsed = NULL;
449 char *pc_rest_slash = NULL;
451 piri_parsed = iri_parse(s_perm);
452 if (piri_parsed == NULL || piri_parsed->host == NULL) {
453 SECURE_C_LOGE("Bad permission format : %s", s_perm);
454 iri_destroy(piri_parsed);
455 return PC_ERR_INVALID_PARAM;
458 size_t i_host_size = strlen(piri_parsed->host);
459 if(i_host_size > INT_MAX) {
460 SECURE_C_LOGE("Permission name too long : %zu", i_host_size);
461 iri_destroy(piri_parsed);
462 return PC_ERR_INVALID_PARAM;
465 size_t i_path_start = 0;
466 char *pc_host_dot = NULL;
468 if(piri_parsed->path) {
469 pc_host_dot = strrchr(piri_parsed->host, '.');
470 i_path_start = i_host_size;
473 int ret = asprintf(ps_name, "%s%s%.*s%s",
474 pc_host_dot ? pc_host_dot + 1 : "",
475 pc_host_dot ? "." : "",
476 pc_host_dot ? (int)(pc_host_dot - piri_parsed->host) : (int)i_host_size,
478 piri_parsed->path ? piri_parsed->path : "");
480 C_LOGE("asprintf failed");
481 iri_destroy(piri_parsed);
482 return PC_ERR_MEM_OPERATION;
485 pc_rest_slash = *ps_name + i_path_start;
486 while ((pc_rest_slash = strchr(pc_rest_slash, '/'))) {
487 *pc_rest_slash = '.';
490 iri_destroy(piri_parsed);
491 return PC_OPERATION_SUCCESS;