OSDN Git Service

cb555cde8a5a985364a999b0ef0d9d525e38a85b
[gpet/origin.git] / src / usr_sbin / editpolicy.c
1 /*
2  * editpolicy.c
3  *
4  * TOMOYO Linux's utilities.
5  *
6  * Copyright (C) 2005-2010  NTT DATA CORPORATION
7  *
8  * Version: 1.8.0   2010/11/11
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License v2 as published by the
12  * Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
22  */
23 #include "ccstools.h"
24 #include "editpolicy.h"
25 #ifndef __GPET
26         #include "readline.h"
27 #else
28         static char *gpet_line = NULL;
29 #endif /* __GPET */
30
31 /* Variables */
32
33 extern int ccs_persistent_fd;
34
35 struct ccs_path_group_entry *ccs_path_group_list = NULL;
36 int ccs_path_group_list_len = 0;
37 struct ccs_generic_acl *ccs_generic_acl_list = NULL;
38 int ccs_generic_acl_list_count = 0;
39
40 static const char *ccs_policy_dir = NULL;
41 static _Bool ccs_offline_mode = false;
42 static _Bool ccs_readonly_mode = false;
43 static unsigned int ccs_refresh_interval = 0;
44 static _Bool ccs_need_reload = false;
45 static const char *ccs_policy_file = NULL;
46 static const char *ccs_list_caption = NULL;
47 static char *ccs_current_domain = NULL;
48 static unsigned int ccs_current_pid = 0;
49 static int ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
50 static struct ccs_transition_control_entry *ccs_transition_control_list = NULL;
51 static int ccs_transition_control_list_len = 0;
52 static int ccs_profile_sort_type = 0;
53 static int ccs_unnumbered_domain_count = 0;
54 static int ccs_window_width = 0;
55 static int ccs_window_height = 0;
56 static int ccs_current_item_index[CCS_MAXSCREEN];
57 int ccs_current_y[CCS_MAXSCREEN];
58 int ccs_list_item_count[CCS_MAXSCREEN];
59 static int ccs_body_lines = 0;
60 static int ccs_max_eat_col[CCS_MAXSCREEN];
61 static int ccs_eat_col = 0;
62 static int ccs_max_col = 0;
63 static int ccs_list_indent = 0;
64 static int ccs_acl_sort_type = 0;
65 static char *ccs_last_error = NULL;
66
67 /* Prototypes */
68
69 static void ccs_sigalrm_handler(int sig);
70 static const char *ccs_get_last_name(const struct ccs_domain_policy *dp, const int index);
71 static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index);
72 static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index);
73 static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index);
74 static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index);
75 static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index);
76 static const struct ccs_transition_control_entry *ccs_transition_control(const struct ccs_path_info *domainname, const char *program);
77 static int ccs_generic_acl_compare(const void *a, const void *b);
78 static int ccs_generic_acl_compare0(const void *a, const void *b);
79 static int ccs_string_acl_compare(const void *a, const void *b);
80 static int ccs_profile_entry_compare(const void *a, const void *b);
81 static void ccs_read_generic_policy(void);
82 static int ccs_add_transition_control_entry(const char *domainname, const char *program, const u8 type);
83 static int ccs_add_transition_control_policy(char *data, const u8 type);
84 static int ccs_add_path_group_entry(const char *group_name, const char *member_name, const _Bool is_delete);
85 static int ccs_add_path_group_policy(char *data, const _Bool is_delete);
86 static void ccs_assign_dis(struct ccs_domain_policy *dp, const struct ccs_path_info *domainname, const char *program);
87 static int ccs_domainname_attribute_compare(const void *a, const void *b);
88 static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp);
89 static void ccs_show_current(struct ccs_domain_policy *dp);
90 static const char *ccs_eat(const char *str);
91 static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index);
92 static int ccs_show_acl_line(const int index, const int list_indent);
93 static int ccs_show_profile_line(const int index);
94 static int ccs_show_literal_line(const int index);
95 static int ccs_show_meminfo_line(const int index);
96 static void ccs_show_list(struct ccs_domain_policy *dp);
97 static void ccs_resize_window(void);
98 static void ccs_up_arrow_key(struct ccs_domain_policy *dp);
99 static void ccs_down_arrow_key(struct ccs_domain_policy *dp);
100 static void ccs_page_up_key(struct ccs_domain_policy *dp);
101 static void ccs_page_down_key(struct ccs_domain_policy *dp);
102 static void ccs_adjust_cursor_pos(const int item_count);
103 static void ccs_set_cursor_pos(const int index);
104 static int ccs_count(const unsigned char *array, const int len);
105 static int ccs_count2(const struct ccs_generic_acl *array, int len);
106 static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index);
107 static int ccs_generic_acl_compare(const void *a, const void *b);
108 static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index);
109 static void ccs_add_entry(struct ccs_readline_data *rl);
110 static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward, const int current, struct ccs_readline_data *rl);
111 static void ccs_set_profile(struct ccs_domain_policy *dp, const int current);
112 static void ccs_set_level(struct ccs_domain_policy *dp, const int current);
113 static void ccs_set_quota(struct ccs_domain_policy *dp, const int current);
114 static int ccs_select_window(struct ccs_domain_policy *dp, const int current);
115 static _Bool ccs_show_command_key(const int screen, const _Bool readonly);
116 static int ccs_generic_list_loop(struct ccs_domain_policy *dp);
117 static void ccs_copy_file(const char *source, const char *dest);
118 static FILE *ccs_editpolicy_open_write(const char *filename);
119
120 /* Utility Functions */
121
122 static void ccs_copy_file(const char *source, const char *dest)
123 {
124         FILE *fp_in = fopen(source, "r");
125         FILE *fp_out = fp_in ? ccs_editpolicy_open_write(dest) : NULL;
126         while (fp_in && fp_out) {
127                 int c = fgetc(fp_in);
128                 if (c == EOF)
129                         break;
130                 fputc(c, fp_out);
131         }
132         if (fp_out)
133                 fclose(fp_out);
134         if (fp_in)
135                 fclose(fp_in);
136 }
137
138 static const char *ccs_get_last_name(const struct ccs_domain_policy *dp,
139                                      const int index)
140 {
141         const char *cp0 = ccs_domain_name(dp, index);
142         const char *cp1 = strrchr(cp0, ' ');
143         if (cp1)
144                 return cp1 + 1;
145         return cp0;
146 }
147
148 static int ccs_count(const unsigned char *array, const int len)
149 {
150         int i;
151         int c = 0;
152         for (i = 0; i < len; i++)
153                 if (array[i])
154                         c++;
155         return c;
156 }
157
158 static int ccs_count2(const struct ccs_generic_acl *array, int len)
159 {
160         int i;
161         int c = 0;
162         for (i = 0; i < len; i++)
163                 if (array[i].selected)
164                         c++;
165         return c;
166 }
167
168 static int ccs_count3(const struct ccs_task_entry *array, int len)
169 {
170         int i;
171         int c = 0;
172         for (i = 0; i < len; i++)
173                 if (array[i].selected)
174                         c++;
175         return c;
176 }
177
178 static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index)
179 {
180         return dp->list[index].is_dk;
181 }
182
183 static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index)
184 {
185         return dp->list[index].is_dis;
186 }
187
188 static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index)
189 {
190         return dp->list[index].is_dit;
191 }
192
193 static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index)
194 {
195         return dp->list[index].is_du;
196 }
197
198 static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index)
199 {
200         return dp->list[index].is_dd;
201 }
202
203 static int ccs_generic_acl_compare0(const void *a, const void *b)
204 {
205         const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
206         const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
207         const char *a1 = ccs_directives[a0->directive].alias;
208         const char *b1 = ccs_directives[b0->directive].alias;
209         const char *a2 = a0->operand;
210         const char *b2 = b0->operand;
211         const int ret = strcmp(a1, b1);
212         if (ret)
213                 return ret;
214         return strcmp(a2, b2);
215 }
216
217 static int ccs_string_acl_compare(const void *a, const void *b)
218 {
219         const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
220         const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
221         const char *a1 = a0->operand;
222         const char *b1 = b0->operand;
223         return strcmp(a1, b1);
224 }
225
226 static int ccs_add_transition_control_policy(char *data, const u8 type)
227 {
228         char *domainname = strstr(data, " from ");
229         if (domainname) {
230                 *domainname = '\0';
231                 domainname += 6;
232         } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
233                    type == CCS_TRANSITION_CONTROL_KEEP) {
234                 domainname = data;
235                 data = NULL;
236         }
237         return ccs_add_transition_control_entry(domainname, data, type);
238 }
239
240 static int ccs_add_path_group_policy(char *data, const _Bool is_delete)
241 {
242         char *cp = strchr(data, ' ');
243         if (!cp)
244                 return -EINVAL;
245         *cp++ = '\0';
246         return ccs_add_path_group_entry(data, cp, is_delete);
247 }
248
249 static void ccs_assign_dis(struct ccs_domain_policy *dp,
250                            const struct ccs_path_info *domainname,
251                            const char *program)
252 {
253         const struct ccs_transition_control_entry *d_t =
254                 ccs_transition_control(domainname, program);
255         if (d_t && d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE) {
256                 char *line;
257                 int source;
258                 ccs_get();
259                 line = ccs_shprintf("%s %s", domainname->name, program);
260                 ccs_normalize_line(line);
261                 source = ccs_assign_domain(dp, line, true, false);
262                 if (source == EOF)
263                         ccs_out_of_memory();
264                 line = ccs_shprintf(CCS_ROOT_NAME " %s", program);
265                 dp->list[source].target_domainname = strdup(line);
266                 if (!dp->list[source].target_domainname)
267                         ccs_out_of_memory();
268                 ccs_put();
269         }
270 }
271
272 static int ccs_domainname_attribute_compare(const void *a, const void *b)
273 {
274         const struct ccs_domain_info *a0 = a;
275         const struct ccs_domain_info *b0 = b;
276         const int k = strcmp(a0->domainname->name, b0->domainname->name);
277         if ((k > 0) || (!k && !a0->is_dis && b0->is_dis))
278                 return 1;
279         return k;
280 }
281
282 static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
283         [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
284         [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
285         [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
286         [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
287 };
288
289 static int ccs_find_target_domain(struct ccs_domain_policy *dp, const int index)
290 {
291         return ccs_find_domain(dp, dp->list[index].target_domainname, false, false);
292 }
293
294 static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index)
295 {
296         int tmp_col = 0;
297         const struct ccs_transition_control_entry *transition_control;
298         char *line;
299         const char *sp;
300         const int number = dp->list[index].number;
301         int redirect_index;
302         const bool is_dis = ccs_initializer_source(dp, index);
303         const bool is_deleted = ccs_deleted_domain(dp, index);
304         if (number >= 0) {
305                 printw("%c%4d:", dp->list_selected[index] ? '&' : ' ', number);
306                 if (dp->list[index].profile_assigned)
307                         printw("%3u", dp->list[index].profile);
308                 else
309                         printw("???");
310                 printw(" %c%c%c ", ccs_keeper_domain(dp, index) ? '#' : ' ',
311                        ccs_initializer_target(dp, index) ? '*' : ' ',
312                        ccs_domain_unreachable(dp, index) ? '!' : ' ');
313         } else
314                 printw("              ");
315         tmp_col += 14;
316         sp = ccs_domain_name(dp, index);
317         while (true) {
318                 const char *cp = strchr(sp, ' ');
319                 if (!cp)
320                         break;
321                 printw("%s", ccs_eat("    "));
322                 tmp_col += 4;
323                 sp = cp + 1;
324         }
325         if (is_deleted) {
326                 printw("%s", ccs_eat("( "));
327                 tmp_col += 2;
328         }
329         printw("%s", ccs_eat(sp));
330         tmp_col += strlen(sp);
331         if (is_deleted) {
332                 printw("%s", ccs_eat(" )"));
333                 tmp_col += 2;
334         }
335         transition_control = dp->list[index].d_t;
336         if (!transition_control || is_dis)
337                 goto no_transition_control;
338         ccs_get();
339         line = ccs_shprintf(" ( %s%s from %s )",
340                             ccs_transition_type[transition_control->type],
341                             transition_control->program ?
342                             transition_control->program->name : "any",
343                             transition_control->domainname ?
344                             transition_control->domainname->name : "any");
345         printw("%s", ccs_eat(line));
346         tmp_col += strlen(line);
347         ccs_put();
348         goto done;
349 no_transition_control:
350         if (!is_dis)
351                 goto done;
352         ccs_get();
353         redirect_index = ccs_find_target_domain(dp, index);
354         if (redirect_index >= 0)
355                 line = ccs_shprintf(" ( -> %d )", dp->list[redirect_index].number);
356         else
357                 line = ccs_shprintf(" ( -> Not Found )");
358         printw("%s", ccs_eat(line));
359         tmp_col += strlen(line);
360         ccs_put();
361 done:
362         return tmp_col;
363 }
364
365 static int ccs_show_acl_line(const int index, const int list_indent)
366 {
367         u16 directive = ccs_generic_acl_list[index].directive;
368         const char *cp1 = ccs_directives[directive].alias;
369         const char *cp2 = ccs_generic_acl_list[index].operand;
370         int len = list_indent - ccs_directives[directive].alias_len;
371         printw("%c%4d: %s ",
372                ccs_generic_acl_list[index].selected ? '&' : ' ',
373                index, ccs_eat(cp1));
374         while (len-- > 0)
375                 printw("%s", ccs_eat(" "));
376         printw("%s", ccs_eat(cp2));
377         return strlen(cp1) + strlen(cp2) + 8 + list_indent;
378 }
379
380 static int ccs_show_profile_line(const int index)
381 {
382         const char *cp = ccs_generic_acl_list[index].operand;
383         const u16 profile = ccs_generic_acl_list[index].directive;
384         char number[8] = "";
385         if (profile <= 256)
386                 snprintf(number, sizeof(number) - 1, "%3u-", profile);
387         printw("%c%4d: %s", ccs_generic_acl_list[index].selected ? '&' : ' ',
388                index, ccs_eat(number));
389         printw("%s ", ccs_eat(cp));
390         return strlen(number) + strlen(cp) + 8;
391 }
392
393 static int ccs_show_literal_line(const int index)
394 {
395         const char *cp = ccs_generic_acl_list[index].operand;
396         printw("%c%4d: %s ",
397                ccs_generic_acl_list[index].selected ? '&' : ' ',
398                index, ccs_eat(cp));
399         return strlen(cp) + 8;
400 }
401
402 static int ccs_show_meminfo_line(const int index)
403 {
404         char *line;
405         unsigned int now = 0;
406         unsigned int quota = -1;
407         const char *data = ccs_generic_acl_list[index].operand;
408         ccs_get();
409         if (sscanf(data, "Policy: %u (Quota: %u)", &now, &quota) >= 1)
410                 line = ccs_shprintf("Memory used for policy      = %10u bytes   "
411                                     "(Quota: %10u bytes)", now, quota);
412         else if (sscanf(data, "Audit logs: %u (Quota: %u)", &now, &quota) >= 1)
413                 line = ccs_shprintf("Memory used for audit logs  = %10u bytes   "
414                                     "(Quota: %10u bytes)", now, quota);
415         else if (sscanf(data, "Query lists: %u (Quota: %u)", &now, &quota) >= 1)
416                 line = ccs_shprintf("Memory used for query lists = %10u bytes   "
417                                     "(Quota: %10u bytes)", now, quota);
418         else if (sscanf(data, "Total: %u", &now) == 1)
419                 line = ccs_shprintf("Total memory in use         = %10u bytes",
420                                     now);
421         else if (sscanf(data, "Shared: %u (Quota: %u)", &now, &quota) >= 1)
422                 line = ccs_shprintf("Memory for string data      = %10u bytes    "
423                                     "Quota = %10u bytes", now, quota);
424         else if (sscanf(data, "Private: %u (Quota: %u)", &now, &quota) >= 1)
425                 line = ccs_shprintf("Memory for numeric data     = %10u bytes    "
426                                     "Quota = %10u bytes", now, quota);
427         else if (sscanf(data, "Dynamic: %u (Quota: %u)", &now, &quota) >= 1)
428                 line = ccs_shprintf("Memory for temporary data   = %10u bytes    "
429                                     "Quota = %10u bytes", now, quota);
430         else
431                 line = ccs_shprintf("%s", data);
432         if (line[0])
433                 printw("%s", ccs_eat(line));
434         now = strlen(line);
435         ccs_put();
436         return now;
437 }
438
439 static int ccs_domain_sort_type = 0;
440
441 static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
442 {
443         int c;
444         clear();
445         printw("Commands available for this screen are:\n\n");
446         printw("Q/q        Quit this editor.\n");
447         printw("R/r        Refresh to the latest information.\n");
448         switch (screen) {
449         case CCS_SCREEN_MEMINFO_LIST:
450                 break;
451         default:
452                 printw("F/f        Find first.\n");
453                 printw("N/n        Find next.\n");
454                 printw("P/p        Find previous.\n");
455         }
456         printw("W/w        Switch to selected screen.\n");
457         /* printw("Tab        Switch to next screen.\n"); */
458         switch (screen) {
459         case CCS_SCREEN_MEMINFO_LIST:
460                 break;
461         default:
462                 printw("Insert     Copy an entry at the cursor position to "
463                        "history buffer.\n");
464                 printw("Space      Invert selection state of an entry at "
465                        "the cursor position.\n");
466                 printw("C/c        Copy selection state of an entry at "
467                        "the cursor position to all entries below the cursor "
468                        "position.\n");
469         }
470         switch (screen) {
471         case CCS_SCREEN_DOMAIN_LIST:
472                 if (ccs_domain_sort_type) {
473                         printw("S/s        Set profile number of selected "
474                                "processes.\n");
475                         printw("Enter      Edit ACLs of a process at the "
476                                "cursor position.\n");
477                 } else {
478                         if (!readonly) {
479                                 printw("A/a        Add a new domain.\n");
480                                 printw("D/d        Delete selected domains.\n");
481                                 printw("S/s        Set profile number of "
482                                        "selected domains.\n");
483                         }
484                         printw("Enter      Edit ACLs of a domain at the "
485                                "cursor position.\n");
486                 }
487                 break;
488         case CCS_SCREEN_MEMINFO_LIST:
489                 if (!readonly)
490                         printw("S/s        Set memory quota of selected "
491                                "items.\n");
492                 break;
493         case CCS_SCREEN_PROFILE_LIST:
494                 if (!readonly)
495                         printw("S/s        Set mode of selected items.\n");
496                 break;
497         }
498         switch (screen) {
499         case CCS_SCREEN_EXCEPTION_LIST:
500         case CCS_SCREEN_ACL_LIST:
501         case CCS_SCREEN_MANAGER_LIST:
502                 if (!readonly) {
503                         printw("A/a        Add a new entry.\n");
504                         printw("D/d        Delete selected entries.\n");
505                 }
506         }
507         switch (screen) {
508         case CCS_SCREEN_PROFILE_LIST:
509                 if (!readonly)
510                         printw("A/a        Define a new profile.\n");
511         }
512         switch (screen) {
513         case CCS_SCREEN_ACL_LIST:
514                 printw("O/o        Set selection state to other entries "
515                        "included in an entry at the cursor position.\n");
516                 /* Fall through. */
517         case CCS_SCREEN_PROFILE_LIST:
518                 printw("@          Switch sort type.\n");
519                 break;
520         case CCS_SCREEN_DOMAIN_LIST:
521                 if (!ccs_offline_mode)
522                         printw("@          Switch domain/process list.\n");
523         }
524         printw("Arrow-keys and PageUp/PageDown/Home/End keys "
525                "for scroll.\n\n");
526         printw("Press '?' to escape from this help.\n");
527         refresh();
528         while (true) {
529                 c = ccs_getch2();
530                 if (c == '?' || c == EOF)
531                         break;
532                 if (c == 'Q' || c == 'q')
533                         return false;
534         }
535         return true;
536 }
537
538 /* Main Functions */
539
540 static void ccs_close_write(FILE *fp)
541 {
542         if (ccs_network_mode) {
543                 fputc(0, fp);
544                 fflush(fp);
545                 fgetc(fp);
546         }
547         fclose(fp);
548 }
549
550 static void ccs_set_error(const char *filename)
551 {
552         if (filename) {
553                 const int len = strlen(filename) + 128;
554                 ccs_last_error = realloc(ccs_last_error, len);
555                 if (!ccs_last_error)
556                         ccs_out_of_memory();
557                 memset(ccs_last_error, 0, len);
558                 snprintf(ccs_last_error, len - 1, "Can't open %s .", filename);
559         } else {
560                 free(ccs_last_error);
561                 ccs_last_error = NULL;
562         }
563 }
564
565 static FILE *ccs_editpolicy_open_write(const char *filename)
566 {
567         if (ccs_network_mode) {
568                 FILE *fp = ccs_open_write(filename);
569                 if (!fp)
570                         ccs_set_error(filename);
571                 return fp;
572         } else if (ccs_offline_mode) {
573                 char request[1024];
574                 int fd[2];
575                 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
576                         fprintf(stderr, "socketpair()\n");
577                         exit(1);
578                 }
579                 if (shutdown(fd[0], SHUT_RD))
580                         goto out;
581                 memset(request, 0, sizeof(request));
582                 snprintf(request, sizeof(request) - 1, "POST %s", filename);
583                 ccs_send_fd(request, &fd[1]);
584                 return fdopen(fd[0], "w");
585 out:
586                 close(fd[1]);
587                 close(fd[0]);
588                 exit(1);
589         } else {
590                 FILE *fp;
591                 if (ccs_readonly_mode)
592                         return NULL;
593                 fp = ccs_open_write(filename);
594                 if (!fp)
595                         ccs_set_error(filename);
596                 return fp;
597         }
598 }
599
600 static FILE *ccs_editpolicy_open_read(const char *filename)
601 {
602         if (ccs_network_mode) {
603                 return ccs_open_read(filename);
604         } else if (ccs_offline_mode) {
605                 char request[1024];
606                 int fd[2];
607                 FILE *fp;
608                 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
609                         fprintf(stderr, "socketpair()\n");
610                         exit(1);
611                 }
612                 if (shutdown(fd[0], SHUT_WR))
613                         goto out;
614                 fp = fdopen(fd[0], "r");
615                 if (!fp)
616                         goto out;
617                 memset(request, 0, sizeof(request));
618                 snprintf(request, sizeof(request) - 1, "GET %s", filename);
619                 ccs_send_fd(request, &fd[1]);
620                 return fp;
621 out:
622                 close(fd[1]);
623                 close(fd[0]);
624                 exit(1);
625         } else {
626                 return fopen(filename, "r");
627         }
628 }
629
630 static int ccs_open2(const char *filename, int mode)
631 {
632         const int fd = open(filename, mode);
633         if (fd == EOF && errno != ENOENT)
634                 ccs_set_error(filename);
635         return fd;
636 }
637
638 static void ccs_sigalrm_handler(int sig)
639 {
640         ccs_need_reload = true;
641         alarm(ccs_refresh_interval);
642 }
643
644 static const char *ccs_eat(const char *str)
645 {
646         while (*str && ccs_eat_col) {
647                 str++;
648                 ccs_eat_col--;
649         }
650         return str;
651 }
652
653 static const struct ccs_transition_control_entry *ccs_transition_control
654 (const struct ccs_path_info *domainname, const char *program)
655 {
656         int i;
657         u8 type;
658         struct ccs_path_info last_name;
659         last_name.name = strrchr(domainname->name, ' ');
660         if (last_name.name)
661                 last_name.name++;
662         else
663                 last_name.name = domainname->name;
664         ccs_fill_path_info(&last_name);
665         for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
666  next:
667                 for (i = 0; i < ccs_transition_control_list_len; i++) {
668                         struct ccs_transition_control_entry *ptr
669                                 = &ccs_transition_control_list[i];
670                         if (ptr->type != type)
671                                 continue;
672                         if (ptr->domainname) {
673                                 if (!ptr->is_last_name) {
674                                         if (ccs_pathcmp(ptr->domainname,
675                                                         domainname))
676                                                 continue;
677                                 } else {
678                                         if (ccs_pathcmp(ptr->domainname,
679                                                         &last_name))
680                                                 continue;
681                                 }
682                         }
683                         if (ptr->program && strcmp(ptr->program->name, program))
684                                 continue;
685                         if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
686                                 /*
687                                  * Do not check for initialize_domain if
688                                  * no_initialize_domain matched.
689                                  */
690                                 type = CCS_TRANSITION_CONTROL_NO_KEEP;
691                                 goto next;
692                         }
693                         if (type == CCS_TRANSITION_CONTROL_INITIALIZE ||
694                             type == CCS_TRANSITION_CONTROL_KEEP)
695                                 return ptr;
696                         else
697                                 return NULL;
698                 }
699         }
700         return NULL;
701 }
702
703 static int ccs_profile_entry_compare(const void *a, const void *b)
704 {
705         const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
706         const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
707         const char *a1 = a0->operand;
708         const char *b1 = b0->operand;
709         const int a2 = a0->directive;
710         const int b2 = b0->directive;
711         if (a2 >= 256 || b2 >= 256) {
712                 int i;
713                 static const char *global[5] = {
714                         "PROFILE_VERSION=",
715                         "PREFERENCE::audit=",
716                         "PREFERENCE::learning=",
717                         "PREFERENCE::permissive=",
718                         "PREFERENCE::enforcing="
719                 };
720                 for (i = 0; i < 5; i++) {
721                         if (!strncmp(a1, global[i], strlen(global[i])))
722                                 return -1;
723                         if (!strncmp(b1, global[i], strlen(global[i])))
724                                 return 1;
725                 }
726         }
727         if (ccs_profile_sort_type == 0) {
728                 if (a2 == b2)
729                         return strcmp(a1, b1);
730                 else
731                         return a2 - b2;
732         } else {
733                 const int a3 = strcspn(a1, "=");
734                 const int b3 = strcspn(b1, "=");
735                 const int c = strncmp(a1, b1, a3 >= b3 ? b3 : a3);
736                 if (c)
737                         return c;
738                 if (a3 != b3)
739                         return a3 - b3;
740                 else
741                         return a2 - b2;
742         }
743 }
744
745 static void ccs_read_generic_policy(void)
746 {
747         FILE *fp = NULL;
748         _Bool flag = false;
749         while (ccs_generic_acl_list_count)
750                 free((void *)
751                      ccs_generic_acl_list[--ccs_generic_acl_list_count].operand);
752         if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
753                 if (ccs_network_mode)
754                         /* We can read after write. */
755                         fp = ccs_editpolicy_open_write(ccs_policy_file);
756                 else if (!ccs_offline_mode)
757                         /* Don't set error message if failed. */
758                         fp = fopen(ccs_policy_file, "r+");
759                 if (fp) {
760                         if (ccs_domain_sort_type)
761                                 fprintf(fp, "select pid=%u\n", ccs_current_pid);
762                         else
763                                 fprintf(fp, "select domain=%s\n",
764                                         ccs_current_domain);
765                         if (ccs_network_mode)
766                                 fputc(0, fp);
767                         fflush(fp);
768                 }
769         }
770         if (!fp)
771                 fp = ccs_editpolicy_open_read(ccs_policy_file);
772         if (!fp) {
773                 ccs_set_error(ccs_policy_file);
774                 return;
775         }
776         ccs_get();
777         while (true) {
778                 char *line = ccs_freadline(fp);
779                 u16 directive;
780                 char *cp;
781                 if (!line)
782                         break;
783                 if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
784                         if (ccs_domain_def(line)) {
785                                 flag = !strcmp(line, ccs_current_domain);
786                                 continue;
787                         }
788                         if (!flag || !line[0] ||
789                             !strncmp(line, "use_profile ", 12))
790                                 continue;
791                 } else {
792                         if (!line[0])
793                                 continue;
794                 }
795                 switch (ccs_current_screen) {
796                 case CCS_SCREEN_EXCEPTION_LIST:
797                 case CCS_SCREEN_ACL_LIST:
798                         directive = ccs_find_directive(true, line);
799                         if (directive == CCS_DIRECTIVE_NONE)
800                                 continue;
801                         break;
802                 case CCS_SCREEN_PROFILE_LIST:
803                         cp = strchr(line, '-');
804                         if (cp) {
805                                 *cp++ = '\0';
806                                 directive = atoi(line);
807                                 memmove(line, cp, strlen(cp) + 1);
808                         } else
809                                 directive = (u16) -1;
810                         break;
811                 default:
812                         directive = CCS_DIRECTIVE_NONE;
813                         break;
814                 }
815                 ccs_generic_acl_list = realloc(ccs_generic_acl_list,
816                                                (ccs_generic_acl_list_count + 1) *
817                                                sizeof(struct ccs_generic_acl));
818                 if (!ccs_generic_acl_list)
819                         ccs_out_of_memory();
820                 cp = strdup(line);
821                 if (!cp)
822                         ccs_out_of_memory();
823                 ccs_generic_acl_list[ccs_generic_acl_list_count].directive = directive;
824                 ccs_generic_acl_list[ccs_generic_acl_list_count].selected = 0;
825                 ccs_generic_acl_list[ccs_generic_acl_list_count++].operand = cp;
826         }
827         ccs_put();
828         fclose(fp);
829         switch (ccs_current_screen) {
830         case CCS_SCREEN_ACL_LIST:
831                 qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
832                       sizeof(struct ccs_generic_acl), ccs_generic_acl_compare);
833                 break;
834         case CCS_SCREEN_EXCEPTION_LIST:
835                 qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
836                       sizeof(struct ccs_generic_acl), ccs_generic_acl_compare0);
837                 break;
838         case CCS_SCREEN_PROFILE_LIST:
839                 qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
840                       sizeof(struct ccs_generic_acl), ccs_profile_entry_compare);
841                 break;
842         default:
843                 qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
844                       sizeof(struct ccs_generic_acl), ccs_string_acl_compare);
845         }
846 }
847
848 static int ccs_add_transition_control_entry(const char *domainname,
849                                             const char *program,
850                                             const u8 type)
851 {
852         void *vp;
853         struct ccs_transition_control_entry *ptr;
854         _Bool is_last_name = false;
855         if (program && strcmp(program, "any")) {
856                 if (!ccs_correct_path(program))
857                         return -EINVAL;
858         }
859         if (domainname && strcmp(domainname, "any")) {
860                 if (!ccs_correct_domain(domainname)) {
861                         if (!ccs_correct_path(domainname))
862                                 return -EINVAL;
863                         is_last_name = true;
864                 }
865         }
866         vp = realloc(ccs_transition_control_list,
867                      (ccs_transition_control_list_len + 1) *
868                      sizeof(struct ccs_transition_control_entry));
869         if (!vp)
870                 ccs_out_of_memory();
871         ccs_transition_control_list = vp;
872         ptr = &ccs_transition_control_list[ccs_transition_control_list_len++];
873         memset(ptr, 0, sizeof(struct ccs_transition_control_entry));
874         if (program && strcmp(program, "any")) {
875                 ptr->program = ccs_savename(program);
876                 if (!ptr->program)
877                         ccs_out_of_memory();
878         }
879         if (domainname && strcmp(domainname, "any")) {
880                 ptr->domainname = ccs_savename(domainname);
881                 if (!ptr->domainname)
882                         ccs_out_of_memory();
883         }
884         ptr->type = type;
885         ptr->is_last_name = is_last_name;
886         return 0;
887 }
888
889 static int ccs_add_path_group_entry(const char *group_name, const char *member_name,
890                                 const _Bool is_delete)
891 {
892         const struct ccs_path_info *saved_group_name;
893         const struct ccs_path_info *saved_member_name;
894         int i;
895         int j;
896         struct ccs_path_group_entry *group = NULL;
897         if (!ccs_correct_word(group_name) || !ccs_correct_word(member_name))
898                 return -EINVAL;
899         saved_group_name = ccs_savename(group_name);
900         saved_member_name = ccs_savename(member_name);
901         if (!saved_group_name || !saved_member_name)
902                 return -ENOMEM;
903         for (i = 0; i < ccs_path_group_list_len; i++) {
904                 group = &ccs_path_group_list[i];
905                 if (saved_group_name != group->group_name)
906                         continue;
907                 for (j = 0; j < group->member_name_len; j++) {
908                         if (group->member_name[j] != saved_member_name)
909                                 continue;
910                         if (!is_delete)
911                                 return 0;
912                         while (j < group->member_name_len - 1)
913                                 group->member_name[j] =
914                                         group->member_name[j + 1];
915                         group->member_name_len--;
916                         return 0;
917                 }
918                 break;
919         }
920         if (is_delete)
921                 return -ENOENT;
922         if (i == ccs_path_group_list_len) {
923                 ccs_path_group_list = realloc(ccs_path_group_list,
924                                           (ccs_path_group_list_len + 1) *
925                                           sizeof(struct ccs_path_group_entry));
926                 if (!ccs_path_group_list)
927                         ccs_out_of_memory();
928                 group = &ccs_path_group_list[ccs_path_group_list_len++];
929                 memset(group, 0, sizeof(struct ccs_path_group_entry));
930                 group->group_name = saved_group_name;
931         }
932         group->member_name = realloc(group->member_name,
933                                      (group->member_name_len + 1)
934                                      * sizeof(const struct ccs_path_info *));
935         if (!group->member_name)
936                 ccs_out_of_memory();
937         group->member_name[group->member_name_len++] = saved_member_name;
938         return 0;
939 }
940
941 static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp)
942 {
943         FILE *fp;
944         int i;
945         int j;
946         int index;
947         int max_index;
948         static char **ccs_jump_list = NULL;
949         static int ccs_jump_list_len = 0;
950         while (ccs_jump_list_len)
951                 free(ccs_jump_list[--ccs_jump_list_len]);
952         ccs_clear_domain_policy(dp);
953         ccs_transition_control_list_len = 0;
954         while (ccs_path_group_list_len)
955                 free(ccs_path_group_list[--ccs_path_group_list_len].member_name);
956         /*
957         while (ccs_address_group_list_len)
958                 free(ccs_address_group_list[--ccs_address_group_list_len].member_name);
959         */
960         ccs_address_group_list_len = 0;
961         ccs_number_group_list_len = 0;
962         ccs_assign_domain(dp, CCS_ROOT_NAME, false, false);
963
964         /* Load all domain list. */
965         fp = NULL;
966         if (ccs_network_mode)
967                 /* We can read after write. */
968                 fp = ccs_editpolicy_open_write(ccs_policy_file);
969         else if (!ccs_offline_mode)
970                 /* Don't set error message if failed. */
971                 fp = fopen(ccs_policy_file, "r+");
972         if (fp) {
973                 fprintf(fp, "select execute\n");
974                 if (ccs_network_mode)
975                         fputc(0, fp);
976                 fflush(fp);
977         }
978         if (!fp)
979                 fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_DOMAIN_POLICY);
980         if (!fp) {
981                 ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY);
982                 goto no_domain;
983         }
984         index = EOF;
985         ccs_get();
986         while (true) {
987                 char *line = ccs_freadline(fp);
988                 unsigned int profile;
989                 if (!line)
990                         break;
991                 if (ccs_domain_def(line)) {
992                         index = ccs_assign_domain(dp, line, false, false);
993                         continue;
994                 } else if (index == EOF) {
995                         continue;
996                 }
997                 if (ccs_str_starts(line, "task auto_execute_handler ") ||
998                     ccs_str_starts(line, "task denied_execute_handler ") ||
999                     ccs_str_starts(line, "file execute ")) {
1000                         char *cp = strchr(line, ' ');
1001                         if (cp)
1002                                 *cp = '\0';
1003                         if (*line == '@' || ccs_correct_path(line))
1004                                 ccs_add_string_entry(dp, line, index);
1005                 } else if (ccs_str_starts(line,
1006                                           "task auto_domain_transition ") ||
1007                            ccs_str_starts(line,
1008                                           "task manual_domain_transition ")) {
1009                         static char domainname[4096];
1010                         int source;
1011                         char *m;
1012                         int i;
1013                         for (i = 0; line[i]; i++)
1014                                 if (line[i] == ' ' && line[i + 1] != '/') {
1015                                         line[i] = '\0';
1016                                         break;
1017                                 }
1018                         if (!ccs_correct_domain(line))
1019                                 continue;
1020                         ccs_jump_list = realloc(ccs_jump_list,
1021                                                 (ccs_jump_list_len + 1)
1022                                                 * sizeof(char *));
1023                         if (!ccs_jump_list)
1024                                 ccs_out_of_memory();
1025                         ccs_jump_list[ccs_jump_list_len] = strdup(line);
1026                         if (!ccs_jump_list[ccs_jump_list_len])
1027                                 ccs_out_of_memory();
1028                         ccs_jump_list_len++;
1029                         m = strrchr(line, ' ');
1030                         if (m)
1031                                 m++;
1032                         else
1033                                 m = line;
1034                         snprintf(domainname, sizeof(domainname) - 1, "%s %s",
1035                                  ccs_domain_name(dp, index), m);
1036                         domainname[sizeof(domainname) - 1] = '\0';
1037                         ccs_normalize_line(domainname);
1038                         source = ccs_assign_domain(dp, domainname, true, false);
1039                         if (source == EOF)
1040                                 ccs_out_of_memory();
1041                         dp->list[source].target_domainname = strdup(line);
1042                         if (!dp->list[source].target_domainname)
1043                                 ccs_out_of_memory();
1044                 } else if (sscanf(line, "use_profile %u", &profile) == 1) {
1045                         dp->list[index].profile = (u8) profile;
1046                         dp->list[index].profile_assigned = 1;
1047                 } else if (sscanf(line, "use_group %u", &profile) == 1) {
1048                         dp->list[index].group = (u8) profile;
1049                 }
1050         }
1051         ccs_put();
1052         fclose(fp);
1053 no_domain:
1054
1055         max_index = dp->list_len;
1056
1057         /* Load domain_initializer list, domain_keeper list. */
1058         fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_EXCEPTION_POLICY);
1059         if (!fp) {
1060                 ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY);
1061                 goto no_exception;
1062         }
1063         ccs_get();
1064         while (true) {
1065                 unsigned int group;
1066                 char *line = ccs_freadline(fp);
1067                 if (!line)
1068                         break;
1069                 if (ccs_str_starts(line, "initialize_domain "))
1070                         ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_INITIALIZE);
1071                 else if (ccs_str_starts(line, "no_initialize_domain "))
1072                         ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_INITIALIZE);
1073                 else if (ccs_str_starts(line, "keep_domain "))
1074                         ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_KEEP);
1075                 else if (ccs_str_starts(line, "no_keep_domain "))
1076                         ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_KEEP);
1077                 else if (ccs_str_starts(line, "path_group "))
1078                         ccs_add_path_group_policy(line, false);
1079                 else if (ccs_str_starts(line, "address_group "))
1080                         ccs_add_address_group_policy(line, false);
1081                 else if (ccs_str_starts(line, "number_group "))
1082                         ccs_add_number_group_policy(line, false);
1083                 else if (sscanf(line, "acl_group %u", &group) == 1
1084                          && group < 256) {
1085                         char *cp = strchr(line + 10, ' ');
1086                         if (cp)
1087                                 line = cp + 1;
1088                         if (ccs_str_starts(line,
1089                                            "task auto_execute_handler ") ||
1090                             ccs_str_starts(line,
1091                                            "task denied_execute_handler ") ||
1092                             ccs_str_starts(line, "file execute ")) {
1093                                 cp = strchr(line, ' ');
1094                                 if (cp)
1095                                         *cp = '\0';
1096                                 if (*line == '@' || ccs_correct_path(line)) {
1097                                         for (index = 0; index < max_index;
1098                                              index++)
1099                                                 if (dp->list[index].group
1100                                                     == group)
1101                                                         ccs_add_string_entry(dp, line, index);
1102                                 }
1103                         }
1104                 }
1105         }
1106         ccs_put();
1107         fclose(fp);
1108 no_exception:
1109
1110         /* Find unreachable domains. */
1111         for (index = 0; index < max_index; index++) {
1112                 char *line;
1113                 ccs_get();
1114                 line = ccs_shprintf("%s", ccs_domain_name(dp, index));
1115                 while (true) {
1116                         const struct ccs_transition_control_entry *d_t;
1117                         struct ccs_path_info parent;
1118                         char *cp = strrchr(line, ' ');
1119                         if (!cp)
1120                                 break;
1121                         *cp++ = '\0';
1122                         parent.name = line;
1123                         ccs_fill_path_info(&parent);
1124                         d_t = ccs_transition_control(&parent, cp);
1125                         if (!d_t)
1126                                 continue;
1127                         /* Initializer under <kernel> is reachable. */
1128                         if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE &&
1129                             parent.total_len == CCS_ROOT_NAME_LEN)
1130                                 break;
1131                         dp->list[index].d_t = d_t;
1132                         continue;
1133                 }
1134                 ccs_put();
1135                 if (dp->list[index].d_t)
1136                         dp->list[index].is_du = true;
1137         }
1138
1139         /* Find domain initializer target domains. */
1140         for (index = 0; index < max_index; index++) {
1141                 char *cp = strchr(ccs_domain_name(dp, index), ' ');
1142                 if (!cp || strchr(cp + 1, ' '))
1143                         continue;
1144                 for (i = 0; i < ccs_transition_control_list_len; i++) {
1145                         struct ccs_transition_control_entry *ptr
1146                                 = &ccs_transition_control_list[i];
1147                         if (ptr->type != CCS_TRANSITION_CONTROL_INITIALIZE)
1148                                 continue;
1149                         if (ptr->program && strcmp(ptr->program->name, cp + 1))
1150                                 continue;
1151                         dp->list[index].is_dit = true;
1152                 }
1153         }
1154
1155         /* Find domain keeper domains. */
1156         for (index = 0; index < max_index; index++) {
1157                 for (i = 0; i < ccs_transition_control_list_len; i++) {
1158                         struct ccs_transition_control_entry *ptr
1159                                 = &ccs_transition_control_list[i];
1160                         char *cp;
1161                         if (ptr->type != CCS_TRANSITION_CONTROL_KEEP)
1162                                 continue;
1163                         if (!ptr->is_last_name) {
1164                                 if (ptr->domainname &&
1165                                     ccs_pathcmp(ptr->domainname,
1166                                                 dp->list[index].domainname))
1167                                         continue;
1168                                 dp->list[index].is_dk = true;
1169                                 continue;
1170                         }
1171                         cp = strrchr(dp->list[index].domainname->name,
1172                                      ' ');
1173                         if (!cp || (ptr->domainname->name &&
1174                                     strcmp(ptr->domainname->name, cp + 1)))
1175                                 continue;
1176                         dp->list[index].is_dk = true;
1177                 }
1178         }
1179
1180         /* Create domain initializer source domains. */
1181         for (index = 0; index < max_index; index++) {
1182                 const struct ccs_path_info *domainname
1183                         = dp->list[index].domainname;
1184                 const struct ccs_path_info **string_ptr
1185                         = dp->list[index].string_ptr;
1186                 const int max_count = dp->list[index].string_count;
1187                 /* Don't create source domain under <kernel> because
1188                    they will become ccs_target domains. */
1189                 if (domainname->total_len == CCS_ROOT_NAME_LEN)
1190                         continue;
1191                 for (i = 0; i < max_count; i++) {
1192                         const struct ccs_path_info *cp = string_ptr[i];
1193                         struct ccs_path_group_entry *group;
1194                         if (cp->name[0] != '@') {
1195                                 ccs_assign_dis(dp, domainname, cp->name);
1196                                 continue;
1197                         }
1198                         group = ccs_find_path_group(cp->name + 1);
1199                         if (!group)
1200                                 continue;
1201                         for (j = 0; j < group->member_name_len; j++) {
1202                                 cp = group->member_name[j];
1203                                 ccs_assign_dis(dp, domainname, cp->name);
1204                         }
1205                 }
1206         }
1207
1208         /* Create domain jump target domains. */
1209         for (i = 0; i < ccs_jump_list_len; i++) {
1210                 int index = ccs_find_domain(dp, ccs_jump_list[i], false, false);
1211                 if (index != EOF)
1212                         dp->list[index].is_dit = true;
1213         }
1214
1215         //max_index = dp->list_len;
1216
1217         /* Create missing parent domains. */
1218         for (index = 0; index < max_index; index++) {
1219                 char *line;
1220                 ccs_get();
1221                 line = ccs_shprintf("%s", ccs_domain_name(dp, index));
1222                 while (true) {
1223                         char *cp = strrchr(line, ' ');
1224                         if (!cp)
1225                                 break;
1226                         *cp = '\0';
1227                         if (ccs_find_domain(dp, line, false, false) != EOF)
1228                                 continue;
1229                         if (ccs_assign_domain(dp, line, false, true) == EOF)
1230                                 ccs_out_of_memory();
1231                 }
1232                 ccs_put();
1233         }
1234
1235         /* Sort by domain name. */
1236         qsort(dp->list, dp->list_len, sizeof(struct ccs_domain_info),
1237               ccs_domainname_attribute_compare);
1238
1239         /* Assign domain numbers. */
1240         {
1241                 int number = 0;
1242                 int index;
1243                 ccs_unnumbered_domain_count = 0;
1244                 for (index = 0; index < dp->list_len; index++) {
1245                         if (ccs_deleted_domain(dp, index) ||
1246                             ccs_initializer_source(dp, index)) {
1247                                 dp->list[index].number = -1;
1248                                 ccs_unnumbered_domain_count++;
1249                         } else {
1250                                 dp->list[index].number = number++;
1251                         }
1252                 }
1253         }
1254
1255         dp->list_selected = realloc(dp->list_selected, dp->list_len);
1256         if (dp->list_len && !dp->list_selected)
1257                 ccs_out_of_memory();
1258         memset(dp->list_selected, 0, dp->list_len);
1259 }
1260
1261 static int ccs_show_process_line(const int index)
1262 {
1263         char *line;
1264         int tmp_col = 0;
1265         int i;
1266         printw("%c%4d:%3u ", ccs_task_list[index].selected ? '&' : ' ', index,
1267                ccs_task_list[index].profile);
1268         tmp_col += 10;
1269         for (i = 0; i < ccs_task_list[index].depth - 1; i++) {
1270                 printw("%s", ccs_eat("    "));
1271                 tmp_col += 4;
1272         }
1273         ccs_get();
1274         line = ccs_shprintf("%s%s (%u) %s", ccs_task_list[index].depth ?
1275                             " +- " : "", ccs_task_list[index].name,
1276                             ccs_task_list[index].pid, ccs_task_list[index].domain);
1277         printw("%s", ccs_eat(line));
1278         tmp_col += strlen(line);
1279         ccs_put();
1280         return tmp_col;
1281 }
1282
1283 static void ccs_show_list(struct ccs_domain_policy *dp)
1284 {
1285         const int offset = ccs_current_item_index[ccs_current_screen];
1286         int i;
1287         int tmp_col;
1288         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST)
1289                 ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST] = ccs_domain_sort_type ?
1290                         ccs_task_list_len : dp->list_len;
1291         else
1292                 ccs_list_item_count[ccs_current_screen] = ccs_generic_acl_list_count;
1293         clear();
1294         move(0, 0);
1295         if (ccs_window_height < CCS_HEADER_LINES + 1) {
1296                 printw("Please enlarge window.");
1297                 clrtobot();
1298                 refresh();
1299                 return;
1300         }
1301         /* add color */
1302         ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), true);
1303         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
1304                 if (ccs_domain_sort_type) {
1305                         printw("<<< Process State Viewer >>>"
1306                                "      %d process%s    '?' for help",
1307                                ccs_task_list_len, ccs_task_list_len > 1 ? "es" : "");
1308                 } else {
1309                         int i = ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST]
1310                                 - ccs_unnumbered_domain_count;
1311                         printw("<<< Domain Transition Editor >>>"
1312                                "      %d domain%c    '?' for help",
1313                                i, i > 1 ? 's' : ' ');
1314                 }
1315         } else {
1316                 int i = ccs_list_item_count[ccs_current_screen];
1317                 printw("<<< %s >>>"
1318                        "      %d entr%s    '?' for help", ccs_list_caption,
1319                        i, i > 1 ? "ies" : "y");
1320         }
1321         /* add color */
1322         ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), false);
1323         ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
1324         ccs_max_col = 0;
1325         if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
1326                 char *line;
1327                 ccs_get();
1328                 line = ccs_shprintf("%s", ccs_eat(ccs_current_domain));
1329                 ccs_editpolicy_attr_change(A_REVERSE, true);  /* add color */
1330                 move(2, 0);
1331                 printw("%s", line);
1332                 ccs_editpolicy_attr_change(A_REVERSE, false); /* add color */
1333                 ccs_put();
1334         }
1335         ccs_list_indent = 0;
1336         switch (ccs_current_screen) {
1337         case CCS_SCREEN_EXCEPTION_LIST:
1338         case CCS_SCREEN_ACL_LIST:
1339                 for (i = 0; i < ccs_list_item_count[ccs_current_screen]; i++) {
1340                         const u16 directive = ccs_generic_acl_list[i].directive;
1341                         const int len = ccs_directives[directive].alias_len;
1342                         if (len > ccs_list_indent)
1343                                 ccs_list_indent = len;
1344                 }
1345                 break;
1346         }
1347         for (i = 0; i < ccs_body_lines; i++) {
1348                 const int index = offset + i;
1349                 ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
1350                 if (index >= ccs_list_item_count[ccs_current_screen])
1351                         break;
1352                 move(CCS_HEADER_LINES + i, 0);
1353                 switch (ccs_current_screen) {
1354                 case CCS_SCREEN_DOMAIN_LIST:
1355                         if (!ccs_domain_sort_type)
1356                                 tmp_col = ccs_show_domain_line(dp, index);
1357                         else
1358                                 tmp_col = ccs_show_process_line(index);
1359                         break;
1360                 case CCS_SCREEN_EXCEPTION_LIST:
1361                 case CCS_SCREEN_ACL_LIST:
1362                         tmp_col = ccs_show_acl_line(index, ccs_list_indent);
1363                         break;
1364                 case CCS_SCREEN_PROFILE_LIST:
1365                         tmp_col = ccs_show_profile_line(index);
1366                         break;
1367                 case CCS_SCREEN_MEMINFO_LIST:
1368                         tmp_col = ccs_show_meminfo_line(index);
1369                         break;
1370                 default:
1371                         tmp_col = ccs_show_literal_line(index);
1372                         break;
1373                 }
1374                 clrtoeol();
1375                 tmp_col -= ccs_window_width;
1376                 if (tmp_col > ccs_max_col)
1377                         ccs_max_col = tmp_col;
1378         }
1379         ccs_show_current(dp);
1380 }
1381
1382 static void ccs_resize_window(void)
1383 {
1384         getmaxyx(stdscr, ccs_window_height, ccs_window_width);
1385         ccs_body_lines = ccs_window_height - CCS_HEADER_LINES;
1386         if (ccs_body_lines <= ccs_current_y[ccs_current_screen])
1387                 ccs_current_y[ccs_current_screen] = ccs_body_lines - 1;
1388         if (ccs_current_y[ccs_current_screen] < 0)
1389                 ccs_current_y[ccs_current_screen] = 0;
1390 }
1391
1392 static void ccs_up_arrow_key(struct ccs_domain_policy *dp)
1393 {
1394         if (ccs_current_y[ccs_current_screen] > 0) {
1395                 ccs_current_y[ccs_current_screen]--;
1396                 ccs_show_current(dp);
1397         } else if (ccs_current_item_index[ccs_current_screen] > 0) {
1398                 ccs_current_item_index[ccs_current_screen]--;
1399                 ccs_show_list(dp);
1400         }
1401 }
1402
1403 static void ccs_down_arrow_key(struct ccs_domain_policy *dp)
1404 {
1405         if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1) {
1406                 if (ccs_current_item_index[ccs_current_screen]
1407                     + ccs_current_y[ccs_current_screen]
1408                     < ccs_list_item_count[ccs_current_screen] - 1) {
1409                         ccs_current_y[ccs_current_screen]++;
1410                         ccs_show_current(dp);
1411                 }
1412         } else if (ccs_current_item_index[ccs_current_screen]
1413                    + ccs_current_y[ccs_current_screen]
1414                    < ccs_list_item_count[ccs_current_screen] - 1) {
1415                 ccs_current_item_index[ccs_current_screen]++;
1416                 ccs_show_list(dp);
1417         }
1418 }
1419
1420 static void ccs_page_up_key(struct ccs_domain_policy *dp)
1421 {
1422         int p0 = ccs_current_item_index[ccs_current_screen];
1423         int p1 = ccs_current_y[ccs_current_screen];
1424         _Bool refresh;
1425         if (p0 + p1 > ccs_body_lines) {
1426                 p0 -= ccs_body_lines;
1427                 if (p0 < 0)
1428                         p0 = 0;
1429         } else if (p0 + p1 > 0) {
1430                 p0 = 0;
1431                 p1 = 0;
1432         } else {
1433                 return;
1434         }
1435         refresh = (ccs_current_item_index[ccs_current_screen] != p0);
1436         ccs_current_item_index[ccs_current_screen] = p0;
1437         ccs_current_y[ccs_current_screen] = p1;
1438         if (refresh)
1439                 ccs_show_list(dp);
1440         else
1441                 ccs_show_current(dp);
1442 }
1443
1444 static void ccs_page_down_key(struct ccs_domain_policy *dp)
1445 {
1446         int ccs_count = ccs_list_item_count[ccs_current_screen] - 1;
1447         int p0 = ccs_current_item_index[ccs_current_screen];
1448         int p1 = ccs_current_y[ccs_current_screen];
1449         _Bool refresh;
1450         if (p0 + p1 + ccs_body_lines < ccs_count) {
1451                 p0 += ccs_body_lines;
1452         } else if (p0 + p1 < ccs_count) {
1453                 while (p0 + p1 < ccs_count) {
1454                         if (p1 + 1 < ccs_body_lines)
1455                                 p1++;
1456                         else
1457                                 p0++;
1458                 }
1459         } else {
1460                 return;
1461         }
1462         refresh = (ccs_current_item_index[ccs_current_screen] != p0);
1463         ccs_current_item_index[ccs_current_screen] = p0;
1464         ccs_current_y[ccs_current_screen] = p1;
1465         if (refresh)
1466                 ccs_show_list(dp);
1467         else
1468                 ccs_show_current(dp);
1469 }
1470
1471 int ccs_editpolicy_get_current(void)
1472 {
1473         int ccs_count = ccs_list_item_count[ccs_current_screen];
1474         const int p0 = ccs_current_item_index[ccs_current_screen];
1475         const int p1 = ccs_current_y[ccs_current_screen];
1476         if (!ccs_count)
1477                 return EOF;
1478         if (p0 + p1 < 0 || p0 + p1 >= ccs_count) {
1479                 fprintf(stderr, "ERROR: ccs_current_item_index=%d ccs_current_y=%d\n",
1480                         p0, p1);
1481                 exit(127);
1482         }
1483         return p0 + p1;
1484 }
1485
1486 static void ccs_show_current(struct ccs_domain_policy *dp)
1487 {
1488         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && !ccs_domain_sort_type) {
1489                 char *line;
1490                 const int index = ccs_editpolicy_get_current();
1491                 ccs_get();
1492                 ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
1493                 line = ccs_shprintf("%s", ccs_eat(ccs_domain_name(dp, index)));
1494                 if (ccs_window_width < strlen(line))
1495                         line[ccs_window_width] = '\0';
1496                 move(2, 0);
1497                 clrtoeol();
1498                 ccs_editpolicy_attr_change(A_REVERSE, true);  /* add color */
1499                 printw("%s", line);
1500                 ccs_editpolicy_attr_change(A_REVERSE, false); /* add color */
1501                 ccs_put();
1502         }
1503         move(CCS_HEADER_LINES + ccs_current_y[ccs_current_screen], 0);
1504         ccs_editpolicy_line_draw(ccs_current_screen);     /* add color */
1505         refresh();
1506 }
1507
1508 static void ccs_adjust_cursor_pos(const int item_count)
1509 {
1510         if (item_count == 0) {
1511                 ccs_current_item_index[ccs_current_screen] = 0;
1512                 ccs_current_y[ccs_current_screen] = 0;
1513         } else {
1514                 while (ccs_current_item_index[ccs_current_screen]
1515                        + ccs_current_y[ccs_current_screen] >= item_count) {
1516                         if (ccs_current_y[ccs_current_screen] > 0)
1517                                 ccs_current_y[ccs_current_screen]--;
1518                         else if (ccs_current_item_index[ccs_current_screen] > 0)
1519                                 ccs_current_item_index[ccs_current_screen]--;
1520                 }
1521         }
1522 }
1523
1524 static void ccs_set_cursor_pos(const int index)
1525 {
1526         while (index < ccs_current_y[ccs_current_screen]
1527                + ccs_current_item_index[ccs_current_screen]) {
1528                 if (ccs_current_y[ccs_current_screen] > 0)
1529                         ccs_current_y[ccs_current_screen]--;
1530                 else
1531                         ccs_current_item_index[ccs_current_screen]--;
1532         }
1533         while (index > ccs_current_y[ccs_current_screen]
1534                + ccs_current_item_index[ccs_current_screen]) {
1535                 if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1)
1536                         ccs_current_y[ccs_current_screen]++;
1537                 else
1538                         ccs_current_item_index[ccs_current_screen]++;
1539         }
1540 }
1541
1542 static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index)
1543 {
1544         int x;
1545         int y;
1546         if (index < 0)
1547                 return false;
1548         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
1549                 if (!ccs_domain_sort_type) {
1550                         if (ccs_deleted_domain(dp, index) ||
1551                             ccs_initializer_source(dp, index))
1552                                 return false;
1553                         dp->list_selected[index] ^= 1;
1554                 } else {
1555                         ccs_task_list[index].selected ^= 1;
1556                 }
1557         } else {
1558                 ccs_generic_acl_list[index].selected ^= 1;
1559         }
1560         getyx(stdscr, y, x);
1561         ccs_editpolicy_sttr_save();    /* add color */
1562         ccs_show_list(dp);
1563         ccs_editpolicy_sttr_restore(); /* add color */
1564         move(y, x);
1565         return true;
1566 }
1567
1568 static int ccs_generic_acl_compare(const void *a, const void *b)
1569 {
1570         const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
1571         const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
1572         const char *a1 = ccs_directives[a0->directive].alias;
1573         const char *b1 = ccs_directives[b0->directive].alias;
1574         const char *a2 = a0->operand;
1575         const char *b2 = b0->operand;
1576         if (ccs_acl_sort_type == 0) {
1577                 const int ret = strcmp(a1, b1);
1578                 if (ret)
1579                         return ret;
1580                 return strcmp(a2, b2);
1581         } else {
1582                 const int ret = strcmp(a2, b2);
1583                 if (ret)
1584                         return ret;
1585                 return strcmp(a1, b1);
1586         }
1587 }
1588
1589 static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index)
1590 {
1591 #ifndef __GPET
1592         int c;
1593         move(1, 0);
1594         ccs_editpolicy_color_change(CCS_DISP_ERR, true);        /* add color */
1595         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
1596                 c = ccs_count(dp->list_selected, dp->list_len);
1597                 if (!c && index < dp->list_len)
1598                         c = ccs_select_item(dp, index);
1599                 if (!c)
1600                         printw("Select domain using Space key first.");
1601                 else
1602                         printw("Delete selected domain%s? ('Y'es/'N'o)",
1603                                c > 1 ? "s" : "");
1604         } else {
1605                 c = ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count);
1606                 if (!c)
1607                         c = ccs_select_item(dp, index);
1608                 if (!c)
1609                         printw("Select entry using Space key first.");
1610                 else
1611                         printw("Delete selected entr%s? ('Y'es/'N'o)",
1612                                c > 1 ? "ies" : "y");
1613         }
1614         ccs_editpolicy_color_change(CCS_DISP_ERR, false);       /* add color */
1615         clrtoeol();
1616         refresh();
1617         if (!c)
1618                 return;
1619         do {
1620                 c = ccs_getch2();
1621         } while (!(c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == EOF));
1622         ccs_resize_window();
1623         if (c != 'Y' && c != 'y') {
1624                 ccs_show_list(dp);
1625                 return;
1626         }
1627 #endif /* __GPET */
1628         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
1629                 int i;
1630                 FILE *fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
1631                 if (!fp)
1632                         return;
1633                 for (i = 1; i < dp->list_len; i++) {
1634                         if (!dp->list_selected[i])
1635                                 continue;
1636                         fprintf(fp, "delete %s\n", ccs_domain_name(dp, i));
1637                 }
1638                 ccs_close_write(fp);
1639         } else {
1640                 int i;
1641                 FILE *fp = ccs_editpolicy_open_write(ccs_policy_file);
1642                 if (!fp)
1643                         return;
1644                 if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
1645                         if (ccs_domain_sort_type)
1646                                 fprintf(fp, "select pid=%u\n", ccs_current_pid);
1647                         else
1648                                 fprintf(fp, "select domain=%s\n",
1649                                         ccs_current_domain);
1650                 }
1651                 for (i = 0; i < ccs_generic_acl_list_count; i++) {
1652                         u16 directive;
1653                         if (!ccs_generic_acl_list[i].selected)
1654                                 continue;
1655                         directive = ccs_generic_acl_list[i].directive;
1656                         fprintf(fp, "delete %s %s\n",
1657                                 ccs_directives[directive].original,
1658                                 ccs_generic_acl_list[i].operand);
1659                 }
1660                 ccs_close_write(fp);
1661         }
1662 }
1663
1664 static void ccs_add_entry(struct ccs_readline_data *rl)
1665 {
1666         FILE *fp;
1667         char *line;
1668 #ifndef __GPET
1669         ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
1670         line = ccs_readline(ccs_window_height - 1, 0, "Enter new entry> ",
1671                             rl->history, rl->count, 128000, 8);
1672         ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
1673         if (!line || !*line)
1674                 goto out;
1675         rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
1676 #else
1677         line = gpet_line;
1678 #endif
1679         fp = ccs_editpolicy_open_write(ccs_policy_file);
1680         if (!fp)
1681                 goto out;
1682         switch (ccs_current_screen) {
1683                 u16 directive;
1684         case CCS_SCREEN_DOMAIN_LIST:
1685                 if (!ccs_correct_domain(line)) {
1686                         const int len = strlen(line) + 128;
1687                         ccs_last_error = realloc(ccs_last_error, len);
1688                         if (!ccs_last_error)
1689                                 ccs_out_of_memory();
1690                         memset(ccs_last_error, 0, len);
1691                         snprintf(ccs_last_error, len - 1,
1692                                  "%s is an invalid domainname.", line);
1693                         line[0] = '\0';
1694                 }
1695                 break;
1696         case CCS_SCREEN_ACL_LIST:
1697                 if (ccs_domain_sort_type)
1698                         fprintf(fp, "select pid=%u\n", ccs_current_pid);
1699                 else
1700                         fprintf(fp, "select domain=%s\n", ccs_current_domain);
1701                 /* Fall through. */
1702         case CCS_SCREEN_EXCEPTION_LIST:
1703                 directive = ccs_find_directive(false, line);
1704                 if (directive != CCS_DIRECTIVE_NONE)
1705                         fprintf(fp, "%s ",
1706                                 ccs_directives[directive].original);
1707                 break;
1708         case CCS_SCREEN_PROFILE_LIST:
1709                 if (!strchr(line, '='))
1710                         fprintf(fp, "%s-COMMENT=\n", line);
1711                 break;
1712         }
1713         fprintf(fp, "%s\n", line);
1714         ccs_close_write(fp);
1715 out:
1716         free(line);
1717 }
1718
1719 static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward,
1720                            const int current, struct ccs_readline_data *rl)
1721 {
1722         int index = current;
1723         char *line = NULL;
1724         if (current == EOF)
1725                 return;
1726         if (!input)
1727                 goto start_search;
1728         ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
1729         line = ccs_readline(ccs_window_height - 1, 0, "Search> ",
1730                             rl->history, rl->count, 128000, 8);
1731         ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
1732         if (!line || !*line)
1733                 goto out;
1734         rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
1735         free(rl->search_buffer[ccs_current_screen]);
1736         rl->search_buffer[ccs_current_screen] = line;
1737         line = NULL;
1738         index = -1;
1739 start_search:
1740         ccs_get();
1741         while (true) {
1742                 const char *cp;
1743                 if (forward) {
1744                         if (++index >= ccs_list_item_count[ccs_current_screen])
1745                                 break;
1746                 } else {
1747                         if (--index < 0)
1748                                 break;
1749                 }
1750                 if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
1751                         if (ccs_domain_sort_type)
1752                                 cp = ccs_task_list[index].name;
1753                         else
1754                                 cp = ccs_get_last_name(dp, index);
1755                 } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
1756                         cp = ccs_shprintf("%u-%s",
1757                                           ccs_generic_acl_list[index].directive,
1758                                           ccs_generic_acl_list[index].operand);
1759                 } else {
1760                         const u16 directive = ccs_generic_acl_list[index].directive;
1761                         cp = ccs_shprintf("%s %s", ccs_directives[directive].alias,
1762                                           ccs_generic_acl_list[index].operand);
1763                 }
1764                 if (!strstr(cp, rl->search_buffer[ccs_current_screen]))
1765                         continue;
1766                 ccs_set_cursor_pos(index);
1767                 break;
1768         }
1769         ccs_put();
1770 out:
1771         free(line);
1772         ccs_show_list(dp);
1773 }
1774
1775 static void ccs_set_profile(struct ccs_domain_policy *dp, const int current)
1776 {
1777         int index;
1778         FILE *fp;
1779         char *line;
1780 #ifndef __GPET
1781         if (!ccs_domain_sort_type) {
1782                 if (!ccs_count(dp->list_selected, dp->list_len) &&
1783                     !ccs_select_item(dp, current)) {
1784                         move(1, 0);
1785                         printw("Select domain using Space key first.");
1786                         clrtoeol();
1787                         refresh();
1788                         return;
1789                 }
1790         } else {
1791                 if (!ccs_count3(ccs_task_list, ccs_task_list_len) &&
1792                     !ccs_select_item(dp, current)) {
1793                         move(1, 0);
1794                         printw("Select processes using Space key first.");
1795                         clrtoeol();
1796                         refresh();
1797                         return;
1798                 }
1799         }
1800         ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
1801         line = ccs_readline(ccs_window_height - 1, 0, "Enter profile number> ",
1802                             NULL, 0, 8, 1);
1803         ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
1804 #else
1805         line = gpet_line;
1806 #endif
1807         if (!line || !*line)
1808                 goto out;
1809         fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
1810         if (!fp)
1811                 goto out;
1812         if (!ccs_domain_sort_type) {
1813                 for (index = 0; index < dp->list_len; index++) {
1814                         if (!dp->list_selected[index])
1815                                 continue;
1816                         fprintf(fp, "select domain=%s\n" "use_profile %s\n",
1817                                 ccs_domain_name(dp, index), line);
1818                 }
1819         } else {
1820                 for (index = 0; index < ccs_task_list_len; index++) {
1821                         if (!ccs_task_list[index].selected)
1822                                 continue;
1823                         fprintf(fp, "select pid=%u\n" "use_profile %s\n",
1824                                 ccs_task_list[index].pid, line);
1825                 }
1826         }
1827         ccs_close_write(fp);
1828 out:
1829         free(line);
1830 }
1831
1832 static void ccs_set_level(struct ccs_domain_policy *dp, const int current)
1833 {
1834         int index;
1835         FILE *fp;
1836         char *line;
1837 #ifndef __GPET
1838         if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count))
1839                 ccs_select_item(dp, current);
1840         ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
1841         ccs_initial_readline_data = NULL;
1842         for (index = 0; index < ccs_generic_acl_list_count; index++) {
1843                 char *cp;
1844                 if (!ccs_generic_acl_list[index].selected)
1845                         continue;
1846                 cp = strchr(ccs_generic_acl_list[index].operand, '=');
1847                 if (!cp)
1848                         continue;
1849                 ccs_initial_readline_data = cp + 1;
1850                 break;
1851         }
1852         line = ccs_readline(ccs_window_height - 1, 0, "Enter new value> ",
1853                             NULL, 0, 128000, 1);
1854         ccs_initial_readline_data = NULL;
1855         ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
1856 #else
1857         line = gpet_line;
1858 #endif
1859         if (!line || !*line)
1860                 goto out;
1861         fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_PROFILE);
1862         if (!fp)
1863                 goto out;
1864         for (index = 0; index < ccs_generic_acl_list_count; index++) {
1865                 char *buf;
1866                 char *cp;
1867                 u16 directive;
1868                 if (!ccs_generic_acl_list[index].selected)
1869                         continue;
1870                 ccs_get();
1871                 buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand);
1872                 cp = strchr(buf, '=');
1873                 if (cp)
1874                         *cp = '\0';
1875                 directive = ccs_generic_acl_list[index].directive;
1876                 if (directive < 256)
1877                         fprintf(fp, "%u-", directive);
1878                 fprintf(fp, "%s=%s\n", buf, line);
1879                 ccs_put();
1880         }
1881         ccs_close_write(fp);
1882 out:
1883         free(line);
1884 }
1885
1886 static void ccs_set_quota(struct ccs_domain_policy *dp, const int current)
1887 {
1888         int index;
1889         FILE *fp;
1890         char *line;
1891 #ifndef __GPET
1892         if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count))
1893                 ccs_select_item(dp, current);
1894         ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
1895         line = ccs_readline(ccs_window_height - 1, 0, "Enter new value> ",
1896                             NULL, 0, 20, 1);
1897         ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
1898 #else
1899         line = gpet_line;
1900 #endif
1901         if (!line || !*line)
1902                 goto out;
1903         fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_MEMINFO);
1904         if (!fp)
1905                 goto out;
1906         for (index = 0; index < ccs_generic_acl_list_count; index++) {
1907                 char *buf;
1908                 char *cp;
1909                 if (!ccs_generic_acl_list[index].selected)
1910                         continue;
1911                 ccs_get();
1912                 buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand);
1913                 cp = strchr(buf, ':');
1914                 if (cp)
1915                         *cp = '\0';
1916                 fprintf(fp, "%s: %s\n", buf, line);
1917                 ccs_put();
1918         }
1919         ccs_close_write(fp);
1920 out:
1921         free(line);
1922 }
1923
1924 static _Bool ccs_select_acl_window(struct ccs_domain_policy *dp, const int current,
1925                                    const _Bool may_refresh)
1926 {
1927         if (ccs_current_screen != CCS_SCREEN_DOMAIN_LIST || current == EOF)
1928                 return false;
1929         ccs_current_pid = 0;
1930         if (ccs_domain_sort_type) {
1931                 ccs_current_pid = ccs_task_list[current].pid;
1932         } else if (ccs_initializer_source(dp, current)) {
1933                 int redirect_index;
1934                 if (!may_refresh)
1935                         return false;
1936                 redirect_index = ccs_find_target_domain(dp, current);
1937                 if (redirect_index == EOF)
1938                         return false;
1939                 ccs_current_item_index[ccs_current_screen]
1940                         = redirect_index - ccs_current_y[ccs_current_screen];
1941                 while (ccs_current_item_index[ccs_current_screen] < 0) {
1942                         ccs_current_item_index[ccs_current_screen]++;
1943                         ccs_current_y[ccs_current_screen]--;
1944                 }
1945                 ccs_show_list(dp);
1946                 return false;
1947         } else if (ccs_deleted_domain(dp, current)) {
1948                 return false;
1949         }
1950         free(ccs_current_domain);
1951         if (ccs_domain_sort_type)
1952                 ccs_current_domain = strdup(ccs_task_list[current].domain);
1953         else
1954                 ccs_current_domain = strdup(ccs_domain_name(dp, current));
1955         if (!ccs_current_domain)
1956                 ccs_out_of_memory();
1957         return true;
1958 }
1959
1960 static int ccs_select_window(struct ccs_domain_policy *dp, const int current)
1961 {
1962         move(0, 0);
1963         printw("Press one of below keys to switch window.\n\n");
1964         printw("e     <<< Exception Policy Editor >>>\n");
1965         printw("d     <<< Domain Transition Editor >>>\n");
1966         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && current != EOF &&
1967             !ccs_initializer_source(dp, current) &&
1968             !ccs_deleted_domain(dp, current))
1969                 printw("a     <<< Domain Policy Editor >>>\n");
1970         printw("p     <<< Profile Editor >>>\n");
1971         printw("m     <<< Manager Policy Editor >>>\n");
1972         if (!ccs_offline_mode) {
1973                 /* printw("i     <<< Interactive Enforcing Mode >>>\n"); */
1974                 printw("u     <<< Memory Usage >>>\n");
1975         }
1976         printw("q     Quit this editor.\n");
1977         clrtobot();
1978         refresh();
1979         while (true) {
1980                 int c = ccs_getch2();
1981                 if (c == 'E' || c == 'e')
1982                         return CCS_SCREEN_EXCEPTION_LIST;
1983                 if (c == 'D' || c == 'd')
1984                         return CCS_SCREEN_DOMAIN_LIST;
1985                 if (c == 'A' || c == 'a')
1986                         if (ccs_select_acl_window(dp, current, false))
1987                                 return CCS_SCREEN_ACL_LIST;
1988                 if (c == 'P' || c == 'p')
1989                         return CCS_SCREEN_PROFILE_LIST;
1990                 if (c == 'M' || c == 'm')
1991                         return CCS_SCREEN_MANAGER_LIST;
1992                 if (!ccs_offline_mode) {
1993                         /*
1994                         if (c == 'I' || c == 'i')
1995                                 return CCS_SCREEN_QUERY_LIST;
1996                         */
1997                         if (c == 'U' || c == 'u')
1998                                 return CCS_SCREEN_MEMINFO_LIST;
1999                 }
2000                 if (c == 'Q' || c == 'q')
2001                         return CCS_MAXSCREEN;
2002                 if (c == EOF)
2003                         return CCS_MAXSCREEN;
2004         }
2005 }
2006
2007 static void ccs_copy_mark_state(struct ccs_domain_policy *dp, const int current)
2008 {
2009         int index;
2010         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
2011                 if (ccs_domain_sort_type) {
2012                         const u8 selected = ccs_task_list[current].selected;
2013                         for (index = current; index < ccs_task_list_len; index++)
2014                                 ccs_task_list[index].selected = selected;
2015                 } else {
2016                         const u8 selected = dp->list_selected[current];
2017                         if (ccs_deleted_domain(dp, current) ||
2018                             ccs_initializer_source(dp, current))
2019                                 return;
2020                         for (index = current;
2021                              index < dp->list_len; index++) {
2022                                 if (ccs_deleted_domain(dp, index) ||
2023                                     ccs_initializer_source(dp, index))
2024                                         continue;
2025                                 dp->list_selected[index] = selected;
2026                         }
2027                 }
2028         } else {
2029                 const u8 selected = ccs_generic_acl_list[current].selected;
2030                 for (index = current; index < ccs_generic_acl_list_count; index++)
2031                         ccs_generic_acl_list[index].selected = selected;
2032         }
2033         ccs_show_list(dp);
2034 }
2035
2036 static void ccs_copy_to_history(struct ccs_domain_policy *dp, const int current,
2037                                 struct ccs_readline_data *rl)
2038 {
2039         const char *line;
2040         if (current == EOF)
2041                 return;
2042         ccs_get();
2043         switch (ccs_current_screen) {
2044                 u16 directive;
2045         case CCS_SCREEN_DOMAIN_LIST:
2046                 line = ccs_domain_name(dp, current);
2047                 break;
2048         case CCS_SCREEN_EXCEPTION_LIST:
2049         case CCS_SCREEN_ACL_LIST:
2050                 directive = ccs_generic_acl_list[current].directive;
2051                 line = ccs_shprintf("%s %s", ccs_directives[directive].alias,
2052                                 ccs_generic_acl_list[current].operand);
2053                 break;
2054         case CCS_SCREEN_MEMINFO_LIST:
2055                 line = NULL;
2056                 break;
2057         default:
2058                 line = ccs_shprintf("%s", ccs_generic_acl_list[current].operand);
2059         }
2060         rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
2061         ccs_put();
2062 }
2063
2064 static int ccs_generic_list_loop(struct ccs_domain_policy *dp)
2065 {
2066         static struct ccs_readline_data rl;
2067         static int saved_current_y[CCS_MAXSCREEN];
2068         static int saved_current_item_index[CCS_MAXSCREEN];
2069         static _Bool first = true;
2070         if (first) {
2071                 memset(&rl, 0, sizeof(rl));
2072                 rl.max = 20;
2073                 rl.history = malloc(rl.max * sizeof(const char *));
2074                 memset(saved_current_y, 0, sizeof(saved_current_y));
2075                 memset(saved_current_item_index, 0,
2076                        sizeof(saved_current_item_index));
2077                 first = false;
2078         }
2079         if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST) {
2080                 ccs_policy_file = CCS_PROC_POLICY_EXCEPTION_POLICY;
2081                 ccs_list_caption = "Exception Policy Editor";
2082         } else if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
2083                 ccs_policy_file = CCS_PROC_POLICY_DOMAIN_POLICY;
2084                 ccs_list_caption = "Domain Policy Editor";
2085         } else if (ccs_current_screen == CCS_SCREEN_QUERY_LIST) {
2086                 ccs_policy_file = CCS_PROC_POLICY_QUERY;
2087                 ccs_list_caption = "Interactive Enforcing Mode";
2088         } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
2089                 ccs_policy_file = CCS_PROC_POLICY_PROFILE;
2090                 ccs_list_caption = "Profile Editor";
2091         } else if (ccs_current_screen == CCS_SCREEN_MANAGER_LIST) {
2092                 ccs_policy_file = CCS_PROC_POLICY_MANAGER;
2093                 ccs_list_caption = "Manager Policy Editor";
2094         } else if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST) {
2095                 ccs_policy_file = CCS_PROC_POLICY_MEMINFO;
2096                 ccs_list_caption = "Memory Usage";
2097         } else {
2098                 ccs_policy_file = CCS_PROC_POLICY_DOMAIN_POLICY;
2099                 /* ccs_list_caption = "Domain Transition Editor"; */
2100         }
2101         ccs_current_item_index[ccs_current_screen]
2102                 = saved_current_item_index[ccs_current_screen];
2103         ccs_current_y[ccs_current_screen] = saved_current_y[ccs_current_screen];
2104 start:
2105         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
2106                 if (ccs_domain_sort_type == 0) {
2107                         ccs_read_domain_and_exception_policy(dp);
2108                         ccs_adjust_cursor_pos(dp->list_len);
2109                 } else {
2110                         ccs_read_process_list(true);
2111                         ccs_adjust_cursor_pos(ccs_task_list_len);
2112                 }
2113         } else {
2114                 ccs_read_generic_policy();
2115                 ccs_adjust_cursor_pos(ccs_generic_acl_list_count);
2116         }
2117 #ifdef __GPET
2118         return 0;
2119 #else
2120 start2:
2121         ccs_show_list(dp);
2122         if (ccs_last_error) {
2123                 move(1, 0);
2124                 printw("ERROR: %s", ccs_last_error);
2125                 clrtoeol();
2126                 refresh();
2127                 free(ccs_last_error);
2128                 ccs_last_error = NULL;
2129         }
2130         while (true) {
2131                 const int current = ccs_editpolicy_get_current();
2132                 const int c = ccs_getch2();
2133                 saved_current_item_index[ccs_current_screen]
2134                         = ccs_current_item_index[ccs_current_screen];
2135                 saved_current_y[ccs_current_screen] = ccs_current_y[ccs_current_screen];
2136                 if (c == 'q' || c == 'Q')
2137                         return CCS_MAXSCREEN;
2138                 if ((c == '\r' || c == '\n') &&
2139                     ccs_current_screen == CCS_SCREEN_ACL_LIST)
2140                         return CCS_SCREEN_DOMAIN_LIST;
2141                 if (c == '\t') {
2142                         if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST)
2143                                 return CCS_SCREEN_EXCEPTION_LIST;
2144                         else
2145                                 return CCS_SCREEN_DOMAIN_LIST;
2146                 }
2147                 if (ccs_need_reload) {
2148                         ccs_need_reload = false;
2149                         goto start;
2150                 }
2151                 if (c == ERR)
2152                         continue; /* Ignore invalid key. */
2153                 switch (c) {
2154                 case KEY_RESIZE:
2155                         ccs_resize_window();
2156                         ccs_show_list(dp);
2157                         break;
2158                 case KEY_UP:
2159                         ccs_up_arrow_key(dp);
2160                         break;
2161                 case KEY_DOWN:
2162                         ccs_down_arrow_key(dp);
2163                         break;
2164                 case KEY_PPAGE:
2165                         ccs_page_up_key(dp);
2166                         break;
2167                 case KEY_NPAGE:
2168                         ccs_page_down_key(dp);
2169                         break;
2170                 case ' ':
2171                         ccs_select_item(dp, current);
2172                         break;
2173                 case 'c':
2174                 case 'C':
2175                         if (current == EOF)
2176                                 break;
2177                         ccs_copy_mark_state(dp, current);
2178                         ccs_show_list(dp);
2179                         break;
2180                 case 'f':
2181                 case 'F':
2182                         if (ccs_current_screen != CCS_SCREEN_MEMINFO_LIST)
2183                                 ccs_find_entry(dp, true, true, current, &rl);
2184                         break;
2185                 case 'p':
2186                 case 'P':
2187                         if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST)
2188                                 break;
2189                         if (!rl.search_buffer[ccs_current_screen])
2190                                 ccs_find_entry(dp, true, false, current, &rl);
2191                         else
2192                                 ccs_find_entry(dp, false, false, current, &rl);
2193                         break;
2194                 case 'n':
2195                 case 'N':
2196                         if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST)
2197                                 break;
2198                         if (!rl.search_buffer[ccs_current_screen])
2199                                 ccs_find_entry(dp, true, true, current, &rl);
2200                         else
2201                                 ccs_find_entry(dp, false, true, current, &rl);
2202                         break;
2203                 case 'd':
2204                 case 'D':
2205                         if (ccs_readonly_mode)
2206                                 break;
2207                         switch (ccs_current_screen) {
2208                         case CCS_SCREEN_DOMAIN_LIST:
2209                                 if (ccs_domain_sort_type)
2210                                         break;
2211                         case CCS_SCREEN_EXCEPTION_LIST:
2212                         case CCS_SCREEN_ACL_LIST:
2213                         case CCS_SCREEN_MANAGER_LIST:
2214                                 ccs_delete_entry(dp, current);
2215                                 goto start;
2216                         }
2217                         break;
2218                 case 'a':
2219                 case 'A':
2220                         if (ccs_readonly_mode)
2221                                 break;
2222                         switch (ccs_current_screen) {
2223                         case CCS_SCREEN_DOMAIN_LIST:
2224                                 if (ccs_domain_sort_type)
2225                                         break;
2226                         case CCS_SCREEN_EXCEPTION_LIST:
2227                         case CCS_SCREEN_ACL_LIST:
2228                         case CCS_SCREEN_PROFILE_LIST:
2229                         case CCS_SCREEN_MANAGER_LIST:
2230                                 ccs_add_entry(&rl);
2231                                 goto start;
2232                         }
2233                         break;
2234                 case '\r':
2235                 case '\n':
2236                         if (ccs_select_acl_window(dp, current, true))
2237                                 return CCS_SCREEN_ACL_LIST;
2238                         break;
2239                 case 's':
2240                 case 'S':
2241                         if (ccs_readonly_mode)
2242                                 break;
2243                         switch (ccs_current_screen) {
2244                         case CCS_SCREEN_DOMAIN_LIST:
2245                                 ccs_set_profile(dp, current);
2246                                 goto start;
2247                         case CCS_SCREEN_PROFILE_LIST:
2248                                 ccs_set_level(dp, current);
2249                                 goto start;
2250                         case CCS_SCREEN_MEMINFO_LIST:
2251                                 ccs_set_quota(dp, current);
2252                                 goto start;
2253                         }
2254                         break;
2255                 case 'r':
2256                 case 'R':
2257                         goto start;
2258                 case KEY_LEFT:
2259                         if (!ccs_max_eat_col[ccs_current_screen])
2260                                 break;
2261                         ccs_max_eat_col[ccs_current_screen]--;
2262                         goto start2;
2263                 case KEY_RIGHT:
2264                         ccs_max_eat_col[ccs_current_screen]++;
2265                         goto start2;
2266                 case KEY_HOME:
2267                         ccs_max_eat_col[ccs_current_screen] = 0;
2268                         goto start2;
2269                 case KEY_END:
2270                         ccs_max_eat_col[ccs_current_screen] = ccs_max_col;
2271                         goto start2;
2272                 case KEY_IC:
2273                         ccs_copy_to_history(dp, current, &rl);
2274                         break;
2275                 case 'o':
2276                 case 'O':
2277                         if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
2278                                 ccs_editpolicy_try_optimize(dp, current,
2279                                                             ccs_current_screen);
2280                                 ccs_show_list(dp);
2281                         }
2282                         break;
2283                 case '@':
2284                         if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
2285                                 ccs_acl_sort_type = (ccs_acl_sort_type + 1) % 2;
2286                                 goto start;
2287                         } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
2288                                 ccs_profile_sort_type = (ccs_profile_sort_type + 1) % 2;
2289                                 goto start;
2290                         } else if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST &&
2291                                    !ccs_offline_mode) {
2292                                 ccs_domain_sort_type = (ccs_domain_sort_type + 1) % 2;
2293                                 goto start;
2294                         }
2295                         break;
2296                 case 'w':
2297                 case 'W':
2298                         return ccs_select_window(dp, current);
2299                 case '?':
2300                         if (ccs_show_command_key(ccs_current_screen, ccs_readonly_mode))
2301                                 goto start;
2302                         return CCS_MAXSCREEN;
2303                 }
2304         }
2305 #endif /* __GPET */
2306 }
2307
2308 static _Bool ccs_save_to_file(const char *src, const char *dest)
2309 {
2310         FILE *proc_fp = ccs_editpolicy_open_read(src);
2311         FILE *file_fp = fopen(dest, "w");
2312         if (!file_fp) {
2313                 fprintf(stderr, "Can't open %s\n", dest);
2314                 fclose(proc_fp);
2315                 return false;
2316         }
2317         while (true) {
2318                 int c = fgetc(proc_fp);
2319                 if (c == EOF)
2320                         break;
2321                 fputc(c, file_fp);
2322         }
2323         fclose(proc_fp);
2324         fclose(file_fp);
2325         return true;
2326 }
2327
2328 #ifdef __GPET   /* gpet */
2329 int gpet_main(void);
2330 int ccs_main(int argc, char *argv[])
2331 #else
2332 int main(int argc, char *argv[])
2333 #endif  /* gpet */
2334 {
2335         struct ccs_domain_policy dp = { NULL, 0, NULL };
2336         struct ccs_domain_policy bp = { NULL, 0, NULL };
2337         memset(ccs_current_y, 0, sizeof(ccs_current_y));
2338         memset(ccs_current_item_index, 0, sizeof(ccs_current_item_index));
2339         memset(ccs_list_item_count, 0, sizeof(ccs_list_item_count));
2340         memset(ccs_max_eat_col, 0, sizeof(ccs_max_eat_col));
2341         if (argc > 1) {
2342                 int i;
2343                 for (i = 1; i < argc; i++) {
2344                         char *ptr = argv[i];
2345                         char *cp = strchr(ptr, ':');
2346                         if (*ptr == '/') {
2347                                 if (ccs_network_mode || ccs_offline_mode)
2348                                         goto usage;
2349                                 ccs_policy_dir = ptr;
2350                                 ccs_offline_mode = true;
2351                         } else if (cp) {
2352                                 *cp++ = '\0';
2353                                 if (ccs_network_mode || ccs_offline_mode)
2354                                         goto usage;
2355                                 ccs_network_ip = inet_addr(ptr);
2356                                 ccs_network_port = htons(atoi(cp));
2357                                 ccs_network_mode = true;
2358                                 if (!ccs_check_remote_host())
2359                                         return 1;
2360                         } else if (!strcmp(ptr, "e"))
2361                                 ccs_current_screen = CCS_SCREEN_EXCEPTION_LIST;
2362                         else if (!strcmp(ptr, "d"))
2363                                 ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
2364                         else if (!strcmp(ptr, "p"))
2365                                 ccs_current_screen = CCS_SCREEN_PROFILE_LIST;
2366                         else if (!strcmp(ptr, "m"))
2367                                 ccs_current_screen = CCS_SCREEN_MANAGER_LIST;
2368                         else if (!strcmp(ptr, "u"))
2369                                 ccs_current_screen = CCS_SCREEN_MEMINFO_LIST;
2370                         else if (!strcmp(ptr, "readonly"))
2371                                 ccs_readonly_mode = true;
2372                         else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval)
2373                                  != 1) {
2374 usage:
2375                                 printf("Usage: %s [e|d|p|m|u] [readonly] "
2376                                        "[refresh=interval] "
2377                                        "[{policy_dir|remote_ip:remote_port}]\n",
2378                                        argv[0]);
2379                                 return 1;
2380                         }
2381                 }
2382         }
2383         ccs_editpolicy_init_keyword_map();
2384         if (ccs_offline_mode) {
2385                 int fd[2] = { EOF, EOF };
2386                 if (chdir(ccs_policy_dir)) {
2387                         printf("Directory %s doesn't exist.\n",
2388                                ccs_policy_dir);
2389                         return 1;
2390                 }
2391                 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
2392                         fprintf(stderr, "socketpair()\n");
2393                         exit(1);
2394                 }
2395                 switch (fork()) {
2396                 case 0:
2397                         close(fd[0]);
2398                         ccs_persistent_fd = fd[1];
2399                         ccs_editpolicy_offline_daemon();
2400                         _exit(0);
2401                 case -1:
2402                         fprintf(stderr, "fork()\n");
2403                         exit(1);
2404                 }
2405                 close(fd[1]);
2406                 ccs_persistent_fd = fd[0];
2407                 ccs_copy_file(CCS_DISK_POLICY_EXCEPTION_POLICY,
2408                               CCS_PROC_POLICY_EXCEPTION_POLICY);
2409                 ccs_copy_file(CCS_DISK_POLICY_DOMAIN_POLICY, CCS_PROC_POLICY_DOMAIN_POLICY);
2410                 ccs_copy_file(CCS_DISK_POLICY_PROFILE, CCS_PROC_POLICY_PROFILE);
2411                 ccs_copy_file(CCS_DISK_POLICY_MANAGER, CCS_PROC_POLICY_MANAGER);
2412         } else if (!ccs_network_mode) {
2413                 if (chdir(CCS_PROC_POLICY_DIR)) {
2414                         fprintf(stderr,
2415                                 "You can't use this editor for this kernel.\n");
2416                         return 1;
2417                 }
2418                 if (!ccs_readonly_mode) {
2419                         const int fd1 = ccs_open2(CCS_PROC_POLICY_EXCEPTION_POLICY,
2420                                                   O_RDWR);
2421                         const int fd2 = ccs_open2(CCS_PROC_POLICY_DOMAIN_POLICY,
2422                                                   O_RDWR);
2423                         if ((fd1 != EOF && write(fd1, "", 0) != 0) ||
2424                             (fd2 != EOF && write(fd2, "", 0) != 0)) {
2425                                 fprintf(stderr,
2426                                         "You need to register this program to "
2427                                         "%s to run this program.\n",
2428                                         CCS_PROC_POLICY_MANAGER);
2429                                 return 1;
2430                         }
2431                         close(fd1);
2432                         close(fd2);
2433                 }
2434         }
2435 #ifdef __GPET
2436         if (gpet_main())
2437                 return 1;
2438 #else
2439         initscr();
2440         ccs_editpolicy_color_init();
2441         cbreak();
2442         noecho();
2443         nonl();
2444         intrflush(stdscr, FALSE);
2445         keypad(stdscr, TRUE);
2446         getmaxyx(stdscr, ccs_window_height, ccs_window_width);
2447         if (ccs_refresh_interval) {
2448                 signal(SIGALRM, ccs_sigalrm_handler);
2449                 alarm(ccs_refresh_interval);
2450                 timeout(1000);
2451         }
2452         while (ccs_current_screen < CCS_MAXSCREEN) {
2453                 ccs_resize_window();
2454                 ccs_current_screen = ccs_generic_list_loop(&dp);
2455         }
2456         alarm(0);
2457         clear();
2458         move(0, 0);
2459         refresh();
2460         endwin();
2461 #endif /* __GPET */
2462         if (ccs_offline_mode && !ccs_readonly_mode) {
2463                 int ret_ignored;
2464                 time_t now = time(NULL);
2465                 const char *filename = ccs_make_filename("exception_policy",
2466                                                          now);
2467                 if (ccs_save_to_file(CCS_PROC_POLICY_EXCEPTION_POLICY,
2468                                      filename)) {
2469                         if (ccs_identical_file("exception_policy.conf",
2470                                                filename)) {
2471                                 unlink(filename);
2472                         } else {
2473                                 unlink("exception_policy.conf");
2474                                 ret_ignored = symlink(filename,
2475                                                       "exception_policy.conf");
2476                         }
2477                 }
2478                 ccs_clear_domain_policy(&dp);
2479                 filename = ccs_make_filename("domain_policy", now);
2480                 if (ccs_save_to_file(CCS_PROC_POLICY_DOMAIN_POLICY,
2481                                      filename)) {
2482                         if (ccs_identical_file("domain_policy.conf",
2483                                                filename)) {
2484                                 unlink(filename);
2485                         } else {
2486                                 unlink("domain_policy.conf");
2487                                 ret_ignored = symlink(filename,
2488                                                       "domain_policy.conf");
2489                         }
2490                 }
2491                 filename = ccs_make_filename("profile", now);
2492                 if (ccs_save_to_file(CCS_PROC_POLICY_PROFILE, filename)) {
2493                         if (ccs_identical_file("profile.conf", filename)) {
2494                                 unlink(filename);
2495                         } else {
2496                                 unlink("profile.conf");
2497                                 ret_ignored = symlink(filename,
2498                                                       "profile.conf");
2499                         }
2500                 }
2501                 filename = ccs_make_filename("manager", now);
2502                 if (ccs_save_to_file(CCS_PROC_POLICY_MANAGER, filename)) {
2503                         if (ccs_identical_file("manager.conf", filename)) {
2504                                 unlink(filename);
2505                         } else {
2506                                 unlink("manager.conf");
2507                                 ret_ignored = symlink(filename,
2508                                                       "manager.conf");
2509                         }
2510                 }
2511         }
2512         ccs_clear_domain_policy(&bp);
2513         ccs_clear_domain_policy(&dp);
2514         return 0;
2515 }
2516
2517 #ifdef __GPET
2518         #include "../interface.inc"
2519 #endif /* __GPET */