• R/O
  • HTTP
  • SSH
  • HTTPS

origin: Commit

gpet(Gui Policy Editor for TOMOYO Linux) repository


Commit MetaInfo

Revision46e8bfd6a6fccc3b398c08c4861504e452f2f9f5 (tree)
Zeit2011-09-09 22:15:19
Autoryocto <yocto@user...>
Commiteryocto

Log Message

Ver. 0.4 Released --- Merge branch 'develop'

  • Support TOMOYO Linux 2.4
  • The version of ccstools used was changed from 1.8.1 to 1.8.2p4.
  • Support policy namespace.
  • Desktop shortcut sample [gpet.desktop] added

Ändern Zusammenfassung

Diff

--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
1+2011/09/09 yocto <yocto@users.sourceforge.jp>
2+
3+ 0.4 Released
4+
5+ * Support TOMOYO Linux 2.4
6+
7+ * The version of ccstools used was changed from 1.8.1 to 1.8.2p4.
8+
9+ * Support policy namespace.
10+
11+ * Desktop shortcut sample [gpet.desktop] added
12+ Usage example
13+ cp /usr/share/doc/gpet/gpet.desktop ~/Desktop/
14+
15+
116 2011/06/18 yocto <yocto@users.sourceforge.jp>
217
318 0.3 Released
--- a/ChangeLog.ja
+++ b/ChangeLog.ja
@@ -1,3 +1,18 @@
1+2011/09/09 yocto <yocto@users.sourceforge.jp>
2+
3+ 0.4 Released
4+
5+ * TOMOYO Linux 2.4 対応
6+
7+ * ベースとなるccs-editpolicyをccstools 1.8.2p4 20110820版 に変更
8+
9+ * ポリシー名前空間対応
10+
11+ * デスクトップに配置するショートカットのサンプル gpet.desktop 追加
12+ 下記のようにコピーして使用してください
13+ cp /usr/share/doc/gpet/gpet.desktop ~/{Desktop|デスクトップ}/
14+
15+
116 2011/06/18 yocto <yocto@users.sourceforge.jp>
217
318 0.3 Released
@@ -53,7 +68,7 @@
5368
5469 * フォント及び色のリソースファイルに対応 gpetrc.sample 追加
5570 下記のようにコピーして中身を変更してください
56- cp /usr/share/doc/gpetrc.sample ~/.gpetrc
71+ cp /usr/share/doc/gpet/gpetrc.sample ~/.gpetrc
5772
5873 * プロセスモードのショーカットキーを Ctrl+O から Ctrl+@ に変更
5974
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
1-gpet 0.3 2011-06-18
1+gpet 0.4 2011-09-09
22
33 gpet (Gui Policy Editor for TOMOYO Linux)
44 Build / Install / Run / Uninstall
@@ -8,9 +8,9 @@ $ sudo apt-get install gcc make libncurses-dev
88
99 $ sudo apt-get install intltool libgtk2.0-dev libgconf2-dev
1010
11-$ tar xjvf gpet-0.3.tar.bz2
11+$ tar xjvf gpet-0.4.tar.bz2
1212
13-$ cd gpet-0.3
13+$ cd gpet-0.4
1414 $ ./configure --prefix /usr
1515
1616 $ make
@@ -21,42 +21,46 @@ $ sudo make install
2121
2222
2323 *** Run ***
24-$ sudo sh -c 'echo /usr/sbin/gpet >> /etc/ccs/manager.conf'
25-$ sudo ccs-loadpolicy -m < /etc/ccs/manager.conf
24+$ sudo sh -c 'echo /usr/sbin/gpet >> /etc/{ccs|tomoyo}/manager.conf'
25+$ sudo {ccs|tomoyo}-loadpolicy -m < /etc/{ccs|tomoyo}/manager.conf
2626
27-$ sudo gpet [{policy_dir|remote_ip:remote_port}]
27+$ sudo gpet [{policy_dir|remote_ip:remote_port}] [<namespace>]
2828
2929
3030 Ubuntu 11.04 disable overlay scrollbars.
3131 $ sudo sh -c "LIBOVERLAY_SCROLLBAR=0 gpet"
3232
3333
34---- Option ---
34+--- Options ---
3535 Font & color change
3636 $ cp /usr/share/doc/gpet/gpetrc.sample ~/.gpetrc
37+Desktop Launcher
38+$ cp /usr/share/doc/gpet/gpet.desktop ~/Desktop/
3739
3840
3941 *** Instll location ***
40-|-- sbin
41-| `-- gpet
42-`-- share
43- |-- doc
44- | `-- gpet
45- | |-- AUTHORS
46- | |-- COPYING
47- | |-- ChangeLog
48- | |-- ChangeLog.ja
49- | |-- INSTALL
50- | |-- NEWS
51- | |-- README
52- | `-- gpetrc.sample
53- |-- gpet
54- | `-- pixmaps
55- | `-- tomoyo.png
56- `-- locale
57- `-- ja
58- `-- LC_MESSAGES
59- `-- gpet.mo
42+/usr
43+ |-- sbin
44+ | `-- gpet
45+ `-- share
46+ |-- doc
47+ | `-- gpet
48+ | |-- AUTHORS
49+ | |-- COPYING
50+ | |-- ChangeLog
51+ | |-- ChangeLog.ja
52+ | |-- INSTALL
53+ | |-- NEWS
54+ | |-- README
55+ | |-- gpet.desktop
56+ | `-- gpetrc.sample
57+ |-- gpet
58+ | `-- pixmaps
59+ | `-- tomoyo.png
60+ `-- locale
61+ `-- ja
62+ `-- LC_MESSAGES
63+ `-- gpet.mo
6064
6165
6266 *** Uninstall ***
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,7 +14,8 @@ gpetdoc_DATA = \
1414 ChangeLog.ja\
1515 INSTALL\
1616 NEWS\
17- gpetrc.sample
17+ gpetrc.sample\
18+ gpet.desktop
1819
1920
2021 INTLTOOL_FILES = intltool-extract.in \
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
11 dnl Process this file with autoconf to produce a configure script.
22 dnl Created by Anjuta application wizard.
33
4-AC_INIT(gpet, 0.3)
4+AC_INIT(gpet, 0.4)
55
66 __GPET=gpet
77 AC_SUBST(__GPET)
--- /dev/null
+++ b/gpet.desktop
@@ -0,0 +1,9 @@
1+#!/usr/bin/env xdg-open
2+
3+[Desktop Entry]
4+Version=1.0
5+Type=Application
6+Terminal=false
7+Exec=gksudo /usr/sbin/gpet
8+Name=gpet
9+Icon=/usr/share/gpet/pixmaps/tomoyo.png
--- a/po/ja.po
+++ b/po/ja.po
@@ -8,8 +8,8 @@ msgid ""
88 msgstr ""
99 "Project-Id-Version: 0.1\n"
1010 "Report-Msgid-Bugs-To: \n"
11-"POT-Creation-Date: 2011-06-10 13:56+0900\n"
12-"PO-Revision-Date: 2011-06-10 13:56+0900\n"
11+"POT-Creation-Date: 2011-09-09 21:50+0900\n"
12+"PO-Revision-Date: 2011-09-09 20:43+0900\n"
1313 "Last-Translator: Yoshihiro Kusuno <yocto@users.sourceforge.jp>\n"
1414 "Language-Team: Japanese < >\n"
1515 "Language: \n"
@@ -17,44 +17,44 @@ msgstr ""
1717 "Content-Type: text/plain; charset=UTF-8\n"
1818 "Content-Transfer-Encoding: 8bit\n"
1919
20-#: ../src/gpet.c:1193
20+#: ../src/gpet.c:1241
2121 msgid "offline"
2222 msgstr "オフライン"
2323
24-#: ../src/gpet.c:1193
24+#: ../src/gpet.c:1241
2525 msgid "nework"
2626 msgstr "ネットワーク"
2727
28-#: ../src/gpet.c:1193
28+#: ../src/gpet.c:1241
2929 msgid "online"
3030 msgstr "オンライン"
3131
32-#: ../src/gpet.c:1237 ../src/gpet.c:1242 ../src/menu.c:79
32+#: ../src/gpet.c:1286 ../src/gpet.c:1291 ../src/menu.c:79
3333 msgid "Statistics"
3434 msgstr "統計情報"
3535
36-#: ../src/gpet.c:1248 ../src/gpet.c:1252 ../src/gpet.c:1257
36+#: ../src/gpet.c:1297 ../src/gpet.c:1301 ../src/gpet.c:1306
3737 msgid "Manager Policy"
3838 msgstr "マネージャ 一覧"
3939
40-#: ../src/gpet.c:1263 ../src/gpet.c:1267 ../src/gpet.c:1272
40+#: ../src/gpet.c:1312 ../src/gpet.c:1316 ../src/gpet.c:1321
4141 msgid "Domain Policy Editor"
4242 msgstr "ドメインポリシーエディタ"
4343
44-#: ../src/gpet.c:1443 ../src/gpet.c:1468
44+#: ../src/gpet.c:1494 ../src/gpet.c:1519
4545 msgid "gpet"
4646 msgstr "gpet"
4747
4848 #. create tab
49-#: ../src/gpet.c:1575 ../src/menu.c:469
49+#: ../src/gpet.c:1644 ../src/menu.c:473
5050 msgid "Domain Transition"
5151 msgstr "ドメイン遷移 一覧"
5252
53-#: ../src/gpet.c:1576
53+#: ../src/gpet.c:1645
5454 msgid "Exception Policy"
5555 msgstr "例外ポリシー 一覧"
5656
57-#: ../src/gpet.c:1577
57+#: ../src/gpet.c:1646
5858 msgid "Profile"
5959 msgstr "プロファイル 一覧"
6060
@@ -159,7 +159,7 @@ msgid "_Manager..."
159159 msgstr "マネージャ...(_M)"
160160
161161 #: ../src/menu.c:77
162-msgid "Manager Profile Editor"
162+msgid "Manager Policy Editor"
163163 msgstr "マネージャ 一覧"
164164
165165 #: ../src/menu.c:78
@@ -190,11 +190,11 @@ msgstr "ACLウィンドウ切離し"
190190 msgid "Detach ACL window"
191191 msgstr "ドメインポリシーを別ウィンドウで表示します。"
192192
193-#: ../src/menu.c:466
193+#: ../src/menu.c:470
194194 msgid "Process State"
195195 msgstr "プロセス 一覧"
196196
197-#: ../src/menu.c:748
197+#: ../src/menu.c:776
198198 #, c-format
199199 msgid ""
200200 "<span foreground='red' size='x-large'><b>Delete</b> the %d selected "
@@ -203,7 +203,7 @@ msgstr ""
203203 "<span foreground='red' size='x-large'>選択した %d行の例外ポリシーを<b>削除</"
204204 "b>します。</span>"
205205
206-#: ../src/menu.c:751
206+#: ../src/menu.c:779
207207 #, c-format
208208 msgid ""
209209 "<span foreground='red' size='x-large'><b>Delete</b> the selected exception "
@@ -212,7 +212,7 @@ msgstr ""
212212 "<span foreground='red' size='x-large'>選択した 例外ポリシーを<b>削除</b>しま"
213213 "す。</span>"
214214
215-#: ../src/menu.c:768
215+#: ../src/menu.c:796
216216 #, c-format
217217 msgid ""
218218 "<span foreground='red' size='x-large'><b>Delete</b> the %d selected domains?"
@@ -221,7 +221,7 @@ msgstr ""
221221 "<span foreground='red' size='x-large'>選択した %d行のドメインを<b>削除</b>し"
222222 "ます。</span>"
223223
224-#: ../src/menu.c:771
224+#: ../src/menu.c:799
225225 #, c-format
226226 msgid ""
227227 "<span foreground='red' size='x-large'><b>Delete</b> the selected domain?</"
@@ -230,7 +230,7 @@ msgstr ""
230230 "<span foreground='red' size='x-large'>選択した ドメインを<b>削除</b>します。"
231231 "</span>"
232232
233-#: ../src/menu.c:790
233+#: ../src/menu.c:818
234234 #, c-format
235235 msgid ""
236236 "<span foreground='blue' size='x-large'><b>Delete</b> the %d selected "
@@ -239,7 +239,7 @@ msgstr ""
239239 "<span foreground='red' size='x-large'>選択した %d行のポリシーを<b>削除</b>し"
240240 "ます。</span>"
241241
242-#: ../src/menu.c:793
242+#: ../src/menu.c:821
243243 #, c-format
244244 msgid ""
245245 "<span foreground='blue' size='x-large'><b>Delete</b> the selected policy?</"
@@ -248,41 +248,45 @@ msgstr ""
248248 "<span foreground='red' size='x-large'>選択した ポリシーを<b>削除</b>します。"
249249 "</span>"
250250
251-#: ../src/menu.c:1027
251+#: ../src/menu.c:1055
252252 msgid "Add Domain"
253253 msgstr "ドメインを追加します。"
254254
255-#: ../src/menu.c:1034
255+#: ../src/menu.c:1062
256256 msgid "Add Acl"
257257 msgstr "ドメインに対するアクセス許可を追加します。"
258258
259-#: ../src/menu.c:1046
259+#: ../src/menu.c:1074
260260 msgid "Add Exception"
261261 msgstr "例外ポリシーを追加します。"
262262
263-#: ../src/menu.c:1054
263+#: ../src/menu.c:1082
264264 msgid "Add Profile (0 - 255)"
265265 msgstr "プロファイルを追加します。 (0 - 255)"
266266
267-#: ../src/menu.c:1196
267+#: ../src/menu.c:1090
268+msgid "Add Namespace"
269+msgstr "ポリシー名前空間を追加します。"
270+
271+#: ../src/menu.c:1232
268272 msgid "Profile list"
269273 msgstr "プロファイルを選択します。"
270274
271-#: ../src/menu.c:1271
275+#: ../src/menu.c:1309
272276 msgid "Profile Edit"
273277 msgstr "プロファイルを変更します。"
274278
275-#: ../src/menu.c:1355
279+#: ../src/menu.c:1393
276280 msgid "Yoshihiro Kusuno <yocto@users.sourceforge.jp>"
277-msgstr "楠野 佳宏 <yocto@users.sourceforge.jp>"
281+msgstr "クスノ <yocto@users.sourceforge.jp>"
278282
279-#: ../src/menu.c:1356
283+#: ../src/menu.c:1394
280284 msgid "ccstools --- kumaneko san"
281285 msgstr "ccstools --- 熊猫さん"
282286
283-#: ../src/menu.c:1358
287+#: ../src/menu.c:1396
284288 msgid "Yoshihiro Kusuno"
285-msgstr "楠野 佳宏"
289+msgstr "クスノ"
286290
287291 #: ../src/other.c:49
288292 msgid "Edit the selected line"
--- a/src/gpet.c
+++ b/src/gpet.c
@@ -72,6 +72,12 @@ gchar *decode_from_octal_str(const char *name)
7272 }
7373
7474 /*---------------------------------------------------------------------------*/
75+static gboolean is_jump_source(
76+ struct ccs_domain_policy3 *dp, const int index)
77+{
78+ return dp->list[index].target != NULL;
79+}
80+/*---------------------------------------------------------------------------*/
7581 enum tree_column_pos {
7682 COLUMN_INDEX, // data index (invisible)
7783 COLUMN_NUMBER, // n
@@ -87,7 +93,7 @@ enum tree_column_pos {
8793 };
8894 /*---------------------------------------------------------------------------*/
8995 static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
90- struct ccs_domain_policy *dp, int *index, int nest)
96+ struct ccs_domain_policy3 *dp, int *index, int nest)
9197 {
9298 GtkTreeIter iter;
9399 gchar *color = "black";
@@ -99,7 +105,7 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
99105
100106 //g_print("add_tree_store index[%3d] nest[%2d]\n", *index, nest);
101107
102- sp = ccs_domain_name(dp, *index);
108+ sp = get_domain_name(dp, *index);
103109 for (n = 0; ; n++) {
104110 const char *cp = strchr(sp, ' ');
105111 if (!cp)
@@ -112,9 +118,7 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
112118 number = dp->list[*index].number;
113119 if (number >= 0) {
114120 str_num = g_strdup_printf("%4d", number);
115- str_prof = dp->list[*index].profile_assigned ?
116- g_strdup_printf("%3u", dp->list[*index].profile) :
117- g_strdup("???");
121+ str_prof = g_strdup_printf("%3u", dp->list[*index].profile);
118122 } else {
119123 str_num = g_strdup("");
120124 str_prof = g_strdup("");
@@ -126,14 +130,14 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
126130 COLUMN_COLON, number >= 0 ? ":" : "",
127131 COLUMN_PROFILE, str_prof,
128132 COLUMN_KEEPER_DOMAIN, dp->list[*index].is_dk ? "#" : " ",
129- COLUMN_INITIALIZER_TARGET, dp->list[*index].is_dit ? "*" : " ",
133+ COLUMN_INITIALIZER_TARGET, dp->list[*index].is_djt ? "*" : " ",
130134 COLUMN_DOMAIN_UNREACHABLE, dp->list[*index].is_du ? "!" : " ",
131135 -1);
132136 g_free(str_num);
133137 g_free(str_prof);
134138
135139 transition_control = dp->list[*index].d_t;
136- if (transition_control && !(dp->list[*index].is_dis)) {
140+ if (transition_control && !is_jump_source(dp, *index)) {
137141 line = g_strdup_printf(" ( %s%s from %s )",
138142 get_transition_name(transition_control->type),
139143 transition_control->program ?
@@ -141,24 +145,26 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
141145 transition_control->domainname ?
142146 transition_control->domainname->name : "any");
143147 color =
144- transition_control->type == CCS_TRANSITION_CONTROL_KEEP ?
145- "green" : "cyan";
146- } else if (dp->list[*index].is_dis) { /* initialize_domain */
147- is_dis = g_strdup_printf(CCS_ROOT_NAME "%s",
148- strrchr(ccs_domain_name(dp, *index), ' '));
149- redirect_index = ccs_find_domain(dp, is_dis, false, false);
150- g_free(is_dis);
148+ transition_control->type == CCS_TRANSITION_CONTROL_KEEP ?
149+ "green" : "cyan";
150+ } else if (is_jump_source(dp, *index)) { /* initialize_domain */
151+ g_free(name);
152+ name = g_strdup(dp->list[*index].target->name);
153+ redirect_index = get_find_target_domain(*index);
151154 color = "blue";
152155 if (redirect_index >= 0)
153156 is_dis = g_strdup_printf(" ( -> %d )",
154157 dp->list[redirect_index].number);
155- else
158+ else if (redirect_index == EOF)
156159 is_dis = g_strdup_printf(" ( -> Not Found )");
160+ else
161+ is_dis = g_strdup_printf(" ( -> Namespace jump )");
157162 } else if (dp->list[*index].is_dd) { /* delete_domain */
158163 color = "gray";
159164 }
160- domain = g_strdup_printf("%s%s%s%s%s",
165+ domain = g_strdup_printf("%s%s%s%s%s%s",
161166 dp->list[*index].is_dd ? "( " : "",
167+ is_jump_source(dp, *index) ? "=> " : "",
162168 name,
163169 dp->list[*index].is_dd ? " )" : "",
164170 line ? line : "",
@@ -175,7 +181,7 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
175181 (*index)++;
176182
177183 while (*index < dp->list_len) {
178- sp = ccs_domain_name(dp, *index);
184+ sp = get_domain_name(dp, *index);
179185 for (n = 0; ; n++) {
180186 const char *cp = strchr(sp, ' ');
181187 if (!cp)
@@ -192,7 +198,7 @@ static int add_tree_store(GtkTreeStore *store, GtkTreeIter *parent_iter,
192198 return n;
193199 }
194200
195-void add_tree_data(GtkTreeView *treeview, struct ccs_domain_policy *dp)
201+void add_tree_data(GtkTreeView *treeview, struct ccs_domain_policy3 *dp)
196202 {
197203 GtkTreeStore *store;
198204 GtkTreeIter *iter = NULL;
@@ -200,7 +206,8 @@ void add_tree_data(GtkTreeView *treeview, struct ccs_domain_policy *dp)
200206
201207 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
202208 gtk_tree_store_clear(store); // TODO 遅い
203- add_tree_store(store, iter, dp, &index, nest);
209+ if (dp->list_len > 0)
210+ add_tree_store(store, iter, dp, &index, nest);
204211 }
205212 /*---------------------------------------------------------------------------*/
206213 static GtkTreeViewColumn *column_add(
@@ -308,12 +315,13 @@ enum list_column_pos {
308315 N_COLUMNS_LIST
309316 };
310317
311-void add_list_data(generic_list_t *generic, gboolean alias_flag)
318+void add_list_data(generic_list_t *generic,
319+ enum ccs_screen_type current_page)
312320 {
313321 GtkListStore *store;
314322 GtkTreeIter iter;
315323 int i;
316- gchar *str_num, *profile, *alias;
324+ gchar *str_num, *ope, *profile, *alias;
317325
318326 store = GTK_LIST_STORE(gtk_tree_view_get_model(
319327 GTK_TREE_VIEW(generic->listview)));
@@ -323,21 +331,21 @@ void add_list_data(generic_list_t *generic, gboolean alias_flag)
323331 str_num = g_strdup_printf("%4d", i);
324332 gtk_list_store_append(store, &iter);
325333
326- if (alias_flag) {
327- gchar *ope = decode_from_octal_str(
328- generic->list[i].operand);
329-
334+ switch((int)current_page) {
335+ case CCS_SCREEN_EXCEPTION_LIST :
336+ case CCS_SCREEN_ACL_LIST :
337+ ope = decode_from_octal_str(generic->list[i].operand);
330338 alias = (gchar *)
331339 ccs_directives[generic->list[i].directive].alias;
332340 gtk_list_store_set(store, &iter,
333- LIST_NUMBER, str_num,
334- LIST_COLON, ":",
335- LIST_ALIAS, alias,
336-// LIST_OPERAND, generic->list[i].operand,
337- LIST_OPERAND, ope, // test
338- -1);
339- g_free(ope); // test
340- } else {
341+ LIST_NUMBER, str_num,
342+ LIST_COLON, ":",
343+ LIST_ALIAS, alias,
344+ LIST_OPERAND, ope,
345+ -1);
346+ g_free(ope);
347+ break;
348+ case CCS_SCREEN_PROFILE_LIST :
341349 profile = g_strdup_printf("%3u-",
342350 generic->list[i].directive);
343351 alias = g_strdup_printf("%s%s",
@@ -351,6 +359,14 @@ void add_list_data(generic_list_t *generic, gboolean alias_flag)
351359 -1);
352360 g_free(profile);
353361 g_free(alias);
362+ break;
363+ case CCS_SCREEN_NS_LIST :
364+ gtk_list_store_set(store, &iter,
365+ LIST_NUMBER, str_num,
366+ LIST_COLON, ":",
367+ LIST_OPERAND, generic->list[i].operand,
368+ -1);
369+ break;
354370 }
355371 g_free(str_num);
356372 }
@@ -500,7 +516,7 @@ static gboolean move_pos_list(GtkTreeModel *model, GtkTreePath *path,
500516 view = transition->treeview;
501517 gtk_tree_model_get(model, iter, COLUMN_INDEX, &index, -1);
502518 str_buff = decode_from_octal_str(
503- ccs_domain_name(transition->dp, index));
519+ get_domain_name(transition->dp, index));
504520 cmp = strcmp(entry, str_buff);
505521 break;
506522 case ADDENTRY_ACL_LIST :
@@ -524,6 +540,11 @@ static gboolean move_pos_list(GtkTreeModel *model, GtkTreePath *path,
524540 cmp = atoi(entry) - transition->prf.list[atoi(str_buff)].directive;
525541 //g_print("entry[%s] [%s:%d]\n", entry, str_buff, transition->prf.list[atoi(str_buff)].directive);
526542 break;
543+ case ADDENTRY_NAMESPACE_LIST :
544+ view = transition->ns.listview;
545+ gtk_tree_model_get(model, iter, LIST_OPERAND, &operand, -1);
546+ cmp = strcmp(entry, operand);
547+ break;
527548 }
528549 g_free(alias);
529550 g_free(operand);
@@ -572,6 +593,9 @@ void set_position_addentry(transition_t *transition, GtkTreePath **path)
572593 case ADDENTRY_PROFILE_LIST :
573594 view = transition->prf.listview;
574595 break;
596+ case ADDENTRY_NAMESPACE_LIST :
597+ view = transition->ns.listview;
598+ break;
575599 }
576600
577601 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
@@ -622,7 +646,12 @@ static void cb_selection(GtkTreeSelection *selection,
622646 g_list_free(list);
623647 gtk_tree_model_get(model, &iter, COLUMN_INDEX, &index, -1);
624648 DEBUG_PRINT("--- index [%4d] ---\n", index);
625- name = decode_from_octal_str(ccs_domain_name(transition->dp, index));
649+ name = decode_from_octal_str(get_domain_name(transition->dp, index));
650+ if (is_jump_source(transition->dp, index)) {
651+ gchar *cp = strrchr(name, ' ');
652+ if (cp)
653+ *cp = '\0';
654+ }
626655 gtk_entry_set_text(GTK_ENTRY(transition->domainbar), name);
627656 g_free(name);
628657
@@ -631,7 +660,7 @@ static void cb_selection(GtkTreeSelection *selection,
631660
632661 get_acl_list(transition->dp, index,
633662 &(transition->acl.list), &(transition->acl.count));
634- add_list_data(&(transition->acl), TRUE);
663+ add_list_data(&(transition->acl), CCS_SCREEN_ACL_LIST);
635664
636665 if (transition->acl.count) {
637666 set_position_addentry(transition, &path);
@@ -645,55 +674,24 @@ static void cb_selection(GtkTreeSelection *selection,
645674 }
646675 DEBUG_PRINT("Out **************************** \n");
647676 }
648-#if 0
649-static void cb_selection (GtkTreeView *treeview,
650- transition_t *transition)
677+/*---------------------------------------------------------------------------*/
678+static void set_ns_tab_label(transition_t *transition,
679+ const gchar *namespace)
651680 {
652- GtkTreeSelection *selection;
653- GtkTreeIter iter;
654- gint select_count;
655- GtkTreeModel *model;
656- GList *list;
657- gint index;
658- GtkTreePath *path = NULL;
659- GtkTreeViewColumn *column = NULL;
660-
661- DEBUG_PRINT("In **************************** \n");
662- selection = gtk_tree_view_get_selection(treeview);
663- select_count = gtk_tree_selection_count_selected_rows(selection);
664- DEBUG_PRINT("select count[%d]\n", select_count);
665- if (0 == select_count)
666- return;
667-
668- model = gtk_tree_view_get_model(
669- GTK_TREE_VIEW(transition->treeview));
670- list = gtk_tree_selection_get_selected_rows(selection, NULL);
671- gtk_tree_model_get_iter(model, &iter, g_list_first(list)->data);
672- g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
673- g_list_free(list);
674- gtk_tree_model_get(model, &iter, COLUMN_INDEX, &index, -1);
675- DEBUG_PRINT("--- index [%4d] ---\n", index);
676- gtk_entry_set_text(GTK_ENTRY(transition->domainbar),
677- ccs_domain_name(transition->dp, index));
678-
679- gtk_tree_view_get_cursor(GTK_TREE_VIEW(
680- transition->acl.listview), &path, &column);
681-
682- get_acl_list(transition->dp, index,
683- &(transition->acl.list), &(transition->acl.count));
684- add_list_data(&(transition->acl), TRUE);
685-
686- if (transition->acl.count) {
687- DEBUG_PRINT("ACL count<%d>\n", transition->acl.count);
688- DEBUG_PRINT("ACL ");
689- view_cursor_set(transition->acl.listview, path, column);
690- disp_statusbar(transition, CCS_SCREEN_ACL_LIST);
691- } else { /* delete_domain or initializer_source */
692- disp_statusbar(transition, CCS_MAXSCREEN);
693- }
694- DEBUG_PRINT("Out **************************** \n");
681+ GtkWidget *notebook;
682+ GtkWidget *tab4;
683+
684+ notebook = g_object_get_data(
685+ G_OBJECT(transition->window), "notebook");
686+ tab4 = g_object_get_data(
687+ G_OBJECT(transition->window), "tab4");
688+ gtk_notebook_set_tab_label_text(
689+ GTK_NOTEBOOK(notebook), tab4, namespace);
690+ gtk_notebook_set_menu_label_text(
691+ GTK_NOTEBOOK(notebook), tab4, namespace);
692+
693+ put_ns_name(namespace);
695694 }
696-#endif
697695 /*---------------------------------------------------------------------------*/
698696 struct FindIsDis_t {
699697 gint redirect_index;
@@ -716,21 +714,36 @@ static gboolean find_is_dis(GtkTreeModel *model, GtkTreePath *path,
716714 }
717715
718716 static void cb_initialize_domain(GtkTreeView *treeview, GtkTreePath *treepath,
719- GtkTreeViewColumn treeviewcolumn, gpointer dummy)
717+ GtkTreeViewColumn *treeviewcolumn, transition_t *transition)
720718 {
721- GtkTreeIter iter;
722- GtkTreeModel *model;
723- gboolean ret;
719+ GtkTreeIter iter;
720+ GtkTreeModel *model;
724721 struct FindIsDis_t data;
722+ gint index;
725723
726724 DEBUG_PRINT("In **************************** \n");
727725 model = gtk_tree_view_get_model(treeview);
728- ret = gtk_tree_model_get_iter(model, &iter, treepath);
729- if (ret)
730- gtk_tree_model_get(model, &iter,
726+ if (!gtk_tree_model_get_iter(model, &iter, treepath))
727+ return;
728+
729+ gtk_tree_model_get(model, &iter, COLUMN_INDEX, &index,
731730 COLUMN_REDIRECT, &data.redirect_index, -1);
732- DEBUG_PRINT("redirect_index[%d]\n", data.redirect_index);
733- if (!ret || data.redirect_index < 0)
731+//#undef DEBUG_PRINT
732+//#define DEBUG_PRINT g_print
733+ DEBUG_PRINT("index[%d] redirect_index[%d]\n", index, data.redirect_index);
734+
735+ if (data.redirect_index == -2) {
736+ gchar *namespace =
737+ g_strdup(transition->dp->list[index].target->name);
738+ DEBUG_PRINT("%s\n", namespace);
739+ char *cp = strchr(namespace, ' ');
740+ if (cp)
741+ *cp = '\0';
742+ set_ns_tab_label(transition, namespace);
743+ g_free(namespace);
744+ refresh_transition(NULL, transition);
745+ return;
746+ } else if (data.redirect_index < 0)
734747 return; /* not initialize_domain */
735748
736749 data.path = NULL;
@@ -793,6 +806,10 @@ void set_sensitive(GtkActionGroup *actions, int task_flag,
793806 sens_add = TRUE;
794807 sens_cpy = TRUE;
795808 break;
809+ case CCS_SCREEN_NS_LIST :
810+ sens_add = TRUE;
811+ sens_cpy = TRUE;
812+ break;
796813 }
797814
798815 gtk_action_set_sensitive(gtk_action_group_get_action(
@@ -876,6 +893,37 @@ static gboolean cb_select_prf(GtkTreeView *listview, GdkEventButton *event,
876893 transition->current_page);
877894 return popup_menu(transition, event->button);
878895 }
896+
897+static gboolean cb_select_ns(GtkTreeView *listview, GdkEventButton *event,
898+ transition_t *transition)
899+{
900+ transition->current_page = CCS_SCREEN_NS_LIST;
901+ set_sensitive(transition->actions, transition->task_flag,
902+ transition->current_page);
903+ return popup_menu(transition, event->button);
904+}
905+/*---------------------------------------------------------------------------*/
906+static void cb_ns_selection(GtkTreeSelection *selection,
907+ transition_t *transition)
908+{
909+ GtkTreeIter iter;
910+ GtkTreeModel *model;
911+ GList *list;
912+ gchar *namespace;
913+
914+ if (0 == gtk_tree_selection_count_selected_rows(selection))
915+ return;
916+
917+ model = gtk_tree_view_get_model(
918+ GTK_TREE_VIEW(transition->ns.listview));
919+ list = gtk_tree_selection_get_selected_rows(selection, NULL);
920+ gtk_tree_model_get_iter(model, &iter, g_list_first(list)->data);
921+ g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
922+ g_list_free(list);
923+ gtk_tree_model_get(model, &iter, LIST_OPERAND, &namespace, -1);
924+ set_ns_tab_label(transition, namespace);
925+ g_free(namespace);
926+}
879927 /*---------------------------------------------------------------------------*/
880928 static gboolean inc_search(GtkTreeModel *model, gint column,
881929 const gchar *key, GtkTreeIter *iter, gpointer search_data)
@@ -975,7 +1023,7 @@ static void set_select_flag_domain(gpointer data,
9751023 GtkTreeModel *model;
9761024 GtkTreeIter iter;
9771025 gint index;
978- struct ccs_domain_policy *dp = transition->dp;
1026+ struct ccs_domain_policy3 *dp = transition->dp;
9791027
9801028
9811029 model = gtk_tree_view_get_model(
@@ -988,7 +1036,7 @@ static void set_select_flag_domain(gpointer data,
9881036
9891037 DEBUG_PRINT("index[%d]\n", index);
9901038 /* deleted_domain or initializer_source */
991- if (!(dp->list[index].is_dd) && !(dp->list[index].is_dis))
1039+ if (!(dp->list[index].is_dd) && !(dp->list[index].target))
9921040 dp->list_selected[index] = 1;
9931041 }
9941042
@@ -1164,7 +1212,7 @@ gint delete_exp(transition_t *transition,
11641212 return result;
11651213 }
11661214 /*---------------------------------------------------------------------------*/
1167-static void create_tabs(GtkWidget *notebook, GtkWidget *box, gchar *str)
1215+static void create_tabs(GtkWidget *notebook, GtkWidget *box, const gchar *str)
11681216 {
11691217 GtkWidget *label, *label_box, *menu_box;
11701218
@@ -1220,6 +1268,7 @@ gchar *disp_window_title(enum ccs_screen_type current_page)
12201268 CCS_PROC_POLICY_EXCEPTION_POLICY);
12211269 break;
12221270 case CCS_SCREEN_PROFILE_LIST :
1271+ case CCS_SCREEN_NS_LIST :
12231272 if (is_offline())
12241273 title = g_strdup_printf("%s - %s%s%s", mode[e_off], dir,
12251274 CCS_DISK_POLICY_DIR, CCS_DISK_POLICY_PROFILE);
@@ -1320,25 +1369,20 @@ static void cb_switch_page(GtkWidget *notebook,
13201369 GTK_TREE_VIEW(tran->treeview));
13211370 selection_list = gtk_tree_view_get_selection(
13221371 GTK_TREE_VIEW(tran->acl.listview));
1323-
13241372 if (tran->acl_detached) {
1325- if(selection_list &&
1326- gtk_tree_selection_count_selected_rows(selection_list))
1327- tran->current_page = CCS_SCREEN_ACL_LIST;
1373+ tran->current_page = CCS_SCREEN_ACL_LIST;
13281374 control_acl_window(tran);
1329- g_object_set(G_OBJECT(notebook), "can-focus", FALSE, NULL);
1330- } else {
1331- if (tran->task_flag ||
1332- (selection_tree &&
1333- gtk_tree_selection_count_selected_rows(selection_tree)))
1334- tran->current_page = CCS_SCREEN_DOMAIN_LIST;
1335- else if(selection_list &&
1336- gtk_tree_selection_count_selected_rows(selection_list))
1337- tran->current_page = CCS_SCREEN_ACL_LIST;
1338- else
1339- tran->current_page = CCS_MAXSCREEN;
1340- g_object_set(G_OBJECT(notebook), "can-focus", TRUE, NULL);
13411375 }
1376+ if (tran->task_flag ||
1377+ (selection_tree &&
1378+ gtk_tree_selection_count_selected_rows(selection_tree)))
1379+ tran->current_page = CCS_SCREEN_DOMAIN_LIST;
1380+ else if(selection_list &&
1381+ gtk_tree_selection_count_selected_rows(selection_list))
1382+ tran->current_page = CCS_SCREEN_ACL_LIST;
1383+ else
1384+ tran->current_page = CCS_MAXSCREEN;
1385+ g_object_set(G_OBJECT(notebook), "can-focus", TRUE, NULL);
13421386 break;
13431387 case 1 :
13441388 tran->current_page = CCS_SCREEN_EXCEPTION_LIST;
@@ -1354,16 +1398,23 @@ static void cb_switch_page(GtkWidget *notebook,
13541398 }
13551399 g_object_set(G_OBJECT(notebook), "can-focus", FALSE, NULL);
13561400 break;
1401+ case 3 :
1402+ tran->current_page = CCS_SCREEN_NS_LIST;
1403+ if (tran->acl_detached) {
1404+ control_acl_window(tran);
1405+ }
1406+ g_object_set(G_OBJECT(notebook), "can-focus", FALSE, NULL);
1407+ break;
13571408 }
13581409
13591410 title = disp_window_title(tran->current_page);
13601411 gtk_window_set_title(GTK_WINDOW(tran->window), title);
13611412 g_free(title);
1362-// disp_statusbar(tran, tran->current_page);
13631413 set_sensitive(tran->actions, tran->task_flag,
13641414 tran->current_page);
13651415
13661416 refresh_transition(NULL, tran);
1417+ disp_statusbar(tran, tran->current_page);
13671418 DEBUG_PRINT("Out Tab[%d]\n", page_num);
13681419 }
13691420 /*---------------------------------------------------------------------------*/
@@ -1422,7 +1473,7 @@ int gpet_main(void)
14221473 GtkWidget *statusbar;
14231474 gint contextid;
14241475 GtkWidget *vbox;
1425- GtkWidget *tab1, *tab2, *tab3;
1476+ GtkWidget *tab1, *tab2, *tab3, *tab4;
14261477 GtkWidget *notebook;
14271478 GtkWidget *pane;
14281479 GtkWidget *domainbar;
@@ -1430,7 +1481,7 @@ int gpet_main(void)
14301481 GtkWidget *treeview, *listview;
14311482 GtkContainer *container, *acl_container;
14321483 gchar *title;
1433- struct ccs_domain_policy dp = { NULL, 0, NULL };
1484+ struct ccs_domain_policy3 dp = { NULL, 0, NULL };
14341485 transition_t transition;
14351486
14361487 transition.task_flag = 0;
@@ -1533,12 +1584,12 @@ int gpet_main(void)
15331584
15341585 // cursor move domain window
15351586 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
1536- "changed", G_CALLBACK(cb_selection), &transition);
1587+ "changed", G_CALLBACK(cb_selection), &transition);
15371588 // g_signal_connect(GTK_TREE_VIEW(treeview), "cursor-changed",
15381589 // G_CALLBACK(cb_selection), &transition);
15391590 // double click or enter key domain window
15401591 g_signal_connect(G_OBJECT(treeview), "row-activated",
1541- G_CALLBACK(cb_initialize_domain), NULL);
1592+ G_CALLBACK(cb_initialize_domain), &transition);
15421593 // mouse click domain window
15431594 g_signal_connect(G_OBJECT(treeview), "button-press-event",
15441595 G_CALLBACK(cb_select_domain), &transition);
@@ -1566,19 +1617,40 @@ int gpet_main(void)
15661617 if (get_profile(&(transition.prf.list), &(transition.prf.count)))
15671618 g_warning("Read error : profile");
15681619 else
1569- add_list_data(&(transition.prf), FALSE);
1620+ add_list_data(&(transition.prf), CCS_SCREEN_PROFILE_LIST);
15701621 // mouse click profile window
15711622 g_signal_connect(G_OBJECT(listview), "button-press-event",
15721623 G_CALLBACK(cb_select_prf), &transition);
15731624
1625+ tab4 = gtk_vbox_new(FALSE, 1);
1626+ // create namespace view
1627+ listview = create_list_model(FALSE);
1628+ create_list_view(tab4, listview, FALSE);
1629+ transition.ns.listview = listview;
1630+ transition.ns.count = 0;
1631+ transition.ns.list = NULL;
1632+ if (get_namespace(&(transition.ns.list), &(transition.ns.count)))
1633+ g_warning("Read error : namespace");
1634+ else
1635+ add_list_data(&(transition.ns), CCS_SCREEN_NS_LIST);
1636+ // mouse click namespace window
1637+ g_signal_connect(G_OBJECT(listview), "button-press-event",
1638+ G_CALLBACK(cb_select_ns), &transition);
1639+ // cursor move namespace window
1640+ g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)),
1641+ "changed", G_CALLBACK(cb_ns_selection), &transition);
1642+
15741643 // create tab
15751644 create_tabs(notebook, tab1, _("Domain Transition"));
15761645 create_tabs(notebook, tab2, _("Exception Policy"));
15771646 create_tabs(notebook, tab3, _("Profile"));
1647+ create_tabs(notebook, tab4, get_ns_name());
15781648
15791649 /* to save menu.c Process_state() */
15801650 g_object_set_data(G_OBJECT(window), "notebook", notebook);
15811651 g_object_set_data(G_OBJECT(window), "tab1", tab1);
1652+ /* to save cb_ns_selection() */
1653+ g_object_set_data(G_OBJECT(window), "tab4", tab4);
15821654
15831655 // tab change
15841656 g_signal_connect(G_OBJECT(notebook), "switch_page",
--- a/src/gpet.h
+++ b/src/gpet.h
@@ -44,6 +44,7 @@ enum addentry_type {
4444 ADDENTRY_EXCEPTION_LIST,
4545 ADDENTRY_PROFILE_LIST,
4646 ADDENTRY_MANAGER_LIST,
47+ ADDENTRY_NAMESPACE_LIST,
4748 ADDENTRY_NON
4849 };
4950
@@ -58,13 +59,14 @@ typedef struct _transition_t {
5859
5960 GtkContainer *container;
6061
61- struct ccs_domain_policy *dp;
62+ struct ccs_domain_policy3 *dp;
6263 int domain_count;
6364 generic_list_t acl; // ACL
6465 GtkWidget *acl_window;
6566 gboolean acl_detached;
6667 generic_list_t exp; // exception
6768 generic_list_t prf; // profile
69+ generic_list_t ns; // namespace
6870 task_list_t tsk; // Process
6971 int task_flag; // 1:process
7072 // 0:domain
@@ -93,17 +95,19 @@ typedef struct _transition_t {
9395 int ccs_main(int argc, char *argv[]);
9496
9597 // interface.inc
96-int get_domain_policy(struct ccs_domain_policy *dp, int *count);
98+int get_domain_policy(struct ccs_domain_policy3 *dp, int *count);
9799 int add_domain(char *input, char **err_buff);
98-int set_profile(struct ccs_domain_policy *dp,
100+int set_profile(struct ccs_domain_policy3 *dp,
99101 char *profile, char **err_buff);
100102 int get_task_list(struct ccs_task_entry **tsk, int *count);
101-int get_acl_list(struct ccs_domain_policy *dp, int current,
103+const char *get_domain_name(const struct ccs_domain_policy3 *dp,
104+ const int index);
105+int get_acl_list(struct ccs_domain_policy3 *dp, int current,
102106 struct ccs_generic_acl **ga, int *count);
103107 int get_process_acl_list(int current,
104108 struct ccs_generic_acl **ga, int *count);
105109 int get_optimize_acl_list(int current, struct ccs_generic_acl **ga, int count);
106-int add_acl_list(struct ccs_domain_policy *dp, int current,
110+int add_acl_list(struct ccs_domain_policy3 *dp, int current,
107111 char *input, char **err_buff);
108112 const char *get_transition_name(enum ccs_transition_type type);
109113 int get_exception_policy(struct ccs_generic_acl **ga, int *count);
@@ -111,27 +115,34 @@ int add_exception_policy(char *input, char **err_buff);
111115 int get_profile(struct ccs_generic_acl **ga, int *count);
112116 int add_profile(char *input, char **err_buff);
113117 int set_profile_level(int index, const char *input, char **err_buff);
118+int get_namespace(struct ccs_generic_acl **ga, int *count);
119+int add_namespace(char *input, char **err_buff);
114120 int get_manager(struct ccs_generic_acl **ga, int *count);
115121 int add_manager(char *input, char **err_buff);
116122 int get_memory(struct ccs_generic_acl **ga, int *count);
117123 int set_memory(struct ccs_generic_acl *ga, int count, char **err_buff);
118-int delete_domain_policy(struct ccs_domain_policy *dp, char **err_buff);
119-int delete_acl_policy(struct ccs_domain_policy *dp, char **err_buff,
124+int delete_domain_policy(struct ccs_domain_policy3 *dp, char **err_buff);
125+int delete_acl_policy(struct ccs_domain_policy3 *dp, char **err_buff,
120126 struct ccs_generic_acl *ga, int count);
121-int delete_exp_policy(struct ccs_domain_policy *dp, char **err_buff,
127+int delete_exp_policy(struct ccs_domain_policy3 *dp, char **err_buff,
122128 struct ccs_generic_acl *ga, int count);
123129 int delete_manager_policy(
124130 struct ccs_generic_acl *ga, int count, char **err_buff);
125-int is_offline(void);
126-int is_network(void);
131+_Bool is_offline(void);
132+_Bool is_network(void);
127133 char *get_remote_ip(char *str_ip);
128134 const char *get_policy_dir(void);
129135 const char *get_domain_last_name(const int index);
136+int get_find_target_domain(const int index);
137+const char *get_ns_name(void);
138+void put_ns_name(const char *namespace);
139+_Bool is_ccs(void);
130140
131141 // gpet.c
132142 gchar *decode_from_octal_str(const char *name);
133-void add_tree_data(GtkTreeView *treeview, struct ccs_domain_policy *dp);
134-void add_list_data(generic_list_t *generic, gboolean alias_flag);
143+void add_tree_data(GtkTreeView *treeview, struct ccs_domain_policy3 *dp);
144+void add_list_data(generic_list_t *generic,
145+ enum ccs_screen_type current_page);
135146 gint get_current_domain_index(transition_t *transition);
136147 gchar *get_alias_and_operand(GtkWidget *view, gboolean alias_flag);
137148 void set_position_addentry(transition_t *transition, GtkTreePath **path);
@@ -168,6 +179,7 @@ void read_config(transition_t *tran);
168179 void write_config(transition_t *tran);
169180
170181 // other.c
182+gboolean namespace_main(transition_t *transition);
171183 void manager_main(transition_t *transition);
172184 void memory_main(transition_t *transition);
173185
--- a/src/interface.inc
+++ b/src/interface.inc
@@ -19,8 +19,13 @@
1919 * along with this program; if not, write to the Free Software
2020 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
2121 */
22+static void ccs_out_of_memory(void)
23+{
24+ fprintf(stderr, "Out of memory. Aborted.\n");
25+ exit(1);
26+}
2227
23-int get_domain_policy(struct ccs_domain_policy *dp, int *count)
28+int get_domain_policy(struct ccs_domain_policy3 *dp, int *count)
2429 {
2530 int result = 1;
2631
@@ -52,7 +57,7 @@ int add_domain(char *input, char **err_buff)
5257 return result;
5358 }
5459
55-int set_profile(struct ccs_domain_policy *dp,
60+int set_profile(struct ccs_domain_policy3 *dp,
5661 char *profile, char **err_buff)
5762 {
5863 int dummy = 0, result = 0;
@@ -112,19 +117,25 @@ static void generic_acl_copy(struct ccs_generic_acl **src, int src_cnt,
112117 }
113118 }
114119
115-int get_acl_list(struct ccs_domain_policy *dp, int current,
120+const char *get_domain_name(const struct ccs_domain_policy3 *dp,
121+ const int index)
122+{
123+ return dp->list[index].domainname->name;
124+}
125+
126+int get_acl_list(struct ccs_domain_policy3 *dp, int current,
116127 struct ccs_generic_acl **ga, int *count)
117128 {
118129 int result = 0;
119130
120131 ccs_dp = *dp;
121- if (ccs_initializer_source(current)) {
132+ if (ccs_jump_source(current)) {
122133 *count = 0;
123134 } else if (ccs_deleted_domain(current)) {
124135 *count = 0;
125136 } else {
126137 free(ccs_current_domain);
127- ccs_current_domain = strdup(ccs_domain_name(dp, current));
138+ ccs_current_domain = strdup(get_domain_name(dp, current));
128139 if (!ccs_current_domain)
129140 ccs_out_of_memory();
130141 else {
@@ -178,14 +189,13 @@ int get_optimize_acl_list(int current, struct ccs_generic_acl **ga, int count)
178189 return 0;
179190 }
180191
181-int add_acl_list(struct ccs_domain_policy *dp, int current,
192+int add_acl_list(struct ccs_domain_policy3 *dp, int current,
182193 char *input, char **err_buff)
183194 {
184195 int result = 0;
185196
186197 ccs_dp = *dp;
187- if (ccs_initializer_source(current) ||
188- ccs_deleted_domain(current)) {
198+ if (ccs_jump_source(current) || ccs_deleted_domain(current)) {
189199 *dp = ccs_dp;
190200 return 1;
191201 }
@@ -298,6 +308,54 @@ int set_profile_level(int index, const char *input, char **err_buff)
298308 return result;
299309 }
300310
311+int get_namespace(struct ccs_generic_acl **ga, int *count)
312+{
313+ struct ccs_generic_acl *orig_generic_acl_list = NULL;
314+ int orig_generic_acl_list_count = 0;
315+ int result;
316+
317+ generic_acl_copy(&ccs_gacl_list,
318+ ccs_gacl_list_count,
319+ &orig_generic_acl_list,
320+ orig_generic_acl_list_count);
321+ orig_generic_acl_list_count = ccs_gacl_list_count;
322+
323+ ccs_current_screen = CCS_SCREEN_NS_LIST;
324+ result = ccs_generic_list_loop();
325+
326+ generic_acl_copy(&ccs_gacl_list,
327+ ccs_gacl_list_count,
328+ ga, *count);
329+ *count = ccs_gacl_list_count;
330+
331+ generic_acl_copy(&orig_generic_acl_list,
332+ orig_generic_acl_list_count,
333+ &ccs_gacl_list,
334+ ccs_gacl_list_count);
335+ ccs_gacl_list_count = orig_generic_acl_list_count;
336+
337+ return result;
338+}
339+
340+int add_namespace(char *input, char **err_buff)
341+{
342+ int result = 0;
343+
344+ ccs_current_screen = CCS_SCREEN_NS_LIST;
345+ gpet_line = input;
346+ ccs_add_entry();
347+ gpet_line = NULL;
348+
349+ if (ccs_last_error) {
350+ (*err_buff) = strdup(ccs_last_error);
351+ free(ccs_last_error);
352+ ccs_last_error = NULL;
353+ result = 1;
354+ }
355+
356+ return result;
357+}
358+
301359 int get_manager(struct ccs_generic_acl **ga, int *count)
302360 {
303361 struct ccs_generic_acl *orig_generic_acl_list = NULL;
@@ -411,7 +469,7 @@ int set_memory(struct ccs_generic_acl *ga, int count, char **err_buff)
411469 return result;
412470 }
413471
414-int delete_domain_policy(struct ccs_domain_policy *dp, char **err_buff)
472+int delete_domain_policy(struct ccs_domain_policy3 *dp, char **err_buff)
415473 {
416474 int result = 0;
417475
@@ -431,7 +489,7 @@ int delete_domain_policy(struct ccs_domain_policy *dp, char **err_buff)
431489 return result;
432490 }
433491
434-int delete_acl_policy(struct ccs_domain_policy *dp, char **err_buff,
492+int delete_acl_policy(struct ccs_domain_policy3 *dp, char **err_buff,
435493 struct ccs_generic_acl *ga, int count)
436494 {
437495 int result = 0;
@@ -456,7 +514,7 @@ int delete_acl_policy(struct ccs_domain_policy *dp, char **err_buff,
456514 return result;
457515 }
458516
459-int delete_exp_policy(struct ccs_domain_policy *dp, char **err_buff,
517+int delete_exp_policy(struct ccs_domain_policy3 *dp, char **err_buff,
460518 struct ccs_generic_acl *ga, int count)
461519 {
462520 int result = 0;
@@ -501,12 +559,12 @@ int delete_manager_policy(
501559 return result;
502560 }
503561
504-int is_offline(void)
562+_Bool is_offline(void)
505563 {
506564 return ccs_offline_mode;
507565 }
508566
509-int is_network(void)
567+_Bool is_network(void)
510568 {
511569 return ccs_network_mode;
512570 }
@@ -529,3 +587,31 @@ const char *get_domain_last_name(const int index)
529587 {
530588 return ccs_get_last_name(index);
531589 }
590+
591+int get_find_target_domain(const int index)
592+{
593+ return ccs_find_target_domain(index);
594+}
595+
596+const char *get_ns_name(void)
597+{
598+ return ccs_current_ns->name;
599+}
600+
601+void put_ns_name(const char *namespace)
602+{
603+ ccs_current_ns = ccs_savename(namespace);
604+}
605+
606+/*-------+---------+---------+---------+---------+---------+---------+--------*/
607+static _Bool gpet_is_ccs_flag;
608+static void set_ccs_flag(void)
609+{
610+// if (!is_offline() && !is_network())
611+ gpet_is_ccs_flag = chdir(TOMOYO_PROC_POLICY_DIR) ? true : false;
612+}
613+
614+_Bool is_ccs(void)
615+{
616+ return gpet_is_ccs_flag;
617+}
--- a/src/menu.c
+++ b/src/menu.c
@@ -74,7 +74,7 @@ static GtkActionEntry entries[] = {
7474 {"Refresh", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>R",
7575 N_("Refresh to the latest information"), G_CALLBACK(refresh_transition)},
7676 {"Manager", GTK_STOCK_DND, N_("_Manager..."), "<control>M",
77- N_("Manager Profile Editor"), G_CALLBACK(manager_transition)},
77+ N_("Manager Policy Editor"), G_CALLBACK(manager_transition)},
7878 {"Memory", GTK_STOCK_DND, N_("_Statistics..."), "<control>S",
7979 N_("Statistics"), G_CALLBACK(memory_transition)},
8080
@@ -232,6 +232,10 @@ void disp_statusbar(transition_t *transition, int scr)
232232 status_str = g_strdup_printf("Entry[%d]",
233233 transition->prf.count);
234234 break;
235+ case CCS_SCREEN_NS_LIST :
236+ status_str = g_strdup_printf("Entry[%d]",
237+ transition->ns.count);
238+ break;
235239 case CCS_SCREEN_DOMAIN_LIST :
236240 case CCS_SCREEN_ACL_LIST :
237241 if (transition->task_flag)
@@ -498,20 +502,34 @@ void view_cursor_set(GtkWidget *view,
498502 if (!path) {
499503 path = gtk_tree_path_new_from_indices(0, -1);
500504 }
501-
505+#if 0
502506 {
503507 gchar *path_str = gtk_tree_path_to_string(path);
504508 DEBUG_PRINT("<%s> TreePath[%s]\n",
505509 g_type_name(G_OBJECT_TYPE(view)), path_str);
506510 g_free(path_str);
507511 }
508- gtk_tree_view_set_cursor(
509- GTK_TREE_VIEW(view), path, column, FALSE);
512+#endif
513+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), path, column, FALSE);
514+ gtk_tree_path_free(path);
515+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(view), &path, &column);
516+ if (!path) {
517+ path = gtk_tree_path_new_from_indices(0, -1);
518+ gtk_tree_view_set_cursor(
519+ GTK_TREE_VIEW(view), path, column, FALSE);
520+ }
510521 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view), path, NULL,
511522 TRUE, 0.5, 0.0); // ksn
512523 gtk_tree_path_free(path);
513524 }
514525
526+static void clear_acl_view(transition_t *transition)
527+{
528+ gtk_entry_set_text(GTK_ENTRY(transition->domainbar), get_ns_name());
529+ transition->acl.count = 0;
530+ add_list_data(&(transition->acl), CCS_SCREEN_ACL_LIST);
531+}
532+
515533 void refresh_transition(GtkAction *action, transition_t *transition)
516534 {
517535 GtkTreePath *path = NULL;
@@ -527,7 +545,7 @@ void refresh_transition(GtkAction *action, transition_t *transition)
527545 if (get_exception_policy(
528546 &(transition->exp.list), &(transition->exp.count)))
529547 break;
530- add_list_data(&(transition->exp), TRUE);
548+ add_list_data(&(transition->exp), CCS_SCREEN_EXCEPTION_LIST);
531549 set_position_addentry(transition, &path);
532550 disp_statusbar(transition, CCS_SCREEN_EXCEPTION_LIST);
533551 view_cursor_set(view, path, column);
@@ -540,12 +558,25 @@ void refresh_transition(GtkAction *action, transition_t *transition)
540558 if (get_profile(
541559 &(transition->prf.list), &(transition->prf.count)))
542560 break;
543- add_list_data(&(transition->prf), FALSE);
561+ add_list_data(&(transition->prf), CCS_SCREEN_PROFILE_LIST);
544562 set_position_addentry(transition, &path);
545563 disp_statusbar(transition, CCS_SCREEN_PROFILE_LIST);
546564 view_cursor_set(view, path, column);
547565 gtk_widget_grab_focus(view);
548566 break;
567+ case CCS_SCREEN_NS_LIST :
568+ view = transition->ns.listview;
569+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(view),
570+ &path, &column);
571+ if (get_namespace(
572+ &(transition->ns.list), &(transition->ns.count)))
573+ break;
574+ add_list_data(&(transition->ns), CCS_SCREEN_NS_LIST);
575+ set_position_addentry(transition, &path);
576+ disp_statusbar(transition, CCS_SCREEN_NS_LIST);
577+ view_cursor_set(view, path, column);
578+ gtk_widget_grab_focus(view);
579+ break;
549580 case CCS_SCREEN_DOMAIN_LIST :
550581 case CCS_MAXSCREEN :
551582 view = transition->task_flag ?
@@ -560,6 +591,7 @@ void refresh_transition(GtkAction *action, transition_t *transition)
560591 break;
561592 add_task_tree_data(GTK_TREE_VIEW(view), &(transition->tsk));
562593 gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
594+ view_cursor_set(view, path, column);
563595 } else {
564596 if (get_domain_policy(
565597 transition->dp, &(transition->domain_count)))
@@ -567,20 +599,12 @@ void refresh_transition(GtkAction *action, transition_t *transition)
567599 add_tree_data(GTK_TREE_VIEW(view), transition->dp);
568600 gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
569601 set_position_addentry(transition, &path);
602+ if (transition->domain_count)
603+ view_cursor_set(view, path, column);
604+ else
605+ clear_acl_view(transition);
570606 }
571-
572- view_cursor_set(view, path, column);
573607 gtk_widget_show(view);
574-#if 0
575- if (transition->acl_detached) { // get focus
576- gtk_widget_grab_focus(transition->acl.listview);
577- DEBUG_PRINT("☆Transition[%d] Acl[%d]\n",
578- gtk_window_has_toplevel_focus(GTK_WINDOW(transition->window)),
579- gtk_window_has_toplevel_focus(GTK_WINDOW(transition->acl_window)));
580- } else {
581- gtk_widget_grab_focus(view);
582- }
583-#endif
584608 gtk_widget_grab_focus(view);
585609 break;
586610 case CCS_SCREEN_ACL_LIST :
@@ -612,7 +636,7 @@ static void copy_line(GtkAction *action, transition_t *transition)
612636 view = transition->treeview;
613637 if (index >= 0)
614638 insert_history_buffer(view, decode_from_octal_str(
615- ccs_domain_name(transition->dp, index)));
639+ get_domain_name(transition->dp, index)));
616640 break;
617641 case CCS_SCREEN_ACL_LIST :
618642 view = transition->acl.listview;
@@ -626,6 +650,10 @@ static void copy_line(GtkAction *action, transition_t *transition)
626650 view = transition->prf.listview;
627651 insert_history_buffer(view, get_alias_and_operand(view, FALSE));
628652 break;
653+ case CCS_SCREEN_NS_LIST :
654+ view = transition->ns.listview;
655+ insert_history_buffer(view, get_alias_and_operand(view, FALSE));
656+ break;
629657 default :
630658 break;
631659 }
@@ -1056,6 +1084,14 @@ static void append_transition(GtkAction *action, transition_t *transition)
10561084 result = add_profile(input, &err_buff);
10571085 type = ADDENTRY_PROFILE_LIST;
10581086 break;
1087+ case CCS_SCREEN_NS_LIST :
1088+ DEBUG_PRINT("append namespace\n");
1089+ result = append_dialog(transition,
1090+ _("Add Namespace"), &input);
1091+ if (!result)
1092+ result = add_namespace(input, &err_buff);
1093+ type = ADDENTRY_NAMESPACE_LIST;
1094+ break;
10591095 default :
10601096 DEBUG_PRINT("append ???\n");
10611097 break;
@@ -1203,6 +1239,8 @@ static void set_domain(transition_t *transition)
12031239 listview = create_list_profile();
12041240 g_signal_connect(G_OBJECT(listview), "row-activated",
12051241 G_CALLBACK(cb_profile_activate), dialog);
1242+ if (get_profile(&(transition->prf.list), &(transition->prf.count)))
1243+ return;
12061244 add_list_profile(listview, &(transition->prf));
12071245 view_cursor_set(listview, NULL, NULL);
12081246 gtk_container_add(
@@ -1368,8 +1406,8 @@ static void show_about_dialog(void)
13681406 gtk_about_dialog_set_copyright(about,
13691407 "Copyright(C) 2010,2011 TOMOYO Linux Project");
13701408 gtk_about_dialog_set_comments(about,
1371- "Gui Policy Editor for TOMOYO Linux 1.8.1"
1372- " or AKARI 1.0.11"
1409+ "Gui Policy Editor for TOMOYO Linux 2.4 , 1.8.2"
1410+ " or AKARI 1.0.17"
13731411 "\n(based on ccs-editpolicy:ccstools)");
13741412 gtk_about_dialog_set_website(about, "http://sourceforge.jp/projects/gpet/");
13751413 // gtk_about_dialog_set_website_label(about, "http://tomoyo.sourceforge.jp/");
--- a/src/process.c
+++ b/src/process.c
@@ -181,7 +181,7 @@ static void cb_selection_proc(GtkTreeSelection *selection,
181181
182182 get_process_acl_list(index,
183183 &(transition->acl.list), &(transition->acl.count));
184- add_list_data(&(transition->acl), TRUE);
184+ add_list_data(&(transition->acl), CCS_SCREEN_ACL_LIST);
185185
186186 view_cursor_set(transition->acl.listview, path, column);
187187
--- a/src/usr_sbin/ccstools.c
+++ b/src/usr_sbin/ccstools.c
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2+ 2011/08/20
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -61,13 +61,79 @@ static void ccs_sort_domain_policy(struct ccs_domain_policy *dp);
6161 *
6262 * This function does not return.
6363 */
64-void ccs_out_of_memory(void)
64+static void ccs_out_of_memory(void)
6565 {
6666 fprintf(stderr, "Out of memory. Aborted.\n");
6767 exit(1);
6868 }
6969
7070 /**
71+ * ccs_strdup - strdup() with abort on error.
72+ *
73+ * @string: String to duplicate.
74+ *
75+ * Returns copy of @string on success, abort otherwise.
76+ */
77+char *ccs_strdup(const char *string)
78+{
79+ char *cp = strdup(string);
80+ if (!cp)
81+ ccs_out_of_memory();
82+ return cp;
83+}
84+
85+/**
86+ * ccs_realloc - realloc() with abort on error.
87+ *
88+ * @ptr: Pointer to void.
89+ * @size: New size.
90+ *
91+ * Returns return value of realloc() on success, abort otherwise.
92+ */
93+void *ccs_realloc(void *ptr, const size_t size)
94+{
95+ void *vp = realloc(ptr, size);
96+ if (!vp)
97+ ccs_out_of_memory();
98+ return vp;
99+}
100+
101+/**
102+ * ccs_realloc2 - realloc() with abort on error.
103+ *
104+ * @ptr: Pointer to void.
105+ * @size: New size.
106+ *
107+ * Returns return value of realloc() on success, abort otherwise.
108+ *
109+ * Allocated memory is cleared with 0.
110+ */
111+void *ccs_realloc2(void *ptr, const size_t size)
112+{
113+ void *vp = ccs_realloc(ptr, size);
114+ memset(vp, 0, size);
115+ return vp;
116+}
117+
118+/**
119+ * ccs_malloc - malloc() with abort on error.
120+ *
121+ * @size: Size to allocate.
122+ *
123+ * Returns return value of malloc() on success, abort otherwise.
124+ *
125+ * Allocated memory is cleared with 0.
126+ */
127+void *ccs_malloc(const size_t size)
128+{
129+ void *vp = malloc(size);
130+ if (!vp)
131+ ccs_out_of_memory();
132+ memset(vp, 0, size);
133+ return vp;
134+}
135+
136+/**
71137 * ccs_str_starts - Check whether the given string starts with the given keyword.
72138 *
73139 * @str: Pointer to "char *".
@@ -186,28 +252,6 @@ void ccs_normalize_line(char *buffer)
186252 }
187253
188254 /**
189- * ccs_make_filename - Make filename using given prefix.
190- *
191- * @prefix: String to use as a prefix, including leading directories.
192- * @time: A time_t value, usually return value of time(NULL).
193- *
194- * Returns pathname with timestamp embedded using static buffer.
195- *
196- * Note that this function is no longer used by anybody since 1.8.0p1.
197- */
198-char *ccs_make_filename(const char *prefix, const time_t time)
199-{
200- struct tm *tm = localtime(&time);
201- static char filename[1024];
202- memset(filename, 0, sizeof(filename));
203- snprintf(filename, sizeof(filename) - 1,
204- "%s.%02d-%02d-%02d.%02d:%02d:%02d.conf",
205- prefix, tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
206- tm->tm_hour, tm->tm_min, tm->tm_sec);
207- return filename;
208-}
209-
210-/**
211255 * ccs_partial_name_hash - Hash name.
212256 *
213257 * @c: A unsigned long value.
@@ -286,22 +330,6 @@ static int ccs_const_part_length(const char *filename)
286330 }
287331
288332 /**
289- * ccs_domain_def - Check whether the given token can be a domainname.
290- *
291- * @domainname: The token to check.
292- *
293- * Returns true if @domainname possibly be a domainname, false otherwise.
294- *
295- * Note that this function in kernel source checks only !strncmp() part.
296- */
297-_Bool ccs_domain_def(const char *domainname)
298-{
299- return !strncmp(domainname, CCS_ROOT_NAME, CCS_ROOT_NAME_LEN) &&
300- (domainname[CCS_ROOT_NAME_LEN] == '\0'
301- || domainname[CCS_ROOT_NAME_LEN] == ' ');
302-}
303-
304-/**
305333 * ccs_fprintf_encoded - fprintf() using TOMOYO's escape rules.
306334 *
307335 * @fp: Pointer to "FILE".
@@ -481,6 +509,28 @@ _Bool ccs_correct_path(const char *filename)
481509 }
482510
483511 /**
512+ * ccs_domain_def - Check whether the given token can be a domainname.
513+ *
514+ * @buffer: The token to check.
515+ *
516+ * Returns true if @buffer possibly be a domainname, false otherwise.
517+ */
518+_Bool ccs_domain_def(const char *buffer)
519+{
520+ const char *cp;
521+ int len;
522+ if (*buffer != '<')
523+ return false;
524+ cp = strchr(buffer, ' ');
525+ if (!cp)
526+ len = strlen(buffer);
527+ else
528+ len = cp - buffer;
529+ return buffer[len - 1] == '>' &&
530+ ccs_correct_word2(buffer + 1, len - 2);
531+}
532+
533+/**
484534 * ccs_correct_domain - Check whether the given domainname follows the naming rules.
485535 *
486536 * @domainname: The domainname to check.
@@ -489,20 +539,17 @@ _Bool ccs_correct_path(const char *filename)
489539 */
490540 _Bool ccs_correct_domain(const char *domainname)
491541 {
492- if (!domainname || strncmp(domainname, CCS_ROOT_NAME,
493- CCS_ROOT_NAME_LEN))
494- goto out;
495- domainname += CCS_ROOT_NAME_LEN;
496- if (!*domainname)
542+ if (!domainname || !ccs_domain_def(domainname))
543+ return false;
544+ domainname = strchr(domainname, ' ');
545+ if (!domainname++)
497546 return true;
498- if (*domainname++ != ' ')
499- goto out;
500547 while (1) {
501548 const char *cp = strchr(domainname, ' ');
502549 if (!cp)
503550 break;
504551 if (*domainname != '/' ||
505- !ccs_correct_word2(domainname, cp - domainname - 1))
552+ !ccs_correct_word2(domainname, cp - domainname))
506553 goto out;
507554 domainname = cp + 1;
508555 }
@@ -829,7 +876,7 @@ void ccs_fill_path_info(struct ccs_path_info *ptr)
829876 *
830877 * @name: Pointer to "const char".
831878 *
832- * Returns pointer to "const struct ccs_path_info" on success, NULL otherwise.
879+ * Returns pointer to "const struct ccs_path_info" on success, abort otherwise.
833880 *
834881 * The returned pointer refers shared string. Thus, the caller must not free().
835882 */
@@ -843,7 +890,7 @@ const struct ccs_path_info *ccs_savename(const char *name)
843890 int len;
844891 static _Bool first_call = true;
845892 if (!name)
846- return NULL;
893+ ccs_out_of_memory();
847894 len = strlen(name) + 1;
848895 hash = ccs_full_name_hash((const unsigned char *) name, len - 1);
849896 if (first_call) {
@@ -855,23 +902,19 @@ const struct ccs_path_info *ccs_savename(const char *name)
855902 ccs_fill_path_info(&name_list[i].entry);
856903 }
857904 }
858- ptr = &name_list[hash % CCS_SAVENAME_MAX_HASH];
859- while (ptr) {
905+ for (ptr = &name_list[hash % CCS_SAVENAME_MAX_HASH]; ptr;
906+ ptr = ptr->next) {
860907 if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
861- goto out;
908+ return &ptr->entry;
862909 prev = ptr;
863- ptr = ptr->next;
864910 }
865- ptr = malloc(sizeof(*ptr) + len);
866- if (!ptr)
867- ccs_out_of_memory();
911+ ptr = ccs_malloc(sizeof(*ptr) + len);
868912 ptr->next = NULL;
869913 ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
870914 memmove((void *) ptr->entry.name, name, len);
871915 ccs_fill_path_info(&ptr->entry);
872916 prev->next = ptr; /* prev != NULL because name_list is not empty. */
873-out:
874- return ptr ? &ptr->entry : NULL;
917+ return &ptr->entry;
875918 }
876919
877920 /**
@@ -912,6 +955,222 @@ int ccs_parse_number(const char *number, struct ccs_number_entry *entry)
912955 return 0;
913956 }
914957
958+/*
959+ * Routines for parsing IPv4 or IPv6 address.
960+ * These are copied from lib/hexdump.c net/core/utils.c .
961+ */
962+#include <ctype.h>
963+
964+static int hex_to_bin(char ch)
965+{
966+ if ((ch >= '0') && (ch <= '9'))
967+ return ch - '0';
968+ ch = tolower(ch);
969+ if ((ch >= 'a') && (ch <= 'f'))
970+ return ch - 'a' + 10;
971+ return -1;
972+}
973+
974+#define IN6PTON_XDIGIT 0x00010000
975+#define IN6PTON_DIGIT 0x00020000
976+#define IN6PTON_COLON_MASK 0x00700000
977+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
978+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
979+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
980+#define IN6PTON_DOT 0x00800000 /* . */
981+#define IN6PTON_DELIM 0x10000000
982+#define IN6PTON_NULL 0x20000000 /* first/tail */
983+#define IN6PTON_UNKNOWN 0x40000000
984+
985+static inline int xdigit2bin(char c, int delim)
986+{
987+ int val;
988+
989+ if (c == delim || c == '\0')
990+ return IN6PTON_DELIM;
991+ if (c == ':')
992+ return IN6PTON_COLON_MASK;
993+ if (c == '.')
994+ return IN6PTON_DOT;
995+
996+ val = hex_to_bin(c);
997+ if (val >= 0)
998+ return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
999+
1000+ if (delim == -1)
1001+ return IN6PTON_DELIM;
1002+ return IN6PTON_UNKNOWN;
1003+}
1004+
1005+static int in4_pton(const char *src, int srclen, u8 *dst, int delim,
1006+ const char **end)
1007+{
1008+ const char *s;
1009+ u8 *d;
1010+ u8 dbuf[4];
1011+ int ret = 0;
1012+ int i;
1013+ int w = 0;
1014+
1015+ if (srclen < 0)
1016+ srclen = strlen(src);
1017+ s = src;
1018+ d = dbuf;
1019+ i = 0;
1020+ while(1) {
1021+ int c;
1022+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
1023+ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
1024+ IN6PTON_COLON_MASK))) {
1025+ goto out;
1026+ }
1027+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
1028+ if (w == 0)
1029+ goto out;
1030+ *d++ = w & 0xff;
1031+ w = 0;
1032+ i++;
1033+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
1034+ if (i != 4)
1035+ goto out;
1036+ break;
1037+ }
1038+ goto cont;
1039+ }
1040+ w = (w * 10) + c;
1041+ if ((w & 0xffff) > 255) {
1042+ goto out;
1043+ }
1044+cont:
1045+ if (i >= 4)
1046+ goto out;
1047+ s++;
1048+ srclen--;
1049+ }
1050+ ret = 1;
1051+ memcpy(dst, dbuf, sizeof(dbuf));
1052+out:
1053+ if (end)
1054+ *end = s;
1055+ return ret;
1056+}
1057+
1058+static int in6_pton(const char *src, int srclen, u8 *dst, int delim,
1059+ const char **end)
1060+{
1061+ const char *s, *tok = NULL;
1062+ u8 *d, *dc = NULL;
1063+ u8 dbuf[16];
1064+ int ret = 0;
1065+ int i;
1066+ int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
1067+ int w = 0;
1068+
1069+ memset(dbuf, 0, sizeof(dbuf));
1070+
1071+ s = src;
1072+ d = dbuf;
1073+ if (srclen < 0)
1074+ srclen = strlen(src);
1075+
1076+ while (1) {
1077+ int c;
1078+
1079+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
1080+ if (!(c & state))
1081+ goto out;
1082+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
1083+ /* process one 16-bit word */
1084+ if (!(state & IN6PTON_NULL)) {
1085+ *d++ = (w >> 8) & 0xff;
1086+ *d++ = w & 0xff;
1087+ }
1088+ w = 0;
1089+ if (c & IN6PTON_DELIM) {
1090+ /* We've processed last word */
1091+ break;
1092+ }
1093+ /*
1094+ * COLON_1 => XDIGIT
1095+ * COLON_2 => XDIGIT|DELIM
1096+ * COLON_1_2 => COLON_2
1097+ */
1098+ switch (state & IN6PTON_COLON_MASK) {
1099+ case IN6PTON_COLON_2:
1100+ dc = d;
1101+ state = IN6PTON_XDIGIT | IN6PTON_DELIM;
1102+ if (dc - dbuf >= sizeof(dbuf))
1103+ state |= IN6PTON_NULL;
1104+ break;
1105+ case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
1106+ state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
1107+ break;
1108+ case IN6PTON_COLON_1:
1109+ state = IN6PTON_XDIGIT;
1110+ break;
1111+ case IN6PTON_COLON_1_2:
1112+ state = IN6PTON_COLON_2;
1113+ break;
1114+ default:
1115+ state = 0;
1116+ }
1117+ tok = s + 1;
1118+ goto cont;
1119+ }
1120+
1121+ if (c & IN6PTON_DOT) {
1122+ ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok),
1123+ d, delim, &s);
1124+ if (ret > 0) {
1125+ d += 4;
1126+ break;
1127+ }
1128+ goto out;
1129+ }
1130+
1131+ w = (w << 4) | (0xff & c);
1132+ state = IN6PTON_COLON_1 | IN6PTON_DELIM;
1133+ if (!(w & 0xf000)) {
1134+ state |= IN6PTON_XDIGIT;
1135+ }
1136+ if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
1137+ state |= IN6PTON_COLON_1_2;
1138+ state &= ~IN6PTON_DELIM;
1139+ }
1140+ if (d + 2 >= dbuf + sizeof(dbuf)) {
1141+ state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
1142+ }
1143+cont:
1144+ if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
1145+ d + 4 == dbuf + sizeof(dbuf)) {
1146+ state |= IN6PTON_DOT;
1147+ }
1148+ if (d >= dbuf + sizeof(dbuf)) {
1149+ state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
1150+ }
1151+ s++;
1152+ srclen--;
1153+ }
1154+
1155+ i = 15; d--;
1156+
1157+ if (dc) {
1158+ while(d >= dc)
1159+ dst[i--] = *d--;
1160+ while(i >= dc - dbuf)
1161+ dst[i--] = 0;
1162+ while(i >= 0)
1163+ dst[i--] = *d--;
1164+ } else
1165+ memcpy(dst, dbuf, sizeof(dbuf));
1166+
1167+ ret = 1;
1168+out:
1169+ if (end)
1170+ *end = s;
1171+ return ret;
1172+}
1173+
9151174 /**
9161175 * ccs_parse_ip - Parse a ccs_ip_address_entry.
9171176 *
@@ -922,40 +1181,27 @@ int ccs_parse_number(const char *number, struct ccs_number_entry *entry)
9221181 */
9231182 int ccs_parse_ip(const char *address, struct ccs_ip_address_entry *entry)
9241183 {
925- unsigned int min[8];
926- unsigned int max[8];
927- int i;
928- int j;
929- memset(entry, 0, sizeof(*entry));
930- i = sscanf(address, "%u.%u.%u.%u-%u.%u.%u.%u",
931- &min[0], &min[1], &min[2], &min[3],
932- &max[0], &max[1], &max[2], &max[3]);
933- if (i == 4)
934- for (j = 0; j < 4; j++)
935- max[j] = min[j];
936- if (i == 4 || i == 8) {
937- for (j = 0; j < 4; j++) {
938- entry->min[j] = (u8) min[j];
939- entry->max[j] = (u8) max[j];
940- }
1184+ u8 * const min = entry->min;
1185+ u8 * const max = entry->max;
1186+ const char *end;
1187+ memset(entry, 0, sizeof(entry));
1188+ if (!strchr(address, ':') &&
1189+ in4_pton(address, -1, min, '-', &end) > 0) {
1190+ entry->is_ipv6 = false;
1191+ if (!*end)
1192+ memmove(max, min, 4);
1193+ else if (*end++ != '-' ||
1194+ in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
1195+ return -EINVAL;
9411196 return 0;
9421197 }
943- i = sscanf(address, "%X:%X:%X:%X:%X:%X:%X:%X-%X:%X:%X:%X:%X:%X:%X:%X",
944- &min[0], &min[1], &min[2], &min[3],
945- &min[4], &min[5], &min[6], &min[7],
946- &max[0], &max[1], &max[2], &max[3],
947- &max[4], &max[5], &max[6], &max[7]);
948- if (i == 8)
949- for (j = 0; j < 8; j++)
950- max[j] = min[j];
951- if (i == 8 || i == 16) {
952- for (j = 0; j < 8; j++) {
953- entry->min[j * 2] = (u8) (min[j] >> 8);
954- entry->min[j * 2 + 1] = (u8) min[j];
955- entry->max[j * 2] = (u8) (max[j] >> 8);
956- entry->max[j * 2 + 1] = (u8) max[j];
957- }
1198+ if (in6_pton(address, -1, min, '-', &end) > 0) {
9581199 entry->is_ipv6 = true;
1200+ if (!*end)
1201+ memmove(max, min, 16);
1202+ else if (*end++ != '-' ||
1203+ in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
1204+ return -EINVAL;
9591205 return 0;
9601206 }
9611207 return -EINVAL;
@@ -1024,34 +1270,25 @@ int ccs_find_domain(const struct ccs_domain_policy *dp,
10241270 * @is_dd: True if the domain is marked as deleted, false otherwise.
10251271 *
10261272 * Returns index number (>= 0) in the @dp array if created or already exists,
1027- * EOF otherwise.
1273+ * abort otherwise.
10281274 */
10291275 int ccs_assign_domain(struct ccs_domain_policy *dp, const char *domainname,
10301276 const _Bool is_dis, const _Bool is_dd)
10311277 {
1032- const struct ccs_path_info *saved_domainname;
10331278 int index = ccs_find_domain(dp, domainname, is_dis, is_dd);
10341279 if (index >= 0)
1035- goto found;
1280+ return index;
10361281 if (!is_dis && !ccs_correct_domain(domainname)) {
1037- fprintf(stderr, "Invalid domainname '%s'\n",
1038- domainname);
1039- return EOF;
1040- }
1041- dp->list = realloc(dp->list, (dp->list_len + 1) *
1042- sizeof(struct ccs_domain_info));
1043- if (!dp->list)
1044- ccs_out_of_memory();
1045- memset(&dp->list[dp->list_len], 0,
1046- sizeof(struct ccs_domain_info));
1047- saved_domainname = ccs_savename(domainname);
1048- if (!saved_domainname)
1282+ fprintf(stderr, "Invalid domainname '%s'\n", domainname);
10491283 ccs_out_of_memory();
1050- dp->list[dp->list_len].domainname = saved_domainname;
1051- dp->list[dp->list_len].is_dis = is_dis;
1052- dp->list[dp->list_len].is_dd = is_dd;
1284+ }
10531285 index = dp->list_len++;
1054-found:
1286+ dp->list = ccs_realloc(dp->list, dp->list_len *
1287+ sizeof(struct ccs_domain_info));
1288+ memset(&dp->list[index], 0, sizeof(struct ccs_domain_info));
1289+ dp->list[index].domainname = ccs_savename(domainname);
1290+ dp->list[index].is_dis = is_dis;
1291+ dp->list[index].is_dd = is_dd;
10551292 return index;
10561293 }
10571294
@@ -1190,6 +1427,44 @@ static int ccs_task_entry_compare(const void *a, const void *b)
11901427 }
11911428
11921429 /**
1430+ * ccs_add_process_entry - Add entry for running processes.
1431+ *
1432+ * @line: A line containing PID and profile and domainname.
1433+ * @ppid: Parent PID.
1434+ * @name: Comm name (allocated by strdup()).
1435+ *
1436+ * Returns nothing.
1437+ *
1438+ * @name is free()d on failure.
1439+ */
1440+static void ccs_add_process_entry(const char *line, const pid_t ppid,
1441+ char *name)
1442+{
1443+ int index;
1444+ unsigned int pid = 0;
1445+ int profile = -1;
1446+ char *domain;
1447+ if (!line || sscanf(line, "%u %u", &pid, &profile) != 2) {
1448+ free(name);
1449+ return;
1450+ }
1451+ domain = strchr(line, '<');
1452+ if (domain)
1453+ domain = ccs_strdup(domain);
1454+ else
1455+ domain = ccs_strdup("<UNKNOWN>");
1456+ index = ccs_task_list_len++;
1457+ ccs_task_list = ccs_realloc(ccs_task_list, ccs_task_list_len *
1458+ sizeof(struct ccs_task_entry));
1459+ memset(&ccs_task_list[index], 0, sizeof(ccs_task_list[0]));
1460+ ccs_task_list[index].pid = pid;
1461+ ccs_task_list[index].ppid = ppid;
1462+ ccs_task_list[index].profile = profile;
1463+ ccs_task_list[index].name = name;
1464+ ccs_task_list[index].domain = domain;
1465+}
1466+
1467+/**
11931468 * ccs_read_process_list - Read all process's information.
11941469 *
11951470 * @show_all: Ture if kernel threads should be included, false otherwise.
@@ -1216,45 +1491,17 @@ void ccs_read_process_list(_Bool show_all)
12161491 char *line = ccs_freadline(fp);
12171492 unsigned int pid = 0;
12181493 unsigned int ppid = 0;
1219- int profile = -1;
12201494 char *name;
1221- char *domain;
12221495 if (!line)
12231496 break;
12241497 sscanf(line, "PID=%u PPID=%u", &pid, &ppid);
12251498 name = strstr(line, "NAME=");
12261499 if (name)
1227- name = strdup(name + 5);
1228- if (!name)
1229- name = strdup("<UNKNOWN>");
1230- if (!name)
1231- ccs_out_of_memory();
1500+ name = ccs_strdup(name + 5);
1501+ else
1502+ name = ccs_strdup("<UNKNOWN>");
12321503 line = ccs_freadline(fp);
1233- if (!line ||
1234- sscanf(line, "%u %u", &pid, &profile) != 2) {
1235- free(name);
1236- break;
1237- }
1238- domain = strchr(line, '<');
1239- if (domain)
1240- domain = strdup(domain);
1241- if (!domain)
1242- domain = strdup("<UNKNOWN>");
1243- if (!domain)
1244- ccs_out_of_memory();
1245- ccs_task_list = realloc(ccs_task_list,
1246- (ccs_task_list_len + 1) *
1247- sizeof(struct ccs_task_entry));
1248- if (!ccs_task_list)
1249- ccs_out_of_memory();
1250- memset(&ccs_task_list[ccs_task_list_len], 0,
1251- sizeof(ccs_task_list[0]));
1252- ccs_task_list[ccs_task_list_len].pid = pid;
1253- ccs_task_list[ccs_task_list_len].ppid = ppid;
1254- ccs_task_list[ccs_task_list_len].profile = profile;
1255- ccs_task_list[ccs_task_list_len].name = name;
1256- ccs_task_list[ccs_task_list_len].domain = domain;
1257- ccs_task_list_len++;
1504+ ccs_add_process_entry(line, ppid, name);
12581505 }
12591506 ccs_put();
12601507 fclose(fp);
@@ -1270,13 +1517,9 @@ void ccs_read_process_list(_Bool show_all)
12701517 closedir(dir);
12711518 return;
12721519 }
1273- line = malloc(line_len);
1274- if (!line)
1275- ccs_out_of_memory();
1520+ line = ccs_malloc(line_len);
12761521 while (1) {
12771522 char *name;
1278- char *domain;
1279- int profile = -1;
12801523 int ret_ignored;
12811524 unsigned int pid = 0;
12821525 char buffer[128];
@@ -1296,38 +1539,12 @@ void ccs_read_process_list(_Bool show_all)
12961539 }
12971540 name = ccs_get_name(pid);
12981541 if (!name)
1299- name = strdup("<UNKNOWN>");
1300- if (!name)
1301- ccs_out_of_memory();
1542+ name = ccs_strdup("<UNKNOWN>");
13021543 snprintf(buffer, sizeof(buffer) - 1, "%u\n", pid);
13031544 ret_ignored = write(status_fd, buffer, strlen(buffer));
13041545 memset(line, 0, line_len);
13051546 ret_ignored = read(status_fd, line, line_len - 1);
1306- if (sscanf(line, "%u %u", &pid, &profile) != 2) {
1307- free(name);
1308- continue;
1309- }
1310- domain = strchr(line, '<');
1311- if (domain)
1312- domain = strdup(domain);
1313- if (!domain)
1314- domain = strdup("<UNKNOWN>");
1315- if (!domain)
1316- ccs_out_of_memory();
1317- ccs_task_list = realloc(ccs_task_list,
1318- (ccs_task_list_len + 1) *
1319- sizeof(struct ccs_task_entry));
1320- if (!ccs_task_list)
1321- ccs_out_of_memory();
1322- memset(&ccs_task_list[ccs_task_list_len], 0,
1323- sizeof(ccs_task_list[0]));
1324- ccs_task_list[ccs_task_list_len].pid = pid;
1325- ccs_task_list[ccs_task_list_len].ppid =
1326- ccs_get_ppid(pid);
1327- ccs_task_list[ccs_task_list_len].profile = profile;
1328- ccs_task_list[ccs_task_list_len].name = name;
1329- ccs_task_list[ccs_task_list_len].domain = domain;
1330- ccs_task_list_len++;
1547+ ccs_add_process_entry(line, ccs_get_ppid(pid), name);
13311548 }
13321549 free(line);
13331550 closedir(dir);
@@ -1469,47 +1686,6 @@ _Bool ccs_move_proc_to_file(const char *src, const char *dest)
14691686 }
14701687
14711688 /**
1472- * ccs_identical_file - Check whether two files are identical or not.
1473- *
1474- * @file1: Pointer to "const char ".
1475- * @file2: Pointer to "const char".
1476- *
1477- * Returns true if both @file1 and @file2 exist and are readable and are
1478- * identical, false otherwise.
1479- *
1480- * Note that this function is no longer used by anybody since 1.8.0p1.
1481- */
1482-_Bool ccs_identical_file(const char *file1, const char *file2)
1483-{
1484- char buffer1[4096];
1485- char buffer2[4096];
1486- struct stat sb1;
1487- struct stat sb2;
1488- const int fd1 = open(file1, O_RDONLY);
1489- const int fd2 = open(file2, O_RDONLY);
1490- int len1;
1491- int len2;
1492- /* Don't compare if file1 is a symlink to file2. */
1493- if (fstat(fd1, &sb1) || fstat(fd2, &sb2) || sb1.st_ino == sb2.st_ino)
1494- goto out;
1495- do {
1496- len1 = read(fd1, buffer1, sizeof(buffer1));
1497- len2 = read(fd2, buffer2, sizeof(buffer2));
1498- if (len1 < 0 || len1 != len2)
1499- goto out;
1500- if (memcmp(buffer1, buffer2, len1))
1501- goto out;
1502- } while (len1);
1503- close(fd1);
1504- close(fd2);
1505- return true;
1506-out:
1507- close(fd1);
1508- close(fd2);
1509- return false;
1510-}
1511-
1512-/**
15131689 * ccs_clear_domain_policy - Clean up domain policy.
15141690 *
15151691 * @dp: Pointer to "struct ccs_domain_policy".
@@ -1719,23 +1895,18 @@ int ccs_add_string_entry(struct ccs_domain_policy *dp, const char *entry,
17191895 if (!entry || !*entry)
17201896 return -EINVAL;
17211897 cp = ccs_savename(entry);
1722- if (!cp)
1723- ccs_out_of_memory();
17241898
17251899 acl_ptr = dp->list[index].string_ptr;
17261900 acl_count = dp->list[index].string_count;
17271901
17281902 /* Check for the same entry. */
1729- for (i = 0; i < acl_count; i++) {
1903+ for (i = 0; i < acl_count; i++)
17301904 /* Faster comparison, for they are ccs_savename'd. */
17311905 if (cp == acl_ptr[i])
17321906 return 0;
1733- }
17341907
1735- acl_ptr = realloc(acl_ptr, (acl_count + 1)
1736- * sizeof(const struct ccs_path_info *));
1737- if (!acl_ptr)
1738- ccs_out_of_memory();
1908+ acl_ptr = ccs_realloc(acl_ptr, (acl_count + 1) *
1909+ sizeof(const struct ccs_path_info *));
17391910 acl_ptr[acl_count++] = cp;
17401911 dp->list[index].string_ptr = acl_ptr;
17411912 dp->list[index].string_count = acl_count;
@@ -1766,8 +1937,6 @@ int ccs_del_string_entry(struct ccs_domain_policy *dp, const char *entry,
17661937 if (!entry || !*entry)
17671938 return -EINVAL;
17681939 cp = ccs_savename(entry);
1769- if (!cp)
1770- ccs_out_of_memory();
17711940
17721941 acl_ptr = dp->list[index].string_ptr;
17731942 acl_count = dp->list[index].string_count;
@@ -1911,12 +2080,8 @@ char *ccs_shprintf(const char *fmt, ...)
19112080 if (len < 0)
19122081 ccs_out_of_memory();
19132082 if (len >= max_policy_len) {
1914- char *cp;
19152083 max_policy_len = len + 1;
1916- cp = realloc(policy, max_policy_len);
1917- if (!cp)
1918- ccs_out_of_memory();
1919- policy = cp;
2084+ policy = ccs_realloc(policy, max_policy_len);
19202085 } else
19212086 return policy;
19222087 }
@@ -1943,12 +2108,8 @@ char *ccs_freadline(FILE *fp)
19432108 if (ccs_network_mode && !c)
19442109 return NULL;
19452110 if (pos == max_policy_len) {
1946- char *cp;
19472111 max_policy_len += 4096;
1948- cp = realloc(policy, max_policy_len);
1949- if (!cp)
1950- ccs_out_of_memory();
1951- policy = cp;
2112+ policy = ccs_realloc(policy, max_policy_len);
19522113 }
19532114 policy[pos++] = (char) c;
19542115 if (c == '\n') {
@@ -1992,14 +2153,33 @@ char *ccs_freadline_unpack(FILE *fp)
19922153 char *line = ccs_freadline(fp);
19932154 if (!line)
19942155 return NULL;
1995- if (sscanf(line, "acl_group %u", &offset) == 1 && offset < 256)
1996- pos = strchr(line + 11, ' ');
2156+ /*
2157+ * Skip
2158+ * <$namespace>
2159+ * prefix unless this line represents a domainname.
2160+ */
2161+ if (ccs_domain_def(line) && !ccs_correct_domain(line)) {
2162+ pos = strchr(line, ' ');
2163+ if (!pos++)
2164+ pos = line;
2165+ } else
2166+ pos = line;
2167+ /*
2168+ * Skip
2169+ * acl_group $group
2170+ * prefix if this line is a line of exception policy.
2171+ */
2172+ if (sscanf(pos, "acl_group %u", &offset) == 1 && offset < 256)
2173+ pos = strchr(pos + 11, ' ');
19972174 else
19982175 pos = NULL;
19992176 if (pos++)
20002177 offset = pos - line;
20012178 else
20022179 offset = 0;
2180+ /*
2181+ * Only "file " and "network " are subjected to unpacking.
2182+ */
20032183 if (!strncmp(line + offset, "file ", 5)) {
20042184 char *cp = line + offset + 5;
20052185 char *cp2 = strchr(cp + 1, ' ');
@@ -2025,9 +2205,7 @@ char *ccs_freadline_unpack(FILE *fp)
20252205 return line;
20262206 prepare:
20272207 pack_len = len;
2028- cached_line = strdup(line);
2029- if (!cached_line)
2030- ccs_out_of_memory();
2208+ cached_line = ccs_strdup(line);
20312209 }
20322210 unpack:
20332211 {
@@ -2047,9 +2225,7 @@ unpack:
20472225 cached_line = NULL;
20482226 } else {
20492227 /* Current string is "abc d/e/f ghi". */
2050- line = strdup(cached_line);
2051- if (!line)
2052- ccs_out_of_memory();
2228+ line = ccs_strdup(cached_line);
20532229 previous_line = line;
20542230 /* Overwrite "abc d/e/f ghi" with "abc d ghi". */
20552231 memmove(line + pack_start + len, pos + pack_len,
--- a/src/usr_sbin/ccstools.h
+++ b/src/usr_sbin/ccstools.h
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2+ 2011/07/07
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -51,12 +51,39 @@
5151
5252 /***** CONSTANTS DEFINITION START *****/
5353
54-#define CCS_ROOT_NAME "<kernel>"
55-#define CCS_ROOT_NAME_LEN (sizeof(CCS_ROOT_NAME) - 1)
56-
54+#ifdef __GPET
55+_Bool is_ccs(void);
56+#define TOMOYO_PROC_POLICY_DIR "/sys/kernel/security/tomoyo/"
57+
58+#define CCS_PROC_POLICY_DIR \
59+ is_ccs() ? "/proc/ccs/" : "/sys/kernel/security/tomoyo/"
60+#define CCS_PROC_POLICY_DOMAIN_POLICY \
61+ is_ccs() ? "/proc/ccs/domain_policy" : \
62+ "/sys/kernel/security/tomoyo/domain_policy"
63+#define CCS_PROC_POLICY_EXCEPTION_POLICY \
64+ is_ccs() ? "/proc/ccs/exception_policy" : \
65+ "/sys/kernel/security/tomoyo/exception_policy"
66+#define CCS_PROC_POLICY_AUDIT \
67+ is_ccs() ? "/proc/ccs/audit" : \
68+ "/sys/kernel/security/tomoyo/audit"
69+#define CCS_PROC_POLICY_MANAGER \
70+ is_ccs() ? "/proc/ccs/manager" : \
71+ "/sys/kernel/security/tomoyo/manager"
72+#define CCS_PROC_POLICY_STAT \
73+ is_ccs() ? "/proc/ccs/stat" : \
74+ "/sys/kernel/security/tomoyo/stat"
75+#define CCS_PROC_POLICY_PROCESS_STATUS \
76+ is_ccs() ? "/proc/ccs/.process_status" : \
77+ "/sys/kernel/security/tomoyo/.process_status"
78+#define CCS_PROC_POLICY_PROFILE \
79+ is_ccs() ? "/proc/ccs/profile" : \
80+ "/sys/kernel/security/tomoyo/profile"
81+#define CCS_PROC_POLICY_QUERY \
82+ is_ccs() ? "/proc/ccs/query" : \
83+ "/sys/kernel/security/tomoyo/query"
84+#else
5785 #define CCS_PROC_POLICY_DIR "/proc/ccs/"
5886 #define CCS_PROC_POLICY_DOMAIN_POLICY "/proc/ccs/domain_policy"
59-#define CCS_PROC_POLICY_DOMAIN_STATUS "/proc/ccs/.domain_status"
6087 #define CCS_PROC_POLICY_EXCEPTION_POLICY "/proc/ccs/exception_policy"
6188 #define CCS_PROC_POLICY_AUDIT "/proc/ccs/audit"
6289 #define CCS_PROC_POLICY_MANAGER "/proc/ccs/manager"
@@ -64,6 +91,7 @@
6491 #define CCS_PROC_POLICY_PROCESS_STATUS "/proc/ccs/.process_status"
6592 #define CCS_PROC_POLICY_PROFILE "/proc/ccs/profile"
6693 #define CCS_PROC_POLICY_QUERY "/proc/ccs/query"
94+#endif /* __GPET */
6795
6896 /***** CONSTANTS DEFINITION END *****/
6997
@@ -136,16 +164,17 @@ _Bool ccs_correct_path(const char *filename);
136164 _Bool ccs_correct_word(const char *string);
137165 _Bool ccs_decode(const char *ascii, char *bin);
138166 _Bool ccs_domain_def(const char *domainname);
139-_Bool ccs_identical_file(const char *file1, const char *file2);
140167 _Bool ccs_move_proc_to_file(const char *src, const char *dest);
141168 _Bool ccs_path_matches_pattern(const struct ccs_path_info *pathname0,
142169 const struct ccs_path_info *pattern0);
143-_Bool ccs_pathcmp(const struct ccs_path_info *a, const struct ccs_path_info *b);
170+_Bool ccs_pathcmp(const struct ccs_path_info *a,
171+ const struct ccs_path_info *b);
144172 _Bool ccs_str_starts(char *str, const char *begin);
145173 char *ccs_freadline(FILE *fp);
146174 char *ccs_freadline_unpack(FILE *fp);
147-char *ccs_make_filename(const char *prefix, const time_t time);
148-char *ccs_shprintf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
175+char *ccs_shprintf(const char *fmt, ...)
176+ __attribute__ ((format(printf, 1, 2)));
177+char *ccs_strdup(const char *string);
149178 const char *ccs_domain_name(const struct ccs_domain_policy *dp,
150179 const int index);
151180 const struct ccs_path_info *ccs_savename(const char *name);
@@ -155,8 +184,9 @@ int ccs_assign_domain(struct ccs_domain_policy *dp, const char *domainname,
155184 const _Bool is_dis, const _Bool is_dd);
156185 int ccs_del_string_entry(struct ccs_domain_policy *dp, const char *entry,
157186 const int index);
158-int ccs_find_domain(const struct ccs_domain_policy *dp, const char *domainname0,
159- const _Bool is_dis, const _Bool is_dd);
187+int ccs_find_domain(const struct ccs_domain_policy *dp,
188+ const char *domainname0, const _Bool is_dis,
189+ const _Bool is_dd);
160190 int ccs_find_domain_by_ptr(struct ccs_domain_policy *dp,
161191 const struct ccs_path_info *domainname);
162192 int ccs_open_stream(const char *filename);
@@ -165,6 +195,9 @@ int ccs_parse_number(const char *number, struct ccs_number_entry *entry);
165195 int ccs_string_compare(const void *a, const void *b);
166196 int ccs_write_domain_policy(struct ccs_domain_policy *dp, const int fd);
167197 struct ccs_path_group_entry *ccs_find_path_group(const char *group_name);
198+void *ccs_malloc(const size_t size);
199+void *ccs_realloc(void *ptr, const size_t size);
200+void *ccs_realloc2(void *ptr, const size_t size);
168201 void ccs_clear_domain_policy(struct ccs_domain_policy *dp);
169202 void ccs_delete_domain(struct ccs_domain_policy *dp, const int index);
170203 void ccs_fill_path_info(struct ccs_path_info *ptr);
@@ -173,9 +206,9 @@ void ccs_get(void);
173206 void ccs_handle_domain_policy(struct ccs_domain_policy *dp, FILE *fp,
174207 _Bool is_write);
175208 void ccs_normalize_line(char *buffer);
176-void ccs_out_of_memory(void);
177209 void ccs_put(void);
178-void ccs_read_domain_policy(struct ccs_domain_policy *dp, const char *filename);
210+void ccs_read_domain_policy(struct ccs_domain_policy *dp,
211+ const char *filename);
179212 void ccs_read_process_list(_Bool show_all);
180213
181214 extern _Bool ccs_freadline_raw;
--- a/src/usr_sbin/editpolicy.c
+++ b/src/usr_sbin/editpolicy.c
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2+ 2011/07/11
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -29,14 +29,11 @@
2929 #endif /* __GPET */
3030
3131 /* Domain policy. */
32-struct ccs_domain_policy ccs_dp = { };
32+struct ccs_domain_policy3 ccs_dp = { };
3333
3434 /* Readline history. */
3535 static struct ccs_readline_data ccs_rl = { };
3636
37-/* File descriptor for offline mode. */
38-int ccs_persistent_fd = EOF;
39-
4037 /* Array of "path_group" entries. */
4138 struct ccs_path_group_entry *ccs_path_group_list = NULL;
4239 /* Length of ccs_path_group_list array. */
@@ -44,7 +41,7 @@ int ccs_path_group_list_len = 0;
4441 /* Array of string ACL entries. */
4542 struct ccs_generic_acl *ccs_gacl_list = NULL;
4643 /* Length of ccs_generic_list array. */
47-int ccs_gacl_list_count = 0;
44+static int ccs_gacl_list_count = 0;
4845
4946 /* Policy directory. */
5047 static const char *ccs_policy_dir = NULL;
@@ -66,6 +63,8 @@ static char *ccs_current_domain = NULL;
6663 static unsigned int ccs_current_pid = 0;
6764 /* Currently active screen's index. */
6865 enum ccs_screen_type ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
66+/* Previously active screen's index. */
67+static enum ccs_screen_type ccs_previous_screen = CCS_SCREEN_DOMAIN_LIST;
6968 /*
7069 * Array of "initialize_domain"/"no_initialize_domain"/"keep_domain"/
7170 * "no_keep_domain" entries.
@@ -75,7 +74,7 @@ static struct ccs_transition_control_entry *ccs_transition_control_list = NULL;
7574 static int ccs_transition_control_list_len = 0;
7675 /* Sort profiles by value? */
7776 static _Bool ccs_profile_sort_type = false;
78-/* Number of domain initializer source domains. */
77+/* Number of domain jump source domains. */
7978 static int ccs_unnumbered_domain_count = 0;
8079 /* Width of CUI screen. */
8180 static int ccs_window_width = 0;
@@ -85,7 +84,7 @@ static int ccs_window_height = 0;
8584 struct ccs_screen ccs_screen[CCS_MAXSCREEN] = { };
8685 /* Number of entries available on current screen. */
8786 int ccs_list_item_count = 0;
88-/* Lines available for displaying ACL entries. */
87+/* Lines available for displaying ACL entries. */
8988 static int ccs_body_lines = 0;
9089 /* Columns to shift. */
9190 static int ccs_eat_col = 0;
@@ -99,20 +98,26 @@ static char *ccs_last_error = NULL;
9998 static _Bool ccs_domain_sort_type = false;
10099 /* Start from the first line when showing ACL screen? */
101100 static _Bool ccs_no_restore_cursor = false;
101+static _Bool ccs_force_move_cursor = false;
102+
103+/* Namespace to use. */
104+const struct ccs_path_info *ccs_current_ns = NULL;
102105
103106 /* Domain transition coltrol keywords. */
104107 static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
105- [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
108+ [CCS_TRANSITION_CONTROL_RESET] = "reset_domain ",
109+ [CCS_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ",
110+ [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
106111 [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
107- [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
108- [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
112+ [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
113+ [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
109114 };
110115
111116 static FILE *ccs_editpolicy_open_write(const char *filename);
112117 static _Bool ccs_deleted_domain(const int index);
113118 static _Bool ccs_domain_unreachable(const int index);
114-static _Bool ccs_initializer_source(const int index);
115-static _Bool ccs_initializer_target(const int index);
119+static _Bool ccs_jump_source(const int index);
120+static _Bool ccs_jump_target(const int index);
116121 static _Bool ccs_keeper_domain(const int index);
117122 static _Bool ccs_select_item(const int index);
118123 static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
@@ -120,17 +125,21 @@ static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
120125 static const char *ccs_eat(const char *str);
121126 static const char *ccs_get_last_name(const int index);
122127 static const struct ccs_transition_control_entry *ccs_transition_control
123-(const struct ccs_path_info *domainname, const char *program);
128+(const struct ccs_path_info *ns, const char *domainname, const char *program);
124129 static enum ccs_screen_type ccs_generic_list_loop(void);
125130 static enum ccs_screen_type ccs_select_window(const int current);
126-static int ccs_add_path_group_entry(const char *group_name,
131+static int ccs_add_path_group_entry(const struct ccs_path_info *ns,
132+ const char *group_name,
127133 const char *member_name,
128134 const _Bool is_delete);
129-static int ccs_add_path_group_policy(char *data, const _Bool is_delete);
130-static int ccs_add_transition_control_entry(const char *domainname,
135+static int ccs_add_path_group_policy(const struct ccs_path_info *ns,
136+ char *data, const _Bool is_delete);
137+static int ccs_add_transition_control_entry(const struct ccs_path_info *ns,
138+ const char *domainname,
131139 const char *program, const enum
132140 ccs_transition_type type);
133-static int ccs_add_transition_control_policy(char *data, const enum
141+static int ccs_add_transition_control_policy(const struct ccs_path_info *ns,
142+ char *data, const enum
134143 ccs_transition_type type);
135144 static int ccs_count(const unsigned char *array, const int len);
136145 static int ccs_count2(const struct ccs_generic_acl *array, int len);
@@ -146,8 +155,8 @@ static int ccs_show_stat_line(const int index);
146155 static int ccs_string_acl_compare(const void *a, const void *b);
147156 static void ccs_add_entry(void);
148157 static void ccs_adjust_cursor_pos(const int item_count);
149-static void ccs_assign_dis(const struct ccs_path_info *domainname,
150- const char *program);
158+static void ccs_assign_djs(const struct ccs_path_info *ns,
159+ const char *domainname, const char *program);
151160 static void ccs_copy_file(const char *source, const char *dest);
152161 static void ccs_delete_entry(const int index);
153162 static void ccs_down_arrow_key(void);
@@ -168,6 +177,162 @@ static void ccs_sigalrm_handler(int sig);
168177 static void ccs_up_arrow_key(void);
169178
170179 /**
180+ * ccs_find_domain3 - Find a domain by name and other attributes.
181+ *
182+ * @domainname: Name of domain to find.
183+ * @target: Name of target to find. Maybe NULL.
184+ * @is_dd: True if the domain is marked as deleted, false otherwise.
185+ *
186+ * Returns index number (>= 0) if found, EOF otherwise.
187+ */
188+static int ccs_find_domain3(const char *domainname, const char *target,
189+ const _Bool is_dd)
190+{
191+ int i;
192+ for (i = 0; i < ccs_dp.list_len; i++) {
193+ const struct ccs_domain *ptr = &ccs_dp.list[i];
194+ if (ptr->is_dd == is_dd &&
195+ ((!ptr->target && !target) ||
196+ (ptr->target && target &&
197+ !strcmp(ptr->target->name, target))) &&
198+ !strcmp(ptr->domainname->name, domainname))
199+ return i;
200+ }
201+ return EOF;
202+}
203+
204+/**
205+ * ccs_find_domain3_by_name - Find a domain by name.
206+ *
207+ * @domainname: Name of domain to find.
208+ *
209+ * Returns pointer to "struct ccs_domain" if found, NULL otherwise.
210+ */
211+static struct ccs_domain *ccs_find_domain3_by_name(const char *domainname)
212+{
213+ int i;
214+ for (i = 0; i < ccs_dp.list_len; i++) {
215+ struct ccs_domain *ptr = &ccs_dp.list[i];
216+ if (!ptr->target && !strcmp(ptr->domainname->name, domainname))
217+ return ptr;
218+ }
219+ return NULL;
220+}
221+
222+/**
223+ * ccs_assign_domain3 - Create a domain by name and other attributes.
224+ *
225+ * @domainname: Name of domain to find.
226+ * @target: Name of target domain if the domain acts as domain jump source,
227+ * NULL otherwise.
228+ * @is_dd: True if the domain is marked as deleted, false otherwise.
229+ *
230+ * Returns index number (>= 0) if created or already exists, abort otherwise.
231+ */
232+static int ccs_assign_domain3(const char *domainname, const char *target,
233+ const _Bool is_dd)
234+{
235+ struct ccs_domain *ptr;
236+ int index = ccs_find_domain3(domainname, target, is_dd);
237+ if (index >= 0)
238+ return index;
239+ index = ccs_dp.list_len++;
240+ ccs_dp.list = ccs_realloc(ccs_dp.list, ccs_dp.list_len *
241+ sizeof(struct ccs_domain));
242+ ptr = &ccs_dp.list[index];
243+ memset(ptr, 0, sizeof(*ptr));
244+ ptr->domainname = ccs_savename(domainname);
245+ if (target)
246+ ptr->target = ccs_savename(target);
247+ ptr->is_dd = is_dd;
248+ return index;
249+}
250+
251+/**
252+ * ccs_add_string_entry - Add string entry to a domain.
253+ *
254+ * @entry: String to add.
255+ * @index: Index in the @dp array.
256+ *
257+ * Returns 0 if successfully added or already exists, -EINVAL otherwise.
258+ */
259+static int ccs_add_string_entry3(const char *entry, const int index)
260+{
261+ const struct ccs_path_info **acl_ptr;
262+ int acl_count;
263+ const struct ccs_path_info *cp;
264+ int i;
265+ if (index < 0 || index >= ccs_dp.list_len) {
266+ fprintf(stderr, "ERROR: domain is out of range.\n");
267+ return -EINVAL;
268+ }
269+ if (!entry || !*entry)
270+ return -EINVAL;
271+ cp = ccs_savename(entry);
272+
273+ acl_ptr = ccs_dp.list[index].string_ptr;
274+ acl_count = ccs_dp.list[index].string_count;
275+
276+ /* Check for the same entry. */
277+ for (i = 0; i < acl_count; i++)
278+ /* Faster comparison, for they are ccs_savename'd. */
279+ if (cp == acl_ptr[i])
280+ return 0;
281+
282+ acl_ptr = ccs_realloc(acl_ptr, (acl_count + 1) *
283+ sizeof(const struct ccs_path_info *));
284+ acl_ptr[acl_count++] = cp;
285+ ccs_dp.list[index].string_ptr = acl_ptr;
286+ ccs_dp.list[index].string_count = acl_count;
287+ return 0;
288+}
289+
290+/**
291+ * ccs_clear_domain_policy3 - Clean up domain policy.
292+ *
293+ * Returns nothing.
294+ */
295+static void ccs_clear_domain_policy3(void)
296+{
297+ int index;
298+ for (index = 0; index < ccs_dp.list_len; index++) {
299+ free(ccs_dp.list[index].string_ptr);
300+ ccs_dp.list[index].string_ptr = NULL;
301+ ccs_dp.list[index].string_count = 0;
302+ }
303+ free(ccs_dp.list);
304+ ccs_dp.list = NULL;
305+ ccs_dp.list_len = 0;
306+}
307+
308+/**
309+ * ccs_is_same_namespace - Check namespace.
310+ *
311+ * @domain: Domainname.
312+ * @ns: Namespace.
313+ *
314+ * Returns true if same namespace, false otherwise.
315+ */
316+static _Bool ccs_is_same_namespace(const char *domain,
317+ const struct ccs_path_info *ns)
318+{
319+ return !strncmp(domain, ns->name, ns->total_len) &&
320+ (domain[ns->total_len] == ' ' || !domain[ns->total_len]);
321+}
322+
323+/**
324+ * ccs_is_current_namespace - Check namespace.
325+ *
326+ * @line: Line to check namespace.
327+ *
328+ * Returns true if this line deals current namespace, false otherwise.
329+ */
330+static _Bool ccs_is_current_namespace(const char *line)
331+{
332+ return ccs_is_same_namespace(line, ccs_current_ns);
333+}
334+
335+/**
171336 * ccs_copy_file - Copy local file to local or remote file.
172337 *
173338 * @source: Local file.
@@ -192,19 +357,50 @@ static void ccs_copy_file(const char *source, const char *dest)
192357 }
193358
194359 /**
360+ * ccs_get_ns - Get namespace component from domainname.
361+ *
362+ * @domainname: A domainname.
363+ *
364+ * Returns the namespace component of @domainname.
365+ */
366+static const struct ccs_path_info *ccs_get_ns(const char *domainname)
367+{
368+ const struct ccs_path_info *ns;
369+ char *line = ccs_strdup(domainname);
370+ char *cp;
371+ cp = strchr(line, ' ');
372+ if (cp)
373+ *cp = '\0';
374+ ns = ccs_savename(line);
375+ free(line);
376+ return ns;
377+}
378+
379+/**
380+ * ccs_get_last_word - Get last component of a line.
381+ *
382+ * @line: A line of words.
383+ *
384+ * Returns the last component of the line.
385+ */
386+static const char *ccs_get_last_word(const char *line)
387+{
388+ const char *cp = strrchr(line, ' ');
389+ if (cp)
390+ return cp + 1;
391+ return line;
392+}
393+
394+/**
195395 * ccs_get_last_name - Get last component of a domainname.
196396 *
197397 * @index: Index in the domain policy.
198398 *
199- * Returns the last componet of the domainname.
399+ * Returns the last component of the domainname.
200400 */
201401 static const char *ccs_get_last_name(const int index)
202402 {
203- const char *cp0 = ccs_domain_name(&ccs_dp, index);
204- const char *cp1 = strrchr(cp0, ' ');
205- if (cp1)
206- return cp1 + 1;
207- return cp0;
403+ return ccs_get_last_word(ccs_dp.list[index].domainname->name);
208404 }
209405
210406 /**
@@ -262,7 +458,7 @@ static int ccs_count3(const struct ccs_task_entry *array, int len)
262458 }
263459
264460 /**
265- * ccs_keeper_domain - Check whether the given domain is marked as "keep_domain".
461+ * ccs_keeper_domain - Check whether the given domain is marked as keeper or not.
266462 *
267463 * @index: Index in the domain policy.
268464 *
@@ -275,41 +471,36 @@ static _Bool ccs_keeper_domain(const int index)
275471 }
276472
277473 /**
278- * ccs_initializer_source - Check whether the given domain is marked as "initialize_domain".
474+ * ccs_jump_source - Check whether the given domain is marked as jump source or not.
279475 *
280476 * @index: Index in the domain policy.
281477 *
282- * Returns true if the given domain is marked as "initialize_domain",
478+ * Returns true if the given domain is marked as domain jump source,
283479 * false otherwise.
284480 */
285-static _Bool ccs_initializer_source(const int index)
481+static _Bool ccs_jump_source(const int index)
286482 {
287- return ccs_dp.list[index].is_dis;
483+ return ccs_dp.list[index].target != NULL;
288484 }
289485
290486 /**
291- * ccs_initializer_target - Check whether the given domain is a target of "initialize_domain".
487+ * ccs_jump_target - Check whether the given domain is marked as jump target or not.
292488 *
293489 * @index: Index in the domain policy.
294490 *
295- * Returns true if the given domain is a target of "initialize_domain",
296- * false otherwise.
491+ * Returns true if the given domain is a domain jump target, false otherwise.
297492 */
298-static _Bool ccs_initializer_target(const int index)
493+static _Bool ccs_jump_target(const int index)
299494 {
300- return ccs_dp.list[index].is_dit;
495+ return ccs_dp.list[index].is_djt;
301496 }
302497
303498 /**
304- * ccs_domain_unreachable - Check whether the given domain is unreachable or not.
499+ * ccs_domain_unreachable - Check whether the given domain is marked as unreachable or not.
305500 *
306501 * @index: Index in the domain policy.
307502 *
308503 * Returns true if the given domain is unreachable, false otherwise.
309- *
310- * TODO: Check "task auto_domain_transition" and
311- * "task manual_domain_transition" which allow other domains to reach
312- * the given domain.
313504 */
314505 static _Bool ccs_domain_unreachable(const int index)
315506 {
@@ -368,15 +559,17 @@ static int ccs_string_acl_compare(const void *a, const void *b)
368559 }
369560
370561 /**
371- * ccs_add_transition_control_policy - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries.
562+ * ccs_add_transition_control_policy - Add "reset_domain"/"no_reset_domain"/"initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain" entries.
372563 *
564+ * @ns: Pointer to "const struct ccs_path_info".
373565 * @data: Line to parse.
374566 * @type: One of values in "enum ccs_transition_type".
375567 *
376568 * Returns 0 on success, negative value otherwise.
377569 */
378570 static int ccs_add_transition_control_policy
379-(char *data, const enum ccs_transition_type type)
571+(const struct ccs_path_info *ns, char *data,
572+ const enum ccs_transition_type type)
380573 {
381574 char *domainname = strstr(data, " from ");
382575 if (domainname) {
@@ -387,50 +580,59 @@ static int ccs_add_transition_control_policy
387580 domainname = data;
388581 data = NULL;
389582 }
390- return ccs_add_transition_control_entry(domainname, data, type);
583+ return ccs_add_transition_control_entry(ns, domainname, data, type);
391584 }
392585
393586 /**
394587 * ccs_add_path_group_policy - Add "path_group" entry.
395588 *
589+ * @ns: Pointer to "const struct ccs_path_info".
396590 * @data: Line to parse.
397591 * @is_delete: True if it is delete request, false otherwise.
398592 *
399593 * Returns 0 on success, negative value otherwise.
400594 */
401-static int ccs_add_path_group_policy(char *data, const _Bool is_delete)
595+static int ccs_add_path_group_policy(const struct ccs_path_info *ns,
596+ char *data, const _Bool is_delete)
402597 {
403598 char *cp = strchr(data, ' ');
404599 if (!cp)
405600 return -EINVAL;
406601 *cp++ = '\0';
407- return ccs_add_path_group_entry(data, cp, is_delete);
602+ return ccs_add_path_group_entry(ns, data, cp, is_delete);
408603 }
409604
410605 /**
411- * ccs_assign_dis - Assign domain initializer source domain.
606+ * ccs_assign_djs - Assign domain jump source domain.
412607 *
413- * @domainname: Pointer to "const struct ccs_path_info".
608+ * @ns: Pointer to "const struct ccs_path_info".
609+ * @domainname: Domainname.
414610 * @program: Program name.
415611 */
416-static void ccs_assign_dis(const struct ccs_path_info *domainname,
417- const char *program)
612+static void ccs_assign_djs(const struct ccs_path_info *ns,
613+ const char *domainname, const char *program)
418614 {
419615 const struct ccs_transition_control_entry *d_t =
420- ccs_transition_control(domainname, program);
421- if (d_t && d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE) {
616+ ccs_transition_control(ns, domainname, program);
617+ if (!d_t)
618+ return;
619+ if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE ||
620+ d_t->type == CCS_TRANSITION_CONTROL_RESET) {
422621 char *line;
423- int source;
622+ char *cp;
424623 ccs_get();
425- line = ccs_shprintf("%s %s", domainname->name, program);
624+ if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE)
625+ line = ccs_shprintf("%s %s", domainname, program);
626+ else
627+ line = ccs_shprintf("%s <%s>", domainname, program);
426628 ccs_normalize_line(line);
427- source = ccs_assign_domain(&ccs_dp, line, true, false);
428- if (source == EOF)
429- ccs_out_of_memory();
430- line = ccs_shprintf(CCS_ROOT_NAME " %s", program);
431- ccs_dp.list[source].target_domainname = strdup(line);
432- if (!ccs_dp.list[source].target_domainname)
433- ccs_out_of_memory();
629+ cp = ccs_strdup(line);
630+ if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE)
631+ line = ccs_shprintf("%s %s", ns->name, program);
632+ else
633+ line = ccs_shprintf("<%s>", program);
634+ ccs_assign_domain3(cp, line, false);
635+ free(cp);
434636 ccs_put();
435637 }
436638 }
@@ -445,25 +647,68 @@ static void ccs_assign_dis(const struct ccs_path_info *domainname,
445647 */
446648 static int ccs_domainname_attribute_compare(const void *a, const void *b)
447649 {
448- const struct ccs_domain_info *a0 = a;
449- const struct ccs_domain_info *b0 = b;
450- const int k = strcmp(a0->domainname->name, b0->domainname->name);
451- if ((k > 0) || (!k && !a0->is_dis && b0->is_dis))
452- return 1;
650+ const struct ccs_domain *a0 = a;
651+ const struct ccs_domain *b0 = b;
652+ char *name1;
653+ char *name2;
654+ char *line;
655+ char *cp;
656+ int k;
657+ if (!a0->target && !b0->target)
658+ return strcmp(a0->domainname->name, b0->domainname->name);
659+ name1 = ccs_strdup(a0->domainname->name);
660+ if (a0->target) {
661+ cp = strrchr(name1, ' ');
662+ if (cp)
663+ *cp = '\0';
664+ }
665+ name2 = ccs_strdup(b0->domainname->name);
666+ if (b0->target) {
667+ cp = strrchr(name2, ' ');
668+ if (cp)
669+ *cp = '\0';
670+ }
671+ k = strcmp(name1, name2);
672+ if (k)
673+ goto done;
674+ ccs_get();
675+ if (a0->target)
676+ line = ccs_shprintf("%s %s", name1, a0->target->name);
677+ else
678+ line = ccs_shprintf("%s", name1);
679+ free(name1);
680+ name1 = ccs_strdup(line);
681+ if (b0->target)
682+ line = ccs_shprintf("%s %s", name2, b0->target->name);
683+ else
684+ line = ccs_shprintf("%s", name2);
685+ free(name2);
686+ name2 = ccs_strdup(line);
687+ ccs_put();
688+ k = strcmp(name1, name2);
689+done:
690+ free(name1);
691+ free(name2);
453692 return k;
454693 }
455694
456695 /**
457- * ccs_find_target_domain - Find the initialize_domain target domain.
696+ * ccs_find_target_domain - Find the domain jump target domain.
458697 *
459698 * @index: Index in the domain policy.
460699 *
461- * Returns index in the domain policy if found, EOF otherwise.
700+ * Returns index of the domain if found in a current namespace,
701+ * -2 if found in a different namespace, EOF otherwise.
462702 */
463703 static int ccs_find_target_domain(const int index)
464704 {
465- return ccs_find_domain(&ccs_dp, ccs_dp.list[index].target_domainname,
466- false, false);
705+ const char *cp = ccs_dp.list[index].target->name;
706+ if (!ccs_is_current_namespace(cp)) {
707+ if (ccs_dp.list[index].is_du)
708+ return EOF;
709+ return -2;
710+ }
711+ return ccs_find_domain3(cp, NULL, false);
467712 }
468713
469714 /**
@@ -481,22 +726,22 @@ static int ccs_show_domain_line(const int index)
481726 const char *sp;
482727 const int number = ccs_dp.list[index].number;
483728 int redirect_index;
484- const bool is_dis = ccs_initializer_source(index);
729+ const bool is_djs = ccs_jump_source(index);
485730 const bool is_deleted = ccs_deleted_domain(index);
486- if (number >= 0) {
487- printw("%c%4d:", ccs_dp.list_selected[index] ? '&' : ' ',
488- number);
489- if (ccs_dp.list[index].profile_assigned)
490- printw("%3u", ccs_dp.list[index].profile);
491- else
492- printw("???");
493- printw(" %c%c%c ", ccs_keeper_domain(index) ? '#' : ' ',
494- ccs_initializer_target(index) ? '*' : ' ',
731+ if (number >= 0)
732+ printw("%c%4d:%3u %c%c%c ", ccs_dp.list_selected[index] ? '&' :
733+ ' ', number, ccs_dp.list[index].profile,
734+ ccs_keeper_domain(index) ? '#' : ' ',
735+ ccs_jump_target(index) ? '*' : ' ',
495736 ccs_domain_unreachable(index) ? '!' : ' ');
496- } else
737+ else if (ccs_dp.list[index].is_djt)
738+ printw(" %c*%c ",
739+ ccs_keeper_domain(index) ? '#' : ' ',
740+ ccs_domain_unreachable(index) ? '!' : ' ');
741+ else
497742 printw(" ");
498743 tmp_col += 14;
499- sp = ccs_domain_name(&ccs_dp, index);
744+ sp = ccs_dp.list[index].domainname->name;
500745 while (true) {
501746 const char *cp = strchr(sp, ' ');
502747 if (!cp)
@@ -505,6 +750,11 @@ static int ccs_show_domain_line(const int index)
505750 tmp_col += 4;
506751 sp = cp + 1;
507752 }
753+ if (is_djs) {
754+ printw("%s", ccs_eat("=> "));
755+ tmp_col += 3;
756+ sp = ccs_dp.list[index].target->name;
757+ }
508758 if (is_deleted) {
509759 printw("%s", ccs_eat("( "));
510760 tmp_col += 2;
@@ -516,7 +766,7 @@ static int ccs_show_domain_line(const int index)
516766 tmp_col += 2;
517767 }
518768 transition_control = ccs_dp.list[index].d_t;
519- if (!transition_control || is_dis)
769+ if (!transition_control || is_djs)
520770 goto no_transition_control;
521771 ccs_get();
522772 line = ccs_shprintf(" ( %s%s from %s )",
@@ -530,15 +780,17 @@ static int ccs_show_domain_line(const int index)
530780 ccs_put();
531781 goto done;
532782 no_transition_control:
533- if (!is_dis)
783+ if (!is_djs)
534784 goto done;
535785 ccs_get();
536786 redirect_index = ccs_find_target_domain(index);
537787 if (redirect_index >= 0)
538788 line = ccs_shprintf(" ( -> %d )",
539789 ccs_dp.list[redirect_index].number);
540- else
790+ else if (redirect_index == EOF)
541791 line = ccs_shprintf(" ( -> Not Found )");
792+ else
793+ line = ccs_shprintf(" ( -> Namespace jump )");
542794 printw("%s", ccs_eat(line));
543795 tmp_col += strlen(line);
544796 ccs_put();
@@ -665,6 +917,10 @@ static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
665917 "position.\n");
666918 }
667919 switch (screen) {
920+ case CCS_SCREEN_NS_LIST:
921+ if (!readonly)
922+ printw("A/a Add a new namespace.\n");
923+ break;
668924 case CCS_SCREEN_DOMAIN_LIST:
669925 if (ccs_domain_sort_type) {
670926 printw("S/s Set profile number of selected "
@@ -674,7 +930,8 @@ static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
674930 } else {
675931 if (!readonly) {
676932 printw("A/a Add a new domain.\n");
677- printw("D/d Delete selected domains.\n");
933+ printw("D/d Delete selected domains."
934+ "\n");
678935 printw("S/s Set profile number of "
679936 "selected domains.\n");
680937 }
@@ -751,10 +1008,7 @@ static void ccs_set_error(const char *filename)
7511008 {
7521009 if (filename) {
7531010 const int len = strlen(filename) + 128;
754- ccs_last_error = realloc(ccs_last_error, len);
755- if (!ccs_last_error)
756- ccs_out_of_memory();
757- memset(ccs_last_error, 0, len);
1011+ ccs_last_error = ccs_realloc2(ccs_last_error, len);
7581012 snprintf(ccs_last_error, len - 1, "Can't open %s .", filename);
7591013 } else {
7601014 free(ccs_last_error);
@@ -763,34 +1017,6 @@ static void ccs_set_error(const char *filename)
7631017 }
7641018
7651019 /**
766- * ccs_send_fd - Send file descriptor.
767- *
768- * @data: String data to send with file descriptor.
769- * @fd: Pointer to file desciptor.
770- *
771- * Returns nothing.
772- */
773-static void ccs_send_fd(char *data, int *fd)
774-{
775- struct msghdr msg;
776- struct iovec iov = { data, strlen(data) };
777- char cmsg_buf[CMSG_SPACE(sizeof(int))];
778- struct cmsghdr *cmsg = (struct cmsghdr *) cmsg_buf;
779- memset(&msg, 0, sizeof(msg));
780- msg.msg_iov = &iov;
781- msg.msg_iovlen = 1;
782- msg.msg_control = cmsg_buf;
783- msg.msg_controllen = sizeof(cmsg_buf);
784- cmsg->cmsg_level = SOL_SOCKET;
785- cmsg->cmsg_type = SCM_RIGHTS;
786- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
787- msg.msg_controllen = cmsg->cmsg_len;
788- memmove(CMSG_DATA(cmsg), fd, sizeof(int));
789- sendmsg(ccs_persistent_fd, &msg, 0);
790- close(*fd);
791-}
792-
793-/**
7941020 * ccs_editpolicy_open_write - Wrapper for ccs_open_write().
7951021 *
7961022 * @filename: File to open for writing.
@@ -803,37 +1029,10 @@ static void ccs_send_fd(char *data, int *fd)
8031029 */
8041030 static FILE *ccs_editpolicy_open_write(const char *filename)
8051031 {
806- if (ccs_network_mode) {
807- FILE *fp = ccs_open_write(filename);
808- if (!fp)
809- ccs_set_error(filename);
810- return fp;
811- } else if (ccs_offline_mode) {
812- char request[1024];
813- int fd[2];
814- if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
815- fprintf(stderr, "socketpair()\n");
816- exit(1);
817- }
818- if (shutdown(fd[0], SHUT_RD))
819- goto out;
820- memset(request, 0, sizeof(request));
821- snprintf(request, sizeof(request) - 1, "POST %s", filename);
822- ccs_send_fd(request, &fd[1]);
823- return fdopen(fd[0], "w");
824-out:
825- close(fd[1]);
826- close(fd[0]);
827- exit(1);
828- } else {
829- FILE *fp;
830- if (ccs_readonly_mode)
831- return NULL;
832- fp = ccs_open_write(filename);
833- if (!fp)
834- ccs_set_error(filename);
835- return fp;
836- }
1032+ FILE *fp = ccs_open_write(filename);
1033+ if (!fp)
1034+ ccs_set_error(filename);
1035+ return fp;
8371036 }
8381037
8391038 /**
@@ -848,32 +1047,10 @@ out:
8481047 */
8491048 static FILE *ccs_editpolicy_open_read(const char *filename)
8501049 {
851- if (ccs_network_mode) {
852- return ccs_open_read(filename);
853- } else if (ccs_offline_mode) {
854- char request[1024];
855- int fd[2];
856- FILE *fp;
857- if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
858- fprintf(stderr, "socketpair()\n");
859- exit(1);
860- }
861- if (shutdown(fd[0], SHUT_WR))
862- goto out;
863- fp = fdopen(fd[0], "r");
864- if (!fp)
865- goto out;
866- memset(request, 0, sizeof(request));
867- snprintf(request, sizeof(request) - 1, "GET %s", filename);
868- ccs_send_fd(request, &fd[1]);
869- return fp;
870-out:
871- close(fd[1]);
872- close(fd[0]);
873- exit(1);
874- } else {
875- return fopen(filename, "r");
876- }
1050+ FILE *fp = ccs_open_read(filename);
1051+ if (!fp)
1052+ ccs_set_error(filename);
1053+ return fp;
8771054 }
8781055
8791056 /**
@@ -930,23 +1107,23 @@ static const char *ccs_eat(const char *str)
9301107 /**
9311108 * ccs_transition_control - Find domain transition control.
9321109 *
933- * @domainname: Pointer to "const struct ccs_path_info".
1110+ * @ns: Pointer to "const struct ccs_path_info".
1111+ * @domainname: Domainname.
9341112 * @program: Program name.
9351113 *
9361114 * Returns pointer to "const struct ccs_transition_control_entry" if found one,
9371115 * NULL otherwise.
9381116 */
9391117 static const struct ccs_transition_control_entry *ccs_transition_control
940-(const struct ccs_path_info *domainname, const char *program)
1118+(const struct ccs_path_info *ns, const char *domainname, const char *program)
9411119 {
9421120 int i;
9431121 u8 type;
1122+ struct ccs_path_info domain;
9441123 struct ccs_path_info last_name;
945- last_name.name = strrchr(domainname->name, ' ');
946- if (last_name.name)
947- last_name.name++;
948- else
949- last_name.name = domainname->name;
1124+ domain.name = domainname;
1125+ last_name.name = ccs_get_last_word(domainname);
1126+ ccs_fill_path_info(&domain);
9501127 ccs_fill_path_info(&last_name);
9511128 for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
9521129 next:
@@ -955,20 +1132,23 @@ next:
9551132 = &ccs_transition_control_list[i];
9561133 if (ptr->type != type)
9571134 continue;
958- if (ptr->domainname) {
959- if (!ptr->is_last_name) {
960- if (ccs_pathcmp(ptr->domainname,
961- domainname))
962- continue;
963- } else {
964- if (ccs_pathcmp(ptr->domainname,
965- &last_name))
966- continue;
967- }
968- }
1135+ if (ccs_pathcmp(ptr->ns, ns))
1136+ continue;
1137+ if (ptr->domainname &&
1138+ ccs_pathcmp(ptr->domainname, &domain) &&
1139+ ccs_pathcmp(ptr->domainname, &last_name))
1140+ continue;
9691141 if (ptr->program &&
9701142 strcmp(ptr->program->name, program))
9711143 continue;
1144+ if (type == CCS_TRANSITION_CONTROL_NO_RESET) {
1145+ /*
1146+ * Do not check for reset_domain if
1147+ * no_reset_domain matched.
1148+ */
1149+ type = CCS_TRANSITION_CONTROL_NO_INITIALIZE;
1150+ goto next;
1151+ }
9721152 if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
9731153 /*
9741154 * Do not check for initialize_domain if
@@ -977,7 +1157,8 @@ next:
9771157 type = CCS_TRANSITION_CONTROL_NO_KEEP;
9781158 goto next;
9791159 }
980- if (type == CCS_TRANSITION_CONTROL_INITIALIZE ||
1160+ if (type == CCS_TRANSITION_CONTROL_RESET ||
1161+ type == CCS_TRANSITION_CONTROL_INITIALIZE ||
9811162 type == CCS_TRANSITION_CONTROL_KEEP)
9821163 return ptr;
9831164 else
@@ -1004,20 +1185,10 @@ static int ccs_profile_entry_compare(const void *a, const void *b)
10041185 const int a2 = a0->directive;
10051186 const int b2 = b0->directive;
10061187 if (a2 >= 256 || b2 >= 256) {
1007- int i;
1008- static const char *global[5] = {
1009- "PROFILE_VERSION=",
1010- "PREFERENCE::audit=",
1011- "PREFERENCE::learning=",
1012- "PREFERENCE::permissive=",
1013- "PREFERENCE::enforcing="
1014- };
1015- for (i = 0; i < 5; i++) {
1016- if (!strncmp(a1, global[i], strlen(global[i])))
1017- return -1;
1018- if (!strncmp(b1, global[i], strlen(global[i])))
1019- return 1;
1020- }
1188+ if (a1[0] == 'P')
1189+ return -1;
1190+ if (b1[0] == 'P')
1191+ return 1;
10211192 }
10221193 if (!ccs_profile_sort_type) {
10231194 if (a2 == b2)
@@ -1038,6 +1209,30 @@ static int ccs_profile_entry_compare(const void *a, const void *b)
10381209 }
10391210
10401211 /**
1212+ * ccs_add_generic_entry - Add text lines.
1213+ *
1214+ * @line: Line to add.
1215+ * @directive: One of values in "enum ccs_editpolicy_directives".
1216+ *
1217+ * Returns true if this line deals current namespace, false otherwise.
1218+ */
1219+static void ccs_add_generic_entry(const char *line, const enum
1220+ ccs_editpolicy_directives directive)
1221+{
1222+ int i;
1223+ for (i = 0; i < ccs_gacl_list_count; i++)
1224+ if (ccs_gacl_list[i].directive == directive &&
1225+ !strcmp(line, ccs_gacl_list[i].operand))
1226+ return;
1227+ i = ccs_gacl_list_count++;
1228+ ccs_gacl_list = ccs_realloc(ccs_gacl_list, ccs_gacl_list_count *
1229+ sizeof(struct ccs_generic_acl));
1230+ ccs_gacl_list[i].directive = directive;
1231+ ccs_gacl_list[i].selected = 0;
1232+ ccs_gacl_list[i].operand = ccs_strdup(line);
1233+}
1234+
1235+/**
10411236 * ccs_read_generic_policy - Read policy data other than domain policy.
10421237 *
10431238 * Returns nothing.
@@ -1046,15 +1241,14 @@ static void ccs_read_generic_policy(void)
10461241 {
10471242 FILE *fp = NULL;
10481243 _Bool flag = false;
1244+ const _Bool is_kernel_ns = !strcmp(ccs_current_ns->name, "<kernel>");
10491245 while (ccs_gacl_list_count)
1050- free((void *)
1051- ccs_gacl_list[--ccs_gacl_list_count].
1052- operand);
1246+ free((void *) ccs_gacl_list[--ccs_gacl_list_count].operand);
10531247 if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
10541248 if (ccs_network_mode)
10551249 /* We can read after write. */
10561250 fp = ccs_editpolicy_open_write(ccs_policy_file);
1057- else if (!ccs_offline_mode)
1251+ else
10581252 /* Don't set error message if failed. */
10591253 fp = fopen(ccs_policy_file, "r+");
10601254 if (fp) {
@@ -1068,6 +1262,8 @@ static void ccs_read_generic_policy(void)
10681262 fputc(0, fp);
10691263 fflush(fp);
10701264 }
1265+ } else if (ccs_current_screen == CCS_SCREEN_NS_LIST) {
1266+ ccs_add_generic_entry("<kernel>", CCS_DIRECTIVE_NONE);
10711267 }
10721268 if (!fp)
10731269 fp = ccs_editpolicy_open_read(ccs_policy_file);
@@ -1095,8 +1291,36 @@ static void ccs_read_generic_policy(void)
10951291 if (!line[0])
10961292 continue;
10971293 }
1294+ if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST ||
1295+ ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
1296+ if (*line == '<') {
1297+ cp = strchr(line, ' ');
1298+ if (!cp++ || !ccs_is_current_namespace(line))
1299+ continue;
1300+ memmove(line, cp, strlen(cp) + 1);
1301+ } else if (!is_kernel_ns)
1302+ continue;
1303+ }
10981304 switch (ccs_current_screen) {
10991305 case CCS_SCREEN_EXCEPTION_LIST:
1306+ directive = ccs_find_directive(true, line);
1307+ if (directive == CCS_DIRECTIVE_NONE)
1308+ continue;
1309+ /* Remember groups for ccs_editpolicy_optimize(). */
1310+ if (directive != CCS_DIRECTIVE_PATH_GROUP &&
1311+ directive != CCS_DIRECTIVE_NUMBER_GROUP &&
1312+ directive != CCS_DIRECTIVE_ADDRESS_GROUP)
1313+ break;
1314+ cp = ccs_strdup(line);
1315+ if (directive == CCS_DIRECTIVE_PATH_GROUP)
1316+ ccs_add_path_group_policy(ccs_current_ns, cp,
1317+ false);
1318+ else if (directive == CCS_DIRECTIVE_NUMBER_GROUP)
1319+ ccs_add_number_group_policy(cp, false);
1320+ else
1321+ ccs_add_address_group_policy(cp, false);
1322+ free(cp);
1323+ break;
11001324 case CCS_SCREEN_ACL_LIST:
11011325 directive = ccs_find_directive(true, line);
11021326 if (directive == CCS_DIRECTIVE_NONE)
@@ -1111,24 +1335,21 @@ static void ccs_read_generic_policy(void)
11111335 } else
11121336 directive = (u16) -1;
11131337 break;
1338+ case CCS_SCREEN_NS_LIST:
1339+ if (*line != '<')
1340+ continue;
1341+ cp = strchr(line, ' ');
1342+ if (!cp)
1343+ continue;
1344+ *cp = '\0';
1345+ if (!ccs_domain_def(line))
1346+ continue;
1347+ /* Fall through. */
11141348 default:
11151349 directive = CCS_DIRECTIVE_NONE;
11161350 break;
11171351 }
1118- ccs_gacl_list =
1119- realloc(ccs_gacl_list,
1120- (ccs_gacl_list_count + 1) *
1121- sizeof(struct ccs_generic_acl));
1122- if (!ccs_gacl_list)
1123- ccs_out_of_memory();
1124- cp = strdup(line);
1125- if (!cp)
1126- ccs_out_of_memory();
1127- ccs_gacl_list[ccs_gacl_list_count].directive =
1128- directive;
1129- ccs_gacl_list[ccs_gacl_list_count].selected = 0;
1130- ccs_gacl_list[ccs_gacl_list_count++].operand =
1131- cp;
1352+ ccs_add_generic_entry(line, directive);
11321353 }
11331354 ccs_put();
11341355 ccs_freadline_raw = false;
@@ -1157,65 +1378,54 @@ static void ccs_read_generic_policy(void)
11571378 }
11581379
11591380 /**
1160- * ccs_add_transition_control_entry - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries.
1381+ * ccs_add_transition_control_entry - Add "reset_domain"/"no_reset_domain"/"initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries.
11611382 *
1383+ * @ns: Pointer to "const struct ccs_path_info".
11621384 * @domainname: Domainname.
11631385 * @program: Program name.
1164- * @type: One of values in "enum ccs_transition_type".
1386+ * @type: One of values in "enum ccs_transition_type".
11651387 *
11661388 * Returns 0 on success, -EINVAL otherwise.
11671389 */
11681390 static int ccs_add_transition_control_entry
1169-(const char *domainname, const char *program,
1391+(const struct ccs_path_info *ns, const char *domainname, const char *program,
11701392 const enum ccs_transition_type type)
11711393 {
1172- void *vp;
11731394 struct ccs_transition_control_entry *ptr;
1174- _Bool is_last_name = false;
1175- if (program && strcmp(program, "any")) {
1395+ if (program && strcmp(program, "any"))
11761396 if (!ccs_correct_path(program))
11771397 return -EINVAL;
1178- }
1179- if (domainname && strcmp(domainname, "any")) {
1180- if (!ccs_correct_domain(domainname)) {
1398+ if (domainname && strcmp(domainname, "any"))
1399+ if (!ccs_correct_domain(domainname))
11811400 if (!ccs_correct_path(domainname))
11821401 return -EINVAL;
1183- is_last_name = true;
1184- }
1185- }
1186- vp = realloc(ccs_transition_control_list,
1187- (ccs_transition_control_list_len + 1) *
1188- sizeof(struct ccs_transition_control_entry));
1189- if (!vp)
1190- ccs_out_of_memory();
1191- ccs_transition_control_list = vp;
1402+ ccs_transition_control_list =
1403+ ccs_realloc(ccs_transition_control_list,
1404+ (ccs_transition_control_list_len + 1) *
1405+ sizeof(struct ccs_transition_control_entry));
11921406 ptr = &ccs_transition_control_list[ccs_transition_control_list_len++];
1193- memset(ptr, 0, sizeof(struct ccs_transition_control_entry));
1194- if (program && strcmp(program, "any")) {
1407+ memset(ptr, 0, sizeof(*ptr));
1408+ ptr->ns = ns;
1409+ if (program && strcmp(program, "any"))
11951410 ptr->program = ccs_savename(program);
1196- if (!ptr->program)
1197- ccs_out_of_memory();
1198- }
1199- if (domainname && strcmp(domainname, "any")) {
1411+ if (domainname && strcmp(domainname, "any"))
12001412 ptr->domainname = ccs_savename(domainname);
1201- if (!ptr->domainname)
1202- ccs_out_of_memory();
1203- }
12041413 ptr->type = type;
1205- ptr->is_last_name = is_last_name;
12061414 return 0;
12071415 }
12081416
12091417 /**
12101418 * ccs_add_path_group_entry - Add "path_group" entry.
12111419 *
1420+ * @ns: Pointer to "const struct ccs_path_info".
12121421 * @group_name: Name of address group.
12131422 * @member_name: Address string.
12141423 * @is_delete: True if it is delete request, false otherwise.
12151424 *
12161425 * Returns 0 on success, negative value otherwise.
12171426 */
1218-static int ccs_add_path_group_entry(const char *group_name,
1427+static int ccs_add_path_group_entry(const struct ccs_path_info *ns,
1428+ const char *group_name,
12191429 const char *member_name,
12201430 const _Bool is_delete)
12211431 {
@@ -1228,10 +1438,10 @@ static int ccs_add_path_group_entry(const char *group_name,
12281438 return -EINVAL;
12291439 saved_group_name = ccs_savename(group_name);
12301440 saved_member_name = ccs_savename(member_name);
1231- if (!saved_group_name || !saved_member_name)
1232- return -ENOMEM;
12331441 for (i = 0; i < ccs_path_group_list_len; i++) {
12341442 group = &ccs_path_group_list[i];
1443+ if (group->ns != ns)
1444+ continue;
12351445 if (saved_group_name != group->group_name)
12361446 continue;
12371447 for (j = 0; j < group->member_name_len; j++) {
@@ -1250,20 +1460,18 @@ static int ccs_add_path_group_entry(const char *group_name,
12501460 if (is_delete)
12511461 return -ENOENT;
12521462 if (i == ccs_path_group_list_len) {
1253- ccs_path_group_list = realloc(ccs_path_group_list,
1254- (ccs_path_group_list_len + 1) *
1255- sizeof(struct ccs_path_group_entry));
1256- if (!ccs_path_group_list)
1257- ccs_out_of_memory();
1463+ ccs_path_group_list =
1464+ ccs_realloc(ccs_path_group_list,
1465+ (ccs_path_group_list_len + 1) *
1466+ sizeof(struct ccs_path_group_entry));
12581467 group = &ccs_path_group_list[ccs_path_group_list_len++];
1259- memset(group, 0, sizeof(struct ccs_path_group_entry));
1468+ memset(group, 0, sizeof(*group));
1469+ group->ns = ns;
12601470 group->group_name = saved_group_name;
12611471 }
1262- group->member_name = realloc(group->member_name,
1263- (group->member_name_len + 1)
1264- * sizeof(const struct ccs_path_info *));
1265- if (!group->member_name)
1266- ccs_out_of_memory();
1472+ group->member_name =
1473+ ccs_realloc(group->member_name, (group->member_name_len + 1) *
1474+ sizeof(const struct ccs_path_info *));
12671475 group->member_name[group->member_name_len++] = saved_member_name;
12681476 return 0;
12691477 }
@@ -1288,7 +1496,9 @@ static void ccs_add_condition_domain_transition(char *line, const int index)
12881496 static char domainname[4096];
12891497 int source;
12901498 char *cp = strrchr(line, ' ');
1291- if (!cp || strncmp(cp, " auto_domain_transition=\"", 25))
1499+ if (!cp)
1500+ return;
1501+ if (strncmp(cp, " auto_domain_transition=\"", 25))
12921502 return;
12931503 *cp = '\0';
12941504 cp += 25;
@@ -1296,23 +1506,14 @@ static void ccs_add_condition_domain_transition(char *line, const int index)
12961506 if (!source)
12971507 return;
12981508 cp[source - 1] = '\0';
1299- snprintf(domainname, sizeof(domainname) - 1, "%s %s",
1300- ccs_domain_name(&ccs_dp, index), cp);
1509+ snprintf(domainname, sizeof(domainname) - 1, "%s %s",
1510+ ccs_dp.list[index].domainname->name, cp);
13011511 domainname[sizeof(domainname) - 1] = '\0';
13021512 ccs_normalize_line(domainname);
1303- cp = strdup(domainname);
1304- ccs_jump_list = realloc(ccs_jump_list,
1305- (ccs_jump_list_len + 1) * sizeof(char *));
1306- if (!cp || !ccs_jump_list)
1307- ccs_out_of_memory();
1308- ccs_jump_list[ccs_jump_list_len++] = cp;
1309- source = ccs_assign_domain(&ccs_dp, domainname, true, false);
1310- if (source == EOF)
1311- ccs_out_of_memory();
1312- cp = strdup(domainname);
1313- if (!cp)
1314- ccs_out_of_memory();
1315- ccs_dp.list[source].target_domainname = cp;
1513+ ccs_jump_list = ccs_realloc(ccs_jump_list,
1514+ (ccs_jump_list_len + 1) * sizeof(char *));
1515+ ccs_jump_list[ccs_jump_list_len++] = ccs_strdup(domainname);
1516+ ccs_assign_domain3(domainname, *cp == '<' ? cp : domainname, false);
13161517 }
13171518
13181519 /**
@@ -1326,117 +1527,96 @@ static void ccs_add_condition_domain_transition(char *line, const int index)
13261527 static void ccs_add_acl_domain_transition(char *line, const int index)
13271528 {
13281529 static char domainname[4096];
1329- int source;
1330- char *cp;
1331- for (source = 0; line[source]; source++)
1332- if (line[source] == ' ' && line[source + 1] != '/') {
1333- line[source] = '\0';
1530+ int pos;
1531+ /* Chop off condition part which follows domainname. */
1532+ for (pos = 0; line[pos]; pos++)
1533+ if (line[pos] == ' ' && line[pos + 1] != '/') {
1534+ line[pos] = '\0';
13341535 break;
13351536 }
13361537 if (!ccs_correct_domain(line))
13371538 return;
1338- cp = strdup(line);
1339- ccs_jump_list = realloc(ccs_jump_list,
1340- (ccs_jump_list_len + 1) * sizeof(char *));
1341- if (!cp || !ccs_jump_list)
1342- ccs_out_of_memory();
1343- ccs_jump_list[ccs_jump_list_len++] = cp;
1344- cp = strrchr(line, ' ');
1345- if (cp)
1346- cp++;
1347- else
1348- cp = line;
1349- snprintf(domainname, sizeof(domainname) - 1, "%s %s",
1350- ccs_domain_name(&ccs_dp, index), cp);
1539+ ccs_jump_list = ccs_realloc(ccs_jump_list,
1540+ (ccs_jump_list_len + 1) * sizeof(char *));
1541+ ccs_jump_list[ccs_jump_list_len++] = ccs_strdup(line);
1542+ snprintf(domainname, sizeof(domainname) - 1, "%s %s",
1543+ ccs_dp.list[index].domainname->name, ccs_get_last_word(line));
13511544 domainname[sizeof(domainname) - 1] = '\0';
13521545 ccs_normalize_line(domainname);
1353- source = ccs_assign_domain(&ccs_dp, domainname, true, false);
1354- if (source == EOF)
1355- ccs_out_of_memory();
1356- cp = strdup(line);
1357- if (!cp)
1358- ccs_out_of_memory();
1359- ccs_dp.list[source].target_domainname = cp;
1546+ ccs_assign_domain3(domainname, line, false);
13601547 }
13611548
13621549 /**
13631550 * ccs_parse_domain_line - Parse an ACL entry in domain policy.
13641551 *
1552+ * @ns: Pointer to "const struct ccs_path_info".
13651553 * @line: Line to parse.
13661554 * @index: Current domain's index.
1367- * @parse_flags: True if parse use_profile and use_group lines, false otherwise.
1555+ * @parse_flags: True if parse use_profile and use_group lines, false
1556+ * otherwise.
13681557 *
13691558 * Returns nothing.
13701559 */
1371-static void ccs_parse_domain_line(char *line, const int index,
1372- const bool parse_flags)
1560+static void ccs_parse_domain_line(const struct ccs_path_info *ns, char *line,
1561+ const int index, const bool parse_flags)
13731562 {
13741563 ccs_add_condition_domain_transition(line, index);
13751564 if (ccs_str_starts(line, "task auto_execute_handler ") ||
13761565 ccs_str_starts(line, "task denied_execute_handler ") ||
13771566 ccs_str_starts(line, "file execute ")) {
1567+ /* Chop off condition part which follows pathname. */
13781568 char *cp = strchr(line, ' ');
13791569 if (cp)
13801570 *cp = '\0';
13811571 if (*line == '@' || ccs_correct_path(line))
1382- ccs_add_string_entry(&ccs_dp, line, index);
1383- } else if (ccs_str_starts(line,
1384- "task auto_domain_transition ") ||
1385- ccs_str_starts(line,
1386- "task manual_domain_transition ")) {
1572+ ccs_add_string_entry3(line, index);
1573+ } else if (ccs_str_starts(line, "task auto_domain_transition ") ||
1574+ ccs_str_starts(line, "task manual_domain_transition ")) {
13871575 ccs_add_acl_domain_transition(line, index);
13881576 } else if (parse_flags) {
13891577 unsigned int profile;
1390- if (sscanf(line, "use_profile %u", &profile) == 1) {
1578+ if (sscanf(line, "use_profile %u", &profile) == 1)
13911579 ccs_dp.list[index].profile = (u8) profile;
1392- ccs_dp.list[index].profile_assigned = 1;
1393- } else if (sscanf(line, "use_group %u", &profile) == 1) {
1580+ else if (sscanf(line, "use_group %u", &profile) == 1)
13941581 ccs_dp.list[index].group = (u8) profile;
1395- }
13961582 }
13971583 }
13981584
13991585 /**
14001586 * ccs_parse_exception_line - Parse an ACL entry in exception policy.
14011587 *
1402- * @line: Line to parse.
1403- * @max_index: Number of domains currently defined.
1588+ * @ns: Pointer to "const struct ccs_path_info".
1589+ * @line: Line to parse.
14041590 *
14051591 * Returns nothing.
14061592 */
1407-static void ccs_parse_exception_line(char *line, const int max_index)
1593+static void ccs_parse_exception_line(const struct ccs_path_info *ns,
1594+ char *line)
14081595 {
14091596 unsigned int group;
1410- if (ccs_str_starts(line, "initialize_domain "))
1411- ccs_add_transition_control_policy
1412- (line, CCS_TRANSITION_CONTROL_INITIALIZE);
1413- else if (ccs_str_starts(line, "no_initialize_domain "))
1414- ccs_add_transition_control_policy
1415- (line, CCS_TRANSITION_CONTROL_NO_INITIALIZE);
1416- else if (ccs_str_starts(line, "keep_domain "))
1417- ccs_add_transition_control_policy
1418- (line, CCS_TRANSITION_CONTROL_KEEP);
1419- else if (ccs_str_starts(line, "no_keep_domain "))
1420- ccs_add_transition_control_policy
1421- (line, CCS_TRANSITION_CONTROL_NO_KEEP);
1422- else if (ccs_str_starts(line, "path_group "))
1423- ccs_add_path_group_policy(line, false);
1597+ for (group = 0; group < CCS_MAX_TRANSITION_TYPE; group++) {
1598+ if (!ccs_str_starts(line, ccs_transition_type[group]))
1599+ continue;
1600+ ccs_add_transition_control_policy(ns, line, group);
1601+ return;
1602+ }
1603+ if (ccs_str_starts(line, "path_group "))
1604+ ccs_add_path_group_policy(ns, line, false);
14241605 else if (ccs_str_starts(line, "address_group "))
14251606 ccs_add_address_group_policy(line, false);
14261607 else if (ccs_str_starts(line, "number_group "))
14271608 ccs_add_number_group_policy(line, false);
14281609 else if (sscanf(line, "acl_group %u", &group) == 1 && group < 256) {
14291610 int index;
1430- char *cp = strchr(line + 10, ' ');
1431- if (cp)
1432- line = cp + 1;
1433- for (index = 0; index < max_index; index++) {
1611+ line = strchr(line + 10, ' ');
1612+ if (!line++)
1613+ return;
1614+ for (index = 0; index < ccs_dp.list_len; index++) {
1615+ char *cp;
14341616 if (ccs_dp.list[index].group != group)
14351617 continue;
1436- cp = strdup(line);
1437- if (!cp)
1438- ccs_out_of_memory();
1439- ccs_parse_domain_line(cp, index, false);
1618+ cp = ccs_strdup(line);
1619+ ccs_parse_domain_line(ns, cp, index, false);
14401620 free(cp);
14411621 }
14421622 }
@@ -1447,7 +1627,7 @@ static void ccs_parse_exception_line(char *line, const int max_index)
14471627 *
14481628 * Returns nothing.
14491629 *
1450- * Since CUI policy editor screen shows domain initializer source domains and
1630+ * Since CUI policy editor screen shows domain jump source domains and
14511631 * unreachable domains, we need to read not only the domain policy but also
14521632 * the exception policy for printing the domain transition tree.
14531633 */
@@ -1458,19 +1638,24 @@ static void ccs_read_domain_and_exception_policy(void)
14581638 int j;
14591639 int index;
14601640 int max_index;
1641+ static const struct ccs_path_info *ccs_kernel_ns = NULL;
1642+ const struct ccs_path_info *ns;
1643+
14611644 while (ccs_jump_list_len)
14621645 free(ccs_jump_list[--ccs_jump_list_len]);
1463- ccs_clear_domain_policy(&ccs_dp);
1646+ ccs_clear_domain_policy3();
14641647 ccs_transition_control_list_len = 0;
14651648 ccs_editpolicy_clear_groups();
1466- ccs_assign_domain(&ccs_dp, CCS_ROOT_NAME, false, false);
1649+ if (!ccs_kernel_ns)
1650+ ccs_kernel_ns = ccs_savename("<kernel>");
1651+ ns = ccs_kernel_ns;
14671652
14681653 /* Load all domain transition related entries. */
14691654 fp = NULL;
14701655 if (ccs_network_mode)
14711656 /* We can read after write. */
14721657 fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
1473- else if (!ccs_offline_mode)
1658+ else
14741659 /* Don't set error message if failed. */
14751660 fp = fopen(CCS_PROC_POLICY_DOMAIN_POLICY, "r+");
14761661 if (fp) {
@@ -1488,30 +1673,26 @@ static void ccs_read_domain_and_exception_policy(void)
14881673 char *line = ccs_freadline_unpack(fp);
14891674 if (!line)
14901675 break;
1491- if (ccs_domain_def(line)) {
1492- index = ccs_assign_domain(&ccs_dp, line, false,
1493- false);
1676+ if (*line == '<') {
1677+ ns = ccs_get_ns(line);
1678+ index = ccs_assign_domain3(line, NULL, false);
14941679 continue;
14951680 } else if (index == EOF) {
14961681 continue;
14971682 }
1498- ccs_parse_domain_line(line, index, true);
1683+ ccs_parse_domain_line(ns, line, index, true);
14991684 }
15001685 ccs_put();
15011686 fclose(fp);
1502- } else {
1503- ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY);
15041687 }
15051688
1506- max_index = ccs_dp.list_len;
1507-
15081689 /* Load domain transition related entries and group entries. */
15091690 fp = NULL;
15101691 if (ccs_network_mode)
15111692 /* We can read after write. */
15121693 fp = ccs_editpolicy_open_write
15131694 (CCS_PROC_POLICY_EXCEPTION_POLICY);
1514- else if (!ccs_offline_mode)
1695+ else
15151696 /* Don't set error message if failed. */
15161697 fp = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "r+");
15171698 if (fp) {
@@ -1529,160 +1710,265 @@ static void ccs_read_domain_and_exception_policy(void)
15291710 char *line = ccs_freadline_unpack(fp);
15301711 if (!line)
15311712 break;
1532- ccs_parse_exception_line(line, max_index);
1713+ if (*line == '<') {
1714+ char *cp = strchr(line, ' ');
1715+ if (!cp)
1716+ continue;
1717+ *cp++ = '\0';
1718+ ns = ccs_savename(line);
1719+ memmove(line, cp, strlen(cp) + 1);
1720+ } else
1721+ ns = ccs_kernel_ns;
1722+ ccs_parse_exception_line(ns, line);
15331723 }
15341724 ccs_put();
15351725 fclose(fp);
1536- } else {
1537- ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY);
15381726 }
15391727
15401728 /*
1541- * Find unreachable domains.
1729+ * Domain jump sources by "task manual_domain_transition" keyword or
1730+ * "task auto_domain_transition" keyword or "auto_domain_transition="
1731+ * part of conditional ACL have been created by now because these
1732+ * keywords do not depend on domain transition control directives
1733+ * defined in the exception policy.
15421734 *
1543- * This is calculated based on "initialize_domain" and "keep_domain"
1544- * keywords. However, since "task auto_domain_transition" and "task
1545- * manual_domain_transition" keywords and "auto_domain_transition="
1546- * condition are not subjected to "initialize_domain" and "keep_domain"
1547- * keywords, we need to adjust later.
1735+ * Create domain jump sources for "task auto_execute_handler" keyword
1736+ * or "task denied_execute_handler" keyword or "file execute" keyword
1737+ * now because these keywords depend on domain transition control
1738+ * directives defined in the exception policy. Note that "file execute"
1739+ * allows referring "path_group" directives.
15481740 */
1741+ max_index = ccs_dp.list_len;
1742+ for (index = 0; index < max_index; index++) {
1743+ const char *domainname = ccs_dp.list[index].domainname->name;
1744+ const struct ccs_path_info **string_ptr
1745+ = ccs_dp.list[index].string_ptr;
1746+ const int max_count = ccs_dp.list[index].string_count;
1747+ /* Do not recursively create domain jump source. */
1748+ if (ccs_dp.list[index].target)
1749+ continue;
1750+ ns = ccs_get_ns(domainname);
1751+ for (i = 0; i < max_count; i++) {
1752+ const char *name = string_ptr[i]->name;
1753+ struct ccs_path_group_entry *group;
1754+ if (name[0] != '@') {
1755+ ccs_assign_djs(ns, domainname, name);
1756+ continue;
1757+ }
1758+ group = ccs_find_path_group_ns(ns, name + 1);
1759+ if (!group)
1760+ continue;
1761+ for (j = 0; j < group->member_name_len; j++) {
1762+ name = group->member_name[j]->name;
1763+ ccs_assign_djs(ns, domainname, name);
1764+ }
1765+ }
1766+ }
1767+
1768+ /* Create missing parent domains. */
1769+ max_index = ccs_dp.list_len;
15491770 for (index = 0; index < max_index; index++) {
15501771 char *line;
15511772 ccs_get();
1552- line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index));
1773+ line = ccs_shprintf("%s", ccs_dp.list[index].domainname->name);
15531774 while (true) {
1554- const struct ccs_transition_control_entry *d_t;
1555- struct ccs_path_info parent;
15561775 char *cp = strrchr(line, ' ');
15571776 if (!cp)
15581777 break;
1559- *cp++ = '\0';
1560- parent.name = line;
1561- ccs_fill_path_info(&parent);
1562- d_t = ccs_transition_control(&parent, cp);
1563- if (!d_t)
1564- continue;
1565- /* Initializer under <kernel> is reachable. */
1566- if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE &&
1567- parent.total_len == CCS_ROOT_NAME_LEN)
1568- break;
1569- ccs_dp.list[index].d_t = d_t;
1570- continue;
1778+ *cp = '\0';
1779+ if (ccs_find_domain3(line, NULL, false) == EOF)
1780+ ccs_assign_domain3(line, NULL, true);
15711781 }
15721782 ccs_put();
1573- if (ccs_dp.list[index].d_t)
1574- ccs_dp.list[index].is_du = true;
15751783 }
15761784
1577- /* Find domain initializer target domains. */
1785+ /*
1786+ * All domains and jump sources have been created by now.
1787+ * Let's markup domain jump targets and unreachable domains.
1788+ */
1789+ max_index = ccs_dp.list_len;
1790+
1791+ /*
1792+ * Find domains that might be reachable via
1793+ * "task manual_domain_transition" keyword or
1794+ * "task auto_domain_transition" keyword or
1795+ * "auto_domain_transition=" part of conditional ACL.
1796+ * Such domains are marked with '*'.
1797+ */
1798+ for (i = 0; i < ccs_jump_list_len; i++) {
1799+ struct ccs_domain *ptr =
1800+ ccs_find_domain3_by_name(ccs_jump_list[i]);
1801+ if (ptr)
1802+ ptr->is_djt = true;
1803+ }
1804+
1805+ /*
1806+ * Find domains that might be reachable via "initialize_domain"
1807+ * keyword. Such domains are marked with '*'.
1808+ */
15781809 for (index = 0; index < max_index; index++) {
1579- char *cp = strchr(ccs_domain_name(&ccs_dp, index), ' ');
1580- if (!cp || strchr(cp + 1, ' '))
1810+ const struct ccs_domain *domain = &ccs_dp.list[index];
1811+ const char *domainname = domain->domainname->name;
1812+ char *cp;
1813+ /* Ignore domain jump sources. */
1814+ if (domain->target)
1815+ continue;
1816+ /* Ignore if already marked as domain jump targets. */
1817+ if (domain->is_djt)
1818+ continue;
1819+ /* Ignore if not a namespace's root's child domain. */
1820+ cp = strchr(domainname, ' ');
1821+ if (!cp++ || strchr(cp, ' '))
1822+ continue;
1823+ /* Check "no_initialize_domain $program from any" entry. */
1824+ for (i = 0; i < ccs_transition_control_list_len; i++) {
1825+ struct ccs_transition_control_entry *ptr
1826+ = &ccs_transition_control_list[i];
1827+ if (ptr->type != CCS_TRANSITION_CONTROL_NO_INITIALIZE)
1828+ continue;
1829+ if (!ccs_is_same_namespace(domainname, ptr->ns))
1830+ continue;
1831+ if (ptr->domainname)
1832+ continue;
1833+ if (ptr->program && strcmp(ptr->program->name, cp))
1834+ continue;
1835+ break;
1836+ }
1837+ if (i < ccs_transition_control_list_len)
15811838 continue;
1839+ /*
1840+ * Check "initialize_domain $program from $domainname" entry.
1841+ */
15821842 for (i = 0; i < ccs_transition_control_list_len; i++) {
15831843 struct ccs_transition_control_entry *ptr
15841844 = &ccs_transition_control_list[i];
15851845 if (ptr->type != CCS_TRANSITION_CONTROL_INITIALIZE)
15861846 continue;
1587- if (ptr->program && strcmp(ptr->program->name, cp + 1))
1847+ if (!ccs_is_same_namespace(domainname, ptr->ns))
15881848 continue;
1589- ccs_dp.list[index].is_dit = true;
1849+ if (ptr->program && strcmp(ptr->program->name, cp))
1850+ continue;
1851+ break;
15901852 }
1853+ if (i < ccs_transition_control_list_len)
1854+ ccs_dp.list[index].is_djt = true;
15911855 }
15921856
1593- /* Find domain keeper domains. */
1857+ /*
1858+ * Find domains that might suppress domain transition via "keep_domain"
1859+ * keyword. Such domains are marked with '#'.
1860+ */
15941861 for (index = 0; index < max_index; index++) {
1862+ const struct ccs_domain *domain = &ccs_dp.list[index];
1863+ const struct ccs_path_info *name = domain->domainname;
1864+ const char *last_name = ccs_get_last_word(name->name);
1865+ /* Ignore domain jump sources. */
1866+ if (domain->target)
1867+ continue;
1868+ /* Check "no_keep_domain any from $domainname" entry. */
15951869 for (i = 0; i < ccs_transition_control_list_len; i++) {
15961870 struct ccs_transition_control_entry *ptr
15971871 = &ccs_transition_control_list[i];
1598- char *cp;
1599- if (ptr->type != CCS_TRANSITION_CONTROL_KEEP)
1872+ if (ptr->type != CCS_TRANSITION_CONTROL_NO_KEEP)
16001873 continue;
1601- if (!ptr->is_last_name) {
1602- if (ptr->domainname &&
1603- ccs_pathcmp(ptr->domainname,
1604- ccs_dp.list[index].domainname))
1605- continue;
1606- ccs_dp.list[index].is_dk = true;
1874+ if (!ccs_is_same_namespace(name->name, ptr->ns))
16071875 continue;
1608- }
1609- cp = strrchr(ccs_dp.list[index].domainname->name,
1610- ' ');
1611- if (!cp || (ptr->domainname->name &&
1612- strcmp(ptr->domainname->name, cp + 1)))
1876+ if (ptr->program)
16131877 continue;
1614- ccs_dp.list[index].is_dk = true;
1878+ if (!ptr->domainname ||
1879+ !ccs_pathcmp(ptr->domainname, name) ||
1880+ !strcmp(ptr->domainname->name, last_name))
1881+ break;
16151882 }
1616- }
1617-
1618- /* Create domain initializer source domains. */
1619- for (index = 0; index < max_index; index++) {
1620- const struct ccs_path_info *domainname
1621- = ccs_dp.list[index].domainname;
1622- const struct ccs_path_info **string_ptr
1623- = ccs_dp.list[index].string_ptr;
1624- const int max_count = ccs_dp.list[index].string_count;
1625- /*
1626- * Don't create source domain under <kernel> because
1627- * they will become target domains.
1628- */
1629- if (domainname->total_len == CCS_ROOT_NAME_LEN)
1883+ if (i < ccs_transition_control_list_len)
16301884 continue;
1631- for (i = 0; i < max_count; i++) {
1632- const struct ccs_path_info *cp = string_ptr[i];
1633- struct ccs_path_group_entry *group;
1634- if (cp->name[0] != '@') {
1635- ccs_assign_dis(domainname, cp->name);
1885+ /* Check "keep_domain $program from $domainname" entry. */
1886+ for (i = 0; i < ccs_transition_control_list_len; i++) {
1887+ struct ccs_transition_control_entry *ptr
1888+ = &ccs_transition_control_list[i];
1889+ if (ptr->type != CCS_TRANSITION_CONTROL_KEEP)
16361890 continue;
1637- }
1638- group = ccs_find_path_group(cp->name + 1);
1639- if (!group)
1891+ if (!ccs_is_same_namespace(name->name, ptr->ns))
16401892 continue;
1641- for (j = 0; j < group->member_name_len; j++) {
1642- cp = group->member_name[j];
1643- ccs_assign_dis(domainname, cp->name);
1644- }
1893+ if (!ptr->domainname ||
1894+ !ccs_pathcmp(ptr->domainname, name) ||
1895+ !strcmp(ptr->domainname->name, last_name))
1896+ break;
16451897 }
1898+ if (i < ccs_transition_control_list_len)
1899+ ccs_dp.list[index].is_dk = true;
16461900 }
16471901
16481902 /*
1649- * Create domain jump target domains.
1650- * This may reset unreachable domains.
1903+ * Find unreachable domains. Such domains are marked with '!'.
1904+ * Unreachable domains are caused by one of "initialize_domain" keyword
1905+ * or "keep_domain" keyword or "reset_domain" keyword.
16511906 */
1652- for (i = 0; i < ccs_jump_list_len; i++) {
1653- const int index = ccs_find_domain(&ccs_dp, ccs_jump_list[i],
1654- false, false);
1655- if (index == EOF)
1656- continue;
1657- ccs_dp.list[index].is_dit = true;
1658- ccs_dp.list[index].d_t = NULL;
1659- ccs_dp.list[index].is_du = false;
1660- }
1661-
1662- /* Create missing parent domains. */
16631907 for (index = 0; index < max_index; index++) {
16641908 char *line;
1909+ struct ccs_domain * const domain = &ccs_dp.list[index];
1910+ /*
1911+ * Mark domain jump source as unreachable if domain jump target
1912+ * does not exist. Note that such domains are not marked with
1913+ * '!'.
1914+ */
1915+ if (domain->target) {
1916+ if (ccs_find_domain3(domain->target->name, NULL,
1917+ false) == EOF)
1918+ domain->is_du = true;
1919+ continue;
1920+ }
1921+ /* Ignore if domain jump targets. */
1922+ if (domain->is_djt)
1923+ continue;
1924+ /* Ignore if deleted domain. */
1925+ if (domain->is_dd)
1926+ continue;
1927+ ns = ccs_get_ns(domain->domainname->name);
16651928 ccs_get();
1666- line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index));
1929+ line = ccs_shprintf("%s", domain->domainname->name);
16671930 while (true) {
1668- char *cp = strrchr(line, ' ');
1669- if (!cp)
1931+ const struct ccs_domain *ptr =
1932+ ccs_find_domain3_by_name(line);
1933+ const struct ccs_transition_control_entry *d_t;
1934+ char *cp;
1935+ /* Stop traversal if current is domain jump target. */
1936+ if (ptr && ptr->is_djt)
16701937 break;
1671- *cp = '\0';
1672- if (ccs_find_domain(&ccs_dp, line, false, false)
1673- != EOF)
1674- continue;
1675- if (ccs_assign_domain(&ccs_dp, line, false, true)
1676- == EOF)
1677- ccs_out_of_memory();
1938+ cp = strrchr(line, ' ');
1939+ if (cp)
1940+ *cp++ = '\0';
1941+ else
1942+ break;
1943+ d_t = ccs_transition_control(ns, line, cp);
1944+ if (d_t)
1945+ domain->d_t = d_t;
16781946 }
16791947 ccs_put();
1948+ if (domain->d_t)
1949+ domain->is_du = true;
16801950 }
16811951
16821952 /* Sort by domain name. */
1683- qsort(ccs_dp.list, ccs_dp.list_len, sizeof(struct ccs_domain_info),
1953+ qsort(ccs_dp.list, ccs_dp.list_len, sizeof(struct ccs_domain),
16841954 ccs_domainname_attribute_compare);
16851955
1956+ /*
1957+ * Since this screen shows domain transition tree within current
1958+ * namespace, purge domains that are not in current namespace.
1959+ */
1960+ for (index = 0; index < ccs_dp.list_len; index++) {
1961+ int i;
1962+ if (ccs_is_current_namespace(ccs_dp.list[index].
1963+ domainname->name))
1964+ continue;
1965+ free(ccs_dp.list[index].string_ptr);
1966+ ccs_dp.list_len--;
1967+ for (i = index; i < ccs_dp.list_len; i++)
1968+ ccs_dp.list[i] = ccs_dp.list[i + 1];
1969+ index--;
1970+ }
1971+
16861972 /* Assign domain numbers. */
16871973 {
16881974 int number = 0;
@@ -1690,7 +1976,7 @@ static void ccs_read_domain_and_exception_policy(void)
16901976 ccs_unnumbered_domain_count = 0;
16911977 for (index = 0; index < ccs_dp.list_len; index++) {
16921978 if (ccs_deleted_domain(index) ||
1693- ccs_initializer_source(index)) {
1979+ ccs_jump_source(index)) {
16941980 ccs_dp.list[index].number = -1;
16951981 ccs_unnumbered_domain_count++;
16961982 } else {
@@ -1699,10 +1985,10 @@ static void ccs_read_domain_and_exception_policy(void)
16991985 }
17001986 }
17011987
1702- ccs_dp.list_selected = realloc(ccs_dp.list_selected, ccs_dp.list_len);
1703- if (ccs_dp.list_len && !ccs_dp.list_selected)
1704- ccs_out_of_memory();
1705- memset(ccs_dp.list_selected, 0, ccs_dp.list_len);
1988+ if (!ccs_dp.list_len)
1989+ return;
1990+ ccs_dp.list_selected = ccs_realloc2(ccs_dp.list_selected,
1991+ ccs_dp.list_len);
17061992 }
17071993
17081994 /**
@@ -1998,8 +2284,32 @@ static void ccs_show_current(void)
19982284 const int index = ccs_editpolicy_get_current();
19992285 ccs_get();
20002286 ccs_eat_col = ptr->x;
2001- line = ccs_shprintf("%s",
2002- ccs_eat(ccs_domain_name(&ccs_dp, index)));
2287+ if (index >= 0) {
2288+ line = ccs_shprintf
2289+ ("%s", ccs_eat(ccs_dp.list[index].
2290+ domainname->name));
2291+ if (ccs_jump_source(index)) {
2292+ char *cp = strrchr(line, ' ');
2293+ if (cp)
2294+ *cp = '\0';
2295+ }
2296+ } else
2297+ line = ccs_shprintf("%s", ccs_current_ns->name);
2298+ if (ccs_window_width < strlen(line))
2299+ line[ccs_window_width] = '\0';
2300+ move(2, 0);
2301+ clrtoeol();
2302+ ccs_editpolicy_attr_change(A_REVERSE, true); /* add color */
2303+ printw("%s", line);
2304+ ccs_editpolicy_attr_change(A_REVERSE, false); /* add color */
2305+ ccs_put();
2306+ }
2307+ if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST ||
2308+ ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
2309+ char *line;
2310+ ccs_get();
2311+ ccs_eat_col = ptr->x;
2312+ line = ccs_shprintf("%s", ccs_current_ns->name);
20032313 if (ccs_window_width < strlen(line))
20042314 line[ccs_window_width] = '\0';
20052315 move(2, 0);
@@ -2081,7 +2391,7 @@ static _Bool ccs_select_item(const int index)
20812391 if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
20822392 if (!ccs_domain_sort_type) {
20832393 if (ccs_deleted_domain(index) ||
2084- ccs_initializer_source(index))
2394+ ccs_jump_source(index))
20852395 return false;
20862396 ccs_dp.list_selected[index] ^= 1;
20872397 } else {
@@ -2192,15 +2502,17 @@ static void ccs_delete_entry(const int index)
21922502 (CCS_PROC_POLICY_DOMAIN_POLICY);
21932503 if (!fp)
21942504 return;
2195- for (i = 1; i < ccs_dp.list_len; i++) {
2505+ for (i = 0; i < ccs_dp.list_len; i++) {
21962506 if (!ccs_dp.list_selected[i])
21972507 continue;
21982508 fprintf(fp, "delete %s\n",
2199- ccs_domain_name(&ccs_dp, i));
2509+ ccs_dp.list[i].domainname->name);
22002510 }
22012511 ccs_close_write(fp);
22022512 } else {
22032513 int i;
2514+ const _Bool is_kernel_ns = !strcmp(ccs_current_ns->name,
2515+ "<kernel>");
22042516 FILE *fp = ccs_editpolicy_open_write(ccs_policy_file);
22052517 if (!fp)
22062518 return;
@@ -2217,7 +2529,9 @@ static void ccs_delete_entry(const int index)
22172529 if (!ccs_gacl_list[i].selected)
22182530 continue;
22192531 directive = ccs_gacl_list[i].directive;
2220- fprintf(fp, "delete %s %s\n",
2532+ fprintf(fp, "delete %s %s %s\n",
2533+ ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST
2534+ && !is_kernel_ns ? ccs_current_ns->name : "",
22212535 ccs_directives[directive].original,
22222536 ccs_gacl_list[i].operand);
22232537 }
@@ -2234,6 +2548,7 @@ static void ccs_add_entry(void)
22342548 {
22352549 FILE *fp;
22362550 char *line;
2551+ const _Bool is_kernel_ns = !strcmp(ccs_current_ns->name, "<kernel>");
22372552 #ifndef __GPET
22382553 ccs_editpolicy_attr_change(A_BOLD, true); /* add color */
22392554 line = ccs_readline(ccs_window_height - 1, 0, "Enter new entry> ",
@@ -2254,10 +2569,7 @@ static void ccs_add_entry(void)
22542569 case CCS_SCREEN_DOMAIN_LIST:
22552570 if (!ccs_correct_domain(line)) {
22562571 const int len = strlen(line) + 128;
2257- ccs_last_error = realloc(ccs_last_error, len);
2258- if (!ccs_last_error)
2259- ccs_out_of_memory();
2260- memset(ccs_last_error, 0, len);
2572+ ccs_last_error = ccs_realloc2(ccs_last_error, len);
22612573 snprintf(ccs_last_error, len - 1,
22622574 "%s is an invalid domainname.", line);
22632575 line[0] = '\0';
@@ -2270,14 +2582,24 @@ static void ccs_add_entry(void)
22702582 fprintf(fp, "select domain=%s\n", ccs_current_domain);
22712583 /* Fall through. */
22722584 case CCS_SCREEN_EXCEPTION_LIST:
2585+ if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST &&
2586+ !is_kernel_ns)
2587+ fprintf(fp, "%s ", ccs_current_ns->name);
22732588 directive = ccs_find_directive(false, line);
22742589 if (directive != CCS_DIRECTIVE_NONE)
2275- fprintf(fp, "%s ",
2276- ccs_directives[directive].original);
2590+ fprintf(fp, "%s ", ccs_directives[directive].original);
22772591 break;
22782592 case CCS_SCREEN_PROFILE_LIST:
22792593 if (!strchr(line, '='))
2280- fprintf(fp, "%s-COMMENT=\n", line);
2594+ fprintf(fp, "%s %s-COMMENT=\n",
2595+ !is_kernel_ns ? ccs_current_ns->name : "",
2596+ line);
2597+ if (!is_kernel_ns)
2598+ fprintf(fp, "%s ", ccs_current_ns->name);
2599+ break;
2600+ case CCS_SCREEN_NS_LIST:
2601+ fprintf(fp, "%s PROFILE_VERSION=20100903\n", line);
2602+ line[0] = '\0';
22812603 break;
22822604 default:
22832605 break;
@@ -2405,7 +2727,7 @@ static void ccs_set_profile(const int current)
24052727 if (!ccs_dp.list_selected[index])
24062728 continue;
24072729 fprintf(fp, "select domain=%s\n" "use_profile %s\n",
2408- ccs_domain_name(&ccs_dp, index), line);
2730+ ccs_dp.list[index].domainname->name, line);
24092731 }
24102732 } else {
24112733 for (index = 0; index < ccs_task_list_len; index++) {
@@ -2471,6 +2793,7 @@ static void ccs_set_level(const int current)
24712793 if (cp)
24722794 *cp = '\0';
24732795 directive = ccs_gacl_list[index].directive;
2796+ fprintf(fp, "%s ", ccs_current_ns->name);
24742797 if (directive < 256)
24752798 fprintf(fp, "%u-", directive);
24762799 fprintf(fp, "%s=%s\n", buf, line);
@@ -2531,41 +2854,62 @@ out:
25312854 *
25322855 * @current: Index in the domain policy.
25332856 *
2534- * Returns true if next window is ACL list, false otherwise.
2857+ * Returns true if next window is ACL list or namespace list, false otherwise.
25352858 */
25362859 static _Bool ccs_select_acl_window(const int current)
25372860 {
25382861 char *old_domain;
2539- if (ccs_current_screen != CCS_SCREEN_DOMAIN_LIST || current == EOF)
2862+ if (current == EOF)
2863+ return false;
2864+ if (ccs_current_screen == CCS_SCREEN_NS_LIST) {
2865+ const char *namespace = ccs_gacl_list[current].operand;
2866+ if (ccs_previous_screen == CCS_SCREEN_ACL_LIST &&
2867+ strcmp(ccs_current_ns->name, namespace))
2868+ ccs_previous_screen = CCS_SCREEN_DOMAIN_LIST;
2869+ ccs_current_ns = ccs_savename(namespace);
2870+ ccs_current_screen = ccs_previous_screen;
2871+ return true;
2872+ }
2873+ if (ccs_current_screen != CCS_SCREEN_DOMAIN_LIST)
25402874 return false;
25412875 ccs_current_pid = 0;
25422876 if (ccs_domain_sort_type) {
25432877 ccs_current_pid = ccs_task_list[current].pid;
2544- } else if (ccs_initializer_source(current)) {
2878+ } else if (ccs_jump_source(current)) {
25452879 struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
25462880 const int redirect_index = ccs_find_target_domain(current);
2547- if (redirect_index == EOF)
2548- return false;
2549- ptr->current = redirect_index - ptr->y;
2550- while (ptr->current < 0) {
2551- ptr->current++;
2552- ptr->y--;
2881+ if (redirect_index >= 0) {
2882+ ptr->current = redirect_index - ptr->y;
2883+ while (ptr->current < 0) {
2884+ ptr->current++;
2885+ ptr->y--;
2886+ }
2887+ ccs_show_list();
2888+ }
2889+ if (redirect_index == -2) {
2890+ const char *domainname =
2891+ ccs_dp.list[current].target->name;
2892+ ccs_current_ns = ccs_get_ns(domainname);
2893+ free(ccs_current_domain);
2894+ ccs_current_domain = ccs_strdup(domainname);
2895+ ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
2896+ ccs_force_move_cursor = true;
2897+ return true;
25532898 }
2554- ccs_show_list();
25552899 return false;
25562900 } else if (ccs_deleted_domain(current)) {
25572901 return false;
25582902 }
25592903 old_domain = ccs_current_domain;
25602904 if (ccs_domain_sort_type)
2561- ccs_current_domain = strdup(ccs_task_list[current].domain);
2905+ ccs_current_domain = ccs_strdup(ccs_task_list[current].domain);
25622906 else
2563- ccs_current_domain = strdup(ccs_domain_name(&ccs_dp, current));
2564- if (!ccs_current_domain)
2565- ccs_out_of_memory();
2907+ ccs_current_domain = ccs_strdup(ccs_dp.list[current].
2908+ domainname->name);
25662909 ccs_no_restore_cursor = old_domain &&
25672910 strcmp(old_domain, ccs_current_domain);
25682911 free(old_domain);
2912+ ccs_current_screen = CCS_SCREEN_ACL_LIST;
25692913 return true;
25702914 }
25712915
@@ -2583,10 +2927,11 @@ static enum ccs_screen_type ccs_select_window(const int current)
25832927 printw("e <<< Exception Policy Editor >>>\n");
25842928 printw("d <<< Domain Transition Editor >>>\n");
25852929 if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && current != EOF &&
2586- !ccs_initializer_source(current) && !ccs_deleted_domain(current))
2930+ !ccs_jump_source(current) && !ccs_deleted_domain(current))
25872931 printw("a <<< Domain Policy Editor >>>\n");
25882932 printw("p <<< Profile Editor >>>\n");
25892933 printw("m <<< Manager Policy Editor >>>\n");
2934+ printw("n <<< Namespace Selector >>>\n");
25902935 if (!ccs_offline_mode) {
25912936 /* printw("i <<< Interactive Enforcing Mode >>>\n"); */
25922937 printw("s <<< Statistics >>>\n");
@@ -2602,11 +2947,15 @@ static enum ccs_screen_type ccs_select_window(const int current)
26022947 return CCS_SCREEN_DOMAIN_LIST;
26032948 if (c == 'A' || c == 'a')
26042949 if (ccs_select_acl_window(current))
2605- return CCS_SCREEN_ACL_LIST;
2950+ return ccs_current_screen;
26062951 if (c == 'P' || c == 'p')
26072952 return CCS_SCREEN_PROFILE_LIST;
26082953 if (c == 'M' || c == 'm')
26092954 return CCS_SCREEN_MANAGER_LIST;
2955+ if (c == 'N' || c == 'n') {
2956+ ccs_previous_screen = ccs_current_screen;
2957+ return CCS_SCREEN_NS_LIST;
2958+ }
26102959 if (!ccs_offline_mode) {
26112960 /*
26122961 if (c == 'I' || c == 'i')
@@ -2641,12 +2990,12 @@ static void ccs_copy_mark_state(const int current)
26412990 } else {
26422991 const u8 selected = ccs_dp.list_selected[current];
26432992 if (ccs_deleted_domain(current) ||
2644- ccs_initializer_source(current))
2993+ ccs_jump_source(current))
26452994 return;
26462995 for (index = current; index < ccs_dp.list_len;
26472996 index++) {
26482997 if (ccs_deleted_domain(index) ||
2649- ccs_initializer_source(index))
2998+ ccs_jump_source(index))
26502999 continue;
26513000 ccs_dp.list_selected[index] = selected;
26523001 }
@@ -2676,7 +3025,15 @@ static void ccs_copy_to_history(const int current)
26763025 switch (ccs_current_screen) {
26773026 enum ccs_editpolicy_directives directive;
26783027 case CCS_SCREEN_DOMAIN_LIST:
2679- line = ccs_domain_name(&ccs_dp, current);
3028+ if (!ccs_domain_sort_type) {
3029+ const struct ccs_domain *domain =
3030+ &ccs_dp.list[current];
3031+ if (domain->target)
3032+ line = domain->target->name;
3033+ else
3034+ line = domain->domainname->name;
3035+ } else
3036+ line = ccs_task_list[current].domain;
26803037 break;
26813038 case CCS_SCREEN_EXCEPTION_LIST:
26823039 case CCS_SCREEN_ACL_LIST:
@@ -2714,9 +3071,14 @@ static enum ccs_screen_type ccs_generic_list_loop(void)
27143071 } else if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
27153072 ccs_policy_file = CCS_PROC_POLICY_DOMAIN_POLICY;
27163073 ccs_list_caption = "Domain Policy Editor";
3074+ /*
27173075 } else if (ccs_current_screen == CCS_SCREEN_QUERY_LIST) {
27183076 ccs_policy_file = CCS_PROC_POLICY_QUERY;
27193077 ccs_list_caption = "Interactive Enforcing Mode";
3078+ */
3079+ } else if (ccs_current_screen == CCS_SCREEN_NS_LIST) {
3080+ ccs_policy_file = CCS_PROC_POLICY_PROFILE;
3081+ ccs_list_caption = "Namespace Selector";
27203082 } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
27213083 ccs_policy_file = CCS_PROC_POLICY_PROFILE;
27223084 ccs_list_caption = "Profile Editor";
@@ -2731,7 +3093,7 @@ static enum ccs_screen_type ccs_generic_list_loop(void)
27313093 /* ccs_list_caption = "Domain Transition Editor"; */
27323094 }
27333095 ptr = &ccs_screen[ccs_current_screen];
2734- if (ccs_no_restore_cursor) {
3096+ if (ccs_no_restore_cursor || ccs_force_move_cursor) {
27353097 ptr->current = 0;
27363098 ptr->y = 0;
27373099 ccs_no_restore_cursor = false;
@@ -2743,6 +3105,19 @@ start:
27433105 if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
27443106 if (!ccs_domain_sort_type) {
27453107 ccs_read_domain_and_exception_policy();
3108+ if (ccs_force_move_cursor) {
3109+ const int redirect_index =
3110+ ccs_find_domain3(ccs_current_domain,
3111+ NULL, false);
3112+ if (redirect_index >= 0) {
3113+ ptr->current = redirect_index - ptr->y;
3114+ while (ptr->current < 0) {
3115+ ptr->current++;
3116+ ptr->y--;
3117+ }
3118+ }
3119+ ccs_force_move_cursor = false;
3120+ }
27463121 ccs_adjust_cursor_pos(ccs_dp.list_len);
27473122 } else {
27483123 ccs_read_process_list(true);
@@ -2866,6 +3241,7 @@ start2:
28663241 case CCS_SCREEN_ACL_LIST:
28673242 case CCS_SCREEN_PROFILE_LIST:
28683243 case CCS_SCREEN_MANAGER_LIST:
3244+ case CCS_SCREEN_NS_LIST:
28693245 ccs_add_entry();
28703246 goto start;
28713247 default:
@@ -2875,7 +3251,7 @@ start2:
28753251 case '\r':
28763252 case '\n':
28773253 if (ccs_select_acl_window(current))
2878- return CCS_SCREEN_ACL_LIST;
3254+ return ccs_current_screen;
28793255 break;
28803256 case 's':
28813257 case 'S':
@@ -2917,7 +3293,8 @@ start2:
29173293 break;
29183294 case 'o':
29193295 case 'O':
2920- if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
3296+ if (ccs_current_screen == CCS_SCREEN_ACL_LIST ||
3297+ ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST) {
29213298 ccs_editpolicy_optimize(current);
29223299 ccs_show_list();
29233300 }
@@ -2964,20 +3341,27 @@ static _Bool ccs_save_to_file(const char *src, const char *dest)
29643341 {
29653342 FILE *proc_fp = ccs_editpolicy_open_read(src);
29663343 FILE *file_fp = fopen(dest, "w");
2967- if (!file_fp) {
3344+ int c;
3345+ if (!file_fp || !proc_fp) {
29683346 fprintf(stderr, "Can't open %s\n", dest);
2969- fclose(proc_fp);
3347+ if (file_fp)
3348+ fclose(file_fp);
3349+ if (proc_fp)
3350+ fclose(proc_fp);
29703351 return false;
29713352 }
29723353 while (true) {
2973- int c = fgetc(proc_fp);
2974- if (c == EOF)
3354+ c = fgetc(proc_fp);
3355+ if (!c || c == EOF)
29753356 break;
2976- fputc(c, file_fp);
3357+ if (fputc(c, file_fp) == EOF) {
3358+ c = EOF;
3359+ break;
3360+ }
29773361 }
29783362 fclose(proc_fp);
29793363 fclose(file_fp);
2980- return true;
3364+ return !c;
29813365 }
29823366
29833367 /**
@@ -2999,6 +3383,11 @@ static void ccs_parse_args(int argc, char *argv[])
29993383 goto usage;
30003384 ccs_policy_dir = ptr;
30013385 ccs_offline_mode = true;
3386+ } else if (*ptr == '<') {
3387+ if (ccs_current_ns || strchr(ptr, ' ') ||
3388+ !ccs_domain_def(ptr))
3389+ goto usage;
3390+ ccs_current_ns = ccs_savename(ptr);
30023391 } else if (cp) {
30033392 *cp++ = '\0';
30043393 if (ccs_network_mode || ccs_offline_mode)
@@ -3018,18 +3407,22 @@ static void ccs_parse_args(int argc, char *argv[])
30183407 ccs_current_screen = CCS_SCREEN_MANAGER_LIST;
30193408 else if (!strcmp(ptr, "s"))
30203409 ccs_current_screen = CCS_SCREEN_STAT_LIST;
3410+ else if (!strcmp(ptr, "n"))
3411+ ccs_current_screen = CCS_SCREEN_NS_LIST;
30213412 else if (!strcmp(ptr, "readonly"))
30223413 ccs_readonly_mode = true;
30233414 else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval)
30243415 != 1) {
30253416 usage:
3026- printf("Usage: %s [e|d|p|m|s] [readonly] "
3027- "[refresh=interval] "
3417+ printf("Usage: %s [e|d|p|m|s|n] [readonly] "
3418+ "[refresh=interval] [<namespace>]"
30283419 "[{policy_dir|remote_ip:remote_port}]\n",
30293420 argv[0]);
30303421 exit(1);
30313422 }
30323423 }
3424+ if (!ccs_current_ns)
3425+ ccs_current_ns = ccs_savename("<kernel>");
30333426 }
30343427
30353428 /**
@@ -3039,32 +3432,60 @@ usage:
30393432 */
30403433 static void ccs_load_offline(void)
30413434 {
3042- int fd[2] = { EOF, EOF };
3435+ int pipe_fd[2] = { EOF, EOF };
3436+ int fd = socket(AF_INET, SOCK_STREAM, 0);
3437+ struct sockaddr_in addr = { };
3438+ socklen_t size = sizeof(addr);
3439+ /*
3440+ * Use PF_INET socket as a method for communicating with child task
3441+ * so that we can use same method for child task and
3442+ * ccs-editpolicy-agent.
3443+ */
3444+ addr.sin_family = AF_INET;
3445+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
30433446 if (chdir(ccs_policy_dir) || chdir("policy/current/")) {
30443447 fprintf(stderr, "Directory %s/policy/current/ doesn't "
30453448 "exist.\n", ccs_policy_dir);
30463449 exit(1);
30473450 }
3048- if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
3049- fprintf(stderr, "socketpair()\n");
3451+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) || listen(fd, 5)
3452+ || getsockname(fd, (struct sockaddr *) &addr, &size)) {
3453+ fprintf(stderr, "Can't create listener socket.\n");
3454+ exit(1);
3455+ }
3456+ ccs_network_ip = addr.sin_addr.s_addr;
3457+ ccs_network_port = addr.sin_port;
3458+ ccs_network_mode = true;
3459+ /*
3460+ * Use pipe as a notifier for termination.
3461+ *
3462+ * Sending signals by remembering child task's PID would be possible.
3463+ * But such approach will not work if main task exited unexpectedly
3464+ * (e.g. SIGKILL). Since pipe_fd[1] is guaranteed to be closed no
3465+ * matter how main task exits, pipe approach is more reliable for
3466+ * telling the child task to exit.
3467+ */
3468+ if (pipe(pipe_fd)) {
3469+ fprintf(stderr, "Can't create pipe.\n");
30503470 exit(1);
30513471 }
30523472 switch (fork()) {
30533473 case 0:
3054- close(fd[0]);
3055- ccs_persistent_fd = fd[1];
3056- ccs_editpolicy_offline_daemon();
3057- _exit(0);
3474+ if (close(pipe_fd[1]) ||
3475+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK))
3476+ _exit(1);
3477+ ccs_editpolicy_offline_daemon(fd, pipe_fd[0]);
3478+ _exit(1);
30583479 case -1:
30593480 fprintf(stderr, "fork()\n");
30603481 exit(1);
30613482 }
3062- close(fd[1]);
3063- ccs_persistent_fd = fd[0];
3483+ if (close(fd) || close(pipe_fd[0]))
3484+ exit(1);
3485+ ccs_copy_file("profile.conf", CCS_PROC_POLICY_PROFILE);
30643486 ccs_copy_file("exception_policy.conf",
30653487 CCS_PROC_POLICY_EXCEPTION_POLICY);
30663488 ccs_copy_file("domain_policy.conf", CCS_PROC_POLICY_DOMAIN_POLICY);
3067- ccs_copy_file("profile.conf", CCS_PROC_POLICY_PROFILE);
30683489 ccs_copy_file("manager.conf", CCS_PROC_POLICY_MANAGER);
30693490 if (chdir("..")) {
30703491 fprintf(stderr, "Directory %s/policy/ doesn't exist.\n",
@@ -3142,6 +3563,7 @@ static void ccs_save_offline(void)
31423563 }
31433564
31443565 #ifdef __GPET /* gpet */
3566+static void set_ccs_flag(void);
31453567 int gpet_main(void);
31463568 int ccs_main(int argc, char *argv[])
31473569 #else
@@ -3149,11 +3571,12 @@ int main(int argc, char *argv[])
31493571 #endif /* gpet */
31503572 {
31513573 ccs_parse_args(argc, argv);
3574+#ifdef __GPET /* gpet */
3575+ set_ccs_flag();
3576+#endif /* gpet */
31523577 ccs_editpolicy_init_keyword_map();
3153- if (ccs_offline_mode) {
3578+ if (ccs_offline_mode)
31543579 ccs_load_offline();
3155- goto start;
3156- }
31573580 if (ccs_network_mode)
31583581 goto start;
31593582 if (chdir(CCS_PROC_POLICY_DIR)) {
@@ -3182,7 +3605,7 @@ start:
31823605 timeout(1000);
31833606 }
31843607 ccs_rl.max = 20;
3185- ccs_rl.history = malloc(ccs_rl.max * sizeof(const char *));
3608+ ccs_rl.history = ccs_malloc(ccs_rl.max * sizeof(const char *));
31863609 while (ccs_current_screen < CCS_MAXSCREEN) {
31873610 ccs_resize_window();
31883611 ccs_current_screen = ccs_generic_list_loop();
@@ -3195,7 +3618,7 @@ start:
31953618 #endif /* __GPET */
31963619 if (ccs_offline_mode && !ccs_readonly_mode)
31973620 ccs_save_offline();
3198- ccs_clear_domain_policy(&ccs_dp);
3621+ ccs_clear_domain_policy3();
31993622 return 0;
32003623 }
32013624
--- a/src/usr_sbin/editpolicy.h
+++ b/src/usr_sbin/editpolicy.h
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2+ 2011/07/07
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -29,13 +29,16 @@ enum ccs_screen_type {
2929 CCS_SCREEN_ACL_LIST,
3030 CCS_SCREEN_PROFILE_LIST,
3131 CCS_SCREEN_MANAGER_LIST,
32- CCS_SCREEN_QUERY_LIST,
32+ /* CCS_SCREEN_QUERY_LIST, */
33+ CCS_SCREEN_NS_LIST,
3334 CCS_SCREEN_STAT_LIST,
3435 CCS_MAXSCREEN
3536 };
3637
3738 enum ccs_transition_type {
3839 /* Do not change this order, */
40+ CCS_TRANSITION_CONTROL_NO_RESET,
41+ CCS_TRANSITION_CONTROL_RESET,
3942 CCS_TRANSITION_CONTROL_NO_INITIALIZE,
4043 CCS_TRANSITION_CONTROL_INITIALIZE,
4144 CCS_TRANSITION_CONTROL_NO_KEEP,
@@ -338,9 +341,11 @@ enum ccs_editpolicy_directives {
338341 CCS_DIRECTIVE_NETWORK_UNIX,
339342 CCS_DIRECTIVE_NO_INITIALIZE_DOMAIN,
340343 CCS_DIRECTIVE_NO_KEEP_DOMAIN,
344+ CCS_DIRECTIVE_NO_RESET_DOMAIN,
341345 CCS_DIRECTIVE_NUMBER_GROUP,
342346 CCS_DIRECTIVE_PATH_GROUP,
343347 CCS_DIRECTIVE_QUOTA_EXCEEDED,
348+ CCS_DIRECTIVE_RESET_DOMAIN,
344349 CCS_DIRECTIVE_TASK_AUTO_DOMAIN_TRANSITION,
345350 CCS_DIRECTIVE_TASK_AUTO_EXECUTE_HANDLER,
346351 CCS_DIRECTIVE_TASK_DENIED_EXECUTE_HANDLER,
@@ -365,14 +370,15 @@ enum ccs_color_pair {
365370 CCS_MANAGER_CURSOR,
366371 CCS_STAT_HEAD,
367372 CCS_STAT_CURSOR,
373+ CCS_DEFAULT_COLOR,
368374 CCS_DISP_ERR
369375 };
370376
371377 struct ccs_transition_control_entry {
378+ const struct ccs_path_info *ns;
372379 const struct ccs_path_info *domainname; /* This may be NULL */
373380 const struct ccs_path_info *program; /* This may be NULL */
374381 u8 type;
375- _Bool is_last_name;
376382 };
377383
378384 struct ccs_generic_acl {
@@ -394,6 +400,7 @@ struct ccs_misc_policy {
394400 };
395401
396402 struct ccs_path_group_entry {
403+ const struct ccs_path_info *ns;
397404 const struct ccs_path_info *group_name;
398405 const struct ccs_path_info **member_name;
399406 int member_name_len;
@@ -434,21 +441,43 @@ void ccs_editpolicy_color_change(const attr_t attr, const _Bool flg);
434441 void ccs_editpolicy_color_init(void);
435442 void ccs_editpolicy_init_keyword_map(void);
436443 void ccs_editpolicy_line_draw(void);
437-void ccs_editpolicy_offline_daemon(void);
444+void ccs_editpolicy_offline_daemon(const int listener, const int notifier);
438445 void ccs_editpolicy_optimize(const int current);
439446 void ccs_editpolicy_sttr_restore(void);
440447 void ccs_editpolicy_sttr_save(void);
448+struct ccs_path_group_entry *ccs_find_path_group_ns
449+(const struct ccs_path_info *ns, const char *group_name);
450+
451+struct ccs_domain {
452+ const struct ccs_path_info *domainname;
453+ const struct ccs_path_info *target; /* This may be NULL */
454+ const struct ccs_transition_control_entry *d_t; /* This may be NULL */
455+ const struct ccs_path_info **string_ptr;
456+ int string_count;
457+ int number; /* domain number (-1 if target or is_dd) */
458+ u8 profile;
459+ u8 group;
460+ _Bool is_djt; /* domain jump target */
461+ _Bool is_dk; /* domain keeper */
462+ _Bool is_du; /* unreachable domain */
463+ _Bool is_dd; /* deleted domain */
464+};
465+
466+struct ccs_domain_policy3 {
467+ struct ccs_domain *list;
468+ int list_len;
469+ unsigned char *list_selected;
470+};
441471
442472 extern enum ccs_screen_type ccs_current_screen;
443-extern int ccs_gacl_list_count;
444473 extern int ccs_list_item_count;
445474 extern int ccs_path_group_list_len;
446-extern int ccs_persistent_fd;
447-extern struct ccs_domain_policy ccs_dp;
475+extern struct ccs_domain_policy3 ccs_dp;
448476 extern struct ccs_editpolicy_directive ccs_directives[CCS_MAX_DIRECTIVE_INDEX];
449477 extern struct ccs_generic_acl *ccs_gacl_list;
450478 extern struct ccs_path_group_entry *ccs_path_group_list;
451479 extern struct ccs_screen ccs_screen[CCS_MAXSCREEN];
480+extern const struct ccs_path_info *ccs_current_ns;
452481
453482 #ifdef __GPET
454483 #include "../g_undef.h"
--- a/src/usr_sbin/editpolicy_color.c
+++ b/src/usr_sbin/editpolicy_color.c
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2 2011/06/20
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -62,6 +62,8 @@ void ccs_editpolicy_color_init(void)
6262 COLOR_YELLOW, "STAT_HEAD" },
6363 { CCS_STAT_CURSOR, COLOR_BLACK,
6464 COLOR_YELLOW, "STAT_CURSOR" },
65+ { CCS_DEFAULT_COLOR, COLOR_WHITE,
66+ COLOR_BLACK, "DEFAULT_COLOR" },
6567 { CCS_NORMAL, COLOR_WHITE,
6668 COLOR_BLACK, NULL }
6769 };
@@ -110,6 +112,7 @@ use_default:
110112 init_pair(colorp->tag, colorp->fore, colorp->back);
111113 }
112114 init_pair(CCS_DISP_ERR, COLOR_RED, COLOR_BLACK); /* error message */
115+ bkgdset(A_NORMAL | COLOR_PAIR(CCS_DEFAULT_COLOR) | ' ');
113116 for (i = 0; i < CCS_MAXSCREEN; i++)
114117 ccs_screen[i].saved_color_current = -1;
115118 }
@@ -123,7 +126,7 @@ use_default:
123126 */
124127 static void ccs_editpolicy_color_save(const _Bool flg)
125128 {
126- static attr_t save_color = CCS_NORMAL;
129+ static attr_t save_color = CCS_DEFAULT_COLOR;
127130 if (flg)
128131 save_color = getattrs(stdscr);
129132 else
@@ -183,7 +186,7 @@ void ccs_editpolicy_sttr_restore(void)
183186 }
184187
185188 /**
186- * ccseditpolicy_color_head - Get color to use for header line.
189+ * ccs_editpolicy_color_head - Get color to use for header line.
187190 *
188191 * Returns one of values in "enum ccs_color_pair".
189192 */
@@ -247,7 +250,7 @@ void ccs_editpolicy_line_draw(void)
247250 if (-1 < ptr->saved_color_current &&
248251 current != ptr->saved_color_current) {
249252 move(CCS_HEADER_LINES + ptr->saved_color_y, 0);
250- chgat(-1, A_NORMAL, CCS_NORMAL, NULL);
253+ chgat(-1, A_NORMAL, CCS_DEFAULT_COLOR, NULL);
251254 }
252255
253256 move(y, x);
@@ -312,13 +315,13 @@ void ccs_editpolicy_sttr_restore(void)
312315 }
313316
314317 /**
315- * ccseditpolicy_color_head - Get color to use for header line.
318+ * ccs_editpolicy_color_head - Get color to use for header line.
316319 *
317320 * Returns one of values in "enum ccs_color_pair".
318321 */
319322 enum ccs_color_pair ccs_editpolicy_color_head(void)
320323 {
321- return CCS_NORMAL;
324+ return CCS_DEFAULT_COLOR;
322325 }
323326
324327 /**
--- a/src/usr_sbin/editpolicy_keyword.c
+++ b/src/usr_sbin/editpolicy_keyword.c
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2 2011/06/20
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -310,7 +310,8 @@ struct ccs_editpolicy_directive ccs_directives[CCS_MAX_DIRECTIVE_INDEX] = {
310310 [CCS_DIRECTIVE_FILE_UNLINK] = { "file unlink", NULL, 0, 0 },
311311 [CCS_DIRECTIVE_FILE_UNMOUNT] = { "file unmount", NULL, 0, 0 },
312312 [CCS_DIRECTIVE_FILE_WRITE] = { "file write", NULL, 0, 0 },
313- [CCS_DIRECTIVE_INITIALIZE_DOMAIN] = { "initialize_domain", NULL, 0, 0 },
313+ [CCS_DIRECTIVE_INITIALIZE_DOMAIN]
314+ = { "initialize_domain", NULL, 0, 0 },
314315 [CCS_DIRECTIVE_IPC_SIGNAL] = { "ipc signal", NULL, 0, 0 },
315316 [CCS_DIRECTIVE_KEEP_DOMAIN] = { "keep_domain", NULL, 0, 0 },
316317 [CCS_DIRECTIVE_MISC_ENV] = { "misc env", NULL, 0, 0 },
@@ -320,9 +321,11 @@ struct ccs_editpolicy_directive ccs_directives[CCS_MAX_DIRECTIVE_INDEX] = {
320321 [CCS_DIRECTIVE_NO_INITIALIZE_DOMAIN]
321322 = { "no_initialize_domain", NULL, 0, 0 },
322323 [CCS_DIRECTIVE_NO_KEEP_DOMAIN] = { "no_keep_domain", NULL, 0, 0 },
324+ [CCS_DIRECTIVE_NO_RESET_DOMAIN] = { "no_reset_domain", NULL, 0, 0 },
323325 [CCS_DIRECTIVE_NUMBER_GROUP] = { "number_group", NULL, 0, 0 },
324326 [CCS_DIRECTIVE_PATH_GROUP] = { "path_group", NULL, 0, 0 },
325327 [CCS_DIRECTIVE_QUOTA_EXCEEDED] = { "quota_exceeded", NULL, 0, 0 },
328+ [CCS_DIRECTIVE_RESET_DOMAIN] = { "reset_domain", NULL, 0, 0 },
326329 [CCS_DIRECTIVE_TASK_AUTO_DOMAIN_TRANSITION]
327330 = { "task auto_domain_transition", NULL, 0, 0 },
328331 [CCS_DIRECTIVE_TASK_AUTO_EXECUTE_HANDLER]
@@ -331,7 +334,8 @@ struct ccs_editpolicy_directive ccs_directives[CCS_MAX_DIRECTIVE_INDEX] = {
331334 = { "task denied_execute_handler", NULL, 0, 0 },
332335 [CCS_DIRECTIVE_TASK_MANUAL_DOMAIN_TRANSITION]
333336 = { "task manual_domain_transition", NULL, 0, 0 },
334- [CCS_DIRECTIVE_TRANSITION_FAILED] = { "transition_failed", NULL, 0, 0 },
337+ [CCS_DIRECTIVE_TRANSITION_FAILED]
338+ = { "transition_failed", NULL, 0, 0 },
335339 [CCS_DIRECTIVE_USE_GROUP] = { "use_group", NULL, 0, 0 },
336340 [CCS_DIRECTIVE_USE_PROFILE] = { "use_profile", NULL, 0, 0 },
337341 };
@@ -407,9 +411,7 @@ void ccs_editpolicy_init_keyword_map(void)
407411 if (strcmp(line, ccs_directives[i].original))
408412 continue;
409413 free((void *) ccs_directives[i].alias);
410- cp = strdup(cp);
411- if (!cp)
412- ccs_out_of_memory();
414+ cp = ccs_strdup(cp);
413415 ccs_directives[i].alias = cp;
414416 ccs_directives[i].alias_len = strlen(cp);
415417 break;
--- a/src/usr_sbin/editpolicy_offline.c
+++ b/src/usr_sbin/editpolicy_offline.c
@@ -5,7 +5,7 @@
55 *
66 * Copyright (C) 2005-2011 NTT DATA CORPORATION
77 *
8- * Version: 1.8.1 2011/04/01
8+ * Version: 1.8.2+ 2011/07/13
99 *
1010 * This program is free software; you can redistribute it and/or modify it
1111 * under the terms of the GNU General Public License v2 as published by the
@@ -22,143 +22,4802 @@
2222 */
2323 #include "ccstools.h"
2424 #include "editpolicy.h"
25+#include <poll.h>
26+
27+struct list_head {
28+ struct list_head *next;
29+ struct list_head *prev;
30+};
31+
32+#define LIST_HEAD_INIT(name) { &(name), &(name) }
33+#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
34+
35+#ifndef offsetof
36+#ifdef __compiler_offsetof
37+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
38+#else
39+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
40+#endif
41+#endif
42+#define container_of(ptr, type, member) ({ \
43+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
44+ (type *)( (char *)__mptr - offsetof(type,member) );})
45+
46+#define list_entry(ptr, type, member) container_of(ptr, type, member)
47+#define list_for_each_entry(pos, head, member) \
48+ for (pos = list_entry((head)->next, typeof(*pos), member); \
49+ &pos->member != (head); \
50+ pos = list_entry(pos->member.next, typeof(*pos), member))
51+
52+static inline void __list_add(struct list_head *new, struct list_head *prev,
53+ struct list_head *next)
54+{
55+ next->prev = new;
56+ new->next = next;
57+ new->prev = prev;
58+ prev->next = new;
59+}
60+
61+static inline void list_add(struct list_head *new, struct list_head *head)
62+{
63+ __list_add(new, head, head->next);
64+}
65+
66+static inline void list_add_tail(struct list_head *new, struct list_head *head)
67+{
68+ __list_add(new, head->prev, head);
69+}
70+
71+static inline void INIT_LIST_HEAD(struct list_head *list)
72+{
73+ list->next = list;
74+ list->prev = list;
75+}
76+
77+static inline int list_empty(const struct list_head *head)
78+{
79+ return head->next == head;
80+}
81+
82+/* Enumeration definition for internal use. */
83+
84+/* Index numbers for Access Controls. */
85+enum ccs_acl_entry_type_index {
86+ CCS_TYPE_PATH_ACL,
87+ CCS_TYPE_PATH2_ACL,
88+ CCS_TYPE_PATH_NUMBER_ACL,
89+ CCS_TYPE_MKDEV_ACL,
90+ CCS_TYPE_MOUNT_ACL,
91+ CCS_TYPE_ENV_ACL,
92+ CCS_TYPE_CAPABILITY_ACL,
93+ CCS_TYPE_INET_ACL,
94+ CCS_TYPE_UNIX_ACL,
95+ CCS_TYPE_SIGNAL_ACL,
96+ CCS_TYPE_AUTO_EXECUTE_HANDLER,
97+ CCS_TYPE_DENIED_EXECUTE_HANDLER,
98+ CCS_TYPE_AUTO_TASK_ACL,
99+ CCS_TYPE_MANUAL_TASK_ACL,
100+};
101+
102+/* Index numbers for Capability Controls. */
103+enum ccs_capability_acl_index {
104+ /* socket(PF_ROUTE, *, *) */
105+ CCS_USE_ROUTE_SOCKET,
106+ /* socket(PF_PACKET, *, *) */
107+ CCS_USE_PACKET_SOCKET,
108+ /* sys_reboot() */
109+ CCS_SYS_REBOOT,
110+ /* sys_vhangup() */
111+ CCS_SYS_VHANGUP,
112+ /* do_settimeofday(), sys_adjtimex() */
113+ CCS_SYS_SETTIME,
114+ /* sys_nice(), sys_setpriority() */
115+ CCS_SYS_NICE,
116+ /* sys_sethostname(), sys_setdomainname() */
117+ CCS_SYS_SETHOSTNAME,
118+ /* sys_create_module(), sys_init_module(), sys_delete_module() */
119+ CCS_USE_KERNEL_MODULE,
120+ /* sys_kexec_load() */
121+ CCS_SYS_KEXEC_LOAD,
122+ /* sys_ptrace() */
123+ CCS_SYS_PTRACE,
124+ CCS_MAX_CAPABILITY_INDEX
125+};
126+
127+/* Index numbers for "struct ccs_condition". */
128+enum ccs_conditions_index {
129+ CCS_TASK_UID, /* current_uid() */
130+ CCS_TASK_EUID, /* current_euid() */
131+ CCS_TASK_SUID, /* current_suid() */
132+ CCS_TASK_FSUID, /* current_fsuid() */
133+ CCS_TASK_GID, /* current_gid() */
134+ CCS_TASK_EGID, /* current_egid() */
135+ CCS_TASK_SGID, /* current_sgid() */
136+ CCS_TASK_FSGID, /* current_fsgid() */
137+ CCS_TASK_PID, /* sys_getpid() */
138+ CCS_TASK_PPID, /* sys_getppid() */
139+ CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
140+ CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
141+ CCS_TYPE_IS_SOCKET, /* S_IFSOCK */
142+ CCS_TYPE_IS_SYMLINK, /* S_IFLNK */
143+ CCS_TYPE_IS_FILE, /* S_IFREG */
144+ CCS_TYPE_IS_BLOCK_DEV, /* S_IFBLK */
145+ CCS_TYPE_IS_DIRECTORY, /* S_IFDIR */
146+ CCS_TYPE_IS_CHAR_DEV, /* S_IFCHR */
147+ CCS_TYPE_IS_FIFO, /* S_IFIFO */
148+ CCS_MODE_SETUID, /* S_ISUID */
149+ CCS_MODE_SETGID, /* S_ISGID */
150+ CCS_MODE_STICKY, /* S_ISVTX */
151+ CCS_MODE_OWNER_READ, /* S_IRUSR */
152+ CCS_MODE_OWNER_WRITE, /* S_IWUSR */
153+ CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
154+ CCS_MODE_GROUP_READ, /* S_IRGRP */
155+ CCS_MODE_GROUP_WRITE, /* S_IWGRP */
156+ CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
157+ CCS_MODE_OTHERS_READ, /* S_IROTH */
158+ CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
159+ CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
160+ CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
161+ CCS_TASK_IS_EXECUTE_HANDLER */
162+ CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
163+ CCS_EXEC_REALPATH,
164+ CCS_SYMLINK_TARGET,
165+ CCS_PATH1_UID,
166+ CCS_PATH1_GID,
167+ CCS_PATH1_INO,
168+ CCS_PATH1_MAJOR,
169+ CCS_PATH1_MINOR,
170+ CCS_PATH1_PERM,
171+ CCS_PATH1_TYPE,
172+ CCS_PATH1_DEV_MAJOR,
173+ CCS_PATH1_DEV_MINOR,
174+ CCS_PATH2_UID,
175+ CCS_PATH2_GID,
176+ CCS_PATH2_INO,
177+ CCS_PATH2_MAJOR,
178+ CCS_PATH2_MINOR,
179+ CCS_PATH2_PERM,
180+ CCS_PATH2_TYPE,
181+ CCS_PATH2_DEV_MAJOR,
182+ CCS_PATH2_DEV_MINOR,
183+ CCS_PATH1_PARENT_UID,
184+ CCS_PATH1_PARENT_GID,
185+ CCS_PATH1_PARENT_INO,
186+ CCS_PATH1_PARENT_PERM,
187+ CCS_PATH2_PARENT_UID,
188+ CCS_PATH2_PARENT_GID,
189+ CCS_PATH2_PARENT_INO,
190+ CCS_PATH2_PARENT_PERM,
191+ CCS_MAX_CONDITION_KEYWORD,
192+ CCS_NUMBER_UNION,
193+ CCS_NAME_UNION,
194+ CCS_ARGV_ENTRY,
195+ CCS_ENVP_ENTRY,
196+};
197+
198+/* Index numbers for domain's attributes. */
199+enum ccs_domain_info_flags_index {
200+ /* Quota warnning flag. */
201+ CCS_DIF_QUOTA_WARNED,
202+ /*
203+ * This domain was unable to create a new domain at
204+ * ccs_find_next_domain() because the name of the domain to be created
205+ * was too long or it could not allocate memory.
206+ * More than one process continued execve() without domain transition.
207+ */
208+ CCS_DIF_TRANSITION_FAILED,
209+ CCS_MAX_DOMAIN_INFO_FLAGS
210+};
211+
212+/* Index numbers for audit type. */
213+enum ccs_grant_log {
214+ /* Follow profile's configuration. */
215+ CCS_GRANTLOG_AUTO,
216+ /* Do not generate grant log. */
217+ CCS_GRANTLOG_NO,
218+ /* Generate grant_log. */
219+ CCS_GRANTLOG_YES,
220+};
221+
222+/* Index numbers for group entries. */
223+enum ccs_group_id {
224+ CCS_PATH_GROUP,
225+ CCS_NUMBER_GROUP,
226+ CCS_ADDRESS_GROUP,
227+ CCS_MAX_GROUP
228+};
229+
230+/* Index numbers for category of functionality. */
231+enum ccs_mac_category_index {
232+ CCS_MAC_CATEGORY_FILE,
233+ CCS_MAC_CATEGORY_NETWORK,
234+ CCS_MAC_CATEGORY_MISC,
235+ CCS_MAC_CATEGORY_IPC,
236+ CCS_MAC_CATEGORY_CAPABILITY,
237+ CCS_MAX_MAC_CATEGORY_INDEX
238+};
239+
240+/* Index numbers for functionality. */
241+enum ccs_mac_index {
242+ CCS_MAC_FILE_EXECUTE,
243+ CCS_MAC_FILE_OPEN,
244+ CCS_MAC_FILE_CREATE,
245+ CCS_MAC_FILE_UNLINK,
246+ CCS_MAC_FILE_GETATTR,
247+ CCS_MAC_FILE_MKDIR,
248+ CCS_MAC_FILE_RMDIR,
249+ CCS_MAC_FILE_MKFIFO,
250+ CCS_MAC_FILE_MKSOCK,
251+ CCS_MAC_FILE_TRUNCATE,
252+ CCS_MAC_FILE_SYMLINK,
253+ CCS_MAC_FILE_MKBLOCK,
254+ CCS_MAC_FILE_MKCHAR,
255+ CCS_MAC_FILE_LINK,
256+ CCS_MAC_FILE_RENAME,
257+ CCS_MAC_FILE_CHMOD,
258+ CCS_MAC_FILE_CHOWN,
259+ CCS_MAC_FILE_CHGRP,
260+ CCS_MAC_FILE_IOCTL,
261+ CCS_MAC_FILE_CHROOT,
262+ CCS_MAC_FILE_MOUNT,
263+ CCS_MAC_FILE_UMOUNT,
264+ CCS_MAC_FILE_PIVOT_ROOT,
265+ CCS_MAC_NETWORK_INET_STREAM_BIND,
266+ CCS_MAC_NETWORK_INET_STREAM_LISTEN,
267+ CCS_MAC_NETWORK_INET_STREAM_CONNECT,
268+ CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
269+ CCS_MAC_NETWORK_INET_DGRAM_BIND,
270+ CCS_MAC_NETWORK_INET_DGRAM_SEND,
271+ CCS_MAC_NETWORK_INET_DGRAM_RECV,
272+ CCS_MAC_NETWORK_INET_RAW_BIND,
273+ CCS_MAC_NETWORK_INET_RAW_SEND,
274+ CCS_MAC_NETWORK_INET_RAW_RECV,
275+ CCS_MAC_NETWORK_UNIX_STREAM_BIND,
276+ CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
277+ CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
278+ CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
279+ CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
280+ CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
281+ CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
282+ CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
283+ CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
284+ CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
285+ CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
286+ CCS_MAC_ENVIRON,
287+ CCS_MAC_SIGNAL,
288+ CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
289+ CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
290+ CCS_MAC_CAPABILITY_SYS_REBOOT,
291+ CCS_MAC_CAPABILITY_SYS_VHANGUP,
292+ CCS_MAC_CAPABILITY_SYS_SETTIME,
293+ CCS_MAC_CAPABILITY_SYS_NICE,
294+ CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
295+ CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
296+ CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
297+ CCS_MAC_CAPABILITY_SYS_PTRACE,
298+ CCS_MAX_MAC_INDEX
299+};
300+
301+/* Index numbers for /proc/ccs/stat interface. */
302+enum ccs_memory_stat_type {
303+ CCS_MEMORY_POLICY,
304+ CCS_MEMORY_AUDIT,
305+ CCS_MEMORY_QUERY,
306+ CCS_MAX_MEMORY_STAT
307+};
308+
309+/* Index numbers for access controls with one pathname and three numbers. */
310+enum ccs_mkdev_acl_index {
311+ CCS_TYPE_MKBLOCK,
312+ CCS_TYPE_MKCHAR,
313+ CCS_MAX_MKDEV_OPERATION
314+};
315+
316+/* Index numbers for operation mode. */
317+enum ccs_mode_value {
318+ CCS_CONFIG_DISABLED,
319+ CCS_CONFIG_LEARNING,
320+ CCS_CONFIG_PERMISSIVE,
321+ CCS_CONFIG_ENFORCING,
322+ CCS_CONFIG_MAX_MODE,
323+ CCS_CONFIG_WANT_REJECT_LOG = 64,
324+ CCS_CONFIG_WANT_GRANT_LOG = 128,
325+ CCS_CONFIG_USE_DEFAULT = 255,
326+};
327+
328+/* Index numbers for socket operations. */
329+enum ccs_network_acl_index {
330+ CCS_NETWORK_BIND, /* bind() operation. */
331+ CCS_NETWORK_LISTEN, /* listen() operation. */
332+ CCS_NETWORK_CONNECT, /* connect() operation. */
333+ CCS_NETWORK_ACCEPT, /* accept() operation. */
334+ CCS_NETWORK_SEND, /* send() operation. */
335+ CCS_NETWORK_RECV, /* recv() operation. */
336+ CCS_MAX_NETWORK_OPERATION
337+};
338+
339+/* Index numbers for access controls with two pathnames. */
340+enum ccs_path2_acl_index {
341+ CCS_TYPE_LINK,
342+ CCS_TYPE_RENAME,
343+ CCS_TYPE_PIVOT_ROOT,
344+ CCS_MAX_PATH2_OPERATION
345+};
346+
347+/* Index numbers for access controls with one pathname. */
348+enum ccs_path_acl_index {
349+ CCS_TYPE_EXECUTE,
350+ CCS_TYPE_READ,
351+ CCS_TYPE_WRITE,
352+ CCS_TYPE_APPEND,
353+ CCS_TYPE_UNLINK,
354+ CCS_TYPE_GETATTR,
355+ CCS_TYPE_RMDIR,
356+ CCS_TYPE_TRUNCATE,
357+ CCS_TYPE_SYMLINK,
358+ CCS_TYPE_CHROOT,
359+ CCS_TYPE_UMOUNT,
360+ CCS_MAX_PATH_OPERATION
361+};
362+
363+/* Index numbers for access controls with one pathname and one number. */
364+enum ccs_path_number_acl_index {
365+ CCS_TYPE_CREATE,
366+ CCS_TYPE_MKDIR,
367+ CCS_TYPE_MKFIFO,
368+ CCS_TYPE_MKSOCK,
369+ CCS_TYPE_IOCTL,
370+ CCS_TYPE_CHMOD,
371+ CCS_TYPE_CHOWN,
372+ CCS_TYPE_CHGRP,
373+ CCS_MAX_PATH_NUMBER_OPERATION
374+};
375+
376+/* Index numbers for stat(). */
377+enum ccs_path_stat_index {
378+ /* Do not change this order. */
379+ CCS_PATH1,
380+ CCS_PATH1_PARENT,
381+ CCS_PATH2,
382+ CCS_PATH2_PARENT,
383+ CCS_MAX_PATH_STAT
384+};
385+
386+/* Index numbers for /proc/ccs/stat interface. */
387+enum ccs_policy_stat_type {
388+ /* Do not change this order. */
389+ CCS_STAT_POLICY_UPDATES,
390+ CCS_STAT_POLICY_LEARNING, /* == CCS_CONFIG_LEARNING */
391+ CCS_STAT_POLICY_PERMISSIVE, /* == CCS_CONFIG_PERMISSIVE */
392+ CCS_STAT_POLICY_ENFORCING, /* == CCS_CONFIG_ENFORCING */
393+ CCS_MAX_POLICY_STAT
394+};
395+
396+/* Index numbers for profile's PREFERENCE values. */
397+enum ccs_pref_index {
398+ CCS_PREF_MAX_AUDIT_LOG,
399+ CCS_PREF_MAX_LEARNING_ENTRY,
400+ CCS_PREF_ENFORCING_PENALTY,
401+ CCS_MAX_PREF
402+};
403+
404+/* Index numbers for /proc/ccs/ interfaces. */
405+enum ccs_proc_interface_index {
406+ CCS_DOMAINPOLICY,
407+ CCS_EXCEPTIONPOLICY,
408+ CCS_PROCESS_STATUS,
409+ CCS_STAT,
410+ CCS_AUDIT,
411+ CCS_VERSION,
412+ CCS_PROFILE,
413+ CCS_QUERY,
414+ CCS_MANAGER,
415+ CCS_EXECUTE_HANDLER,
416+};
417+
418+/* Index numbers for special mount operations. */
419+enum ccs_special_mount {
420+ CCS_MOUNT_BIND, /* mount --bind /source /dest */
421+ CCS_MOUNT_MOVE, /* mount --move /old /new */
422+ CCS_MOUNT_REMOUNT, /* mount -o remount /dir */
423+ CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
424+ CCS_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */
425+ CCS_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */
426+ CCS_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */
427+ CCS_MAX_SPECIAL_MOUNT
428+};
429+
430+/* Index numbers for type of numeric values. */
431+enum ccs_value_type {
432+ CCS_VALUE_TYPE_INVALID,
433+ CCS_VALUE_TYPE_DECIMAL,
434+ CCS_VALUE_TYPE_OCTAL,
435+ CCS_VALUE_TYPE_HEXADECIMAL,
436+};
437+
438+/* Constants definition for internal use. */
439+
440+/*
441+ * TOMOYO uses this hash only when appending a string into the string table.
442+ * Frequency of appending strings is very low. So we don't need large (e.g.
443+ * 64k) hash size. 256 will be sufficient.
444+ */
445+#define CCS_HASH_BITS 8
446+#define CCS_MAX_HASH (1u << CCS_HASH_BITS)
447+
448+/*
449+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
450+ * Therefore, we don't need SOCK_MAX.
451+ */
452+#define CCS_SOCK_MAX 6
453+
454+/* Size of temporary buffer for execve() operation. */
455+#define CCS_EXEC_TMPSIZE 4096
456+
457+/* Profile number is an integer between 0 and 255. */
458+#define CCS_MAX_PROFILES 256
459+
460+/* Group number is an integer between 0 and 255. */
461+#define CCS_MAX_ACL_GROUPS 256
462+
463+/* Structure definition for internal use. */
464+
465+struct ccs_policy_namespace;
466+
467+/* Common header for holding ACL entries. */
468+struct ccs_acl_head {
469+ struct list_head list;
470+ bool is_deleted;
471+} __attribute__((__packed__));
472+
473+/* Common header for shared entries. */
474+struct ccs_shared_acl_head {
475+ struct list_head list;
476+ unsigned int users;
477+} __attribute__((__packed__));
478+
479+/* Common header for individual entries. */
480+struct ccs_acl_info {
481+ struct list_head list;
482+ struct ccs_condition *cond; /* Maybe NULL. */
483+ bool is_deleted;
484+ u8 type; /* One of values in "enum ccs_acl_entry_type_index". */
485+} __attribute__((__packed__));
486+
487+/* Structure for holding a word. */
488+struct ccs_name_union {
489+ /* Either @filename or @group is NULL. */
490+ const struct ccs_path_info *filename;
491+ struct ccs_group *group;
492+};
493+
494+/* Structure for holding a number. */
495+struct ccs_number_union {
496+ unsigned long values[2];
497+ struct ccs_group *group; /* Maybe NULL. */
498+ /* One of values in "enum ccs_value_type". */
499+ u8 value_type[2];
500+};
501+
502+/* Structure for holding an IP address. */
503+struct ccs_ipaddr_union {
504+ struct in6_addr ip[2]; /* Big endian. */
505+ struct ccs_group *group; /* Pointer to address group. */
506+ bool is_ipv6; /* Valid only if @group == NULL. */
507+};
508+
509+/* Structure for "path_group"/"number_group"/"address_group" directive. */
510+struct ccs_group {
511+ struct ccs_shared_acl_head head;
512+ struct ccs_policy_namespace *ns;
513+ /* Name of group (without leading '@'). */
514+ const struct ccs_path_info *group_name;
515+ /*
516+ * List of "struct ccs_path_group" or "struct ccs_number_group" or
517+ * "struct ccs_address_group".
518+ */
519+ struct list_head member_list;
520+};
521+
522+/* Structure for "path_group" directive. */
523+struct ccs_path_group {
524+ struct ccs_acl_head head;
525+ const struct ccs_path_info *member_name;
526+};
527+
528+/* Structure for "number_group" directive. */
529+struct ccs_number_group {
530+ struct ccs_acl_head head;
531+ struct ccs_number_union number;
532+};
533+
534+/* Structure for "address_group" directive. */
535+struct ccs_address_group {
536+ struct ccs_acl_head head;
537+ /* Structure for holding an IP address. */
538+ struct ccs_ipaddr_union address;
539+};
540+
541+/* Structure for entries which follows "struct ccs_condition". */
542+struct ccs_condition_element {
543+ /*
544+ * Left hand operand. A "struct ccs_argv" for CCS_ARGV_ENTRY, a
545+ * "struct ccs_envp" for CCS_ENVP_ENTRY is attached to the tail
546+ * of the array of this struct.
547+ */
548+ u8 left;
549+ /*
550+ * Right hand operand. A "struct ccs_number_union" for
551+ * CCS_NUMBER_UNION, a "struct ccs_name_union" for CCS_NAME_UNION is
552+ * attached to the tail of the array of this struct.
553+ */
554+ u8 right;
555+ /* Equation operator. True if equals or overlaps, false otherwise. */
556+ bool equals;
557+};
558+
559+/* Structure for optional arguments. */
560+struct ccs_condition {
561+ struct ccs_shared_acl_head head;
562+ u32 size; /* Memory size allocated for this entry. */
563+ u16 condc; /* Number of conditions in this struct. */
564+ u16 numbers_count; /* Number of "struct ccs_number_union values". */
565+ u16 names_count; /* Number of "struct ccs_name_union names". */
566+ u16 argc; /* Number of "struct ccs_argv". */
567+ u16 envc; /* Number of "struct ccs_envp". */
568+ u8 grant_log; /* One of values in "enum ccs_grant_log". */
569+ const struct ccs_path_info *transit; /* Maybe NULL. */
570+ /*
571+ * struct ccs_condition_element condition[condc];
572+ * struct ccs_number_union values[numbers_count];
573+ * struct ccs_name_union names[names_count];
574+ * struct ccs_argv argv[argc];
575+ * struct ccs_envp envp[envc];
576+ */
577+};
578+
579+/*
580+ * Structure for "reset_domain"/"no_reset_domain"/"initialize_domain"/
581+ * "no_initialize_domain"/"keep_domain"/"no_keep_domain" keyword.
582+ */
583+struct ccs_transition_control {
584+ struct ccs_acl_head head;
585+ u8 type; /* One of values in "enum ccs_transition_type" */
586+ bool is_last_name; /* True if the domainname is ccs_last_word(). */
587+ const struct ccs_path_info *domainname; /* Maybe NULL */
588+ const struct ccs_path_info *program; /* Maybe NULL */
589+ struct ccs_policy_namespace *ns;
590+};
591+
592+/* Structure for "aggregator" keyword. */
593+struct ccs_aggregator {
594+ struct ccs_acl_head head;
595+ const struct ccs_path_info *original_name;
596+ const struct ccs_path_info *aggregated_name;
597+ struct ccs_policy_namespace *ns;
598+};
599+
600+/* Structure for "deny_autobind" keyword. */
601+struct ccs_reserved {
602+ struct ccs_acl_head head;
603+ struct ccs_number_union port;
604+ struct ccs_policy_namespace *ns;
605+};
606+
607+/* Structure for policy manager. */
608+struct ccs_manager {
609+ struct ccs_acl_head head;
610+ bool is_domain; /* True if manager is a domainname. */
611+ /* A path to program or a domainname. */
612+ const struct ccs_path_info *manager;
613+};
614+
615+/* Structure for argv[]. */
616+struct ccs_argv {
617+ unsigned long index;
618+ const struct ccs_path_info *value;
619+ bool is_not;
620+};
621+
622+/* Structure for envp[]. */
623+struct ccs_envp {
624+ const struct ccs_path_info *name;
625+ const struct ccs_path_info *value;
626+ bool is_not;
627+};
628+
629+/*
630+ * Structure for "task auto_execute_handler" and "task denied_execute_handler"
631+ * directive.
632+ *
633+ * If "task auto_execute_handler" directive exists and the current process is
634+ * not an execute handler, all execve() requests are replaced by execve()
635+ * requests of a program specified by "task auto_execute_handler" directive.
636+ * If the current process is an execute handler, "task auto_execute_handler"
637+ * and "task denied_execute_handler" directives are ignored.
638+ * The program specified by "task execute_handler" validates execve()
639+ * parameters and executes the original execve() requests if appropriate.
640+ *
641+ * "task denied_execute_handler" directive is used only when execve() request
642+ * was rejected in enforcing mode (i.e. CONFIG::file::execute={ mode=enforcing
643+ * }). The program specified by "task denied_execute_handler" does whatever it
644+ * wants to do (e.g. silently terminate, change firewall settings, redirect the
645+ * user to honey pot etc.).
646+ */
647+struct ccs_handler_acl {
648+ struct ccs_acl_info head; /* type = CCS_TYPE_*_EXECUTE_HANDLER */
649+ const struct ccs_path_info *handler; /* Pointer to single pathname. */
650+};
651+
652+/*
653+ * Structure for "task auto_domain_transition" and
654+ * "task manual_domain_transition" directive.
655+ */
656+struct ccs_task_acl {
657+ struct ccs_acl_info head; /* type = CCS_TYPE_*_TASK_ACL */
658+ /* Pointer to domainname. */
659+ const struct ccs_path_info *domainname;
660+};
661+
662+/*
663+ * Structure for "file execute", "file read", "file write", "file append",
664+ * "file unlink", "file getattr", "file rmdir", "file truncate",
665+ * "file symlink", "file chroot" and "file unmount" directive.
666+ */
667+struct ccs_path_acl {
668+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_ACL */
669+ u16 perm; /* Bitmask of values in "enum ccs_path_acl_index". */
670+ struct ccs_name_union name;
671+};
672+
673+/*
674+ * Structure for "file rename", "file link" and "file pivot_root" directive.
675+ */
676+struct ccs_path2_acl {
677+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH2_ACL */
678+ u8 perm; /* Bitmask of values in "enum ccs_path2_acl_index". */
679+ struct ccs_name_union name1;
680+ struct ccs_name_union name2;
681+};
682+
683+/*
684+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
685+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
686+ */
687+struct ccs_path_number_acl {
688+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_NUMBER_ACL */
689+ u8 perm; /* Bitmask of values in "enum ccs_path_number_acl_index". */
690+ struct ccs_name_union name;
691+ struct ccs_number_union number;
692+};
693+
694+/* Structure for "file mkblock" and "file mkchar" directive. */
695+struct ccs_mkdev_acl {
696+ struct ccs_acl_info head; /* type = CCS_TYPE_MKDEV_ACL */
697+ u8 perm; /* Bitmask of values in "enum ccs_mkdev_acl_index". */
698+ struct ccs_name_union name;
699+ struct ccs_number_union mode;
700+ struct ccs_number_union major;
701+ struct ccs_number_union minor;
702+};
703+
704+/* Structure for "file mount" directive. */
705+struct ccs_mount_acl {
706+ struct ccs_acl_info head; /* type = CCS_TYPE_MOUNT_ACL */
707+ struct ccs_name_union dev_name;
708+ struct ccs_name_union dir_name;
709+ struct ccs_name_union fs_type;
710+ struct ccs_number_union flags;
711+};
712+
713+/* Structure for "misc env" directive in domain policy. */
714+struct ccs_env_acl {
715+ struct ccs_acl_info head; /* type = CCS_TYPE_ENV_ACL */
716+ const struct ccs_path_info *env; /* environment variable */
717+};
718+
719+/* Structure for "capability" directive. */
720+struct ccs_capability_acl {
721+ struct ccs_acl_info head; /* type = CCS_TYPE_CAPABILITY_ACL */
722+ u8 operation; /* One of values in "enum ccs_capability_acl_index". */
723+};
724+
725+/* Structure for "ipc signal" directive. */
726+struct ccs_signal_acl {
727+ struct ccs_acl_info head; /* type = CCS_TYPE_SIGNAL_ACL */
728+ struct ccs_number_union sig;
729+ /* Pointer to destination pattern. */
730+ const struct ccs_path_info *domainname;
731+};
732+
733+/* Structure for "network inet" directive. */
734+struct ccs_inet_acl {
735+ struct ccs_acl_info head; /* type = CCS_TYPE_INET_ACL */
736+ u8 protocol;
737+ u8 perm; /* Bitmask of values in "enum ccs_network_acl_index" */
738+ struct ccs_ipaddr_union address;
739+ struct ccs_number_union port;
740+};
741+
742+/* Structure for "network unix" directive. */
743+struct ccs_unix_acl {
744+ struct ccs_acl_info head; /* type = CCS_TYPE_UNIX_ACL */
745+ u8 protocol;
746+ u8 perm; /* Bitmask of values in "enum ccs_network_acl_index" */
747+ struct ccs_name_union name;
748+};
749+
750+/* Structure for holding string data. */
751+struct ccs_name {
752+ struct ccs_shared_acl_head head;
753+ int size; /* Memory size allocated for this entry. */
754+ struct ccs_path_info entry;
755+};
756+
757+/* Structure for holding a line from /proc/ccs/ interface. */
758+struct ccs_acl_param {
759+ char *namespace;
760+ char *data; /* Unprocessed data. */
761+ struct list_head *list; /* List to add or remove. */
762+ struct ccs_policy_namespace *ns; /* Namespace to use. */
763+ bool is_delete; /* True if it is a delete request. */
764+};
765+
766+/* Structure for /proc/ccs/profile interface. */
767+struct ccs_profile {
768+ const struct ccs_path_info *comment;
769+ u8 default_config;
770+ u8 config[CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX];
771+ unsigned int pref[CCS_MAX_PREF];
772+};
773+
774+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
775+struct ccs_time {
776+ u16 year;
777+ u8 month;
778+ u8 day;
779+ u8 hour;
780+ u8 min;
781+ u8 sec;
782+};
783+
784+/* Structure for policy namespace. */
785+struct ccs_policy_namespace {
786+ /* Profile table. Memory is allocated as needed. */
787+ struct ccs_profile *profile_ptr[CCS_MAX_PROFILES];
788+ /* The global ACL referred by "use_group" keyword. */
789+ struct list_head acl_group[CCS_MAX_ACL_GROUPS];
790+ /* List for connecting to ccs_namespace_list list. */
791+ struct list_head namespace_list;
792+ /* Profile version. Currently only 20100903 is defined. */
793+ unsigned int profile_version;
794+ /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
795+ const char *name;
796+};
797+
798+struct ccs_domain2_info {
799+ struct list_head list;
800+ struct list_head acl_info_list;
801+ /* Name of this domain. Never NULL. */
802+ const struct ccs_path_info *domainname;
803+ u8 profile; /* Profile number to use. */
804+ u8 group; /* Group number to use. */
805+ bool is_deleted; /* Delete flag. */
806+ bool flags[CCS_MAX_DOMAIN_INFO_FLAGS];
807+};
808+
809+struct ccs_io_buffer {
810+ char *data;
811+ struct ccs_policy_namespace *ns;
812+ struct ccs_domain2_info *domain;
813+ struct ccs_domain2_info *print_this_domain_only;
814+ bool is_delete;
815+ bool print_transition_related_only;
816+ bool eof;
817+ bool reset;
818+ u8 type;
819+ u8 acl_group_index;
820+};
821+
822+/* String table for operation mode. */
823+static const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
824+ [CCS_CONFIG_DISABLED] = "disabled",
825+ [CCS_CONFIG_LEARNING] = "learning",
826+ [CCS_CONFIG_PERMISSIVE] = "permissive",
827+ [CCS_CONFIG_ENFORCING] = "enforcing"
828+};
829+
830+/* String table for /proc/ccs/profile interface. */
831+static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
832+ + CCS_MAX_MAC_CATEGORY_INDEX] = {
833+ /* CONFIG::file group */
834+ [CCS_MAC_FILE_EXECUTE] = "execute",
835+ [CCS_MAC_FILE_OPEN] = "open",
836+ [CCS_MAC_FILE_CREATE] = "create",
837+ [CCS_MAC_FILE_UNLINK] = "unlink",
838+ [CCS_MAC_FILE_GETATTR] = "getattr",
839+ [CCS_MAC_FILE_MKDIR] = "mkdir",
840+ [CCS_MAC_FILE_RMDIR] = "rmdir",
841+ [CCS_MAC_FILE_MKFIFO] = "mkfifo",
842+ [CCS_MAC_FILE_MKSOCK] = "mksock",
843+ [CCS_MAC_FILE_TRUNCATE] = "truncate",
844+ [CCS_MAC_FILE_SYMLINK] = "symlink",
845+ [CCS_MAC_FILE_MKBLOCK] = "mkblock",
846+ [CCS_MAC_FILE_MKCHAR] = "mkchar",
847+ [CCS_MAC_FILE_LINK] = "link",
848+ [CCS_MAC_FILE_RENAME] = "rename",
849+ [CCS_MAC_FILE_CHMOD] = "chmod",
850+ [CCS_MAC_FILE_CHOWN] = "chown",
851+ [CCS_MAC_FILE_CHGRP] = "chgrp",
852+ [CCS_MAC_FILE_IOCTL] = "ioctl",
853+ [CCS_MAC_FILE_CHROOT] = "chroot",
854+ [CCS_MAC_FILE_MOUNT] = "mount",
855+ [CCS_MAC_FILE_UMOUNT] = "unmount",
856+ [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
857+ /* CONFIG::misc group */
858+ [CCS_MAC_ENVIRON] = "env",
859+ /* CONFIG::network group */
860+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
861+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
862+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
863+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = "inet_stream_accept",
864+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
865+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
866+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = "inet_dgram_recv",
867+ [CCS_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
868+ [CCS_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
869+ [CCS_MAC_NETWORK_INET_RAW_RECV] = "inet_raw_recv",
870+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
871+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
872+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
873+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
874+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
875+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
876+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = "unix_dgram_recv",
877+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
878+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
879+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
880+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
881+ /* CONFIG::ipc group */
882+ [CCS_MAC_SIGNAL] = "signal",
883+ /* CONFIG::capability group */
884+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = "use_route",
885+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
886+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = "SYS_REBOOT",
887+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = "SYS_VHANGUP",
888+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = "SYS_TIME",
889+ [CCS_MAC_CAPABILITY_SYS_NICE] = "SYS_NICE",
890+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
891+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
892+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
893+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = "SYS_PTRACE",
894+ /* CONFIG group */
895+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE] = "file",
896+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK] = "network",
897+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC] = "misc",
898+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC] = "ipc",
899+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
900+};
901+
902+/* String table for path operation. */
903+static const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
904+ [CCS_TYPE_EXECUTE] = "execute",
905+ [CCS_TYPE_READ] = "read",
906+ [CCS_TYPE_WRITE] = "write",
907+ [CCS_TYPE_APPEND] = "append",
908+ [CCS_TYPE_UNLINK] = "unlink",
909+ [CCS_TYPE_GETATTR] = "getattr",
910+ [CCS_TYPE_RMDIR] = "rmdir",
911+ [CCS_TYPE_TRUNCATE] = "truncate",
912+ [CCS_TYPE_SYMLINK] = "symlink",
913+ [CCS_TYPE_CHROOT] = "chroot",
914+ [CCS_TYPE_UMOUNT] = "unmount",
915+};
916+
917+/* String table for socket's operation. */
918+static const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = {
919+ [CCS_NETWORK_BIND] = "bind",
920+ [CCS_NETWORK_LISTEN] = "listen",
921+ [CCS_NETWORK_CONNECT] = "connect",
922+ [CCS_NETWORK_ACCEPT] = "accept",
923+ [CCS_NETWORK_SEND] = "send",
924+ [CCS_NETWORK_RECV] = "recv",
925+};
926+
927+/* String table for categories. */
928+static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
929+ [CCS_MAC_CATEGORY_FILE] = "file",
930+ [CCS_MAC_CATEGORY_NETWORK] = "network",
931+ [CCS_MAC_CATEGORY_MISC] = "misc",
932+ [CCS_MAC_CATEGORY_IPC] = "ipc",
933+ [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
934+};
935+
936+/* String table for conditions. */
937+static const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
938+ [CCS_TASK_UID] = "task.uid",
939+ [CCS_TASK_EUID] = "task.euid",
940+ [CCS_TASK_SUID] = "task.suid",
941+ [CCS_TASK_FSUID] = "task.fsuid",
942+ [CCS_TASK_GID] = "task.gid",
943+ [CCS_TASK_EGID] = "task.egid",
944+ [CCS_TASK_SGID] = "task.sgid",
945+ [CCS_TASK_FSGID] = "task.fsgid",
946+ [CCS_TASK_PID] = "task.pid",
947+ [CCS_TASK_PPID] = "task.ppid",
948+ [CCS_EXEC_ARGC] = "exec.argc",
949+ [CCS_EXEC_ENVC] = "exec.envc",
950+ [CCS_TYPE_IS_SOCKET] = "socket",
951+ [CCS_TYPE_IS_SYMLINK] = "symlink",
952+ [CCS_TYPE_IS_FILE] = "file",
953+ [CCS_TYPE_IS_BLOCK_DEV] = "block",
954+ [CCS_TYPE_IS_DIRECTORY] = "directory",
955+ [CCS_TYPE_IS_CHAR_DEV] = "char",
956+ [CCS_TYPE_IS_FIFO] = "fifo",
957+ [CCS_MODE_SETUID] = "setuid",
958+ [CCS_MODE_SETGID] = "setgid",
959+ [CCS_MODE_STICKY] = "sticky",
960+ [CCS_MODE_OWNER_READ] = "owner_read",
961+ [CCS_MODE_OWNER_WRITE] = "owner_write",
962+ [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
963+ [CCS_MODE_GROUP_READ] = "group_read",
964+ [CCS_MODE_GROUP_WRITE] = "group_write",
965+ [CCS_MODE_GROUP_EXECUTE] = "group_execute",
966+ [CCS_MODE_OTHERS_READ] = "others_read",
967+ [CCS_MODE_OTHERS_WRITE] = "others_write",
968+ [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
969+ [CCS_TASK_TYPE] = "task.type",
970+ [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
971+ [CCS_EXEC_REALPATH] = "exec.realpath",
972+ [CCS_SYMLINK_TARGET] = "symlink.target",
973+ [CCS_PATH1_UID] = "path1.uid",
974+ [CCS_PATH1_GID] = "path1.gid",
975+ [CCS_PATH1_INO] = "path1.ino",
976+ [CCS_PATH1_MAJOR] = "path1.major",
977+ [CCS_PATH1_MINOR] = "path1.minor",
978+ [CCS_PATH1_PERM] = "path1.perm",
979+ [CCS_PATH1_TYPE] = "path1.type",
980+ [CCS_PATH1_DEV_MAJOR] = "path1.dev_major",
981+ [CCS_PATH1_DEV_MINOR] = "path1.dev_minor",
982+ [CCS_PATH2_UID] = "path2.uid",
983+ [CCS_PATH2_GID] = "path2.gid",
984+ [CCS_PATH2_INO] = "path2.ino",
985+ [CCS_PATH2_MAJOR] = "path2.major",
986+ [CCS_PATH2_MINOR] = "path2.minor",
987+ [CCS_PATH2_PERM] = "path2.perm",
988+ [CCS_PATH2_TYPE] = "path2.type",
989+ [CCS_PATH2_DEV_MAJOR] = "path2.dev_major",
990+ [CCS_PATH2_DEV_MINOR] = "path2.dev_minor",
991+ [CCS_PATH1_PARENT_UID] = "path1.parent.uid",
992+ [CCS_PATH1_PARENT_GID] = "path1.parent.gid",
993+ [CCS_PATH1_PARENT_INO] = "path1.parent.ino",
994+ [CCS_PATH1_PARENT_PERM] = "path1.parent.perm",
995+ [CCS_PATH2_PARENT_UID] = "path2.parent.uid",
996+ [CCS_PATH2_PARENT_GID] = "path2.parent.gid",
997+ [CCS_PATH2_PARENT_INO] = "path2.parent.ino",
998+ [CCS_PATH2_PARENT_PERM] = "path2.parent.perm",
999+};
1000+
1001+/* String table for PREFERENCE keyword. */
1002+static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
1003+ [CCS_PREF_MAX_AUDIT_LOG] = "max_audit_log",
1004+ [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
1005+ [CCS_PREF_ENFORCING_PENALTY] = "enforcing_penalty",
1006+};
1007+
1008+/* Mapping table from "enum ccs_path_acl_index" to "enum ccs_mac_index". */
1009+static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
1010+ [CCS_TYPE_EXECUTE] = CCS_MAC_FILE_EXECUTE,
1011+ [CCS_TYPE_READ] = CCS_MAC_FILE_OPEN,
1012+ [CCS_TYPE_WRITE] = CCS_MAC_FILE_OPEN,
1013+ [CCS_TYPE_APPEND] = CCS_MAC_FILE_OPEN,
1014+ [CCS_TYPE_UNLINK] = CCS_MAC_FILE_UNLINK,
1015+ [CCS_TYPE_GETATTR] = CCS_MAC_FILE_GETATTR,
1016+ [CCS_TYPE_RMDIR] = CCS_MAC_FILE_RMDIR,
1017+ [CCS_TYPE_TRUNCATE] = CCS_MAC_FILE_TRUNCATE,
1018+ [CCS_TYPE_SYMLINK] = CCS_MAC_FILE_SYMLINK,
1019+ [CCS_TYPE_CHROOT] = CCS_MAC_FILE_CHROOT,
1020+ [CCS_TYPE_UMOUNT] = CCS_MAC_FILE_UMOUNT,
1021+};
1022+
1023+/* Mapping table from "enum ccs_mkdev_acl_index" to "enum ccs_mac_index". */
1024+static const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION] = {
1025+ [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
1026+ [CCS_TYPE_MKCHAR] = CCS_MAC_FILE_MKCHAR,
1027+};
1028+
1029+/* Mapping table from "enum ccs_path2_acl_index" to "enum ccs_mac_index". */
1030+static const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
1031+ [CCS_TYPE_LINK] = CCS_MAC_FILE_LINK,
1032+ [CCS_TYPE_RENAME] = CCS_MAC_FILE_RENAME,
1033+ [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
1034+};
1035+
1036+/*
1037+ * Mapping table from "enum ccs_path_number_acl_index" to "enum ccs_mac_index".
1038+ */
1039+static const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
1040+ [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
1041+ [CCS_TYPE_MKDIR] = CCS_MAC_FILE_MKDIR,
1042+ [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
1043+ [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
1044+ [CCS_TYPE_IOCTL] = CCS_MAC_FILE_IOCTL,
1045+ [CCS_TYPE_CHMOD] = CCS_MAC_FILE_CHMOD,
1046+ [CCS_TYPE_CHOWN] = CCS_MAC_FILE_CHOWN,
1047+ [CCS_TYPE_CHGRP] = CCS_MAC_FILE_CHGRP,
1048+};
1049+
1050+/*
1051+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
1052+ * inet domain socket.
1053+ */
1054+static const u8 ccs_inet2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
1055+ [SOCK_STREAM] = {
1056+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_STREAM_BIND,
1057+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_INET_STREAM_LISTEN,
1058+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_INET_STREAM_CONNECT,
1059+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
1060+ },
1061+ [SOCK_DGRAM] = {
1062+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_DGRAM_BIND,
1063+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_DGRAM_SEND,
1064+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_DGRAM_RECV,
1065+ },
1066+ [SOCK_RAW] = {
1067+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_RAW_BIND,
1068+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_RAW_SEND,
1069+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_RAW_RECV,
1070+ },
1071+};
1072+
1073+/*
1074+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
1075+ * unix domain socket.
1076+ */
1077+static const u8 ccs_unix2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
1078+ [SOCK_STREAM] = {
1079+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_STREAM_BIND,
1080+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
1081+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
1082+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
1083+ },
1084+ [SOCK_DGRAM] = {
1085+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
1086+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
1087+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
1088+ },
1089+ [SOCK_SEQPACKET] = {
1090+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
1091+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
1092+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
1093+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
1094+ },
1095+};
1096+
1097+/* String table for socket's protocols. */
1098+static const char * const ccs_proto_keyword[CCS_SOCK_MAX] = {
1099+ [SOCK_STREAM] = "stream",
1100+ [SOCK_DGRAM] = "dgram",
1101+ [SOCK_RAW] = "raw",
1102+ [SOCK_SEQPACKET] = "seqpacket",
1103+ [0] = " ", /* Dummy for avoiding NULL pointer dereference. */
1104+ [4] = " ", /* Dummy for avoiding NULL pointer dereference. */
1105+};
1106+
1107+/*
1108+ * Mapping table from "enum ccs_capability_acl_index" to "enum ccs_mac_index".
1109+ */
1110+static const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX] = {
1111+ [CCS_USE_ROUTE_SOCKET] = CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
1112+ [CCS_USE_PACKET_SOCKET] = CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
1113+ [CCS_SYS_REBOOT] = CCS_MAC_CAPABILITY_SYS_REBOOT,
1114+ [CCS_SYS_VHANGUP] = CCS_MAC_CAPABILITY_SYS_VHANGUP,
1115+ [CCS_SYS_SETTIME] = CCS_MAC_CAPABILITY_SYS_SETTIME,
1116+ [CCS_SYS_NICE] = CCS_MAC_CAPABILITY_SYS_NICE,
1117+ [CCS_SYS_SETHOSTNAME] = CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
1118+ [CCS_USE_KERNEL_MODULE] = CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
1119+ [CCS_SYS_KEXEC_LOAD] = CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
1120+ [CCS_SYS_PTRACE] = CCS_MAC_CAPABILITY_SYS_PTRACE,
1121+};
1122+
1123+/* String table for /proc/ccs/stat interface. */
1124+static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
1125+ [CCS_MEMORY_POLICY] = "policy:",
1126+ [CCS_MEMORY_AUDIT] = "audit log:",
1127+ [CCS_MEMORY_QUERY] = "query message:",
1128+};
1129+
1130+/* String table for domain transition control keywords. */
1131+static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
1132+ [CCS_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ",
1133+ [CCS_TRANSITION_CONTROL_RESET] = "reset_domain ",
1134+ [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
1135+ [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
1136+ [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
1137+ [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
1138+};
1139+
1140+/* String table for grouping keywords. */
1141+static const char * const ccs_group_name[CCS_MAX_GROUP] = {
1142+ [CCS_PATH_GROUP] = "path_group ",
1143+ [CCS_NUMBER_GROUP] = "number_group ",
1144+ [CCS_ADDRESS_GROUP] = "address_group ",
1145+};
1146+
1147+/* String table for domain flags. */
1148+static const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
1149+ [CCS_DIF_QUOTA_WARNED] = "quota_exceeded\n",
1150+ [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
1151+};
1152+
1153+/* Mapping table from "enum ccs_mac_index" to "enum ccs_mac_category_index". */
1154+static const u8 ccs_index2category[CCS_MAX_MAC_INDEX] = {
1155+ /* CONFIG::file group */
1156+ [CCS_MAC_FILE_EXECUTE] = CCS_MAC_CATEGORY_FILE,
1157+ [CCS_MAC_FILE_OPEN] = CCS_MAC_CATEGORY_FILE,
1158+ [CCS_MAC_FILE_CREATE] = CCS_MAC_CATEGORY_FILE,
1159+ [CCS_MAC_FILE_UNLINK] = CCS_MAC_CATEGORY_FILE,
1160+ [CCS_MAC_FILE_GETATTR] = CCS_MAC_CATEGORY_FILE,
1161+ [CCS_MAC_FILE_MKDIR] = CCS_MAC_CATEGORY_FILE,
1162+ [CCS_MAC_FILE_RMDIR] = CCS_MAC_CATEGORY_FILE,
1163+ [CCS_MAC_FILE_MKFIFO] = CCS_MAC_CATEGORY_FILE,
1164+ [CCS_MAC_FILE_MKSOCK] = CCS_MAC_CATEGORY_FILE,
1165+ [CCS_MAC_FILE_TRUNCATE] = CCS_MAC_CATEGORY_FILE,
1166+ [CCS_MAC_FILE_SYMLINK] = CCS_MAC_CATEGORY_FILE,
1167+ [CCS_MAC_FILE_MKBLOCK] = CCS_MAC_CATEGORY_FILE,
1168+ [CCS_MAC_FILE_MKCHAR] = CCS_MAC_CATEGORY_FILE,
1169+ [CCS_MAC_FILE_LINK] = CCS_MAC_CATEGORY_FILE,
1170+ [CCS_MAC_FILE_RENAME] = CCS_MAC_CATEGORY_FILE,
1171+ [CCS_MAC_FILE_CHMOD] = CCS_MAC_CATEGORY_FILE,
1172+ [CCS_MAC_FILE_CHOWN] = CCS_MAC_CATEGORY_FILE,
1173+ [CCS_MAC_FILE_CHGRP] = CCS_MAC_CATEGORY_FILE,
1174+ [CCS_MAC_FILE_IOCTL] = CCS_MAC_CATEGORY_FILE,
1175+ [CCS_MAC_FILE_CHROOT] = CCS_MAC_CATEGORY_FILE,
1176+ [CCS_MAC_FILE_MOUNT] = CCS_MAC_CATEGORY_FILE,
1177+ [CCS_MAC_FILE_UMOUNT] = CCS_MAC_CATEGORY_FILE,
1178+ [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
1179+ /* CONFIG::misc group */
1180+ [CCS_MAC_ENVIRON] = CCS_MAC_CATEGORY_MISC,
1181+ /* CONFIG::network group */
1182+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
1183+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
1184+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
1185+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
1186+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
1187+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
1188+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
1189+ [CCS_MAC_NETWORK_INET_RAW_BIND] = CCS_MAC_CATEGORY_NETWORK,
1190+ [CCS_MAC_NETWORK_INET_RAW_SEND] = CCS_MAC_CATEGORY_NETWORK,
1191+ [CCS_MAC_NETWORK_INET_RAW_RECV] = CCS_MAC_CATEGORY_NETWORK,
1192+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
1193+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
1194+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
1195+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
1196+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
1197+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
1198+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
1199+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = CCS_MAC_CATEGORY_NETWORK,
1200+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
1201+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
1202+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
1203+ /* CONFIG::ipc group */
1204+ [CCS_MAC_SIGNAL] = CCS_MAC_CATEGORY_IPC,
1205+ /* CONFIG::capability group */
1206+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
1207+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
1208+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = CCS_MAC_CATEGORY_CAPABILITY,
1209+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = CCS_MAC_CATEGORY_CAPABILITY,
1210+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = CCS_MAC_CATEGORY_CAPABILITY,
1211+ [CCS_MAC_CAPABILITY_SYS_NICE] = CCS_MAC_CATEGORY_CAPABILITY,
1212+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = CCS_MAC_CATEGORY_CAPABILITY,
1213+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = CCS_MAC_CATEGORY_CAPABILITY,
1214+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = CCS_MAC_CATEGORY_CAPABILITY,
1215+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = CCS_MAC_CATEGORY_CAPABILITY,
1216+};
1217+
1218+static struct ccs_io_buffer head;
1219+static struct ccs_domain2_info ccs_kernel_domain;
1220+static struct ccs_policy_namespace ccs_kernel_namespace;
1221+static LIST_HEAD(ccs_domain_list);
1222+static LIST_HEAD(ccs_manager_list);
1223+static LIST_HEAD(ccs_path_group);
1224+static LIST_HEAD(ccs_number_group);
1225+static LIST_HEAD(ccs_address_group);
1226+static LIST_HEAD(ccs_transition_list);
1227+static LIST_HEAD(ccs_aggregator_list);
1228+static LIST_HEAD(ccs_reserved_list);
1229+static LIST_HEAD(ccs_namespace_list);
1230+static bool ccs_namespace_enabled;
1231+static struct list_head ccs_name_list[CCS_MAX_HASH];
1232+static unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
1233+
1234+/**
1235+ * ccs_put_condition - Drop reference on "struct ccs_condition".
1236+ *
1237+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
1238+ *
1239+ * Returns nothing.
1240+ */
1241+static inline void ccs_put_condition(struct ccs_condition *cond)
1242+{
1243+ if (cond)
1244+ cond->head.users--;
1245+}
1246+
1247+/**
1248+ * ccs_put_group - Drop reference on "struct ccs_group".
1249+ *
1250+ * @group: Pointer to "struct ccs_group". Maybe NULL.
1251+ *
1252+ * Returns nothing.
1253+ */
1254+static inline void ccs_put_group(struct ccs_group *group)
1255+{
1256+ if (group)
1257+ group->head.users--;
1258+}
1259+
1260+/**
1261+ * ccs_put_name - Drop reference on "struct ccs_name".
1262+ *
1263+ * @name: Pointer to "struct ccs_path_info". Maybe NULL.
1264+ *
1265+ * Returns nothing.
1266+ */
1267+static inline void ccs_put_name(const struct ccs_path_info *name)
1268+{
1269+ if (name)
1270+ container_of(name, struct ccs_name, entry)->head.users--;
1271+}
1272+
1273+/**
1274+ * ccs_put_name_union - Drop reference on "struct ccs_name_union".
1275+ *
1276+ * @ptr: Pointer to "struct ccs_name_union".
1277+ *
1278+ * Returns nothing.
1279+ */
1280+static void ccs_put_name_union(struct ccs_name_union *ptr)
1281+{
1282+ ccs_put_group(ptr->group);
1283+ ccs_put_name(ptr->filename);
1284+}
1285+
1286+/**
1287+ * ccs_put_number_union - Drop reference on "struct ccs_number_union".
1288+ *
1289+ * @ptr: Pointer to "struct ccs_number_union".
1290+ *
1291+ * Returns nothing.
1292+ */
1293+static void ccs_put_number_union(struct ccs_number_union *ptr)
1294+{
1295+ ccs_put_group(ptr->group);
1296+}
1297+
1298+/**
1299+ * ccs_del_condition - Delete members in "struct ccs_condition".
1300+ *
1301+ * @element: Pointer to "struct list_head".
1302+ *
1303+ * Returns nothing.
1304+ */
1305+static void ccs_del_condition(struct list_head *element)
1306+{
1307+ struct ccs_condition *cond = container_of(element, typeof(*cond),
1308+ head.list);
1309+ const u16 condc = cond->condc;
1310+ const u16 numbers_count = cond->numbers_count;
1311+ const u16 names_count = cond->names_count;
1312+ const u16 argc = cond->argc;
1313+ const u16 envc = cond->envc;
1314+ unsigned int i;
1315+ const struct ccs_condition_element *condp
1316+ = (const struct ccs_condition_element *) (cond + 1);
1317+ struct ccs_number_union *numbers_p
1318+ = (struct ccs_number_union *) (condp + condc);
1319+ struct ccs_name_union *names_p
1320+ = (struct ccs_name_union *) (numbers_p + numbers_count);
1321+ const struct ccs_argv *argv
1322+ = (const struct ccs_argv *) (names_p + names_count);
1323+ const struct ccs_envp *envp
1324+ = (const struct ccs_envp *) (argv + argc);
1325+ for (i = 0; i < numbers_count; i++)
1326+ ccs_put_number_union(numbers_p++);
1327+ for (i = 0; i < names_count; i++)
1328+ ccs_put_name_union(names_p++);
1329+ for (i = 0; i < argc; argv++, i++)
1330+ ccs_put_name(argv->value);
1331+ for (i = 0; i < envc; envp++, i++) {
1332+ ccs_put_name(envp->name);
1333+ ccs_put_name(envp->value);
1334+ }
1335+ ccs_put_name(cond->transit);
1336+}
1337+
1338+/**
1339+ * ccs_yesno - Return "yes" or "no".
1340+ *
1341+ * @value: Bool value.
1342+ *
1343+ * Returns "yes" if @value is not 0, "no" otherwise.
1344+ */
1345+static const char *ccs_yesno(const unsigned int value)
1346+{
1347+ return value ? "yes" : "no";
1348+}
1349+
1350+/**
1351+ * ccs_same_name_union - Check for duplicated "struct ccs_name_union" entry.
1352+ *
1353+ * @a: Pointer to "struct ccs_name_union".
1354+ * @b: Pointer to "struct ccs_name_union".
1355+ *
1356+ * Returns true if @a == @b, false otherwise.
1357+ */
1358+static inline bool ccs_same_name_union(const struct ccs_name_union *a,
1359+ const struct ccs_name_union *b)
1360+{
1361+ return a->filename == b->filename && a->group == b->group;
1362+}
1363+
1364+/**
1365+ * ccs_same_number_union - Check for duplicated "struct ccs_number_union" entry.
1366+ *
1367+ * @a: Pointer to "struct ccs_number_union".
1368+ * @b: Pointer to "struct ccs_number_union".
1369+ *
1370+ * Returns true if @a == @b, false otherwise.
1371+ */
1372+static inline bool ccs_same_number_union(const struct ccs_number_union *a,
1373+ const struct ccs_number_union *b)
1374+{
1375+ return a->values[0] == b->values[0] && a->values[1] == b->values[1] &&
1376+ a->group == b->group && a->value_type[0] == b->value_type[0] &&
1377+ a->value_type[1] == b->value_type[1];
1378+}
1379+
1380+/**
1381+ * ccs_same_ipaddr_union - Check for duplicated "struct ccs_ipaddr_union" entry.
1382+ *
1383+ * @a: Pointer to "struct ccs_ipaddr_union".
1384+ * @b: Pointer to "struct ccs_ipaddr_union".
1385+ *
1386+ * Returns true if @a == @b, false otherwise.
1387+ */
1388+static inline bool ccs_same_ipaddr_union(const struct ccs_ipaddr_union *a,
1389+ const struct ccs_ipaddr_union *b)
1390+{
1391+ return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group &&
1392+ a->is_ipv6 == b->is_ipv6;
1393+}
1394+
1395+/**
1396+ * ccs_partial_name_hash - Hash name.
1397+ *
1398+ * @c: A unsigned long value.
1399+ * @prevhash: A previous hash value.
1400+ *
1401+ * Returns new hash value.
1402+ *
1403+ * This function is copied from partial_name_hash() in the kernel source.
1404+ */
1405+static inline unsigned long ccs_partial_name_hash(unsigned long c,
1406+ unsigned long prevhash)
1407+{
1408+ return (prevhash + (c << 4) + (c >> 4)) * 11;
1409+}
1410+
1411+/**
1412+ * ccs_full_name_hash - Hash full name.
1413+ *
1414+ * @name: Pointer to "const unsigned char".
1415+ * @len: Length of @name in byte.
1416+ *
1417+ * Returns hash value.
1418+ *
1419+ * This function is copied from full_name_hash() in the kernel source.
1420+ */
1421+static inline unsigned int ccs_full_name_hash(const unsigned char *name,
1422+ unsigned int len)
1423+{
1424+ unsigned long hash = 0;
1425+ while (len--)
1426+ hash = ccs_partial_name_hash(*name++, hash);
1427+ return (unsigned int) hash;
1428+}
1429+
1430+/**
1431+ * ccs_get_name - Allocate memory for string data.
1432+ *
1433+ * @name: The string to store into the permernent memory.
1434+ *
1435+ * Returns pointer to "struct ccs_path_info" on success, abort otherwise.
1436+ */
1437+static const struct ccs_path_info *ccs_get_name(const char *name)
1438+{
1439+ struct ccs_name *ptr;
1440+ unsigned int hash;
1441+ int len;
1442+ int allocated_len;
1443+ struct list_head *head;
1444+
1445+ if (!name)
1446+ name = "";
1447+ len = strlen(name) + 1;
1448+ hash = ccs_full_name_hash((const unsigned char *) name, len - 1);
1449+ head = &ccs_name_list[hash % CCS_MAX_HASH];
1450+ list_for_each_entry(ptr, head, head.list) {
1451+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
1452+ continue;
1453+ ptr->head.users++;
1454+ goto out;
1455+ }
1456+ allocated_len = sizeof(*ptr) + len;
1457+ ptr = ccs_malloc(allocated_len);
1458+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
1459+ memmove((char *) ptr->entry.name, name, len);
1460+ ptr->head.users = 1;
1461+ ccs_fill_path_info(&ptr->entry);
1462+ ptr->size = allocated_len;
1463+ list_add_tail(&ptr->head.list, head);
1464+out:
1465+ return &ptr->entry;
1466+}
1467+
1468+
1469+/**
1470+ * ccs_commit_ok - Allocate memory and check memory quota.
1471+ *
1472+ * @data: Data to copy from.
1473+ * @size: Size in byte.
1474+ *
1475+ * Returns pointer to allocated memory on success, abort otherwise.
1476+ * @data is zero-cleared on success.
1477+ */
1478+static void *ccs_commit_ok(void *data, const unsigned int size)
1479+{
1480+ void *ptr = ccs_malloc(size);
1481+ memmove(ptr, data, size);
1482+ memset(data, 0, size);
1483+ return ptr;
1484+}
1485+
1486+/**
1487+ * ccs_permstr - Find permission keywords.
1488+ *
1489+ * @string: String representation for permissions in foo/bar/buz format.
1490+ * @keyword: Keyword to find from @string/
1491+ *
1492+ * Returns ture if @keyword was found in @string, false otherwise.
1493+ *
1494+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
1495+ */
1496+static bool ccs_permstr(const char *string, const char *keyword)
1497+{
1498+ const char *cp = strstr(string, keyword);
1499+ if (cp)
1500+ return cp == string || *(cp - 1) == '/';
1501+ return false;
1502+}
1503+
1504+/**
1505+ * ccs_read_token - Read a word from a line.
1506+ *
1507+ * @param: Pointer to "struct ccs_acl_param".
1508+ *
1509+ * Returns a word on success, "" otherwise.
1510+ *
1511+ * To allow the caller to skip NULL check, this function returns "" rather than
1512+ * NULL if there is no more words to read.
1513+ */
1514+static char *ccs_read_token(struct ccs_acl_param *param)
1515+{
1516+ char *pos = param->data;
1517+ char *del = strchr(pos, ' ');
1518+ if (del)
1519+ *del++ = '\0';
1520+ else
1521+ del = pos + strlen(pos);
1522+ param->data = del;
1523+ return pos;
1524+}
1525+
1526+/**
1527+ * ccs_get_domainname - Read a domainname from a line.
1528+ *
1529+ * @param: Pointer to "struct ccs_acl_param".
1530+ *
1531+ * Returns a domainname on success, NULL otherwise.
1532+ */
1533+static const struct ccs_path_info *ccs_get_domainname
1534+(struct ccs_acl_param *param)
1535+{
1536+ char *start = param->data;
1537+ char *pos = start;
1538+ while (*pos) {
1539+ if (*pos++ != ' ' || *pos++ == '/')
1540+ continue;
1541+ pos -= 2;
1542+ *pos++ = '\0';
1543+ break;
1544+ }
1545+ param->data = pos;
1546+ if (ccs_correct_domain(start))
1547+ return ccs_get_name(start);
1548+ return NULL;
1549+}
1550+
1551+/**
1552+ * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
1553+ *
1554+ * @param: Pointer to "struct ccs_acl_param".
1555+ * @list: List to use.
1556+ *
1557+ * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1558+ */
1559+static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
1560+ struct list_head *list)
1561+{
1562+ struct ccs_group e = { };
1563+ struct ccs_group *group = NULL;
1564+ const char *group_name = ccs_read_token(param);
1565+ bool found = false;
1566+ if (!ccs_correct_word(group_name))
1567+ return NULL;
1568+ e.ns = param->ns;
1569+ e.group_name = ccs_get_name(group_name);
1570+ list_for_each_entry(group, list, head.list) {
1571+ if (e.ns != group->ns || e.group_name != group->group_name)
1572+ continue;
1573+ group->head.users++;
1574+ found = true;
1575+ break;
1576+ }
1577+ if (!found) {
1578+ struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1579+ INIT_LIST_HEAD(&entry->member_list);
1580+ entry->head.users = 1;
1581+ list_add_tail(&entry->head.list, list);
1582+ group = entry;
1583+ found = true;
1584+ }
1585+ ccs_put_name(e.group_name);
1586+ return found ? group : NULL;
1587+}
1588+
1589+/**
1590+ * ccs_parse_ulong - Parse an "unsigned long" value.
1591+ *
1592+ * @result: Pointer to "unsigned long".
1593+ * @str: Pointer to string to parse.
1594+ *
1595+ * Returns one of values in "enum ccs_value_type".
1596+ *
1597+ * The @src is updated to point the first character after the value
1598+ * on success.
1599+ */
1600+static u8 ccs_parse_ulong(unsigned long *result, char **str)
1601+{
1602+ const char *cp = *str;
1603+ char *ep;
1604+ int base = 10;
1605+ if (*cp == '0') {
1606+ char c = *(cp + 1);
1607+ if (c == 'x' || c == 'X') {
1608+ base = 16;
1609+ cp += 2;
1610+ } else if (c >= '0' && c <= '7') {
1611+ base = 8;
1612+ cp++;
1613+ }
1614+ }
1615+ *result = strtoul(cp, &ep, base);
1616+ if (cp == ep)
1617+ return CCS_VALUE_TYPE_INVALID;
1618+ *str = ep;
1619+ switch (base) {
1620+ case 16:
1621+ return CCS_VALUE_TYPE_HEXADECIMAL;
1622+ case 8:
1623+ return CCS_VALUE_TYPE_OCTAL;
1624+ default:
1625+ return CCS_VALUE_TYPE_DECIMAL;
1626+ }
1627+}
1628+
1629+/**
1630+ * ccs_parse_name_union - Parse a ccs_name_union.
1631+ *
1632+ * @param: Pointer to "struct ccs_acl_param".
1633+ * @ptr: Pointer to "struct ccs_name_union".
1634+ *
1635+ * Returns true on success, false otherwise.
1636+ */
1637+static bool ccs_parse_name_union(struct ccs_acl_param *param,
1638+ struct ccs_name_union *ptr)
1639+{
1640+ char *filename;
1641+ if (param->data[0] == '@') {
1642+ param->data++;
1643+ ptr->group = ccs_get_group(param, &ccs_path_group);
1644+ return ptr->group != NULL;
1645+ }
1646+ filename = ccs_read_token(param);
1647+ if (!ccs_correct_word(filename))
1648+ return false;
1649+ ptr->filename = ccs_get_name(filename);
1650+ return true;
1651+}
1652+
1653+/**
1654+ * ccs_parse_number_union - Parse a ccs_number_union.
1655+ *
1656+ * @param: Pointer to "struct ccs_acl_param".
1657+ * @ptr: Pointer to "struct ccs_number_union".
1658+ *
1659+ * Returns true on success, false otherwise.
1660+ */
1661+static bool ccs_parse_number_union(struct ccs_acl_param *param,
1662+ struct ccs_number_union *ptr)
1663+{
1664+ char *data;
1665+ u8 type;
1666+ unsigned long v;
1667+ memset(ptr, 0, sizeof(*ptr));
1668+ if (param->data[0] == '@') {
1669+ param->data++;
1670+ ptr->group = ccs_get_group(param, &ccs_number_group);
1671+ return ptr->group != NULL;
1672+ }
1673+ data = ccs_read_token(param);
1674+ type = ccs_parse_ulong(&v, &data);
1675+ if (type == CCS_VALUE_TYPE_INVALID)
1676+ return false;
1677+ ptr->values[0] = v;
1678+ ptr->value_type[0] = type;
1679+ if (!*data) {
1680+ ptr->values[1] = v;
1681+ ptr->value_type[1] = type;
1682+ return true;
1683+ }
1684+ if (*data++ != '-')
1685+ return false;
1686+ type = ccs_parse_ulong(&v, &data);
1687+ if (type == CCS_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
1688+ return false;
1689+ ptr->values[1] = v;
1690+ ptr->value_type[1] = type;
1691+ return true;
1692+}
1693+
1694+/**
1695+ * ccs_find_domain2 - Find a domain by the given name.
1696+ *
1697+ * @domainname: The domainname to find.
1698+ *
1699+ * Returns pointer to "struct ccs_domain2_info" if found, NULL otherwise.
1700+ */
1701+static struct ccs_domain2_info *ccs_find_domain2(const char *domainname)
1702+{
1703+ struct ccs_domain2_info *domain;
1704+ struct ccs_path_info name;
1705+ name.name = domainname;
1706+ ccs_fill_path_info(&name);
1707+ list_for_each_entry(domain, &ccs_domain_list, list) {
1708+ if (!domain->is_deleted &&
1709+ !ccs_pathcmp(&name, domain->domainname))
1710+ return domain;
1711+ }
1712+ return NULL;
1713+}
1714+
1715+static int client_fd = EOF;
1716+
1717+static void cprintf(const char *fmt, ...)
1718+ __attribute__ ((format(printf, 1, 2)));
1719+
1720+/**
1721+ * cprintf - printf() over socket.
1722+ *
1723+ * @fmt: The printf()'s format string, followed by parameters.
1724+ *
1725+ * Returns nothing.
1726+ */
1727+static void cprintf(const char *fmt, ...)
1728+{
1729+ va_list args;
1730+ static char *buffer = NULL;
1731+ static unsigned int buffer_len = 0;
1732+ static unsigned int buffer_pos = 0;
1733+ int len;
1734+ if (head.reset) {
1735+ head.reset = false;
1736+ buffer_pos = 0;
1737+ }
1738+ while (1) {
1739+ va_start(args, fmt);
1740+ len = vsnprintf(buffer + buffer_pos, buffer_len - buffer_pos,
1741+ fmt, args);
1742+ va_end(args);
1743+ if (len < 0)
1744+ _exit(1);
1745+ if (buffer_pos + len < buffer_len) {
1746+ buffer_pos += len;
1747+ break;
1748+ }
1749+ buffer_len = buffer_pos + len + 4096;
1750+ buffer = ccs_realloc(buffer, buffer_len);
1751+ }
1752+ if (len && buffer_pos < 1048576)
1753+ return;
1754+ /*
1755+ * Reader might close connection without reading until EOF.
1756+ * In that case, we should not call _exit() because offline daemon does
1757+ * not call fork() for each accept()ed socket connection.
1758+ */
1759+ if (write(client_fd, buffer, buffer_pos) != buffer_pos) {
1760+ close(client_fd);
1761+ client_fd = EOF;
1762+ }
1763+ buffer_pos = 0;
1764+}
1765+
1766+/**
1767+ * ccs_update_policy - Update an entry for exception policy.
1768+ *
1769+ * @new_entry: Pointer to "struct ccs_acl_info".
1770+ * @size: Size of @new_entry in bytes.
1771+ * @param: Pointer to "struct ccs_acl_param".
1772+ * @check_duplicate: Callback function to find duplicated entry.
1773+ *
1774+ * Returns 0 on success, negative value otherwise.
1775+ */
1776+static int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
1777+ struct ccs_acl_param *param,
1778+ bool (*check_duplicate)
1779+ (const struct ccs_acl_head *,
1780+ const struct ccs_acl_head *))
1781+{
1782+ int error = param->is_delete ? -ENOENT : -ENOMEM;
1783+ struct ccs_acl_head *entry;
1784+ struct list_head *list = param->list;
1785+ list_for_each_entry(entry, list, list) {
1786+ if (!check_duplicate(entry, new_entry))
1787+ continue;
1788+ entry->is_deleted = param->is_delete;
1789+ error = 0;
1790+ break;
1791+ }
1792+ if (error && !param->is_delete) {
1793+ entry = ccs_commit_ok(new_entry, size);
1794+ list_add_tail(&entry->list, list);
1795+ error = 0;
1796+ }
1797+ return error;
1798+}
1799+
1800+/* List of "struct ccs_condition". */
1801+static LIST_HEAD(ccs_condition_list);
1802+
1803+/**
1804+ * ccs_get_dqword - ccs_get_name() for a quoted string.
1805+ *
1806+ * @start: String to save.
1807+ *
1808+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1809+ */
1810+static const struct ccs_path_info *ccs_get_dqword(char *start)
1811+{
1812+ char *cp = start + strlen(start) - 1;
1813+ if (cp == start || *start++ != '"' || *cp != '"')
1814+ return NULL;
1815+ *cp = '\0';
1816+ if (*start && !ccs_correct_word(start))
1817+ return NULL;
1818+ return ccs_get_name(start);
1819+}
1820+
1821+/**
1822+ * ccs_parse_name_union_quoted - Parse a quoted word.
1823+ *
1824+ * @param: Pointer to "struct ccs_acl_param".
1825+ * @ptr: Pointer to "struct ccs_name_union".
1826+ *
1827+ * Returns true on success, false otherwise.
1828+ */
1829+static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
1830+ struct ccs_name_union *ptr)
1831+{
1832+ char *filename = param->data;
1833+ if (*filename == '@')
1834+ return ccs_parse_name_union(param, ptr);
1835+ ptr->filename = ccs_get_dqword(filename);
1836+ return ptr->filename != NULL;
1837+}
1838+
1839+/**
1840+ * ccs_parse_argv - Parse an argv[] condition part.
1841+ *
1842+ * @left: Lefthand value.
1843+ * @right: Righthand value.
1844+ * @argv: Pointer to "struct ccs_argv".
1845+ *
1846+ * Returns true on success, false otherwise.
1847+ */
1848+static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv)
1849+{
1850+ if (ccs_parse_ulong(&argv->index, &left) != CCS_VALUE_TYPE_DECIMAL ||
1851+ *left++ != ']' || *left)
1852+ return false;
1853+ argv->value = ccs_get_dqword(right);
1854+ return argv->value != NULL;
1855+}
1856+
1857+/**
1858+ * ccs_parse_envp - Parse an envp[] condition part.
1859+ *
1860+ * @left: Lefthand value.
1861+ * @right: Righthand value.
1862+ * @envp: Pointer to "struct ccs_envp".
1863+ *
1864+ * Returns true on success, false otherwise.
1865+ */
1866+static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp)
1867+{
1868+ const struct ccs_path_info *name;
1869+ const struct ccs_path_info *value;
1870+ char *cp = left + strlen(left) - 1;
1871+ if (*cp-- != ']' || *cp != '"')
1872+ goto out;
1873+ *cp = '\0';
1874+ if (!ccs_correct_word(left))
1875+ goto out;
1876+ name = ccs_get_name(left);
1877+ if (!strcmp(right, "NULL")) {
1878+ value = NULL;
1879+ } else {
1880+ value = ccs_get_dqword(right);
1881+ if (!value) {
1882+ ccs_put_name(name);
1883+ goto out;
1884+ }
1885+ }
1886+ envp->name = name;
1887+ envp->value = value;
1888+ return true;
1889+out:
1890+ return false;
1891+}
1892+
1893+/**
1894+ * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1895+ *
1896+ * @a: Pointer to "struct ccs_condition".
1897+ * @b: Pointer to "struct ccs_condition".
1898+ *
1899+ * Returns true if @a == @b, false otherwise.
1900+ */
1901+static inline bool ccs_same_condition(const struct ccs_condition *a,
1902+ const struct ccs_condition *b)
1903+{
1904+ return a->size == b->size && a->condc == b->condc &&
1905+ a->numbers_count == b->numbers_count &&
1906+ a->names_count == b->names_count &&
1907+ a->argc == b->argc && a->envc == b->envc &&
1908+ a->grant_log == b->grant_log && a->transit == b->transit &&
1909+ !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1910+}
1911+
1912+/**
1913+ * ccs_condition_type - Get condition type.
1914+ *
1915+ * @word: Keyword string.
1916+ *
1917+ * Returns one of values in "enum ccs_conditions_index" on success,
1918+ * CCS_MAX_CONDITION_KEYWORD otherwise.
1919+ */
1920+static u8 ccs_condition_type(const char *word)
1921+{
1922+ u8 i;
1923+ for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
1924+ if (!strcmp(word, ccs_condition_keyword[i]))
1925+ break;
1926+ }
1927+ return i;
1928+}
1929+
1930+/* Define this to enable debug mode. */
1931+/* #define DEBUG_CONDITION */
1932+
1933+#ifdef DEBUG_CONDITION
1934+#define dprintk printk
1935+#else
1936+#define dprintk(...) do { } while (0)
1937+#endif
1938+
1939+/**
1940+ * ccs_commit_condition - Commit "struct ccs_condition".
1941+ *
1942+ * @entry: Pointer to "struct ccs_condition".
1943+ *
1944+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1945+ *
1946+ * This function merges duplicated entries. This function returns NULL if
1947+ * @entry is not duplicated but memory quota for policy has exceeded.
1948+ */
1949+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1950+{
1951+ struct ccs_condition *ptr;
1952+ bool found = false;
1953+ list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1954+ if (!ccs_same_condition(ptr, entry))
1955+ continue;
1956+ /* Same entry found. Share this entry. */
1957+ ptr->head.users++;
1958+ found = true;
1959+ break;
1960+ }
1961+ if (!found) {
1962+ if (entry) {
1963+ entry->head.users = 1;
1964+ list_add(&entry->head.list, &ccs_condition_list);
1965+ } else {
1966+ found = true;
1967+ ptr = NULL;
1968+ }
1969+ }
1970+ if (found) {
1971+ ccs_del_condition(&entry->head.list);
1972+ free(entry);
1973+ entry = ptr;
1974+ }
1975+ return entry;
1976+}
1977+
1978+/**
1979+ * ccs_get_condition - Parse condition part.
1980+ *
1981+ * @param: Pointer to "struct ccs_acl_param".
1982+ *
1983+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1984+ */
1985+static struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param)
1986+{
1987+ struct ccs_condition *entry = NULL;
1988+ struct ccs_condition_element *condp = NULL;
1989+ struct ccs_number_union *numbers_p = NULL;
1990+ struct ccs_name_union *names_p = NULL;
1991+ struct ccs_argv *argv = NULL;
1992+ struct ccs_envp *envp = NULL;
1993+ struct ccs_condition e = { };
1994+ char * const start_of_string = param->data;
1995+ char * const end_of_string = start_of_string + strlen(start_of_string);
1996+ char *pos;
1997+rerun:
1998+ pos = start_of_string;
1999+ while (1) {
2000+ u8 left = -1;
2001+ u8 right = -1;
2002+ char *left_word = pos;
2003+ char *cp;
2004+ char *right_word;
2005+ bool is_not;
2006+ if (!*left_word)
2007+ break;
2008+ /*
2009+ * Since left-hand condition does not allow use of "path_group"
2010+ * or "number_group" and environment variable's names do not
2011+ * accept '=', it is guaranteed that the original line consists
2012+ * of one or more repetition of $left$operator$right blocks
2013+ * where "$left is free from '=' and ' '" and "$operator is
2014+ * either '=' or '!='" and "$right is free from ' '".
2015+ * Therefore, we can reconstruct the original line at the end
2016+ * of dry run even if we overwrite $operator with '\0'.
2017+ */
2018+ cp = strchr(pos, ' ');
2019+ if (cp) {
2020+ *cp = '\0'; /* Will restore later. */
2021+ pos = cp + 1;
2022+ } else {
2023+ pos = "";
2024+ }
2025+ right_word = strchr(left_word, '=');
2026+ if (!right_word || right_word == left_word)
2027+ goto out;
2028+ is_not = *(right_word - 1) == '!';
2029+ if (is_not)
2030+ *(right_word++ - 1) = '\0'; /* Will restore later. */
2031+ else if (*(right_word + 1) != '=')
2032+ *right_word++ = '\0'; /* Will restore later. */
2033+ else
2034+ goto out;
2035+ dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
2036+ is_not ? "!" : "", right_word);
2037+ if (!strcmp(left_word, "grant_log")) {
2038+ if (entry) {
2039+ if (is_not ||
2040+ entry->grant_log != CCS_GRANTLOG_AUTO)
2041+ goto out;
2042+ else if (!strcmp(right_word, "yes"))
2043+ entry->grant_log = CCS_GRANTLOG_YES;
2044+ else if (!strcmp(right_word, "no"))
2045+ entry->grant_log = CCS_GRANTLOG_NO;
2046+ else
2047+ goto out;
2048+ }
2049+ continue;
2050+ }
2051+ if (!strcmp(left_word, "auto_domain_transition")) {
2052+ if (entry) {
2053+ if (is_not || entry->transit)
2054+ goto out;
2055+ entry->transit = ccs_get_dqword(right_word);
2056+ if (!entry->transit ||
2057+ (entry->transit->name[0] != '/' &&
2058+ !ccs_domain_def(entry->transit->name)))
2059+ goto out;
2060+ }
2061+ continue;
2062+ }
2063+ if (!strncmp(left_word, "exec.argv[", 10)) {
2064+ if (!argv) {
2065+ e.argc++;
2066+ e.condc++;
2067+ } else {
2068+ e.argc--;
2069+ e.condc--;
2070+ left = CCS_ARGV_ENTRY;
2071+ argv->is_not = is_not;
2072+ if (!ccs_parse_argv(left_word + 10,
2073+ right_word, argv++))
2074+ goto out;
2075+ }
2076+ goto store_value;
2077+ }
2078+ if (!strncmp(left_word, "exec.envp[\"", 11)) {
2079+ if (!envp) {
2080+ e.envc++;
2081+ e.condc++;
2082+ } else {
2083+ e.envc--;
2084+ e.condc--;
2085+ left = CCS_ENVP_ENTRY;
2086+ envp->is_not = is_not;
2087+ if (!ccs_parse_envp(left_word + 11,
2088+ right_word, envp++))
2089+ goto out;
2090+ }
2091+ goto store_value;
2092+ }
2093+ left = ccs_condition_type(left_word);
2094+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
2095+ left);
2096+ if (left == CCS_MAX_CONDITION_KEYWORD) {
2097+ if (!numbers_p) {
2098+ e.numbers_count++;
2099+ } else {
2100+ e.numbers_count--;
2101+ left = CCS_NUMBER_UNION;
2102+ param->data = left_word;
2103+ if (*left_word == '@' ||
2104+ !ccs_parse_number_union(param,
2105+ numbers_p++))
2106+ goto out;
2107+ }
2108+ }
2109+ if (!condp)
2110+ e.condc++;
2111+ else
2112+ e.condc--;
2113+ if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
2114+ if (!names_p) {
2115+ e.names_count++;
2116+ } else {
2117+ e.names_count--;
2118+ right = CCS_NAME_UNION;
2119+ param->data = right_word;
2120+ if (!ccs_parse_name_union_quoted(param,
2121+ names_p++))
2122+ goto out;
2123+ }
2124+ goto store_value;
2125+ }
2126+ right = ccs_condition_type(right_word);
2127+ if (right == CCS_MAX_CONDITION_KEYWORD) {
2128+ if (!numbers_p) {
2129+ e.numbers_count++;
2130+ } else {
2131+ e.numbers_count--;
2132+ right = CCS_NUMBER_UNION;
2133+ param->data = right_word;
2134+ if (!ccs_parse_number_union(param,
2135+ numbers_p++))
2136+ goto out;
2137+ }
2138+ }
2139+store_value:
2140+ if (!condp) {
2141+ dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
2142+ "match=%u\n", __LINE__, left, right, !is_not);
2143+ continue;
2144+ }
2145+ condp->left = left;
2146+ condp->right = right;
2147+ condp->equals = !is_not;
2148+ dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
2149+ __LINE__, condp->left, condp->right,
2150+ condp->equals);
2151+ condp++;
2152+ }
2153+ dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
2154+ __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
2155+ e.envc);
2156+ if (entry)
2157+ return ccs_commit_condition(entry);
2158+ e.size = sizeof(*entry)
2159+ + e.condc * sizeof(struct ccs_condition_element)
2160+ + e.numbers_count * sizeof(struct ccs_number_union)
2161+ + e.names_count * sizeof(struct ccs_name_union)
2162+ + e.argc * sizeof(struct ccs_argv)
2163+ + e.envc * sizeof(struct ccs_envp);
2164+ entry = ccs_malloc(e.size);
2165+ *entry = e;
2166+ condp = (struct ccs_condition_element *) (entry + 1);
2167+ numbers_p = (struct ccs_number_union *) (condp + e.condc);
2168+ names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
2169+ argv = (struct ccs_argv *) (names_p + e.names_count);
2170+ envp = (struct ccs_envp *) (argv + e.argc);
2171+ {
2172+ bool flag = false;
2173+ for (pos = start_of_string; pos < end_of_string; pos++) {
2174+ if (*pos)
2175+ continue;
2176+ if (flag) /* Restore " ". */
2177+ *pos = ' ';
2178+ else if (*(pos + 1) == '=') /* Restore "!=". */
2179+ *pos = '!';
2180+ else /* Restore "=". */
2181+ *pos = '=';
2182+ flag = !flag;
2183+ }
2184+ }
2185+ goto rerun;
2186+out:
2187+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
2188+ if (entry) {
2189+ ccs_del_condition(&entry->head.list);
2190+ free(entry);
2191+ }
2192+ return NULL;
2193+}
2194+
2195+/**
2196+ * ccs_same_acl_head - Check for duplicated "struct ccs_acl_info" entry.
2197+ *
2198+ * @a: Pointer to "struct ccs_acl_info".
2199+ * @b: Pointer to "struct ccs_acl_info".
2200+ *
2201+ * Returns true if @a == @b, false otherwise.
2202+ */
2203+static inline bool ccs_same_acl_head(const struct ccs_acl_info *a,
2204+ const struct ccs_acl_info *b)
2205+{
2206+ return a->type == b->type && a->cond == b->cond;
2207+}
2208+
2209+/**
2210+ * ccs_update_domain - Update an entry for domain policy.
2211+ *
2212+ * @new_entry: Pointer to "struct ccs_acl_info".
2213+ * @size: Size of @new_entry in bytes.
2214+ * @param: Pointer to "struct ccs_acl_param".
2215+ * @check_duplicate: Callback function to find duplicated entry.
2216+ * @merge_duplicate: Callback function to merge duplicated entry. Maybe NULL.
2217+ *
2218+ * Returns 0 on success, negative value otherwise.
2219+ */
2220+static int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
2221+ struct ccs_acl_param *param,
2222+ bool (*check_duplicate)
2223+ (const struct ccs_acl_info *,
2224+ const struct ccs_acl_info *),
2225+ bool (*merge_duplicate)
2226+ (struct ccs_acl_info *, struct ccs_acl_info *,
2227+ const bool))
2228+{
2229+ const bool is_delete = param->is_delete;
2230+ int error = is_delete ? -ENOENT : -ENOMEM;
2231+ struct ccs_acl_info *entry;
2232+ struct list_head * const list = param->list;
2233+ if (param->data[0]) {
2234+ new_entry->cond = ccs_get_condition(param);
2235+ if (!new_entry->cond)
2236+ return -EINVAL;
2237+ }
2238+ list_for_each_entry(entry, list, list) {
2239+ if (!ccs_same_acl_head(entry, new_entry) ||
2240+ !check_duplicate(entry, new_entry))
2241+ continue;
2242+ if (merge_duplicate)
2243+ entry->is_deleted = merge_duplicate(entry, new_entry,
2244+ is_delete);
2245+ else
2246+ entry->is_deleted = is_delete;
2247+ error = 0;
2248+ break;
2249+ }
2250+ if (error && !is_delete) {
2251+ entry = ccs_commit_ok(new_entry, size);
2252+ list_add_tail(&entry->list, list);
2253+ error = 0;
2254+ }
2255+ ccs_put_condition(new_entry->cond);
2256+ return error;
2257+}
2258+
2259+/**
2260+ * ccs_same_transition_control - Check for duplicated "struct ccs_transition_control" entry.
2261+ *
2262+ * @a: Pointer to "struct ccs_acl_head".
2263+ * @b: Pointer to "struct ccs_acl_head".
2264+ *
2265+ * Returns true if @a == @b, false otherwise.
2266+ */
2267+static bool ccs_same_transition_control(const struct ccs_acl_head *a,
2268+ const struct ccs_acl_head *b)
2269+{
2270+ const struct ccs_transition_control *p1 = container_of(a, typeof(*p1),
2271+ head);
2272+ const struct ccs_transition_control *p2 = container_of(b, typeof(*p2),
2273+ head);
2274+ return p1->type == p2->type && p1->is_last_name == p2->is_last_name
2275+ && p1->domainname == p2->domainname
2276+ && p1->program == p2->program && p1->ns == p2->ns;
2277+}
2278+
2279+/**
2280+ * ccs_write_transition_control - Write "struct ccs_transition_control" list.
2281+ *
2282+ * @param: Pointer to "struct ccs_acl_param".
2283+ * @type: Type of this entry.
2284+ *
2285+ * Returns 0 on success, negative value otherwise.
2286+ */
2287+static int ccs_write_transition_control(struct ccs_acl_param *param,
2288+ const u8 type)
2289+{
2290+ struct ccs_transition_control e = { .type = type, .ns = param->ns };
2291+ int error = param->is_delete ? -ENOENT : -ENOMEM;
2292+ char *program = param->data;
2293+ char *domainname = strstr(program, " from ");
2294+ if (domainname) {
2295+ *domainname = '\0';
2296+ domainname += 6;
2297+ } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
2298+ type == CCS_TRANSITION_CONTROL_KEEP) {
2299+ domainname = program;
2300+ program = NULL;
2301+ }
2302+ if (program && strcmp(program, "any")) {
2303+ if (!ccs_correct_path(program))
2304+ return -EINVAL;
2305+ e.program = ccs_get_name(program);
2306+ }
2307+ if (domainname && strcmp(domainname, "any")) {
2308+ if (!ccs_correct_domain(domainname)) {
2309+ if (!ccs_correct_path(domainname))
2310+ goto out;
2311+ e.is_last_name = true;
2312+ }
2313+ e.domainname = ccs_get_name(domainname);
2314+ }
2315+ param->list = &ccs_transition_list;
2316+ error = ccs_update_policy(&e.head, sizeof(e), param,
2317+ ccs_same_transition_control);
2318+out:
2319+ ccs_put_name(e.domainname);
2320+ ccs_put_name(e.program);
2321+ return error;
2322+}
2323+
2324+/**
2325+ * ccs_same_aggregator - Check for duplicated "struct ccs_aggregator" entry.
2326+ *
2327+ * @a: Pointer to "struct ccs_acl_head".
2328+ * @b: Pointer to "struct ccs_acl_head".
2329+ *
2330+ * Returns true if @a == @b, false otherwise.
2331+ */
2332+static bool ccs_same_aggregator(const struct ccs_acl_head *a,
2333+ const struct ccs_acl_head *b)
2334+{
2335+ const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
2336+ const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
2337+ return p1->original_name == p2->original_name &&
2338+ p1->aggregated_name == p2->aggregated_name && p1->ns == p2->ns;
2339+}
2340+
2341+/**
2342+ * ccs_write_aggregator - Write "struct ccs_aggregator" list.
2343+ *
2344+ * @param: Pointer to "struct ccs_acl_param".
2345+ *
2346+ * Returns 0 on success, negative value otherwise.
2347+ */
2348+static int ccs_write_aggregator(struct ccs_acl_param *param)
2349+{
2350+ struct ccs_aggregator e = { .ns = param->ns };
2351+ int error = param->is_delete ? -ENOENT : -ENOMEM;
2352+ const char *original_name = ccs_read_token(param);
2353+ const char *aggregated_name = ccs_read_token(param);
2354+ if (!ccs_correct_word(original_name) ||
2355+ !ccs_correct_path(aggregated_name))
2356+ return -EINVAL;
2357+ e.original_name = ccs_get_name(original_name);
2358+ e.aggregated_name = ccs_get_name(aggregated_name);
2359+ if (e.aggregated_name->is_patterned) /* No patterns allowed. */
2360+ goto out;
2361+ param->list = &ccs_aggregator_list;
2362+ error = ccs_update_policy(&e.head, sizeof(e), param,
2363+ ccs_same_aggregator);
2364+out:
2365+ ccs_put_name(e.original_name);
2366+ ccs_put_name(e.aggregated_name);
2367+ return error;
2368+}
2369+
2370+/* Domain create handler. */
2371+
2372+/**
2373+ * ccs_find_namespace - Find specified namespace.
2374+ *
2375+ * @name: Name of namespace to find.
2376+ * @len: Length of @name.
2377+ *
2378+ * Returns pointer to "struct ccs_policy_namespace" if found, NULL otherwise.
2379+ */
2380+static struct ccs_policy_namespace *ccs_find_namespace(const char *name,
2381+ const unsigned int len)
2382+{
2383+ struct ccs_policy_namespace *ns;
2384+ list_for_each_entry(ns, &ccs_namespace_list, namespace_list) {
2385+ if (strncmp(name, ns->name, len) ||
2386+ (name[len] && name[len] != ' '))
2387+ continue;
2388+ return ns;
2389+ }
2390+ return NULL;
2391+}
2392+
2393+/**
2394+ * ccs_assign_namespace - Create a new namespace.
2395+ *
2396+ * @domainname: Name of namespace to create.
2397+ *
2398+ * Returns pointer to "struct ccs_policy_namespace" on success, NULL otherwise.
2399+ */
2400+static struct ccs_policy_namespace *ccs_assign_namespace(const char *domainname)
2401+{
2402+ struct ccs_policy_namespace *ptr;
2403+ struct ccs_policy_namespace *entry;
2404+ const char *cp = domainname;
2405+ unsigned int len = 0;
2406+ while (*cp && *cp++ != ' ')
2407+ len++;
2408+ ptr = ccs_find_namespace(domainname, len);
2409+ if (ptr)
2410+ return ptr;
2411+ if (len >= CCS_EXEC_TMPSIZE - 10 || !ccs_domain_def(domainname))
2412+ return NULL;
2413+ entry = ccs_malloc(sizeof(*entry) + len + 1);
2414+ {
2415+ char *name = (char *) (entry + 1);
2416+ memmove(name, domainname, len);
2417+ name[len] = '\0';
2418+ entry->name = name;
2419+ }
2420+ entry->profile_version = 20100903;
2421+ for (len = 0; len < CCS_MAX_ACL_GROUPS; len++)
2422+ INIT_LIST_HEAD(&entry->acl_group[len]);
2423+ ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
2424+ list_add_tail(&entry->namespace_list, &ccs_namespace_list);
2425+ return entry;
2426+}
2427+
2428+/**
2429+ * ccs_assign_domain2 - Create a domain or a namespace.
2430+ *
2431+ * @domainname: The name of domain.
2432+ *
2433+ * Returns pointer to "struct ccs_domain2_info" on success, NULL otherwise.
2434+ */
2435+static struct ccs_domain2_info *ccs_assign_domain2(const char *domainname)
2436+{
2437+ struct ccs_domain2_info e = { };
2438+ struct ccs_domain2_info *entry = ccs_find_domain2(domainname);
2439+ if (entry)
2440+ return entry;
2441+ /* Requested domain does not exist. */
2442+ /* Don't create requested domain if domainname is invalid. */
2443+ if (strlen(domainname) >= CCS_EXEC_TMPSIZE - 10 ||
2444+ !ccs_correct_domain(domainname))
2445+ return NULL;
2446+ e.domainname = ccs_get_name(domainname);
2447+ entry = ccs_commit_ok(&e, sizeof(e));
2448+ INIT_LIST_HEAD(&entry->acl_info_list);
2449+ list_add_tail(&entry->list, &ccs_domain_list);
2450+ ccs_put_name(e.domainname);
2451+ return entry;
2452+}
2453+
2454+/**
2455+ * ccs_same_path_acl - Check for duplicated "struct ccs_path_acl" entry.
2456+ *
2457+ * @a: Pointer to "struct ccs_acl_info".
2458+ * @b: Pointer to "struct ccs_acl_info".
2459+ *
2460+ * Returns true if @a == @b except permission bits, false otherwise.
2461+ */
2462+static bool ccs_same_path_acl(const struct ccs_acl_info *a,
2463+ const struct ccs_acl_info *b)
2464+{
2465+ const struct ccs_path_acl *p1 = container_of(a, typeof(*p1), head);
2466+ const struct ccs_path_acl *p2 = container_of(b, typeof(*p2), head);
2467+ return ccs_same_name_union(&p1->name, &p2->name);
2468+}
2469+
2470+/**
2471+ * ccs_merge_path_acl - Merge duplicated "struct ccs_path_acl" entry.
2472+ *
2473+ * @a: Pointer to "struct ccs_acl_info".
2474+ * @b: Pointer to "struct ccs_acl_info".
2475+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
2476+ *
2477+ * Returns true if @a is empty, false otherwise.
2478+ */
2479+static bool ccs_merge_path_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
2480+ const bool is_delete)
2481+{
2482+ u16 * const a_perm = &container_of(a, struct ccs_path_acl, head)->perm;
2483+ u16 perm = *a_perm;
2484+ const u16 b_perm = container_of(b, struct ccs_path_acl, head)->perm;
2485+ if (is_delete)
2486+ perm &= ~b_perm;
2487+ else
2488+ perm |= b_perm;
2489+ *a_perm = perm;
2490+ return !perm;
2491+}
2492+
2493+/**
2494+ * ccs_update_path_acl - Update "struct ccs_path_acl" list.
2495+ *
2496+ * @perm: Permission.
2497+ * @param: Pointer to "struct ccs_acl_param".
2498+ *
2499+ * Returns 0 on success, negative value otherwise.
2500+ */
2501+static int ccs_update_path_acl(const u16 perm, struct ccs_acl_param *param)
2502+{
2503+ struct ccs_path_acl e = {
2504+ .head.type = CCS_TYPE_PATH_ACL,
2505+ .perm = perm
2506+ };
2507+ int error;
2508+ if (!ccs_parse_name_union(param, &e.name))
2509+ error = -EINVAL;
2510+ else
2511+ error = ccs_update_domain(&e.head, sizeof(e), param,
2512+ ccs_same_path_acl,
2513+ ccs_merge_path_acl);
2514+ ccs_put_name_union(&e.name);
2515+ return error;
2516+}
2517+
2518+/**
2519+ * ccs_same_mkdev_acl - Check for duplicated "struct ccs_mkdev_acl" entry.
2520+ *
2521+ * @a: Pointer to "struct ccs_acl_info".
2522+ * @b: Pointer to "struct ccs_acl_info".
2523+ *
2524+ * Returns true if @a == @b except permission bits, false otherwise.
2525+ */
2526+static bool ccs_same_mkdev_acl(const struct ccs_acl_info *a,
2527+ const struct ccs_acl_info *b)
2528+{
2529+ const struct ccs_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
2530+ const struct ccs_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
2531+ return ccs_same_name_union(&p1->name, &p2->name) &&
2532+ ccs_same_number_union(&p1->mode, &p2->mode) &&
2533+ ccs_same_number_union(&p1->major, &p2->major) &&
2534+ ccs_same_number_union(&p1->minor, &p2->minor);
2535+}
2536+
2537+/**
2538+ * ccs_merge_mkdev_acl - Merge duplicated "struct ccs_mkdev_acl" entry.
2539+ *
2540+ * @a: Pointer to "struct ccs_acl_info".
2541+ * @b: Pointer to "struct ccs_acl_info".
2542+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
2543+ *
2544+ * Returns true if @a is empty, false otherwise.
2545+ */
2546+static bool ccs_merge_mkdev_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
2547+ const bool is_delete)
2548+{
2549+ u8 *const a_perm = &container_of(a, struct ccs_mkdev_acl, head)->perm;
2550+ u8 perm = *a_perm;
2551+ const u8 b_perm = container_of(b, struct ccs_mkdev_acl, head)->perm;
2552+ if (is_delete)
2553+ perm &= ~b_perm;
2554+ else
2555+ perm |= b_perm;
2556+ *a_perm = perm;
2557+ return !perm;
2558+}
2559+
2560+/**
2561+ * ccs_update_mkdev_acl - Update "struct ccs_mkdev_acl" list.
2562+ *
2563+ * @perm: Permission.
2564+ * @param: Pointer to "struct ccs_acl_param".
2565+ *
2566+ * Returns 0 on success, negative value otherwise.
2567+ */
2568+static int ccs_update_mkdev_acl(const u8 perm, struct ccs_acl_param *param)
2569+{
2570+ struct ccs_mkdev_acl e = {
2571+ .head.type = CCS_TYPE_MKDEV_ACL,
2572+ .perm = perm
2573+ };
2574+ int error;
2575+ if (!ccs_parse_name_union(param, &e.name) ||
2576+ !ccs_parse_number_union(param, &e.mode) ||
2577+ !ccs_parse_number_union(param, &e.major) ||
2578+ !ccs_parse_number_union(param, &e.minor))
2579+ error = -EINVAL;
2580+ else
2581+ error = ccs_update_domain(&e.head, sizeof(e), param,
2582+ ccs_same_mkdev_acl,
2583+ ccs_merge_mkdev_acl);
2584+ ccs_put_name_union(&e.name);
2585+ ccs_put_number_union(&e.mode);
2586+ ccs_put_number_union(&e.major);
2587+ ccs_put_number_union(&e.minor);
2588+ return error;
2589+}
2590+
2591+/**
2592+ * ccs_same_path2_acl - Check for duplicated "struct ccs_path2_acl" entry.
2593+ *
2594+ * @a: Pointer to "struct ccs_acl_info".
2595+ * @b: Pointer to "struct ccs_acl_info".
2596+ *
2597+ * Returns true if @a == @b except permission bits, false otherwise.
2598+ */
2599+static bool ccs_same_path2_acl(const struct ccs_acl_info *a,
2600+ const struct ccs_acl_info *b)
2601+{
2602+ const struct ccs_path2_acl *p1 = container_of(a, typeof(*p1), head);
2603+ const struct ccs_path2_acl *p2 = container_of(b, typeof(*p2), head);
2604+ return ccs_same_name_union(&p1->name1, &p2->name1) &&
2605+ ccs_same_name_union(&p1->name2, &p2->name2);
2606+}
2607+
2608+/**
2609+ * ccs_merge_path2_acl - Merge duplicated "struct ccs_path2_acl" entry.
2610+ *
2611+ * @a: Pointer to "struct ccs_acl_info".
2612+ * @b: Pointer to "struct ccs_acl_info".
2613+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
2614+ *
2615+ * Returns true if @a is empty, false otherwise.
2616+ */
2617+static bool ccs_merge_path2_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
2618+ const bool is_delete)
2619+{
2620+ u8 * const a_perm = &container_of(a, struct ccs_path2_acl, head)->perm;
2621+ u8 perm = *a_perm;
2622+ const u8 b_perm = container_of(b, struct ccs_path2_acl, head)->perm;
2623+ if (is_delete)
2624+ perm &= ~b_perm;
2625+ else
2626+ perm |= b_perm;
2627+ *a_perm = perm;
2628+ return !perm;
2629+}
2630+
2631+/**
2632+ * ccs_update_path2_acl - Update "struct ccs_path2_acl" list.
2633+ *
2634+ * @perm: Permission.
2635+ * @param: Pointer to "struct ccs_acl_param".
2636+ *
2637+ * Returns 0 on success, negative value otherwise.
2638+ */
2639+static int ccs_update_path2_acl(const u8 perm, struct ccs_acl_param *param)
2640+{
2641+ struct ccs_path2_acl e = {
2642+ .head.type = CCS_TYPE_PATH2_ACL,
2643+ .perm = perm
2644+ };
2645+ int error;
2646+ if (!ccs_parse_name_union(param, &e.name1) ||
2647+ !ccs_parse_name_union(param, &e.name2))
2648+ error = -EINVAL;
2649+ else
2650+ error = ccs_update_domain(&e.head, sizeof(e), param,
2651+ ccs_same_path2_acl,
2652+ ccs_merge_path2_acl);
2653+ ccs_put_name_union(&e.name1);
2654+ ccs_put_name_union(&e.name2);
2655+ return error;
2656+}
2657+
2658+/**
2659+ * ccs_same_path_number_acl - Check for duplicated "struct ccs_path_number_acl" entry.
2660+ *
2661+ * @a: Pointer to "struct ccs_acl_info".
2662+ * @b: Pointer to "struct ccs_acl_info".
2663+ *
2664+ * Returns true if @a == @b except permission bits, false otherwise.
2665+ */
2666+static bool ccs_same_path_number_acl(const struct ccs_acl_info *a,
2667+ const struct ccs_acl_info *b)
2668+{
2669+ const struct ccs_path_number_acl *p1 = container_of(a, typeof(*p1),
2670+ head);
2671+ const struct ccs_path_number_acl *p2 = container_of(b, typeof(*p2),
2672+ head);
2673+ return ccs_same_name_union(&p1->name, &p2->name) &&
2674+ ccs_same_number_union(&p1->number, &p2->number);
2675+}
2676+
2677+/**
2678+ * ccs_merge_path_number_acl - Merge duplicated "struct ccs_path_number_acl" entry.
2679+ *
2680+ * @a: Pointer to "struct ccs_acl_info".
2681+ * @b: Pointer to "struct ccs_acl_info".
2682+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
2683+ *
2684+ * Returns true if @a is empty, false otherwise.
2685+ */
2686+static bool ccs_merge_path_number_acl(struct ccs_acl_info *a,
2687+ struct ccs_acl_info *b,
2688+ const bool is_delete)
2689+{
2690+ u8 * const a_perm = &container_of(a, struct ccs_path_number_acl, head)
2691+ ->perm;
2692+ u8 perm = *a_perm;
2693+ const u8 b_perm = container_of(b, struct ccs_path_number_acl, head)
2694+ ->perm;
2695+ if (is_delete)
2696+ perm &= ~b_perm;
2697+ else
2698+ perm |= b_perm;
2699+ *a_perm = perm;
2700+ return !perm;
2701+}
2702+
2703+/**
2704+ * ccs_update_path_number_acl - Update create/mkdir/mkfifo/mksock/ioctl/chmod/chown/chgrp ACL.
2705+ *
2706+ * @perm: Permission.
2707+ * @param: Pointer to "struct ccs_acl_param".
2708+ *
2709+ * Returns 0 on success, negative value otherwise.
2710+ */
2711+static int ccs_update_path_number_acl(const u8 perm,
2712+ struct ccs_acl_param *param)
2713+{
2714+ struct ccs_path_number_acl e = {
2715+ .head.type = CCS_TYPE_PATH_NUMBER_ACL,
2716+ .perm = perm
2717+ };
2718+ int error;
2719+ if (!ccs_parse_name_union(param, &e.name) ||
2720+ !ccs_parse_number_union(param, &e.number))
2721+ error = -EINVAL;
2722+ else
2723+ error = ccs_update_domain(&e.head, sizeof(e), param,
2724+ ccs_same_path_number_acl,
2725+ ccs_merge_path_number_acl);
2726+ ccs_put_name_union(&e.name);
2727+ ccs_put_number_union(&e.number);
2728+ return error;
2729+}
2730+
2731+/**
2732+ * ccs_same_mount_acl - Check for duplicated "struct ccs_mount_acl" entry.
2733+ *
2734+ * @a: Pointer to "struct ccs_acl_info".
2735+ * @b: Pointer to "struct ccs_acl_info".
2736+ *
2737+ * Returns true if @a == @b, false otherwise.
2738+ */
2739+static bool ccs_same_mount_acl(const struct ccs_acl_info *a,
2740+ const struct ccs_acl_info *b)
2741+{
2742+ const struct ccs_mount_acl *p1 = container_of(a, typeof(*p1), head);
2743+ const struct ccs_mount_acl *p2 = container_of(b, typeof(*p2), head);
2744+ return ccs_same_name_union(&p1->dev_name, &p2->dev_name) &&
2745+ ccs_same_name_union(&p1->dir_name, &p2->dir_name) &&
2746+ ccs_same_name_union(&p1->fs_type, &p2->fs_type) &&
2747+ ccs_same_number_union(&p1->flags, &p2->flags);
2748+}
2749+
2750+/**
2751+ * ccs_update_mount_acl - Write "struct ccs_mount_acl" list.
2752+ *
2753+ * @param: Pointer to "struct ccs_acl_param".
2754+ *
2755+ * Returns 0 on success, negative value otherwise.
2756+ */
2757+static int ccs_update_mount_acl(struct ccs_acl_param *param)
2758+{
2759+ struct ccs_mount_acl e = { .head.type = CCS_TYPE_MOUNT_ACL };
2760+ int error;
2761+ if (!ccs_parse_name_union(param, &e.dev_name) ||
2762+ !ccs_parse_name_union(param, &e.dir_name) ||
2763+ !ccs_parse_name_union(param, &e.fs_type) ||
2764+ !ccs_parse_number_union(param, &e.flags))
2765+ error = -EINVAL;
2766+ else
2767+ error = ccs_update_domain(&e.head, sizeof(e), param,
2768+ ccs_same_mount_acl, NULL);
2769+ ccs_put_name_union(&e.dev_name);
2770+ ccs_put_name_union(&e.dir_name);
2771+ ccs_put_name_union(&e.fs_type);
2772+ ccs_put_number_union(&e.flags);
2773+ return error;
2774+}
2775+
2776+/**
2777+ * ccs_write_file - Update file related list.
2778+ *
2779+ * @param: Pointer to "struct ccs_acl_param".
2780+ *
2781+ * Returns 0 on success, negative value otherwise.
2782+ */
2783+static int ccs_write_file(struct ccs_acl_param *param)
2784+{
2785+ u16 perm = 0;
2786+ u8 type;
2787+ const char *operation = ccs_read_token(param);
2788+ for (type = 0; type < CCS_MAX_PATH_OPERATION; type++)
2789+ if (ccs_permstr(operation, ccs_path_keyword[type]))
2790+ perm |= 1 << type;
2791+ if (perm)
2792+ return ccs_update_path_acl(perm, param);
2793+ for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++)
2794+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]]))
2795+ perm |= 1 << type;
2796+ if (perm)
2797+ return ccs_update_path2_acl(perm, param);
2798+ for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++)
2799+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]]))
2800+ perm |= 1 << type;
2801+ if (perm)
2802+ return ccs_update_path_number_acl(perm, param);
2803+ for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++)
2804+ if (ccs_permstr(operation,
2805+ ccs_mac_keywords[ccs_pnnn2mac[type]]))
2806+ perm |= 1 << type;
2807+ if (perm)
2808+ return ccs_update_mkdev_acl(perm, param);
2809+ if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT]))
2810+ return ccs_update_mount_acl(param);
2811+ return -EINVAL;
2812+}
2813+
2814+/**
2815+ * ccs_parse_ipaddr_union - Parse an IP address.
2816+ *
2817+ * @param: Pointer to "struct ccs_acl_param".
2818+ * @ptr: Pointer to "struct ccs_ipaddr_union".
2819+ *
2820+ * Returns true on success, false otherwise.
2821+ */
2822+static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
2823+ struct ccs_ipaddr_union *ptr)
2824+{
2825+ struct ccs_ip_address_entry e;
2826+ memset(ptr, 0, sizeof(ptr));
2827+ if (ccs_parse_ip(ccs_read_token(param), &e) == 0) {
2828+ memmove(&ptr->ip[0], e.min, sizeof(ptr->ip[0]));
2829+ memmove(&ptr->ip[1], e.max, sizeof(ptr->ip[1]));
2830+ ptr->is_ipv6 = e.is_ipv6;
2831+ return true;
2832+ }
2833+ return false;
2834+}
2835+
2836+/*
2837+ * Routines for printing IPv4 or IPv6 address.
2838+ * These are copied from include/linux/kernel.h include/net/ipv6.h
2839+ * include/net/addrconf.h lib/hexdump.c lib/vsprintf.c and simplified.
2840+ */
2841+static const char hex_asc[] = "0123456789abcdef";
2842+#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
2843+#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
2844+
2845+static inline char *pack_hex_byte(char *buf, u8 byte)
2846+{
2847+ *buf++ = hex_asc_hi(byte);
2848+ *buf++ = hex_asc_lo(byte);
2849+ return buf;
2850+}
2851+
2852+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
2853+{
2854+ return (a->s6_addr32[0] | a->s6_addr32[1] |
2855+ (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
2856+}
2857+
2858+static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
2859+{
2860+ return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
2861+}
2862+
2863+static char *ip4_string(char *p, const u8 *addr)
2864+{
2865+ /*
2866+ * Since this function is called outside vsnprintf(), I can use
2867+ * sprintf() here.
2868+ */
2869+ return p +
2870+ sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
2871+}
2872+
2873+static char *ip6_compressed_string(char *p, const char *addr)
2874+{
2875+ int i, j, range;
2876+ unsigned char zerolength[8];
2877+ int longest = 1;
2878+ int colonpos = -1;
2879+ u16 word;
2880+ u8 hi, lo;
2881+ bool needcolon = false;
2882+ bool useIPv4;
2883+ struct in6_addr in6;
2884+
2885+ memcpy(&in6, addr, sizeof(struct in6_addr));
2886+
2887+ useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
2888+
2889+ memset(zerolength, 0, sizeof(zerolength));
2890+
2891+ if (useIPv4)
2892+ range = 6;
2893+ else
2894+ range = 8;
2895+
2896+ /* find position of longest 0 run */
2897+ for (i = 0; i < range; i++) {
2898+ for (j = i; j < range; j++) {
2899+ if (in6.s6_addr16[j] != 0)
2900+ break;
2901+ zerolength[i]++;
2902+ }
2903+ }
2904+ for (i = 0; i < range; i++) {
2905+ if (zerolength[i] > longest) {
2906+ longest = zerolength[i];
2907+ colonpos = i;
2908+ }
2909+ }
2910+ if (longest == 1) /* don't compress a single 0 */
2911+ colonpos = -1;
2912+
2913+ /* emit address */
2914+ for (i = 0; i < range; i++) {
2915+ if (i == colonpos) {
2916+ if (needcolon || i == 0)
2917+ *p++ = ':';
2918+ *p++ = ':';
2919+ needcolon = false;
2920+ i += longest - 1;
2921+ continue;
2922+ }
2923+ if (needcolon) {
2924+ *p++ = ':';
2925+ needcolon = false;
2926+ }
2927+ /* hex u16 without leading 0s */
2928+ word = ntohs(in6.s6_addr16[i]);
2929+ hi = word >> 8;
2930+ lo = word & 0xff;
2931+ if (hi) {
2932+ if (hi > 0x0f)
2933+ p = pack_hex_byte(p, hi);
2934+ else
2935+ *p++ = hex_asc_lo(hi);
2936+ p = pack_hex_byte(p, lo);
2937+ }
2938+ else if (lo > 0x0f)
2939+ p = pack_hex_byte(p, lo);
2940+ else
2941+ *p++ = hex_asc_lo(lo);
2942+ needcolon = true;
2943+ }
2944+
2945+ if (useIPv4) {
2946+ if (needcolon)
2947+ *p++ = ':';
2948+ p = ip4_string(p, &in6.s6_addr[12]);
2949+ }
2950+ *p = '\0';
2951+
2952+ return p;
2953+}
2954+
2955+/**
2956+ * ccs_print_ipv4 - Print an IPv4 address.
2957+ *
2958+ * @min_ip: Pointer to "u32 in network byte order".
2959+ * @max_ip: Pointer to "u32 in network byte order".
2960+ *
2961+ * Returns nothing.
2962+ */
2963+static void ccs_print_ipv4(const u32 *min_ip, const u32 *max_ip)
2964+{
2965+ char addr[sizeof("255.255.255.255")];
2966+ ip4_string(addr, (const u8 *) min_ip);
2967+ cprintf("%s", addr);
2968+ if (*min_ip == *max_ip)
2969+ return;
2970+ ip4_string(addr, (const u8 *) max_ip);
2971+ cprintf("-%s", addr);
2972+}
2973+
2974+/**
2975+ * ccs_print_ipv6 - Print an IPv6 address.
2976+ *
2977+ * @min_ip: Pointer to "struct in6_addr".
2978+ * @max_ip: Pointer to "struct in6_addr".
2979+ *
2980+ * Returns nothing.
2981+ */
2982+static void ccs_print_ipv6(const struct in6_addr *min_ip,
2983+ const struct in6_addr *max_ip)
2984+{
2985+ char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
2986+ ip6_compressed_string(addr, (const char *) min_ip);
2987+ cprintf("%s", addr);
2988+ if (!memcmp(min_ip, max_ip, 16))
2989+ return;
2990+ ip6_compressed_string(addr, (const char *) max_ip);
2991+ cprintf("-%s", addr);
2992+}
2993+
2994+/**
2995+ * ccs_print_ip - Print an IP address.
2996+ *
2997+ * @ptr: Pointer to "struct ccs_ipaddr_union".
2998+ *
2999+ * Returns nothing.
3000+ */
3001+static void ccs_print_ip(const struct ccs_ipaddr_union *ptr)
3002+{
3003+ if (ptr->is_ipv6)
3004+ ccs_print_ipv6(&ptr->ip[0], &ptr->ip[1]);
3005+ else
3006+ ccs_print_ipv4(&ptr->ip[0].s6_addr32[0],
3007+ &ptr->ip[1].s6_addr32[0]);
3008+}
3009+
3010+/**
3011+ * ccs_same_inet_acl - Check for duplicated "struct ccs_inet_acl" entry.
3012+ *
3013+ * @a: Pointer to "struct ccs_acl_info".
3014+ * @b: Pointer to "struct ccs_acl_info".
3015+ *
3016+ * Returns true if @a == @b except permission bits, false otherwise.
3017+ */
3018+static bool ccs_same_inet_acl(const struct ccs_acl_info *a,
3019+ const struct ccs_acl_info *b)
3020+{
3021+ const struct ccs_inet_acl *p1 = container_of(a, typeof(*p1), head);
3022+ const struct ccs_inet_acl *p2 = container_of(b, typeof(*p2), head);
3023+ return p1->protocol == p2->protocol &&
3024+ ccs_same_ipaddr_union(&p1->address, &p2->address) &&
3025+ ccs_same_number_union(&p1->port, &p2->port);
3026+}
3027+
3028+/**
3029+ * ccs_same_unix_acl - Check for duplicated "struct ccs_unix_acl" entry.
3030+ *
3031+ * @a: Pointer to "struct ccs_acl_info".
3032+ * @b: Pointer to "struct ccs_acl_info".
3033+ *
3034+ * Returns true if @a == @b except permission bits, false otherwise.
3035+ */
3036+static bool ccs_same_unix_acl(const struct ccs_acl_info *a,
3037+ const struct ccs_acl_info *b)
3038+{
3039+ const struct ccs_unix_acl *p1 = container_of(a, typeof(*p1), head);
3040+ const struct ccs_unix_acl *p2 = container_of(b, typeof(*p2), head);
3041+ return p1->protocol == p2->protocol &&
3042+ ccs_same_name_union(&p1->name, &p2->name);
3043+}
3044+
3045+/**
3046+ * ccs_merge_inet_acl - Merge duplicated "struct ccs_inet_acl" entry.
3047+ *
3048+ * @a: Pointer to "struct ccs_acl_info".
3049+ * @b: Pointer to "struct ccs_acl_info".
3050+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
3051+ *
3052+ * Returns true if @a is empty, false otherwise.
3053+ */
3054+static bool ccs_merge_inet_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
3055+ const bool is_delete)
3056+{
3057+ u8 * const a_perm = &container_of(a, struct ccs_inet_acl, head)->perm;
3058+ u8 perm = *a_perm;
3059+ const u8 b_perm = container_of(b, struct ccs_inet_acl, head)->perm;
3060+ if (is_delete)
3061+ perm &= ~b_perm;
3062+ else
3063+ perm |= b_perm;
3064+ *a_perm = perm;
3065+ return !perm;
3066+}
3067+
3068+/**
3069+ * ccs_merge_unix_acl - Merge duplicated "struct ccs_unix_acl" entry.
3070+ *
3071+ * @a: Pointer to "struct ccs_acl_info".
3072+ * @b: Pointer to "struct ccs_acl_info".
3073+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
3074+ *
3075+ * Returns true if @a is empty, false otherwise.
3076+ */
3077+static bool ccs_merge_unix_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
3078+ const bool is_delete)
3079+{
3080+ u8 * const a_perm = &container_of(a, struct ccs_unix_acl, head)->perm;
3081+ u8 perm = *a_perm;
3082+ const u8 b_perm = container_of(b, struct ccs_unix_acl, head)->perm;
3083+ if (is_delete)
3084+ perm &= ~b_perm;
3085+ else
3086+ perm |= b_perm;
3087+ *a_perm = perm;
3088+ return !perm;
3089+}
3090+
3091+/**
3092+ * ccs_write_inet_network - Write "struct ccs_inet_acl" list.
3093+ *
3094+ * @param: Pointer to "struct ccs_acl_param".
3095+ *
3096+ * Returns 0 on success, negative value otherwise.
3097+ */
3098+static int ccs_write_inet_network(struct ccs_acl_param *param)
3099+{
3100+ struct ccs_inet_acl e = { .head.type = CCS_TYPE_INET_ACL };
3101+ int error = -EINVAL;
3102+ u8 type;
3103+ const char *protocol = ccs_read_token(param);
3104+ const char *operation = ccs_read_token(param);
3105+ for (e.protocol = 0; e.protocol < CCS_SOCK_MAX; e.protocol++)
3106+ if (!strcmp(protocol, ccs_proto_keyword[e.protocol]))
3107+ break;
3108+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3109+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3110+ e.perm |= 1 << type;
3111+ if (e.protocol == CCS_SOCK_MAX || !e.perm)
3112+ return -EINVAL;
3113+ if (param->data[0] == '@') {
3114+ param->data++;
3115+ e.address.group = ccs_get_group(param, &ccs_address_group);
3116+ if (!e.address.group)
3117+ return -ENOMEM;
3118+ } else {
3119+ if (!ccs_parse_ipaddr_union(param, &e.address))
3120+ goto out;
3121+ }
3122+ if (!ccs_parse_number_union(param, &e.port) ||
3123+ e.port.values[1] > 65535)
3124+ goto out;
3125+ error = ccs_update_domain(&e.head, sizeof(e), param, ccs_same_inet_acl,
3126+ ccs_merge_inet_acl);
3127+out:
3128+ ccs_put_group(e.address.group);
3129+ ccs_put_number_union(&e.port);
3130+ return error;
3131+}
3132+
3133+/**
3134+ * ccs_write_unix_network - Write "struct ccs_unix_acl" list.
3135+ *
3136+ * @param: Pointer to "struct ccs_acl_param".
3137+ *
3138+ * Returns 0 on success, negative value otherwise.
3139+ */
3140+static int ccs_write_unix_network(struct ccs_acl_param *param)
3141+{
3142+ struct ccs_unix_acl e = { .head.type = CCS_TYPE_UNIX_ACL };
3143+ int error;
3144+ u8 type;
3145+ const char *protocol = ccs_read_token(param);
3146+ const char *operation = ccs_read_token(param);
3147+ for (e.protocol = 0; e.protocol < CCS_SOCK_MAX; e.protocol++)
3148+ if (!strcmp(protocol, ccs_proto_keyword[e.protocol]))
3149+ break;
3150+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3151+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3152+ e.perm |= 1 << type;
3153+ if (e.protocol == CCS_SOCK_MAX || !e.perm)
3154+ return -EINVAL;
3155+ if (!ccs_parse_name_union(param, &e.name))
3156+ return -EINVAL;
3157+ error = ccs_update_domain(&e.head, sizeof(e), param, ccs_same_unix_acl,
3158+ ccs_merge_unix_acl);
3159+ ccs_put_name_union(&e.name);
3160+ return error;
3161+}
3162+
3163+/**
3164+ * ccs_same_capability_acl - Check for duplicated "struct ccs_capability_acl" entry.
3165+ *
3166+ * @a: Pointer to "struct ccs_acl_info".
3167+ * @b: Pointer to "struct ccs_acl_info".
3168+ *
3169+ * Returns true if @a == @b, false otherwise.
3170+ */
3171+static bool ccs_same_capability_acl(const struct ccs_acl_info *a,
3172+ const struct ccs_acl_info *b)
3173+{
3174+ const struct ccs_capability_acl *p1 = container_of(a, typeof(*p1),
3175+ head);
3176+ const struct ccs_capability_acl *p2 = container_of(b, typeof(*p2),
3177+ head);
3178+ return p1->operation == p2->operation;
3179+}
3180+
3181+/**
3182+ * ccs_write_capability - Write "struct ccs_capability_acl" list.
3183+ *
3184+ * @param: Pointer to "struct ccs_acl_param".
3185+ *
3186+ * Returns 0 on success, negative value otherwise.
3187+ */
3188+static int ccs_write_capability(struct ccs_acl_param *param)
3189+{
3190+ struct ccs_capability_acl e = { .head.type = CCS_TYPE_CAPABILITY_ACL };
3191+ const char *operation = ccs_read_token(param);
3192+ for (e.operation = 0; e.operation < CCS_MAX_CAPABILITY_INDEX;
3193+ e.operation++) {
3194+ if (strcmp(operation,
3195+ ccs_mac_keywords[ccs_c2mac[e.operation]]))
3196+ continue;
3197+ return ccs_update_domain(&e.head, sizeof(e), param,
3198+ ccs_same_capability_acl, NULL);
3199+ }
3200+ return -EINVAL;
3201+}
3202+
3203+/**
3204+ * ccs_same_env_acl - Check for duplicated "struct ccs_env_acl" entry.
3205+ *
3206+ * @a: Pointer to "struct ccs_acl_info".
3207+ * @b: Pointer to "struct ccs_acl_info".
3208+ *
3209+ * Returns true if @a == @b, false otherwise.
3210+ */
3211+static bool ccs_same_env_acl(const struct ccs_acl_info *a,
3212+ const struct ccs_acl_info *b)
3213+{
3214+ const struct ccs_env_acl *p1 = container_of(a, typeof(*p1), head);
3215+ const struct ccs_env_acl *p2 = container_of(b, typeof(*p2), head);
3216+ return p1->env == p2->env;
3217+}
3218+
3219+/**
3220+ * ccs_write_env - Write "struct ccs_env_acl" list.
3221+ *
3222+ * @param: Pointer to "struct ccs_acl_param".
3223+ *
3224+ * Returns 0 on success, negative value otherwise.
3225+ */
3226+static int ccs_write_env(struct ccs_acl_param *param)
3227+{
3228+ struct ccs_env_acl e = { .head.type = CCS_TYPE_ENV_ACL };
3229+ int error = -ENOMEM;
3230+ const char *data = ccs_read_token(param);
3231+ if (!ccs_correct_word(data) || strchr(data, '='))
3232+ return -EINVAL;
3233+ e.env = ccs_get_name(data);
3234+ error = ccs_update_domain(&e.head, sizeof(e), param,
3235+ ccs_same_env_acl, NULL);
3236+ ccs_put_name(e.env);
3237+ return error;
3238+}
3239+
3240+/**
3241+ * ccs_write_misc - Update environment variable list.
3242+ *
3243+ * @param: Pointer to "struct ccs_acl_param".
3244+ *
3245+ * Returns 0 on success, negative value otherwise.
3246+ */
3247+static int ccs_write_misc(struct ccs_acl_param *param)
3248+{
3249+ if (ccs_str_starts(param->data, "env "))
3250+ return ccs_write_env(param);
3251+ return -EINVAL;
3252+}
3253+
3254+/**
3255+ * ccs_same_signal_acl - Check for duplicated "struct ccs_signal_acl" entry.
3256+ *
3257+ * @a: Pointer to "struct ccs_acl_info".
3258+ * @b: Pointer to "struct ccs_acl_info".
3259+ *
3260+ * Returns true if @a == @b, false otherwise.
3261+ */
3262+static bool ccs_same_signal_acl(const struct ccs_acl_info *a,
3263+ const struct ccs_acl_info *b)
3264+{
3265+ const struct ccs_signal_acl *p1 = container_of(a, typeof(*p1), head);
3266+ const struct ccs_signal_acl *p2 = container_of(b, typeof(*p2), head);
3267+ return ccs_same_number_union(&p1->sig, &p2->sig) &&
3268+ p1->domainname == p2->domainname;
3269+}
3270+
3271+/**
3272+ * ccs_write_ipc - Update "struct ccs_signal_acl" list.
3273+ *
3274+ * @param: Pointer to "struct ccs_acl_param".
3275+ *
3276+ * Returns 0 on success, negative value otherwise.
3277+ */
3278+static int ccs_write_ipc(struct ccs_acl_param *param)
3279+{
3280+ struct ccs_signal_acl e = { .head.type = CCS_TYPE_SIGNAL_ACL };
3281+ int error;
3282+ if (!ccs_parse_number_union(param, &e.sig))
3283+ return -EINVAL;
3284+ e.domainname = ccs_get_domainname(param);
3285+ if (!e.domainname)
3286+ error = -EINVAL;
3287+ else
3288+ error = ccs_update_domain(&e.head, sizeof(e), param,
3289+ ccs_same_signal_acl, NULL);
3290+ ccs_put_name(e.domainname);
3291+ ccs_put_number_union(&e.sig);
3292+ return error;
3293+}
3294+
3295+
3296+/**
3297+ * ccs_same_reserved - Check for duplicated "struct ccs_reserved" entry.
3298+ *
3299+ * @a: Pointer to "struct ccs_acl_head".
3300+ * @b: Pointer to "struct ccs_acl_head".
3301+ *
3302+ * Returns true if @a == @b, false otherwise.
3303+ */
3304+static bool ccs_same_reserved(const struct ccs_acl_head *a,
3305+ const struct ccs_acl_head *b)
3306+{
3307+ const struct ccs_reserved *p1 = container_of(a, typeof(*p1), head);
3308+ const struct ccs_reserved *p2 = container_of(b, typeof(*p2), head);
3309+ return p1->ns == p2->ns && ccs_same_number_union(&p1->port, &p2->port);
3310+}
3311+
3312+/**
3313+ * ccs_write_reserved_port - Update "struct ccs_reserved" list.
3314+ *
3315+ * @param: Pointer to "struct ccs_acl_param".
3316+ *
3317+ * Returns 0 on success, negative value otherwise.
3318+ */
3319+static int ccs_write_reserved_port(struct ccs_acl_param *param)
3320+{
3321+ struct ccs_reserved e = { .ns = param->ns };
3322+ int error;
3323+ if (param->data[0] == '@' || !ccs_parse_number_union(param, &e.port) ||
3324+ e.port.values[1] > 65535 || param->data[0])
3325+ return -EINVAL;
3326+ param->list = &ccs_reserved_list;
3327+ error = ccs_update_policy(&e.head, sizeof(e), param,
3328+ ccs_same_reserved);
3329+ /*
3330+ * ccs_put_number_union() is not needed because param->data[0] != '@'.
3331+ */
3332+ return error;
3333+}
3334+
3335+/**
3336+ * ccs_print_namespace - Print namespace header.
3337+ *
3338+ * @ns: Pointer to "struct ccs_policy_namespace".
3339+ *
3340+ * Returns nothing.
3341+ */
3342+static void ccs_print_namespace(const struct ccs_policy_namespace *ns)
3343+{
3344+ if (!ccs_namespace_enabled)
3345+ return;
3346+ cprintf("%s ", ns->name);
3347+}
3348+
3349+/**
3350+ * ccs_assign_profile - Create a new profile.
3351+ *
3352+ * @ns: Pointer to "struct ccs_policy_namespace".
3353+ * @profile: Profile number to create.
3354+ *
3355+ * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
3356+ */
3357+static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
3358+ const unsigned int profile)
3359+{
3360+ struct ccs_profile *ptr;
3361+ if (profile >= CCS_MAX_PROFILES)
3362+ return NULL;
3363+ ptr = ns->profile_ptr[profile];
3364+ if (ptr)
3365+ return ptr;
3366+ ptr = ccs_malloc(sizeof(*ptr));
3367+ ptr->default_config = CCS_CONFIG_DISABLED |
3368+ CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
3369+ memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
3370+ sizeof(ptr->config));
3371+ ptr->pref[CCS_PREF_MAX_AUDIT_LOG] = 1024;
3372+ ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] = 2048;
3373+ ns->profile_ptr[profile] = ptr;
3374+ return ptr;
3375+}
3376+
3377+/**
3378+ * ccs_find_yesno - Find values for specified keyword.
3379+ *
3380+ * @string: String to check.
3381+ * @find: Name of keyword.
3382+ *
3383+ * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
3384+ */
3385+static s8 ccs_find_yesno(const char *string, const char *find)
3386+{
3387+ const char *cp = strstr(string, find);
3388+ if (cp) {
3389+ cp += strlen(find);
3390+ if (!strncmp(cp, "=yes", 4))
3391+ return 1;
3392+ else if (!strncmp(cp, "=no", 3))
3393+ return 0;
3394+ }
3395+ return -1;
3396+}
3397+
3398+/**
3399+ * ccs_set_uint - Set value for specified preference.
3400+ *
3401+ * @i: Pointer to "unsigned int".
3402+ * @string: String to check.
3403+ * @find: Name of keyword.
3404+ *
3405+ * Returns nothing.
3406+ */
3407+static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
3408+{
3409+ const char *cp = strstr(string, find);
3410+ if (cp)
3411+ sscanf(cp + strlen(find), "=%u", i);
3412+}
3413+
3414+/**
3415+ * ccs_set_mode - Set mode for specified profile.
3416+ *
3417+ * @name: Name of functionality.
3418+ * @value: Mode for @name.
3419+ * @profile: Pointer to "struct ccs_profile".
3420+ *
3421+ * Returns 0 on success, negative value otherwise.
3422+ */
3423+static int ccs_set_mode(char *name, const char *value,
3424+ struct ccs_profile *profile)
3425+{
3426+ u8 i;
3427+ u8 config;
3428+ if (!strcmp(name, "CONFIG")) {
3429+ i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
3430+ config = profile->default_config;
3431+ } else if (ccs_str_starts(name, "CONFIG::")) {
3432+ config = 0;
3433+ for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
3434+ i++) {
3435+ int len = 0;
3436+ if (i < CCS_MAX_MAC_INDEX) {
3437+ const u8 c = ccs_index2category[i];
3438+ const char *category =
3439+ ccs_category_keywords[c];
3440+ len = strlen(category);
3441+ if (strncmp(name, category, len) ||
3442+ name[len++] != ':' || name[len++] != ':')
3443+ continue;
3444+ }
3445+ if (strcmp(name + len, ccs_mac_keywords[i]))
3446+ continue;
3447+ config = profile->config[i];
3448+ break;
3449+ }
3450+ if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
3451+ return -EINVAL;
3452+ } else {
3453+ return -EINVAL;
3454+ }
3455+ if (strstr(value, "use_default")) {
3456+ config = CCS_CONFIG_USE_DEFAULT;
3457+ } else {
3458+ u8 mode;
3459+ for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
3460+ if (strstr(value, ccs_mode[mode]))
3461+ /*
3462+ * Update lower 3 bits in order to distinguish
3463+ * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
3464+ */
3465+ config = (config & ~7) | mode;
3466+ if (config != CCS_CONFIG_USE_DEFAULT) {
3467+ switch (ccs_find_yesno(value, "grant_log")) {
3468+ case 1:
3469+ config |= CCS_CONFIG_WANT_GRANT_LOG;
3470+ break;
3471+ case 0:
3472+ config &= ~CCS_CONFIG_WANT_GRANT_LOG;
3473+ break;
3474+ }
3475+ switch (ccs_find_yesno(value, "reject_log")) {