X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fusr_sbin%2Feditpolicy.c;fp=src%2Fusr_sbin%2Feditpolicy.c;h=d264562079243031ba135f2cb984d28e24d6f6ad;hb=5b01f9264f6f68e990ce2b186580312422d87ca9;hp=cb555cde8a5a985364a999b0ef0d9d525e38a85b;hpb=f7a794388e4c37d6740072de1762c1f50e7bcc8e;p=gpet%2Forigin.git diff --git a/src/usr_sbin/editpolicy.c b/src/usr_sbin/editpolicy.c index cb555cd..d264562 100644 --- a/src/usr_sbin/editpolicy.c +++ b/src/usr_sbin/editpolicy.c @@ -3,9 +3,9 @@ * * TOMOYO Linux's utilities. * - * Copyright (C) 2005-2010 NTT DATA CORPORATION + * Copyright (C) 2005-2011 NTT DATA CORPORATION * - * Version: 1.8.0 2010/11/11 + * Version: 1.8.1 2011/04/01 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License v2 as published by the @@ -28,97 +28,153 @@ static char *gpet_line = NULL; #endif /* __GPET */ -/* Variables */ +/* Domain policy. */ +struct ccs_domain_policy ccs_dp = { }; -extern int ccs_persistent_fd; +/* Readline history. */ +static struct ccs_readline_data ccs_rl = { }; +/* File descriptor for offline mode. */ +int ccs_persistent_fd = EOF; + +/* Array of "path_group" entries. */ struct ccs_path_group_entry *ccs_path_group_list = NULL; +/* Length of ccs_path_group_list array. */ int ccs_path_group_list_len = 0; -struct ccs_generic_acl *ccs_generic_acl_list = NULL; -int ccs_generic_acl_list_count = 0; +/* Array of string ACL entries. */ +struct ccs_generic_acl *ccs_gacl_list = NULL; +/* Length of ccs_generic_list array. */ +int ccs_gacl_list_count = 0; +/* Policy directory. */ static const char *ccs_policy_dir = NULL; +/* Use ccs-editpolicy-agent program? */ static _Bool ccs_offline_mode = false; +/* Use readonly mode? */ static _Bool ccs_readonly_mode = false; +/* Refresh interval in second. 0 means no auto refresh. */ static unsigned int ccs_refresh_interval = 0; +/* Need to reload the screen due to auto refresh? */ static _Bool ccs_need_reload = false; +/* Policy file's name. */ static const char *ccs_policy_file = NULL; +/* Caption of the current screen. */ static const char *ccs_list_caption = NULL; +/* Currently selected domain. */ static char *ccs_current_domain = NULL; +/* Currently selected PID. */ static unsigned int ccs_current_pid = 0; -static int ccs_current_screen = CCS_SCREEN_DOMAIN_LIST; +/* Currently active screen's index. */ +enum ccs_screen_type ccs_current_screen = CCS_SCREEN_DOMAIN_LIST; +/* + * Array of "initialize_domain"/"no_initialize_domain"/"keep_domain"/ + * "no_keep_domain" entries. + */ static struct ccs_transition_control_entry *ccs_transition_control_list = NULL; +/* Length of ccs_transition_control_list array. */ static int ccs_transition_control_list_len = 0; -static int ccs_profile_sort_type = 0; +/* Sort profiles by value? */ +static _Bool ccs_profile_sort_type = false; +/* Number of domain initializer source domains. */ static int ccs_unnumbered_domain_count = 0; +/* Width of CUI screen. */ static int ccs_window_width = 0; +/* Height of CUI screen. */ static int ccs_window_height = 0; -static int ccs_current_item_index[CCS_MAXSCREEN]; -int ccs_current_y[CCS_MAXSCREEN]; -int ccs_list_item_count[CCS_MAXSCREEN]; +/* Cursor info for CUI screen. */ +struct ccs_screen ccs_screen[CCS_MAXSCREEN] = { }; +/* Number of entries available on current screen. */ +int ccs_list_item_count = 0; +/* Lines available for displaying ACL entries. */ static int ccs_body_lines = 0; -static int ccs_max_eat_col[CCS_MAXSCREEN]; +/* Columns to shift. */ static int ccs_eat_col = 0; +/* Max columns. */ static int ccs_max_col = 0; -static int ccs_list_indent = 0; -static int ccs_acl_sort_type = 0; +/* Sort ACL by operand first? */ +static _Bool ccs_acl_sort_type = false; +/* Last error message. */ static char *ccs_last_error = NULL; +/* Domain screen is dealing with process list rather than domain list? */ +static _Bool ccs_domain_sort_type = false; +/* Start from the first line when showing ACL screen? */ +static _Bool ccs_no_restore_cursor = false; -/* Prototypes */ +/* Domain transition coltrol keywords. */ +static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = { + [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", + [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", + [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ", + [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", +}; -static void ccs_sigalrm_handler(int sig); -static const char *ccs_get_last_name(const struct ccs_domain_policy *dp, const int index); -static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index); -static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index); -static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index); -static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index); -static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index); -static const struct ccs_transition_control_entry *ccs_transition_control(const struct ccs_path_info *domainname, const char *program); -static int ccs_generic_acl_compare(const void *a, const void *b); -static int ccs_generic_acl_compare0(const void *a, const void *b); -static int ccs_string_acl_compare(const void *a, const void *b); -static int ccs_profile_entry_compare(const void *a, const void *b); -static void ccs_read_generic_policy(void); -static int ccs_add_transition_control_entry(const char *domainname, const char *program, const u8 type); -static int ccs_add_transition_control_policy(char *data, const u8 type); -static int ccs_add_path_group_entry(const char *group_name, const char *member_name, const _Bool is_delete); +static FILE *ccs_editpolicy_open_write(const char *filename); +static _Bool ccs_deleted_domain(const int index); +static _Bool ccs_domain_unreachable(const int index); +static _Bool ccs_initializer_source(const int index); +static _Bool ccs_initializer_target(const int index); +static _Bool ccs_keeper_domain(const int index); +static _Bool ccs_select_item(const int index); +static _Bool ccs_show_command_key(const enum ccs_screen_type screen, + const _Bool readonly); +static const char *ccs_eat(const char *str); +static const char *ccs_get_last_name(const int index); +static const struct ccs_transition_control_entry *ccs_transition_control +(const struct ccs_path_info *domainname, const char *program); +static enum ccs_screen_type ccs_generic_list_loop(void); +static enum ccs_screen_type ccs_select_window(const int current); +static int ccs_add_path_group_entry(const char *group_name, + const char *member_name, + const _Bool is_delete); static int ccs_add_path_group_policy(char *data, const _Bool is_delete); -static void ccs_assign_dis(struct ccs_domain_policy *dp, const struct ccs_path_info *domainname, const char *program); +static int ccs_add_transition_control_entry(const char *domainname, + const char *program, const enum + ccs_transition_type type); +static int ccs_add_transition_control_policy(char *data, const enum + ccs_transition_type type); +static int ccs_count(const unsigned char *array, const int len); +static int ccs_count2(const struct ccs_generic_acl *array, int len); static int ccs_domainname_attribute_compare(const void *a, const void *b); -static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp); -static void ccs_show_current(struct ccs_domain_policy *dp); -static const char *ccs_eat(const char *str); -static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index); +static int ccs_gacl_compare(const void *a, const void *b); +static int ccs_gacl_compare0(const void *a, const void *b); +static int ccs_profile_entry_compare(const void *a, const void *b); static int ccs_show_acl_line(const int index, const int list_indent); -static int ccs_show_profile_line(const int index); +static int ccs_show_domain_line(const int index); static int ccs_show_literal_line(const int index); -static int ccs_show_meminfo_line(const int index); -static void ccs_show_list(struct ccs_domain_policy *dp); -static void ccs_resize_window(void); -static void ccs_up_arrow_key(struct ccs_domain_policy *dp); -static void ccs_down_arrow_key(struct ccs_domain_policy *dp); -static void ccs_page_up_key(struct ccs_domain_policy *dp); -static void ccs_page_down_key(struct ccs_domain_policy *dp); +static int ccs_show_profile_line(const int index); +static int ccs_show_stat_line(const int index); +static int ccs_string_acl_compare(const void *a, const void *b); +static void ccs_add_entry(void); static void ccs_adjust_cursor_pos(const int item_count); -static void ccs_set_cursor_pos(const int index); -static int ccs_count(const unsigned char *array, const int len); -static int ccs_count2(const struct ccs_generic_acl *array, int len); -static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index); -static int ccs_generic_acl_compare(const void *a, const void *b); -static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index); -static void ccs_add_entry(struct ccs_readline_data *rl); -static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward, const int current, struct ccs_readline_data *rl); -static void ccs_set_profile(struct ccs_domain_policy *dp, const int current); -static void ccs_set_level(struct ccs_domain_policy *dp, const int current); -static void ccs_set_quota(struct ccs_domain_policy *dp, const int current); -static int ccs_select_window(struct ccs_domain_policy *dp, const int current); -static _Bool ccs_show_command_key(const int screen, const _Bool readonly); -static int ccs_generic_list_loop(struct ccs_domain_policy *dp); +static void ccs_assign_dis(const struct ccs_path_info *domainname, + const char *program); static void ccs_copy_file(const char *source, const char *dest); -static FILE *ccs_editpolicy_open_write(const char *filename); - -/* Utility Functions */ +static void ccs_delete_entry(const int index); +static void ccs_down_arrow_key(void); +static void ccs_find_entry(const _Bool input, const _Bool forward, + const int current); +static void ccs_page_down_key(void); +static void ccs_page_up_key(void); +static void ccs_read_domain_and_exception_policy(void); +static void ccs_read_generic_policy(void); +static void ccs_resize_window(void); +static void ccs_set_cursor_pos(const int index); +static void ccs_set_level(const int current); +static void ccs_set_profile(const int current); +static void ccs_set_quota(const int current); +static void ccs_show_current(void); +static void ccs_show_list(void); +static void ccs_sigalrm_handler(int sig); +static void ccs_up_arrow_key(void); +/** + * ccs_copy_file - Copy local file to local or remote file. + * + * @source: Local file. + * @dest: Local or remote file name. + * + * Returns nothing. + */ static void ccs_copy_file(const char *source, const char *dest) { FILE *fp_in = fopen(source, "r"); @@ -135,16 +191,30 @@ static void ccs_copy_file(const char *source, const char *dest) fclose(fp_in); } -static const char *ccs_get_last_name(const struct ccs_domain_policy *dp, - const int index) +/** + * ccs_get_last_name - Get last component of a domainname. + * + * @index: Index in the domain policy. + * + * Returns the last componet of the domainname. + */ +static const char *ccs_get_last_name(const int index) { - const char *cp0 = ccs_domain_name(dp, index); + const char *cp0 = ccs_domain_name(&ccs_dp, index); const char *cp1 = strrchr(cp0, ' '); if (cp1) return cp1 + 1; return cp0; } +/** + * ccs_count - Count non-zero elements in an array. + * + * @array: Pointer to "const unsigned char". + * @len: Length of @array array. + * + * Returns number of non-zero elements. + */ static int ccs_count(const unsigned char *array, const int len) { int i; @@ -155,6 +225,14 @@ static int ccs_count(const unsigned char *array, const int len) return c; } +/** + * ccs_count2 - Count non-zero elements in a "struct ccs_generic_acl" array. + * + * @array: Pointer to "const struct ccs_generic_acl". + * @len: Length of @array array. + * + * Returns number of non-zero elements. + */ static int ccs_count2(const struct ccs_generic_acl *array, int len) { int i; @@ -165,6 +243,14 @@ static int ccs_count2(const struct ccs_generic_acl *array, int len) return c; } +/** + * ccs_count3 - Count non-zero elements in a "struct ccs_task_entry" array. + * + * @array: Pointer to "const struct ccs_task_entry". + * @len: Length of @array array. + * + * Returns number of non-zero elements. + */ static int ccs_count3(const struct ccs_task_entry *array, int len) { int i; @@ -175,32 +261,82 @@ static int ccs_count3(const struct ccs_task_entry *array, int len) return c; } -static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index) +/** + * ccs_keeper_domain - Check whether the given domain is marked as "keep_domain". + * + * @index: Index in the domain policy. + * + * Returns true if the given domain is marked as "keep_domain", + * false otherwise. + */ +static _Bool ccs_keeper_domain(const int index) { - return dp->list[index].is_dk; + return ccs_dp.list[index].is_dk; } -static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index) +/** + * ccs_initializer_source - Check whether the given domain is marked as "initialize_domain". + * + * @index: Index in the domain policy. + * + * Returns true if the given domain is marked as "initialize_domain", + * false otherwise. + */ +static _Bool ccs_initializer_source(const int index) { - return dp->list[index].is_dis; + return ccs_dp.list[index].is_dis; } -static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index) +/** + * ccs_initializer_target - Check whether the given domain is a target of "initialize_domain". + * + * @index: Index in the domain policy. + * + * Returns true if the given domain is a target of "initialize_domain", + * false otherwise. + */ +static _Bool ccs_initializer_target(const int index) { - return dp->list[index].is_dit; + return ccs_dp.list[index].is_dit; } -static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index) +/** + * ccs_domain_unreachable - Check whether the given domain is unreachable or not. + * + * @index: Index in the domain policy. + * + * Returns true if the given domain is unreachable, false otherwise. + * + * TODO: Check "task auto_domain_transition" and + * "task manual_domain_transition" which allow other domains to reach + * the given domain. + */ +static _Bool ccs_domain_unreachable(const int index) { - return dp->list[index].is_du; + return ccs_dp.list[index].is_du; } -static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index) +/** + * ccs_deleted_domain - Check whether the given domain is marked as deleted or not. + * + * @index: Index in the domain policy. + * + * Returns true if the given domain is marked as deleted, false otherwise. + */ +static _Bool ccs_deleted_domain(const int index) { - return dp->list[index].is_dd; + return ccs_dp.list[index].is_dd; } -static int ccs_generic_acl_compare0(const void *a, const void *b) +/** + * ccs_gacl_compare0 - strcmp() for qsort() callback. + * + * @a: Pointer to "void". + * @b: Pointer to "void". + * + * Returns return value of strcmp(). + */ +static int ccs_gacl_compare0(const void *a, const void *b) { const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a; const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b; @@ -214,6 +350,14 @@ static int ccs_generic_acl_compare0(const void *a, const void *b) return strcmp(a2, b2); } +/** + * ccs_string_acl_compare - strcmp() for qsort() callback. + * + * @a: Pointer to "void". + * @b: Pointer to "void". + * + * Returns return value of strcmp(). + */ static int ccs_string_acl_compare(const void *a, const void *b) { const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a; @@ -223,7 +367,16 @@ static int ccs_string_acl_compare(const void *a, const void *b) return strcmp(a1, b1); } -static int ccs_add_transition_control_policy(char *data, const u8 type) +/** + * ccs_add_transition_control_policy - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries. + * + * @data: Line to parse. + * @type: One of values in "enum ccs_transition_type". + * + * Returns 0 on success, negative value otherwise. + */ +static int ccs_add_transition_control_policy +(char *data, const enum ccs_transition_type type) { char *domainname = strstr(data, " from "); if (domainname) { @@ -237,6 +390,14 @@ static int ccs_add_transition_control_policy(char *data, const u8 type) return ccs_add_transition_control_entry(domainname, data, type); } +/** + * ccs_add_path_group_policy - Add "path_group" entry. + * + * @data: Line to parse. + * @is_delete: True if it is delete request, false otherwise. + * + * Returns 0 on success, negative value otherwise. + */ static int ccs_add_path_group_policy(char *data, const _Bool is_delete) { char *cp = strchr(data, ' '); @@ -246,8 +407,13 @@ static int ccs_add_path_group_policy(char *data, const _Bool is_delete) return ccs_add_path_group_entry(data, cp, is_delete); } -static void ccs_assign_dis(struct ccs_domain_policy *dp, - const struct ccs_path_info *domainname, +/** + * ccs_assign_dis - Assign domain initializer source domain. + * + * @domainname: Pointer to "const struct ccs_path_info". + * @program: Program name. + */ +static void ccs_assign_dis(const struct ccs_path_info *domainname, const char *program) { const struct ccs_transition_control_entry *d_t = @@ -258,17 +424,25 @@ static void ccs_assign_dis(struct ccs_domain_policy *dp, ccs_get(); line = ccs_shprintf("%s %s", domainname->name, program); ccs_normalize_line(line); - source = ccs_assign_domain(dp, line, true, false); + source = ccs_assign_domain(&ccs_dp, line, true, false); if (source == EOF) ccs_out_of_memory(); line = ccs_shprintf(CCS_ROOT_NAME " %s", program); - dp->list[source].target_domainname = strdup(line); - if (!dp->list[source].target_domainname) + ccs_dp.list[source].target_domainname = strdup(line); + if (!ccs_dp.list[source].target_domainname) ccs_out_of_memory(); ccs_put(); } } +/** + * ccs_domainname_attribute_compare - strcmp() for qsort() callback. + * + * @a: Pointer to "void". + * @b: Pointer to "void". + * + * Returns return value of strcmp(). + */ static int ccs_domainname_attribute_compare(const void *a, const void *b) { const struct ccs_domain_info *a0 = a; @@ -279,41 +453,50 @@ static int ccs_domainname_attribute_compare(const void *a, const void *b) return k; } -static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = { - [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", - [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", - [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ", - [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", -}; - -static int ccs_find_target_domain(struct ccs_domain_policy *dp, const int index) +/** + * ccs_find_target_domain - Find the initialize_domain target domain. + * + * @index: Index in the domain policy. + * + * Returns index in the domain policy if found, EOF otherwise. + */ +static int ccs_find_target_domain(const int index) { - return ccs_find_domain(dp, dp->list[index].target_domainname, false, false); + return ccs_find_domain(&ccs_dp, ccs_dp.list[index].target_domainname, + false, false); } -static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index) +/** + * ccs_show_domain_line - Show a line of the domain transition tree. + * + * @index: Index in the domain policy. + * + * Returns length of the printed line. + */ +static int ccs_show_domain_line(const int index) { int tmp_col = 0; const struct ccs_transition_control_entry *transition_control; char *line; const char *sp; - const int number = dp->list[index].number; + const int number = ccs_dp.list[index].number; int redirect_index; - const bool is_dis = ccs_initializer_source(dp, index); - const bool is_deleted = ccs_deleted_domain(dp, index); + const bool is_dis = ccs_initializer_source(index); + const bool is_deleted = ccs_deleted_domain(index); if (number >= 0) { - printw("%c%4d:", dp->list_selected[index] ? '&' : ' ', number); - if (dp->list[index].profile_assigned) - printw("%3u", dp->list[index].profile); + printw("%c%4d:", ccs_dp.list_selected[index] ? '&' : ' ', + number); + if (ccs_dp.list[index].profile_assigned) + printw("%3u", ccs_dp.list[index].profile); else printw("???"); - printw(" %c%c%c ", ccs_keeper_domain(dp, index) ? '#' : ' ', - ccs_initializer_target(dp, index) ? '*' : ' ', - ccs_domain_unreachable(dp, index) ? '!' : ' '); + printw(" %c%c%c ", ccs_keeper_domain(index) ? '#' : ' ', + ccs_initializer_target(index) ? '*' : ' ', + ccs_domain_unreachable(index) ? '!' : ' '); } else printw(" "); tmp_col += 14; - sp = ccs_domain_name(dp, index); + sp = ccs_domain_name(&ccs_dp, index); while (true) { const char *cp = strchr(sp, ' '); if (!cp) @@ -332,7 +515,7 @@ static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index) printw("%s", ccs_eat(" )")); tmp_col += 2; } - transition_control = dp->list[index].d_t; + transition_control = ccs_dp.list[index].d_t; if (!transition_control || is_dis) goto no_transition_control; ccs_get(); @@ -350,9 +533,10 @@ no_transition_control: if (!is_dis) goto done; ccs_get(); - redirect_index = ccs_find_target_domain(dp, index); + redirect_index = ccs_find_target_domain(index); if (redirect_index >= 0) - line = ccs_shprintf(" ( -> %d )", dp->list[redirect_index].number); + line = ccs_shprintf(" ( -> %d )", + ccs_dp.list[redirect_index].number); else line = ccs_shprintf(" ( -> Not Found )"); printw("%s", ccs_eat(line)); @@ -362,14 +546,23 @@ done: return tmp_col; } +/** + * ccs_show_acl_line - Print an ACL line. + * + * @index: Index in the generic list. + * @list_indent: Indent size. + * + * Returns length of the printed line. + */ static int ccs_show_acl_line(const int index, const int list_indent) { - u16 directive = ccs_generic_acl_list[index].directive; + const enum ccs_editpolicy_directives directive = + ccs_gacl_list[index].directive; const char *cp1 = ccs_directives[directive].alias; - const char *cp2 = ccs_generic_acl_list[index].operand; + const char *cp2 = ccs_gacl_list[index].operand; int len = list_indent - ccs_directives[directive].alias_len; printw("%c%4d: %s ", - ccs_generic_acl_list[index].selected ? '&' : ' ', + ccs_gacl_list[index].selected ? '&' : ' ', index, ccs_eat(cp1)); while (len-- > 0) printw("%s", ccs_eat(" ")); @@ -377,58 +570,55 @@ static int ccs_show_acl_line(const int index, const int list_indent) return strlen(cp1) + strlen(cp2) + 8 + list_indent; } +/** + * ccs_show_profile_line - Print a profile line. + * + * @index: Index in the generic list. + * + * Returns length of the printed line. + */ static int ccs_show_profile_line(const int index) { - const char *cp = ccs_generic_acl_list[index].operand; - const u16 profile = ccs_generic_acl_list[index].directive; + const char *cp = ccs_gacl_list[index].operand; + const u16 profile = ccs_gacl_list[index].directive; char number[8] = ""; if (profile <= 256) snprintf(number, sizeof(number) - 1, "%3u-", profile); - printw("%c%4d: %s", ccs_generic_acl_list[index].selected ? '&' : ' ', + printw("%c%4d: %s", ccs_gacl_list[index].selected ? '&' : ' ', index, ccs_eat(number)); printw("%s ", ccs_eat(cp)); return strlen(number) + strlen(cp) + 8; } +/** + * ccs_show_literal_line - Print a literal line. + * + * @index: Index in the generic list. + * + * Returns length of the printed line. + */ static int ccs_show_literal_line(const int index) { - const char *cp = ccs_generic_acl_list[index].operand; + const char *cp = ccs_gacl_list[index].operand; printw("%c%4d: %s ", - ccs_generic_acl_list[index].selected ? '&' : ' ', + ccs_gacl_list[index].selected ? '&' : ' ', index, ccs_eat(cp)); return strlen(cp) + 8; } -static int ccs_show_meminfo_line(const int index) +/** + * ccs_show_stat_line - Print a statistics line. + * + * @index: Index in the generic list. + * + * Returns length of the printed line. + */ +static int ccs_show_stat_line(const int index) { char *line; - unsigned int now = 0; - unsigned int quota = -1; - const char *data = ccs_generic_acl_list[index].operand; + unsigned int now; ccs_get(); - if (sscanf(data, "Policy: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory used for policy = %10u bytes " - "(Quota: %10u bytes)", now, quota); - else if (sscanf(data, "Audit logs: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory used for audit logs = %10u bytes " - "(Quota: %10u bytes)", now, quota); - else if (sscanf(data, "Query lists: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory used for query lists = %10u bytes " - "(Quota: %10u bytes)", now, quota); - else if (sscanf(data, "Total: %u", &now) == 1) - line = ccs_shprintf("Total memory in use = %10u bytes", - now); - else if (sscanf(data, "Shared: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory for string data = %10u bytes " - "Quota = %10u bytes", now, quota); - else if (sscanf(data, "Private: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory for numeric data = %10u bytes " - "Quota = %10u bytes", now, quota); - else if (sscanf(data, "Dynamic: %u (Quota: %u)", &now, "a) >= 1) - line = ccs_shprintf("Memory for temporary data = %10u bytes " - "Quota = %10u bytes", now, quota); - else - line = ccs_shprintf("%s", data); + line = ccs_shprintf("%s", ccs_gacl_list[index].operand); if (line[0]) printw("%s", ccs_eat(line)); now = strlen(line); @@ -436,9 +626,16 @@ static int ccs_show_meminfo_line(const int index) return now; } -static int ccs_domain_sort_type = 0; - -static _Bool ccs_show_command_key(const int screen, const _Bool readonly) +/** + * ccs_show_command_key - Print help screen. + * + * @screen: Currently selected screen. + * @readonly: True if readonly_mopde, false otherwise. + * + * Returns true to continue, false to quit. + */ +static _Bool ccs_show_command_key(const enum ccs_screen_type screen, + const _Bool readonly) { int c; clear(); @@ -446,7 +643,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) printw("Q/q Quit this editor.\n"); printw("R/r Refresh to the latest information.\n"); switch (screen) { - case CCS_SCREEN_MEMINFO_LIST: + case CCS_SCREEN_STAT_LIST: break; default: printw("F/f Find first.\n"); @@ -456,7 +653,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) printw("W/w Switch to selected screen.\n"); /* printw("Tab Switch to next screen.\n"); */ switch (screen) { - case CCS_SCREEN_MEMINFO_LIST: + case CCS_SCREEN_STAT_LIST: break; default: printw("Insert Copy an entry at the cursor position to " @@ -485,7 +682,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) "cursor position.\n"); } break; - case CCS_SCREEN_MEMINFO_LIST: + case CCS_SCREEN_STAT_LIST: if (!readonly) printw("S/s Set memory quota of selected " "items.\n"); @@ -494,6 +691,8 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) if (!readonly) printw("S/s Set mode of selected items.\n"); break; + default: + break; } switch (screen) { case CCS_SCREEN_EXCEPTION_LIST: @@ -503,11 +702,15 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) printw("A/a Add a new entry.\n"); printw("D/d Delete selected entries.\n"); } + default: + break; } switch (screen) { case CCS_SCREEN_PROFILE_LIST: if (!readonly) printw("A/a Define a new profile.\n"); + default: + break; } switch (screen) { case CCS_SCREEN_ACL_LIST: @@ -520,6 +723,8 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) case CCS_SCREEN_DOMAIN_LIST: if (!ccs_offline_mode) printw("@ Switch domain/process list.\n"); + default: + break; } printw("Arrow-keys and PageUp/PageDown/Home/End keys " "for scroll.\n\n"); @@ -535,18 +740,13 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly) return true; } -/* Main Functions */ - -static void ccs_close_write(FILE *fp) -{ - if (ccs_network_mode) { - fputc(0, fp); - fflush(fp); - fgetc(fp); - } - fclose(fp); -} - +/** + * ccs_set_error - Set error line's caption. + * + * @filename: Filename to print. Maybe NULL. + * + * Returns nothing. + */ static void ccs_set_error(const char *filename) { if (filename) { @@ -562,6 +762,45 @@ static void ccs_set_error(const char *filename) } } +/** + * ccs_send_fd - Send file descriptor. + * + * @data: String data to send with file descriptor. + * @fd: Pointer to file desciptor. + * + * Returns nothing. + */ +static void ccs_send_fd(char *data, int *fd) +{ + struct msghdr msg; + struct iovec iov = { data, strlen(data) }; + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg = (struct cmsghdr *) cmsg_buf; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + msg.msg_controllen = cmsg->cmsg_len; + memmove(CMSG_DATA(cmsg), fd, sizeof(int)); + sendmsg(ccs_persistent_fd, &msg, 0); + close(*fd); +} + +/** + * ccs_editpolicy_open_write - Wrapper for ccs_open_write(). + * + * @filename: File to open for writing. + * + * Returns pointer to "FILE" on success, NULL otherwise. + * + * Since CUI policy editor screen provides a line for printing error message, + * this function sets error line if failed. Also, this function returns NULL if + * readonly mode. + */ static FILE *ccs_editpolicy_open_write(const char *filename) { if (ccs_network_mode) { @@ -597,6 +836,16 @@ out: } } +/** + * ccs_editpolicy_open_read - Wrapper for ccs_open_read(). + * + * @filename: File to open for reading. + * + * Returns pointer to "FILE" on success, NULL otherwise. + * + * Since CUI policy editor screen provides a line for printing error message, + * this function sets error line if failed. + */ static FILE *ccs_editpolicy_open_read(const char *filename) { if (ccs_network_mode) { @@ -627,6 +876,17 @@ out: } } +/** + * ccs_open2 - Wrapper for open(). + * + * @filename: File to open. + * @mode: Flags to passed to open(). + * + * Returns file descriptor on success, EOF otherwise. + * + * Since CUI policy editor screen provides a line for printing error message, + * this function sets error line if failed. + */ static int ccs_open2(const char *filename, int mode) { const int fd = open(filename, mode); @@ -635,12 +895,29 @@ static int ccs_open2(const char *filename, int mode) return fd; } +/** + * ccs_sigalrm_handler - Callback routine for timer interrupt. + * + * @sig: Signal number. Not used. + * + * Returns nothing. + * + * This function is called when ccs_refresh_interval is non-zero. This function + * marks current screen to reload. Also, this function reenables timer event. + */ static void ccs_sigalrm_handler(int sig) { ccs_need_reload = true; alarm(ccs_refresh_interval); } +/** + * ccs_eat - Shift string data before displaying. + * + * @str: String to be displayed. + * + * Returns shifted string. + */ static const char *ccs_eat(const char *str) { while (*str && ccs_eat_col) { @@ -650,6 +927,15 @@ static const char *ccs_eat(const char *str) return str; } +/** + * ccs_transition_control - Find domain transition control. + * + * @domainname: Pointer to "const struct ccs_path_info". + * @program: Program name. + * + * Returns pointer to "const struct ccs_transition_control_entry" if found one, + * NULL otherwise. + */ static const struct ccs_transition_control_entry *ccs_transition_control (const struct ccs_path_info *domainname, const char *program) { @@ -663,12 +949,12 @@ static const struct ccs_transition_control_entry *ccs_transition_control last_name.name = domainname->name; ccs_fill_path_info(&last_name); for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) { - next: +next: for (i = 0; i < ccs_transition_control_list_len; i++) { struct ccs_transition_control_entry *ptr = &ccs_transition_control_list[i]; if (ptr->type != type) - continue; + continue; if (ptr->domainname) { if (!ptr->is_last_name) { if (ccs_pathcmp(ptr->domainname, @@ -680,7 +966,8 @@ static const struct ccs_transition_control_entry *ccs_transition_control continue; } } - if (ptr->program && strcmp(ptr->program->name, program)) + if (ptr->program && + strcmp(ptr->program->name, program)) continue; if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) { /* @@ -700,6 +987,14 @@ static const struct ccs_transition_control_entry *ccs_transition_control return NULL; } +/** + * ccs_profile_entry_compare - strcmp() for qsort() callback. + * + * @a: Pointer to "void". + * @b: Pointer to "void". + * + * Returns return value of strcmp(). + */ static int ccs_profile_entry_compare(const void *a, const void *b) { const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a; @@ -724,7 +1019,7 @@ static int ccs_profile_entry_compare(const void *a, const void *b) return 1; } } - if (ccs_profile_sort_type == 0) { + if (!ccs_profile_sort_type) { if (a2 == b2) return strcmp(a1, b1); else @@ -742,13 +1037,19 @@ static int ccs_profile_entry_compare(const void *a, const void *b) } } +/** + * ccs_read_generic_policy - Read policy data other than domain policy. + * + * Returns nothing. + */ static void ccs_read_generic_policy(void) { FILE *fp = NULL; _Bool flag = false; - while (ccs_generic_acl_list_count) + while (ccs_gacl_list_count) free((void *) - ccs_generic_acl_list[--ccs_generic_acl_list_count].operand); + ccs_gacl_list[--ccs_gacl_list_count]. + operand); if (ccs_current_screen == CCS_SCREEN_ACL_LIST) { if (ccs_network_mode) /* We can read after write. */ @@ -758,7 +1059,8 @@ static void ccs_read_generic_policy(void) fp = fopen(ccs_policy_file, "r+"); if (fp) { if (ccs_domain_sort_type) - fprintf(fp, "select pid=%u\n", ccs_current_pid); + fprintf(fp, "select pid=%u\n", + ccs_current_pid); else fprintf(fp, "select domain=%s\n", ccs_current_domain); @@ -773,10 +1075,11 @@ static void ccs_read_generic_policy(void) ccs_set_error(ccs_policy_file); return; } + ccs_freadline_raw = ccs_current_screen == CCS_SCREEN_STAT_LIST; ccs_get(); while (true) { - char *line = ccs_freadline(fp); - u16 directive; + char *line = ccs_freadline_unpack(fp); + enum ccs_editpolicy_directives directive; char *cp; if (!line) break; @@ -812,42 +1115,59 @@ static void ccs_read_generic_policy(void) directive = CCS_DIRECTIVE_NONE; break; } - ccs_generic_acl_list = realloc(ccs_generic_acl_list, - (ccs_generic_acl_list_count + 1) * - sizeof(struct ccs_generic_acl)); - if (!ccs_generic_acl_list) + ccs_gacl_list = + realloc(ccs_gacl_list, + (ccs_gacl_list_count + 1) * + sizeof(struct ccs_generic_acl)); + if (!ccs_gacl_list) ccs_out_of_memory(); cp = strdup(line); if (!cp) ccs_out_of_memory(); - ccs_generic_acl_list[ccs_generic_acl_list_count].directive = directive; - ccs_generic_acl_list[ccs_generic_acl_list_count].selected = 0; - ccs_generic_acl_list[ccs_generic_acl_list_count++].operand = cp; + ccs_gacl_list[ccs_gacl_list_count].directive = + directive; + ccs_gacl_list[ccs_gacl_list_count].selected = 0; + ccs_gacl_list[ccs_gacl_list_count++].operand = + cp; } ccs_put(); + ccs_freadline_raw = false; fclose(fp); switch (ccs_current_screen) { case CCS_SCREEN_ACL_LIST: - qsort(ccs_generic_acl_list, ccs_generic_acl_list_count, - sizeof(struct ccs_generic_acl), ccs_generic_acl_compare); + qsort(ccs_gacl_list, ccs_gacl_list_count, + sizeof(struct ccs_generic_acl), ccs_gacl_compare); break; case CCS_SCREEN_EXCEPTION_LIST: - qsort(ccs_generic_acl_list, ccs_generic_acl_list_count, - sizeof(struct ccs_generic_acl), ccs_generic_acl_compare0); + qsort(ccs_gacl_list, ccs_gacl_list_count, + sizeof(struct ccs_generic_acl), + ccs_gacl_compare0); break; case CCS_SCREEN_PROFILE_LIST: - qsort(ccs_generic_acl_list, ccs_generic_acl_list_count, - sizeof(struct ccs_generic_acl), ccs_profile_entry_compare); + qsort(ccs_gacl_list, ccs_gacl_list_count, + sizeof(struct ccs_generic_acl), + ccs_profile_entry_compare); + break; + case CCS_SCREEN_STAT_LIST: break; default: - qsort(ccs_generic_acl_list, ccs_generic_acl_list_count, + qsort(ccs_gacl_list, ccs_gacl_list_count, sizeof(struct ccs_generic_acl), ccs_string_acl_compare); } } -static int ccs_add_transition_control_entry(const char *domainname, - const char *program, - const u8 type) +/** + * ccs_add_transition_control_entry - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries. + * + * @domainname: Domainname. + * @program: Program name. + * @type: One of values in "enum ccs_transition_type". + * + * Returns 0 on success, -EINVAL otherwise. + */ +static int ccs_add_transition_control_entry +(const char *domainname, const char *program, + const enum ccs_transition_type type) { void *vp; struct ccs_transition_control_entry *ptr; @@ -886,8 +1206,18 @@ static int ccs_add_transition_control_entry(const char *domainname, return 0; } -static int ccs_add_path_group_entry(const char *group_name, const char *member_name, - const _Bool is_delete) +/** + * ccs_add_path_group_entry - Add "path_group" entry. + * + * @group_name: Name of address group. + * @member_name: Address string. + * @is_delete: True if it is delete request, false otherwise. + * + * Returns 0 on success, negative value otherwise. + */ +static int ccs_add_path_group_entry(const char *group_name, + const char *member_name, + const _Bool is_delete) { const struct ccs_path_info *saved_group_name; const struct ccs_path_info *saved_member_name; @@ -938,180 +1268,288 @@ static int ccs_add_path_group_entry(const char *group_name, const char *member_n return 0; } -static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp) +/* + * List of "task auto_domain_transition" "task manual_domain_transition" + * "auto_domain_transition=" part. + */ +static char **ccs_jump_list = NULL; +static int ccs_jump_list_len = 0; + +/** + * ccs_add_condition_domain_transition - Add auto_domain_transition= part. + * + * @line: Line to parse. + * @index: Current domain's index. + * + * Returns nothing. + */ +static void ccs_add_condition_domain_transition(char *line, const int index) +{ + static char domainname[4096]; + int source; + char *cp = strrchr(line, ' '); + if (!cp || strncmp(cp, " auto_domain_transition=\"", 25)) + return; + *cp = '\0'; + cp += 25; + source = strlen(cp); + if (!source) + return; + cp[source - 1] = '\0'; + snprintf(domainname, sizeof(domainname) - 1, "%s %s", + ccs_domain_name(&ccs_dp, index), cp); + domainname[sizeof(domainname) - 1] = '\0'; + ccs_normalize_line(domainname); + cp = strdup(domainname); + ccs_jump_list = realloc(ccs_jump_list, + (ccs_jump_list_len + 1) * sizeof(char *)); + if (!cp || !ccs_jump_list) + ccs_out_of_memory(); + ccs_jump_list[ccs_jump_list_len++] = cp; + source = ccs_assign_domain(&ccs_dp, domainname, true, false); + if (source == EOF) + ccs_out_of_memory(); + cp = strdup(domainname); + if (!cp) + ccs_out_of_memory(); + ccs_dp.list[source].target_domainname = cp; +} + +/** + * ccs_add_acl_domain_transition - Add task acl. + * + * @line: Line to parse. + * @index: Current domain's index. + * + * Returns nothing. + */ +static void ccs_add_acl_domain_transition(char *line, const int index) +{ + static char domainname[4096]; + int source; + char *cp; + for (source = 0; line[source]; source++) + if (line[source] == ' ' && line[source + 1] != '/') { + line[source] = '\0'; + break; + } + if (!ccs_correct_domain(line)) + return; + cp = strdup(line); + ccs_jump_list = realloc(ccs_jump_list, + (ccs_jump_list_len + 1) * sizeof(char *)); + if (!cp || !ccs_jump_list) + ccs_out_of_memory(); + ccs_jump_list[ccs_jump_list_len++] = cp; + cp = strrchr(line, ' '); + if (cp) + cp++; + else + cp = line; + snprintf(domainname, sizeof(domainname) - 1, "%s %s", + ccs_domain_name(&ccs_dp, index), cp); + domainname[sizeof(domainname) - 1] = '\0'; + ccs_normalize_line(domainname); + source = ccs_assign_domain(&ccs_dp, domainname, true, false); + if (source == EOF) + ccs_out_of_memory(); + cp = strdup(line); + if (!cp) + ccs_out_of_memory(); + ccs_dp.list[source].target_domainname = cp; +} + +/** + * ccs_parse_domain_line - Parse an ACL entry in domain policy. + * + * @line: Line to parse. + * @index: Current domain's index. + * @parse_flags: True if parse use_profile and use_group lines, false otherwise. + * + * Returns nothing. + */ +static void ccs_parse_domain_line(char *line, const int index, + const bool parse_flags) +{ + ccs_add_condition_domain_transition(line, index); + if (ccs_str_starts(line, "task auto_execute_handler ") || + ccs_str_starts(line, "task denied_execute_handler ") || + ccs_str_starts(line, "file execute ")) { + char *cp = strchr(line, ' '); + if (cp) + *cp = '\0'; + if (*line == '@' || ccs_correct_path(line)) + ccs_add_string_entry(&ccs_dp, line, index); + } else if (ccs_str_starts(line, + "task auto_domain_transition ") || + ccs_str_starts(line, + "task manual_domain_transition ")) { + ccs_add_acl_domain_transition(line, index); + } else if (parse_flags) { + unsigned int profile; + if (sscanf(line, "use_profile %u", &profile) == 1) { + ccs_dp.list[index].profile = (u8) profile; + ccs_dp.list[index].profile_assigned = 1; + } else if (sscanf(line, "use_group %u", &profile) == 1) { + ccs_dp.list[index].group = (u8) profile; + } + } +} + +/** + * ccs_parse_exception_line - Parse an ACL entry in exception policy. + * + * @line: Line to parse. + * @max_index: Number of domains currently defined. + * + * Returns nothing. + */ +static void ccs_parse_exception_line(char *line, const int max_index) +{ + unsigned int group; + if (ccs_str_starts(line, "initialize_domain ")) + ccs_add_transition_control_policy + (line, CCS_TRANSITION_CONTROL_INITIALIZE); + else if (ccs_str_starts(line, "no_initialize_domain ")) + ccs_add_transition_control_policy + (line, CCS_TRANSITION_CONTROL_NO_INITIALIZE); + else if (ccs_str_starts(line, "keep_domain ")) + ccs_add_transition_control_policy + (line, CCS_TRANSITION_CONTROL_KEEP); + else if (ccs_str_starts(line, "no_keep_domain ")) + ccs_add_transition_control_policy + (line, CCS_TRANSITION_CONTROL_NO_KEEP); + else if (ccs_str_starts(line, "path_group ")) + ccs_add_path_group_policy(line, false); + else if (ccs_str_starts(line, "address_group ")) + ccs_add_address_group_policy(line, false); + else if (ccs_str_starts(line, "number_group ")) + ccs_add_number_group_policy(line, false); + else if (sscanf(line, "acl_group %u", &group) == 1 && group < 256) { + int index; + char *cp = strchr(line + 10, ' '); + if (cp) + line = cp + 1; + for (index = 0; index < max_index; index++) { + if (ccs_dp.list[index].group != group) + continue; + cp = strdup(line); + if (!cp) + ccs_out_of_memory(); + ccs_parse_domain_line(cp, index, false); + free(cp); + } + } +} + +/** + * ccs_read_domain_and_exception_policy - Read domain policy and exception policy. + * + * Returns nothing. + * + * Since CUI policy editor screen shows domain initializer source domains and + * unreachable domains, we need to read not only the domain policy but also + * the exception policy for printing the domain transition tree. + */ +static void ccs_read_domain_and_exception_policy(void) { FILE *fp; int i; int j; int index; int max_index; - static char **ccs_jump_list = NULL; - static int ccs_jump_list_len = 0; while (ccs_jump_list_len) free(ccs_jump_list[--ccs_jump_list_len]); - ccs_clear_domain_policy(dp); + ccs_clear_domain_policy(&ccs_dp); ccs_transition_control_list_len = 0; - while (ccs_path_group_list_len) - free(ccs_path_group_list[--ccs_path_group_list_len].member_name); - /* - while (ccs_address_group_list_len) - free(ccs_address_group_list[--ccs_address_group_list_len].member_name); - */ - ccs_address_group_list_len = 0; - ccs_number_group_list_len = 0; - ccs_assign_domain(dp, CCS_ROOT_NAME, false, false); - - /* Load all domain list. */ + ccs_editpolicy_clear_groups(); + ccs_assign_domain(&ccs_dp, CCS_ROOT_NAME, false, false); + + /* Load all domain transition related entries. */ fp = NULL; if (ccs_network_mode) /* We can read after write. */ - fp = ccs_editpolicy_open_write(ccs_policy_file); + fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY); else if (!ccs_offline_mode) /* Don't set error message if failed. */ - fp = fopen(ccs_policy_file, "r+"); + fp = fopen(CCS_PROC_POLICY_DOMAIN_POLICY, "r+"); if (fp) { - fprintf(fp, "select execute\n"); + fprintf(fp, "select transition_only\n"); if (ccs_network_mode) fputc(0, fp); fflush(fp); - } - if (!fp) + } else { fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_DOMAIN_POLICY); - if (!fp) { - ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY); - goto no_domain; } - index = EOF; - ccs_get(); - while (true) { - char *line = ccs_freadline(fp); - unsigned int profile; - if (!line) - break; - if (ccs_domain_def(line)) { - index = ccs_assign_domain(dp, line, false, false); - continue; - } else if (index == EOF) { - continue; - } - if (ccs_str_starts(line, "task auto_execute_handler ") || - ccs_str_starts(line, "task denied_execute_handler ") || - ccs_str_starts(line, "file execute ")) { - char *cp = strchr(line, ' '); - if (cp) - *cp = '\0'; - if (*line == '@' || ccs_correct_path(line)) - ccs_add_string_entry(dp, line, index); - } else if (ccs_str_starts(line, - "task auto_domain_transition ") || - ccs_str_starts(line, - "task manual_domain_transition ")) { - static char domainname[4096]; - int source; - char *m; - int i; - for (i = 0; line[i]; i++) - if (line[i] == ' ' && line[i + 1] != '/') { - line[i] = '\0'; - break; - } - if (!ccs_correct_domain(line)) + if (fp) { + index = EOF; + ccs_get(); + while (true) { + char *line = ccs_freadline_unpack(fp); + if (!line) + break; + if (ccs_domain_def(line)) { + index = ccs_assign_domain(&ccs_dp, line, false, + false); continue; - ccs_jump_list = realloc(ccs_jump_list, - (ccs_jump_list_len + 1) - * sizeof(char *)); - if (!ccs_jump_list) - ccs_out_of_memory(); - ccs_jump_list[ccs_jump_list_len] = strdup(line); - if (!ccs_jump_list[ccs_jump_list_len]) - ccs_out_of_memory(); - ccs_jump_list_len++; - m = strrchr(line, ' '); - if (m) - m++; - else - m = line; - snprintf(domainname, sizeof(domainname) - 1, "%s %s", - ccs_domain_name(dp, index), m); - domainname[sizeof(domainname) - 1] = '\0'; - ccs_normalize_line(domainname); - source = ccs_assign_domain(dp, domainname, true, false); - if (source == EOF) - ccs_out_of_memory(); - dp->list[source].target_domainname = strdup(line); - if (!dp->list[source].target_domainname) - ccs_out_of_memory(); - } else if (sscanf(line, "use_profile %u", &profile) == 1) { - dp->list[index].profile = (u8) profile; - dp->list[index].profile_assigned = 1; - } else if (sscanf(line, "use_group %u", &profile) == 1) { - dp->list[index].group = (u8) profile; + } else if (index == EOF) { + continue; + } + ccs_parse_domain_line(line, index, true); } + ccs_put(); + fclose(fp); + } else { + ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY); } - ccs_put(); - fclose(fp); -no_domain: - max_index = dp->list_len; + max_index = ccs_dp.list_len; - /* Load domain_initializer list, domain_keeper list. */ - fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_EXCEPTION_POLICY); - if (!fp) { - ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY); - goto no_exception; + /* Load domain transition related entries and group entries. */ + fp = NULL; + if (ccs_network_mode) + /* We can read after write. */ + fp = ccs_editpolicy_open_write + (CCS_PROC_POLICY_EXCEPTION_POLICY); + else if (!ccs_offline_mode) + /* Don't set error message if failed. */ + fp = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "r+"); + if (fp) { + fprintf(fp, "select transition_only\n"); + if (ccs_network_mode) + fputc(0, fp); + fflush(fp); + } else { + fp = ccs_editpolicy_open_read + (CCS_PROC_POLICY_EXCEPTION_POLICY); } - ccs_get(); - while (true) { - unsigned int group; - char *line = ccs_freadline(fp); - if (!line) - break; - if (ccs_str_starts(line, "initialize_domain ")) - ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_INITIALIZE); - else if (ccs_str_starts(line, "no_initialize_domain ")) - ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_INITIALIZE); - else if (ccs_str_starts(line, "keep_domain ")) - ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_KEEP); - else if (ccs_str_starts(line, "no_keep_domain ")) - ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_KEEP); - else if (ccs_str_starts(line, "path_group ")) - ccs_add_path_group_policy(line, false); - else if (ccs_str_starts(line, "address_group ")) - ccs_add_address_group_policy(line, false); - else if (ccs_str_starts(line, "number_group ")) - ccs_add_number_group_policy(line, false); - else if (sscanf(line, "acl_group %u", &group) == 1 - && group < 256) { - char *cp = strchr(line + 10, ' '); - if (cp) - line = cp + 1; - if (ccs_str_starts(line, - "task auto_execute_handler ") || - ccs_str_starts(line, - "task denied_execute_handler ") || - ccs_str_starts(line, "file execute ")) { - cp = strchr(line, ' '); - if (cp) - *cp = '\0'; - if (*line == '@' || ccs_correct_path(line)) { - for (index = 0; index < max_index; - index++) - if (dp->list[index].group - == group) - ccs_add_string_entry(dp, line, index); - } - } + if (fp) { + ccs_get(); + while (true) { + char *line = ccs_freadline_unpack(fp); + if (!line) + break; + ccs_parse_exception_line(line, max_index); } + ccs_put(); + fclose(fp); + } else { + ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY); } - ccs_put(); - fclose(fp); -no_exception: - /* Find unreachable domains. */ + /* + * Find unreachable domains. + * + * This is calculated based on "initialize_domain" and "keep_domain" + * keywords. However, since "task auto_domain_transition" and "task + * manual_domain_transition" keywords and "auto_domain_transition=" + * condition are not subjected to "initialize_domain" and "keep_domain" + * keywords, we need to adjust later. + */ for (index = 0; index < max_index; index++) { char *line; ccs_get(); - line = ccs_shprintf("%s", ccs_domain_name(dp, index)); + line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index)); while (true) { const struct ccs_transition_control_entry *d_t; struct ccs_path_info parent; @@ -1128,17 +1566,17 @@ no_exception: if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE && parent.total_len == CCS_ROOT_NAME_LEN) break; - dp->list[index].d_t = d_t; + ccs_dp.list[index].d_t = d_t; continue; } ccs_put(); - if (dp->list[index].d_t) - dp->list[index].is_du = true; + if (ccs_dp.list[index].d_t) + ccs_dp.list[index].is_du = true; } /* Find domain initializer target domains. */ for (index = 0; index < max_index; index++) { - char *cp = strchr(ccs_domain_name(dp, index), ' '); + char *cp = strchr(ccs_domain_name(&ccs_dp, index), ' '); if (!cp || strchr(cp + 1, ' ')) continue; for (i = 0; i < ccs_transition_control_list_len; i++) { @@ -1148,7 +1586,7 @@ no_exception: continue; if (ptr->program && strcmp(ptr->program->name, cp + 1)) continue; - dp->list[index].is_dit = true; + ccs_dp.list[index].is_dit = true; } } @@ -1163,36 +1601,38 @@ no_exception: if (!ptr->is_last_name) { if (ptr->domainname && ccs_pathcmp(ptr->domainname, - dp->list[index].domainname)) + ccs_dp.list[index].domainname)) continue; - dp->list[index].is_dk = true; + ccs_dp.list[index].is_dk = true; continue; } - cp = strrchr(dp->list[index].domainname->name, + cp = strrchr(ccs_dp.list[index].domainname->name, ' '); if (!cp || (ptr->domainname->name && strcmp(ptr->domainname->name, cp + 1))) continue; - dp->list[index].is_dk = true; + ccs_dp.list[index].is_dk = true; } } /* Create domain initializer source domains. */ for (index = 0; index < max_index; index++) { const struct ccs_path_info *domainname - = dp->list[index].domainname; + = ccs_dp.list[index].domainname; const struct ccs_path_info **string_ptr - = dp->list[index].string_ptr; - const int max_count = dp->list[index].string_count; - /* Don't create source domain under because - they will become ccs_target domains. */ + = ccs_dp.list[index].string_ptr; + const int max_count = ccs_dp.list[index].string_count; + /* + * Don't create source domain under because + * they will become target domains. + */ if (domainname->total_len == CCS_ROOT_NAME_LEN) continue; for (i = 0; i < max_count; i++) { const struct ccs_path_info *cp = string_ptr[i]; struct ccs_path_group_entry *group; if (cp->name[0] != '@') { - ccs_assign_dis(dp, domainname, cp->name); + ccs_assign_dis(domainname, cp->name); continue; } group = ccs_find_path_group(cp->name + 1); @@ -1200,40 +1640,47 @@ no_exception: continue; for (j = 0; j < group->member_name_len; j++) { cp = group->member_name[j]; - ccs_assign_dis(dp, domainname, cp->name); + ccs_assign_dis(domainname, cp->name); } } } - /* Create domain jump target domains. */ + /* + * Create domain jump target domains. + * This may reset unreachable domains. + */ for (i = 0; i < ccs_jump_list_len; i++) { - int index = ccs_find_domain(dp, ccs_jump_list[i], false, false); - if (index != EOF) - dp->list[index].is_dit = true; + const int index = ccs_find_domain(&ccs_dp, ccs_jump_list[i], + false, false); + if (index == EOF) + continue; + ccs_dp.list[index].is_dit = true; + ccs_dp.list[index].d_t = NULL; + ccs_dp.list[index].is_du = false; } - //max_index = dp->list_len; - /* Create missing parent domains. */ for (index = 0; index < max_index; index++) { char *line; ccs_get(); - line = ccs_shprintf("%s", ccs_domain_name(dp, index)); + line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index)); while (true) { char *cp = strrchr(line, ' '); if (!cp) break; *cp = '\0'; - if (ccs_find_domain(dp, line, false, false) != EOF) + if (ccs_find_domain(&ccs_dp, line, false, false) + != EOF) continue; - if (ccs_assign_domain(dp, line, false, true) == EOF) + if (ccs_assign_domain(&ccs_dp, line, false, true) + == EOF) ccs_out_of_memory(); } ccs_put(); } /* Sort by domain name. */ - qsort(dp->list, dp->list_len, sizeof(struct ccs_domain_info), + qsort(ccs_dp.list, ccs_dp.list_len, sizeof(struct ccs_domain_info), ccs_domainname_attribute_compare); /* Assign domain numbers. */ @@ -1241,23 +1688,30 @@ no_exception: int number = 0; int index; ccs_unnumbered_domain_count = 0; - for (index = 0; index < dp->list_len; index++) { - if (ccs_deleted_domain(dp, index) || - ccs_initializer_source(dp, index)) { - dp->list[index].number = -1; + for (index = 0; index < ccs_dp.list_len; index++) { + if (ccs_deleted_domain(index) || + ccs_initializer_source(index)) { + ccs_dp.list[index].number = -1; ccs_unnumbered_domain_count++; } else { - dp->list[index].number = number++; + ccs_dp.list[index].number = number++; } } } - dp->list_selected = realloc(dp->list_selected, dp->list_len); - if (dp->list_len && !dp->list_selected) + ccs_dp.list_selected = realloc(ccs_dp.list_selected, ccs_dp.list_len); + if (ccs_dp.list_len && !ccs_dp.list_selected) ccs_out_of_memory(); - memset(dp->list_selected, 0, dp->list_len); + memset(ccs_dp.list_selected, 0, ccs_dp.list_len); } +/** + * ccs_show_process_line - Print a process line. + * + * @index: Index in the ccs_task_list array. + * + * Returns length of the printed line. + */ static int ccs_show_process_line(const int index) { char *line; @@ -1273,23 +1727,31 @@ static int ccs_show_process_line(const int index) ccs_get(); line = ccs_shprintf("%s%s (%u) %s", ccs_task_list[index].depth ? " +- " : "", ccs_task_list[index].name, - ccs_task_list[index].pid, ccs_task_list[index].domain); + ccs_task_list[index].pid, + ccs_task_list[index].domain); printw("%s", ccs_eat(line)); tmp_col += strlen(line); ccs_put(); return tmp_col; } -static void ccs_show_list(struct ccs_domain_policy *dp) +/** + * ccs_show_list - Print list on the screen. + * + * Returns nothing. + */ +static void ccs_show_list(void) { - const int offset = ccs_current_item_index[ccs_current_screen]; + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + int ccs_list_indent; + const int offset = ptr->current; int i; int tmp_col; if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) - ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST] = ccs_domain_sort_type ? - ccs_task_list_len : dp->list_len; + ccs_list_item_count = ccs_domain_sort_type ? + ccs_task_list_len : ccs_dp.list_len; else - ccs_list_item_count[ccs_current_screen] = ccs_generic_acl_list_count; + ccs_list_item_count = ccs_gacl_list_count; clear(); move(0, 0); if (ccs_window_height < CCS_HEADER_LINES + 1) { @@ -1299,28 +1761,29 @@ static void ccs_show_list(struct ccs_domain_policy *dp) return; } /* add color */ - ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), true); + ccs_editpolicy_color_change(ccs_editpolicy_color_head(), true); if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { if (ccs_domain_sort_type) { printw("<<< Process State Viewer >>>" " %d process%s '?' for help", - ccs_task_list_len, ccs_task_list_len > 1 ? "es" : ""); + ccs_task_list_len, + ccs_task_list_len > 1 ? "es" : ""); } else { - int i = ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST] + int i = ccs_list_item_count - ccs_unnumbered_domain_count; printw("<<< Domain Transition Editor >>>" " %d domain%c '?' for help", i, i > 1 ? 's' : ' '); } } else { - int i = ccs_list_item_count[ccs_current_screen]; + int i = ccs_list_item_count; printw("<<< %s >>>" " %d entr%s '?' for help", ccs_list_caption, i, i > 1 ? "ies" : "y"); } /* add color */ - ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), false); - ccs_eat_col = ccs_max_eat_col[ccs_current_screen]; + ccs_editpolicy_color_change(ccs_editpolicy_color_head(), false); + ccs_eat_col = ptr->x; ccs_max_col = 0; if (ccs_current_screen == CCS_SCREEN_ACL_LIST) { char *line; @@ -1336,24 +1799,27 @@ static void ccs_show_list(struct ccs_domain_policy *dp) switch (ccs_current_screen) { case CCS_SCREEN_EXCEPTION_LIST: case CCS_SCREEN_ACL_LIST: - for (i = 0; i < ccs_list_item_count[ccs_current_screen]; i++) { - const u16 directive = ccs_generic_acl_list[i].directive; + for (i = 0; i < ccs_list_item_count; i++) { + const enum ccs_editpolicy_directives directive = + ccs_gacl_list[i].directive; const int len = ccs_directives[directive].alias_len; if (len > ccs_list_indent) ccs_list_indent = len; } break; + default: + break; } for (i = 0; i < ccs_body_lines; i++) { const int index = offset + i; - ccs_eat_col = ccs_max_eat_col[ccs_current_screen]; - if (index >= ccs_list_item_count[ccs_current_screen]) + ccs_eat_col = ptr->x; + if (index >= ccs_list_item_count) break; move(CCS_HEADER_LINES + i, 0); switch (ccs_current_screen) { case CCS_SCREEN_DOMAIN_LIST: if (!ccs_domain_sort_type) - tmp_col = ccs_show_domain_line(dp, index); + tmp_col = ccs_show_domain_line(index); else tmp_col = ccs_show_process_line(index); break; @@ -1364,8 +1830,8 @@ static void ccs_show_list(struct ccs_domain_policy *dp) case CCS_SCREEN_PROFILE_LIST: tmp_col = ccs_show_profile_line(index); break; - case CCS_SCREEN_MEMINFO_LIST: - tmp_col = ccs_show_meminfo_line(index); + case CCS_SCREEN_STAT_LIST: + tmp_col = ccs_show_stat_line(index); break; default: tmp_col = ccs_show_literal_line(index); @@ -1376,51 +1842,71 @@ static void ccs_show_list(struct ccs_domain_policy *dp) if (tmp_col > ccs_max_col) ccs_max_col = tmp_col; } - ccs_show_current(dp); + ccs_show_current(); } +/** + * ccs_resize_window - Callback for resize event. + * + * Returns nothing. + */ static void ccs_resize_window(void) { + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; getmaxyx(stdscr, ccs_window_height, ccs_window_width); ccs_body_lines = ccs_window_height - CCS_HEADER_LINES; - if (ccs_body_lines <= ccs_current_y[ccs_current_screen]) - ccs_current_y[ccs_current_screen] = ccs_body_lines - 1; - if (ccs_current_y[ccs_current_screen] < 0) - ccs_current_y[ccs_current_screen] = 0; + if (ccs_body_lines <= ptr->y) + ptr->y = ccs_body_lines - 1; + if (ptr->y < 0) + ptr->y = 0; } -static void ccs_up_arrow_key(struct ccs_domain_policy *dp) +/** + * ccs_up_arrow_key - Callback event for pressing up-arrow key. + * + * Returns nothing. + */ +static void ccs_up_arrow_key(void) { - if (ccs_current_y[ccs_current_screen] > 0) { - ccs_current_y[ccs_current_screen]--; - ccs_show_current(dp); - } else if (ccs_current_item_index[ccs_current_screen] > 0) { - ccs_current_item_index[ccs_current_screen]--; - ccs_show_list(dp); + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + if (ptr->y > 0) { + ptr->y--; + ccs_show_current(); + } else if (ptr->current > 0) { + ptr->current--; + ccs_show_list(); } } -static void ccs_down_arrow_key(struct ccs_domain_policy *dp) +/** + * ccs_down_arrow_key - Callback event for pressing down-arrow key. + * + * Returns nothing. + */ +static void ccs_down_arrow_key(void) { - if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1) { - if (ccs_current_item_index[ccs_current_screen] - + ccs_current_y[ccs_current_screen] - < ccs_list_item_count[ccs_current_screen] - 1) { - ccs_current_y[ccs_current_screen]++; - ccs_show_current(dp); + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + if (ptr->y < ccs_body_lines - 1) { + if (ptr->current + ptr->y < ccs_list_item_count - 1) { + ptr->y++; + ccs_show_current(); } - } else if (ccs_current_item_index[ccs_current_screen] - + ccs_current_y[ccs_current_screen] - < ccs_list_item_count[ccs_current_screen] - 1) { - ccs_current_item_index[ccs_current_screen]++; - ccs_show_list(dp); + } else if (ptr->current + ptr->y < ccs_list_item_count - 1) { + ptr->current++; + ccs_show_list(); } } -static void ccs_page_up_key(struct ccs_domain_policy *dp) +/** + * ccs_page_up_key - Callback event for pressing page-up key. + * + * Returns nothing. + */ +static void ccs_page_up_key(void) { - int p0 = ccs_current_item_index[ccs_current_screen]; - int p1 = ccs_current_y[ccs_current_screen]; + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + int p0 = ptr->current; + int p1 = ptr->y; _Bool refresh; if (p0 + p1 > ccs_body_lines) { p0 -= ccs_body_lines; @@ -1432,20 +1918,26 @@ static void ccs_page_up_key(struct ccs_domain_policy *dp) } else { return; } - refresh = (ccs_current_item_index[ccs_current_screen] != p0); - ccs_current_item_index[ccs_current_screen] = p0; - ccs_current_y[ccs_current_screen] = p1; + refresh = (ptr->current != p0); + ptr->current = p0; + ptr->y = p1; if (refresh) - ccs_show_list(dp); + ccs_show_list(); else - ccs_show_current(dp); + ccs_show_current(); } -static void ccs_page_down_key(struct ccs_domain_policy *dp) +/** + * ccs_page_down_key - Callback event for pressing page-down key. + * + * Returns nothing. + */ +static void ccs_page_down_key(void) { - int ccs_count = ccs_list_item_count[ccs_current_screen] - 1; - int p0 = ccs_current_item_index[ccs_current_screen]; - int p1 = ccs_current_y[ccs_current_screen]; + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + int ccs_count = ccs_list_item_count - 1; + int p0 = ptr->current; + int p1 = ptr->y; _Bool refresh; if (p0 + p1 + ccs_body_lines < ccs_count) { p0 += ccs_body_lines; @@ -1459,38 +1951,55 @@ static void ccs_page_down_key(struct ccs_domain_policy *dp) } else { return; } - refresh = (ccs_current_item_index[ccs_current_screen] != p0); - ccs_current_item_index[ccs_current_screen] = p0; - ccs_current_y[ccs_current_screen] = p1; + refresh = (ptr->current != p0); + ptr->current = p0; + ptr->y = p1; if (refresh) - ccs_show_list(dp); + ccs_show_list(); else - ccs_show_current(dp); + ccs_show_current(); } +/** + * ccs_editpolicy_get_current - Get currently selected line's index. + * + * Returns index for currently selected line on success, EOF otherwise. + * + * If current screen has no entry, this function returns EOF. + */ int ccs_editpolicy_get_current(void) { - int ccs_count = ccs_list_item_count[ccs_current_screen]; - const int p0 = ccs_current_item_index[ccs_current_screen]; - const int p1 = ccs_current_y[ccs_current_screen]; + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + int ccs_count = ccs_list_item_count; + const int p0 = ptr->current; + const int p1 = ptr->y; if (!ccs_count) return EOF; if (p0 + p1 < 0 || p0 + p1 >= ccs_count) { - fprintf(stderr, "ERROR: ccs_current_item_index=%d ccs_current_y=%d\n", + fprintf(stderr, + "ERROR: ccs_current_item_index=%d ccs_current_y=%d\n", p0, p1); exit(127); } return p0 + p1; } -static void ccs_show_current(struct ccs_domain_policy *dp) +/** + * ccs_show_current - Show current cursor line. + * + * Returns nothing. + */ +static void ccs_show_current(void) { - if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && !ccs_domain_sort_type) { + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && + !ccs_domain_sort_type) { char *line; const int index = ccs_editpolicy_get_current(); ccs_get(); - ccs_eat_col = ccs_max_eat_col[ccs_current_screen]; - line = ccs_shprintf("%s", ccs_eat(ccs_domain_name(dp, index))); + ccs_eat_col = ptr->x; + line = ccs_shprintf("%s", + ccs_eat(ccs_domain_name(&ccs_dp, index))); if (ccs_window_width < strlen(line)) line[ccs_window_width] = '\0'; move(2, 0); @@ -1500,46 +2009,70 @@ static void ccs_show_current(struct ccs_domain_policy *dp) ccs_editpolicy_attr_change(A_REVERSE, false); /* add color */ ccs_put(); } - move(CCS_HEADER_LINES + ccs_current_y[ccs_current_screen], 0); - ccs_editpolicy_line_draw(ccs_current_screen); /* add color */ + move(CCS_HEADER_LINES + ptr->y, 0); + ccs_editpolicy_line_draw(); /* add color */ refresh(); } +/** + * ccs_adjust_cursor_pos - Adjust cursor position if needed. + * + * @item_count: Available item count in this screen. + * + * Returns nothing. + */ static void ccs_adjust_cursor_pos(const int item_count) { + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; if (item_count == 0) { - ccs_current_item_index[ccs_current_screen] = 0; - ccs_current_y[ccs_current_screen] = 0; + ptr->current = 0; + ptr->y = 0; } else { - while (ccs_current_item_index[ccs_current_screen] - + ccs_current_y[ccs_current_screen] >= item_count) { - if (ccs_current_y[ccs_current_screen] > 0) - ccs_current_y[ccs_current_screen]--; - else if (ccs_current_item_index[ccs_current_screen] > 0) - ccs_current_item_index[ccs_current_screen]--; + while (ptr->current + ptr->y >= item_count) { + if (ptr->y > 0) + ptr->y--; + else if (ptr->current > 0) + ptr->current--; } } } +/** + * ccs_set_cursor_pos - Move cursor position if needed. + * + * @index: Index in the domain policy or currently selected line in the generic + * list. + * + * Returns nothing. + */ static void ccs_set_cursor_pos(const int index) { - while (index < ccs_current_y[ccs_current_screen] - + ccs_current_item_index[ccs_current_screen]) { - if (ccs_current_y[ccs_current_screen] > 0) - ccs_current_y[ccs_current_screen]--; + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + while (index < ptr->y + ptr->current) { + if (ptr->y > 0) + ptr->y--; else - ccs_current_item_index[ccs_current_screen]--; + ptr->current--; } - while (index > ccs_current_y[ccs_current_screen] - + ccs_current_item_index[ccs_current_screen]) { - if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1) - ccs_current_y[ccs_current_screen]++; + while (index > ptr->y + ptr->current) { + if (ptr->y < ccs_body_lines - 1) + ptr->y++; else - ccs_current_item_index[ccs_current_screen]++; + ptr->current++; } } -static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index) +/** + * ccs_select_item - Select an item. + * + * @index: Index in the domain policy or currently selected line in the generic + * list. + * + * Returns true if selected, false otherwise. + * + * Domain transition source and deleted domains are not selectable. + */ +static _Bool ccs_select_item(const int index) { int x; int y; @@ -1547,25 +2080,33 @@ static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index) return false; if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { if (!ccs_domain_sort_type) { - if (ccs_deleted_domain(dp, index) || - ccs_initializer_source(dp, index)) + if (ccs_deleted_domain(index) || + ccs_initializer_source(index)) return false; - dp->list_selected[index] ^= 1; + ccs_dp.list_selected[index] ^= 1; } else { ccs_task_list[index].selected ^= 1; } } else { - ccs_generic_acl_list[index].selected ^= 1; + ccs_gacl_list[index].selected ^= 1; } getyx(stdscr, y, x); ccs_editpolicy_sttr_save(); /* add color */ - ccs_show_list(dp); + ccs_show_list(); ccs_editpolicy_sttr_restore(); /* add color */ move(y, x); return true; } -static int ccs_generic_acl_compare(const void *a, const void *b) +/** + * ccs_gacl_compare - strcmp() for qsort() callback. + * + * @a: Pointer to "void". + * @b: Pointer to "void". + * + * Returns return value of strcmp(). + */ +static int ccs_gacl_compare(const void *a, const void *b) { const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a; const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b; @@ -1573,11 +2114,23 @@ static int ccs_generic_acl_compare(const void *a, const void *b) const char *b1 = ccs_directives[b0->directive].alias; const char *a2 = a0->operand; const char *b2 = b0->operand; - if (ccs_acl_sort_type == 0) { + if (!ccs_acl_sort_type) { const int ret = strcmp(a1, b1); if (ret) return ret; return strcmp(a2, b2); + } else if (a0->directive == CCS_DIRECTIVE_USE_GROUP) { + return 1; + } else if (b0->directive == CCS_DIRECTIVE_USE_GROUP) { + return -1; + } else if (a0->directive == CCS_DIRECTIVE_TRANSITION_FAILED) { + return 2; + } else if (b0->directive == CCS_DIRECTIVE_TRANSITION_FAILED) { + return -2; + } else if (a0->directive == CCS_DIRECTIVE_QUOTA_EXCEEDED) { + return 3; + } else if (b0->directive == CCS_DIRECTIVE_QUOTA_EXCEEDED) { + return -3; } else { const int ret = strcmp(a2, b2); if (ret) @@ -1586,25 +2139,33 @@ static int ccs_generic_acl_compare(const void *a, const void *b) } } -static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index) +/** + * ccs_delete_entry - Delete an entry. + * + * @index: Index in the domain policy. + * + * Returns nothing. + */ +static void ccs_delete_entry(const int index) { #ifndef __GPET int c; move(1, 0); ccs_editpolicy_color_change(CCS_DISP_ERR, true); /* add color */ if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { - c = ccs_count(dp->list_selected, dp->list_len); - if (!c && index < dp->list_len) - c = ccs_select_item(dp, index); + c = ccs_count(ccs_dp.list_selected, ccs_dp.list_len); + if (!c && index < ccs_dp.list_len) + c = ccs_select_item(index); if (!c) printw("Select domain using Space key first."); else printw("Delete selected domain%s? ('Y'es/'N'o)", c > 1 ? "s" : ""); } else { - c = ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count); + c = ccs_count2(ccs_gacl_list, + ccs_gacl_list_count); if (!c) - c = ccs_select_item(dp, index); + c = ccs_select_item(index); if (!c) printw("Select entry using Space key first."); else @@ -1621,19 +2182,21 @@ static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index) } while (!(c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == EOF)); ccs_resize_window(); if (c != 'Y' && c != 'y') { - ccs_show_list(dp); + ccs_show_list(); return; } #endif /* __GPET */ if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { int i; - FILE *fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY); + FILE *fp = ccs_editpolicy_open_write + (CCS_PROC_POLICY_DOMAIN_POLICY); if (!fp) return; - for (i = 1; i < dp->list_len; i++) { - if (!dp->list_selected[i]) + for (i = 1; i < ccs_dp.list_len; i++) { + if (!ccs_dp.list_selected[i]) continue; - fprintf(fp, "delete %s\n", ccs_domain_name(dp, i)); + fprintf(fp, "delete %s\n", + ccs_domain_name(&ccs_dp, i)); } ccs_close_write(fp); } else { @@ -1643,36 +2206,43 @@ static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index) return; if (ccs_current_screen == CCS_SCREEN_ACL_LIST) { if (ccs_domain_sort_type) - fprintf(fp, "select pid=%u\n", ccs_current_pid); + fprintf(fp, "select pid=%u\n", + ccs_current_pid); else fprintf(fp, "select domain=%s\n", ccs_current_domain); } - for (i = 0; i < ccs_generic_acl_list_count; i++) { - u16 directive; - if (!ccs_generic_acl_list[i].selected) + for (i = 0; i < ccs_gacl_list_count; i++) { + enum ccs_editpolicy_directives directive; + if (!ccs_gacl_list[i].selected) continue; - directive = ccs_generic_acl_list[i].directive; + directive = ccs_gacl_list[i].directive; fprintf(fp, "delete %s %s\n", ccs_directives[directive].original, - ccs_generic_acl_list[i].operand); + ccs_gacl_list[i].operand); } ccs_close_write(fp); } } -static void ccs_add_entry(struct ccs_readline_data *rl) +/** + * ccs_add_entry - Add an entry. + * + * Returns nothing. + */ +static void ccs_add_entry(void) { FILE *fp; char *line; #ifndef __GPET ccs_editpolicy_attr_change(A_BOLD, true); /* add color */ line = ccs_readline(ccs_window_height - 1, 0, "Enter new entry> ", - rl->history, rl->count, 128000, 8); + ccs_rl.history, ccs_rl.count, 128000, 8); ccs_editpolicy_attr_change(A_BOLD, false); /* add color */ if (!line || !*line) goto out; - rl->count = ccs_add_history(line, rl->history, rl->count, rl->max); + ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count, + ccs_rl.max); #else line = gpet_line; #endif @@ -1680,7 +2250,7 @@ static void ccs_add_entry(struct ccs_readline_data *rl) if (!fp) goto out; switch (ccs_current_screen) { - u16 directive; + enum ccs_editpolicy_directives directive; case CCS_SCREEN_DOMAIN_LIST: if (!ccs_correct_domain(line)) { const int len = strlen(line) + 128; @@ -1709,6 +2279,8 @@ static void ccs_add_entry(struct ccs_readline_data *rl) if (!strchr(line, '=')) fprintf(fp, "%s-COMMENT=\n", line); break; + default: + break; } fprintf(fp, "%s\n", line); ccs_close_write(fp); @@ -1716,8 +2288,17 @@ out: free(line); } -static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward, - const int current, struct ccs_readline_data *rl) +/** + * ccs_find_entry - Find an entry by user's key input. + * + * @input: True if find next/previous, false if find first. + * @forward: True if find next, false if find previous. + * @current: Current position. + * + * Returns nothing. + */ +static void ccs_find_entry(const _Bool input, const _Bool forward, + const int current) { int index = current; char *line = NULL; @@ -1727,13 +2308,14 @@ static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forw goto start_search; ccs_editpolicy_attr_change(A_BOLD, true); /* add color */ line = ccs_readline(ccs_window_height - 1, 0, "Search> ", - rl->history, rl->count, 128000, 8); + ccs_rl.history, ccs_rl.count, 128000, 8); ccs_editpolicy_attr_change(A_BOLD, false); /* add color */ if (!line || !*line) goto out; - rl->count = ccs_add_history(line, rl->history, rl->count, rl->max); - free(rl->search_buffer[ccs_current_screen]); - rl->search_buffer[ccs_current_screen] = line; + ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count, + ccs_rl.max); + free(ccs_rl.search_buffer[ccs_current_screen]); + ccs_rl.search_buffer[ccs_current_screen] = line; line = NULL; index = -1; start_search: @@ -1741,7 +2323,7 @@ start_search: while (true) { const char *cp; if (forward) { - if (++index >= ccs_list_item_count[ccs_current_screen]) + if (++index >= ccs_list_item_count) break; } else { if (--index < 0) @@ -1751,17 +2333,19 @@ start_search: if (ccs_domain_sort_type) cp = ccs_task_list[index].name; else - cp = ccs_get_last_name(dp, index); + cp = ccs_get_last_name(index); } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) { cp = ccs_shprintf("%u-%s", - ccs_generic_acl_list[index].directive, - ccs_generic_acl_list[index].operand); + ccs_gacl_list[index].directive, + ccs_gacl_list[index].operand); } else { - const u16 directive = ccs_generic_acl_list[index].directive; - cp = ccs_shprintf("%s %s", ccs_directives[directive].alias, - ccs_generic_acl_list[index].operand); + const enum ccs_editpolicy_directives directive = + ccs_gacl_list[index].directive; + cp = ccs_shprintf("%s %s", + ccs_directives[directive].alias, + ccs_gacl_list[index].operand); } - if (!strstr(cp, rl->search_buffer[ccs_current_screen])) + if (!strstr(cp, ccs_rl.search_buffer[ccs_current_screen])) continue; ccs_set_cursor_pos(index); break; @@ -1769,18 +2353,25 @@ start_search: ccs_put(); out: free(line); - ccs_show_list(dp); + ccs_show_list(); } -static void ccs_set_profile(struct ccs_domain_policy *dp, const int current) +/** + * ccs_set_profile - Change profile number. + * + * @current: Currently selected line in the generic list. + * + * Returns nothing. + */ +static void ccs_set_profile(const int current) { int index; FILE *fp; char *line; #ifndef __GPET if (!ccs_domain_sort_type) { - if (!ccs_count(dp->list_selected, dp->list_len) && - !ccs_select_item(dp, current)) { + if (!ccs_count(ccs_dp.list_selected, ccs_dp.list_len) && + !ccs_select_item(current)) { move(1, 0); printw("Select domain using Space key first."); clrtoeol(); @@ -1789,7 +2380,7 @@ static void ccs_set_profile(struct ccs_domain_policy *dp, const int current) } } else { if (!ccs_count3(ccs_task_list, ccs_task_list_len) && - !ccs_select_item(dp, current)) { + !ccs_select_item(current)) { move(1, 0); printw("Select processes using Space key first."); clrtoeol(); @@ -1810,11 +2401,11 @@ static void ccs_set_profile(struct ccs_domain_policy *dp, const int current) if (!fp) goto out; if (!ccs_domain_sort_type) { - for (index = 0; index < dp->list_len; index++) { - if (!dp->list_selected[index]) + for (index = 0; index < ccs_dp.list_len; index++) { + if (!ccs_dp.list_selected[index]) continue; fprintf(fp, "select domain=%s\n" "use_profile %s\n", - ccs_domain_name(dp, index), line); + ccs_domain_name(&ccs_dp, index), line); } } else { for (index = 0; index < ccs_task_list_len; index++) { @@ -1829,21 +2420,28 @@ out: free(line); } -static void ccs_set_level(struct ccs_domain_policy *dp, const int current) +/** + * ccs_set_level - Change profiles. + * + * @current: Currently selected line in the generic list. + * + * Returns nothing. + */ +static void ccs_set_level(const int current) { int index; FILE *fp; char *line; #ifndef __GPET - if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count)) - ccs_select_item(dp, current); + if (!ccs_count2(ccs_gacl_list, ccs_gacl_list_count)) + ccs_select_item(current); ccs_editpolicy_attr_change(A_BOLD, true); /* add color */ ccs_initial_readline_data = NULL; - for (index = 0; index < ccs_generic_acl_list_count; index++) { + for (index = 0; index < ccs_gacl_list_count; index++) { char *cp; - if (!ccs_generic_acl_list[index].selected) + if (!ccs_gacl_list[index].selected) continue; - cp = strchr(ccs_generic_acl_list[index].operand, '='); + cp = strchr(ccs_gacl_list[index].operand, '='); if (!cp) continue; ccs_initial_readline_data = cp + 1; @@ -1861,18 +2459,18 @@ static void ccs_set_level(struct ccs_domain_policy *dp, const int current) fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_PROFILE); if (!fp) goto out; - for (index = 0; index < ccs_generic_acl_list_count; index++) { + for (index = 0; index < ccs_gacl_list_count; index++) { char *buf; char *cp; - u16 directive; - if (!ccs_generic_acl_list[index].selected) + enum ccs_editpolicy_directives directive; + if (!ccs_gacl_list[index].selected) continue; ccs_get(); - buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand); + buf = ccs_shprintf("%s", ccs_gacl_list[index].operand); cp = strchr(buf, '='); if (cp) *cp = '\0'; - directive = ccs_generic_acl_list[index].directive; + directive = ccs_gacl_list[index].directive; if (directive < 256) fprintf(fp, "%u-", directive); fprintf(fp, "%s=%s\n", buf, line); @@ -1883,14 +2481,21 @@ out: free(line); } -static void ccs_set_quota(struct ccs_domain_policy *dp, const int current) +/** + * ccs_set_quota - Set memory quota. + * + * @current: Currently selected line in the generic list. + * + * Returns nothing. + */ +static void ccs_set_quota(const int current) { int index; FILE *fp; char *line; #ifndef __GPET - if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count)) - ccs_select_item(dp, current); + if (!ccs_count2(ccs_gacl_list, ccs_gacl_list_count)) + ccs_select_item(current); ccs_editpolicy_attr_change(A_BOLD, true); /* add color */ line = ccs_readline(ccs_window_height - 1, 0, "Enter new value> ", NULL, 0, 20, 1); @@ -1900,16 +2505,16 @@ static void ccs_set_quota(struct ccs_domain_policy *dp, const int current) #endif if (!line || !*line) goto out; - fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_MEMINFO); + fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_STAT); if (!fp) goto out; - for (index = 0; index < ccs_generic_acl_list_count; index++) { + for (index = 0; index < ccs_gacl_list_count; index++) { char *buf; char *cp; - if (!ccs_generic_acl_list[index].selected) + if (!ccs_gacl_list[index].selected) continue; ccs_get(); - buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand); + buf = ccs_shprintf("%s", ccs_gacl_list[index].operand); cp = strchr(buf, ':'); if (cp) *cp = '\0'; @@ -1921,57 +2526,70 @@ out: free(line); } -static _Bool ccs_select_acl_window(struct ccs_domain_policy *dp, const int current, - const _Bool may_refresh) +/** + * ccs_select_acl_window - Check whether to switch to ACL list or not. + * + * @current: Index in the domain policy. + * + * Returns true if next window is ACL list, false otherwise. + */ +static _Bool ccs_select_acl_window(const int current) { + char *old_domain; if (ccs_current_screen != CCS_SCREEN_DOMAIN_LIST || current == EOF) return false; ccs_current_pid = 0; if (ccs_domain_sort_type) { ccs_current_pid = ccs_task_list[current].pid; - } else if (ccs_initializer_source(dp, current)) { - int redirect_index; - if (!may_refresh) - return false; - redirect_index = ccs_find_target_domain(dp, current); + } else if (ccs_initializer_source(current)) { + struct ccs_screen *ptr = &ccs_screen[ccs_current_screen]; + const int redirect_index = ccs_find_target_domain(current); if (redirect_index == EOF) return false; - ccs_current_item_index[ccs_current_screen] - = redirect_index - ccs_current_y[ccs_current_screen]; - while (ccs_current_item_index[ccs_current_screen] < 0) { - ccs_current_item_index[ccs_current_screen]++; - ccs_current_y[ccs_current_screen]--; + ptr->current = redirect_index - ptr->y; + while (ptr->current < 0) { + ptr->current++; + ptr->y--; } - ccs_show_list(dp); + ccs_show_list(); return false; - } else if (ccs_deleted_domain(dp, current)) { + } else if (ccs_deleted_domain(current)) { return false; } - free(ccs_current_domain); + old_domain = ccs_current_domain; if (ccs_domain_sort_type) ccs_current_domain = strdup(ccs_task_list[current].domain); else - ccs_current_domain = strdup(ccs_domain_name(dp, current)); + ccs_current_domain = strdup(ccs_domain_name(&ccs_dp, current)); if (!ccs_current_domain) ccs_out_of_memory(); + ccs_no_restore_cursor = old_domain && + strcmp(old_domain, ccs_current_domain); + free(old_domain); return true; } -static int ccs_select_window(struct ccs_domain_policy *dp, const int current) +/** + * ccs_select_window - Switch window. + * + * @current: Index in the domain policy. + * + * Returns next window to display. + */ +static enum ccs_screen_type ccs_select_window(const int current) { move(0, 0); printw("Press one of below keys to switch window.\n\n"); printw("e <<< Exception Policy Editor >>>\n"); printw("d <<< Domain Transition Editor >>>\n"); if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && current != EOF && - !ccs_initializer_source(dp, current) && - !ccs_deleted_domain(dp, current)) + !ccs_initializer_source(current) && !ccs_deleted_domain(current)) printw("a <<< Domain Policy Editor >>>\n"); printw("p <<< Profile Editor >>>\n"); printw("m <<< Manager Policy Editor >>>\n"); if (!ccs_offline_mode) { /* printw("i <<< Interactive Enforcing Mode >>>\n"); */ - printw("u <<< Memory Usage >>>\n"); + printw("s <<< Statistics >>>\n"); } printw("q Quit this editor.\n"); clrtobot(); @@ -1983,7 +2601,7 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current) if (c == 'D' || c == 'd') return CCS_SCREEN_DOMAIN_LIST; if (c == 'A' || c == 'a') - if (ccs_select_acl_window(dp, current, false)) + if (ccs_select_acl_window(current)) return CCS_SCREEN_ACL_LIST; if (c == 'P' || c == 'p') return CCS_SCREEN_PROFILE_LIST; @@ -1994,8 +2612,8 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current) if (c == 'I' || c == 'i') return CCS_SCREEN_QUERY_LIST; */ - if (c == 'U' || c == 'u') - return CCS_SCREEN_MEMINFO_LIST; + if (c == 'S' || c == 's') + return CCS_SCREEN_STAT_LIST; } if (c == 'Q' || c == 'q') return CCS_MAXSCREEN; @@ -2004,78 +2622,92 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current) } } -static void ccs_copy_mark_state(struct ccs_domain_policy *dp, const int current) +/** + * ccs_copy_mark_state - Copy selected state to lines under the current line. + * + * @current: Index in the domain policy. + * + * Returns nothing. + */ +static void ccs_copy_mark_state(const int current) { int index; if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { if (ccs_domain_sort_type) { const u8 selected = ccs_task_list[current].selected; - for (index = current; index < ccs_task_list_len; index++) + for (index = current; index < ccs_task_list_len; + index++) ccs_task_list[index].selected = selected; } else { - const u8 selected = dp->list_selected[current]; - if (ccs_deleted_domain(dp, current) || - ccs_initializer_source(dp, current)) + const u8 selected = ccs_dp.list_selected[current]; + if (ccs_deleted_domain(current) || + ccs_initializer_source(current)) return; - for (index = current; - index < dp->list_len; index++) { - if (ccs_deleted_domain(dp, index) || - ccs_initializer_source(dp, index)) + for (index = current; index < ccs_dp.list_len; + index++) { + if (ccs_deleted_domain(index) || + ccs_initializer_source(index)) continue; - dp->list_selected[index] = selected; + ccs_dp.list_selected[index] = selected; } } } else { - const u8 selected = ccs_generic_acl_list[current].selected; - for (index = current; index < ccs_generic_acl_list_count; index++) - ccs_generic_acl_list[index].selected = selected; + const u8 selected = ccs_gacl_list[current].selected; + for (index = current; index < ccs_gacl_list_count; + index++) + ccs_gacl_list[index].selected = selected; } - ccs_show_list(dp); + ccs_show_list(); } -static void ccs_copy_to_history(struct ccs_domain_policy *dp, const int current, - struct ccs_readline_data *rl) +/** + * ccs_copy_to_history - Copy line to histoy buffer. + * + * @current: Index in the domain policy. + * + * Returns nothing. + */ +static void ccs_copy_to_history(const int current) { const char *line; if (current == EOF) return; ccs_get(); switch (ccs_current_screen) { - u16 directive; + enum ccs_editpolicy_directives directive; case CCS_SCREEN_DOMAIN_LIST: - line = ccs_domain_name(dp, current); + line = ccs_domain_name(&ccs_dp, current); break; case CCS_SCREEN_EXCEPTION_LIST: case CCS_SCREEN_ACL_LIST: - directive = ccs_generic_acl_list[current].directive; + directive = ccs_gacl_list[current].directive; line = ccs_shprintf("%s %s", ccs_directives[directive].alias, - ccs_generic_acl_list[current].operand); + ccs_gacl_list[current].operand); break; - case CCS_SCREEN_MEMINFO_LIST: + case CCS_SCREEN_STAT_LIST: line = NULL; break; default: - line = ccs_shprintf("%s", ccs_generic_acl_list[current].operand); + line = ccs_shprintf("%s", + ccs_gacl_list[current].operand); } - rl->count = ccs_add_history(line, rl->history, rl->count, rl->max); + ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count, + ccs_rl.max); ccs_put(); } -static int ccs_generic_list_loop(struct ccs_domain_policy *dp) +/** + * ccs_generic_list_loop - Main loop. + * + * Returns next screen to display. + */ +static enum ccs_screen_type ccs_generic_list_loop(void) { - static struct ccs_readline_data rl; - static int saved_current_y[CCS_MAXSCREEN]; - static int saved_current_item_index[CCS_MAXSCREEN]; - static _Bool first = true; - if (first) { - memset(&rl, 0, sizeof(rl)); - rl.max = 20; - rl.history = malloc(rl.max * sizeof(const char *)); - memset(saved_current_y, 0, sizeof(saved_current_y)); - memset(saved_current_item_index, 0, - sizeof(saved_current_item_index)); - first = false; - } + struct ccs_screen *ptr; + static struct { + int y; + int current; + } saved_cursor[CCS_MAXSCREEN] = { }; if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST) { ccs_policy_file = CCS_PROC_POLICY_EXCEPTION_POLICY; ccs_list_caption = "Exception Policy Editor"; @@ -2091,34 +2723,40 @@ static int ccs_generic_list_loop(struct ccs_domain_policy *dp) } else if (ccs_current_screen == CCS_SCREEN_MANAGER_LIST) { ccs_policy_file = CCS_PROC_POLICY_MANAGER; ccs_list_caption = "Manager Policy Editor"; - } else if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST) { - ccs_policy_file = CCS_PROC_POLICY_MEMINFO; - ccs_list_caption = "Memory Usage"; + } else if (ccs_current_screen == CCS_SCREEN_STAT_LIST) { + ccs_policy_file = CCS_PROC_POLICY_STAT; + ccs_list_caption = "Statistics"; } else { ccs_policy_file = CCS_PROC_POLICY_DOMAIN_POLICY; /* ccs_list_caption = "Domain Transition Editor"; */ } - ccs_current_item_index[ccs_current_screen] - = saved_current_item_index[ccs_current_screen]; - ccs_current_y[ccs_current_screen] = saved_current_y[ccs_current_screen]; + ptr = &ccs_screen[ccs_current_screen]; + if (ccs_no_restore_cursor) { + ptr->current = 0; + ptr->y = 0; + ccs_no_restore_cursor = false; + } else { + ptr->current = saved_cursor[ccs_current_screen].current; + ptr->y = saved_cursor[ccs_current_screen].y; + } start: if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) { - if (ccs_domain_sort_type == 0) { - ccs_read_domain_and_exception_policy(dp); - ccs_adjust_cursor_pos(dp->list_len); + if (!ccs_domain_sort_type) { + ccs_read_domain_and_exception_policy(); + ccs_adjust_cursor_pos(ccs_dp.list_len); } else { ccs_read_process_list(true); ccs_adjust_cursor_pos(ccs_task_list_len); } } else { ccs_read_generic_policy(); - ccs_adjust_cursor_pos(ccs_generic_acl_list_count); + ccs_adjust_cursor_pos(ccs_gacl_list_count); } #ifdef __GPET return 0; #else start2: - ccs_show_list(dp); + ccs_show_list(); if (ccs_last_error) { move(1, 0); printw("ERROR: %s", ccs_last_error); @@ -2130,9 +2768,8 @@ start2: while (true) { const int current = ccs_editpolicy_get_current(); const int c = ccs_getch2(); - saved_current_item_index[ccs_current_screen] - = ccs_current_item_index[ccs_current_screen]; - saved_current_y[ccs_current_screen] = ccs_current_y[ccs_current_screen]; + saved_cursor[ccs_current_screen].current = ptr->current; + saved_cursor[ccs_current_screen].y = ptr->y; if (c == 'q' || c == 'Q') return CCS_MAXSCREEN; if ((c == '\r' || c == '\n') && @@ -2153,52 +2790,52 @@ start2: switch (c) { case KEY_RESIZE: ccs_resize_window(); - ccs_show_list(dp); + ccs_show_list(); break; case KEY_UP: - ccs_up_arrow_key(dp); + ccs_up_arrow_key(); break; case KEY_DOWN: - ccs_down_arrow_key(dp); + ccs_down_arrow_key(); break; case KEY_PPAGE: - ccs_page_up_key(dp); + ccs_page_up_key(); break; case KEY_NPAGE: - ccs_page_down_key(dp); + ccs_page_down_key(); break; case ' ': - ccs_select_item(dp, current); + ccs_select_item(current); break; case 'c': case 'C': if (current == EOF) break; - ccs_copy_mark_state(dp, current); - ccs_show_list(dp); + ccs_copy_mark_state(current); + ccs_show_list(); break; case 'f': case 'F': - if (ccs_current_screen != CCS_SCREEN_MEMINFO_LIST) - ccs_find_entry(dp, true, true, current, &rl); + if (ccs_current_screen != CCS_SCREEN_STAT_LIST) + ccs_find_entry(true, true, current); break; case 'p': case 'P': - if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST) + if (ccs_current_screen == CCS_SCREEN_STAT_LIST) break; - if (!rl.search_buffer[ccs_current_screen]) - ccs_find_entry(dp, true, false, current, &rl); + if (!ccs_rl.search_buffer[ccs_current_screen]) + ccs_find_entry(true, false, current); else - ccs_find_entry(dp, false, false, current, &rl); + ccs_find_entry(false, false, current); break; case 'n': case 'N': - if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST) + if (ccs_current_screen == CCS_SCREEN_STAT_LIST) break; - if (!rl.search_buffer[ccs_current_screen]) - ccs_find_entry(dp, true, true, current, &rl); + if (!ccs_rl.search_buffer[ccs_current_screen]) + ccs_find_entry(true, true, current); else - ccs_find_entry(dp, false, true, current, &rl); + ccs_find_entry(false, true, current); break; case 'd': case 'D': @@ -2211,8 +2848,10 @@ start2: case CCS_SCREEN_EXCEPTION_LIST: case CCS_SCREEN_ACL_LIST: case CCS_SCREEN_MANAGER_LIST: - ccs_delete_entry(dp, current); + ccs_delete_entry(current); goto start; + default: + break; } break; case 'a': @@ -2227,13 +2866,15 @@ start2: case CCS_SCREEN_ACL_LIST: case CCS_SCREEN_PROFILE_LIST: case CCS_SCREEN_MANAGER_LIST: - ccs_add_entry(&rl); + ccs_add_entry(); goto start; + default: + break; } break; case '\r': case '\n': - if (ccs_select_acl_window(dp, current, true)) + if (ccs_select_acl_window(current)) return CCS_SCREEN_ACL_LIST; break; case 's': @@ -2242,62 +2883,68 @@ start2: break; switch (ccs_current_screen) { case CCS_SCREEN_DOMAIN_LIST: - ccs_set_profile(dp, current); + ccs_set_profile(current); goto start; case CCS_SCREEN_PROFILE_LIST: - ccs_set_level(dp, current); + ccs_set_level(current); goto start; - case CCS_SCREEN_MEMINFO_LIST: - ccs_set_quota(dp, current); + case CCS_SCREEN_STAT_LIST: + ccs_set_quota(current); goto start; + default: + break; } break; case 'r': case 'R': goto start; case KEY_LEFT: - if (!ccs_max_eat_col[ccs_current_screen]) + if (!ptr->x) break; - ccs_max_eat_col[ccs_current_screen]--; + ptr->x--; goto start2; case KEY_RIGHT: - ccs_max_eat_col[ccs_current_screen]++; + ptr->x++; goto start2; case KEY_HOME: - ccs_max_eat_col[ccs_current_screen] = 0; + ptr->x = 0; goto start2; case KEY_END: - ccs_max_eat_col[ccs_current_screen] = ccs_max_col; + ptr->x = ccs_max_col; goto start2; case KEY_IC: - ccs_copy_to_history(dp, current, &rl); + ccs_copy_to_history(current); break; case 'o': case 'O': if (ccs_current_screen == CCS_SCREEN_ACL_LIST) { - ccs_editpolicy_try_optimize(dp, current, - ccs_current_screen); - ccs_show_list(dp); + ccs_editpolicy_optimize(current); + ccs_show_list(); } break; case '@': - if (ccs_current_screen == CCS_SCREEN_ACL_LIST) { - ccs_acl_sort_type = (ccs_acl_sort_type + 1) % 2; + switch (ccs_current_screen) { + case CCS_SCREEN_ACL_LIST: + ccs_acl_sort_type = !ccs_acl_sort_type; goto start; - } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) { - ccs_profile_sort_type = (ccs_profile_sort_type + 1) % 2; + case CCS_SCREEN_PROFILE_LIST: + ccs_profile_sort_type = !ccs_profile_sort_type; goto start; - } else if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && - !ccs_offline_mode) { - ccs_domain_sort_type = (ccs_domain_sort_type + 1) % 2; + case CCS_SCREEN_DOMAIN_LIST: + if (ccs_offline_mode) + break; + ccs_domain_sort_type = !ccs_domain_sort_type; goto start; + default: + break; } break; case 'w': case 'W': - return ccs_select_window(dp, current); + return ccs_select_window(current); case '?': - if (ccs_show_command_key(ccs_current_screen, ccs_readonly_mode)) + if (ccs_show_command_key(ccs_current_screen, + ccs_readonly_mode)) goto start; return CCS_MAXSCREEN; } @@ -2305,6 +2952,14 @@ start2: #endif /* __GPET */ } +/** + * ccs_save_to_file - Save policy to file. + * + * @src: Filename to read from. + * @dest: Filename to write to. + * + * Returns true on success, false otherwise. + */ static _Bool ccs_save_to_file(const char *src, const char *dest) { FILE *proc_fp = ccs_editpolicy_open_read(src); @@ -2325,6 +2980,167 @@ static _Bool ccs_save_to_file(const char *src, const char *dest) return true; } +/** + * ccs_parse_args - Parse command line arguments. + * + * @argc: argc passed to main(). + * @argv: argv passed to main(). + * + * Returns nothing. + */ +static void ccs_parse_args(int argc, char *argv[]) +{ + int i; + for (i = 1; i < argc; i++) { + char *ptr = argv[i]; + char *cp = strchr(ptr, ':'); + if (*ptr == '/') { + if (ccs_network_mode || ccs_offline_mode) + goto usage; + ccs_policy_dir = ptr; + ccs_offline_mode = true; + } else if (cp) { + *cp++ = '\0'; + if (ccs_network_mode || ccs_offline_mode) + goto usage; + ccs_network_ip = inet_addr(ptr); + ccs_network_port = htons(atoi(cp)); + ccs_network_mode = true; + if (!ccs_check_remote_host()) + exit(1); + } else if (!strcmp(ptr, "e")) + ccs_current_screen = CCS_SCREEN_EXCEPTION_LIST; + else if (!strcmp(ptr, "d")) + ccs_current_screen = CCS_SCREEN_DOMAIN_LIST; + else if (!strcmp(ptr, "p")) + ccs_current_screen = CCS_SCREEN_PROFILE_LIST; + else if (!strcmp(ptr, "m")) + ccs_current_screen = CCS_SCREEN_MANAGER_LIST; + else if (!strcmp(ptr, "s")) + ccs_current_screen = CCS_SCREEN_STAT_LIST; + else if (!strcmp(ptr, "readonly")) + ccs_readonly_mode = true; + else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval) + != 1) { +usage: + printf("Usage: %s [e|d|p|m|s] [readonly] " + "[refresh=interval] " + "[{policy_dir|remote_ip:remote_port}]\n", + argv[0]); + exit(1); + } + } +} + +/** + * ccs_load_offline - Load policy for offline mode. + * + * Returns nothing. + */ +static void ccs_load_offline(void) +{ + int fd[2] = { EOF, EOF }; + if (chdir(ccs_policy_dir) || chdir("policy/current/")) { + fprintf(stderr, "Directory %s/policy/current/ doesn't " + "exist.\n", ccs_policy_dir); + exit(1); + } + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) { + fprintf(stderr, "socketpair()\n"); + exit(1); + } + switch (fork()) { + case 0: + close(fd[0]); + ccs_persistent_fd = fd[1]; + ccs_editpolicy_offline_daemon(); + _exit(0); + case -1: + fprintf(stderr, "fork()\n"); + exit(1); + } + close(fd[1]); + ccs_persistent_fd = fd[0]; + ccs_copy_file("exception_policy.conf", + CCS_PROC_POLICY_EXCEPTION_POLICY); + ccs_copy_file("domain_policy.conf", CCS_PROC_POLICY_DOMAIN_POLICY); + ccs_copy_file("profile.conf", CCS_PROC_POLICY_PROFILE); + ccs_copy_file("manager.conf", CCS_PROC_POLICY_MANAGER); + if (chdir("..")) { + fprintf(stderr, "Directory %s/policy/ doesn't exist.\n", + ccs_policy_dir); + exit(1); + } +} + +/** + * ccs_load_readwrite - Check that this program can write to /proc/ccs/ interface. + * + * Returns nothing. + */ +static void ccs_load_readwrite(void) +{ + const int fd1 = ccs_open2(CCS_PROC_POLICY_EXCEPTION_POLICY, O_RDWR); + const int fd2 = ccs_open2(CCS_PROC_POLICY_DOMAIN_POLICY, O_RDWR); + if ((fd1 != EOF && write(fd1, "", 0) != 0) || + (fd2 != EOF && write(fd2, "", 0) != 0)) { + fprintf(stderr, "In order to run this program, it must be " + "registered to %s . " + "Please reboot.\n", CCS_PROC_POLICY_MANAGER); + exit(1); + } + close(fd1); + close(fd2); +} + +/** + * ccs_save_offline - Save policy for offline mode. + * + * Returns nothing. + */ +static void ccs_save_offline(void) +{ + time_t now = time(NULL); + static char stamp[32] = { }; + while (1) { + struct tm *tm = localtime(&now); + snprintf(stamp, sizeof(stamp) - 1, + "%02d-%02d-%02d.%02d:%02d:%02d/", + tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + if (!mkdir(stamp, 0700)) + break; + else if (errno == EEXIST) + now++; + else { + fprintf(stderr, "Can't create %s/%s .\n", + ccs_policy_dir, stamp); + exit(1); + } + } + if ((symlink("policy/current/profile.conf", "../profile.conf") && + errno != EEXIST) || + (symlink("policy/current/manager.conf", "../manager.conf") && + errno != EEXIST) || + (symlink("policy/current/exception_policy.conf", + "../exception_policy.conf") && errno != EEXIST) || + (symlink("policy/current/domain_policy.conf", + "../domain_policy.conf") && errno != EEXIST) || + chdir(stamp) || + !ccs_save_to_file(CCS_PROC_POLICY_PROFILE, "profile.conf") || + !ccs_save_to_file(CCS_PROC_POLICY_MANAGER, "manager.conf") || + !ccs_save_to_file(CCS_PROC_POLICY_EXCEPTION_POLICY, + "exception_policy.conf") || + !ccs_save_to_file(CCS_PROC_POLICY_DOMAIN_POLICY, + "domain_policy.conf") || + chdir("..") || + (rename("current", "previous") && errno != ENOENT) || + symlink(stamp, "current")) { + fprintf(stderr, "Failed to save policy.\n"); + exit(1); + } +} + #ifdef __GPET /* gpet */ int gpet_main(void); int ccs_main(int argc, char *argv[]) @@ -2332,106 +3148,22 @@ int ccs_main(int argc, char *argv[]) int main(int argc, char *argv[]) #endif /* gpet */ { - struct ccs_domain_policy dp = { NULL, 0, NULL }; - struct ccs_domain_policy bp = { NULL, 0, NULL }; - memset(ccs_current_y, 0, sizeof(ccs_current_y)); - memset(ccs_current_item_index, 0, sizeof(ccs_current_item_index)); - memset(ccs_list_item_count, 0, sizeof(ccs_list_item_count)); - memset(ccs_max_eat_col, 0, sizeof(ccs_max_eat_col)); - if (argc > 1) { - int i; - for (i = 1; i < argc; i++) { - char *ptr = argv[i]; - char *cp = strchr(ptr, ':'); - if (*ptr == '/') { - if (ccs_network_mode || ccs_offline_mode) - goto usage; - ccs_policy_dir = ptr; - ccs_offline_mode = true; - } else if (cp) { - *cp++ = '\0'; - if (ccs_network_mode || ccs_offline_mode) - goto usage; - ccs_network_ip = inet_addr(ptr); - ccs_network_port = htons(atoi(cp)); - ccs_network_mode = true; - if (!ccs_check_remote_host()) - return 1; - } else if (!strcmp(ptr, "e")) - ccs_current_screen = CCS_SCREEN_EXCEPTION_LIST; - else if (!strcmp(ptr, "d")) - ccs_current_screen = CCS_SCREEN_DOMAIN_LIST; - else if (!strcmp(ptr, "p")) - ccs_current_screen = CCS_SCREEN_PROFILE_LIST; - else if (!strcmp(ptr, "m")) - ccs_current_screen = CCS_SCREEN_MANAGER_LIST; - else if (!strcmp(ptr, "u")) - ccs_current_screen = CCS_SCREEN_MEMINFO_LIST; - else if (!strcmp(ptr, "readonly")) - ccs_readonly_mode = true; - else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval) - != 1) { -usage: - printf("Usage: %s [e|d|p|m|u] [readonly] " - "[refresh=interval] " - "[{policy_dir|remote_ip:remote_port}]\n", - argv[0]); - return 1; - } - } - } + ccs_parse_args(argc, argv); ccs_editpolicy_init_keyword_map(); if (ccs_offline_mode) { - int fd[2] = { EOF, EOF }; - if (chdir(ccs_policy_dir)) { - printf("Directory %s doesn't exist.\n", - ccs_policy_dir); - return 1; - } - if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) { - fprintf(stderr, "socketpair()\n"); - exit(1); - } - switch (fork()) { - case 0: - close(fd[0]); - ccs_persistent_fd = fd[1]; - ccs_editpolicy_offline_daemon(); - _exit(0); - case -1: - fprintf(stderr, "fork()\n"); - exit(1); - } - close(fd[1]); - ccs_persistent_fd = fd[0]; - ccs_copy_file(CCS_DISK_POLICY_EXCEPTION_POLICY, - CCS_PROC_POLICY_EXCEPTION_POLICY); - ccs_copy_file(CCS_DISK_POLICY_DOMAIN_POLICY, CCS_PROC_POLICY_DOMAIN_POLICY); - ccs_copy_file(CCS_DISK_POLICY_PROFILE, CCS_PROC_POLICY_PROFILE); - ccs_copy_file(CCS_DISK_POLICY_MANAGER, CCS_PROC_POLICY_MANAGER); - } else if (!ccs_network_mode) { - if (chdir(CCS_PROC_POLICY_DIR)) { - fprintf(stderr, - "You can't use this editor for this kernel.\n"); - return 1; - } - if (!ccs_readonly_mode) { - const int fd1 = ccs_open2(CCS_PROC_POLICY_EXCEPTION_POLICY, - O_RDWR); - const int fd2 = ccs_open2(CCS_PROC_POLICY_DOMAIN_POLICY, - O_RDWR); - if ((fd1 != EOF && write(fd1, "", 0) != 0) || - (fd2 != EOF && write(fd2, "", 0) != 0)) { - fprintf(stderr, - "You need to register this program to " - "%s to run this program.\n", - CCS_PROC_POLICY_MANAGER); - return 1; - } - close(fd1); - close(fd2); - } + ccs_load_offline(); + goto start; + } + if (ccs_network_mode) + goto start; + if (chdir(CCS_PROC_POLICY_DIR)) { + fprintf(stderr, + "You can't use this editor for this kernel.\n"); + return 1; } + if (!ccs_readonly_mode) + ccs_load_readwrite(); +start: #ifdef __GPET if (gpet_main()) return 1; @@ -2449,9 +3181,11 @@ usage: alarm(ccs_refresh_interval); timeout(1000); } + ccs_rl.max = 20; + ccs_rl.history = malloc(ccs_rl.max * sizeof(const char *)); while (ccs_current_screen < CCS_MAXSCREEN) { ccs_resize_window(); - ccs_current_screen = ccs_generic_list_loop(&dp); + ccs_current_screen = ccs_generic_list_loop(); } alarm(0); clear(); @@ -2459,58 +3193,9 @@ usage: refresh(); endwin(); #endif /* __GPET */ - if (ccs_offline_mode && !ccs_readonly_mode) { - int ret_ignored; - time_t now = time(NULL); - const char *filename = ccs_make_filename("exception_policy", - now); - if (ccs_save_to_file(CCS_PROC_POLICY_EXCEPTION_POLICY, - filename)) { - if (ccs_identical_file("exception_policy.conf", - filename)) { - unlink(filename); - } else { - unlink("exception_policy.conf"); - ret_ignored = symlink(filename, - "exception_policy.conf"); - } - } - ccs_clear_domain_policy(&dp); - filename = ccs_make_filename("domain_policy", now); - if (ccs_save_to_file(CCS_PROC_POLICY_DOMAIN_POLICY, - filename)) { - if (ccs_identical_file("domain_policy.conf", - filename)) { - unlink(filename); - } else { - unlink("domain_policy.conf"); - ret_ignored = symlink(filename, - "domain_policy.conf"); - } - } - filename = ccs_make_filename("profile", now); - if (ccs_save_to_file(CCS_PROC_POLICY_PROFILE, filename)) { - if (ccs_identical_file("profile.conf", filename)) { - unlink(filename); - } else { - unlink("profile.conf"); - ret_ignored = symlink(filename, - "profile.conf"); - } - } - filename = ccs_make_filename("manager", now); - if (ccs_save_to_file(CCS_PROC_POLICY_MANAGER, filename)) { - if (ccs_identical_file("manager.conf", filename)) { - unlink(filename); - } else { - unlink("manager.conf"); - ret_ignored = symlink(filename, - "manager.conf"); - } - } - } - ccs_clear_domain_policy(&bp); - ccs_clear_domain_policy(&dp); + if (ccs_offline_mode && !ccs_readonly_mode) + ccs_save_offline(); + ccs_clear_domain_policy(&ccs_dp); return 0; }