• R/O
  • SSH
  • HTTPS

caitsith: Commit


Commit MetaInfo

Revision219 (tree)
Time2016-10-16 18:02:33
Authorkumaneko

Log Message

caitsith-tools 0.2.1

Change Summary

Incremental Difference

--- tags/caitsith-tools/0.2.1/caitsith-tools.spec (nonexistent)
+++ tags/caitsith-tools/0.2.1/caitsith-tools.spec (revision 219)
@@ -0,0 +1,77 @@
1+Summary: Userspace tools for CaitSith 0.2
2+
3+Name: caitsith-tools
4+Version: 0.2
5+Release: 2
6+License: GPL
7+Group: System Environment/Kernel
8+ExclusiveOS: Linux
9+Autoreqprov: no
10+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
11+##
12+## This spec file is intended to be distribution independent.
13+## I don't enable "BuildRequires:" line because rpmbuild will fail on
14+## environments where packages are managed by (e.g.) apt.
15+##
16+# BuildRequires: ncurses-devel
17+Requires: ncurses
18+Conflicts: caitsith-tools < 0.2-2
19+
20+Source0: http://osdn.dl.osdn.jp/caitsith/55465/caitsith-tools-0.2-20161016.tar.gz
21+
22+%description
23+This package contains userspace tools for administrating CaitSith 0.2.
24+Please see http://caitsith.osdn.jp/ for documentation.
25+
26+%prep
27+
28+%setup -q -n caitsith-tools
29+
30+%build
31+
32+make USRLIBDIR=%_libdir CFLAGS="-Wall $RPM_OPT_FLAGS"
33+
34+%install
35+
36+rm -rf $RPM_BUILD_ROOT
37+make INSTALLDIR=$RPM_BUILD_ROOT USRLIBDIR=%_libdir install
38+
39+%clean
40+
41+rm -rf $RPM_BUILD_ROOT
42+
43+%post
44+ldconfig || true
45+
46+%files
47+%defattr(-,root,root)
48+/sbin/*
49+%_libdir/caitsith/*
50+%_libdir/libcaitsith*
51+/usr/sbin/*
52+
53+%changelog
54+* Sun Oct 16 2016 0.2-2
55+- In order to cancel the effect of MS_REC|MS_SHARED done by systemd,
56+ mark MS_REC|MS_PRIVATE before mounting securityfs.
57+
58+* Wed Oct 05 2016 0.2-1
59+- Use /sys/kernel/security/caitsith/ by default and fall back to
60+ /proc/caitsith/ .
61+
62+* Thu Jul 23 2015 0.1-5
63+- caitsith-queryd: Copy a line to edit buffer correctly.
64+
65+* Sun Jan 05 2014 0.1-4
66+- Let caitsith-queryd use poll() rather than select().
67+
68+* Thu Feb 14 2013 0.1-3
69+- Change Makefile's build flags, as suggested by Simon Ruderich and Hideki
70+ Yamane. (Debian bug 674723)
71+- Change / to /* in rpm's %files section because Fedora 18 complains conflicts.
72+
73+* Sat May 05 2012 0.1-2
74+- caitsith-init: Count number of ACL entries correctly.
75+
76+* Sun Apr 01 2012 0.1-1
77+- First-release.
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsithtools.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsithtools.c (revision 219)
@@ -0,0 +1,409 @@
1+/*
2+ * caitsithtools.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/16
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include <unistd.h>
25+#include <sys/mount.h>
26+#include <sched.h>
27+
28+/* Use caitsith-agent process? */
29+_Bool ccs_network_mode = false;
30+/* The IPv4 address of the remote host running the caitsith-agent . */
31+u32 ccs_network_ip = INADDR_NONE;
32+/* The port number of the remote host running the caitsith-agent . */
33+u16 ccs_network_port = 0;
34+
35+const char *CCS_PROC_POLICY_DIR = "/sys/kernel/security/caitsith";
36+const char *CCS_PROC_POLICY_POLICY = "/sys/kernel/security/caitsith/policy";
37+
38+/* Prototypes */
39+
40+/* Utility functions */
41+
42+/**
43+ * ccs_out_of_memory - Print error message and abort.
44+ *
45+ * This function does not return.
46+ */
47+static void ccs_out_of_memory(void)
48+{
49+ fprintf(stderr, "Out of memory. Aborted.\n");
50+ exit(1);
51+}
52+
53+/**
54+ * ccs_strdup - strdup() with abort on error.
55+ *
56+ * @string: String to duplicate.
57+ *
58+ * Returns copy of @string on success, abort otherwise.
59+ */
60+char *ccs_strdup(const char *string)
61+{
62+ char *cp = strdup(string);
63+ if (!cp)
64+ ccs_out_of_memory();
65+ return cp;
66+}
67+
68+/**
69+ * ccs_realloc - realloc() with abort on error.
70+ *
71+ * @ptr: Pointer to void.
72+ * @size: New size.
73+ *
74+ * Returns return value of realloc() on success, abort otherwise.
75+ */
76+void *ccs_realloc(void *ptr, const size_t size)
77+{
78+ void *vp = realloc(ptr, size);
79+ if (!vp)
80+ ccs_out_of_memory();
81+ return vp;
82+}
83+
84+/**
85+ * ccs_malloc - malloc() with abort on error.
86+ *
87+ * @size: Size to allocate.
88+ *
89+ * Returns return value of malloc() on success, abort otherwise.
90+ *
91+ * Allocated memory is cleared with 0.
92+ */
93+void *ccs_malloc(const size_t size)
94+{
95+ void *vp = malloc(size);
96+ if (!vp)
97+ ccs_out_of_memory();
98+ memset(vp, 0, size);
99+ return vp;
100+}
101+
102+/**
103+ * ccs_str_starts - Check whether the given string starts with the given keyword.
104+ *
105+ * @str: Pointer to "char *".
106+ * @begin: Pointer to "const char *".
107+ *
108+ * Returns true if @str starts with @begin, false otherwise.
109+ *
110+ * Note that @begin will be removed from @str before returning true. Therefore,
111+ * @str must not be "const char *".
112+ *
113+ * Note that this function in kernel source has different arguments and behaves
114+ * differently.
115+ */
116+_Bool ccs_str_starts(char *str, const char *begin)
117+{
118+ const int len = strlen(begin);
119+ if (strncmp(str, begin, len))
120+ return false;
121+ memmove(str, str + len, strlen(str + len) + 1);
122+ return true;
123+}
124+
125+/**
126+ * ccs_normalize_line - Format string.
127+ *
128+ * @buffer: The line to normalize.
129+ *
130+ * Returns nothing.
131+ *
132+ * Leading and trailing whitespaces are removed.
133+ * Multiple whitespaces are packed into single space.
134+ */
135+void ccs_normalize_line(char *buffer)
136+{
137+ unsigned char *sp = (unsigned char *) buffer;
138+ unsigned char *dp = (unsigned char *) buffer;
139+ _Bool first = true;
140+ while (*sp && (*sp <= ' ' || 127 <= *sp))
141+ sp++;
142+ while (*sp) {
143+ if (!first)
144+ *dp++ = ' ';
145+ first = false;
146+ while (' ' < *sp && *sp < 127)
147+ *dp++ = *sp++;
148+ while (*sp && (*sp <= ' ' || 127 <= *sp))
149+ sp++;
150+ }
151+ *dp = '\0';
152+}
153+
154+/**
155+ * ccs_decode - Decode a string in CaitSith's rule to a string in C.
156+ *
157+ * @ascii: Pointer to "const char".
158+ * @bin: Pointer to "char". Must not contain wildcards nor '\000'.
159+ *
160+ * Returns true if @ascii was successfully decoded, false otherwise.
161+ *
162+ * Note that it is legal to pass @ascii == @bin if the caller want to decode
163+ * a string in a temporary buffer.
164+ */
165+_Bool ccs_decode(const char *ascii, char *bin)
166+{
167+ while (true) {
168+ char c = *ascii++;
169+ *bin++ = c;
170+ if (!c)
171+ break;
172+ if (c == '\\') {
173+ char d;
174+ char e;
175+ u8 f;
176+ c = *ascii++;
177+ switch (c) {
178+ case '0': /* "\ooo" */
179+ case '1':
180+ case '2':
181+ case '3':
182+ d = *ascii++;
183+ if (d < '0' || d > '7')
184+ break;
185+ e = *ascii++;
186+ if (e < '0' || e > '7')
187+ break;
188+ f = (u8) ((c - '0') << 6) +
189+ (((u8) (d - '0')) << 3) +
190+ (((u8) (e - '0')));
191+ if (f <= ' ' || f >= 127 || f == '\\') {
192+ *(bin - 1) = f;
193+ continue;
194+ }
195+ }
196+ return false;
197+ } else if (c <= ' ' || c >= 127) {
198+ return false;
199+ }
200+ }
201+ return true;
202+}
203+
204+/**
205+ * ccs_open_read - Open a file for reading.
206+ *
207+ * @filename: String to send to remote caitsith-agent program if using
208+ * network mode, file to open for reading otherwise.
209+ *
210+ * Returns pointer to "FILE" on success, NULL otherwise.
211+ */
212+FILE *ccs_open_read(const char *filename)
213+{
214+ if (ccs_network_mode) {
215+ FILE *fp = ccs_open_write(filename);
216+ if (fp) {
217+ fputc(0, fp);
218+ fflush(fp);
219+ }
220+ return fp;
221+ } else {
222+ return fopen(filename, "r");
223+ }
224+}
225+
226+/**
227+ * ccs_open_stream - Establish IP connection.
228+ *
229+ * @filename: String to send to remote caitsith-agent program.
230+ *
231+ * Retruns file descriptor on success, EOF otherwise.
232+ */
233+int ccs_open_stream(const char *filename)
234+{
235+ const int fd = socket(AF_INET, SOCK_STREAM, 0);
236+ struct sockaddr_in addr;
237+ char c;
238+ int len = strlen(filename) + 1;
239+ memset(&addr, 0, sizeof(addr));
240+ addr.sin_family = AF_INET;
241+ addr.sin_addr.s_addr = ccs_network_ip;
242+ addr.sin_port = ccs_network_port;
243+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) ||
244+ write(fd, filename, len) != len || read(fd, &c, 1) != 1 || c) {
245+ close(fd);
246+ return EOF;
247+ }
248+ return fd;
249+}
250+
251+/**
252+ * ccs_open_write - Open a file for writing.
253+ *
254+ * @filename: String to send to remote caitsith-agent program if using
255+ * network mode, file to open for writing otherwise.
256+ *
257+ * Returns pointer to "FILE" on success, NULL otherwise.
258+ */
259+FILE *ccs_open_write(const char *filename)
260+{
261+ if (ccs_network_mode) {
262+ const int fd = socket(AF_INET, SOCK_STREAM, 0);
263+ struct sockaddr_in addr;
264+ FILE *fp;
265+ memset(&addr, 0, sizeof(addr));
266+ addr.sin_family = AF_INET;
267+ addr.sin_addr.s_addr = ccs_network_ip;
268+ addr.sin_port = ccs_network_port;
269+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr))) {
270+ close(fd);
271+ return NULL;
272+ }
273+ fp = fdopen(fd, "r+");
274+ /* setbuf(fp, NULL); */
275+ fprintf(fp, "%s", filename);
276+ fputc(0, fp);
277+ fflush(fp);
278+ if (fgetc(fp) != 0) {
279+ fclose(fp);
280+ return NULL;
281+ }
282+ return fp;
283+ } else {
284+ return fdopen(open(filename, O_WRONLY), "w");
285+ }
286+}
287+
288+/* Is the shared buffer for ccs_freadline() owned? */
289+static _Bool ccs_buffer_locked = false;
290+
291+/**
292+ * ccs_get - Mark the shared buffer for ccs_freadline() owned.
293+ *
294+ * Returns nothing.
295+ *
296+ * This is for avoiding accidental overwriting.
297+ * ccs_freadline() have their own memory buffer.
298+ */
299+void ccs_get(void)
300+{
301+ if (ccs_buffer_locked)
302+ ccs_out_of_memory();
303+ ccs_buffer_locked = true;
304+}
305+
306+/**
307+ * ccs_put - Mark the shared buffer for ccs_freadline() no longer owned.
308+ *
309+ * Returns nothing.
310+ *
311+ * This is for avoiding accidental overwriting.
312+ * ccs_freadline() have their own memory buffer.
313+ */
314+void ccs_put(void)
315+{
316+ if (!ccs_buffer_locked)
317+ ccs_out_of_memory();
318+ ccs_buffer_locked = false;
319+}
320+
321+/**
322+ * ccs_freadline - Read a line from file to dynamically allocated buffer.
323+ *
324+ * @fp: Pointer to "FILE".
325+ *
326+ * Returns pointer to dynamically allocated buffer on success, NULL otherwise.
327+ *
328+ * The caller must not free() the returned pointer.
329+ */
330+char *ccs_freadline(FILE *fp)
331+{
332+ static char *policy = NULL;
333+ int pos = 0;
334+ while (true) {
335+ static int max_policy_len = 0;
336+ const int c = fgetc(fp);
337+ if (c == EOF)
338+ return NULL;
339+ if (ccs_network_mode && !c)
340+ return NULL;
341+ if (pos == max_policy_len) {
342+ max_policy_len += 4096;
343+ policy = ccs_realloc(policy, max_policy_len);
344+ }
345+ policy[pos++] = (char) c;
346+ if (c == '\n') {
347+ policy[--pos] = '\0';
348+ break;
349+ }
350+ }
351+ ccs_normalize_line(policy);
352+ return policy;
353+}
354+
355+/**
356+ * ccs_check_remote_host - Check whether the remote host is running with the CaitSith kernel or not.
357+ *
358+ * Returns true if running with CaitSith kernel, false otherwise.
359+ */
360+_Bool ccs_check_remote_host(_Bool exit_on_failue)
361+{
362+ int major = 0;
363+ int minor = 0;
364+ FILE *fp = ccs_open_read("version");
365+ if (!fp || (fscanf(fp, "%u.%u", &major, &minor) < 2 && major < 2016)) {
366+ const u32 ip = ntohl(ccs_network_ip);
367+ fprintf(stderr, "Can't connect to %u.%u.%u.%u:%u\n",
368+ (u8) (ip >> 24), (u8) (ip >> 16),
369+ (u8) (ip >> 8), (u8) ip, ntohs(ccs_network_port));
370+ if (fp)
371+ fclose(fp);
372+ if (exit_on_failue)
373+ exit(1);
374+ return false;
375+ } else if (major == 0 && minor == 1) {
376+ CCS_PROC_POLICY_DIR = "/proc/caitsith";
377+ CCS_PROC_POLICY_POLICY = "/proc/caitsith/policy";
378+ }
379+ fclose(fp);
380+ return true;
381+}
382+
383+_Bool ccs_check_policy_dir(_Bool exit_on_failue)
384+{
385+ if (access("/proc/caitsith/", X_OK) == 0) {
386+ CCS_PROC_POLICY_DIR = "/proc/caitsith";
387+ CCS_PROC_POLICY_POLICY = "/proc/caitsith/policy";
388+ } else if (access("/sys/kernel/security/caitsith/", X_OK) &&
389+ (unshare(CLONE_NEWNS) ||
390+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) ||
391+ mount("none", "/sys/kernel/security/", "securityfs", 0,
392+ NULL))) {
393+ if (errno != EBUSY) {
394+ fprintf(stderr, "Please mount securityfs on "
395+ "/sys/kernel/security/ .\n");
396+ if (exit_on_failue)
397+ exit(1);
398+ return false;
399+ }
400+ }
401+ if (chdir(CCS_PROC_POLICY_DIR)) {
402+ fprintf(stderr,
403+ "You can't run this program for this kernel.\n");
404+ if (exit_on_failue)
405+ exit(1);
406+ return false;
407+ }
408+ return true;
409+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-auditd.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-auditd.c (revision 219)
@@ -0,0 +1,460 @@
1+/*
2+ * caitsith-auditd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include <signal.h>
25+#include <syslog.h>
26+#include <poll.h>
27+
28+#define CCS_AUDITD_CONF "/etc/caitsith/tools/auditd.conf"
29+
30+struct ccs_destination {
31+ const char *pathname;
32+ int fd;
33+};
34+
35+static struct ccs_destination *destination_list = NULL;
36+static unsigned int destination_list_len = 0;
37+
38+enum ccs_rule_types {
39+ CCS_SORT_RULE_HEADER,
40+ CCS_SORT_RULE_ACL,
41+ CCS_SORT_RULE_DESTINATION,
42+};
43+
44+enum ccs_operator_types {
45+ CCS_SORT_OPERATOR_CONTAINS,
46+ CCS_SORT_OPERATOR_EQUALS,
47+ CCS_SORT_OPERATOR_STARTS,
48+};
49+
50+struct ccs_sort_rules {
51+ enum ccs_rule_types type;
52+ enum ccs_operator_types operation;
53+ unsigned int index;
54+ const char *string;
55+ unsigned int string_len; /* strlen(string). */
56+};
57+
58+static struct ccs_sort_rules *rules = NULL;
59+static unsigned int rules_len = 0;
60+
61+static void ccs_auditd_init_rules(const char *filename)
62+{
63+ static _Bool first = 1;
64+ FILE *fp = fopen(filename, "r");
65+ unsigned int line_no = 0;
66+ unsigned int i;
67+ if (!first) {
68+ for (i = 0; i < rules_len; i++)
69+ free((void *) rules[i].string);
70+ rules_len = 0;
71+ for (i = 0; i < destination_list_len; i++) {
72+ free((void *) destination_list[i].pathname);
73+ close(destination_list[i].fd);
74+ }
75+ destination_list_len = 0;
76+ }
77+ if (!fp) {
78+ if (first)
79+ fprintf(stderr, "Can't open %s for reading.\n",
80+ filename);
81+ else
82+ syslog(LOG_WARNING, "Can't open %s for reading.\n",
83+ filename);
84+ exit(1);
85+ }
86+ ccs_get();
87+ while (true) {
88+ char *line = ccs_freadline(fp);
89+ struct ccs_sort_rules *ptr;
90+ unsigned char c;
91+ if (!line)
92+ break;
93+ line_no++;
94+ ccs_normalize_line(line);
95+ if (*line == '#' || !*line)
96+ continue;
97+ rules = ccs_realloc(rules, sizeof(struct ccs_sort_rules) *
98+ (rules_len + 1));
99+ ptr = &rules[rules_len++];
100+ memset(ptr, 0, sizeof(*ptr));
101+ if (ccs_str_starts(line, "destination ")) {
102+ if (*line != '/')
103+ goto invalid_rule;
104+ for (i = 0; i < destination_list_len; i++)
105+ if (!strcmp(destination_list[i].pathname,
106+ line))
107+ break;
108+ if (i < destination_list_len)
109+ goto store_destination;
110+ destination_list =
111+ ccs_realloc(destination_list,
112+ ++destination_list_len *
113+ sizeof(struct ccs_destination));
114+ if (!ccs_decode(line, line))
115+ goto invalid_rule;
116+ destination_list[i].pathname = ccs_strdup(line);
117+ destination_list[i].fd = EOF;
118+store_destination:
119+ ptr->type = CCS_SORT_RULE_DESTINATION;
120+ ptr->index = i;
121+ continue;
122+ }
123+ if (ccs_str_starts(line, "header"))
124+ ptr->type = CCS_SORT_RULE_HEADER;
125+ else if (ccs_str_starts(line, "acl"))
126+ ptr->type = CCS_SORT_RULE_ACL;
127+ else
128+ goto invalid_rule;
129+ switch (sscanf(line, "[%u%c", &ptr->index, &c)) {
130+ case 0:
131+ break;
132+ case 2:
133+ if (c == ']') {
134+ char *cp = strchr(line, ']') + 1;
135+ memmove(line, cp, strlen(cp) + 1);
136+ break;
137+ }
138+ default:
139+ goto invalid_rule;
140+ }
141+ if (ccs_str_starts(line, ".contains "))
142+ ptr->operation = CCS_SORT_OPERATOR_CONTAINS;
143+ else if (ccs_str_starts(line, ".equals "))
144+ ptr->operation = CCS_SORT_OPERATOR_EQUALS;
145+ else if (ccs_str_starts(line, ".starts "))
146+ ptr->operation = CCS_SORT_OPERATOR_STARTS;
147+ else
148+ goto invalid_rule;
149+ if (!*line)
150+ goto invalid_rule;
151+ line = ccs_strdup(line);
152+ ptr->string = line;
153+ ptr->string_len = strlen(line);
154+ }
155+ ccs_put();
156+ fclose(fp);
157+ if (!rules_len) {
158+ if (first)
159+ fprintf(stderr, "No rules defined in %s .\n",
160+ filename);
161+ else
162+ syslog(LOG_WARNING, "No rules defined in %s .\n",
163+ filename);
164+ exit(1);
165+ }
166+ for (i = 0; i < destination_list_len; i++) {
167+ struct ccs_destination *ptr = &destination_list[i];
168+ const char *path = ptr->pathname;
169+ /* This is OK because path is a strdup()ed string. */
170+ char *pos = (char *) path;
171+ while (*pos) {
172+ int ret_ignored;
173+ if (*pos++ != '/')
174+ continue;
175+ *(pos - 1) = '\0';
176+ ret_ignored = mkdir(path, 0700);
177+ *(pos - 1) = '/';
178+ }
179+ do {
180+ ptr->fd = open(path, O_WRONLY | O_APPEND | O_CREAT,
181+ 0600);
182+ } while (ptr->fd == EOF && errno == EINTR);
183+ if (ptr->fd == EOF) {
184+ if (first)
185+ fprintf(stderr, "Can't open %s for writing.\n",
186+ path);
187+ else
188+ syslog(LOG_WARNING,
189+ "Can't open %s for writing.\n", path);
190+ exit(1);
191+ }
192+ }
193+ first = 0;
194+ return;
195+invalid_rule:
196+ if (first)
197+ fprintf(stderr, "Invalid rule at line %u in %s .\n", line_no,
198+ filename);
199+ else
200+ syslog(LOG_WARNING, "Invalid rule at line %u in %s .\n",
201+ line_no, filename);
202+ exit(1);
203+}
204+
205+static int ccs_check_rules(char *header, char *acl)
206+{
207+ unsigned int i;
208+ _Bool matched = true;
209+ for (i = 0; i < rules_len; i++) {
210+ const struct ccs_sort_rules *ptr = &rules[i];
211+ char *line;
212+ unsigned int index = ptr->index;
213+ const char *find = ptr->string;
214+ unsigned int find_len = ptr->string_len;
215+ switch (ptr->type) {
216+ case CCS_SORT_RULE_HEADER:
217+ line = header;
218+ break;
219+ case CCS_SORT_RULE_ACL:
220+ line = acl;
221+ break;
222+ default: /* CCS_SORT_RULE_DESTINATION */
223+ if (matched)
224+ return ptr->index;
225+ matched = true;
226+ continue;
227+ }
228+ if (!matched)
229+ continue;
230+ if (!index) {
231+ switch (ptr->operation) {
232+ case CCS_SORT_OPERATOR_CONTAINS:
233+ while (1) {
234+ char *cp = strstr(line, find);
235+ if (!cp) {
236+ matched = false;
237+ break;
238+ }
239+ if ((cp == line || *(cp - 1) == ' ') &&
240+ (!cp[find_len] ||
241+ cp[find_len] == ' '))
242+ break;
243+ line = cp + 1;
244+ }
245+ break;
246+ case CCS_SORT_OPERATOR_EQUALS:
247+ matched = !strcmp(line, find);
248+ break;
249+ default: /* CCS_SORT_OPERATOR_STARTS */
250+ matched = !strncmp(line, find, find_len) &&
251+ (!line[find_len] ||
252+ line[find_len] == ' ');
253+ }
254+ } else {
255+ char *word = line;
256+ char *word_end;
257+ while (--index) {
258+ char *cp = strchr(word, ' ');
259+ if (!cp) {
260+ matched = false;
261+ break;
262+ }
263+ word = cp + 1;
264+ }
265+ if (!matched)
266+ continue;
267+ word_end = strchr(word, ' ');
268+ if (word_end)
269+ *word_end = '\0';
270+ switch (ptr->operation) {
271+ case CCS_SORT_OPERATOR_CONTAINS:
272+ matched = strstr(word, find) != NULL;
273+ break;
274+ case CCS_SORT_OPERATOR_EQUALS:
275+ matched = !strcmp(word, find);
276+ break;
277+ default: /* CCS_SORT_OPERATOR_STARTS */
278+ matched = !strncmp(word, find, find_len);
279+ break;
280+ }
281+ if (word_end)
282+ *word_end = ' ';
283+ }
284+ }
285+ return EOF;
286+}
287+
288+static _Bool ccs_write_log(const int i, char *buffer)
289+{
290+ int len = strlen(buffer);
291+ int ret;
292+ struct ccs_destination *ptr = &destination_list[i];
293+ /* Create destination file if needed. */
294+ if (access(ptr->pathname, F_OK)) {
295+ close(ptr->fd);
296+ do {
297+ ptr->fd = open(ptr->pathname,
298+ O_WRONLY | O_APPEND | O_CREAT, 0600);
299+ } while (ptr->fd == EOF && errno == EINTR);
300+ if (ptr->fd == EOF) {
301+ syslog(LOG_WARNING, "Can't open %s for writing.\n",
302+ ptr->pathname);
303+ return 0;
304+ }
305+ }
306+ do {
307+ ret = write(ptr->fd, buffer, len);
308+ if (ret == len)
309+ return 1;
310+ } while (ret == EOF && errno == EINTR);
311+ syslog(LOG_WARNING, "Can't write to %s .\n", ptr->pathname);
312+ return 0;
313+}
314+
315+static void block_sighup(const _Bool block)
316+{
317+ sigset_t sigset;
318+ sigemptyset(&sigset);
319+ sigaddset(&sigset, SIGHUP);
320+ sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigset, NULL);
321+}
322+
323+static void ccs_reload_config(int sig)
324+{
325+ block_sighup(1);
326+ syslog(LOG_WARNING, "Reloading configuration file.\n");
327+ ccs_auditd_init_rules(CCS_AUDITD_CONF);
328+ block_sighup(0);
329+}
330+
331+int main(int argc, char *argv[])
332+{
333+ unsigned int i;
334+ int fd_in;
335+ for (i = 1; i < argc; i++) {
336+ char *ptr = argv[i];
337+ char *cp = strchr(ptr, ':');
338+ if (!cp)
339+ goto usage;
340+ *cp++ = '\0';
341+ if (ccs_network_mode)
342+ goto usage;
343+ ccs_network_ip = inet_addr(ptr);
344+ ccs_network_port = htons(atoi(cp));
345+ ccs_network_mode = true;
346+ }
347+ ccs_auditd_init_rules(CCS_AUDITD_CONF);
348+ if (!ccs_network_mode) {
349+ /* Get exclusive lock. */
350+ int fd = open("/proc/self/exe", O_RDONLY);
351+ if (flock(fd, LOCK_EX | LOCK_NB) == EOF)
352+ return 0;
353+ }
354+ if (ccs_network_mode) {
355+ ccs_check_remote_host(true);
356+ fd_in = ccs_open_stream("proc:audit");
357+ } else {
358+ ccs_check_policy_dir(true);
359+ fd_in = open("audit", O_RDONLY);
360+ }
361+ if (fd_in == EOF) {
362+ fprintf(stderr, "Can't open %s/audit for reading.\n",
363+ CCS_PROC_POLICY_DIR);
364+ return 1;
365+ }
366+ switch (fork()) {
367+ case 0:
368+ break;
369+ case -1:
370+ fprintf(stderr, "Can't fork()\n");
371+ return 1;
372+ default:
373+ return 0;
374+ }
375+ if (setsid() == EOF) {
376+ fprintf(stderr, "Can't setsid()\n");
377+ return 1;
378+ }
379+ switch (fork()) {
380+ case 0:
381+ break;
382+ case -1:
383+ fprintf(stderr, "Can't fork()\n");
384+ return 1;
385+ default:
386+ return 0;
387+ }
388+ if (chdir("/")) {
389+ fprintf(stderr, "Can't chdir()\n");
390+ return 1;
391+ }
392+ close(0);
393+ close(1);
394+ close(2);
395+ openlog("caitsith-auditd", 0, LOG_USER);
396+ syslog(LOG_WARNING, "Started.\n");
397+ signal(SIGHUP, ccs_reload_config);
398+ while (true) {
399+ static char buffer[32768];
400+ char *acl;
401+ char *tail;
402+ int ret;
403+ memset(buffer, 0, sizeof(buffer));
404+ if (ccs_network_mode) {
405+ int j;
406+ for (j = 0; j < sizeof(buffer) - 1; j++) {
407+ do {
408+ ret = read(fd_in, buffer + j, 1);
409+ } while (ret == EOF && errno == EINTR);
410+ if (ret != 1)
411+ goto out;
412+ if (!buffer[j])
413+ break;
414+ }
415+ if (j == sizeof(buffer) - 1)
416+ goto out;
417+ } else {
418+ while (read(fd_in, buffer, sizeof(buffer) - 1) <= 0) {
419+ /* Wait for data. */
420+ struct pollfd pfd = {
421+ .fd = fd_in,
422+ .events = POLLIN,
423+ };
424+ if (poll(&pfd, 1, -1) == EOF && errno != EINTR)
425+ goto out;
426+ }
427+ }
428+ /* Split into two parts. */
429+ acl = strstr(buffer, " / ");
430+ if (!acl)
431+ continue;
432+ *acl = '\0';
433+ acl += 3;
434+ tail = strchr(acl, '\n');
435+ if (!tail)
436+ continue;
437+ *tail = '\0';
438+ block_sighup(1);
439+ /* Check for filtering rules. */
440+ i = ccs_check_rules(buffer, acl);
441+ if (i != EOF) {
442+ *tail = '\n';
443+ *(acl - 3) = ' ';
444+ /* Write the audit log. */
445+ if (!ccs_write_log(i, buffer))
446+ break;
447+ }
448+ block_sighup(0);
449+ }
450+out:
451+ syslog(LOG_WARNING, "Terminated.\n");
452+ closelog();
453+ return 1;
454+usage:
455+ printf("Usage: %s [remote_ip:remote_port]\n\n"
456+ "remote_ip:remote_port : Read from caitsith-agent listening "
457+ "at remote_ip:remote_port .\n\n"
458+ "See %s for configuration.\n", argv[0], CCS_AUDITD_CONF);
459+ return 1;
460+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-loadpolicy.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-loadpolicy.c (revision 219)
@@ -0,0 +1,100 @@
1+/*
2+ * caitsith-loadpolicy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+/**
26+ * ccs_close_write - Close stream opened by ccs_open_write().
27+ *
28+ * @fp: Pointer to "FILE".
29+ *
30+ * Returns true on success, false otherwise.
31+ */
32+static _Bool ccs_close_write(FILE *fp)
33+{
34+ _Bool result = true;
35+ if (ccs_network_mode) {
36+ if (fputc(0, fp) == EOF)
37+ result = false;
38+ if (fflush(fp) == EOF)
39+ result = false;
40+ if (fgetc(fp) == EOF)
41+ result = false;
42+ }
43+ if (fclose(fp) == EOF)
44+ result = false;
45+ return result;
46+}
47+
48+static _Bool ccs_move_file_to_proc(const char *dest)
49+{
50+ FILE *proc_fp = ccs_open_write(dest);
51+ _Bool result = true;
52+ if (!proc_fp) {
53+ fprintf(stderr, "Can't open %s for writing.\n", dest);
54+ return false;
55+ }
56+ ccs_get();
57+ while (true) {
58+ char *line = ccs_freadline(stdin);
59+ if (!line)
60+ break;
61+ if (line[0])
62+ if (fprintf(proc_fp, "%s\n", line) < 0)
63+ result = false;
64+ }
65+ ccs_put();
66+ if (!ccs_close_write(proc_fp))
67+ result = false;
68+ return result;
69+}
70+
71+int main(int argc, char *argv[])
72+{
73+ int i;
74+ for (i = 1; i < argc; i++) {
75+ char *ptr = argv[i];
76+ char *cp = strchr(ptr, ':');
77+ if (!cp)
78+ goto usage;
79+ *cp++ = '\0';
80+ ccs_network_ip = inet_addr(ptr);
81+ ccs_network_port = htons(atoi(cp));
82+ if (ccs_network_mode) {
83+ fprintf(stderr, "You cannot specify multiple "
84+ "%s at the same time.\n\n",
85+ "remote agents");
86+ goto usage;
87+ }
88+ ccs_network_mode = true;
89+ }
90+ if (ccs_network_mode)
91+ ccs_check_remote_host(true);
92+ else
93+ ccs_check_policy_dir(true);
94+ return !ccs_move_file_to_proc(CCS_PROC_POLICY_POLICY);
95+usage:
96+ printf("Usage: %s [remote_ip:remote_port]\n\n"
97+ "remote_ip:remote_port : Write to caitsith-agent listening at "
98+ "remote_ip:remote_port .\n", argv[0]);
99+ return 1;
100+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-notifyd.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-notifyd.c (revision 219)
@@ -0,0 +1,252 @@
1+/*
2+ * caitsith-notifyd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include <sys/wait.h>
25+#include <signal.h>
26+#include <syslog.h>
27+#include <poll.h>
28+
29+#define CCS_NOTIFYD_CONF "/etc/caitsith/tools/notifyd.conf"
30+
31+static int query_fd = EOF;
32+static int time_to_wait = 0;
33+static char **action_to_take = NULL;
34+static int minimal_interval = 0;
35+
36+static void ccs_notifyd_init_rules(const char *filename)
37+{
38+ static _Bool first = 1;
39+ FILE *fp = fopen(filename, "r");
40+ unsigned int line_no = 0;
41+ char *action = NULL;
42+ if (!first) {
43+ free(action_to_take);
44+ action_to_take = NULL;
45+ time_to_wait = 0;
46+ minimal_interval = 0;
47+ }
48+ if (!fp) {
49+ if (first)
50+ fprintf(stderr, "Can't open %s for reading.\n",
51+ filename);
52+ else
53+ syslog(LOG_WARNING, "Can't open %s for reading.\n",
54+ filename);
55+ exit(1);
56+ }
57+ ccs_get();
58+ while (true) {
59+ char *line = ccs_freadline(fp);
60+ if (!line)
61+ break;
62+ line_no++;
63+ ccs_normalize_line(line);
64+ if (*line == '#' || !*line)
65+ continue;
66+ if (sscanf(line, "time_to_wait %u", &time_to_wait) == 1 ||
67+ sscanf(line, "minimal_interval %u", &minimal_interval)
68+ == 1)
69+ continue;
70+ if (!ccs_str_starts(line, "action_to_take "))
71+ continue;
72+ if (!*line)
73+ goto invalid_rule;
74+ if (action)
75+ goto invalid_rule;
76+ action = ccs_strdup(line);
77+ }
78+ ccs_put();
79+ fclose(fp);
80+ if (!action) {
81+ if (first)
82+ fprintf(stderr, "No actions defined in %s .\n",
83+ filename);
84+ else
85+ syslog(LOG_WARNING, "No actions defined in %s .\n",
86+ filename);
87+ exit(1);
88+ }
89+ {
90+ int count = 0;
91+ char *sp = action;
92+ while (true) {
93+ char *cp = strsep(&sp, " ");
94+ action_to_take = ccs_realloc(action_to_take,
95+ sizeof(char *) * ++count);
96+ action_to_take[count - 1] = cp;
97+ if (!cp)
98+ break;
99+ if (!ccs_decode(cp, cp))
100+ goto invalid_rule;
101+ }
102+ }
103+ first = 0;
104+ return;
105+invalid_rule:
106+ if (first)
107+ fprintf(stderr, "Invalid rule at line %u in %s .\n", line_no,
108+ filename);
109+ else
110+ syslog(LOG_WARNING, "Invalid rule at line %u in %s .\n",
111+ line_no, filename);
112+ exit(1);
113+}
114+
115+static void block_sighup(const _Bool block)
116+{
117+ sigset_t sigset;
118+ sigemptyset(&sigset);
119+ sigaddset(&sigset, SIGHUP);
120+ sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigset, NULL);
121+}
122+
123+static void main_loop(void)
124+{
125+ static char buffer[32768];
126+ while (query_fd != EOF) {
127+ int pipe_fd[2];
128+ pid_t pid;
129+ memset(buffer, 0, sizeof(buffer));
130+ while (read(query_fd, buffer, sizeof(buffer) - 1) <= 0) {
131+ /* Wait for data. */
132+ struct pollfd pfd = {
133+ .fd = query_fd,
134+ .events = POLLIN,
135+ };
136+ if (poll(&pfd, 1, -1) == EOF && errno != EINTR)
137+ return;
138+ }
139+ if (pipe(pipe_fd) == EOF) {
140+ syslog(LOG_WARNING, "Can't create pipe.\n");
141+ return;
142+ }
143+ block_sighup(1);
144+ pid = fork();
145+ if (pid == -1) {
146+ syslog(LOG_WARNING, "Can't fork().\n");
147+ return;
148+ }
149+ if (!pid) {
150+ int ret_ignored;
151+ ret_ignored = close(query_fd);
152+ ret_ignored = close(pipe_fd[1]);
153+ ret_ignored = close(0);
154+ ret_ignored = dup2(pipe_fd[0], 0);
155+ ret_ignored = close(pipe_fd[0]);
156+ execvp(action_to_take[0], action_to_take);
157+ syslog(LOG_WARNING, "Can't execute %s\n",
158+ action_to_take[0]);
159+ closelog();
160+ _exit(1);
161+ } else {
162+ int ret_ignored;
163+ int len = strlen(buffer);
164+ close(pipe_fd[0]);
165+ /* This is OK because read() < sizeof(buffer). */
166+ buffer[len++] = '\n';
167+ ret_ignored = write(pipe_fd[1], buffer, len);
168+ close(pipe_fd[1]);
169+ }
170+ block_sighup(0);
171+ while (time_to_wait-- > 0) {
172+ int ret_ignored;
173+ sleep(1);
174+ ret_ignored = write(query_fd, "\n", 1);
175+ }
176+ close(query_fd);
177+ while (waitpid(pid, NULL, __WALL) == EOF && errno == EINTR);
178+ sleep(minimal_interval);
179+ do {
180+ query_fd = open("query", O_RDWR);
181+ } while (query_fd == EOF && errno == EINTR);
182+ }
183+}
184+
185+static void ccs_reload_config(int sig)
186+{
187+ block_sighup(1);
188+ syslog(LOG_WARNING, "Reloading configuration file.\n");
189+ ccs_notifyd_init_rules(CCS_NOTIFYD_CONF);
190+ block_sighup(0);
191+}
192+
193+int main(int argc, char *argv[])
194+{
195+ unsetenv("SHELLOPTS"); /* Make sure popen() executes commands. */
196+ if (argc != 1)
197+ goto usage;
198+ ccs_notifyd_init_rules(CCS_NOTIFYD_CONF);
199+ ccs_check_policy_dir(true);
200+ query_fd = open("query", O_RDWR);
201+ if (query_fd == EOF) {
202+ fprintf(stderr, "You can't run this daemon for this kernel."
203+ "\n");
204+ return 1;
205+ } else if (time_to_wait && write(query_fd, "", 0) != 0) {
206+ fprintf(stderr, "You need to give this program permission to "
207+ "modify policy.\n");
208+ return 1;
209+ }
210+ umask(0);
211+ switch (fork()) {
212+ case 0:
213+ break;
214+ case -1:
215+ fprintf(stderr, "Can't fork()\n");
216+ return 1;
217+ default:
218+ return 0;
219+ }
220+ if (setsid() == EOF) {
221+ fprintf(stderr, "Can't setsid()\n");
222+ return 1;
223+ }
224+ switch (fork()) {
225+ case 0:
226+ break;
227+ case -1:
228+ fprintf(stderr, "Can't fork()\n");
229+ return 1;
230+ default:
231+ return 0;
232+ }
233+ { /* Get exclusive lock. */
234+ int fd = open("/proc/self/exe", O_RDONLY);
235+ if (flock(fd, LOCK_EX | LOCK_NB) == EOF)
236+ return 0;
237+ }
238+ close(0);
239+ close(1);
240+ close(2);
241+ openlog("caitsith-notifyd", 0, LOG_USER);
242+ syslog(LOG_WARNING, "Started.\n");
243+ signal(SIGHUP, ccs_reload_config);
244+ main_loop();
245+ syslog(LOG_WARNING, "Terminated.\n");
246+ closelog();
247+ return 1;
248+usage:
249+ printf("Usage: %s\n\nSee %s for configuration.\n", argv[0],
250+ CCS_NOTIFYD_CONF);
251+ return 1;
252+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-pstree.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-pstree.c (revision 219)
@@ -0,0 +1,387 @@
1+/*
2+ * caitsith-pstree.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+struct ccs_task_entry {
26+ pid_t pid;
27+ pid_t ppid;
28+ char *name;
29+ char *domain;
30+ _Bool selected;
31+ int index;
32+ int depth;
33+};
34+
35+/* The list of processes currently running. */
36+static struct ccs_task_entry *ccs_task_list = NULL;
37+/* The length of ccs_task_list . */
38+static int ccs_task_list_len = 0;
39+
40+/* Serial number for sorting ccs_task_list . */
41+static int ccs_dump_index = 0;
42+
43+/**
44+ * ccs_sort_process_entry - Sort ccs_tasklist list.
45+ *
46+ * @pid: Pid to search.
47+ * @depth: Depth of the process for printing like pstree command.
48+ *
49+ * Returns nothing.
50+ */
51+static void ccs_sort_process_entry(const pid_t pid, const int depth)
52+{
53+ int i;
54+ for (i = 0; i < ccs_task_list_len; i++) {
55+ if (pid != ccs_task_list[i].pid)
56+ continue;
57+ ccs_task_list[i].index = ccs_dump_index++;
58+ ccs_task_list[i].depth = depth;
59+ ccs_task_list[i].selected = true;
60+ }
61+ for (i = 0; i < ccs_task_list_len; i++) {
62+ if (pid != ccs_task_list[i].ppid)
63+ continue;
64+ ccs_sort_process_entry(ccs_task_list[i].pid, depth + 1);
65+ }
66+}
67+
68+/**
69+ * ccs_task_entry_compare - Compare routine for qsort() callback.
70+ *
71+ * @a: Pointer to "void".
72+ * @b: Pointer to "void".
73+ *
74+ * Returns index diff value.
75+ */
76+static int ccs_task_entry_compare(const void *a, const void *b)
77+{
78+ const struct ccs_task_entry *a0 = (struct ccs_task_entry *) a;
79+ const struct ccs_task_entry *b0 = (struct ccs_task_entry *) b;
80+ return a0->index - b0->index;
81+}
82+
83+/**
84+ * ccs_add_process_entry - Add entry for running processes.
85+ *
86+ * @line: A line containing PID and domainname.
87+ * @ppid: Parent PID.
88+ * @name: Comm name (allocated by strdup()).
89+ *
90+ * Returns nothing.
91+ *
92+ * @name is free()d on failure.
93+ */
94+static void ccs_add_process_entry(const char *line, const pid_t ppid,
95+ char *name)
96+{
97+ int index;
98+ unsigned int pid = 0;
99+ char *domain;
100+ if (!line || sscanf(line, "%u", &pid) != 1) {
101+ free(name);
102+ return;
103+ }
104+ domain = strchr(line, ' ');
105+ if (domain++)
106+ domain = ccs_strdup(domain);
107+ else
108+ domain = ccs_strdup("<UNKNOWN>");
109+ index = ccs_task_list_len++;
110+ ccs_task_list = ccs_realloc(ccs_task_list, ccs_task_list_len *
111+ sizeof(struct ccs_task_entry));
112+ memset(&ccs_task_list[index], 0, sizeof(ccs_task_list[0]));
113+ ccs_task_list[index].pid = pid;
114+ ccs_task_list[index].ppid = ppid;
115+ ccs_task_list[index].name = name;
116+ ccs_task_list[index].domain = domain;
117+}
118+
119+/**
120+ * ccs_get_ppid - Get PPID of the given PID.
121+ *
122+ * @pid: A pid_t value.
123+ *
124+ * Returns PPID value.
125+ */
126+static pid_t ccs_get_ppid(const pid_t pid)
127+{
128+ char buffer[1024];
129+ FILE *fp;
130+ pid_t ppid = 1;
131+ memset(buffer, 0, sizeof(buffer));
132+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
133+ fp = fopen(buffer, "r");
134+ if (fp) {
135+ while (memset(buffer, 0, sizeof(buffer)) &&
136+ fgets(buffer, sizeof(buffer) - 1, fp)) {
137+ if (sscanf(buffer, "PPid: %u", &ppid) == 1)
138+ break;
139+ }
140+ fclose(fp);
141+ }
142+ return ppid;
143+}
144+
145+/**
146+ * ccs_get_name - Get comm name of the given PID.
147+ *
148+ * @pid: A pid_t value.
149+ *
150+ * Returns comm name using on success, NULL otherwise.
151+ *
152+ * The caller must free() the returned pointer.
153+ */
154+static char *ccs_get_name(const pid_t pid)
155+{
156+ char buffer[1024];
157+ FILE *fp;
158+ memset(buffer, 0, sizeof(buffer));
159+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
160+ fp = fopen(buffer, "r");
161+ if (fp) {
162+ static const int offset = sizeof(buffer) / 6;
163+ while (memset(buffer, 0, sizeof(buffer)) &&
164+ fgets(buffer, sizeof(buffer) - 1, fp)) {
165+ if (!strncmp(buffer, "Name:\t", 6)) {
166+ char *cp = buffer + 6;
167+ memmove(buffer, cp, strlen(cp) + 1);
168+ cp = strchr(buffer, '\n');
169+ if (cp)
170+ *cp = '\0';
171+ break;
172+ }
173+ }
174+ fclose(fp);
175+ if (buffer[0] && strlen(buffer) < offset - 1) {
176+ const char *src = buffer;
177+ char *dest = buffer + offset;
178+ while (1) {
179+ unsigned char c = *src++;
180+ if (!c) {
181+ *dest = '\0';
182+ break;
183+ }
184+ if (c == '\\') {
185+ c = *src++;
186+ if (c == '\\') {
187+ memmove(dest, "\\134", 4);
188+ dest += 4;
189+ } else if (c == 'n') {
190+ memmove(dest, "\\012", 4);
191+ dest += 4;
192+ } else {
193+ break;
194+ }
195+ } else if (c > ' ' && c <= 126) {
196+ *dest++ = c;
197+ } else {
198+ *dest++ = '\\';
199+ *dest++ = (c >> 6) + '0';
200+ *dest++ = ((c >> 3) & 7) + '0';
201+ *dest++ = (c & 7) + '0';
202+ }
203+ }
204+ return strdup(buffer + offset);
205+ }
206+ }
207+ return NULL;
208+}
209+
210+/**
211+ * ccs_read_process_list - Read all process's information.
212+ *
213+ * @show_all: Ture if kernel threads should be included, false otherwise.
214+ *
215+ * Returns nothing.
216+ */
217+static void ccs_read_process_list(_Bool show_all)
218+{
219+ int i;
220+ while (ccs_task_list_len) {
221+ ccs_task_list_len--;
222+ free((void *) ccs_task_list[ccs_task_list_len].name);
223+ free((void *) ccs_task_list[ccs_task_list_len].domain);
224+ }
225+ ccs_dump_index = 0;
226+ if (ccs_network_mode) {
227+ FILE *fp = ccs_open_write(show_all ?
228+ "proc:all_process_status" :
229+ "proc:process_status");
230+ if (!fp)
231+ return;
232+ ccs_get();
233+ while (true) {
234+ char *line = ccs_freadline(fp);
235+ unsigned int pid = 0;
236+ unsigned int ppid = 0;
237+ char *name;
238+ if (!line)
239+ break;
240+ sscanf(line, "PID=%u PPID=%u", &pid, &ppid);
241+ name = strstr(line, "NAME=");
242+ if (name)
243+ name = ccs_strdup(name + 5);
244+ else
245+ name = ccs_strdup("<UNKNOWN>");
246+ line = ccs_freadline(fp);
247+ ccs_add_process_entry(line, ppid, name);
248+ }
249+ ccs_put();
250+ fclose(fp);
251+ } else {
252+ static const int line_len = 8192;
253+ char *line;
254+ int status_fd = open(".process_status", O_RDWR);
255+ DIR *dir = opendir("/proc/");
256+ if (status_fd == EOF || !dir) {
257+ if (status_fd != EOF)
258+ close(status_fd);
259+ if (dir)
260+ closedir(dir);
261+ return;
262+ }
263+ line = ccs_malloc(line_len);
264+ while (1) {
265+ char *name;
266+ int ret_ignored;
267+ unsigned int pid = 0;
268+ char buffer[128];
269+ char test[16];
270+ struct dirent *dent = readdir(dir);
271+ if (!dent)
272+ break;
273+ if (dent->d_type != DT_DIR ||
274+ sscanf(dent->d_name, "%u", &pid) != 1 || !pid)
275+ continue;
276+ memset(buffer, 0, sizeof(buffer));
277+ if (!show_all) {
278+ snprintf(buffer, sizeof(buffer) - 1,
279+ "/proc/%u/exe", pid);
280+ if (readlink(buffer, test, sizeof(test)) <= 0)
281+ continue;
282+ }
283+ name = ccs_get_name(pid);
284+ if (!name)
285+ name = ccs_strdup("<UNKNOWN>");
286+ snprintf(buffer, sizeof(buffer) - 1, "%u\n", pid);
287+ ret_ignored = write(status_fd, buffer, strlen(buffer));
288+ memset(line, 0, line_len);
289+ ret_ignored = read(status_fd, line, line_len - 1);
290+ ccs_add_process_entry(line, ccs_get_ppid(pid), name);
291+ }
292+ free(line);
293+ closedir(dir);
294+ close(status_fd);
295+ }
296+ ccs_sort_process_entry(1, 0);
297+ for (i = 0; i < ccs_task_list_len; i++) {
298+ if (ccs_task_list[i].selected) {
299+ ccs_task_list[i].selected = false;
300+ continue;
301+ }
302+ ccs_task_list[i].index = ccs_dump_index++;
303+ ccs_task_list[i].depth = 0;
304+ }
305+ qsort(ccs_task_list, ccs_task_list_len, sizeof(struct ccs_task_entry),
306+ ccs_task_entry_compare);
307+}
308+
309+static void ccs_dump(const pid_t pid, const int depth)
310+{
311+ int i;
312+ for (i = 0; i < ccs_task_list_len; i++) {
313+ int j;
314+ if (pid != ccs_task_list[i].pid)
315+ continue;
316+ for (j = 0; j < depth - 1; j++)
317+ printf(" ");
318+ for (; j < depth; j++)
319+ printf(" +-");
320+ printf(" %s (%u) %s\n", ccs_task_list[i].name,
321+ ccs_task_list[i].pid, ccs_task_list[i].domain);
322+ ccs_task_list[i].selected = true;
323+ }
324+ for (i = 0; i < ccs_task_list_len; i++) {
325+ if (pid != ccs_task_list[i].ppid)
326+ continue;
327+ ccs_dump(ccs_task_list[i].pid, depth + 1);
328+ }
329+}
330+
331+int main(int argc, char *argv[])
332+{
333+ static _Bool show_all = false;
334+ int i;
335+ for (i = 1; i < argc; i++) {
336+ char *ptr = argv[i];
337+ char *cp = strchr(ptr, ':');
338+ if (cp) {
339+ *cp++ = '\0';
340+ if (ccs_network_mode)
341+ goto usage;
342+ ccs_network_ip = inet_addr(ptr);
343+ ccs_network_port = htons(atoi(cp));
344+ ccs_network_mode = true;
345+ } else if (!strcmp(ptr, "-a")) {
346+ show_all = true;
347+ } else
348+ goto usage;
349+ }
350+ if (ccs_network_mode)
351+ ccs_check_remote_host(true);
352+ else
353+ ccs_check_policy_dir(true);
354+ ccs_read_process_list(show_all);
355+ if (!ccs_task_list_len) {
356+ if (ccs_network_mode) {
357+ fprintf(stderr, "Can't connect.\n");
358+ return 1;
359+ } else {
360+ fprintf(stderr, "You can't use this command "
361+ "for this kernel.\n");
362+ return 1;
363+ }
364+ }
365+ ccs_dump(1, 0);
366+ for (i = 0; i < ccs_task_list_len; i++) {
367+ if (ccs_task_list[i].selected)
368+ continue;
369+ printf(" %s (%u) %s\n", ccs_task_list[i].name,
370+ ccs_task_list[i].pid, ccs_task_list[i].domain);
371+ ccs_task_list[i].selected = true;
372+ }
373+ while (ccs_task_list_len) {
374+ ccs_task_list_len--;
375+ free((void *) ccs_task_list[ccs_task_list_len].name);
376+ free((void *) ccs_task_list[ccs_task_list_len].domain);
377+ }
378+ free(ccs_task_list);
379+ ccs_task_list = NULL;
380+ return 0;
381+usage:
382+ printf("Usage: %s [-a] [remote_ip:remote_port]\n\n"
383+ "-a : Print all processes including kernel threads.\n"
384+ "remote_ip:remote_port : Read from caitsith-agent listening "
385+ "at remote_ip:remote_port .\n", argv[0]);
386+ return 0;
387+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-queryd.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-queryd.c (revision 219)
@@ -0,0 +1,326 @@
1+/*
2+ * caitsith-queryd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include "readline.h"
25+
26+/* Prototypes */
27+
28+static void ccs_printw(const char *fmt, ...)
29+ __attribute__ ((format(printf, 1, 2)));
30+static _Bool ccs_handle_query(unsigned int serial);
31+
32+/* Utility functions */
33+
34+static void ccs_printw(const char *fmt, ...)
35+{
36+ va_list args;
37+ int i;
38+ int len;
39+ char *buffer;
40+ va_start(args, fmt);
41+ len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16;
42+ va_end(args);
43+ buffer = ccs_malloc(len);
44+ va_start(args, fmt);
45+ len = vsnprintf(buffer, len, fmt, args);
46+ va_end(args);
47+ for (i = 0; i < len; i++) {
48+ addch(buffer[i]);
49+ refresh();
50+ }
51+ free(buffer);
52+}
53+
54+static void ccs_send_keepalive(void)
55+{
56+ static time_t previous = 0;
57+ time_t now = time(NULL);
58+ if (previous != now || !previous) {
59+ int ret_ignored;
60+ previous = now;
61+ ret_ignored = write(ccs_query_fd, "\n", 1);
62+ }
63+}
64+
65+/* Variables */
66+
67+static unsigned short int ccs_retries = 0;
68+
69+static FILE *ccs_policy_fp = NULL;
70+static int ccs_policy_fd = EOF;
71+#define CCS_MAX_READLINE_HISTORY 20
72+static const char **ccs_readline_history = NULL;
73+static int ccs_readline_history_count = 0;
74+static char ccs_buffer[32768];
75+
76+/* Main functions */
77+
78+static _Bool ccs_handle_query(unsigned int serial)
79+{
80+ int c = 0;
81+ int y;
82+ int x;
83+ int ret_ignored;
84+ char *line = NULL;
85+ static unsigned int prev_pid = 0;
86+ unsigned int pid;
87+ char qidbuf[128];
88+ char *cp = strstr(ccs_buffer, " global-pid=");
89+ if (!cp || sscanf(cp + 13, "%u", &pid) != 1) {
90+ ccs_printw("ERROR: Unsupported query.\n");
91+ return false;
92+ }
93+ cp = ccs_buffer + strlen(ccs_buffer);
94+ if (*(cp - 1) != '\n') {
95+ ccs_printw("ERROR: Unsupported query.\n");
96+ return false;
97+ }
98+ *(cp - 1) = '\0';
99+ if (pid != prev_pid) {
100+ if (prev_pid)
101+ ccs_printw("----------------------------------------"
102+ "\n");
103+ prev_pid = pid;
104+ }
105+ ccs_printw("%s\n", ccs_buffer);
106+ memset(qidbuf, 0, sizeof(qidbuf));
107+ snprintf(qidbuf, sizeof(qidbuf) - 1, "Q=%u\n", serial);
108+ ccs_printw("Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy "
109+ "and retry):");
110+ while (true) {
111+ c = ccs_getch2();
112+ if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == 'R' ||
113+ c == 'r' || c == 'A' || c == 'a' || c == 'S' || c == 's')
114+ break;
115+ ccs_send_keepalive();
116+ }
117+ ccs_printw("%c\n", c);
118+
119+ if (c == 'S' || c == 's') {
120+ if (ccs_network_mode) {
121+ fprintf(ccs_policy_fp, "%s", qidbuf);
122+ fputc(0, ccs_policy_fp);
123+ fflush(ccs_policy_fp);
124+ rewind(ccs_policy_fp);
125+ while (1) {
126+ char c;
127+ if (fread(&c, 1, 1, ccs_policy_fp) != 1 || !c)
128+ break;
129+ addch(c);
130+ refresh();
131+ ccs_send_keepalive();
132+ }
133+ } else {
134+ ret_ignored = write(ccs_policy_fd, qidbuf,
135+ strlen(qidbuf));
136+ while (1) {
137+ int i;
138+ int len = read(ccs_policy_fd, ccs_buffer,
139+ sizeof(ccs_buffer) - 1);
140+ if (len <= 0)
141+ break;
142+ for (i = 0; i < len; i++) {
143+ addch(ccs_buffer[i]);
144+ refresh();
145+ }
146+ ccs_send_keepalive();
147+ }
148+ }
149+ c = 'r';
150+ }
151+
152+ /* Append to policy. */
153+ if (c != 'A' && c != 'a')
154+ goto not_append;
155+ c = 'r';
156+ getyx(stdscr, y, x);
157+ cp = strstr(ccs_buffer, " / ");
158+ if (!cp++)
159+ return false;
160+ cp = strchr(cp + 2, ' ');
161+ if (!cp++)
162+ return false;
163+ ccs_initial_readline_data = NULL;
164+ ccs_readline_history_count =
165+ ccs_add_history(cp, ccs_readline_history,
166+ ccs_readline_history_count,
167+ CCS_MAX_READLINE_HISTORY);
168+ line = ccs_readline(y, 0, "Enter new entry> ", ccs_readline_history,
169+ ccs_readline_history_count, 128000, 8);
170+ scrollok(stdscr, TRUE);
171+ ccs_printw("\n");
172+ if (!line || !*line) {
173+ ccs_printw("None added.\n");
174+ goto not_append;
175+ }
176+ ccs_readline_history_count =
177+ ccs_add_history(line, ccs_readline_history,
178+ ccs_readline_history_count,
179+ CCS_MAX_READLINE_HISTORY);
180+ if (ccs_network_mode) {
181+ fprintf(ccs_policy_fp, "%s%s\n", qidbuf, line);
182+ fflush(ccs_policy_fp);
183+ } else {
184+ ret_ignored = write(ccs_policy_fd, qidbuf, strlen(qidbuf));
185+ ret_ignored = write(ccs_policy_fd, line, strlen(line));
186+ ret_ignored = write(ccs_policy_fd, "\n", 1);
187+ }
188+ ccs_printw("Added '%s'.\n", line);
189+not_append:
190+ free(line);
191+ /* Write answer. */
192+ if (c == 'Y' || c == 'y' || c == 'A' || c == 'a')
193+ c = 1;
194+ else if (c == 'R' || c == 'r')
195+ c = 3;
196+ else
197+ c = 2;
198+ snprintf(ccs_buffer, sizeof(ccs_buffer) - 1, "A%u=%u\n", serial, c);
199+ ret_ignored = write(ccs_query_fd, ccs_buffer, strlen(ccs_buffer));
200+ ccs_printw("\n");
201+ return true;
202+}
203+
204+int main(int argc, char *argv[])
205+{
206+ if (argc == 1)
207+ goto ok;
208+ {
209+ char *cp = strchr(argv[1], ':');
210+ if (cp) {
211+ *cp++ = '\0';
212+ ccs_network_ip = inet_addr(argv[1]);
213+ ccs_network_port = htons(atoi(cp));
214+ ccs_network_mode = true;
215+ goto ok;
216+ }
217+ }
218+ printf("Usage: %s [remote_ip:remote_port]\n\n"
219+ "remote_ip:remote_port : Read from and reply to caitsith-agent "
220+ "listening at remote_ip:remote_port .\n\n", argv[0]);
221+ printf("This program is used for granting access requests manually."
222+ "\n");
223+ printf("This program shows access requests that are about to be "
224+ "rejected by the kernel's decision.\n");
225+ printf("If you answer before the kernel's decision takes effect, your "
226+ "decision will take effect.\n");
227+ printf("You can use this program to respond to accidental access "
228+ "requests triggered by non-routine tasks (such as restarting "
229+ "daemons after updating).\n");
230+ printf("To terminate this program, use 'Ctrl-C'.\n");
231+ return 0;
232+ok:
233+ if (ccs_network_mode) {
234+ ccs_check_remote_host(true);
235+ ccs_query_fd = ccs_open_stream("proc:query");
236+ ccs_policy_fp = ccs_open_write(CCS_PROC_POLICY_POLICY);
237+ } else {
238+ ccs_check_policy_dir(true);
239+ ccs_query_fd = open("query", O_RDWR);
240+ ccs_policy_fd = open("policy", O_RDWR);
241+ }
242+ if (ccs_query_fd == EOF) {
243+ fprintf(stderr,
244+ "You can't run this utility for this kernel.\n");
245+ return 1;
246+ } else if (!ccs_network_mode && write(ccs_query_fd, "", 0) != 0) {
247+ fprintf(stderr, "You need to allow this program in "
248+ "%s/policy to run this program.\n",
249+ CCS_PROC_POLICY_DIR);
250+ return 1;
251+ }
252+ ccs_readline_history = ccs_malloc(CCS_MAX_READLINE_HISTORY *
253+ sizeof(const char *));
254+ ccs_send_keepalive();
255+ initscr();
256+ cbreak();
257+ noecho();
258+ nonl();
259+ intrflush(stdscr, FALSE);
260+ keypad(stdscr, TRUE);
261+ clear();
262+ refresh();
263+ scrollok(stdscr, TRUE);
264+ if (ccs_network_mode) {
265+ const u32 ip = ntohl(ccs_network_ip);
266+ ccs_printw("Monitoring %s/query via %u.%u.%u.%u:%u.",
267+ CCS_PROC_POLICY_DIR, (u8) (ip >> 24),
268+ (u8) (ip >> 16), (u8) (ip >> 8), (u8) ip,
269+ ntohs(ccs_network_port));
270+ } else
271+ ccs_printw("Monitoring %s/query .", CCS_PROC_POLICY_DIR);
272+ ccs_printw(" Press Ctrl-C to terminate.\n\n");
273+ while (true) {
274+ unsigned int serial;
275+ char *cp;
276+ /* Wait for query and read query. */
277+ memset(ccs_buffer, 0, sizeof(ccs_buffer));
278+ if (ccs_network_mode) {
279+ int i;
280+ int ret_ignored;
281+ ret_ignored = write(ccs_query_fd, "", 1);
282+ for (i = 0; i < sizeof(ccs_buffer) - 1; i++) {
283+ if (read(ccs_query_fd, ccs_buffer + i, 1) != 1)
284+ break;
285+ if (!ccs_buffer[i])
286+ goto read_ok;
287+ }
288+ break;
289+ } else {
290+ struct pollfd pfd;
291+ pfd.fd = ccs_query_fd;
292+ pfd.events = POLLIN;
293+ pfd.revents = 0;
294+ poll(&pfd, 1, -1);
295+ if (!(pfd.revents & POLLIN))
296+ continue;
297+ if (read(ccs_query_fd, ccs_buffer,
298+ sizeof(ccs_buffer) - 1) <= 0)
299+ continue;
300+ }
301+read_ok:
302+ cp = strchr(ccs_buffer, '\n');
303+ if (!cp)
304+ continue;
305+ *cp = '\0';
306+
307+ /* Get query number. */
308+ if (sscanf(ccs_buffer, "Q%u-%hu", &serial, &ccs_retries) != 2)
309+ continue;
310+ memmove(ccs_buffer, cp + 1, strlen(cp + 1) + 1);
311+
312+ /* Clear pending input. */;
313+ timeout(0);
314+ while (true) {
315+ int c = ccs_getch2();
316+ if (c == EOF || c == ERR)
317+ break;
318+ }
319+ timeout(1000);
320+ if (ccs_handle_query(serial))
321+ continue;
322+ break;
323+ }
324+ endwin();
325+ return 0;
326+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsith-savepolicy.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsith-savepolicy.c (revision 219)
@@ -0,0 +1,167 @@
1+/*
2+ * caitsith-savepolicy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+/**
26+ * ccs_move_proc_to_file - Save /sys/kernel/security/caitsith/ to /etc/caitsith/ .
27+ *
28+ * @src: Filename to save from.
29+ * @dest: Filename to save to.
30+ *
31+ * Returns true on success, false otherwise.
32+ */
33+static _Bool ccs_move_proc_to_file(const char *src, const char *dest)
34+{
35+ FILE *proc_fp = ccs_open_read(src);
36+ FILE *file_fp;
37+ _Bool result = true;
38+ if (!proc_fp) {
39+ fprintf(stderr, "Can't open %s for reading.\n", src);
40+ return false;
41+ }
42+ file_fp = dest ? fopen(dest, "w") : stdout;
43+ if (!file_fp) {
44+ fprintf(stderr, "Can't open %s for writing.\n", dest);
45+ fclose(proc_fp);
46+ return false;
47+ }
48+ while (true) {
49+ const int c = fgetc(proc_fp);
50+ if (ccs_network_mode && !c)
51+ break;
52+ if (c == EOF)
53+ break;
54+ if (fputc(c, file_fp) == EOF)
55+ result = false;
56+ }
57+ fclose(proc_fp);
58+ if (file_fp != stdout)
59+ if (fclose(file_fp) == EOF)
60+ result = false;
61+ return result;
62+}
63+
64+static const char *ccs_policy_dir = NULL;
65+
66+static _Bool ccs_cat_file(const char *path)
67+{
68+ FILE *fp = ccs_open_read(path);
69+ _Bool result = true;
70+ if (!fp) {
71+ fprintf(stderr, "Can't open %s\n", path);
72+ return false;
73+ }
74+ while (true) {
75+ int c = fgetc(fp);
76+ if (ccs_network_mode && !c)
77+ break;
78+ if (c == EOF)
79+ break;
80+ if (putchar(c) == EOF)
81+ result = false;
82+ }
83+ fclose(fp);
84+ return result;
85+}
86+
87+static _Bool ccs_save_policy(void)
88+{
89+ time_t now = time(NULL);
90+ char stamp[32] = { };
91+ while (1) {
92+ struct tm *tm = localtime(&now);
93+ snprintf(stamp, sizeof(stamp) - 1,
94+ "%02d-%02d-%02d.%02d:%02d:%02d",
95+ tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
96+ tm->tm_hour, tm->tm_min, tm->tm_sec);
97+ if (access(stamp, F_OK))
98+ break;
99+ else if (errno == EEXIST)
100+ now++;
101+ else {
102+ fprintf(stderr, "Can't create %s/policy/%s .\n",
103+ ccs_policy_dir, stamp);
104+ return false;
105+ }
106+ }
107+ if (!ccs_move_proc_to_file(CCS_PROC_POLICY_POLICY, stamp) ||
108+ (rename("current", "previous") && errno != ENOENT) ||
109+ symlink(stamp, "current")) {
110+ fprintf(stderr, "Failed to save policy.\n");
111+ return false;
112+ }
113+ return true;
114+}
115+
116+int main(int argc, char *argv[])
117+{
118+ _Bool use_stdout = false;
119+ int i;
120+ for (i = 1; i < argc; i++) {
121+ char *ptr = argv[i];
122+ char *cp = strchr(ptr, ':');
123+ if (*ptr == '/') {
124+ if (ccs_policy_dir || use_stdout)
125+ goto usage;
126+ ccs_policy_dir = ptr;
127+ } else if (cp) {
128+ *cp++ = '\0';
129+ ccs_network_ip = inet_addr(ptr);
130+ ccs_network_port = htons(atoi(cp));
131+ if (ccs_network_mode) {
132+ fprintf(stderr, "You cannot specify multiple "
133+ "%s at the same time.\n\n",
134+ "remote agents");
135+ goto usage;
136+ }
137+ ccs_network_mode = true;
138+ } else if (*ptr++ == '-' && !*ptr) {
139+ if (ccs_policy_dir || use_stdout)
140+ goto usage;
141+ use_stdout = true;
142+ } else
143+ goto usage;
144+ }
145+ if (ccs_network_mode)
146+ ccs_check_remote_host(true);
147+ else
148+ ccs_check_policy_dir(true);
149+ if (use_stdout)
150+ return !ccs_cat_file(CCS_PROC_POLICY_POLICY);
151+ if (!ccs_policy_dir)
152+ ccs_policy_dir = "/etc/caitsith";
153+ if (chdir(ccs_policy_dir) || chdir("policy/")) {
154+ fprintf(stderr, "Directory %s/policy/ doesn't exist.\n",
155+ ccs_policy_dir);
156+ return 1;
157+ }
158+ return !ccs_save_policy();
159+usage:
160+ printf("Usage: %s [policy_dir|-] [remote_ip:remote_port]\n\n"
161+ "policy_dir : Use policy_dir rather than /etc/caitsith "
162+ "directory.\n"
163+ "- : Print policy to stdout rather than save as a file.\n"
164+ "remote_ip:remote_port : Read from caitsith-agent listening at "
165+ "remote_ip:remote_port .\n", argv[0]);
166+ return 1;
167+}
--- tags/caitsith-tools/0.2.1/usr_sbin/caitsithtools.h (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/caitsithtools.h (revision 219)
@@ -0,0 +1,84 @@
1+/*
2+ * caitsithtools.h
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#define _FILE_OFFSET_BITS 64
24+#define _LARGEFILE_SOURCE
25+#define _LARGEFILE64_SOURCE
26+#define _GNU_SOURCE
27+#include <arpa/inet.h>
28+#include <asm/types.h>
29+#include <dirent.h>
30+#include <errno.h>
31+#include <fcntl.h>
32+#include <limits.h>
33+#include <stdio.h>
34+#include <stdlib.h>
35+#include <string.h>
36+#include <sys/file.h>
37+#include <sys/socket.h>
38+#include <sys/stat.h>
39+#include <sys/types.h>
40+#include <sys/un.h>
41+#include <time.h>
42+#include <unistd.h>
43+#include <stdarg.h>
44+#include <poll.h>
45+
46+#define s8 __s8
47+#define u8 __u8
48+#define u16 __u16
49+#define u32 __u32
50+#define true 1
51+#define false 0
52+
53+/***** CONSTANTS DEFINITION START *****/
54+
55+/***** CONSTANTS DEFINITION END *****/
56+
57+/***** STRUCTURES DEFINITION START *****/
58+
59+/***** STRUCTURES DEFINITION END *****/
60+
61+/***** PROTOTYPES DEFINITION START *****/
62+
63+FILE *ccs_open_read(const char *filename);
64+FILE *ccs_open_write(const char *filename);
65+_Bool ccs_check_policy_dir(_Bool exit_on_failue);
66+_Bool ccs_check_remote_host(_Bool exit_on_failue);
67+_Bool ccs_decode(const char *ascii, char *bin);
68+_Bool ccs_str_starts(char *str, const char *begin);
69+char *ccs_freadline(FILE *fp);
70+char *ccs_strdup(const char *string);
71+int ccs_open_stream(const char *filename);
72+void *ccs_malloc(const size_t size);
73+void *ccs_realloc(void *ptr, const size_t size);
74+void ccs_get(void);
75+void ccs_normalize_line(char *buffer);
76+void ccs_put(void);
77+
78+extern _Bool ccs_network_mode;
79+extern u16 ccs_network_port;
80+extern u32 ccs_network_ip;
81+extern const char *CCS_PROC_POLICY_DIR;
82+extern const char *CCS_PROC_POLICY_POLICY;
83+
84+/***** PROTOTYPES DEFINITION END *****/
--- tags/caitsith-tools/0.2.1/usr_sbin/readline.h (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/readline.h (revision 219)
@@ -0,0 +1,303 @@
1+/*
2+ * readline.h
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include <ncurses.h>
24+
25+static int ccs_getch0(void)
26+{
27+ static int enter_key = EOF;
28+ int c;
29+again:
30+ c = getch();
31+ if (c == 127 || c == 8)
32+ c = KEY_BACKSPACE;
33+ /* syslog(LOG_INFO, "ccs_getch0='%c' (%d)\n", c, c); */
34+ if (c == '\r' || c == '\n') {
35+ if (enter_key == EOF)
36+ enter_key = c;
37+ else if (c != enter_key)
38+ goto again;
39+ }
40+ return c;
41+}
42+
43+static int ccs_getch2(void)
44+{
45+ static int c0 = 0;
46+ static int c1 = 0;
47+ static int c2 = 0;
48+ static int c3 = 0;
49+ static int len = 0;
50+ if (len > 0) {
51+ c0 = c1;
52+ c1 = c2;
53+ c2 = c3;
54+ len--;
55+ return c0;
56+ }
57+ c0 = ccs_getch0();
58+ if (c0 != 0x1B)
59+ return c0;
60+ c1 = ccs_getch0();
61+ if (c1 != '[') {
62+ len = 1;
63+ return c0;
64+ }
65+ c2 = ccs_getch0();
66+ if (c2 < '1' || c2 > '6') {
67+ len = 2;
68+ return c0;
69+ }
70+ c3 = ccs_getch0();
71+ if (c3 != '~') {
72+ len = 3;
73+ return c0;
74+ }
75+ /* syslog(LOG_INFO, "ccs_getch2='%c'\n", c2); */
76+ switch (c2) {
77+ case '1':
78+ return KEY_HOME;
79+ case '2':
80+ return KEY_IC;
81+ case '3':
82+ return KEY_DC;
83+ case '4':
84+ return KEY_END;
85+ case '5':
86+ return KEY_PPAGE;
87+ case '6':
88+ return KEY_NPAGE;
89+ }
90+ return 0;
91+}
92+
93+static int ccs_add_history(const char *buffer, const char **history,
94+ const int history_count, const int max_history)
95+{
96+ char *cp = buffer ? strdup(buffer) : NULL;
97+ if (!cp)
98+ return history_count;
99+ if (history_count && !strcmp(history[history_count - 1], cp)) {
100+ free(cp);
101+ return history_count;
102+ }
103+ if (history_count < max_history) {
104+ history[history_count] = cp;
105+ return history_count + 1;
106+ } else if (max_history) {
107+ int i;
108+ free((char *) history[0]);
109+ for (i = 0; i < history_count - 1; i++)
110+ history[i] = history[i + 1];
111+ history[history_count - 1] = cp;
112+ return history_count;
113+ }
114+ return 0;
115+}
116+
117+static int ccs_query_fd = EOF;
118+static char *ccs_initial_readline_data = NULL;
119+
120+static char *ccs_readline(const int start_y, const int start_x,
121+ const char *prompt, const char *history[],
122+ const int history_count, const int max_length,
123+ const int scroll_width)
124+{
125+ const int prompt_len = prompt ? strlen(prompt) : 0;
126+ int buffer_len = 0;
127+ int line_pos = 0;
128+ int cur_pos = 0;
129+ int history_pos = 0;
130+ _Bool tmp_saved = false;
131+ static char *buffer = NULL;
132+ static char *tmp_buffer = NULL;
133+ {
134+ int i;
135+ for (i = 0; i < history_count; i++)
136+ if (!history[i])
137+ return NULL;
138+ }
139+ {
140+ char *tmp;
141+ tmp = realloc(buffer, max_length + 1);
142+ if (!tmp)
143+ return NULL;
144+ buffer = tmp;
145+ tmp = realloc(tmp_buffer, max_length + 1);
146+ if (!tmp)
147+ return NULL;
148+ tmp_buffer = tmp;
149+ memset(buffer, 0, max_length + 1);
150+ memset(tmp_buffer, 0, max_length + 1);
151+ }
152+ move(start_y, start_x);
153+ history_pos = history_count;
154+ if (ccs_initial_readline_data) {
155+ strncpy(buffer, ccs_initial_readline_data, max_length);
156+ buffer_len = strlen(buffer);
157+ ungetch(KEY_END);
158+ }
159+ while (true) {
160+ int window_width;
161+ int window_height;
162+ int c;
163+ int x;
164+ int y;
165+ int i;
166+ int ret_ignored;
167+ getmaxyx(stdscr, window_height, window_width);
168+ window_width -= prompt_len;
169+ getyx(stdscr, y, x);
170+ move(y, 0);
171+ while (cur_pos > window_width - 1) {
172+ cur_pos--;
173+ line_pos++;
174+ }
175+ if (prompt_len)
176+ printw("%s", prompt);
177+ for (i = line_pos; i < line_pos + window_width; i++) {
178+ if (i < buffer_len)
179+ addch(buffer[i]);
180+ else
181+ break;
182+ }
183+ clrtoeol();
184+ move(y, cur_pos + prompt_len);
185+ refresh();
186+ c = ccs_getch2();
187+ if (ccs_query_fd != EOF)
188+ ret_ignored = write(ccs_query_fd, "\n", 1);
189+ if (c == 4) { /* Ctrl-D */
190+ if (!buffer_len)
191+ buffer_len = -1;
192+ break;
193+ } else if (c == KEY_IC) {
194+ scrollok(stdscr, TRUE);
195+ printw("\n");
196+ for (i = 0; i < history_count; i++)
197+ printw("%d: '%s'\n", i, history[i]);
198+ scrollok(stdscr, FALSE);
199+ } else if (c >= 0x20 && c <= 0x7E &&
200+ buffer_len < max_length - 1) {
201+ for (i = buffer_len - 1; i >= line_pos + cur_pos; i--)
202+ buffer[i + 1] = buffer[i];
203+ buffer[line_pos + cur_pos] = c;
204+ buffer[++buffer_len] = '\0';
205+ if (cur_pos < window_width - 1)
206+ cur_pos++;
207+ else
208+ line_pos++;
209+ } else if (c == '\r' || c == '\n') {
210+ break;
211+ } else if (c == KEY_BACKSPACE) {
212+ if (line_pos + cur_pos) {
213+ buffer_len--;
214+ for (i = line_pos + cur_pos - 1;
215+ i < buffer_len; i++)
216+ buffer[i] = buffer[i + 1];
217+ buffer[buffer_len] = '\0';
218+ if (line_pos >= scroll_width && cur_pos == 0) {
219+ line_pos -= scroll_width;
220+ cur_pos += scroll_width - 1;
221+ } else if (cur_pos) {
222+ cur_pos--;
223+ } else if (line_pos) {
224+ line_pos--;
225+ }
226+ }
227+ } else if (c == KEY_DC) {
228+ if (line_pos + cur_pos < buffer_len) {
229+ buffer_len--;
230+ for (i = line_pos + cur_pos; i < buffer_len;
231+ i++)
232+ buffer[i] = buffer[i + 1];
233+ buffer[buffer_len] = '\0';
234+ }
235+ } else if (c == KEY_UP) {
236+ if (history_pos) {
237+ if (!tmp_saved) {
238+ tmp_saved = true;
239+ strncpy(tmp_buffer, buffer,
240+ max_length);
241+ }
242+ history_pos--;
243+ strncpy(buffer, history[history_pos],
244+ max_length);
245+ buffer_len = strlen(buffer);
246+ goto end_key;
247+ }
248+ } else if (c == KEY_DOWN) {
249+ if (history_pos < history_count - 1) {
250+ history_pos++;
251+ strncpy(buffer, history[history_pos],
252+ max_length);
253+ buffer_len = strlen(buffer);
254+ goto end_key;
255+ } else if (tmp_saved) {
256+ tmp_saved = false;
257+ history_pos = history_count;
258+ strncpy(buffer, tmp_buffer, max_length);
259+ buffer_len = strlen(buffer);
260+ goto end_key;
261+ }
262+ } else if (c == KEY_HOME) {
263+ cur_pos = 0;
264+ line_pos = 0;
265+ } else if (c == KEY_END) {
266+ goto end_key;
267+ } else if (c == KEY_LEFT) {
268+ if (line_pos >= scroll_width && cur_pos == 0) {
269+ line_pos -= scroll_width;
270+ cur_pos += scroll_width - 1;
271+ } else if (cur_pos) {
272+ cur_pos--;
273+ } else if (line_pos) {
274+ line_pos--;
275+ }
276+ } else if (c == KEY_RIGHT) {
277+ if (line_pos + cur_pos < buffer_len) {
278+ if (cur_pos < window_width - 1)
279+ cur_pos++;
280+ else if (line_pos + cur_pos <
281+ buffer_len - scroll_width &&
282+ cur_pos >= scroll_width - 1) {
283+ cur_pos -= scroll_width - 1;
284+ line_pos += scroll_width;
285+ } else {
286+ line_pos++;
287+ }
288+ }
289+ }
290+ continue;
291+end_key:
292+ cur_pos = buffer_len;
293+ line_pos = 0;
294+ if (cur_pos > window_width - 1) {
295+ line_pos = buffer_len - (window_width - 1);
296+ cur_pos = window_width - 1;
297+ }
298+ }
299+ if (buffer_len == -1)
300+ return NULL;
301+ ccs_normalize_line(buffer);
302+ return strdup(buffer);
303+}
--- tags/caitsith-tools/0.2.1/usr_sbin/Makefile (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_sbin/Makefile (revision 219)
@@ -0,0 +1,42 @@
1+include ../Include.make
2+
3+BUILD_FILES := caitsith-auditd caitsith-loadpolicy caitsith-notifyd caitsith-pstree caitsith-queryd \
4+ caitsith-savepolicy
5+
6+all: libcaitsithtools.so $(BUILD_FILES)
7+
8+$(BUILD_FILES): libcaitsithtools.so
9+
10+/usr/include/curses.h:
11+ @echo "/usr/include/curses.h is missing."
12+ @echo "Run 'yum install ncurses-devel' or 'apt-get install libncurses-dev'"
13+ sleep 10
14+
15+# -fPIE conflicts with -fPIC, disable it for libraries.
16+CFLAGS_PIC := $(filter-out -fPIE,$(CFLAGS))
17+LDFLAGS_PIC := $(filter-out -pie,$(filter-out -fPIE,$(LDFLAGS)))
18+
19+libcaitsithtools.so: caitsithtools.c caitsithtools.h
20+ $(CC) $(CPPFLAGS) $(CFLAGS_PIC) $(LDFLAGS_PIC) -fPIC caitsithtools.c -shared -Wl,-soname,libcaitsithtools.so.2 -o libcaitsithtools.so.2.0.0
21+ ln -sf libcaitsithtools.so.2.0.0 libcaitsithtools.so
22+
23+.c:
24+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< -lcaitsithtools -L.
25+
26+caitsith-queryd: caitsithtools.h caitsith-queryd.c readline.h /usr/include/curses.h libcaitsithtools.so
27+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o caitsith-queryd caitsith-queryd.c -lncurses -lcaitsithtools -L.
28+
29+install: all
30+ mkdir -p -m 0755 $(INSTALLDIR)$(USRLIBDIR)
31+ $(INSTALL) -m 0755 libcaitsithtools.so.2.0.0 $(INSTALLDIR)$(USRLIBDIR)
32+ ln -sf libcaitsithtools.so.2.0.0 $(INSTALLDIR)$(USRLIBDIR)/libcaitsithtools.so.2
33+ifeq ($(INSTALLDIR),)
34+ ldconfig || true
35+endif
36+ mkdir -p -m 0755 $(INSTALLDIR)$(USRSBINDIR)
37+ $(INSTALL) -m 0755 $(BUILD_FILES) $(INSTALLDIR)$(USRSBINDIR)
38+
39+clean:
40+ rm -f -- $(BUILD_FILES) libcaitsithtools.so*
41+
42+.PHONY: clean install
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_audit2cond_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_audit2cond_test.c (revision 219)
@@ -0,0 +1,1339 @@
1+/*
2+ * caitsith_audit2cond_test.c
3+ *
4+ * Copyright (C) 2012-2013 Tetsuo Handa
5+ *
6+ * Version: 0.2 2016/10/05
7+ *
8+ * This program is free software; you can redistribute it and/or modify it
9+ * under the terms of the GNU General Public License v2 as published by the
10+ * Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful, but WITHOUT
13+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15+ * more details.
16+ *
17+ * You should have received a copy of the GNU General Public License along with
18+ * this program; if not, write to the Free Software Foundation, Inc.,
19+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+ */
21+
22+#include <errno.h>
23+#include <fcntl.h>
24+#include <linux/ip.h>
25+#include <linux/kdev_t.h>
26+#include <linux/reboot.h>
27+#include <netinet/in.h>
28+#include <poll.h>
29+#include <pty.h>
30+#include <sched.h>
31+#include <stdio.h>
32+#include <stdlib.h>
33+#include <string.h>
34+#include <signal.h>
35+#include <sys/mount.h>
36+#include <sys/ptrace.h>
37+#include <sys/socket.h>
38+#include <sys/stat.h>
39+#include <sys/syscall.h>
40+#include <sys/timex.h>
41+#include <sys/types.h>
42+#include <sys/un.h>
43+#include <sys/wait.h>
44+#include <time.h>
45+#include <unistd.h>
46+#ifndef CLONE_NEWNS
47+#include <linux/sched.h>
48+#endif
49+#ifndef PRIO_PROCESS
50+#include <sys/resource.h>
51+#endif
52+#ifndef MS_REC
53+#define MS_REC 16384
54+#endif
55+#ifndef MS_PRIVATE
56+#define MS_PRIVATE (1 << 18)
57+#endif
58+int unshare(int flags);
59+int reboot(int cmd);
60+struct module;
61+int init_module(const char *name, struct module *image);
62+int delete_module(const char *name);
63+int pivot_root(const char *new_root, const char *put_old);
64+struct kexec_segment;
65+static inline long sys_kexec_load(unsigned long entry,
66+ unsigned long nr_segments,
67+ struct kexec_segment *segments,
68+ unsigned long flags)
69+{
70+ return (long) syscall(__NR_kexec_load, entry, nr_segments,
71+ segments, flags);
72+}
73+
74+static char *args[512];
75+static int audit_fd = EOF;
76+static int policy_fd = EOF;
77+static int one = 1;
78+
79+static const char *make_variable(const char *name, const unsigned int type)
80+{
81+ const char *cp = name + strlen(name) + 1;
82+ if (type == 0)
83+ return cp;
84+ if (*cp == '"') {
85+ /* Name variables. */
86+ if (type == 1)
87+ return "NULL";
88+ if (type == 2)
89+ return "!@EMPTY_NAME_GROUP";
90+ //if (type == 3)
91+ // return "task.exe"; // How can this match?
92+ } else if (!strcmp(name, "ip")) {
93+ /* IP address variables */
94+ if (type == 1)
95+ return "!@EMPTY_IP_GROUP";
96+ } else if (strstr(name, ".type")) {
97+ /* task.type or path.type */
98+ /* No variables supported. */
99+ } else {
100+ /* Numeric variables */
101+ const int zero = !strcmp(cp, "0") || !strcmp(cp, "00") ||
102+ !strcmp(cp, "0x0");
103+ if (type == 1)
104+ return "!@EMPTY_NUMBER_GROUP";
105+ if (type == 2)
106+ return "!@ZERO" + zero;
107+ if (type == 3)
108+ return "!task.uid" + zero;
109+ if (strstr(name, ".perm")) {
110+ unsigned int perm = 0;
111+ sscanf(cp, "%o", &perm);
112+ if (type == 4)
113+ return "!setuid" + ((perm & 04000) != 0);
114+ if (type == 5)
115+ return "!setgid" + ((perm & 02000) != 0);
116+ if (type == 6)
117+ return "!sticky" + ((perm & 01000) != 0);
118+ if (type == 7)
119+ return "!owner_read" + ((perm & 0400) != 0);
120+ if (type == 8)
121+ return "!owner_write" + ((perm & 0200) != 0);
122+ if (type == 9)
123+ return "!owner_execute" + ((perm & 0100) != 0);
124+ if (type == 10)
125+ return "!group_read" + ((perm & 040) != 0);
126+ if (type == 11)
127+ return "!group_write" + ((perm & 020) != 0);
128+ if (type == 12)
129+ return "!group_execute" + ((perm & 010) != 0);
130+ if (type == 13)
131+ return "!others_read" + ((perm & 04) != 0);
132+ if (type == 14)
133+ return "!others_write" + ((perm & 02) != 0);
134+ if (type == 15)
135+ return "!others_execute" + ((perm & 01) != 0);
136+ }
137+ }
138+ return NULL;
139+}
140+
141+static int make_policy(const char *action, const unsigned int loop,
142+ const int check, const int max)
143+{
144+ static char buffer[1048576];
145+ int pos;
146+ int i;
147+ const char *var = "";
148+ int not_equals = (loop & 1);
149+ if (max) {
150+ /* Nothing more to test if there is no more variables. */
151+ var = make_variable(args[check], loop >> 1);
152+ if (!var)
153+ return 0;
154+ /* NULL has inverse semantics. */
155+ if (!strcmp(var, "NULL"))
156+ not_equals = !not_equals;
157+ /* Handle other inversed conditions. */
158+ else if (*var == '!') {
159+ var++;
160+ not_equals = !not_equals;
161+ }
162+ }
163+ memset(buffer, 0, sizeof(buffer));
164+ pos = snprintf(buffer, sizeof(buffer) - 1, "0 acl %s task.ppid=%u\n"
165+ "\t0 allow", action, getpid());
166+ for (i = 0; i < max; i++) {
167+ /* Change only one argument at a time. */
168+ if (i != check)
169+ pos += snprintf(buffer + pos, sizeof(buffer) - 1 - pos,
170+ " %s=%s", args[i],
171+ args[i] + strlen(args[i]) + 1);
172+ else
173+ pos += snprintf(buffer + pos, sizeof(buffer) - 1 - pos,
174+ " %s%s=%s", args[i],
175+ not_equals ? "!" : "", var);
176+ }
177+ pos += snprintf(buffer + pos, sizeof(buffer) - 1 - pos, "\n"
178+ "\t1 deny\n");
179+ write(policy_fd, buffer, strlen(buffer));
180+ printf("Expecting %s: %s", (loop & 1) ? "denied" : "allowed",
181+ buffer);
182+ return 1;
183+}
184+
185+static int do_test(int (*func) (void))
186+{
187+ int error = 0;
188+ const pid_t pid = fork();
189+ switch (pid) {
190+ case 0:
191+ if (unshare(CLONE_NEWNS)) {
192+ fprintf(stderr, "***** Can't unshare.\n");
193+ _exit(1);
194+ }
195+ errno = 0;
196+ _exit(func());
197+ case -1:
198+ fprintf(stderr, "***** Can't fork.\n");
199+ return 1;
200+ }
201+ while (waitpid(pid, &error, 0) == EOF && errno == EINTR);
202+ return WIFEXITED(error) ? WEXITSTATUS(error) : -1;
203+}
204+
205+static int check_result(const char *action, int (*func) (void),
206+ const unsigned int loop)
207+{
208+ static char buffer[1048576];
209+ char *cp1;
210+ char *cp2;
211+ int retries = 0;
212+retry:
213+ do_test(func);
214+ memset(buffer, 0, sizeof(buffer));
215+ read(audit_fd, buffer, sizeof(buffer) - 1);
216+ cp1 = strchr(buffer, '\n');
217+ if (!cp1) {
218+ if (retries++ < 100)
219+ goto retry;
220+ fprintf(stderr, "***** Missing audit log for '%s': %s\n",
221+ action, buffer);
222+ return 1;
223+ }
224+ *cp1 = '\0';
225+ cp1 = strstr(buffer, " / ");
226+ if (!cp1) {
227+ fprintf(stderr, "***** Corrupted audit log for '%s': %s\n",
228+ action, buffer);
229+ return 1;
230+ }
231+ cp1 += 3;
232+ cp2 = strchr(cp1, ' ');
233+ if (!cp2) {
234+ fprintf(stderr, "***** Corrupted audit log for '%s': %s\n",
235+ action, buffer);
236+ return 1;
237+ }
238+ *cp2 = '\0';
239+ if (strcmp(cp1, action)) {
240+ if (retries++ < 100)
241+ goto retry;
242+ *cp2 = ' ';
243+ fprintf(stderr, "***** Unexpected audit log for '%s': %s\n",
244+ action, buffer);
245+ return 1;
246+ }
247+ *cp2 = ' ';
248+ if (!(loop & 1)) {
249+ if (!strstr(buffer, " result=allowed ")) {
250+ fprintf(stderr, "***** result=allowed expected: %s\n",
251+ buffer);
252+ exit(1);
253+ return 1;
254+ }
255+ } else {
256+ if (!strstr(buffer, " result=denied ")) {
257+ fprintf(stderr, "***** result=denied expected: %s\n",
258+ buffer);
259+ exit(1);
260+ return 1;
261+ }
262+ }
263+ snprintf(buffer, sizeof(buffer) - 1, "delete 0 acl %s task.ppid=%u\n",
264+ action, getpid());
265+ write(policy_fd, buffer, strlen(buffer));
266+ while (read(audit_fd, buffer, sizeof(buffer) - 1) > 0);
267+ return 0;
268+}
269+
270+static void test_action(const char *action, int (*func) (void))
271+{
272+ static char buffer[1048576];
273+ int pos;
274+ int i;
275+ char *cp1;
276+ char *cp2;
277+ int retries = 0;
278+ memset(args, 0, sizeof(args));
279+ make_policy(action, 0, 0, 0);
280+retry:
281+ do_test(func);
282+ memset(buffer, 0, sizeof(buffer));
283+ read(audit_fd, buffer, sizeof(buffer) - 1);
284+ cp1 = strchr(buffer, '\n');
285+ if (!cp1) {
286+ if (retries++ < 100)
287+ goto retry;
288+ fprintf(stderr, "+++++ Missing audit log for '%s': %s\n",
289+ action, buffer);
290+ return;
291+ }
292+ *cp1 = '\0';
293+ cp1 = strstr(buffer, " / ");
294+ if (!cp1) {
295+ fprintf(stderr, "+++++ Corrupted audit log for '%s': %s\n",
296+ action, buffer);
297+ return;
298+ }
299+ cp1 += 3;
300+ cp2 = strchr(cp1, ' ');
301+ if (!cp2) {
302+ fprintf(stderr, "+++++ Corrupted audit log for '%s': %s\n",
303+ action, buffer);
304+ return;
305+ }
306+ *cp2++ = '\0';
307+ if (strcmp(cp1, action)) {
308+ if (retries++ < 100)
309+ goto retry;
310+ fprintf(stderr, "+++++ Unexpected audit log for '%s': %s\n",
311+ action, cp1);
312+ return;
313+ }
314+ cp1 = cp2;
315+ pos = 0;
316+ while (pos < (sizeof(args) / sizeof(args[0]))) {
317+ char *cp3;
318+ args[pos++] = cp1;
319+ cp2 = strchr(cp1, ' ');
320+ if (cp2)
321+ *cp2++ = '\0';
322+ cp3 = strchr(cp1, '=');
323+ if (!cp3 || !*(cp3 + 1)) {
324+ fprintf(stderr, "+++++ Corrupted audit log.\n");
325+ return;
326+ }
327+ *cp3 = '\0';
328+ /*
329+ * Ignore task.pid which cannot be matched due to tesing under
330+ * fork()ed process.
331+ */
332+ if (!strcmp(cp1, "task.pid"))
333+ pos--;
334+ /*
335+ * Ignore .ino which might change for each test.
336+ */
337+ else if (strstr(cp1, ".ino"))
338+ pos--;
339+ /*
340+ * Ignore .minor which might change for each test.
341+ */
342+ else if (strstr(cp1, ".minor"))
343+ pos--;
344+ cp1 = cp2;
345+ if (!cp1)
346+ break;
347+ }
348+ if (pos == (sizeof(args) / sizeof(args[0]))) {
349+ fprintf(stderr, "+++++ Line too long.\n");
350+ return;
351+ }
352+ {
353+ static char buffer2[1024];
354+ while (read(audit_fd, buffer2, sizeof(buffer2)) > 0);
355+ }
356+ for (i = 0; i < pos; i++) {
357+ unsigned int loop;
358+ for (loop = 0; make_policy(action, loop, i, pos); loop++)
359+ check_result(action, func, loop);
360+ }
361+ return;
362+}
363+
364+static void startup(void)
365+{
366+ int pipe_fd[2] = { EOF, EOF };
367+ static char buffer[1048576];
368+ FILE *fp = fopen(POLDIR "/policy", "r");
369+ policy_fd = open(POLDIR "/policy", O_WRONLY);
370+ audit_fd = open(POLDIR "/audit", O_RDONLY);
371+ if (!fp || policy_fd == EOF || audit_fd == EOF) {
372+ fprintf(stderr,
373+ "***** Can't open " POLDIR "/ interface.\n");
374+ exit(1);
375+ }
376+ if (pipe(pipe_fd)) {
377+ fprintf(stderr, "***** Can't pipe.\n");
378+ exit(1);
379+ }
380+ mkdir("/tmp/caitsith.tmp", 0700);
381+ if (chown("/tmp/caitsith.tmp", 0, 0) ||
382+ chmod("/tmp/caitsith.tmp", 0700)) {
383+ fprintf(stderr, "***** Can't chown/chmod.\n");
384+ exit(1);
385+ }
386+ while (memset(buffer, 0, sizeof(buffer)),
387+ fgets(buffer, sizeof(buffer) - 1, fp)) {
388+ if (!strchr(buffer, '\n')) {
389+ fprintf(stderr, "***** Line too long.\n");
390+ exit(1);
391+ }
392+ write(policy_fd, "delete ", 7);
393+ write(policy_fd, buffer, strlen(buffer));
394+ }
395+ fclose(fp);
396+ {
397+ const char *config = "quota Memory used by audit: 1048576\n"
398+ "quota audit[0] allowed=1024 denied=1024 "
399+ "unmatched=1024\n" "number_group ZERO 0\n";
400+ write(policy_fd, config, strlen(config));
401+ }
402+ while (read(audit_fd, buffer, sizeof(buffer)) > 0);
403+ switch (fork()) {
404+ int fd;
405+ case 0:
406+ close(policy_fd);
407+ close(audit_fd);
408+ close(pipe_fd[1]);
409+ fd = open(POLDIR "/query", O_RDWR);
410+ while (1) {
411+ unsigned int serial;
412+ unsigned int retry;
413+ struct pollfd pfd[2] = {
414+ { fd, POLLIN, 0 },
415+ { pipe_fd[0], POLLIN, 0 }
416+ };
417+ poll(pfd, 2, -1);
418+ if (pfd[0].revents & POLLIN)
419+ break;
420+ if (read(fd, buffer, sizeof(buffer) - 1) <= 0)
421+ continue;
422+ if (sscanf(buffer, "Q%u-%u", &serial, &retry) != 2) {
423+ fprintf(stderr, "***** Corrupted query: %s\n",
424+ buffer);
425+ break;
426+ }
427+ snprintf(buffer, sizeof(buffer) - 1, "A%u=%u\n",
428+ serial,
429+ retry < 5 ? 3 /* Retry */ : 2 /* No */);
430+ write(fd, buffer, strlen(buffer));
431+ }
432+ _exit(0);
433+ case -1:
434+ fprintf(stderr, "***** Can't fork.\n");
435+ exit(1);
436+ }
437+ close(pipe_fd[0]);
438+}
439+
440+static int test_execute(void)
441+{
442+ execlp(BINDIR "/true", "true", NULL);
443+ return errno;
444+}
445+
446+static int test_read(void)
447+{
448+ open("/dev/null", O_RDONLY);
449+ return errno;
450+}
451+
452+static int test_write(void)
453+{
454+ open("/dev/null", O_WRONLY);
455+ return errno;
456+}
457+
458+static int test_create_no_append(void)
459+{
460+ int err;
461+ open("/tmp/caitsith.tmp/file", O_CREAT | O_RDWR | O_TRUNC, 0600);
462+ err = errno;
463+ unlink("/tmp/caitsith.tmp/file");
464+ return err;
465+}
466+
467+static int test_create_append(void)
468+{
469+ int err;
470+ open("/tmp/caitsith.tmp/file", O_CREAT | O_RDWR | O_TRUNC | O_APPEND,
471+ 0600);
472+ err = errno;
473+ unlink("/tmp/caitsith.tmp/file");
474+ return err;
475+}
476+
477+static int test_fcntl_clear_append(void)
478+{
479+ const int fd = open("/dev/null", O_WRONLY | O_APPEND);
480+ const int flags = fcntl(fd, F_GETFL);
481+ errno = 0;
482+ fcntl(fd, F_SETFL, flags & ~O_APPEND);
483+ return errno;
484+}
485+
486+static int test_fcntl_set_append(void)
487+{
488+ const int fd = open("/dev/null", O_WRONLY);
489+ const int flags = fcntl(fd, F_GETFL);
490+ errno = 0;
491+ fcntl(fd, F_SETFL, flags | O_APPEND);
492+ return errno;
493+}
494+
495+static int test_unlink(void)
496+{
497+ mknod("/tmp/caitsith.tmp/file", S_IFREG | 0600, 0);
498+ errno = 0;
499+ unlink("/tmp/caitsith.tmp/file");
500+ return errno;
501+}
502+
503+static int test_getattr(void)
504+{
505+ struct stat buf;
506+ stat("/dev/null", &buf);
507+ return errno;
508+}
509+
510+static int test_mkdir(void)
511+{
512+ int err;
513+ mkdir("/tmp/caitsith.tmp/dir", 0755);
514+ err = errno;
515+ rmdir("/tmp/caitsith.tmp/dir");
516+ return err;
517+}
518+
519+static int test_rmdir(void)
520+{
521+ mkdir("/tmp/caitsith.tmp/dir", 0755);
522+ errno = 0;
523+ rmdir("/tmp/caitsith.tmp/dir");
524+ return errno;
525+}
526+
527+static int test_mkfifo(void)
528+{
529+ int err;
530+ mknod("/tmp/caitsith.tmp/fifo", S_IFIFO | 0600, 0);
531+ err = errno;
532+ unlink("/tmp/caitsith.tmp/fifo");
533+ return err;
534+}
535+
536+static int test_mksock_by_mknod(void)
537+{
538+ int err;
539+ mknod("/tmp/caitsith.tmp/sock", S_IFSOCK | 0600, 0);
540+ err = errno;
541+ unlink("/tmp/caitsith.tmp/sock");
542+ return err;
543+}
544+
545+static int test_mksock_by_bind(void)
546+{
547+ struct sockaddr_un addr;
548+ int err;
549+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
550+ memset(&addr, 0, sizeof(addr));
551+ addr.sun_family = AF_UNIX;
552+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1,
553+ "/tmp/caitsith.tmp/sock");
554+ errno = 0;
555+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
556+ err = errno;
557+ unlink(addr.sun_path);
558+ return err;
559+}
560+
561+static int test_truncate(void)
562+{
563+ mknod("/tmp/caitsith.tmp/truncate", S_IFREG | 0600, 0);
564+ errno = 0;
565+ truncate("/tmp/caitsith.tmp/truncate", 0);
566+ return errno;
567+}
568+
569+static int test_symlink(void)
570+{
571+ int err;
572+ symlink(".", "/tmp/caitsith.tmp/symlink");
573+ err = errno;
574+ unlink("/tmp/caitsith.tmp/symlink");
575+ return err;
576+}
577+
578+static int test_mkchar(void)
579+{
580+ int err;
581+ mknod("/tmp/caitsith.tmp/char", S_IFCHR | 0600, MKDEV(1, 3));
582+ err = errno;
583+ unlink("/tmp/caitsith.tmp/char");
584+ return err;
585+}
586+
587+static int test_mkblock(void)
588+{
589+ int err;
590+ mknod("/tmp/caitsith.tmp/block", S_IFBLK | 0600, MKDEV(1, 0));
591+ err = errno;
592+ unlink("/tmp/caitsith.tmp/block");
593+ return err;
594+}
595+
596+static int test_link(void)
597+{
598+ int err;
599+ mknod("/tmp/caitsith.tmp/old_path", S_IFREG | 0600, 0);
600+ errno = 0;
601+ link("/tmp/caitsith.tmp/old_path", "/tmp/caitsith.tmp/new_path");
602+ err = errno;
603+ unlink("/tmp/caitsith.tmp/old_path");
604+ unlink("/tmp/caitsith.tmp/new_path");
605+ return err;
606+}
607+
608+static int test_rename(void)
609+{
610+ int err;
611+ mknod("/tmp/caitsith.tmp/old_path", S_IFREG | 0600, 0);
612+ errno = 0;
613+ rename("/tmp/caitsith.tmp/old_path", "/tmp/caitsith.tmp/new_path");
614+ err = errno;
615+ unlink("/tmp/caitsith.tmp/old_path");
616+ unlink("/tmp/caitsith.tmp/new_path");
617+ return err;
618+}
619+
620+static int test_chmod(void)
621+{
622+ chmod("/dev/null", 0666);
623+ return errno;
624+}
625+
626+static int test_chown(void)
627+{
628+ chown("/dev/null", 0, -1);
629+ return errno;
630+}
631+
632+static int test_chgrp(void)
633+{
634+ chown("/dev/null", -1, 0);
635+ return errno;
636+}
637+
638+static int test_ioctl(void)
639+{
640+ const int fd = open("/dev/null", O_WRONLY);
641+ errno = 0;
642+ ioctl(fd, 0, 0);
643+ return errno;
644+}
645+
646+static int test_chroot(void)
647+{
648+ chroot("/tmp/caitsith.tmp");
649+ return errno;
650+}
651+
652+static int test_mount(void)
653+{
654+ mount(NULL, "/tmp/caitsith.tmp", "tmpfs", 0, NULL);
655+ return errno;
656+}
657+
658+static int test_unmount(void)
659+{
660+ mount(NULL, "/tmp/caitsith.tmp", "tmpfs", 0, NULL);
661+ errno = 0;
662+ umount("/tmp/caitsith.tmp");
663+ return errno;
664+}
665+
666+static int test_pivot_root(void)
667+{
668+ errno = 0;
669+ pivot_root("/sys/kernel/security/", "/sys/kernel/security/caitsith/");
670+ if (errno == ENOENT) {
671+ errno = 0;
672+ pivot_root("/proc/", "/proc/caitsith/");
673+ }
674+ return errno;
675+}
676+
677+static void inet_bind(const int fd, const unsigned short int port)
678+{
679+ struct sockaddr_in addr = { };
680+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
681+ addr.sin_family = AF_INET;
682+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
683+ addr.sin_port = htons(port);
684+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
685+}
686+
687+static int test_inet_stream_bind(void)
688+{
689+ int fd = socket(PF_INET, SOCK_STREAM, 0);
690+ struct sockaddr_in addr = { };
691+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
692+ addr.sin_family = AF_INET;
693+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
694+ addr.sin_port = htons(10000);
695+ errno = 0;
696+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
697+ return errno;
698+}
699+
700+static int test_inet_stream_listen(void)
701+{
702+ int fd = socket(PF_INET, SOCK_STREAM, 0);
703+ inet_bind(fd, 10000);
704+ errno = 0;
705+ listen(fd, 5);
706+ return errno;
707+}
708+
709+static int test_inet_stream_connect(void)
710+{
711+ int fd1 = socket(PF_INET, SOCK_STREAM, 0);
712+ int fd2 = socket(PF_INET, SOCK_STREAM, 0);
713+ struct sockaddr_in addr = { };
714+ socklen_t size = sizeof(addr);
715+ inet_bind(fd1, 10000);
716+ listen(fd1, 0);
717+ inet_bind(fd2, 10001);
718+ getsockname(fd1, (struct sockaddr *) &addr, &size);
719+ errno = 0;
720+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
721+ return errno;
722+}
723+
724+static int test_inet_stream_accept(void)
725+{
726+ int fd1 = socket(PF_INET, SOCK_STREAM, 0);
727+ int fd2 = socket(PF_INET, SOCK_STREAM, 0);
728+ struct sockaddr_in addr = { };
729+ socklen_t size = sizeof(addr);
730+ inet_bind(fd1, 10000);
731+ listen(fd1, 0);
732+ inet_bind(fd2, 10001);
733+ getsockname(fd1, (struct sockaddr *) &addr, &size);
734+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
735+ errno = 0;
736+ accept(fd1, (struct sockaddr *) &addr, &size);
737+ return errno;
738+}
739+
740+static int test_inet_dgram_bind(void)
741+{
742+ int fd = socket(PF_INET, SOCK_DGRAM, 0);
743+ struct sockaddr_in addr = { };
744+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
745+ addr.sin_family = AF_INET;
746+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
747+ addr.sin_port = htons(10000);
748+ errno = 0;
749+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
750+ return errno;
751+}
752+
753+static int test_inet_dgram_connect(void)
754+{
755+ int fd1 = socket(PF_INET, SOCK_DGRAM, 0);
756+ int fd2 = socket(PF_INET, SOCK_DGRAM, 0);
757+ struct sockaddr_in addr = { };
758+ socklen_t size = sizeof(addr);
759+ inet_bind(fd1, 10000);
760+ inet_bind(fd2, 10001);
761+ getsockname(fd1, (struct sockaddr *) &addr, &size);
762+ errno = 0;
763+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
764+ return errno;
765+}
766+
767+static int test_inet_dgram_send(void)
768+{
769+ int fd1 = socket(PF_INET, SOCK_DGRAM, 0);
770+ int fd2 = socket(PF_INET, SOCK_DGRAM, 0);
771+ struct sockaddr_in addr = { };
772+ socklen_t size = sizeof(addr);
773+ inet_bind(fd1, 10000);
774+ inet_bind(fd2, 10001);
775+ getsockname(fd1, (struct sockaddr *) &addr, &size);
776+ errno = 0;
777+ sendto(fd2, "", 1, 0, (struct sockaddr *) &addr, sizeof(addr));
778+ return errno;
779+}
780+
781+static int test_inet_dgram_recv(void)
782+{
783+ int fd1 = socket(PF_INET, SOCK_DGRAM, 0);
784+ int fd2 = socket(PF_INET, SOCK_DGRAM, 0);
785+ char c;
786+ struct sockaddr_in addr = { };
787+ socklen_t size = sizeof(addr);
788+ inet_bind(fd1, 10000);
789+ inet_bind(fd2, 10001);
790+ getsockname(fd1, (struct sockaddr *) &addr, &size);
791+ sendto(fd2, "", 1, 0, (struct sockaddr *) &addr, sizeof(addr));
792+ errno = 0;
793+ recvfrom(fd1, &c, 1, MSG_DONTWAIT, (struct sockaddr *) &addr, &size);
794+ return errno;
795+}
796+
797+static int test_inet_raw_bind(void)
798+{
799+ int fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
800+ struct sockaddr_in addr = { };
801+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
802+ addr.sin_family = AF_INET;
803+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
804+ addr.sin_port = htons(10000);
805+ errno = 0;
806+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
807+ return errno;
808+}
809+
810+static int test_inet_raw_connect(void)
811+{
812+ int fd1 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
813+ int fd2 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
814+ struct sockaddr_in addr = { };
815+ socklen_t size = sizeof(addr);
816+ inet_bind(fd1, 10000);
817+ inet_bind(fd2, 10001);
818+ getsockname(fd1, (struct sockaddr *) &addr, &size);
819+ errno = 0;
820+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
821+ return errno;
822+}
823+
824+static int test_inet_raw_send(void)
825+{
826+ int fd1 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
827+ int fd2 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
828+ struct sockaddr_in addr = { };
829+ socklen_t size = sizeof(addr);
830+ static struct iphdr ip = { };
831+ inet_bind(fd1, 10000);
832+ inet_bind(fd2, 10001);
833+ getsockname(fd1, (struct sockaddr *) &addr, &size);
834+ ip.version = 4;
835+ ip.ihl = sizeof(struct iphdr) / 4;
836+ ip.protocol = IPPROTO_RAW;
837+ ip.daddr = htonl(INADDR_LOOPBACK);
838+ ip.saddr = ip.daddr;
839+ errno = 0;
840+ sendto(fd2, &ip, sizeof(ip), 0, (struct sockaddr *) &addr,
841+ sizeof(addr));
842+ return errno;
843+}
844+
845+static int test_inet_raw_recv(void)
846+{
847+ int fd1 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
848+ int fd2 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
849+ struct sockaddr_in addr = { };
850+ socklen_t size = sizeof(addr);
851+ static struct iphdr ip = { };
852+ inet_bind(fd1, 10000);
853+ inet_bind(fd2, 10000);
854+ getsockname(fd1, (struct sockaddr *) &addr, &size);
855+ ip.version = 4;
856+ ip.ihl = sizeof(struct iphdr) / 4;
857+ ip.protocol = IPPROTO_RAW;
858+ ip.daddr = htonl(INADDR_LOOPBACK);
859+ ip.saddr = ip.daddr;
860+ sendto(fd2, &ip, sizeof(ip), 0, (struct sockaddr *) &addr,
861+ sizeof(addr));
862+ errno = 0;
863+ recvfrom(fd1, &ip, sizeof(ip), MSG_DONTWAIT, (struct sockaddr *) &addr,
864+ &size);
865+ return errno;
866+}
867+
868+static void unix_bind(const int fd, const _Bool listener)
869+{
870+ struct sockaddr_un addr = { };
871+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
872+ addr.sun_family = AF_UNIX;
873+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1,
874+ "/tmp/caitsith.tmp/%s", listener ? "server" : "client");
875+ unlink(addr.sun_path);
876+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
877+}
878+
879+static int test_unix_stream_bind(void)
880+{
881+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
882+ struct sockaddr_un addr = { };
883+ addr.sun_family = AF_UNIX;
884+ errno = 0;
885+ bind(fd, (struct sockaddr *) &addr, sizeof(addr.sun_family));
886+ return errno;
887+}
888+
889+static int test_unix_stream_listen(void)
890+{
891+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
892+ unix_bind(fd, 1);
893+ errno = 0;
894+ listen(fd, 5);
895+ return errno;
896+}
897+
898+static int test_unix_stream_connect(void)
899+{
900+ int fd1 = socket(PF_UNIX, SOCK_STREAM, 0);
901+ int fd2 = socket(PF_UNIX, SOCK_STREAM, 0);
902+ struct sockaddr_un addr = { };
903+ socklen_t size = sizeof(addr);
904+ unix_bind(fd1, 1);
905+ unix_bind(fd2, 0);
906+ listen(fd1, 0);
907+ getsockname(fd1, (struct sockaddr *) &addr, &size);
908+ errno = 0;
909+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
910+ return errno;
911+}
912+
913+static int test_unix_stream_accept(void)
914+{
915+ int fd1 = socket(PF_UNIX, SOCK_STREAM, 0);
916+ int fd2 = socket(PF_UNIX, SOCK_STREAM, 0);
917+ struct sockaddr_un addr = { };
918+ socklen_t size = sizeof(addr);
919+ unix_bind(fd1, 1);
920+ unix_bind(fd2, 0);
921+ listen(fd1, 0);
922+ getsockname(fd1, (struct sockaddr *) &addr, &size);
923+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
924+ errno = 0;
925+ accept(fd1, (struct sockaddr *) &addr, &size);
926+ return errno;
927+}
928+
929+static int test_unix_dgram_bind(void)
930+{
931+ int fd = socket(PF_UNIX, SOCK_DGRAM, 0);
932+ int err;
933+ struct sockaddr_un addr = { };
934+ addr.sun_family = AF_UNIX;
935+ errno = 0;
936+ bind(fd, (struct sockaddr *) &addr, sizeof(addr));
937+ err = errno;
938+ close(fd);
939+ return err;
940+}
941+
942+static int test_unix_dgram_connect(void)
943+{
944+ int fd1 = socket(PF_UNIX, SOCK_DGRAM, 0);
945+ int fd2 = socket(PF_UNIX, SOCK_DGRAM, 0);
946+ int err;
947+ struct sockaddr_un addr = { };
948+ socklen_t size = sizeof(addr);
949+ unix_bind(fd1, 1);
950+ unix_bind(fd2, 0);
951+ getsockname(fd1, (struct sockaddr *) &addr, &size);
952+ errno = 0;
953+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
954+ err = errno;
955+ close(fd1);
956+ close(fd2);
957+ return err;
958+}
959+
960+static int test_unix_dgram_send(void)
961+{
962+ int fd1 = socket(PF_UNIX, SOCK_DGRAM, 0);
963+ int fd2 = socket(PF_UNIX, SOCK_DGRAM, 0);
964+ int err;
965+ struct sockaddr_un addr = { };
966+ socklen_t size = sizeof(addr);
967+ unix_bind(fd1, 1);
968+ unix_bind(fd2, 0);
969+ getsockname(fd1, (struct sockaddr *) &addr, &size);
970+ errno = 0;
971+ sendto(fd2, "", 1, 0, (struct sockaddr *) &addr, sizeof(addr));
972+ err = errno;
973+ close(fd1);
974+ close(fd2);
975+ return err;
976+}
977+
978+static int test_unix_dgram_recv(void)
979+{
980+ int fd1 = socket(PF_UNIX, SOCK_DGRAM, 0);
981+ int fd2 = socket(PF_UNIX, SOCK_DGRAM, 0);
982+ int err;
983+ char c;
984+ struct sockaddr_un addr = { };
985+ socklen_t size = sizeof(addr);
986+ unix_bind(fd1, 1);
987+ unix_bind(fd2, 0);
988+ getsockname(fd1, (struct sockaddr *) &addr, &size);
989+ sendto(fd2, "", 1, 0, (struct sockaddr *) &addr, sizeof(addr));
990+ errno = 0;
991+ recvfrom(fd1, &c, 1, MSG_DONTWAIT, (struct sockaddr *) &addr, &size);
992+ err = errno;
993+ close(fd1);
994+ close(fd2);
995+ return err;
996+}
997+
998+static int test_unix_seqpacket_bind(void)
999+{
1000+ int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1001+ int err;
1002+ struct sockaddr_un addr = { };
1003+ addr.sun_family = AF_UNIX;
1004+ errno = 0;
1005+ bind(fd, (struct sockaddr *) &addr, sizeof(addr.sun_family));
1006+ err = errno;
1007+ close(fd);
1008+ return err;
1009+}
1010+
1011+static int test_unix_seqpacket_listen(void)
1012+{
1013+ int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1014+ int err;
1015+ unix_bind(fd, 1);
1016+ errno = 0;
1017+ listen(fd, 5);
1018+ err = errno;
1019+ close(fd);
1020+ return err;
1021+}
1022+
1023+static int test_unix_seqpacket_connect(void)
1024+{
1025+ int fd1 = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1026+ int fd2 = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1027+ int err;
1028+ struct sockaddr_un addr = { };
1029+ socklen_t size = sizeof(addr);
1030+ unix_bind(fd1, 1);
1031+ unix_bind(fd2, 0);
1032+ listen(fd1, 0);
1033+ getsockname(fd1, (struct sockaddr *) &addr, &size);
1034+ errno = 0;
1035+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
1036+ err = errno;
1037+ close(fd1);
1038+ close(fd2);
1039+ return err;
1040+}
1041+
1042+static int test_unix_seqpacket_accept(void)
1043+{
1044+ int fd1 = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1045+ int fd2 = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1046+ struct sockaddr_un addr = { };
1047+ socklen_t size = sizeof(addr);
1048+ unix_bind(fd1, 1);
1049+ unix_bind(fd2, 0);
1050+ listen(fd1, 0);
1051+ getsockname(fd1, (struct sockaddr *) &addr, &size);
1052+ connect(fd2, (struct sockaddr *) &addr, sizeof(addr));
1053+ errno = 0;
1054+ accept(fd1, (struct sockaddr *) &addr, &size);
1055+ return errno;
1056+}
1057+
1058+static int test_environ(void)
1059+{
1060+ char * const argv[2] = { "true", NULL };
1061+ char * const envp[2] = { "HOME=/", NULL };
1062+ execve(BINDIR "/true", argv, envp);
1063+ return errno;
1064+}
1065+
1066+static int test_ptrace(void)
1067+{
1068+ ptrace(PTRACE_ATTACH, 1, NULL, NULL);
1069+ return errno;
1070+}
1071+
1072+static int test_signal(void)
1073+{
1074+ kill(1, 1);
1075+ return errno;
1076+}
1077+
1078+static int test_modify_policy(void)
1079+{
1080+ const char *policy = "1 acl modify_policy\n";
1081+ /*
1082+ * Try to execute a non-executable in order to clear cached policy
1083+ * manager attribute.
1084+ */
1085+ const int fd = open("/tmp/caitsith.tmp/exec",
1086+ O_CREAT | O_TRUNC | O_WRONLY, 0600);
1087+ fchmod(fd, 0700);
1088+ close(fd);
1089+ execl("/tmp/caitsith.tmp/exec", "exec", NULL);
1090+ /* Now policy manager attribute was cleared. */
1091+ errno = 0;
1092+ write(policy_fd, policy, strlen(policy));
1093+ return errno;
1094+}
1095+
1096+static int test_use_netlink_socket(void)
1097+{
1098+ const int fd = socket(AF_ROUTE, SOCK_RAW, 0);
1099+ const int err = errno;
1100+ close(fd);
1101+ return err;
1102+}
1103+
1104+static int test_use_packet_socket(void)
1105+{
1106+ const int fd = socket(AF_PACKET, SOCK_RAW, 0);
1107+ const int err = errno;
1108+ close(fd);
1109+ return err;
1110+}
1111+
1112+static int test_use_reboot(void)
1113+{
1114+ FILE *fp = fopen("/proc/sys/kernel/ctrl-alt-del", "a+");
1115+ unsigned int c;
1116+ int err;
1117+ if (fp && fscanf(fp, "%u", &c) == 1) {
1118+ errno = 0;
1119+ reboot(LINUX_REBOOT_CMD_CAD_ON);
1120+ err = errno;
1121+ rewind(fp);
1122+ fprintf(fp, "%u\n", c);
1123+ } else {
1124+ errno = 0;
1125+ /* Use invalid value */
1126+ reboot(0x0000C0DE);
1127+ err = errno;
1128+ }
1129+ if (fp)
1130+ fclose(fp);
1131+ return err;
1132+}
1133+
1134+static int test_use_vhangup(void)
1135+{
1136+ setsid();
1137+ errno = 0;
1138+ vhangup();
1139+ return errno;
1140+}
1141+
1142+static int test_set_time_by_stime(void)
1143+{
1144+ const time_t now = time(NULL);
1145+ errno = 0;
1146+ stime(&now);
1147+ return errno;
1148+}
1149+
1150+static int test_set_time_by_settimeofday(void)
1151+{
1152+ struct timeval tv;
1153+ struct timezone tz;
1154+ gettimeofday(&tv, &tz);
1155+ errno = 0;
1156+ settimeofday(&tv, &tz);
1157+ return errno;
1158+}
1159+
1160+static int test_set_time_by_adjtimex(void)
1161+{
1162+ struct timex buf = { };
1163+ buf.modes = 0x100; /* Use invalid value so that the clock
1164+ won't change. */
1165+ adjtimex(&buf);
1166+ return errno;
1167+}
1168+
1169+static int test_set_priority_by_nice(void)
1170+{
1171+ nice(0);
1172+ return errno;
1173+}
1174+
1175+static int test_set_priority_by_setpriority(void)
1176+{
1177+ const int priority = getpriority(PRIO_PROCESS, getpid());
1178+ errno = 0;
1179+ setpriority(PRIO_PROCESS, getpid(), priority);
1180+ return errno;
1181+}
1182+
1183+static int test_set_hostname_by_sethostname(void)
1184+{
1185+ char buffer[4096] = { };
1186+ gethostname(buffer, sizeof(buffer) - 1);
1187+ errno = 0;
1188+ sethostname(buffer, strlen(buffer));
1189+ return errno;
1190+}
1191+
1192+static int test_set_hostname_by_setdomainname(void)
1193+{
1194+ char buffer[4096] = { };
1195+ getdomainname(buffer, sizeof(buffer) - 1);
1196+ errno = 0;
1197+ setdomainname(buffer, strlen(buffer));
1198+ return errno;
1199+}
1200+
1201+static int test_use_kernel_module_by_init_module(void)
1202+{
1203+ init_module("", NULL);
1204+ return errno;
1205+}
1206+
1207+static int test_use_kernel_module_by_delete_module(void)
1208+{
1209+ delete_module("");
1210+ return errno;
1211+}
1212+
1213+static int test_use_new_kernel(void)
1214+{
1215+ sys_kexec_load(0, 0, NULL, 0);
1216+ return errno;
1217+}
1218+
1219+static void reset_policy(void)
1220+{
1221+ FILE *fp2 = fopen(POLDIR "/policy", "r");
1222+ FILE *fp1 = fopen(POLDIR "/policy", "w");
1223+ if (!fp1 || !fp2) {
1224+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
1225+ exit(1);
1226+ }
1227+ while (1) {
1228+ const int c = fgetc(fp2);
1229+ if (c == EOF)
1230+ break;
1231+ fputc(c, fp1);
1232+ if (c == '\n')
1233+ fprintf(fp1, "delete ");
1234+ }
1235+ fclose(fp2);
1236+ fclose(fp1);
1237+
1238+ /* Do not leave the init process in stopped state. */
1239+ kill(1, SIGCONT);
1240+
1241+ /* Undo mount("/", MS_REC|MS_SHARED) made by systemd. */
1242+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
1243+}
1244+
1245+int main(int argc, char *argv[])
1246+{
1247+ int i;
1248+ static const struct {
1249+ const char *action;
1250+ int (*func) (void);
1251+ } testcases[] = {
1252+ { "execute", test_execute },
1253+ { "read", test_read },
1254+ { "write", test_write },
1255+ { "create", test_create_no_append },
1256+ { "read", test_create_no_append },
1257+ { "write", test_create_no_append },
1258+ /* { "truncate", test_create_no_append }, */
1259+ { "create", test_create_append },
1260+ { "read", test_create_append },
1261+ { "append", test_create_append },
1262+ /* { "truncate", test_create_append }, */
1263+ { "write", test_fcntl_clear_append },
1264+ { "append", test_fcntl_set_append },
1265+ { "unlink", test_unlink },
1266+ { "getattr", test_getattr },
1267+ { "mkdir", test_mkdir },
1268+ { "rmdir", test_rmdir },
1269+ { "mkfifo", test_mkfifo },
1270+ { "mksock", test_mksock_by_mknod },
1271+ { "mksock", test_mksock_by_bind },
1272+ { "truncate", test_truncate },
1273+ { "symlink", test_symlink },
1274+ { "mkchar", test_mkchar },
1275+ { "mkblock", test_mkblock },
1276+ { "link", test_link },
1277+ { "rename", test_rename },
1278+ { "chmod", test_chmod },
1279+ { "chown", test_chown },
1280+ { "chgrp", test_chgrp },
1281+ { "ioctl", test_ioctl },
1282+ { "chroot", test_chroot },
1283+ { "mount", test_mount },
1284+ { "unmount", test_unmount },
1285+ { "pivot_root", test_pivot_root },
1286+ { "inet_stream_bind", test_inet_stream_bind },
1287+ { "inet_stream_listen", test_inet_stream_listen },
1288+ { "inet_stream_connect", test_inet_stream_connect },
1289+ { "inet_stream_accept", test_inet_stream_accept },
1290+ { "inet_dgram_bind", test_inet_dgram_bind },
1291+ { "inet_dgram_send", test_inet_dgram_connect },
1292+ { "inet_dgram_send", test_inet_dgram_send },
1293+ { "inet_dgram_recv", test_inet_dgram_recv },
1294+ { "inet_raw_bind", test_inet_raw_bind },
1295+ { "inet_raw_send", test_inet_raw_connect },
1296+ { "inet_raw_send", test_inet_raw_send },
1297+ { "inet_raw_recv", test_inet_raw_recv },
1298+ { "unix_stream_bind", test_unix_stream_bind },
1299+ { "unix_stream_listen", test_unix_stream_listen },
1300+ { "unix_stream_connect", test_unix_stream_connect },
1301+ { "unix_stream_accept", test_unix_stream_accept },
1302+ { "unix_dgram_bind", test_unix_dgram_bind },
1303+ { "unix_dgram_send", test_unix_dgram_connect },
1304+ { "unix_dgram_send", test_unix_dgram_send },
1305+ { "unix_dgram_recv", test_unix_dgram_recv },
1306+ { "unix_seqpacket_bind", test_unix_seqpacket_bind },
1307+ { "unix_seqpacket_listen", test_unix_seqpacket_listen },
1308+ { "unix_seqpacket_connect", test_unix_seqpacket_connect },
1309+ { "unix_seqpacket_accept", test_unix_seqpacket_accept },
1310+ { "environ", test_environ },
1311+ { "ptrace", test_ptrace },
1312+ { "signal", test_signal },
1313+ { "modify_policy", test_modify_policy },
1314+ { "use_netlink_socket", test_use_netlink_socket },
1315+ { "use_packet_socket", test_use_packet_socket },
1316+ { "use_reboot", test_use_reboot },
1317+ { "use_vhangup", test_use_vhangup },
1318+ { "set_time", test_set_time_by_stime },
1319+ { "set_time", test_set_time_by_settimeofday },
1320+ { "set_time", test_set_time_by_adjtimex },
1321+ { "set_priority", test_set_priority_by_nice },
1322+ { "set_priority", test_set_priority_by_setpriority },
1323+ { "set_hostname", test_set_hostname_by_sethostname },
1324+ { "set_hostname", test_set_hostname_by_setdomainname },
1325+ { "use_kernel_module", test_use_kernel_module_by_init_module },
1326+ { "use_kernel_module",
1327+ test_use_kernel_module_by_delete_module },
1328+ { "use_new_kernel", test_use_new_kernel },
1329+ { NULL, NULL }
1330+ };
1331+
1332+ reset_policy();
1333+
1334+ startup();
1335+ for (i = 0; testcases[i].action; i++)
1336+ test_action(testcases[i].action, testcases[i].func);
1337+ fprintf(stderr, "Done.\n");
1338+ return 0;
1339+}
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_lsm_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_lsm_test.c (revision 219)
@@ -0,0 +1,1843 @@
1+/*
2+ * caitsith_lsm_test.c
3+ *
4+ * Copyright (C) 2012-2013 Tetsuo Handa
5+ *
6+ * Version: 0.2 2016/10/05
7+ *
8+ * This program is free software; you can redistribute it and/or modify it
9+ * under the terms of the GNU General Public License v2 as published by the
10+ * Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful, but WITHOUT
13+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15+ * more details.
16+ *
17+ * You should have received a copy of the GNU General Public License along with
18+ * this program; if not, write to the Free Software Foundation, Inc.,
19+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+ */
21+
22+#include <stdio.h>
23+#include <stdlib.h>
24+#include <string.h>
25+#include <unistd.h>
26+#include <sys/types.h>
27+#include <sys/stat.h>
28+#include <sys/socket.h>
29+#include <netinet/in.h>
30+#include <sys/wait.h>
31+#include <linux/ip.h>
32+#include <fcntl.h>
33+#include <errno.h>
34+#include <sys/mount.h>
35+#ifndef MS_REC
36+#define MS_REC 16384
37+#endif
38+#ifndef MS_PRIVATE
39+#define MS_PRIVATE (1 << 18)
40+#endif
41+
42+static FILE *fp = NULL;
43+
44+static void set(const char *str)
45+{
46+ fprintf(fp, "%s\n", str);
47+ fflush(fp);
48+ errno = 0;
49+}
50+
51+static void unset(const char *str)
52+{
53+ fprintf(fp, "delete %s\n", str);
54+ fflush(fp);
55+ errno = 0;
56+}
57+
58+static void unset2(const char *str)
59+{
60+ const char *cp = str;
61+ while (*cp) {
62+ if (*cp++ != '\n')
63+ continue;
64+ fprintf(fp, "delete ");
65+ fwrite(str, cp - str, 1, fp);
66+ str = cp;
67+ }
68+ fprintf(fp, "delete %s\n", str);
69+ fflush(fp);
70+ errno = 0;
71+}
72+
73+static void check(const char *prompt, int result)
74+{
75+ int err = errno;
76+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
77+ if (!result) {
78+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
79+ {
80+ int fd2 = open(POLDIR "/self_domain", O_RDONLY);
81+ char c;
82+ fprintf(stderr, "task.domain=\"");
83+ while (read(fd2, &c, 1) == 1)
84+ fprintf(stderr, "%c", c);
85+ close(fd2);
86+ fprintf(stderr, "\"\n");
87+ }
88+ kill(1, SIGCONT);
89+ exit(1);
90+ }
91+ printf("\n");
92+ fflush(stdout);
93+}
94+
95+static void check_init(const char *prompt, const char *expected)
96+{
97+ int result;
98+ int fd = open(POLDIR "/.process_status", O_RDWR);
99+ char buffer[1024];
100+ char *cp;
101+ memset(buffer, 0, sizeof(buffer));
102+ kill(1, SIGHUP);
103+ sleep(1);
104+ write(fd, "1\n", 2);
105+ read(fd, buffer, sizeof(buffer) - 1);
106+ close(fd);
107+ cp = strchr(buffer, ' ');
108+ if (cp++)
109+ memmove(buffer, cp, strlen(cp) + 1);
110+ result = !strcmp(buffer, expected);
111+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
112+ if (!result) {
113+ fprintf(stderr, "Err: expected='%s' result='%s'\n",
114+ expected, buffer);
115+ kill(1, SIGCONT);
116+ exit(1);
117+ }
118+ printf("\n");
119+ fflush(stdout);
120+}
121+
122+static void test_task_transition(void)
123+{
124+ int fd = open(POLDIR "/self_domain", O_WRONLY);
125+ char *policy;
126+
127+ policy = "100 acl manual_domain_transition\n"
128+ "0 allow domain=\"domain\\$\"\n";
129+ set(policy);
130+ check(policy, write(fd, "domain0", 7) != EOF);
131+ check(policy, write(fd, "domain10", 8) != EOF);
132+ check(policy, write(fd, "domainXYX", 9) == EOF);
133+ check(policy, write(fd, "domain200", 9) != EOF);
134+ unset(policy);
135+
136+ policy = "100 acl auto_domain_transition\n"
137+ "0 allow task.pid=1 transition=\"<init3>\"\n";
138+ set(policy);
139+ check_init(policy, "<init3>");
140+ unset(policy);
141+
142+ policy = "100 acl auto_domain_transition\n"
143+ "0 allow task.pid=1 task.uid!=0 transition=\"<init2>\"\n";
144+ set(policy);
145+ check_init(policy, "<init3>");
146+ unset(policy);
147+
148+ policy = "100 acl auto_domain_transition\n"
149+ "0 allow task.pid=1 transition=\"<init>\"\n";
150+ set(policy);
151+ check_init(policy, "<init>");
152+ unset(policy);
153+
154+ close(fd);
155+}
156+
157+static void test_file_read(void)
158+{
159+ int fd;
160+ char *policy;
161+
162+ policy = "100 acl read\n";
163+ set(policy);
164+ fd = open("/dev/null", O_RDONLY);
165+ check(policy, fd != EOF);
166+ close(fd);
167+ unset(policy);
168+
169+ policy = "100 acl read\n"
170+ "0 allow\n"
171+ "1 deny\n";
172+ set(policy);
173+ fd = open("/dev/null", O_RDONLY);
174+ check(policy, fd != EOF);
175+ close(fd);
176+ unset(policy);
177+
178+ policy = "100 acl read\n"
179+ "0 deny\n"
180+ "1 allow\n";
181+ set(policy);
182+ fd = open("/dev/null", O_RDONLY);
183+ check(policy, fd == EOF);
184+ close(fd);
185+ unset(policy);
186+
187+ policy = "100 acl read path=\"/dev/null\"\n"
188+ "0 allow\n"
189+ "1 deny\n";
190+ set(policy);
191+ fd = open("/dev/null", O_RDONLY);
192+ check(policy, fd != EOF);
193+ close(fd);
194+ unset(policy);
195+
196+ policy = "100 acl read path=\"/dev/null\"\n"
197+ "0 deny\n"
198+ "1 allow\n";
199+ set(policy);
200+ fd = open("/dev/null", O_RDONLY);
201+ check(policy, fd == EOF);
202+ close(fd);
203+ unset(policy);
204+
205+ policy = "100 acl read\n"
206+ "0 allow path=\"/dev/null\"\n"
207+ "1 deny\n";
208+ set(policy);
209+ fd = open("/dev/null", O_RDONLY);
210+ check(policy, fd != EOF);
211+ close(fd);
212+ unset(policy);
213+
214+ policy = "100 acl read\n"
215+ "0 deny path=\"/dev/null\"\n"
216+ "1 allow\n";
217+ set(policy);
218+ fd = open("/dev/null", O_RDONLY);
219+ check(policy, fd == EOF);
220+ close(fd);
221+ unset(policy);
222+
223+ policy = "100 acl read\n"
224+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
225+ "1 deny\n";
226+ set(policy);
227+ fd = open("/dev/null", O_RDONLY);
228+ check(policy, fd != EOF);
229+ close(fd);
230+ unset(policy);
231+
232+ policy = "100 acl read\n"
233+ "0 deny path.type=char path.dev_major=1 path.dev_minor=3\n"
234+ "1 allow\n";
235+ set(policy);
236+ fd = open("/dev/null", O_RDONLY);
237+ check(policy, fd == EOF);
238+ close(fd);
239+ unset(policy);
240+
241+ policy = "100 acl read\n"
242+ "0 allow path.type=char path.dev_major=1 path.dev_minor!=3\n"
243+ "1 deny\n";
244+ set(policy);
245+ fd = open("/dev/null", O_RDONLY);
246+ check(policy, fd == EOF);
247+ close(fd);
248+ unset(policy);
249+
250+ policy = "100 acl read\n"
251+ "0 deny path.type=char path.dev_major=1 path.dev_minor!=3\n"
252+ "1 allow\n";
253+ set(policy);
254+ fd = open("/dev/null", O_RDONLY);
255+ check(policy, fd != EOF);
256+ close(fd);
257+ unset(policy);
258+
259+ policy = "string_group GROUP1 /dev/null\n"
260+ "100 acl read\n"
261+ "0 allow path=@GROUP1\n"
262+ "1 deny\n";
263+ set(policy);
264+ fd = open("/dev/null", O_RDONLY);
265+ check(policy, fd != EOF);
266+ close(fd);
267+ unset2(policy);
268+
269+ policy = "string_group GROUP1 /dev/null\n"
270+ "100 acl read\n"
271+ "0 deny path=@GROUP1\n"
272+ "1 allow\n";
273+ set(policy);
274+ fd = open("/dev/null", O_RDONLY);
275+ check(policy, fd == EOF);
276+ close(fd);
277+ unset2(policy);
278+
279+ policy = "string_group GROUP1 /dev/null\n"
280+ "100 acl read\n"
281+ "0 allow path!=@GROUP1\n"
282+ "1 deny\n";
283+ set(policy);
284+ fd = open("/dev/null", O_RDONLY);
285+ check(policy, fd == EOF);
286+ close(fd);
287+ unset2(policy);
288+
289+ policy = "string_group GROUP1 /dev/null\n"
290+ "100 acl read\n"
291+ "0 deny path!=@GROUP1\n"
292+ "1 allow\n";
293+ set(policy);
294+ fd = open("/dev/null", O_RDONLY);
295+ check(policy, fd != EOF);
296+ close(fd);
297+ unset2(policy);
298+
299+ policy = "string_group GROUP1 /dev/null\n"
300+ "number_group MAJOR 1\n"
301+ "number_group MINOR 3\n"
302+ "100 acl read\n"
303+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
304+ " path.dev_minor=@MINOR\n"
305+ "1 deny\n";
306+ set(policy);
307+ fd = open("/dev/null", O_RDONLY);
308+ check(policy, fd != EOF);
309+ close(fd);
310+ unset2(policy);
311+
312+ policy = "string_group GROUP1 /dev/null\n"
313+ "number_group MAJOR 1\n"
314+ "number_group MINOR 3\n"
315+ "100 acl read\n"
316+ "0 deny path=@GROUP1 path.dev_major=@MAJOR"
317+ " path.dev_minor=@MINOR\n"
318+ "1 allow\n";
319+ set(policy);
320+ fd = open("/dev/null", O_RDONLY);
321+ check(policy, fd == EOF);
322+ close(fd);
323+ unset2(policy);
324+
325+ policy = "string_group GROUP1 /dev/zero\n"
326+ "string_group GROUP1 /dev/null\n"
327+ "string_group GROUP1 /dev/urandom\n"
328+ "number_group MAJOR 0\n"
329+ "number_group MAJOR 2-255\n"
330+ "number_group MINOR 00-0x2\n"
331+ "number_group MINOR 255\n"
332+ "100 acl read\n"
333+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
334+ " path.dev_minor=@MINOR\n"
335+ "1 deny\n";
336+ set(policy);
337+ fd = open("/dev/null", O_RDONLY);
338+ check(policy, fd == EOF);
339+ close(fd);
340+ unset2(policy);
341+
342+ policy = "string_group GROUP1 /dev/zero\n"
343+ "string_group GROUP1 /dev/null\n"
344+ "string_group GROUP1 /dev/urandom\n"
345+ "number_group MAJOR 0\n"
346+ "number_group MAJOR 2-255\n"
347+ "number_group MINOR 00-0x2\n"
348+ "number_group MINOR 255\n"
349+ "100 acl read\n"
350+ "0 allow path=@GROUP1 path.dev_major!=@MAJOR"
351+ " path.dev_minor!=@MINOR\n"
352+ "1 deny\n";
353+ set(policy);
354+ fd = open("/dev/null", O_RDONLY);
355+ check(policy, fd != EOF);
356+ close(fd);
357+ unset2(policy);
358+}
359+
360+static void test_file_write(void)
361+{
362+ int fd;
363+ char *policy;
364+
365+ policy = "100 acl write\n"
366+ "0 allow\n"
367+ "100 acl append\n"
368+ "0 deny\n";
369+ set(policy);
370+ fd = open("/dev/null", O_WRONLY);
371+ check(policy, fd != EOF);
372+ close(fd);
373+ unset2(policy);
374+
375+ policy = "100 acl write\n"
376+ "0 deny\n"
377+ "100 acl append\n"
378+ "0 allow\n";
379+ set(policy);
380+ fd = open("/dev/null", O_WRONLY);
381+ check(policy, fd == EOF);
382+ close(fd);
383+ unset2(policy);
384+
385+ policy = "100 acl write\n"
386+ "0 allow\n"
387+ "100 acl append\n"
388+ "0 deny\n";
389+ set(policy);
390+ fd = open("/dev/null", O_WRONLY | O_APPEND);
391+ check(policy, fd == EOF);
392+ close(fd);
393+ unset2(policy);
394+
395+ policy = "100 acl write\n"
396+ "0 deny\n"
397+ "100 acl append\n"
398+ "0 append\n";
399+ set(policy);
400+ fd = open("/dev/null", O_WRONLY | O_APPEND);
401+ check(policy, fd != EOF);
402+ close(fd);
403+ unset2(policy);
404+
405+ policy = "100 acl write\n"
406+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
407+ "1 deny\n";
408+ set(policy);
409+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
410+ check(policy, fd != EOF);
411+ close(fd);
412+ unset(policy);
413+
414+ policy = "100 acl write\n"
415+ "0 allow path.type=char path.dev_major=1"
416+ " path.dev_minor=@MINOR\n"
417+ "1 deny\n";
418+ set(policy);
419+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
420+ check(policy, fd == EOF);
421+ close(fd);
422+ unset(policy);
423+
424+ policy = "100 acl write\n"
425+ "0 allow path.parent.uid=0 path.parent.perm=0755\n"
426+ "1 deny\n";
427+ set(policy);
428+ fd = open("/dev/null", O_WRONLY);
429+ check(policy, fd != EOF);
430+ close(fd);
431+ unset(policy);
432+
433+ policy = "100 acl write\n"
434+ "0 allow path.parent.uid=task.uid path.parent.gid=task.gid\n"
435+ "1 deny\n";
436+ set(policy);
437+ fd = open("/dev/null", O_WRONLY);
438+ check(policy, fd != EOF);
439+ close(fd);
440+ unset(policy);
441+
442+ policy = "100 acl write\n"
443+ "0 allow task.uid=path.parent.uid task.gid=path.parent.gid\n"
444+ "1 deny\n";
445+ set(policy);
446+ fd = open("/dev/null", O_WRONLY);
447+ check(policy, fd != EOF);
448+ close(fd);
449+ unset(policy);
450+}
451+
452+static void test_file_create(void)
453+{
454+ int fd;
455+ char *policy;
456+
457+ policy = "100 acl create\n"
458+ "0 allow path.uid=0\n"
459+ "1 deny\n";
460+ set(policy);
461+ unlink("/tmp/file");
462+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
463+ check(policy, fd == EOF);
464+ close(fd);
465+ unset(policy);
466+
467+ policy = "100 acl create\n"
468+ "0 allow path=\"dev(¥$,¥$):/tmp/file\" path.parent.uid=0\n"
469+ "0 allow path=\"/tmp/file\" path.parent.uid=0\n"
470+ "0 allow path=\"dev(¥$,¥$):/file\" path.parent.uid=0\n"
471+ "1 deny\n";
472+ set(policy);
473+ unlink("/tmp/file");
474+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
475+ check(policy, fd != EOF);
476+ close(fd);
477+ unset(policy);
478+
479+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
480+ "100 acl create\n"
481+ "0 allow path.parent.uid!=@GROUP1 perm=0600\n"
482+ "1 deny\n";
483+ set(policy);
484+ unlink("/tmp/file");
485+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
486+ check(policy, fd != EOF);
487+ close(fd);
488+ unset2(policy);
489+
490+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
491+ "100 acl create\n"
492+ "0 allow path.parent.uid!=@GROUP1 perm!=0600\n"
493+ "1 deny\n";
494+ set(policy);
495+ unlink("/tmp/file");
496+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
497+ check(policy, fd == EOF);
498+ close(fd);
499+ unset2(policy);
500+
501+ policy = "100 acl create\n"
502+ "0 allow path.parent.uid=task.uid\n"
503+ "1 deny\n";
504+ set(policy);
505+ unlink("/tmp/file");
506+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
507+ check(policy, fd != EOF);
508+ close(fd);
509+ unset(policy);
510+}
511+
512+static void test_file_unlink(void)
513+{
514+ char *policy;
515+
516+ policy = "100 acl unlink\n"
517+ "0 allow path.uid=0 path.uid=path.parent.uid\n"
518+ "1 deny\n";
519+ set(policy);
520+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
521+ check(policy, unlink("/tmp/file") == 0);
522+ unset(policy);
523+
524+ policy = "100 acl unlink\n"
525+ "0 deny path.uid=0 path.uid=path.parent.uid\n"
526+ "1 allow\n";
527+ set(policy);
528+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
529+ check(policy, unlink("/tmp/file") == EOF);
530+ unset(policy);
531+}
532+
533+static void test_file_link(void)
534+{
535+ char *policy;
536+
537+ policy = "100 acl link\n"
538+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
539+ " old_path.parent.ino=new_path.parent.ino\n"
540+ "1 deny\n";
541+ set(policy);
542+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
543+ unlink("/tmp/file2");
544+ check(policy, link("/tmp/file", "/tmp/file2") == 0);
545+ unset(policy);
546+
547+ policy = "100 acl link\n"
548+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
549+ "1 allow\n";
550+ set(policy);
551+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
552+ unlink("/tmp/file2");
553+ check(policy, link("/tmp/file", "/tmp/file2") == EOF);
554+ unset(policy);
555+}
556+
557+static void test_file_rename(void)
558+{
559+ char *policy;
560+
561+ policy = "100 acl rename\n"
562+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
563+ " old_path.parent.ino=new_path.parent.ino\n"
564+ "1 deny\n";
565+ set(policy);
566+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
567+ unlink("/tmp/file2");
568+ check(policy, rename("/tmp/file", "/tmp/file2") == 0);
569+ unset(policy);
570+
571+ policy = "100 acl rename\n"
572+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
573+ "1 allow\n";
574+ set(policy);
575+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
576+ unlink("/tmp/file2");
577+ check(policy, rename("/tmp/file", "/tmp/file2") == EOF);
578+ unset(policy);
579+}
580+
581+static void test_network_inet_stream(void)
582+{
583+ struct sockaddr_in addr1 = { };
584+ struct sockaddr_in addr2 = { };
585+ socklen_t size = sizeof(addr1);
586+ int fd1;
587+ int fd2;
588+ int fd3;
589+ char *policy;
590+ char buffer[1024];
591+ memset(buffer, 0, sizeof(buffer));
592+
593+ fd1 = socket(PF_INET, SOCK_STREAM, 0);
594+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
595+ addr1.sin_family = AF_INET;
596+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
597+
598+ policy = "100 acl inet_stream_bind\n"
599+ "0 allow ip=127.0.0.1 port!=0\n"
600+ "1 deny\n";
601+ set(policy);
602+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
603+ EOF);
604+ unset(policy);
605+
606+ policy = "100 acl inet_stream_bind\n"
607+ "0 allow ip!=127.0.0.1 port=0\n"
608+ "1 deny\n";
609+ set(policy);
610+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
611+ EOF);
612+ unset(policy);
613+
614+ policy = "100 acl inet_stream_bind\n"
615+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
616+ "1 deny\n";
617+ set(policy);
618+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
619+ EOF);
620+ unset(policy);
621+
622+ policy = "100 acl inet_stream_bind\n"
623+ "0 allow ip=127.0.0.1 port=0\n"
624+ "1 deny\n";
625+ set(policy);
626+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
627+ 0);
628+ unset(policy);
629+
630+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
631+
632+ snprintf(buffer, sizeof(buffer) - 1,
633+ "100 acl inet_stream_listen\n"
634+ "0 allow ip=127.0.0.1 port!=%u\n"
635+ "1 deny\n", ntohs(addr1.sin_port));
636+ policy = buffer;
637+ set(policy);
638+ check(policy, listen(fd1, 5) == EOF);
639+ unset(policy);
640+
641+ snprintf(buffer, sizeof(buffer) - 1,
642+ "100 acl inet_stream_listen\n"
643+ "0 allow ip=127.0.0.1 port=%u\n"
644+ "1 deny\n", ntohs(addr1.sin_port));
645+ policy = buffer;
646+ set(policy);
647+ check(policy, listen(fd1, 5) == 0);
648+ unset(policy);
649+
650+ snprintf(buffer, sizeof(buffer) - 1,
651+ "100 acl inet_stream_connect\n"
652+ "0 allow ip=127.0.0.1 port!=%u\n"
653+ "1 deny\n", ntohs(addr1.sin_port));
654+ policy = buffer;
655+ set(policy);
656+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
657+ == EOF);
658+ unset(policy);
659+
660+ snprintf(buffer, sizeof(buffer) - 1,
661+ "100 acl inet_stream_connect\n"
662+ "0 allow ip=127.0.0.1 port=%u\n"
663+ "1 deny\n", ntohs(addr1.sin_port));
664+ policy = buffer;
665+ set(policy);
666+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
667+ == 0);
668+ unset(policy);
669+
670+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
671+
672+ snprintf(buffer, sizeof(buffer) - 1,
673+ "100 acl inet_stream_accept\n"
674+ "0 allow ip=127.0.0.1 port=%u\n"
675+ "1 deny\n", ntohs(addr2.sin_port));
676+ policy = buffer;
677+ set(policy);
678+ fd3 = accept(fd1, NULL, 0);
679+ check(policy, write(fd3, "", 1) == 1);
680+ close(fd3);
681+ unset(policy);
682+
683+ snprintf(buffer, sizeof(buffer) - 1,
684+ "100 acl inet_stream_connect\n"
685+ "0 allow ip=127.0.0.1 port=%u\n"
686+ "1 deny\n", ntohs(addr1.sin_port));
687+ policy = buffer;
688+ set(policy);
689+ close(fd2);
690+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
691+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
692+ == 0);
693+ unset(policy);
694+
695+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
696+
697+ snprintf(buffer, sizeof(buffer) - 1,
698+ "100 acl inet_stream_accept\n"
699+ "0 allow ip=127.0.0.1 port!=%u\n"
700+ "1 deny\n", ntohs(addr2.sin_port));
701+ policy = buffer;
702+ set(policy);
703+ fd3 = accept(fd1, NULL, 0);
704+ check(policy, write(fd3, "", 1) == EOF);
705+ close(fd3);
706+ unset(policy);
707+
708+ close(fd1);
709+ close(fd2);
710+}
711+
712+static void test_network_inet_dgram(void)
713+{
714+ struct sockaddr_in addr1 = { };
715+ struct sockaddr_in addr2 = { };
716+ socklen_t size = sizeof(addr1);
717+ int fd1;
718+ int fd2;
719+ char *policy;
720+ char buffer[1024];
721+ memset(buffer, 0, sizeof(buffer));
722+
723+ fd1 = socket(PF_INET, SOCK_DGRAM, 0);
724+ fd2 = socket(PF_INET, SOCK_DGRAM, 0);
725+ addr1.sin_family = AF_INET;
726+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
727+
728+ policy = "100 acl inet_dgram_bind\n"
729+ "0 allow ip=127.0.0.1 port!=0\n"
730+ "1 deny\n";
731+ set(policy);
732+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
733+ EOF);
734+ unset(policy);
735+
736+ policy = "100 acl inet_dgram_bind\n"
737+ "0 allow ip!=127.0.0.1 port=0\n"
738+ "1 deny\n";
739+ set(policy);
740+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
741+ EOF);
742+ unset(policy);
743+
744+ policy = "100 acl inet_dgram_bind\n"
745+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
746+ "1 deny\n";
747+ set(policy);
748+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
749+ EOF);
750+ unset(policy);
751+
752+ policy = "100 acl inet_dgram_bind\n"
753+ "0 allow ip=127.0.0.1 port=0\n"
754+ "1 deny\n";
755+ set(policy);
756+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
757+ 0);
758+ unset(policy);
759+
760+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
761+
762+ snprintf(buffer, sizeof(buffer) - 1,
763+ "100 acl inet_dgram_send\n"
764+ "0 allow ip=127.0.0.1 port!=%u\n"
765+ "1 deny\n", ntohs(addr1.sin_port));
766+ policy = buffer;
767+ set(policy);
768+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
769+ == EOF);
770+ unset(policy);
771+
772+ snprintf(buffer, sizeof(buffer) - 1,
773+ "100 acl inet_dgram_send\n"
774+ "0 allow ip=127.0.0.1 port=%u\n"
775+ "1 deny\n", ntohs(addr1.sin_port));
776+ policy = buffer;
777+ set(policy);
778+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
779+ == 0);
780+ unset(policy);
781+
782+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
783+
784+ snprintf(buffer, sizeof(buffer) - 1,
785+ "100 acl inet_dgram_send\n"
786+ "0 allow ip=127.0.0.1 port=%u\n"
787+ "1 deny\n", ntohs(addr1.sin_port));
788+ policy = buffer;
789+ set(policy);
790+ check(policy, send(fd2, "", 1, 0) != EOF);
791+ unset(policy);
792+
793+ snprintf(buffer, sizeof(buffer) - 1,
794+ "100 acl inet_dgram_send\n"
795+ "0 allow ip=127.0.0.1 port=%u\n"
796+ "1 deny\n", ntohs(addr1.sin_port));
797+ policy = buffer;
798+ set(policy);
799+ check(policy, send(fd2, "", 1, 0) != EOF);
800+ unset(policy);
801+
802+ snprintf(buffer, sizeof(buffer) - 1,
803+ "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
804+ "100 acl inet_dgram_send\n"
805+ "0 allow ip=@LOCALHOST port=%u\n"
806+ "1 deny\n", ntohs(addr1.sin_port));
807+ policy = buffer;
808+ set(policy);
809+ check(policy, send(fd2, "", 1, 0) != EOF);
810+ unset2(policy);
811+
812+ close(fd1);
813+ close(fd2);
814+}
815+
816+static void test_network_inet_raw(void)
817+{
818+ struct sockaddr_in addr = { };
819+ static struct iphdr ip = { };
820+ int fd1;
821+ int fd2;
822+ char *policy;
823+ fd1 = socket(PF_INET, SOCK_RAW, 1);
824+ fd2 = socket(PF_INET, SOCK_RAW, 1);
825+ addr.sin_family = AF_INET;
826+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
827+ ip.version = 4;
828+ ip.ihl = sizeof(struct iphdr) / 4;
829+ ip.protocol = IPPROTO_RAW;
830+ ip.daddr = htonl(INADDR_LOOPBACK);
831+ ip.saddr = ip.daddr;
832+
833+ policy = "100 acl inet_raw_bind\n"
834+ "0 allow ip=127.0.0.1 proto!=1\n"
835+ "1 deny\n";
836+ set(policy);
837+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
838+ EOF);
839+ unset(policy);
840+
841+ policy = "100 acl inet_raw_bind\n"
842+ "0 allow ip!=127.0.0.1 proto=1\n"
843+ "1 deny\n";
844+ set(policy);
845+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
846+ EOF);
847+ unset(policy);
848+
849+ policy = "100 acl inet_raw_bind\n"
850+ "0 allow ip=127.0.0.1 proto=1 path.uid=task.uid\n"
851+ "1 deny\n";
852+ set(policy);
853+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
854+ EOF);
855+ unset(policy);
856+
857+ policy = "100 acl inet_raw_bind\n"
858+ "0 allow ip=127.0.0.1 proto=1\n"
859+ "1 deny\n";
860+ set(policy);
861+ check(policy, bind(fd2, (struct sockaddr *) &addr, sizeof(addr)) ==
862+ 0);
863+ unset(policy);
864+
865+ policy = "100 acl inet_raw_send\n"
866+ "0 allow ip=127.0.0.1 proto!=1\n"
867+ "1 deny\n";
868+ set(policy);
869+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
870+ == EOF);
871+ unset(policy);
872+
873+ policy = "100 acl inet_raw_send\n"
874+ "0 allow ip=127.0.0.1 proto=1\n"
875+ "1 deny\n";
876+ set(policy);
877+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
878+ == 0);
879+ unset(policy);
880+
881+ policy = "100 acl inet_raw_send\n"
882+ "0 allow ip=127.0.0.1 proto=1\n"
883+ "1 deny\n";
884+ set(policy);
885+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
886+ unset(policy);
887+
888+ policy = "100 acl inet_raw_send\n"
889+ "0 allow ip=127.0.0.1 proto=1\n"
890+ "1 deny\n";
891+ set(policy);
892+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
893+ unset(policy);
894+
895+ policy = "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
896+ "100 acl inet_raw_send\n"
897+ "0 allow ip=@LOCALHOST proto=1\n"
898+ "1 deny\n";
899+ set(policy);
900+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
901+ unset2(policy);
902+
903+ close(fd1);
904+ close(fd2);
905+}
906+
907+static void test_network_inet6_stream(void)
908+{
909+ struct sockaddr_in6 addr1 = { };
910+ struct sockaddr_in6 addr2 = { };
911+ socklen_t size = sizeof(addr1);
912+ int fd1;
913+ int fd2;
914+ int fd3;
915+ char *policy;
916+ char buffer[1024];
917+ memset(buffer, 0, sizeof(buffer));
918+
919+ fd1 = socket(PF_INET6, SOCK_STREAM, 0);
920+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
921+ addr1.sin6_family = AF_INET6;
922+ addr1.sin6_addr = in6addr_loopback;
923+
924+ policy = "100 acl inet_stream_bind\n"
925+ "0 allow ip=::1 port!=0\n"
926+ "1 deny\n";
927+ set(policy);
928+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
929+ EOF);
930+ unset(policy);
931+
932+ policy = "100 acl inet_stream_bind\n"
933+ "0 allow ip!=::1 port=0\n"
934+ "1 deny\n";
935+ set(policy);
936+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
937+ EOF);
938+ unset(policy);
939+
940+ policy = "100 acl inet_stream_bind\n"
941+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
942+ "1 deny\n";
943+ set(policy);
944+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
945+ EOF);
946+ unset(policy);
947+
948+ policy = "100 acl inet_stream_bind\n"
949+ "0 allow ip=::1 port=0\n"
950+ "1 deny\n";
951+ set(policy);
952+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
953+ 0);
954+ unset(policy);
955+
956+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
957+
958+ snprintf(buffer, sizeof(buffer) - 1,
959+ "100 acl inet_stream_listen\n"
960+ "0 allow ip=::1 port!=%u\n"
961+ "1 deny\n", ntohs(addr1.sin6_port));
962+ policy = buffer;
963+ set(policy);
964+ check(policy, listen(fd1, 5) == EOF);
965+ unset(policy);
966+
967+ snprintf(buffer, sizeof(buffer) - 1,
968+ "100 acl inet_stream_listen\n"
969+ "0 allow ip=::1 port=%u\n"
970+ "1 deny\n", ntohs(addr1.sin6_port));
971+ policy = buffer;
972+ set(policy);
973+ check(policy, listen(fd1, 5) == 0);
974+ unset(policy);
975+
976+ snprintf(buffer, sizeof(buffer) - 1,
977+ "100 acl inet_stream_connect\n"
978+ "0 allow ip=::1 port!=%u\n"
979+ "1 deny\n", ntohs(addr1.sin6_port));
980+ policy = buffer;
981+ set(policy);
982+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
983+ == EOF);
984+ unset(policy);
985+
986+ snprintf(buffer, sizeof(buffer) - 1,
987+ "100 acl inet_stream_connect\n"
988+ "0 allow ip=::1 port=%u\n"
989+ "1 deny\n", ntohs(addr1.sin6_port));
990+ policy = buffer;
991+ set(policy);
992+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
993+ == 0);
994+ unset(policy);
995+
996+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
997+
998+ snprintf(buffer, sizeof(buffer) - 1,
999+ "100 acl inet_stream_accept\n"
1000+ "0 allow ip=::1 port=%u\n"
1001+ "1 deny\n", ntohs(addr2.sin6_port));
1002+ policy = buffer;
1003+ set(policy);
1004+ fd3 = accept(fd1, NULL, 0);
1005+ check(policy, write(fd3, "", 1) == 1);
1006+ close(fd3);
1007+ unset(policy);
1008+
1009+ snprintf(buffer, sizeof(buffer) - 1,
1010+ "100 acl inet_stream_connect\n"
1011+ "0 allow ip=::1 port=%u\n"
1012+ "1 deny\n", ntohs(addr1.sin6_port));
1013+ policy = buffer;
1014+ set(policy);
1015+ close(fd2);
1016+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
1017+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1018+ == 0);
1019+ unset(policy);
1020+
1021+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1022+
1023+ snprintf(buffer, sizeof(buffer) - 1,
1024+ "100 acl inet_stream_accept\n"
1025+ "0 allow ip=::1 port!=%u\n"
1026+ "1 deny\n", ntohs(addr2.sin6_port));
1027+ policy = buffer;
1028+ set(policy);
1029+ fd3 = accept(fd1, NULL, 0);
1030+ check(policy, write(fd3, "", 1) == EOF);
1031+ close(fd3);
1032+ unset(policy);
1033+
1034+ close(fd1);
1035+ close(fd2);
1036+}
1037+
1038+static void test_network_inet6_dgram(void)
1039+{
1040+ struct sockaddr_in6 addr1 = { };
1041+ struct sockaddr_in6 addr2 = { };
1042+ socklen_t size = sizeof(addr1);
1043+ int fd1;
1044+ int fd2;
1045+ char *policy;
1046+ char buffer[1024];
1047+ memset(buffer, 0, sizeof(buffer));
1048+
1049+ fd1 = socket(PF_INET6, SOCK_DGRAM, 0);
1050+ fd2 = socket(PF_INET6, SOCK_DGRAM, 0);
1051+ addr1.sin6_family = AF_INET6;
1052+ addr1.sin6_addr = in6addr_loopback;
1053+
1054+ policy = "100 acl inet_dgram_bind\n"
1055+ "0 allow ip=::1 port!=0\n"
1056+ "1 deny\n";
1057+ set(policy);
1058+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1059+ EOF);
1060+ unset(policy);
1061+
1062+ policy = "100 acl inet_dgram_bind\n"
1063+ "0 allow ip!=::1 port=0\n"
1064+ "1 deny\n";
1065+ set(policy);
1066+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1067+ EOF);
1068+ unset(policy);
1069+
1070+ policy = "100 acl inet_dgram_bind\n"
1071+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
1072+ "1 deny\n";
1073+ set(policy);
1074+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1075+ EOF);
1076+ unset(policy);
1077+
1078+ policy = "100 acl inet_dgram_bind\n"
1079+ "0 allow ip=::1 port=0\n"
1080+ "1 deny\n";
1081+ set(policy);
1082+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1083+ 0);
1084+ unset(policy);
1085+
1086+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
1087+
1088+ snprintf(buffer, sizeof(buffer) - 1,
1089+ "100 acl inet_dgram_send\n"
1090+ "0 allow ip=::1 port!=%u\n"
1091+ "1 deny\n", ntohs(addr1.sin6_port));
1092+ policy = buffer;
1093+ set(policy);
1094+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1095+ == EOF);
1096+ unset(policy);
1097+
1098+ snprintf(buffer, sizeof(buffer) - 1,
1099+ "100 acl inet_dgram_send\n"
1100+ "0 allow ip=::1 port=%u\n"
1101+ "1 deny\n", ntohs(addr1.sin6_port));
1102+ policy = buffer;
1103+ set(policy);
1104+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1105+ == 0);
1106+ unset(policy);
1107+
1108+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1109+
1110+ snprintf(buffer, sizeof(buffer) - 1,
1111+ "100 acl inet_dgram_send\n"
1112+ "0 allow ip=::1 port=%u\n"
1113+ "1 deny\n", ntohs(addr1.sin6_port));
1114+ policy = buffer;
1115+ set(policy);
1116+ check(policy, send(fd2, "", 1, 0) != EOF);
1117+ unset(policy);
1118+
1119+ snprintf(buffer, sizeof(buffer) - 1,
1120+ "100 acl inet_dgram_send\n"
1121+ "0 allow ip=::1 port=%u\n"
1122+ "1 deny\n", ntohs(addr1.sin6_port));
1123+ policy = buffer;
1124+ set(policy);
1125+ check(policy, send(fd2, "", 1, 0) != EOF);
1126+ unset(policy);
1127+
1128+ snprintf(buffer, sizeof(buffer) - 1,
1129+ "ip_group LOCALHOST ::-::ffff\n"
1130+ "100 acl inet_dgram_send\n"
1131+ "0 allow ip=@LOCALHOST port=%u\n"
1132+ "1 deny\n", ntohs(addr1.sin6_port));
1133+ policy = buffer;
1134+ set(policy);
1135+ check(policy, send(fd2, "", 1, 0) != EOF);
1136+ unset2(policy);
1137+
1138+ close(fd1);
1139+ close(fd2);
1140+}
1141+
1142+static int fork_exec(char *envp[])
1143+{
1144+ int ret_ignored;
1145+ int pipe_fd[2] = { EOF, EOF };
1146+ int err = 0;
1147+ pid_t pid;
1148+ if (pipe(pipe_fd)) {
1149+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1150+ exit(1);
1151+ }
1152+ pid = fork();
1153+ if (pid == 0) {
1154+ char *argv[2] = { BINDIR "/true", NULL };
1155+ execve(BINDIR "/true", argv, envp);
1156+ err = errno;
1157+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1158+ _exit(0);
1159+ }
1160+ close(pipe_fd[1]);
1161+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1162+ close(pipe_fd[0]);
1163+ wait(NULL);
1164+ errno = err;
1165+ return err ? EOF : 0;
1166+}
1167+
1168+static void test_environ(void)
1169+{
1170+ char *policy;
1171+ char *envp[2];
1172+ envp[1] = NULL;
1173+
1174+ policy = "100 acl environ name=\"PATH2\"\n"
1175+ "0 allow value=\"/\"\n"
1176+ "1 deny\n";
1177+ set(policy);
1178+ envp[0] = "PATH2=/";
1179+ check(policy, fork_exec(envp) == 0);
1180+ unset(policy);
1181+
1182+ policy = "100 acl environ name=\"PATH2\"\n"
1183+ "0 allow value!=\"/\"\n"
1184+ "1 deny\n";
1185+ set(policy);
1186+ envp[0] = "PATH2=/";
1187+ check(policy, fork_exec(envp) == EOF);
1188+ unset(policy);
1189+
1190+ policy = "100 acl environ name=\"PATH2\"\n"
1191+ "0 deny value!=\"/\"\n"
1192+ "1 allow\n";
1193+ set(policy);
1194+ envp[0] = "PATH2=/";
1195+ check(policy, fork_exec(envp) == 0);
1196+ unset(policy);
1197+
1198+ policy = "100 acl environ name=\"PATH2\"\n"
1199+ "0 deny value=\"/\"\n"
1200+ "1 allow\n";
1201+ set(policy);
1202+ envp[0] = "PATH2=/";
1203+ check(policy, fork_exec(envp) == EOF);
1204+ unset(policy);
1205+
1206+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1207+ "0 allow envp[\"PATH2\"]=\"/\"\n"
1208+ "1 deny\n";
1209+ set(policy);
1210+ envp[0] = "PATH2=/";
1211+ check(policy, fork_exec(envp) == 0);
1212+ unset(policy);
1213+
1214+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1215+ "0 allow envp[\"PATH2\"]!=\"/\"\n"
1216+ "1 deny\n";
1217+ set(policy);
1218+ envp[0] = "PATH2=/";
1219+ check(policy, fork_exec(envp) == EOF);
1220+ unset(policy);
1221+
1222+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1223+ "0 allow envp[\"PATH2\"]!=NULL\n"
1224+ "1 deny\n";
1225+ set(policy);
1226+ envp[0] = "PATH2";
1227+ check(policy, fork_exec(envp) == 0);
1228+ unset(policy);
1229+
1230+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1231+ "0 allow envp[\"PATH2\"]!=NULL\n"
1232+ "1 deny\n";
1233+ set(policy);
1234+ envp[0] = "PATH2=";
1235+ check(policy, fork_exec(envp) == 0);
1236+ unset(policy);
1237+
1238+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1239+ "0 allow envp[\"PATH2\"]!=NULL\n"
1240+ "1 deny\n";
1241+ set(policy);
1242+ envp[0] = "PATH2=/";
1243+ check(policy, fork_exec(envp) == 0);
1244+ unset(policy);
1245+
1246+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1247+ "0 allow envp[\"PATH2\"]=NULL\n"
1248+ "1 deny\n";
1249+ set(policy);
1250+ envp[0] = "PATH2";
1251+ check(policy, fork_exec(envp) == EOF);
1252+ unset(policy);
1253+
1254+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1255+ "0 allow envp[\"PATH2\"]=NULL\n"
1256+ "1 deny\n";
1257+ set(policy);
1258+ envp[0] = "PATH2=";
1259+ check(policy, fork_exec(envp) == EOF);
1260+ unset(policy);
1261+
1262+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1263+ "0 allow envp[\"PATH2\"]=NULL\n"
1264+ "1 deny\n";
1265+ set(policy);
1266+ envp[0] = "PATH2=/";
1267+ check(policy, fork_exec(envp) == EOF);
1268+ unset(policy);
1269+
1270+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1271+ "0 allow envp[\"\"]=NULL\n"
1272+ "1 deny\n";
1273+ set(policy);
1274+ envp[0] = "";
1275+ check(policy, fork_exec(envp) == EOF);
1276+ unset(policy);
1277+
1278+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1279+ "0 allow envp[\"\"]!=NULL\n"
1280+ "1 deny\n";
1281+ set(policy);
1282+ envp[0] = "";
1283+ check(policy, fork_exec(envp) == 0);
1284+ unset(policy);
1285+
1286+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1287+ "0 allow envp[\"\"]!=NULL\n"
1288+ "1 deny\n";
1289+ set(policy);
1290+ envp[0] = "=";
1291+ check(policy, fork_exec(envp) == 0);
1292+ unset(policy);
1293+
1294+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1295+ "0 allow envp[\"\"]!=NULL\n"
1296+ "1 deny\n";
1297+ set(policy);
1298+ envp[0] = "=/";
1299+ check(policy, fork_exec(envp) == 0);
1300+ unset(policy);
1301+}
1302+
1303+static int fork_exec2(char *argv[], char *envp[])
1304+{
1305+ int ret_ignored;
1306+ int pipe_fd[2] = { EOF, EOF };
1307+ int err = 0;
1308+ pid_t pid;
1309+ if (pipe(pipe_fd)) {
1310+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1311+ exit(1);
1312+ }
1313+ pid = fork();
1314+ if (pid == 0) {
1315+ execve(BINDIR "/true", argv, envp);
1316+ err = errno;
1317+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1318+ _exit(0);
1319+ }
1320+ close(pipe_fd[1]);
1321+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1322+ close(pipe_fd[0]);
1323+ wait(NULL);
1324+ errno = err;
1325+ return err ? EOF : 0;
1326+}
1327+
1328+static void test_file_execute(void)
1329+{
1330+ char *policy;
1331+ char *argv[5];
1332+ char *envp[5];
1333+ memset(argv, 0, sizeof(argv));
1334+ memset(envp, 0, sizeof(envp));
1335+
1336+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1337+ "0 allow argc=1\n"
1338+ "1 deny\n";
1339+ set(policy);
1340+ argv[0]="true";
1341+ check(policy, fork_exec2(argv, envp) == 0);
1342+ unset(policy);
1343+
1344+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1345+ "0 allow argc!=1\n"
1346+ "1 deny\n";
1347+ set(policy);
1348+ check(policy, fork_exec2(argv, envp) == EOF);
1349+ unset(policy);
1350+
1351+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1352+ "0 deny argc!=1\n"
1353+ "1 allow\n";
1354+ set(policy);
1355+ check(policy, fork_exec2(argv, envp) == 0);
1356+ unset(policy);
1357+
1358+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1359+ "0 deny argc=1\n"
1360+ "1 allow\n";
1361+ set(policy);
1362+ check(policy, fork_exec2(argv, envp) == EOF);
1363+ unset(policy);
1364+
1365+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1366+ "0 deny argv[0]!=\"true\"\n"
1367+ "1 allow\n";
1368+ set(policy);
1369+ check(policy, fork_exec2(argv, envp) == 0);
1370+ unset(policy);
1371+
1372+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1373+ "0 deny argv[0]=\"true\"\n"
1374+ "1 allow\n";
1375+ set(policy);
1376+ check(policy, fork_exec2(argv, envp) == EOF);
1377+ unset(policy);
1378+
1379+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1380+ "0 allow argv[0]!=\"true\"\n"
1381+ "1 deny\n";
1382+ set(policy);
1383+ check(policy, fork_exec2(argv, envp) == EOF);
1384+ unset(policy);
1385+
1386+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1387+ "0 allow argv[0]=\"true\"\n"
1388+ "1 deny\n";
1389+ set(policy);
1390+ check(policy, fork_exec2(argv, envp) == 0);
1391+ unset(policy);
1392+
1393+ policy = "string_group EXEC_ARGV0 false\n"
1394+ "string_group EXEC_ARGV0 true\n"
1395+ "100 acl execute path=\"" BINDIR "/true\"\n"
1396+ "0 deny argv[0]!=@EXEC_ARGV0\n"
1397+ "1 allow\n";
1398+ set(policy);
1399+ check(policy, fork_exec2(argv, envp) == 0);
1400+ unset2(policy);
1401+
1402+ policy = "string_group EXEC_ARGV0 false\n"
1403+ "string_group EXEC_ARGV0 true\n"
1404+ "100 acl execute path=\"" BINDIR "/true\"\n"
1405+ "0 deny argv[0]=@EXEC_ARGV0\n"
1406+ "1 allow\n";
1407+ set(policy);
1408+ check(policy, fork_exec2(argv, envp) == EOF);
1409+ unset2(policy);
1410+
1411+ policy = "string_group EXEC_ARGV0 false\n"
1412+ "string_group EXEC_ARGV0 true\n"
1413+ "100 acl execute path=\"" BINDIR "/true\"\n"
1414+ "0 allow argv[0]!=@EXEC_ARGV0\n"
1415+ "1 deny\n";
1416+ set(policy);
1417+ check(policy, fork_exec2(argv, envp) == EOF);
1418+ unset2(policy);
1419+
1420+ policy = "string_group EXEC_ARGV0 false\n"
1421+ "string_group EXEC_ARGV0 true\n"
1422+ "100 acl execute path=\"" BINDIR "/true\"\n"
1423+ "0 allow argv[0]=@EXEC_ARGV0\n"
1424+ "1 deny\n";
1425+ set(policy);
1426+ check(policy, fork_exec2(argv, envp) == 0);
1427+ unset2(policy);
1428+
1429+
1430+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1431+ "0 allow envc=1\n"
1432+ "1 deny\n";
1433+ set(policy);
1434+ envp[0]="PATH=/";
1435+ check(policy, fork_exec2(argv, envp) == 0);
1436+ unset(policy);
1437+
1438+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1439+ "0 allow envc!=1\n"
1440+ "1 deny\n";
1441+ set(policy);
1442+ check(policy, fork_exec2(argv, envp) == EOF);
1443+ unset(policy);
1444+
1445+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1446+ "0 deny envc!=1\n"
1447+ "1 allow\n";
1448+ set(policy);
1449+ check(policy, fork_exec2(argv, envp) == 0);
1450+ unset(policy);
1451+
1452+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1453+ "0 deny envc=1\n"
1454+ "1 allow\n";
1455+ set(policy);
1456+ check(policy, fork_exec2(argv, envp) == EOF);
1457+ unset(policy);
1458+
1459+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1460+ "0 deny envp[\"PATH\"]!=\"/\"\n"
1461+ "1 allow\n";
1462+ set(policy);
1463+ check(policy, fork_exec2(argv, envp) == 0);
1464+ unset(policy);
1465+
1466+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1467+ "0 deny envp[\"PATH\"]=\"/\"\n"
1468+ "1 allow\n";
1469+ set(policy);
1470+ check(policy, fork_exec2(argv, envp) == EOF);
1471+ unset(policy);
1472+
1473+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1474+ "0 allow envp[\"PATH\"]!=\"/\"\n"
1475+ "1 deny\n";
1476+ set(policy);
1477+ check(policy, fork_exec2(argv, envp) == EOF);
1478+ unset(policy);
1479+
1480+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1481+ "0 allow envp[\"PATH\"]=\"/\"\n"
1482+ "1 deny\n";
1483+ set(policy);
1484+ check(policy, fork_exec2(argv, envp) == 0);
1485+ unset(policy);
1486+
1487+ policy = "string_group PATH_VALUES " BINDIR "\n"
1488+ "string_group PATH_VALUES /\n"
1489+ "string_group PATH_VALUES /sbin\n"
1490+ "100 acl execute path=\"" BINDIR "/true\"\n"
1491+ "0 deny envp[\"PATH\"]!=@PATH_VALUES\n"
1492+ "1 allow\n";
1493+ set(policy);
1494+ check(policy, fork_exec2(argv, envp) == 0);
1495+ unset2(policy);
1496+
1497+ policy = "string_group PATH_VALUES " BINDIR "\n"
1498+ "string_group PATH_VALUES /\n"
1499+ "string_group PATH_VALUES /sbin\n"
1500+ "100 acl execute path=\"" BINDIR "/true\"\n"
1501+ "0 deny envp[\"PATH\"]=@PATH_VALUES\n"
1502+ "1 allow\n";
1503+ set(policy);
1504+ check(policy, fork_exec2(argv, envp) == EOF);
1505+ unset2(policy);
1506+
1507+ policy = "string_group PATH_VALUES " BINDIR "\n"
1508+ "string_group PATH_VALUES /\n"
1509+ "string_group PATH_VALUES /sbin\n"
1510+ "100 acl execute path=\"" BINDIR "/true\"\n"
1511+ "0 allow envp[\"PATH\"]!=@PATH_VALUES\n"
1512+ "1 deny\n";
1513+ set(policy);
1514+ check(policy, fork_exec2(argv, envp) == EOF);
1515+ unset2(policy);
1516+
1517+ policy = "string_group PATH_VALUES " BINDIR "\n"
1518+ "string_group PATH_VALUES /\n"
1519+ "string_group PATH_VALUES /sbin\n"
1520+ "100 acl execute path=\"" BINDIR "/true\"\n"
1521+ "0 allow envp[\"PATH\"]=@PATH_VALUES\n"
1522+ "1 deny\n";
1523+ set(policy);
1524+ check(policy, fork_exec2(argv, envp) == 0);
1525+ unset2(policy);
1526+
1527+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1528+ "0 deny envp[\"PATH\"]!=NULL\n"
1529+ "1 allow\n";
1530+ set(policy);
1531+ check(policy, fork_exec2(argv, envp) == EOF);
1532+ unset(policy);
1533+
1534+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1535+ "0 deny envp[\"PATH\"]=NULL\n"
1536+ "1 allow\n";
1537+ set(policy);
1538+ check(policy, fork_exec2(argv, envp) == 0);
1539+ unset(policy);
1540+
1541+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1542+ "0 allow envp[\"PATH\"]!=NULL\n"
1543+ "1 deny\n";
1544+ set(policy);
1545+ check(policy, fork_exec2(argv, envp) == 0);
1546+ unset(policy);
1547+
1548+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1549+ "0 allow envp[\"PATH\"]=NULL\n"
1550+ "1 deny\n";
1551+ set(policy);
1552+ check(policy, fork_exec2(argv, envp) == EOF);
1553+ unset(policy);
1554+}
1555+
1556+static void test_file_misc(void)
1557+{
1558+ int fd;
1559+ const pid_t pid = getpid();
1560+ char buffer[1024];
1561+ memset(buffer, 0, sizeof(buffer));
1562+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1563+ "10 allow path!=NULL\n"
1564+ "20 deny\n", pid);
1565+ set(buffer);
1566+ fd = open("/dev/null", O_RDONLY);
1567+ check(buffer, fd != EOF);
1568+ close(fd);
1569+ unset(buffer);
1570+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1571+ "10 allow path=NULL\n"
1572+ "20 deny\n", pid);
1573+ set(buffer);
1574+ fd = open("/dev/null", O_RDONLY);
1575+ check(buffer, fd == EOF);
1576+ close(fd);
1577+ unset(buffer);
1578+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1579+ "10 deny path=NULL\n"
1580+ "20 allow\n", pid);
1581+ set(buffer);
1582+ fd = open("/dev/null", O_RDONLY);
1583+ check(buffer, fd != EOF);
1584+ close(fd);
1585+ unset(buffer);
1586+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1587+ "10 deny path!=NULL\n"
1588+ "20 allow\n", pid);
1589+ set(buffer);
1590+ fd = open("/dev/null", O_RDONLY);
1591+ check(buffer, fd == EOF);
1592+ close(fd);
1593+ unset(buffer);
1594+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1595+ "10 allow path=path\n"
1596+ "20 deny\n", pid);
1597+ set(buffer);
1598+ fd = open("/dev/null", O_RDONLY);
1599+ check(buffer, fd != EOF);
1600+ close(fd);
1601+ unset(buffer);
1602+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1603+ "10 allow path!=path\n"
1604+ "20 deny\n", pid);
1605+ set(buffer);
1606+ fd = open("/dev/null", O_RDONLY);
1607+ check(buffer, fd == EOF);
1608+ close(fd);
1609+ unset(buffer);
1610+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1611+ "10 deny path!=path\n"
1612+ "20 allow\n", pid);
1613+ set(buffer);
1614+ fd = open("/dev/null", O_RDONLY);
1615+ check(buffer, fd != EOF);
1616+ close(fd);
1617+ unset(buffer);
1618+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1619+ "10 deny path=path\n"
1620+ "20 allow\n", pid);
1621+ set(buffer);
1622+ fd = open("/dev/null", O_RDONLY);
1623+ check(buffer, fd == EOF);
1624+ close(fd);
1625+ unset(buffer);
1626+ snprintf(buffer, sizeof(buffer) - 1,
1627+ "string_group STRING_GROUP1 /dev/null\n"
1628+ "100 acl read task.pid=%u\n"
1629+ "10 allow path=@STRING_GROUP1\n"
1630+ "20 deny\n", pid);
1631+ set(buffer);
1632+ fd = open("/dev/null", O_RDONLY);
1633+ check(buffer, fd != EOF);
1634+ close(fd);
1635+ unset2(buffer);
1636+ snprintf(buffer, sizeof(buffer) - 1,
1637+ "string_group STRING_GROUP1 /dev/null\n"
1638+ "100 acl read task.pid=%u\n"
1639+ "10 allow path!=@STRING_GROUP1\n"
1640+ "20 deny\n", pid);
1641+ set(buffer);
1642+ fd = open("/dev/null", O_RDONLY);
1643+ check(buffer, fd == EOF);
1644+ close(fd);
1645+ unset2(buffer);
1646+ snprintf(buffer, sizeof(buffer) - 1,
1647+ "string_group STRING_GROUP1 /dev/null\n"
1648+ "100 acl read task.pid=%u\n"
1649+ "10 deny path!=@STRING_GROUP1\n"
1650+ "20 allow\n", pid);
1651+ set(buffer);
1652+ fd = open("/dev/null", O_RDONLY);
1653+ check(buffer, fd != EOF);
1654+ close(fd);
1655+ unset2(buffer);
1656+ snprintf(buffer, sizeof(buffer) - 1,
1657+ "string_group STRING_GROUP1 /dev/null\n"
1658+ "100 acl read task.pid=%u\n"
1659+ "10 deny path=@STRING_GROUP1\n"
1660+ "20 allow\n", pid);
1661+ set(buffer);
1662+ fd = open("/dev/null", O_RDONLY);
1663+ check(buffer, fd == EOF);
1664+ close(fd);
1665+ unset2(buffer);
1666+ snprintf(buffer, sizeof(buffer) - 1,
1667+ "number_group NUMBER_GROUP1 0666\n"
1668+ "100 acl read task.pid=%u\n"
1669+ "10 deny path.perm!=@NUMBER_GROUP1\n"
1670+ "20 allow\n", pid);
1671+ set(buffer);
1672+ fd = open("/dev/null", O_RDONLY);
1673+ check(buffer, fd != EOF);
1674+ close(fd);
1675+ unset2(buffer);
1676+ snprintf(buffer, sizeof(buffer) - 1,
1677+ "number_group NUMBER_GROUP1 0666\n"
1678+ "100 acl read task.pid=%u\n"
1679+ "10 deny path.perm=@NUMBER_GROUP1\n"
1680+ "20 allow\n", pid);
1681+ set(buffer);
1682+ fd = open("/dev/null", O_RDONLY);
1683+ check(buffer, fd == EOF);
1684+ close(fd);
1685+ unset2(buffer);
1686+ snprintf(buffer, sizeof(buffer) - 1,
1687+ "100 acl read task.pid=%u\n"
1688+ "10 deny path.perm!=owner_read\n"
1689+ "20 allow\n", pid);
1690+ set(buffer);
1691+ fd = open("/dev/null", O_RDONLY);
1692+ check(buffer, fd != EOF);
1693+ close(fd);
1694+ unset2(buffer);
1695+ snprintf(buffer, sizeof(buffer) - 1,
1696+ "100 acl read task.pid=%u\n"
1697+ "10 deny path.perm=owner_read\n"
1698+ "20 allow\n", pid);
1699+ set(buffer);
1700+ fd = open("/dev/null", O_RDONLY);
1701+ check(buffer, fd == EOF);
1702+ close(fd);
1703+ unset2(buffer);
1704+ snprintf(buffer, sizeof(buffer) - 1,
1705+ "100 acl read task.pid=%u\n"
1706+ "10 deny path.perm!=group_write\n"
1707+ "20 allow\n", pid);
1708+ set(buffer);
1709+ fd = open("/dev/null", O_RDONLY);
1710+ check(buffer, fd != EOF);
1711+ close(fd);
1712+ unset2(buffer);
1713+ snprintf(buffer, sizeof(buffer) - 1,
1714+ "100 acl read task.pid=%u\n"
1715+ "10 deny path.perm=group_write\n"
1716+ "20 allow\n", pid);
1717+ set(buffer);
1718+ fd = open("/dev/null", O_RDONLY);
1719+ check(buffer, fd == EOF);
1720+ close(fd);
1721+ unset2(buffer);
1722+ snprintf(buffer, sizeof(buffer) - 1,
1723+ "100 acl read task.pid=%u\n"
1724+ "10 deny path.perm!=others_read\n"
1725+ "20 allow\n", pid);
1726+ set(buffer);
1727+ fd = open("/dev/null", O_RDONLY);
1728+ check(buffer, fd != EOF);
1729+ close(fd);
1730+ unset2(buffer);
1731+ snprintf(buffer, sizeof(buffer) - 1,
1732+ "100 acl read task.pid=%u\n"
1733+ "10 deny path.perm=others_read\n"
1734+ "20 allow\n", pid);
1735+ set(buffer);
1736+ fd = open("/dev/null", O_RDONLY);
1737+ check(buffer, fd == EOF);
1738+ close(fd);
1739+ unset2(buffer);
1740+ snprintf(buffer, sizeof(buffer) - 1,
1741+ "100 acl read task.pid=%u\n"
1742+ "10 deny path.perm=path.parent.perm\n"
1743+ "20 allow\n", pid);
1744+ set(buffer);
1745+ fd = open("/dev/null", O_RDONLY);
1746+ check(buffer, fd != EOF);
1747+ close(fd);
1748+ unset2(buffer);
1749+ snprintf(buffer, sizeof(buffer) - 1,
1750+ "100 acl read task.pid=%u\n"
1751+ "10 deny path.perm!=path.parent.perm\n"
1752+ "20 allow\n", pid);
1753+ set(buffer);
1754+ fd = open("/dev/null", O_RDONLY);
1755+ check(buffer, fd == EOF);
1756+ close(fd);
1757+ unset2(buffer);
1758+ snprintf(buffer, sizeof(buffer) - 1,
1759+ "100 acl execute task.ppid=%u\n"
1760+ "10 allow path=exec\n"
1761+ "20 deny\n", pid);
1762+ set(buffer);
1763+ check(buffer, fork_exec(NULL) == 0);
1764+ unset(buffer);
1765+ snprintf(buffer, sizeof(buffer) - 1,
1766+ "100 acl execute task.ppid=%u\n"
1767+ "10 allow path!=exec\n"
1768+ "20 deny\n", pid);
1769+ set(buffer);
1770+ check(buffer, fork_exec(NULL) == EOF);
1771+ unset(buffer);
1772+ snprintf(buffer, sizeof(buffer) - 1,
1773+ "100 acl execute task.ppid=%u\n"
1774+ "10 deny path=exec\n"
1775+ "20 allow\n", pid);
1776+ set(buffer);
1777+ check(buffer, fork_exec(NULL) == EOF);
1778+ unset(buffer);
1779+ snprintf(buffer, sizeof(buffer) - 1,
1780+ "100 acl execute task.ppid=%u\n"
1781+ "10 deny path!=exec\n"
1782+ "20 allow\n", pid);
1783+ set(buffer);
1784+ check(buffer, fork_exec(NULL) == 0);
1785+ unset(buffer);
1786+}
1787+
1788+static void reset_policy(void)
1789+{
1790+ FILE *fp2 = fopen(POLDIR "/policy", "r");
1791+ FILE *fp1 = fopen(POLDIR "/policy", "w");
1792+ if (!fp1 || !fp2) {
1793+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
1794+ exit(1);
1795+ }
1796+ while (1) {
1797+ const int c = fgetc(fp2);
1798+ if (c == EOF)
1799+ break;
1800+ fputc(c, fp1);
1801+ if (c == '\n')
1802+ fprintf(fp1, "delete ");
1803+ }
1804+ fclose(fp2);
1805+ fclose(fp1);
1806+
1807+ /* Do not leave the init process in stopped state. */
1808+ kill(1, SIGCONT);
1809+
1810+ /* Undo mount("/", MS_REC|MS_SHARED) made by systemd. */
1811+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
1812+}
1813+
1814+int main(int argc, char *argv[])
1815+{
1816+ reset_policy();
1817+
1818+ fp = fopen(POLDIR "/policy", "w");
1819+ if (!fp) {
1820+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
1821+ return 1;
1822+ }
1823+ fprintf(fp, "quota audit[0]"
1824+ " allowed=1024 unmatched=1024 denied=1024\n");
1825+ fflush(fp);
1826+
1827+ test_task_transition();
1828+ test_file_read();
1829+ test_file_write();
1830+ test_file_create();
1831+ test_file_unlink();
1832+ test_file_link();
1833+ test_file_rename();
1834+ test_network_inet_stream();
1835+ test_network_inet_dgram();
1836+ test_network_inet_raw();
1837+ test_network_inet6_stream();
1838+ test_network_inet6_dgram();
1839+ test_environ();
1840+ test_file_execute();
1841+ test_file_misc();
1842+ return 0;
1843+}
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_parser_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_parser_test.c (revision 219)
@@ -0,0 +1,953 @@
1+/*
2+ * caitsith-parser-test.c
3+ *
4+ * Copyright (C) 2012-2013 Tetsuo Handa
5+ *
6+ * Version: 0.2 2016/10/05
7+ *
8+ * This program is free software; you can redistribute it and/or modify it
9+ * under the terms of the GNU General Public License v2 as published by the
10+ * Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful, but WITHOUT
13+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15+ * more details.
16+ *
17+ * You should have received a copy of the GNU General Public License along with
18+ * this program; if not, write to the Free Software Foundation, Inc.,
19+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+ */
21+
22+#include <stdio.h>
23+#include <string.h>
24+#include <stdlib.h>
25+#include <sys/types.h>
26+#include <sys/stat.h>
27+#include <fcntl.h>
28+#include <unistd.h>
29+#include <time.h>
30+#include <signal.h>
31+#include <sys/mount.h>
32+#ifndef MS_REC
33+#define MS_REC 16384
34+#endif
35+#ifndef MS_PRIVATE
36+#define MS_PRIVATE (1 << 18)
37+#endif
38+
39+enum ccs_mac_index {
40+ CCS_MAC_EXECUTE,
41+ CCS_MAC_READ,
42+ CCS_MAC_WRITE,
43+ CCS_MAC_APPEND,
44+ CCS_MAC_CREATE,
45+ CCS_MAC_UNLINK,
46+ CCS_MAC_GETATTR,
47+ CCS_MAC_MKDIR,
48+ CCS_MAC_RMDIR,
49+ CCS_MAC_MKFIFO,
50+ CCS_MAC_MKSOCK,
51+ CCS_MAC_TRUNCATE,
52+ CCS_MAC_SYMLINK,
53+ CCS_MAC_MKBLOCK,
54+ CCS_MAC_MKCHAR,
55+ CCS_MAC_LINK,
56+ CCS_MAC_RENAME,
57+ CCS_MAC_CHMOD,
58+ CCS_MAC_CHOWN,
59+ CCS_MAC_CHGRP,
60+ CCS_MAC_IOCTL,
61+ CCS_MAC_CHROOT,
62+ CCS_MAC_MOUNT,
63+ CCS_MAC_UMOUNT,
64+ CCS_MAC_PIVOT_ROOT,
65+ CCS_MAC_INET_STREAM_BIND,
66+ CCS_MAC_INET_STREAM_LISTEN,
67+ CCS_MAC_INET_STREAM_CONNECT,
68+ CCS_MAC_INET_STREAM_ACCEPT,
69+ CCS_MAC_INET_DGRAM_BIND,
70+ CCS_MAC_INET_DGRAM_SEND,
71+ CCS_MAC_INET_DGRAM_RECV,
72+ CCS_MAC_INET_RAW_BIND,
73+ CCS_MAC_INET_RAW_SEND,
74+ CCS_MAC_INET_RAW_RECV,
75+ CCS_MAC_UNIX_STREAM_BIND,
76+ CCS_MAC_UNIX_STREAM_LISTEN,
77+ CCS_MAC_UNIX_STREAM_CONNECT,
78+ CCS_MAC_UNIX_STREAM_ACCEPT,
79+ CCS_MAC_UNIX_DGRAM_BIND,
80+ CCS_MAC_UNIX_DGRAM_SEND,
81+ CCS_MAC_UNIX_DGRAM_RECV,
82+ CCS_MAC_UNIX_SEQPACKET_BIND,
83+ CCS_MAC_UNIX_SEQPACKET_LISTEN,
84+ CCS_MAC_UNIX_SEQPACKET_CONNECT,
85+ CCS_MAC_UNIX_SEQPACKET_ACCEPT,
86+ CCS_MAC_ENVIRON,
87+ CCS_MAC_PTRACE,
88+ CCS_MAC_SIGNAL,
89+ CCS_MAC_MODIFY_POLICY,
90+ CCS_MAC_USE_NETLINK_SOCKET,
91+ CCS_MAC_USE_PACKET_SOCKET,
92+ CCS_MAC_USE_REBOOT,
93+ CCS_MAC_USE_VHANGUP,
94+ CCS_MAC_SET_TIME,
95+ CCS_MAC_SET_PRIORITY,
96+ CCS_MAC_SET_HOSTNAME,
97+ CCS_MAC_USE_KERNEL_MODULE,
98+ CCS_MAC_USE_NEW_KERNEL,
99+ CCS_MAC_AUTO_DOMAIN_TRANSITION,
100+ CCS_MAC_MANUAL_DOMAIN_TRANSITION,
101+ CCS_MAX_MAC_INDEX
102+};
103+
104+static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX] = {
105+ [CCS_MAC_EXECUTE] = "execute",
106+ [CCS_MAC_READ] = "read",
107+ [CCS_MAC_WRITE] = "write",
108+ [CCS_MAC_APPEND] = "append",
109+ [CCS_MAC_CREATE] = "create",
110+ [CCS_MAC_UNLINK] = "unlink",
111+ [CCS_MAC_GETATTR] = "getattr",
112+ [CCS_MAC_MKDIR] = "mkdir",
113+ [CCS_MAC_RMDIR] = "rmdir",
114+ [CCS_MAC_MKFIFO] = "mkfifo",
115+ [CCS_MAC_MKSOCK] = "mksock",
116+ [CCS_MAC_TRUNCATE] = "truncate",
117+ [CCS_MAC_SYMLINK] = "symlink",
118+ [CCS_MAC_MKBLOCK] = "mkblock",
119+ [CCS_MAC_MKCHAR] = "mkchar",
120+ [CCS_MAC_LINK] = "link",
121+ [CCS_MAC_RENAME] = "rename",
122+ [CCS_MAC_CHMOD] = "chmod",
123+ [CCS_MAC_CHOWN] = "chown",
124+ [CCS_MAC_CHGRP] = "chgrp",
125+ [CCS_MAC_IOCTL] = "ioctl",
126+ [CCS_MAC_CHROOT] = "chroot",
127+ [CCS_MAC_MOUNT] = "mount",
128+ [CCS_MAC_UMOUNT] = "unmount",
129+ [CCS_MAC_PIVOT_ROOT] = "pivot_root",
130+ [CCS_MAC_INET_STREAM_BIND] = "inet_stream_bind",
131+ [CCS_MAC_INET_STREAM_LISTEN] = "inet_stream_listen",
132+ [CCS_MAC_INET_STREAM_CONNECT] = "inet_stream_connect",
133+ [CCS_MAC_INET_STREAM_ACCEPT] = "inet_stream_accept",
134+ [CCS_MAC_INET_DGRAM_BIND] = "inet_dgram_bind",
135+ [CCS_MAC_INET_DGRAM_SEND] = "inet_dgram_send",
136+ [CCS_MAC_INET_DGRAM_RECV] = "inet_dgram_recv",
137+ [CCS_MAC_INET_RAW_BIND] = "inet_raw_bind",
138+ [CCS_MAC_INET_RAW_SEND] = "inet_raw_send",
139+ [CCS_MAC_INET_RAW_RECV] = "inet_raw_recv",
140+ [CCS_MAC_UNIX_STREAM_BIND] = "unix_stream_bind",
141+ [CCS_MAC_UNIX_STREAM_LISTEN] = "unix_stream_listen",
142+ [CCS_MAC_UNIX_STREAM_CONNECT] = "unix_stream_connect",
143+ [CCS_MAC_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
144+ [CCS_MAC_UNIX_DGRAM_BIND] = "unix_dgram_bind",
145+ [CCS_MAC_UNIX_DGRAM_SEND] = "unix_dgram_send",
146+ [CCS_MAC_UNIX_DGRAM_RECV] = "unix_dgram_recv",
147+ [CCS_MAC_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
148+ [CCS_MAC_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
149+ [CCS_MAC_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
150+ [CCS_MAC_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
151+ [CCS_MAC_ENVIRON] = "environ",
152+ [CCS_MAC_PTRACE] = "ptrace",
153+ [CCS_MAC_SIGNAL] = "signal",
154+ [CCS_MAC_MODIFY_POLICY] = "modify_policy",
155+ [CCS_MAC_USE_NETLINK_SOCKET] = "use_netlink_socket",
156+ [CCS_MAC_USE_PACKET_SOCKET] = "use_packet_socket",
157+ [CCS_MAC_USE_REBOOT] = "use_reboot",
158+ [CCS_MAC_USE_VHANGUP] = "use_vhangup",
159+ [CCS_MAC_SET_TIME] = "set_time",
160+ [CCS_MAC_SET_PRIORITY] = "set_priority",
161+ [CCS_MAC_SET_HOSTNAME] = "set_hostname",
162+ [CCS_MAC_USE_KERNEL_MODULE] = "use_kernel_module",
163+ [CCS_MAC_USE_NEW_KERNEL] = "use_new_kernel",
164+ [CCS_MAC_AUTO_DOMAIN_TRANSITION] = "auto_domain_transition",
165+ [CCS_MAC_MANUAL_DOMAIN_TRANSITION] = "manual_domain_transition",
166+};
167+
168+#define F(bit) (1ULL << bit)
169+
170+#define CCS_ALL_OK \
171+ (F(CCS_MAC_EXECUTE) | \
172+ F(CCS_MAC_READ) | \
173+ F(CCS_MAC_WRITE) | \
174+ F(CCS_MAC_APPEND) | \
175+ F(CCS_MAC_CREATE) | \
176+ F(CCS_MAC_UNLINK) | \
177+ F(CCS_MAC_GETATTR) | \
178+ F(CCS_MAC_MKDIR) | \
179+ F(CCS_MAC_RMDIR) | \
180+ F(CCS_MAC_MKFIFO) | \
181+ F(CCS_MAC_MKSOCK) | \
182+ F(CCS_MAC_TRUNCATE) | \
183+ F(CCS_MAC_SYMLINK) | \
184+ F(CCS_MAC_MKBLOCK) | \
185+ F(CCS_MAC_MKCHAR) | \
186+ F(CCS_MAC_LINK) | \
187+ F(CCS_MAC_RENAME) | \
188+ F(CCS_MAC_CHMOD) | \
189+ F(CCS_MAC_CHOWN) | \
190+ F(CCS_MAC_CHGRP) | \
191+ F(CCS_MAC_IOCTL) | \
192+ F(CCS_MAC_CHROOT) | \
193+ F(CCS_MAC_MOUNT) | \
194+ F(CCS_MAC_UMOUNT) | \
195+ F(CCS_MAC_PIVOT_ROOT) | \
196+ F(CCS_MAC_INET_STREAM_BIND) | \
197+ F(CCS_MAC_INET_STREAM_LISTEN) | \
198+ F(CCS_MAC_INET_STREAM_CONNECT) | \
199+ F(CCS_MAC_INET_STREAM_ACCEPT) | \
200+ F(CCS_MAC_INET_DGRAM_BIND) | \
201+ F(CCS_MAC_INET_DGRAM_SEND) | \
202+ F(CCS_MAC_INET_DGRAM_RECV) | \
203+ F(CCS_MAC_INET_RAW_BIND) | \
204+ F(CCS_MAC_INET_RAW_SEND) | \
205+ F(CCS_MAC_INET_RAW_RECV) | \
206+ F(CCS_MAC_UNIX_STREAM_BIND) | \
207+ F(CCS_MAC_UNIX_STREAM_LISTEN) | \
208+ F(CCS_MAC_UNIX_STREAM_CONNECT) | \
209+ F(CCS_MAC_UNIX_STREAM_ACCEPT) | \
210+ F(CCS_MAC_UNIX_DGRAM_BIND) | \
211+ F(CCS_MAC_UNIX_DGRAM_SEND) | \
212+ F(CCS_MAC_UNIX_DGRAM_RECV) | \
213+ F(CCS_MAC_UNIX_SEQPACKET_BIND) | \
214+ F(CCS_MAC_UNIX_SEQPACKET_LISTEN) | \
215+ F(CCS_MAC_UNIX_SEQPACKET_CONNECT) | \
216+ F(CCS_MAC_UNIX_SEQPACKET_ACCEPT) | \
217+ F(CCS_MAC_ENVIRON) | \
218+ F(CCS_MAC_PTRACE) | \
219+ F(CCS_MAC_SIGNAL) | \
220+ F(CCS_MAC_MODIFY_POLICY) | \
221+ F(CCS_MAC_USE_NETLINK_SOCKET) | \
222+ F(CCS_MAC_USE_PACKET_SOCKET) | \
223+ F(CCS_MAC_USE_REBOOT) | \
224+ F(CCS_MAC_USE_VHANGUP) | \
225+ F(CCS_MAC_SET_TIME) | \
226+ F(CCS_MAC_SET_PRIORITY) | \
227+ F(CCS_MAC_SET_HOSTNAME) | \
228+ F(CCS_MAC_USE_KERNEL_MODULE) | \
229+ F(CCS_MAC_USE_NEW_KERNEL) | \
230+ F(CCS_MAC_AUTO_DOMAIN_TRANSITION) | \
231+ F(CCS_MAC_MANUAL_DOMAIN_TRANSITION))
232+
233+#define CCS_PATH_SELF_OK \
234+ (F(CCS_MAC_EXECUTE) | \
235+ F(CCS_MAC_ENVIRON) | \
236+ F(CCS_MAC_READ) | \
237+ F(CCS_MAC_WRITE) | \
238+ F(CCS_MAC_APPEND) | \
239+ F(CCS_MAC_UNLINK) | \
240+ F(CCS_MAC_GETATTR) | \
241+ F(CCS_MAC_RMDIR) | \
242+ F(CCS_MAC_TRUNCATE) | \
243+ F(CCS_MAC_CHMOD) | \
244+ F(CCS_MAC_CHOWN) | \
245+ F(CCS_MAC_CHGRP) | \
246+ F(CCS_MAC_IOCTL) | \
247+ F(CCS_MAC_CHROOT) | \
248+ F(CCS_MAC_UMOUNT))
249+
250+#define CCS_PATH_PARENT_OK \
251+ (F(CCS_MAC_CREATE) | \
252+ F(CCS_MAC_MKDIR) | \
253+ F(CCS_MAC_MKFIFO) | \
254+ F(CCS_MAC_MKSOCK) | \
255+ F(CCS_MAC_SYMLINK) | \
256+ F(CCS_MAC_MKBLOCK) | \
257+ F(CCS_MAC_MKCHAR))
258+
259+#define CCS_PATH_OK (CCS_PATH_SELF_OK | CCS_PATH_PARENT_OK)
260+
261+#define CCS_RENAME_OR_LINK_OK (F(CCS_MAC_LINK) | F(CCS_MAC_RENAME))
262+
263+#define CCS_EXECUTE_OR_ENVIRON_OK (F(CCS_MAC_EXECUTE) | F(CCS_MAC_ENVIRON))
264+
265+#define CCS_MKDEV_OK (F(CCS_MAC_MKBLOCK) | F(CCS_MAC_MKCHAR))
266+
267+#define CCS_PATH_PERM_OK \
268+ (F(CCS_MAC_MKDIR) | \
269+ F(CCS_MAC_MKBLOCK) | \
270+ F(CCS_MAC_MKCHAR) | \
271+ F(CCS_MAC_MKFIFO) | \
272+ F(CCS_MAC_MKSOCK) | \
273+ F(CCS_MAC_CREATE) | \
274+ F(CCS_MAC_CHMOD))
275+
276+#define CCS_IP_SOCKET_OK \
277+ (F(CCS_MAC_INET_STREAM_BIND) | \
278+ F(CCS_MAC_INET_STREAM_LISTEN) | \
279+ F(CCS_MAC_INET_STREAM_CONNECT) | \
280+ F(CCS_MAC_INET_STREAM_ACCEPT) | \
281+ F(CCS_MAC_INET_DGRAM_BIND) | \
282+ F(CCS_MAC_INET_DGRAM_SEND) | \
283+ F(CCS_MAC_INET_DGRAM_RECV))
284+
285+#define CCS_RAW_SOCKET_OK \
286+ (F(CCS_MAC_INET_RAW_BIND) | \
287+ F(CCS_MAC_INET_RAW_SEND) | \
288+ F(CCS_MAC_INET_RAW_RECV))
289+
290+#define CCS_INET_SOCKET_OK (CCS_IP_SOCKET_OK | CCS_RAW_SOCKET_OK)
291+
292+#define CCS_UNIX_SOCKET_OK \
293+ (F(CCS_MAC_UNIX_STREAM_BIND) | \
294+ F(CCS_MAC_UNIX_STREAM_LISTEN) | \
295+ F(CCS_MAC_UNIX_STREAM_CONNECT) | \
296+ F(CCS_MAC_UNIX_STREAM_ACCEPT) | \
297+ F(CCS_MAC_UNIX_DGRAM_BIND) | \
298+ F(CCS_MAC_UNIX_DGRAM_SEND) | \
299+ F(CCS_MAC_UNIX_DGRAM_RECV) | \
300+ F(CCS_MAC_UNIX_SEQPACKET_BIND) | \
301+ F(CCS_MAC_UNIX_SEQPACKET_LISTEN) | \
302+ F(CCS_MAC_UNIX_SEQPACKET_CONNECT) | \
303+ F(CCS_MAC_UNIX_SEQPACKET_ACCEPT))
304+
305+enum ccs_var_type {
306+ CCS_TYPE_INVALID,
307+ CCS_TYPE_NUMBER,
308+ CCS_TYPE_STRING,
309+ CCS_TYPE_IPADDR,
310+ CCS_TYPE_FILEPERM,
311+ CCS_TYPE_FILETYPE,
312+ CCS_TYPE_TASKTYPE,
313+ CCS_TYPE_ASSIGN,
314+};
315+
316+static const struct {
317+ const char * const keyword;
318+ const enum ccs_var_type left_type;
319+ const enum ccs_var_type right_type;
320+ const unsigned long long available;
321+} ccs_conditions[] = {
322+ { "addr", CCS_TYPE_STRING, CCS_TYPE_STRING,
323+ CCS_UNIX_SOCKET_OK },
324+ { "argc", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
325+ CCS_EXECUTE_OR_ENVIRON_OK },
326+ { "block", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
327+ CCS_ALL_OK },
328+ { "char", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
329+ CCS_ALL_OK },
330+ { "cmd", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
331+ F(CCS_MAC_IOCTL) | F(CCS_MAC_PTRACE) },
332+ { "data", CCS_TYPE_STRING, CCS_TYPE_STRING,
333+ F(CCS_MAC_MOUNT) },
334+ { "dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
335+ CCS_MKDEV_OK },
336+ { "dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
337+ CCS_MKDEV_OK },
338+ { "directory", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
339+ CCS_ALL_OK },
340+ { "domain", CCS_TYPE_STRING, CCS_TYPE_STRING,
341+ F(CCS_MAC_PTRACE) | F(CCS_MAC_MANUAL_DOMAIN_TRANSITION) },
342+ { "envc", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
343+ CCS_EXECUTE_OR_ENVIRON_OK },
344+ { "exec", CCS_TYPE_STRING, CCS_TYPE_STRING,
345+ CCS_EXECUTE_OR_ENVIRON_OK },
346+ { "exec.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
347+ CCS_EXECUTE_OR_ENVIRON_OK },
348+ { "exec.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
349+ CCS_EXECUTE_OR_ENVIRON_OK },
350+ { "exec.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
351+ CCS_EXECUTE_OR_ENVIRON_OK },
352+ { "exec.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
353+ CCS_EXECUTE_OR_ENVIRON_OK },
354+ { "exec.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
355+ CCS_EXECUTE_OR_ENVIRON_OK },
356+ { "exec.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
357+ CCS_EXECUTE_OR_ENVIRON_OK },
358+ { "exec.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
359+ CCS_EXECUTE_OR_ENVIRON_OK },
360+ { "exec.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
361+ CCS_EXECUTE_OR_ENVIRON_OK },
362+ { "exec.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
363+ CCS_EXECUTE_OR_ENVIRON_OK },
364+ { "exec.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
365+ CCS_EXECUTE_OR_ENVIRON_OK },
366+ { "exec.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
367+ CCS_EXECUTE_OR_ENVIRON_OK },
368+ { "exec.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
369+ CCS_EXECUTE_OR_ENVIRON_OK },
370+ { "exec.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
371+ CCS_EXECUTE_OR_ENVIRON_OK },
372+ { "exec.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
373+ CCS_EXECUTE_OR_ENVIRON_OK },
374+ { "exec.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
375+ CCS_EXECUTE_OR_ENVIRON_OK },
376+ { "execute_handler", CCS_TYPE_INVALID, CCS_TYPE_TASKTYPE,
377+ CCS_ALL_OK },
378+ { "fifo", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
379+ CCS_ALL_OK },
380+ { "file", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
381+ CCS_ALL_OK },
382+ { "flags", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
383+ F(CCS_MAC_MOUNT) | F(CCS_MAC_UMOUNT) },
384+ { "fstype", CCS_TYPE_STRING, CCS_TYPE_STRING,
385+ F(CCS_MAC_MOUNT) },
386+ { "gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
387+ F(CCS_MAC_CHGRP) },
388+ { "group_execute", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
389+ CCS_ALL_OK },
390+ { "group_read", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
391+ CCS_ALL_OK },
392+ { "group_write", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
393+ CCS_ALL_OK },
394+ { "handler", CCS_TYPE_ASSIGN, CCS_TYPE_INVALID,
395+ F(CCS_MAC_EXECUTE) },
396+ { "ip", CCS_TYPE_IPADDR, CCS_TYPE_INVALID,
397+ CCS_INET_SOCKET_OK },
398+ { "name", CCS_TYPE_STRING, CCS_TYPE_STRING,
399+ F(CCS_MAC_ENVIRON) },
400+ { "new_path", CCS_TYPE_STRING, CCS_TYPE_STRING,
401+ CCS_RENAME_OR_LINK_OK },
402+ { "new_path.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
403+ F(CCS_MAC_RENAME) },
404+ { "new_path.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
405+ F(CCS_MAC_RENAME) },
406+ { "new_path.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
407+ F(CCS_MAC_RENAME) },
408+ { "new_path.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
409+ F(CCS_MAC_RENAME) },
410+ { "new_path.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
411+ F(CCS_MAC_RENAME) },
412+ { "new_path.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
413+ F(CCS_MAC_RENAME) },
414+ { "new_path.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
415+ F(CCS_MAC_RENAME) },
416+ { "new_path.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
417+ CCS_RENAME_OR_LINK_OK },
418+ { "new_path.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
419+ CCS_RENAME_OR_LINK_OK },
420+ { "new_path.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
421+ CCS_RENAME_OR_LINK_OK },
422+ { "new_path.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
423+ CCS_RENAME_OR_LINK_OK },
424+ { "new_path.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
425+ CCS_RENAME_OR_LINK_OK },
426+ { "new_path.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
427+ CCS_RENAME_OR_LINK_OK },
428+ { "new_path.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
429+ CCS_RENAME_OR_LINK_OK },
430+ { "new_path.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
431+ F(CCS_MAC_RENAME) },
432+ { "new_path.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
433+ F(CCS_MAC_RENAME) },
434+ { "new_path.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
435+ F(CCS_MAC_RENAME) },
436+ { "new_root", CCS_TYPE_STRING, CCS_TYPE_STRING,
437+ F(CCS_MAC_PIVOT_ROOT) },
438+ { "new_root.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
439+ F(CCS_MAC_PIVOT_ROOT) },
440+ { "new_root.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
441+ F(CCS_MAC_PIVOT_ROOT) },
442+ { "new_root.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
443+ F(CCS_MAC_PIVOT_ROOT) },
444+ { "new_root.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
445+ F(CCS_MAC_PIVOT_ROOT) },
446+ { "new_root.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
447+ F(CCS_MAC_PIVOT_ROOT) },
448+ { "new_root.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
449+ F(CCS_MAC_PIVOT_ROOT) },
450+ { "new_root.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
451+ F(CCS_MAC_PIVOT_ROOT) },
452+ { "new_root.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
453+ F(CCS_MAC_PIVOT_ROOT) },
454+ { "new_root.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
455+ F(CCS_MAC_PIVOT_ROOT) },
456+ { "new_root.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
457+ F(CCS_MAC_PIVOT_ROOT) },
458+ { "new_root.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
459+ F(CCS_MAC_PIVOT_ROOT) },
460+ { "new_root.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
461+ F(CCS_MAC_PIVOT_ROOT) },
462+ { "new_root.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
463+ F(CCS_MAC_PIVOT_ROOT) },
464+ { "new_root.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
465+ F(CCS_MAC_PIVOT_ROOT) },
466+ { "new_root.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
467+ F(CCS_MAC_PIVOT_ROOT) },
468+ { "new_root.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
469+ F(CCS_MAC_PIVOT_ROOT) },
470+ { "new_root.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
471+ F(CCS_MAC_PIVOT_ROOT) },
472+ { "old_path", CCS_TYPE_STRING, CCS_TYPE_STRING,
473+ CCS_RENAME_OR_LINK_OK },
474+ { "old_path.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
475+ CCS_RENAME_OR_LINK_OK },
476+ { "old_path.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
477+ CCS_RENAME_OR_LINK_OK },
478+ { "old_path.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
479+ CCS_RENAME_OR_LINK_OK },
480+ { "old_path.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
481+ CCS_RENAME_OR_LINK_OK },
482+ { "old_path.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
483+ CCS_RENAME_OR_LINK_OK },
484+ { "old_path.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
485+ CCS_RENAME_OR_LINK_OK },
486+ { "old_path.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
487+ CCS_RENAME_OR_LINK_OK },
488+ { "old_path.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
489+ CCS_RENAME_OR_LINK_OK },
490+ { "old_path.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
491+ CCS_RENAME_OR_LINK_OK },
492+ { "old_path.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
493+ CCS_RENAME_OR_LINK_OK },
494+ { "old_path.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
495+ CCS_RENAME_OR_LINK_OK },
496+ { "old_path.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
497+ CCS_RENAME_OR_LINK_OK },
498+ { "old_path.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
499+ CCS_RENAME_OR_LINK_OK },
500+ { "old_path.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
501+ CCS_RENAME_OR_LINK_OK },
502+ { "old_path.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
503+ CCS_RENAME_OR_LINK_OK },
504+ { "old_path.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
505+ CCS_RENAME_OR_LINK_OK },
506+ { "old_path.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
507+ CCS_RENAME_OR_LINK_OK },
508+ { "others_execute", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
509+ CCS_ALL_OK },
510+ { "others_read", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
511+ CCS_ALL_OK },
512+ { "others_write", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
513+ CCS_ALL_OK },
514+ { "owner_execute", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
515+ CCS_ALL_OK },
516+ { "owner_read", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
517+ CCS_ALL_OK },
518+ { "owner_write", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
519+ CCS_ALL_OK },
520+ { "path", CCS_TYPE_STRING, CCS_TYPE_STRING,
521+ CCS_PATH_OK },
522+ { "path.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
523+ CCS_PATH_SELF_OK },
524+ { "path.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
525+ CCS_PATH_SELF_OK },
526+ { "path.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
527+ CCS_PATH_SELF_OK },
528+ { "path.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
529+ CCS_PATH_SELF_OK },
530+ { "path.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
531+ CCS_PATH_SELF_OK },
532+ { "path.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
533+ CCS_PATH_SELF_OK },
534+ { "path.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
535+ CCS_PATH_SELF_OK },
536+ { "path.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
537+ CCS_PATH_OK },
538+ { "path.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
539+ CCS_PATH_OK },
540+ { "path.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
541+ CCS_PATH_OK },
542+ { "path.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
543+ CCS_PATH_OK },
544+ { "path.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
545+ CCS_PATH_OK },
546+ { "path.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
547+ CCS_PATH_OK },
548+ { "path.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
549+ CCS_PATH_OK },
550+ { "path.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
551+ CCS_PATH_SELF_OK },
552+ { "path.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
553+ CCS_PATH_SELF_OK },
554+ { "path.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
555+ CCS_PATH_SELF_OK },
556+ { "perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
557+ CCS_PATH_PERM_OK },
558+ { "port", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
559+ CCS_IP_SOCKET_OK },
560+ { "proto", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
561+ CCS_RAW_SOCKET_OK },
562+ { "put_old", CCS_TYPE_STRING, CCS_TYPE_STRING,
563+ F(CCS_MAC_PIVOT_ROOT) },
564+ { "put_old.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
565+ F(CCS_MAC_PIVOT_ROOT) },
566+ { "put_old.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
567+ F(CCS_MAC_PIVOT_ROOT) },
568+ { "put_old.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
569+ F(CCS_MAC_PIVOT_ROOT) },
570+ { "put_old.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
571+ F(CCS_MAC_PIVOT_ROOT) },
572+ { "put_old.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
573+ F(CCS_MAC_PIVOT_ROOT) },
574+ { "put_old.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
575+ F(CCS_MAC_PIVOT_ROOT) },
576+ { "put_old.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
577+ F(CCS_MAC_PIVOT_ROOT) },
578+ { "put_old.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
579+ F(CCS_MAC_PIVOT_ROOT) },
580+ { "put_old.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
581+ F(CCS_MAC_PIVOT_ROOT) },
582+ { "put_old.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
583+ F(CCS_MAC_PIVOT_ROOT) },
584+ { "put_old.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
585+ F(CCS_MAC_PIVOT_ROOT) },
586+ { "put_old.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
587+ F(CCS_MAC_PIVOT_ROOT) },
588+ { "put_old.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
589+ F(CCS_MAC_PIVOT_ROOT) },
590+ { "put_old.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
591+ F(CCS_MAC_PIVOT_ROOT) },
592+ { "put_old.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
593+ F(CCS_MAC_PIVOT_ROOT) },
594+ { "put_old.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
595+ F(CCS_MAC_PIVOT_ROOT) },
596+ { "put_old.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
597+ F(CCS_MAC_PIVOT_ROOT) },
598+ { "setgid", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
599+ CCS_ALL_OK },
600+ { "setuid", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
601+ CCS_ALL_OK },
602+ { "sig", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
603+ F(CCS_MAC_SIGNAL) },
604+ { "socket", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
605+ CCS_ALL_OK },
606+ { "source", CCS_TYPE_STRING, CCS_TYPE_STRING,
607+ F(CCS_MAC_MOUNT) },
608+ { "source.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
609+ F(CCS_MAC_MOUNT) },
610+ { "source.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
611+ F(CCS_MAC_MOUNT) },
612+ { "source.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
613+ F(CCS_MAC_MOUNT) },
614+ { "source.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
615+ F(CCS_MAC_MOUNT) },
616+ { "source.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
617+ F(CCS_MAC_MOUNT) },
618+ { "source.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
619+ F(CCS_MAC_MOUNT) },
620+ { "source.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
621+ F(CCS_MAC_MOUNT) },
622+ { "source.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
623+ F(CCS_MAC_MOUNT) },
624+ { "source.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
625+ F(CCS_MAC_MOUNT) },
626+ { "source.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
627+ F(CCS_MAC_MOUNT) },
628+ { "source.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
629+ F(CCS_MAC_MOUNT) },
630+ { "source.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
631+ F(CCS_MAC_MOUNT) },
632+ { "source.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
633+ F(CCS_MAC_MOUNT) },
634+ { "source.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
635+ F(CCS_MAC_MOUNT) },
636+ { "source.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
637+ F(CCS_MAC_MOUNT) },
638+ { "source.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
639+ F(CCS_MAC_MOUNT) },
640+ { "source.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
641+ F(CCS_MAC_MOUNT) },
642+ { "sticky", CCS_TYPE_INVALID, CCS_TYPE_FILEPERM,
643+ CCS_ALL_OK },
644+ { "symlink", CCS_TYPE_INVALID, CCS_TYPE_FILETYPE,
645+ CCS_ALL_OK },
646+ { "target", CCS_TYPE_STRING, CCS_TYPE_STRING,
647+ F(CCS_MAC_MOUNT) | F(CCS_MAC_SYMLINK) },
648+ { "target.dev_major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
649+ F(CCS_MAC_MOUNT) },
650+ { "target.dev_minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
651+ F(CCS_MAC_MOUNT) },
652+ { "target.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
653+ F(CCS_MAC_MOUNT) },
654+ { "target.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
655+ F(CCS_MAC_MOUNT) },
656+ { "target.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
657+ F(CCS_MAC_MOUNT) },
658+ { "target.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
659+ F(CCS_MAC_MOUNT) },
660+ { "target.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
661+ F(CCS_MAC_MOUNT) },
662+ { "target.parent.fsmagic", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
663+ F(CCS_MAC_MOUNT) },
664+ { "target.parent.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
665+ F(CCS_MAC_MOUNT) },
666+ { "target.parent.ino", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
667+ F(CCS_MAC_MOUNT) },
668+ { "target.parent.major", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
669+ F(CCS_MAC_MOUNT) },
670+ { "target.parent.minor", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
671+ F(CCS_MAC_MOUNT) },
672+ { "target.parent.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
673+ F(CCS_MAC_MOUNT) },
674+ { "target.parent.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
675+ F(CCS_MAC_MOUNT) },
676+ { "target.perm", CCS_TYPE_FILEPERM, CCS_TYPE_FILEPERM,
677+ F(CCS_MAC_MOUNT) },
678+ { "target.type", CCS_TYPE_FILETYPE, CCS_TYPE_FILETYPE,
679+ F(CCS_MAC_MOUNT) },
680+ { "target.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
681+ F(CCS_MAC_MOUNT) },
682+ { "task.domain", CCS_TYPE_STRING, CCS_TYPE_STRING,
683+ CCS_ALL_OK },
684+ { "task.egid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
685+ CCS_ALL_OK },
686+ { "task.euid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
687+ CCS_ALL_OK },
688+ { "task.exe", CCS_TYPE_STRING, CCS_TYPE_STRING,
689+ CCS_ALL_OK },
690+ { "task.fsgid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
691+ CCS_ALL_OK },
692+ { "task.fsuid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
693+ CCS_ALL_OK },
694+ { "task.gid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
695+ CCS_ALL_OK },
696+ { "task.pid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
697+ CCS_ALL_OK },
698+ { "task.ppid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
699+ CCS_ALL_OK },
700+ { "task.sgid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
701+ CCS_ALL_OK },
702+ { "task.suid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
703+ CCS_ALL_OK },
704+ { "task.type", CCS_TYPE_TASKTYPE, CCS_TYPE_INVALID,
705+ CCS_ALL_OK },
706+ { "task.uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
707+ CCS_ALL_OK },
708+ { "transition", CCS_TYPE_ASSIGN, CCS_TYPE_INVALID,
709+ F(CCS_MAC_EXECUTE) | F(CCS_MAC_AUTO_DOMAIN_TRANSITION) },
710+ { "uid", CCS_TYPE_NUMBER, CCS_TYPE_NUMBER,
711+ F(CCS_MAC_CHOWN) },
712+ { "value", CCS_TYPE_STRING, CCS_TYPE_STRING,
713+ F(CCS_MAC_ENVIRON) },
714+ { "argv[0]", CCS_TYPE_STRING, CCS_TYPE_INVALID,
715+ CCS_EXECUTE_OR_ENVIRON_OK },
716+ { "argv[4294967295]", CCS_TYPE_STRING, CCS_TYPE_INVALID,
717+ CCS_EXECUTE_OR_ENVIRON_OK },
718+ { "envp[\"PATH\"]", CCS_TYPE_STRING, CCS_TYPE_INVALID,
719+ CCS_EXECUTE_OR_ENVIRON_OK },
720+ { "envp[\"\\*\"]", CCS_TYPE_STRING, CCS_TYPE_INVALID,
721+ CCS_EXECUTE_OR_ENVIRON_OK },
722+ { "NULL", CCS_TYPE_INVALID, CCS_TYPE_STRING,
723+ CCS_ALL_OK },
724+ { "\"word\"", CCS_TYPE_INVALID, CCS_TYPE_ASSIGN,
725+ CCS_ALL_OK },
726+ { "\"/\"", CCS_TYPE_INVALID, CCS_TYPE_STRING,
727+ CCS_ALL_OK },
728+ { "\"/\\*\"", CCS_TYPE_INVALID, CCS_TYPE_STRING,
729+ CCS_ALL_OK },
730+ { "@STRING_GROUP", CCS_TYPE_INVALID, CCS_TYPE_STRING,
731+ CCS_ALL_OK },
732+ { "0", CCS_TYPE_INVALID, CCS_TYPE_NUMBER,
733+ CCS_ALL_OK },
734+ { "0-4294967295", CCS_TYPE_INVALID, CCS_TYPE_NUMBER,
735+ CCS_ALL_OK },
736+ { "@NUMBER_GROUP", CCS_TYPE_INVALID, CCS_TYPE_NUMBER,
737+ CCS_ALL_OK },
738+ { "127.0.0.1", CCS_TYPE_INVALID, CCS_TYPE_IPADDR,
739+ CCS_ALL_OK },
740+ { "0.0.0.0-0.0.0.1", CCS_TYPE_INVALID, CCS_TYPE_IPADDR,
741+ CCS_ALL_OK },
742+ { "::1", CCS_TYPE_INVALID, CCS_TYPE_IPADDR,
743+ CCS_ALL_OK },
744+ { "::-::1", CCS_TYPE_INVALID, CCS_TYPE_IPADDR,
745+ CCS_ALL_OK },
746+ { "@IP_GROUP", CCS_TYPE_INVALID, CCS_TYPE_IPADDR,
747+ CCS_ALL_OK },
748+};
749+
750+static char *policy = NULL;
751+static int policy_len = 0;
752+
753+static inline void truncate_policy(void)
754+{
755+ policy_len = 0;
756+}
757+
758+static void add_policy(const char *data)
759+{
760+ const int len = strlen(data);
761+ char *tmp = realloc(policy, policy_len + len + 1);
762+ if (!tmp) {
763+ fprintf(stderr, "Out of memory\n");
764+ exit(1);
765+ }
766+ policy = tmp;
767+ memmove(policy + policy_len, data, len + 1);
768+ policy_len += len;
769+}
770+
771+static unsigned int tests_now = 0;
772+
773+static void check_policy_written(const _Bool valid)
774+{
775+ int fd1 = open(POLDIR "/policy", O_RDWR);
776+ int fd2 = open(POLDIR "/policy", O_RDWR);
777+ int len = strlen(policy);
778+ int ret;
779+ char *buffer;
780+ if (fd1 == EOF || fd2 == EOF) {
781+ printf("%s", policy);
782+ return;
783+ }
784+ ret = write(fd1, policy, len);
785+ if (ret != len) {
786+ fprintf(stderr, "Write error (%d, %d)\n", ret, len);
787+ exit(1);
788+ }
789+ buffer = calloc(len + 4096, 1);
790+ if (!buffer) {
791+ fprintf(stderr, "Out of memory\n");
792+ exit(1);
793+ }
794+ ret = read(fd1, buffer, len + 4095);
795+ if (!strstr(buffer, policy) != !valid) {
796+ fprintf(stderr, "Test %u: FAILED(add) '%s' : '%s' valid=%u\n",
797+ tests_now - 1, buffer, policy, valid);
798+ exit(1);
799+ }
800+ printf("Test %u: OK '%s' : '%s'\n", tests_now - 1, buffer, policy);
801+ if (write(fd2, "delete ", 7) != 7 || write(fd2, policy, len) != len) {
802+ fprintf(stderr, "Write error\n");
803+ exit(1);
804+ }
805+ memset(buffer, 0, len + 1024);
806+ ret = read(fd2, buffer, len + 1023);
807+ if (strstr(buffer, policy)) {
808+ fprintf(stderr, "Test %u: FAILED(remove) '%s' : '%s'\n",
809+ tests_now - 1, buffer, policy);
810+ exit(1);
811+ }
812+ printf("Test %u: OK '%s' : '%s'\n", tests_now - 1, buffer, policy);
813+ free(buffer);
814+ close(fd1);
815+ close(fd2);
816+}
817+
818+static inline void add_policy2(const char *data1, const char *data2)
819+{
820+ add_policy(data1);
821+ add_policy(data2);
822+}
823+
824+static inline void add_policy3(const char *data1, const char *data2,
825+ const char *data3)
826+{
827+ add_policy(data1);
828+ add_policy(data2);
829+ add_policy(data3);
830+}
831+
832+static _Bool adjust_exception(const int mac, const int p1, const int p2)
833+{
834+ if (ccs_conditions[p1].left_type == CCS_TYPE_ASSIGN)
835+ return !strcmp(ccs_conditions[p2].keyword, "NULL") ||
836+ !strcmp(ccs_conditions[p2].keyword,"\"/\"");
837+ if (ccs_conditions[p2].keyword[0] == '@')
838+ return ccs_conditions[p1].left_type == CCS_TYPE_STRING ||
839+ ccs_conditions[p1].left_type == CCS_TYPE_NUMBER ||
840+ ccs_conditions[p1].left_type == CCS_TYPE_IPADDR ||
841+ ccs_conditions[p1].left_type == CCS_TYPE_FILEPERM;
842+ if (ccs_conditions[p1].left_type == CCS_TYPE_STRING)
843+ return !strcmp(ccs_conditions[p2].keyword, "\"word\"");
844+ if (ccs_conditions[p1].left_type == CCS_TYPE_FILEPERM &&
845+ ccs_conditions[p2].right_type == CCS_TYPE_NUMBER)
846+ return 1;
847+ return 0;
848+}
849+
850+static unsigned int tests_start = 0;
851+
852+static void check_righthand(const int mac, const int p1, const _Bool org_valid)
853+{
854+ int p2;
855+ const enum ccs_var_type type = ccs_conditions[p1].left_type;
856+ for (p2 = 0; p2 < sizeof(ccs_conditions) / sizeof(ccs_conditions[0]);
857+ p2++) {
858+ _Bool valid = org_valid;
859+ if (tests_now++ < tests_start)
860+ continue;
861+ if (valid) {
862+ if (!(ccs_conditions[p2].available & F(mac)))
863+ valid = 0;
864+ else if (ccs_conditions[p2].right_type != type)
865+ valid = adjust_exception(mac, p1, p2);
866+ }
867+ truncate_policy();
868+ add_policy3("0 acl ", ccs_mac_keywords[mac], "\n"
869+ " audit 0\n 0 allow");
870+ add_policy2(" ", ccs_conditions[p1].keyword);
871+ add_policy2("=", ccs_conditions[p2].keyword);
872+ if (mac == CCS_MAC_AUTO_DOMAIN_TRANSITION &&
873+ strcmp(ccs_conditions[p1].keyword, "transition"))
874+ add_policy(" transition=\"word\"");
875+ add_policy("\n");
876+ check_policy_written(valid);
877+ if (type == CCS_TYPE_ASSIGN)
878+ valid = 0;
879+ truncate_policy();
880+ add_policy3("0 acl ", ccs_mac_keywords[mac], "\n"
881+ " audit 0\n 0 allow");
882+ add_policy2(" ", ccs_conditions[p1].keyword);
883+ add_policy2("!=", ccs_conditions[p2].keyword);
884+ if (mac == CCS_MAC_AUTO_DOMAIN_TRANSITION &&
885+ strcmp(ccs_conditions[p1].keyword, "transition"))
886+ add_policy(" transition=\"word\"");
887+ add_policy("\n");
888+ check_policy_written(valid);
889+ {
890+ static time_t last = 0;
891+ time_t now = time(NULL);
892+ if (now - last >= (time_t) 10) {
893+ last = now;
894+ fprintf(stderr, "Test %u passed\n",
895+ tests_now - 1);
896+ }
897+ }
898+ }
899+}
900+
901+static void reset_policy(void)
902+{
903+ FILE *fp2 = fopen(POLDIR "/policy", "r");
904+ FILE *fp1 = fopen(POLDIR "/policy", "w");
905+ if (!fp1 || !fp2) {
906+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
907+ exit(1);
908+ }
909+ while (1) {
910+ const int c = fgetc(fp2);
911+ if (c == EOF)
912+ break;
913+ fputc(c, fp1);
914+ if (c == '\n')
915+ fprintf(fp1, "delete ");
916+ }
917+ fclose(fp2);
918+ fclose(fp1);
919+
920+ /* Do not leave the init process in stopped state. */
921+ kill(1, SIGCONT);
922+
923+ /* Undo mount("/", MS_REC|MS_SHARED) made by systemd. */
924+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
925+}
926+
927+int main(int argc, char *argv[]) {
928+ int mac;
929+
930+ reset_policy();
931+ if (argc > 1)
932+ tests_start = atoi(argv[1]);
933+ for (mac = 0; mac < CCS_MAX_MAC_INDEX; mac++) {
934+ truncate_policy();
935+ add_policy3("0 acl ", ccs_mac_keywords[mac], "\n"
936+ " audit 0\n");
937+ check_policy_written(1);
938+ }
939+ for (mac = 0; mac < CCS_MAX_MAC_INDEX; mac++) {
940+ int p1;
941+ for (p1 = 0;
942+ p1 < sizeof(ccs_conditions) / sizeof(ccs_conditions[0]);
943+ p1++) {
944+ _Bool valid = 1;
945+ if (ccs_conditions[p1].left_type == CCS_TYPE_INVALID ||
946+ !(ccs_conditions[p1].available & F(mac)))
947+ valid = 0;
948+ check_righthand(mac, p1, valid);
949+ }
950+ }
951+ fprintf(stderr, "Test %u passed\n", tests_now - 1);
952+ return 0;
953+}
--- tags/caitsith-tools/0.2.1/kernel_test/Makefile (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/Makefile (revision 219)
@@ -0,0 +1,23 @@
1+include ../Include.make
2+
3+ALL_FILES = caitsith_param_test caitsith_log_test caitsith_parser_test caitsith_audit2cond_test caitsith_lsm_test caitsith_wildcard_test
4+
5+all: $(ALL_FILES)
6+
7+#
8+# Tools for kernel testing.
9+#
10+
11+BINDIR = '"'$(shell readlink -f /bin)'"'
12+POLDIR = '"/sys/kernel/security/caitsith"'
13+#POLDIR = '"/proc/caitsith"'
14+
15+.c:
16+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -DBINDIR=$(BINDIR) -DPOLDIR=$(POLDIR) -o $@ $<
17+
18+#
19+# Delete all test programs.
20+#
21+
22+clean:
23+ rm -f $(ALL_FILES)
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_log_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_log_test.c (revision 219)
@@ -0,0 +1,440 @@
1+#include <stdio.h>
2+#include <string.h>
3+#include <stdlib.h>
4+#include <sys/types.h>
5+#include <sys/stat.h>
6+#include <fcntl.h>
7+#include <unistd.h>
8+#include <linux/kdev_t.h>
9+#include <signal.h>
10+#include <sys/mount.h>
11+#include <sys/ioctl.h>
12+
13+#ifndef MS_MOVE
14+#define MS_MOVE 8192
15+#endif
16+#ifndef MS_REC
17+#define MS_REC 16384
18+#endif
19+#ifndef MS_UNBINDABLE
20+#define MS_UNBINDABLE (1<<17)
21+#endif
22+#ifndef MS_PRIVATE
23+#define MS_PRIVATE (1<<18)
24+#endif
25+#ifndef MS_SLAVE
26+#define MS_SLAVE (1<<19)
27+#endif
28+#ifndef MS_SHARED
29+#define MS_SHARED (1<<20)
30+#endif
31+
32+#include <asm/unistd.h>
33+static inline int pivot_root(const char *new_root, const char *put_old)
34+{
35+ return syscall(__NR_pivot_root, new_root, put_old);
36+}
37+
38+static _Bool debug = 0;
39+
40+static char *read_log(const char *expected_result, const char *expected_action)
41+{
42+ static int fd = EOF;
43+ static char buffer[16384];
44+ if (fd == EOF)
45+ fd = open(POLDIR "/audit", O_RDONLY);
46+ memset(buffer, 0, sizeof(buffer));
47+ while (buffer[0] = '\0', read(fd, buffer, sizeof(buffer) - 1) > 0) {
48+ char *cp1;
49+ char *cp2;
50+ if (debug)
51+ printf("Got '%s'\n", buffer);
52+ cp1 = strstr(buffer, " / ");
53+ if (buffer[0] != '#' || !cp1 || !strchr(buffer, '\n')) {
54+ fprintf(stderr,
55+ "Expected complete audit log, got '%s'\n",
56+ buffer);
57+ return NULL;
58+ }
59+ *cp1 = '\0';
60+ if (!strstr(buffer, expected_result))
61+ continue;
62+ cp1 += 3;
63+ cp2 = strchr(cp1, ' ');
64+ if (!cp2) {
65+ fprintf(stderr,
66+ "Expected complete audit log, got '%s'\n",
67+ cp1);
68+ return NULL;
69+ }
70+ *cp2++ = '\0';
71+ if (strcmp(expected_action, cp1))
72+ continue;
73+ return cp2;
74+ }
75+ fprintf(stderr, "Expected '%s' '%s', found none\n",
76+ expected_result, expected_action);
77+ return NULL;
78+}
79+
80+static void create_dummy(const char *path)
81+{
82+ close(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600));
83+}
84+
85+static void test_execute(void)
86+{
87+ char *args[3] = { "null", "--help", NULL };
88+ char *envs[3] = { "PATH=/", "HOME=/", NULL };
89+ create_dummy("/tmp/null");
90+ chmod("/tmp/null", 0700);
91+ execve("/tmp/null", args, envs);
92+}
93+
94+static void test_read(void)
95+{
96+ close(open("/dev/null", O_RDONLY));
97+}
98+
99+static void test_write(void)
100+{
101+ close(open("/dev/null", O_WRONLY));
102+}
103+
104+static void test_append(void)
105+{
106+ close(open("/dev/null", O_WRONLY | O_APPEND));
107+}
108+
109+static void test_create(void)
110+{
111+ unlink("/tmp/null");
112+ create_dummy("/tmp/null");
113+}
114+
115+static void test_unlink(void)
116+{
117+ create_dummy("/tmp/null");
118+ unlink("/tmp/null");
119+}
120+
121+static void test_getattr(void)
122+{
123+ struct stat buf;
124+ create_dummy("/tmp/null");
125+ stat("/tmp/null", &buf);
126+}
127+
128+static void test_mkdir(void)
129+{
130+ rmdir("/tmp/nulldir");
131+ mkdir("/tmp/nulldir", 0755);
132+}
133+
134+static void test_rmdir(void)
135+{
136+ mkdir("/tmp/nulldir", 0755);
137+ rmdir("/tmp/nulldir");
138+}
139+
140+static void test_mkfifo(void)
141+{
142+ unlink("/tmp/null");
143+ mknod("/tmp/null", S_IFIFO, 0);
144+}
145+
146+static void test_mksock(void)
147+{
148+ unlink("/tmp/null");
149+ mknod("/tmp/null", S_IFSOCK, 0);
150+}
151+
152+static void test_truncate(void)
153+{
154+ create_dummy("/tmp/null");
155+ truncate("/tmp/null", 0);
156+}
157+
158+static void test_symlink(void)
159+{
160+ unlink("/tmp/null");
161+ symlink("symlink'starget", "/tmp/null");
162+}
163+
164+static void test_mkblock(void)
165+{
166+ unlink("/tmp/null");
167+ mknod("/tmp/null", S_IFBLK, MKDEV(1, 0));
168+}
169+
170+static void test_mkchar(void)
171+{
172+ unlink("/tmp/null");
173+ mknod("/tmp/null", S_IFCHR, MKDEV(1, 3));
174+}
175+
176+static void test_link(void)
177+{
178+ create_dummy("/tmp/link");
179+ unlink("/tmp/newlink");
180+ link("/tmp/link", "/tmp/newlink");
181+}
182+
183+static void test_rename(void)
184+{
185+ link("/dev/null", "/dev/null0");
186+ rename("/dev/null0", "/dev/null1");
187+ unlink("/dev/null1");
188+}
189+
190+static void test_chmod(void)
191+{
192+ chmod("/dev/null", 0666);
193+}
194+
195+static void test_chown(void)
196+{
197+ chown("/dev/null", 0, -1);
198+}
199+
200+static void test_chgrp(void)
201+{
202+ chown("/dev/null", -1, 0);
203+}
204+
205+static void test_ioctl(void)
206+{
207+ int fd = open("/dev/null", 3);
208+ ioctl(fd, 0);
209+ close(fd);
210+}
211+
212+static void test_chroot(void)
213+{
214+ chroot("/");
215+}
216+
217+static void test_mount1(void)
218+{
219+ mount(NULL, "/tmp", "tmpfs", 0, "size=10%,uid=0,gid=0");
220+ umount("/tmp");
221+}
222+
223+static void test_mount2(void)
224+{
225+ mount("/", "/", NULL, MS_BIND, NULL);
226+}
227+
228+static void test_mount3(void)
229+{
230+ mount("/", "/", NULL, MS_MOVE, NULL);
231+}
232+
233+static void test_mount4(void)
234+{
235+ mount(NULL, "/", NULL, MS_REMOUNT | MS_NOATIME, NULL);
236+}
237+
238+static void test_unmount(void)
239+{
240+ umount2("/", 1);
241+}
242+
243+static void test_pivot_root(void)
244+{
245+ pivot_root("/", "/");
246+}
247+
248+static _Bool check_policy(const char *policy, const char *decision,
249+ const char *condition)
250+{
251+ static char buffer[16384];
252+ FILE *fp = fopen(POLDIR "/policy", "r");
253+ _Bool found = 0;
254+ if (!fp) {
255+ fprintf(stderr, "Can't read " POLDIR "/policy interface.\n");
256+ return 0;
257+ }
258+ memset(buffer, 0, sizeof(buffer));
259+ while (fgets(buffer, sizeof(buffer) - 1, fp)) {
260+ if (strstr(buffer, decision) && strstr(buffer, condition)) {
261+ found = 1;
262+ break;
263+ }
264+ }
265+ fclose(fp);
266+ if (found) {
267+ printf("%s %s%s\n", policy, decision, condition);
268+ return 1;
269+ }
270+ fprintf(stderr, "Can't find %s %s%s\n",
271+ policy, decision, condition);
272+ return 0;
273+}
274+
275+static void reset_policy(void)
276+{
277+ FILE *fp2 = fopen(POLDIR "/policy", "r");
278+ FILE *fp1 = fopen(POLDIR "/policy", "w");
279+ if (!fp1 || !fp2) {
280+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
281+ exit(1);
282+ }
283+ while (1) {
284+ const int c = fgetc(fp2);
285+ if (c == EOF)
286+ break;
287+ fputc(c, fp1);
288+ if (c == '\n')
289+ fprintf(fp1, "delete ");
290+ }
291+ fclose(fp2);
292+ fclose(fp1);
293+
294+ /* Do not leave the init process in stopped state. */
295+ kill(1, SIGCONT);
296+
297+ /* Undo mount("/", MS_REC|MS_SHARED) made by systemd. */
298+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
299+}
300+
301+int main(int argc, char *argv[])
302+{
303+ unsigned int i;
304+ char buffer[16384];
305+ struct {
306+ const char *action;
307+ void (*func) (void);
308+ } testcases[] = {
309+ { "execute", test_execute },
310+ { "read", test_read },
311+ { "write", test_write },
312+ { "append", test_append },
313+ { "create", test_create },
314+ { "unlink", test_unlink },
315+ { "getattr", test_getattr },
316+ { "mkdir", test_mkdir },
317+ { "rmdir", test_rmdir },
318+ { "mkfifo", test_mkfifo },
319+ { "mksock", test_mksock },
320+ { "truncate", test_truncate },
321+ { "symlink", test_symlink },
322+ { "mkblock", test_mkblock },
323+ { "mkchar", test_mkchar },
324+ { "link", test_link },
325+ { "rename", test_rename },
326+ { "chmod", test_chmod },
327+ { "chown", test_chown },
328+ { "chgrp", test_chgrp },
329+ { "ioctl", test_ioctl },
330+ { "chroot", test_chroot },
331+ { "mount", test_mount1 },
332+ { "mount", test_mount2 },
333+ { "mount", test_mount3 },
334+ { "mount", test_mount4 },
335+ { "unmount", test_unmount },
336+ { "pivot_root", test_pivot_root },
337+ /*
338+ acl inet_stream_bind
339+ acl inet_stream_listen
340+ acl inet_stream_connect
341+ acl inet_stream_accept
342+ acl inet_dgram_bind
343+ acl inet_dgram_send
344+ acl inet_dgram_recv
345+ acl inet_raw_bind
346+ acl inet_raw_send
347+ acl inet_raw_recv
348+ acl unix_stream_bind
349+ acl unix_stream_listen
350+ # acl unix_stream_connect
351+ acl unix_stream_accept
352+ acl unix_dgram_bind
353+ acl unix_dgram_send
354+ acl unix_dgram_recv
355+ acl unix_seqpacket_bind
356+ acl unix_seqpacket_listen
357+ acl unix_seqpacket_connect
358+ acl unix_seqpacket_accept
359+ # acl environ
360+ acl ptrace
361+ acl signal
362+ acl modify_policy
363+ # acl use_netlink_socket
364+ acl use_packet_socket
365+ acl use_reboot
366+ acl use_vhangup
367+ acl set_time
368+ acl set_priority
369+ acl set_hostname
370+ acl use_kernel_module
371+ acl use_new_kernel
372+ # acl auto_domain_transition
373+ acl manual_domain_transition
374+ */
375+ { NULL, NULL },
376+ };
377+ int fd_out = open(POLDIR "/policy", O_WRONLY);
378+ char *cp1;
379+ char *cp2;
380+
381+ reset_policy();
382+
383+ memset(buffer, 0, sizeof(buffer));
384+ if (fd_out == EOF) {
385+ fprintf(stderr, "Can't write " POLDIR "/policy interface.\n");
386+ goto out;
387+ }
388+ {
389+ int fd = open(POLDIR "/audit", O_RDONLY);
390+ char buffer[4096];
391+ while (read(fd, buffer, sizeof(buffer)) > 0);
392+ close(fd);
393+ }
394+ cp1 = "POLICY_VERSION=20120401\n"
395+ "quota memory audit 16777216\n"
396+ "quota memory query 1048576\n"
397+ "quota audit[1] allowed=1024 denied=1024 unmatched=1024\n";
398+ i = strlen(cp1);
399+ if (write(fd_out, cp1, i) != i) {
400+ fprintf(stderr, "Can't write " POLDIR "/policy interface.\n");
401+ goto out;
402+ }
403+ for (i = 0; testcases[i].action; i++) {
404+ int fd_in = open(POLDIR "/policy", O_RDONLY);
405+ if (fd_in == EOF) {
406+ fprintf(stderr,
407+ "Can't read " POLDIR "/policy interface.\n");
408+ goto out;
409+ }
410+ snprintf(buffer, sizeof(buffer) - 1, "0 acl %s task.pid=%u\n"
411+ " audit 1\n", testcases[i].action, getpid());
412+ write(fd_out, buffer, strlen(buffer));
413+ testcases[i].func();
414+ cp2 = read_log("result=unmatched", testcases[i].action);
415+ if (!cp2)
416+ goto out;
417+ cp1 = "0 deny ";
418+ write(fd_out, cp1, strlen(cp1));
419+ if (!strcmp(testcases[i].action, "rmdir")) {
420+ char *cp3 = strstr(cp2, " path.ino=");
421+ char *cp4 = cp3 ? strchr(cp3 + 1, ' ') : NULL;
422+ if (cp4)
423+ memmove(cp3, cp4, strlen(cp4) + 1);
424+ }
425+ write(fd_out, cp2, strlen(cp2));
426+ if (!check_policy(buffer, cp1, cp2))
427+ goto out;
428+ testcases[i].func();
429+ cp2 = read_log("result=denied", testcases[i].action);
430+ if (!cp2)
431+ goto out;
432+ snprintf(buffer, sizeof(buffer) - 1,
433+ "delete 0 acl %s task.pid=%u\n",
434+ testcases[i].action, getpid());
435+ write(fd_out, buffer, strlen(buffer));
436+ }
437+ return 0;
438+out:
439+ return 1;
440+}
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_param_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_param_test.c (revision 219)
@@ -0,0 +1,2040 @@
1+#include <stdio.h>
2+#include <stdlib.h>
3+#include <string.h>
4+#include <unistd.h>
5+#include <sys/types.h>
6+#include <sys/stat.h>
7+#include <sys/socket.h>
8+#include <netinet/in.h>
9+#include <sys/ptrace.h>
10+#include <sys/wait.h>
11+#include <linux/ip.h>
12+#include <fcntl.h>
13+#include <errno.h>
14+#include <sys/mount.h>
15+#ifndef MS_REC
16+#define MS_REC 16384
17+#endif
18+#ifndef MS_PRIVATE
19+#define MS_PRIVATE (1 << 18)
20+#endif
21+
22+static FILE *fp = NULL;
23+
24+static void set(const char *str)
25+{
26+ fprintf(fp, "%s\n", str);
27+ fflush(fp);
28+ errno = 0;
29+}
30+
31+static void unset(const char *str)
32+{
33+ fprintf(fp, "delete %s\n", str);
34+ fflush(fp);
35+ errno = 0;
36+}
37+
38+static void unset2(const char *str)
39+{
40+ const char *cp = str;
41+ while (*cp) {
42+ if (*cp++ != '\n')
43+ continue;
44+ fprintf(fp, "delete ");
45+ fwrite(str, cp - str, 1, fp);
46+ str = cp;
47+ }
48+ fprintf(fp, "delete %s\n", str);
49+ fflush(fp);
50+ errno = 0;
51+}
52+
53+static void check(const char *prompt, int result)
54+{
55+ int err = errno;
56+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
57+ if (!result) {
58+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
59+ {
60+ int fd2 = open(POLDIR "/self_domain", O_RDONLY);
61+ char c;
62+ fprintf(stderr, "task.domain=\"");
63+ while (read(fd2, &c, 1) == 1)
64+ fprintf(stderr, "%c", c);
65+ close(fd2);
66+ fprintf(stderr, "\"\n");
67+ }
68+ kill(1, SIGCONT);
69+ exit(1);
70+ }
71+ printf("\n");
72+ fflush(stdout);
73+}
74+
75+static void check_init(const char *prompt, const char *expected)
76+{
77+ int result;
78+ int fd = open(POLDIR "/.process_status", O_RDWR);
79+ char buffer[1024];
80+ char *cp;
81+ memset(buffer, 0, sizeof(buffer));
82+ kill(1, SIGHUP);
83+ sleep(1);
84+ write(fd, "1\n", 2);
85+ read(fd, buffer, sizeof(buffer) - 1);
86+ close(fd);
87+ cp = strchr(buffer, ' ');
88+ if (cp++)
89+ memmove(buffer, cp, strlen(cp) + 1);
90+ result = !strcmp(buffer, expected);
91+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
92+ if (!result) {
93+ fprintf(stderr, "Err: expected='%s' result='%s'\n",
94+ expected, buffer);
95+ kill(1, SIGCONT);
96+ exit(1);
97+ }
98+ printf("\n");
99+ fflush(stdout);
100+}
101+
102+static void test_task_transition(void)
103+{
104+ int fd = open(POLDIR "/self_domain", O_WRONLY);
105+ char *policy;
106+
107+ policy = "100 acl manual_domain_transition\n"
108+ "0 allow domain=\"domain\\$\"\n";
109+ set(policy);
110+ check(policy, write(fd, "domain0", 7) != EOF);
111+ check(policy, write(fd, "domain10", 8) != EOF);
112+ check(policy, write(fd, "domainXYX", 9) == EOF);
113+ check(policy, write(fd, "domain200", 9) != EOF);
114+ unset(policy);
115+
116+ policy = "100 acl auto_domain_transition\n"
117+ "0 allow task.pid=1 transition=\"<init3>\"\n";
118+ set(policy);
119+ check_init(policy, "<init3>");
120+ unset(policy);
121+
122+ policy = "100 acl auto_domain_transition\n"
123+ "0 allow task.pid=1 task.uid!=0 transition=\"<init2>\"\n";
124+ set(policy);
125+ check_init(policy, "<init3>");
126+ unset(policy);
127+
128+ policy = "100 acl auto_domain_transition\n"
129+ "0 allow task.pid=1 transition=\"<init>\"\n";
130+ set(policy);
131+ check_init(policy, "<init>");
132+ unset(policy);
133+
134+ close(fd);
135+}
136+
137+static void test_file_read(void)
138+{
139+ int fd;
140+ char *policy;
141+
142+ policy = "100 acl read\n";
143+ set(policy);
144+ fd = open("/dev/null", O_RDONLY);
145+ check(policy, fd != EOF);
146+ close(fd);
147+ unset(policy);
148+
149+ policy = "100 acl read\n"
150+ "0 allow\n"
151+ "1 deny\n";
152+ set(policy);
153+ fd = open("/dev/null", O_RDONLY);
154+ check(policy, fd != EOF);
155+ close(fd);
156+ unset(policy);
157+
158+ policy = "100 acl read\n"
159+ "0 deny\n"
160+ "1 allow\n";
161+ set(policy);
162+ fd = open("/dev/null", O_RDONLY);
163+ check(policy, fd == EOF);
164+ close(fd);
165+ unset(policy);
166+
167+ policy = "100 acl read path=\"/dev/null\"\n"
168+ "0 allow\n"
169+ "1 deny\n";
170+ set(policy);
171+ fd = open("/dev/null", O_RDONLY);
172+ check(policy, fd != EOF);
173+ close(fd);
174+ unset(policy);
175+
176+ policy = "100 acl read path=\"/dev/null\"\n"
177+ "0 deny\n"
178+ "1 allow\n";
179+ set(policy);
180+ fd = open("/dev/null", O_RDONLY);
181+ check(policy, fd == EOF);
182+ close(fd);
183+ unset(policy);
184+
185+ policy = "100 acl read\n"
186+ "0 allow path=\"/dev/null\"\n"
187+ "1 deny\n";
188+ set(policy);
189+ fd = open("/dev/null", O_RDONLY);
190+ check(policy, fd != EOF);
191+ close(fd);
192+ unset(policy);
193+
194+ policy = "100 acl read\n"
195+ "0 deny path=\"/dev/null\"\n"
196+ "1 allow\n";
197+ set(policy);
198+ fd = open("/dev/null", O_RDONLY);
199+ check(policy, fd == EOF);
200+ close(fd);
201+ unset(policy);
202+
203+ policy = "100 acl read\n"
204+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
205+ "1 deny\n";
206+ set(policy);
207+ fd = open("/dev/null", O_RDONLY);
208+ check(policy, fd != EOF);
209+ close(fd);
210+ unset(policy);
211+
212+ policy = "100 acl read\n"
213+ "0 deny path.type=char path.dev_major=1 path.dev_minor=3\n"
214+ "1 allow\n";
215+ set(policy);
216+ fd = open("/dev/null", O_RDONLY);
217+ check(policy, fd == EOF);
218+ close(fd);
219+ unset(policy);
220+
221+ policy = "100 acl read\n"
222+ "0 allow path.type=char path.dev_major=1 path.dev_minor!=3\n"
223+ "1 deny\n";
224+ set(policy);
225+ fd = open("/dev/null", O_RDONLY);
226+ check(policy, fd == EOF);
227+ close(fd);
228+ unset(policy);
229+
230+ policy = "100 acl read\n"
231+ "0 deny path.type=char path.dev_major=1 path.dev_minor!=3\n"
232+ "1 allow\n";
233+ set(policy);
234+ fd = open("/dev/null", O_RDONLY);
235+ check(policy, fd != EOF);
236+ close(fd);
237+ unset(policy);
238+
239+ policy = "string_group GROUP1 /dev/null\n"
240+ "100 acl read\n"
241+ "0 allow path=@GROUP1\n"
242+ "1 deny\n";
243+ set(policy);
244+ fd = open("/dev/null", O_RDONLY);
245+ check(policy, fd != EOF);
246+ close(fd);
247+ unset2(policy);
248+
249+ policy = "string_group GROUP1 /dev/null\n"
250+ "100 acl read\n"
251+ "0 deny path=@GROUP1\n"
252+ "1 allow\n";
253+ set(policy);
254+ fd = open("/dev/null", O_RDONLY);
255+ check(policy, fd == EOF);
256+ close(fd);
257+ unset2(policy);
258+
259+ policy = "string_group GROUP1 /dev/null\n"
260+ "100 acl read\n"
261+ "0 allow path!=@GROUP1\n"
262+ "1 deny\n";
263+ set(policy);
264+ fd = open("/dev/null", O_RDONLY);
265+ check(policy, fd == EOF);
266+ close(fd);
267+ unset2(policy);
268+
269+ policy = "string_group GROUP1 /dev/null\n"
270+ "100 acl read\n"
271+ "0 deny path!=@GROUP1\n"
272+ "1 allow\n";
273+ set(policy);
274+ fd = open("/dev/null", O_RDONLY);
275+ check(policy, fd != EOF);
276+ close(fd);
277+ unset2(policy);
278+
279+ policy = "string_group GROUP1 /dev/null\n"
280+ "number_group MAJOR 1\n"
281+ "number_group MINOR 3\n"
282+ "100 acl read\n"
283+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
284+ " path.dev_minor=@MINOR\n"
285+ "1 deny\n";
286+ set(policy);
287+ fd = open("/dev/null", O_RDONLY);
288+ check(policy, fd != EOF);
289+ close(fd);
290+ unset2(policy);
291+
292+ policy = "string_group GROUP1 /dev/null\n"
293+ "number_group MAJOR 1\n"
294+ "number_group MINOR 3\n"
295+ "100 acl read\n"
296+ "0 deny path=@GROUP1 path.dev_major=@MAJOR"
297+ " path.dev_minor=@MINOR\n"
298+ "1 allow\n";
299+ set(policy);
300+ fd = open("/dev/null", O_RDONLY);
301+ check(policy, fd == EOF);
302+ close(fd);
303+ unset2(policy);
304+
305+ policy = "string_group GROUP1 /dev/zero\n"
306+ "string_group GROUP1 /dev/null\n"
307+ "string_group GROUP1 /dev/urandom\n"
308+ "number_group MAJOR 0\n"
309+ "number_group MAJOR 2-255\n"
310+ "number_group MINOR 00-0x2\n"
311+ "number_group MINOR 255\n"
312+ "100 acl read\n"
313+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
314+ " path.dev_minor=@MINOR\n"
315+ "1 deny\n";
316+ set(policy);
317+ fd = open("/dev/null", O_RDONLY);
318+ check(policy, fd == EOF);
319+ close(fd);
320+ unset2(policy);
321+
322+ policy = "string_group GROUP1 /dev/zero\n"
323+ "string_group GROUP1 /dev/null\n"
324+ "string_group GROUP1 /dev/urandom\n"
325+ "number_group MAJOR 0\n"
326+ "number_group MAJOR 2-255\n"
327+ "number_group MINOR 00-0x2\n"
328+ "number_group MINOR 255\n"
329+ "100 acl read\n"
330+ "0 allow path=@GROUP1 path.dev_major!=@MAJOR"
331+ " path.dev_minor!=@MINOR\n"
332+ "1 deny\n";
333+ set(policy);
334+ fd = open("/dev/null", O_RDONLY);
335+ check(policy, fd != EOF);
336+ close(fd);
337+ unset2(policy);
338+}
339+
340+static void test_file_write(void)
341+{
342+ int fd;
343+ char *policy;
344+
345+ policy = "100 acl write\n"
346+ "0 allow\n"
347+ "100 acl append\n"
348+ "0 deny\n";
349+ set(policy);
350+ fd = open("/dev/null", O_WRONLY);
351+ check(policy, fd != EOF);
352+ close(fd);
353+ unset2(policy);
354+
355+ policy = "100 acl write\n"
356+ "0 deny\n"
357+ "100 acl append\n"
358+ "0 allow\n";
359+ set(policy);
360+ fd = open("/dev/null", O_WRONLY);
361+ check(policy, fd == EOF);
362+ close(fd);
363+ unset2(policy);
364+
365+ policy = "100 acl write\n"
366+ "0 allow\n"
367+ "100 acl append\n"
368+ "0 deny\n";
369+ set(policy);
370+ fd = open("/dev/null", O_WRONLY | O_APPEND);
371+ check(policy, fd == EOF);
372+ close(fd);
373+ unset2(policy);
374+
375+ policy = "100 acl write\n"
376+ "0 deny\n"
377+ "100 acl append\n"
378+ "0 append\n";
379+ set(policy);
380+ fd = open("/dev/null", O_WRONLY | O_APPEND);
381+ check(policy, fd != EOF);
382+ close(fd);
383+ unset2(policy);
384+
385+ policy = "100 acl write\n"
386+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
387+ "1 deny\n";
388+ set(policy);
389+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
390+ check(policy, fd != EOF);
391+ close(fd);
392+ unset(policy);
393+
394+ policy = "100 acl write\n"
395+ "0 allow path.type=char path.dev_major=1"
396+ " path.dev_minor=@MINOR\n"
397+ "1 deny\n";
398+ set(policy);
399+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
400+ check(policy, fd == EOF);
401+ close(fd);
402+ unset(policy);
403+
404+ policy = "100 acl write\n"
405+ "0 allow path.parent.uid=0 path.parent.perm=0755\n"
406+ "1 deny\n";
407+ set(policy);
408+ fd = open("/dev/null", O_WRONLY);
409+ check(policy, fd != EOF);
410+ close(fd);
411+ unset(policy);
412+
413+ policy = "100 acl write\n"
414+ "0 allow path.parent.uid=task.uid path.parent.gid=task.gid\n"
415+ "1 deny\n";
416+ set(policy);
417+ fd = open("/dev/null", O_WRONLY);
418+ check(policy, fd != EOF);
419+ close(fd);
420+ unset(policy);
421+
422+ policy = "100 acl write\n"
423+ "0 allow task.uid=path.parent.uid task.gid=path.parent.gid\n"
424+ "1 deny\n";
425+ set(policy);
426+ fd = open("/dev/null", O_WRONLY);
427+ check(policy, fd != EOF);
428+ close(fd);
429+ unset(policy);
430+}
431+
432+static void test_file_create(void)
433+{
434+ int fd;
435+ char *policy;
436+
437+ policy = "100 acl create\n"
438+ "0 allow path.uid=0\n"
439+ "1 deny\n";
440+ set(policy);
441+ unlink("/tmp/file");
442+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
443+ check(policy, fd == EOF);
444+ close(fd);
445+ unset(policy);
446+
447+ policy = "100 acl create\n"
448+ "0 allow path=\"/tmp/file\" path.parent.uid=0\n"
449+ "1 deny\n";
450+ set(policy);
451+ unlink("/tmp/file");
452+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
453+ check(policy, fd != EOF);
454+ close(fd);
455+ unset(policy);
456+
457+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
458+ "100 acl create\n"
459+ "0 allow path.parent.uid!=@GROUP1 perm=0600\n"
460+ "1 deny\n";
461+ set(policy);
462+ unlink("/tmp/file");
463+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
464+ check(policy, fd != EOF);
465+ close(fd);
466+ unset2(policy);
467+
468+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
469+ "100 acl create\n"
470+ "0 allow path.parent.uid!=@GROUP1 perm!=0600\n"
471+ "1 deny\n";
472+ set(policy);
473+ unlink("/tmp/file");
474+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
475+ check(policy, fd == EOF);
476+ close(fd);
477+ unset2(policy);
478+
479+ policy = "100 acl create\n"
480+ "0 allow path.parent.uid=task.uid\n"
481+ "1 deny\n";
482+ set(policy);
483+ unlink("/tmp/file");
484+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
485+ check(policy, fd != EOF);
486+ close(fd);
487+ unset(policy);
488+}
489+
490+static void test_file_unlink(void)
491+{
492+ char *policy;
493+
494+ policy = "100 acl unlink\n"
495+ "0 allow path.uid=0 path.uid=path.parent.uid\n"
496+ "1 deny\n";
497+ set(policy);
498+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
499+ check(policy, unlink("/tmp/file") == 0);
500+ unset(policy);
501+
502+ policy = "100 acl unlink\n"
503+ "0 deny path.uid=0 path.uid=path.parent.uid\n"
504+ "1 allow\n";
505+ set(policy);
506+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
507+ check(policy, unlink("/tmp/file") == EOF);
508+ unset(policy);
509+}
510+
511+static void test_file_link(void)
512+{
513+ char *policy;
514+
515+ policy = "100 acl link\n"
516+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
517+ " old_path.parent.ino=new_path.parent.ino\n"
518+ "1 deny\n";
519+ set(policy);
520+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
521+ unlink("/tmp/file2");
522+ check(policy, link("/tmp/file", "/tmp/file2") == 0);
523+ unset(policy);
524+
525+ policy = "100 acl link\n"
526+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
527+ "1 allow\n";
528+ set(policy);
529+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
530+ unlink("/tmp/file2");
531+ check(policy, link("/tmp/file", "/tmp/file2") == EOF);
532+ unset(policy);
533+}
534+
535+static void test_file_rename(void)
536+{
537+ char *policy;
538+
539+ policy = "100 acl rename\n"
540+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
541+ " old_path.parent.ino=new_path.parent.ino\n"
542+ "1 deny\n";
543+ set(policy);
544+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
545+ unlink("/tmp/file2");
546+ check(policy, rename("/tmp/file", "/tmp/file2") == 0);
547+ unset(policy);
548+
549+ policy = "100 acl rename\n"
550+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
551+ "1 allow\n";
552+ set(policy);
553+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
554+ unlink("/tmp/file2");
555+ check(policy, rename("/tmp/file", "/tmp/file2") == EOF);
556+ unset(policy);
557+}
558+
559+static void test_network_inet_stream(void)
560+{
561+ struct sockaddr_in addr1 = { };
562+ struct sockaddr_in addr2 = { };
563+ socklen_t size = sizeof(addr1);
564+ int fd1;
565+ int fd2;
566+ int fd3;
567+ char *policy;
568+ char buffer[1024];
569+ memset(buffer, 0, sizeof(buffer));
570+
571+ fd1 = socket(PF_INET, SOCK_STREAM, 0);
572+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
573+ addr1.sin_family = AF_INET;
574+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
575+
576+ policy = "100 acl inet_stream_bind\n"
577+ "0 allow ip=127.0.0.1 port!=0\n"
578+ "1 deny\n";
579+ set(policy);
580+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
581+ EOF);
582+ unset(policy);
583+
584+ policy = "100 acl inet_stream_bind\n"
585+ "0 allow ip!=127.0.0.1 port=0\n"
586+ "1 deny\n";
587+ set(policy);
588+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
589+ EOF);
590+ unset(policy);
591+
592+ policy = "100 acl inet_stream_bind\n"
593+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
594+ "1 deny\n";
595+ set(policy);
596+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
597+ EOF);
598+ unset(policy);
599+
600+ policy = "100 acl inet_stream_bind\n"
601+ "0 allow ip=127.0.0.1 port=0\n"
602+ "1 deny\n";
603+ set(policy);
604+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
605+ 0);
606+ unset(policy);
607+
608+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
609+
610+ snprintf(buffer, sizeof(buffer) - 1,
611+ "100 acl inet_stream_listen\n"
612+ "0 allow ip=127.0.0.1 port!=%u\n"
613+ "1 deny\n", ntohs(addr1.sin_port));
614+ policy = buffer;
615+ set(policy);
616+ check(policy, listen(fd1, 5) == EOF);
617+ unset(policy);
618+
619+ snprintf(buffer, sizeof(buffer) - 1,
620+ "100 acl inet_stream_listen\n"
621+ "0 allow ip=127.0.0.1 port=%u\n"
622+ "1 deny\n", ntohs(addr1.sin_port));
623+ policy = buffer;
624+ set(policy);
625+ check(policy, listen(fd1, 5) == 0);
626+ unset(policy);
627+
628+ snprintf(buffer, sizeof(buffer) - 1,
629+ "100 acl inet_stream_connect\n"
630+ "0 allow ip=127.0.0.1 port!=%u\n"
631+ "1 deny\n", ntohs(addr1.sin_port));
632+ policy = buffer;
633+ set(policy);
634+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
635+ == EOF);
636+ unset(policy);
637+
638+ snprintf(buffer, sizeof(buffer) - 1,
639+ "100 acl inet_stream_connect\n"
640+ "0 allow ip=127.0.0.1 port=%u\n"
641+ "1 deny\n", ntohs(addr1.sin_port));
642+ policy = buffer;
643+ set(policy);
644+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
645+ == 0);
646+ unset(policy);
647+
648+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
649+
650+ snprintf(buffer, sizeof(buffer) - 1,
651+ "100 acl inet_stream_accept\n"
652+ "0 allow ip=127.0.0.1 port=%u\n"
653+ "1 deny\n", ntohs(addr2.sin_port));
654+ policy = buffer;
655+ set(policy);
656+ fd3 = accept(fd1, NULL, 0);
657+ check(policy, fd3 != EOF);
658+ close(fd3);
659+ unset(policy);
660+
661+ snprintf(buffer, sizeof(buffer) - 1,
662+ "100 acl inet_stream_connect\n"
663+ "0 allow ip=127.0.0.1 port=%u\n"
664+ "1 deny\n", ntohs(addr1.sin_port));
665+ policy = buffer;
666+ set(policy);
667+ close(fd2);
668+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
669+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
670+ == 0);
671+ unset(policy);
672+
673+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
674+
675+ snprintf(buffer, sizeof(buffer) - 1,
676+ "100 acl inet_stream_accept\n"
677+ "0 allow ip=127.0.0.1 port!=%u\n"
678+ "1 deny\n", ntohs(addr2.sin_port));
679+ policy = buffer;
680+ set(policy);
681+ fd3 = accept(fd1, NULL, 0);
682+ check(policy, fd3 == EOF);
683+ close(fd3);
684+ unset(policy);
685+
686+ close(fd1);
687+ close(fd2);
688+}
689+
690+static void test_network_inet_dgram(void)
691+{
692+ struct sockaddr_in addr1 = { };
693+ struct sockaddr_in addr2 = { };
694+ socklen_t size = sizeof(addr1);
695+ int fd1;
696+ int fd2;
697+ char c;
698+ char *policy;
699+ char buffer[1024];
700+ memset(buffer, 0, sizeof(buffer));
701+
702+ fd1 = socket(PF_INET, SOCK_DGRAM, 0);
703+ fd2 = socket(PF_INET, SOCK_DGRAM, 0);
704+ addr1.sin_family = AF_INET;
705+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
706+
707+ policy = "100 acl inet_dgram_bind\n"
708+ "0 allow ip=127.0.0.1 port!=0\n"
709+ "1 deny\n";
710+ set(policy);
711+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
712+ EOF);
713+ unset(policy);
714+
715+ policy = "100 acl inet_dgram_bind\n"
716+ "0 allow ip!=127.0.0.1 port=0\n"
717+ "1 deny\n";
718+ set(policy);
719+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
720+ EOF);
721+ unset(policy);
722+
723+ policy = "100 acl inet_dgram_bind\n"
724+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
725+ "1 deny\n";
726+ set(policy);
727+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
728+ EOF);
729+ unset(policy);
730+
731+ policy = "100 acl inet_dgram_bind\n"
732+ "0 allow ip=127.0.0.1 port=0\n"
733+ "1 deny\n";
734+ set(policy);
735+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
736+ 0);
737+ unset(policy);
738+
739+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
740+
741+ snprintf(buffer, sizeof(buffer) - 1,
742+ "100 acl inet_dgram_send\n"
743+ "0 allow ip=127.0.0.1 port!=%u\n"
744+ "1 deny\n", ntohs(addr1.sin_port));
745+ policy = buffer;
746+ set(policy);
747+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
748+ == EOF);
749+ unset(policy);
750+
751+ snprintf(buffer, sizeof(buffer) - 1,
752+ "100 acl inet_dgram_send\n"
753+ "0 allow ip=127.0.0.1 port=%u\n"
754+ "1 deny\n", ntohs(addr1.sin_port));
755+ policy = buffer;
756+ set(policy);
757+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
758+ == 0);
759+ unset(policy);
760+
761+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
762+
763+ snprintf(buffer, sizeof(buffer) - 1,
764+ "100 acl inet_dgram_send\n"
765+ "0 allow ip=127.0.0.1 port=%u\n"
766+ "1 deny\n", ntohs(addr1.sin_port));
767+ policy = buffer;
768+ set(policy);
769+ check(policy, send(fd2, "", 1, 0) != EOF);
770+ unset(policy);
771+
772+ snprintf(buffer, sizeof(buffer) - 1,
773+ "100 acl inet_dgram_recv\n"
774+ "0 allow ip=127.0.0.1 port=%u\n"
775+ "1 deny\n", ntohs(addr2.sin_port));
776+ policy = buffer;
777+ set(policy);
778+ check(policy, recv(fd1, &c, 1, 0) != EOF);
779+ unset(policy);
780+
781+ snprintf(buffer, sizeof(buffer) - 1,
782+ "100 acl inet_dgram_send\n"
783+ "0 allow ip=127.0.0.1 port=%u\n"
784+ "1 deny\n", ntohs(addr1.sin_port));
785+ policy = buffer;
786+ set(policy);
787+ check(policy, send(fd2, "", 1, 0) != EOF);
788+ unset(policy);
789+
790+ snprintf(buffer, sizeof(buffer) - 1,
791+ "100 acl inet_dgram_recv\n"
792+ "0 allow ip=127.0.0.1 port!=%u\n"
793+ "1 deny\n", ntohs(addr2.sin_port));
794+ policy = buffer;
795+ set(policy);
796+ check(policy, recv(fd1, &c, 1, 0) == EOF);
797+ unset(policy);
798+
799+ snprintf(buffer, sizeof(buffer) - 1,
800+ "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
801+ "100 acl inet_dgram_send\n"
802+ "0 allow ip=@LOCALHOST port=%u\n"
803+ "1 deny\n", ntohs(addr1.sin_port));
804+ policy = buffer;
805+ set(policy);
806+ check(policy, send(fd2, "", 1, 0) != EOF);
807+ unset2(policy);
808+
809+ snprintf(buffer, sizeof(buffer) - 1,
810+ "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
811+ "100 acl inet_dgram_recv\n"
812+ "0 allow ip!=@LOCALHOST port=%u\n"
813+ "1 deny\n", ntohs(addr2.sin_port));
814+ policy = buffer;
815+ set(policy);
816+ check(policy, recv(fd1, &c, 1, 0) == EOF);
817+ unset2(policy);
818+
819+ close(fd1);
820+ close(fd2);
821+}
822+
823+static void test_network_inet_raw(void)
824+{
825+ struct sockaddr_in addr = { };
826+ static struct iphdr ip = { };
827+ int fd1;
828+ int fd2;
829+ char *policy;
830+ fd1 = socket(PF_INET, SOCK_RAW, 1);
831+ fd2 = socket(PF_INET, SOCK_RAW, 1);
832+ addr.sin_family = AF_INET;
833+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
834+ ip.version = 4;
835+ ip.ihl = sizeof(struct iphdr) / 4;
836+ ip.protocol = IPPROTO_RAW;
837+ ip.daddr = htonl(INADDR_LOOPBACK);
838+ ip.saddr = ip.daddr;
839+
840+ policy = "100 acl inet_raw_bind\n"
841+ "0 allow ip=127.0.0.1 proto!=1\n"
842+ "1 deny\n";
843+ set(policy);
844+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
845+ EOF);
846+ unset(policy);
847+
848+ policy = "100 acl inet_raw_bind\n"
849+ "0 allow ip!=127.0.0.1 proto=1\n"
850+ "1 deny\n";
851+ set(policy);
852+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
853+ EOF);
854+ unset(policy);
855+
856+ policy = "100 acl inet_raw_bind\n"
857+ "0 allow ip=127.0.0.1 proto=1 path.uid=task.uid\n"
858+ "1 deny\n";
859+ set(policy);
860+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
861+ EOF);
862+ unset(policy);
863+
864+ policy = "100 acl inet_raw_bind\n"
865+ "0 allow ip=127.0.0.1 proto=1\n"
866+ "1 deny\n";
867+ set(policy);
868+ check(policy, bind(fd2, (struct sockaddr *) &addr, sizeof(addr)) ==
869+ 0);
870+ unset(policy);
871+
872+ policy = "100 acl inet_raw_send\n"
873+ "0 allow ip=127.0.0.1 proto!=1\n"
874+ "1 deny\n";
875+ set(policy);
876+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
877+ == EOF);
878+ unset(policy);
879+
880+ policy = "100 acl inet_raw_send\n"
881+ "0 allow ip=127.0.0.1 proto=1\n"
882+ "1 deny\n";
883+ set(policy);
884+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
885+ == 0);
886+ unset(policy);
887+
888+ policy = "100 acl inet_raw_send\n"
889+ "0 allow ip=127.0.0.1 proto=1\n"
890+ "1 deny\n";
891+ set(policy);
892+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
893+ unset(policy);
894+
895+ policy = "100 acl inet_raw_recv\n"
896+ "0 allow ip=127.0.0.1 proto=1\n"
897+ "1 deny\n";
898+ set(policy);
899+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) != EOF);
900+ unset(policy);
901+
902+ policy = "100 acl inet_raw_send\n"
903+ "0 allow ip=127.0.0.1 proto=1\n"
904+ "1 deny\n";
905+ set(policy);
906+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
907+ unset(policy);
908+
909+ policy = "100 acl inet_raw_recv\n"
910+ "0 allow ip=127.0.0.1 proto!=1\n"
911+ "1 deny\n";
912+ set(policy);
913+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) == EOF);
914+ unset(policy);
915+
916+ policy = "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
917+ "100 acl inet_raw_send\n"
918+ "0 allow ip=@LOCALHOST proto=1\n"
919+ "1 deny\n";
920+ set(policy);
921+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
922+ unset2(policy);
923+
924+ policy = "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
925+ "100 acl inet_raw_recv\n"
926+ "0 allow ip!=@LOCALHOST proto=1\n"
927+ "1 deny\n";
928+ set(policy);
929+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) == EOF);
930+ unset2(policy);
931+
932+ close(fd1);
933+ close(fd2);
934+}
935+
936+static void test_network_inet6_stream(void)
937+{
938+ struct sockaddr_in6 addr1 = { };
939+ struct sockaddr_in6 addr2 = { };
940+ socklen_t size = sizeof(addr1);
941+ int fd1;
942+ int fd2;
943+ int fd3;
944+ char *policy;
945+ char buffer[1024];
946+ memset(buffer, 0, sizeof(buffer));
947+
948+ fd1 = socket(PF_INET6, SOCK_STREAM, 0);
949+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
950+ addr1.sin6_family = AF_INET6;
951+ addr1.sin6_addr = in6addr_loopback;
952+
953+ policy = "100 acl inet_stream_bind\n"
954+ "0 allow ip=::1 port!=0\n"
955+ "1 deny\n";
956+ set(policy);
957+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
958+ EOF);
959+ unset(policy);
960+
961+ policy = "100 acl inet_stream_bind\n"
962+ "0 allow ip!=::1 port=0\n"
963+ "1 deny\n";
964+ set(policy);
965+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
966+ EOF);
967+ unset(policy);
968+
969+ policy = "100 acl inet_stream_bind\n"
970+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
971+ "1 deny\n";
972+ set(policy);
973+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
974+ EOF);
975+ unset(policy);
976+
977+ policy = "100 acl inet_stream_bind\n"
978+ "0 allow ip=::1 port=0\n"
979+ "1 deny\n";
980+ set(policy);
981+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
982+ 0);
983+ unset(policy);
984+
985+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
986+
987+ snprintf(buffer, sizeof(buffer) - 1,
988+ "100 acl inet_stream_listen\n"
989+ "0 allow ip=::1 port!=%u\n"
990+ "1 deny\n", ntohs(addr1.sin6_port));
991+ policy = buffer;
992+ set(policy);
993+ check(policy, listen(fd1, 5) == EOF);
994+ unset(policy);
995+
996+ snprintf(buffer, sizeof(buffer) - 1,
997+ "100 acl inet_stream_listen\n"
998+ "0 allow ip=::1 port=%u\n"
999+ "1 deny\n", ntohs(addr1.sin6_port));
1000+ policy = buffer;
1001+ set(policy);
1002+ check(policy, listen(fd1, 5) == 0);
1003+ unset(policy);
1004+
1005+ snprintf(buffer, sizeof(buffer) - 1,
1006+ "100 acl inet_stream_connect\n"
1007+ "0 allow ip=::1 port!=%u\n"
1008+ "1 deny\n", ntohs(addr1.sin6_port));
1009+ policy = buffer;
1010+ set(policy);
1011+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1012+ == EOF);
1013+ unset(policy);
1014+
1015+ snprintf(buffer, sizeof(buffer) - 1,
1016+ "100 acl inet_stream_connect\n"
1017+ "0 allow ip=::1 port=%u\n"
1018+ "1 deny\n", ntohs(addr1.sin6_port));
1019+ policy = buffer;
1020+ set(policy);
1021+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1022+ == 0);
1023+ unset(policy);
1024+
1025+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1026+
1027+ snprintf(buffer, sizeof(buffer) - 1,
1028+ "100 acl inet_stream_accept\n"
1029+ "0 allow ip=::1 port=%u\n"
1030+ "1 deny\n", ntohs(addr2.sin6_port));
1031+ policy = buffer;
1032+ set(policy);
1033+ fd3 = accept(fd1, NULL, 0);
1034+ check(policy, fd3 != EOF);
1035+ close(fd3);
1036+ unset(policy);
1037+
1038+ snprintf(buffer, sizeof(buffer) - 1,
1039+ "100 acl inet_stream_connect\n"
1040+ "0 allow ip=::1 port=%u\n"
1041+ "1 deny\n", ntohs(addr1.sin6_port));
1042+ policy = buffer;
1043+ set(policy);
1044+ close(fd2);
1045+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
1046+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1047+ == 0);
1048+ unset(policy);
1049+
1050+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1051+
1052+ snprintf(buffer, sizeof(buffer) - 1,
1053+ "100 acl inet_stream_accept\n"
1054+ "0 allow ip=::1 port!=%u\n"
1055+ "1 deny\n", ntohs(addr2.sin6_port));
1056+ policy = buffer;
1057+ set(policy);
1058+ fd3 = accept(fd1, NULL, 0);
1059+ check(policy, fd3 == EOF);
1060+ close(fd3);
1061+ unset(policy);
1062+
1063+ close(fd1);
1064+ close(fd2);
1065+}
1066+
1067+static void test_network_inet6_dgram(void)
1068+{
1069+ struct sockaddr_in6 addr1 = { };
1070+ struct sockaddr_in6 addr2 = { };
1071+ socklen_t size = sizeof(addr1);
1072+ int fd1;
1073+ int fd2;
1074+ char c;
1075+ char *policy;
1076+ char buffer[1024];
1077+ memset(buffer, 0, sizeof(buffer));
1078+
1079+ fd1 = socket(PF_INET6, SOCK_DGRAM, 0);
1080+ fd2 = socket(PF_INET6, SOCK_DGRAM, 0);
1081+ addr1.sin6_family = AF_INET6;
1082+ addr1.sin6_addr = in6addr_loopback;
1083+
1084+ policy = "100 acl inet_dgram_bind\n"
1085+ "0 allow ip=::1 port!=0\n"
1086+ "1 deny\n";
1087+ set(policy);
1088+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1089+ EOF);
1090+ unset(policy);
1091+
1092+ policy = "100 acl inet_dgram_bind\n"
1093+ "0 allow ip!=::1 port=0\n"
1094+ "1 deny\n";
1095+ set(policy);
1096+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1097+ EOF);
1098+ unset(policy);
1099+
1100+ policy = "100 acl inet_dgram_bind\n"
1101+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
1102+ "1 deny\n";
1103+ set(policy);
1104+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1105+ EOF);
1106+ unset(policy);
1107+
1108+ policy = "100 acl inet_dgram_bind\n"
1109+ "0 allow ip=::1 port=0\n"
1110+ "1 deny\n";
1111+ set(policy);
1112+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1113+ 0);
1114+ unset(policy);
1115+
1116+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
1117+
1118+ snprintf(buffer, sizeof(buffer) - 1,
1119+ "100 acl inet_dgram_send\n"
1120+ "0 allow ip=::1 port!=%u\n"
1121+ "1 deny\n", ntohs(addr1.sin6_port));
1122+ policy = buffer;
1123+ set(policy);
1124+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1125+ == EOF);
1126+ unset(policy);
1127+
1128+ snprintf(buffer, sizeof(buffer) - 1,
1129+ "100 acl inet_dgram_send\n"
1130+ "0 allow ip=::1 port=%u\n"
1131+ "1 deny\n", ntohs(addr1.sin6_port));
1132+ policy = buffer;
1133+ set(policy);
1134+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1135+ == 0);
1136+ unset(policy);
1137+
1138+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1139+
1140+ snprintf(buffer, sizeof(buffer) - 1,
1141+ "100 acl inet_dgram_send\n"
1142+ "0 allow ip=::1 port=%u\n"
1143+ "1 deny\n", ntohs(addr1.sin6_port));
1144+ policy = buffer;
1145+ set(policy);
1146+ check(policy, send(fd2, "", 1, 0) != EOF);
1147+ unset(policy);
1148+
1149+ snprintf(buffer, sizeof(buffer) - 1,
1150+ "100 acl inet_dgram_recv\n"
1151+ "0 allow ip=::1 port=%u\n"
1152+ "1 deny\n", ntohs(addr2.sin6_port));
1153+ policy = buffer;
1154+ set(policy);
1155+ check(policy, recv(fd1, &c, 1, 0) != EOF);
1156+ unset(policy);
1157+
1158+ snprintf(buffer, sizeof(buffer) - 1,
1159+ "100 acl inet_dgram_send\n"
1160+ "0 allow ip=::1 port=%u\n"
1161+ "1 deny\n", ntohs(addr1.sin6_port));
1162+ policy = buffer;
1163+ set(policy);
1164+ check(policy, send(fd2, "", 1, 0) != EOF);
1165+ unset(policy);
1166+
1167+ snprintf(buffer, sizeof(buffer) - 1,
1168+ "100 acl inet_dgram_recv\n"
1169+ "0 allow ip=::1 port!=%u\n"
1170+ "1 deny\n", ntohs(addr2.sin6_port));
1171+ policy = buffer;
1172+ set(policy);
1173+ check(policy, recv(fd1, &c, 1, 0) == EOF);
1174+ unset(policy);
1175+
1176+ snprintf(buffer, sizeof(buffer) - 1,
1177+ "ip_group LOCALHOST ::-::ffff\n"
1178+ "100 acl inet_dgram_send\n"
1179+ "0 allow ip=@LOCALHOST port=%u\n"
1180+ "1 deny\n", ntohs(addr1.sin6_port));
1181+ policy = buffer;
1182+ set(policy);
1183+ check(policy, send(fd2, "", 1, 0) != EOF);
1184+ unset2(policy);
1185+
1186+ snprintf(buffer, sizeof(buffer) - 1,
1187+ "ip_group LOCALHOST ::-::ffff\n"
1188+ "100 acl inet_dgram_recv\n"
1189+ "0 allow ip!=@LOCALHOST port=%u\n"
1190+ "1 deny\n", ntohs(addr2.sin6_port));
1191+ policy = buffer;
1192+ set(policy);
1193+ check(policy, recv(fd1, &c, 1, 0) == EOF);
1194+ unset2(policy);
1195+
1196+ close(fd1);
1197+ close(fd2);
1198+}
1199+
1200+static void test_capability(void)
1201+{
1202+ char *policy;
1203+
1204+ policy = "100 acl set_priority\n"
1205+ "0 allow task.uid=0\n"
1206+ "1 deny\n";
1207+ set(policy);
1208+ check(policy, nice(0) == 0);
1209+ unset(policy);
1210+
1211+ policy = "100 acl set_priority\n"
1212+ "0 allow task.uid=task.gid task.type!=execute_handler\n"
1213+ "1 deny\n";
1214+ set(policy);
1215+ check(policy, nice(0) == 0);
1216+ unset(policy);
1217+
1218+ policy = "100 acl set_priority\n"
1219+ "0 deny task.uid=0\n"
1220+ "1 allow\n";
1221+ set(policy);
1222+ check(policy, nice(0) == EOF);
1223+ unset(policy);
1224+
1225+ policy = "100 acl set_priority\n"
1226+ "0 allow task.uid=task.gid task.type=execute_handler\n"
1227+ "1 deny\n";
1228+ set(policy);
1229+ check(policy, nice(0) == EOF);
1230+ unset(policy);
1231+}
1232+
1233+static void detach_init(void)
1234+{
1235+ int i;
1236+ for (i = 0; i < 2; i++) {
1237+ ptrace(PTRACE_DETACH, 1, NULL, NULL);
1238+ kill(1, SIGCONT);
1239+ sleep(1);
1240+ }
1241+}
1242+
1243+static void test_ptrace(void)
1244+{
1245+ char *policy;
1246+
1247+ policy = "100 acl ptrace\n"
1248+ "0 allow cmd=1 domain!=\"foo\"\n"
1249+ "0 allow cmd=17\n"
1250+ "1 deny\n";
1251+ set(policy);
1252+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1253+ unset(policy);
1254+ detach_init();
1255+
1256+ policy = "100 acl ptrace\n"
1257+ "0 allow cmd=16 domain=\"foo\"\n"
1258+ "0 allow cmd=17\n"
1259+ "1 deny\n";
1260+ set(policy);
1261+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1262+ unset(policy);
1263+ detach_init();
1264+
1265+ policy = "100 acl ptrace\n"
1266+ "0 allow cmd=16 domain!=\"foo\"\n"
1267+ "0 allow cmd=17\n"
1268+ "1 deny\n";
1269+ set(policy);
1270+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == 0);
1271+ unset(policy);
1272+ detach_init();
1273+
1274+ policy = "string_group DOMAINS <init>\n"
1275+ "100 acl ptrace\n"
1276+ "0 allow cmd=16 domain=@DOMAINS\n"
1277+ "0 allow cmd=17\n"
1278+ "1 deny\n";
1279+ set(policy);
1280+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == 0);
1281+ unset2(policy);
1282+ detach_init();
1283+
1284+ policy = "string_group DOMAINS <init>\n"
1285+ "100 acl ptrace\n"
1286+ "0 allow cmd=16 domain!=@DOMAINS\n"
1287+ "0 allow cmd=17\n"
1288+ "1 deny\n";
1289+ set(policy);
1290+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1291+ unset2(policy);
1292+ detach_init();
1293+}
1294+
1295+static void test_signal(void)
1296+{
1297+ char *policy;
1298+
1299+ policy = "100 acl signal task.domain=\"domain200\"\n"
1300+ "0 allow sig=1 task.uid=0\n"
1301+ "1 deny\n";
1302+ set(policy);
1303+ check(policy, kill(1, 1) == 0);
1304+ unset(policy);
1305+
1306+ policy = "100 acl signal task.domain=\"domain200\"\n"
1307+ "0 allow sig!=1 task.uid=0\n"
1308+ "1 deny\n";
1309+ set(policy);
1310+ check(policy, kill(1, 1) == EOF);
1311+ unset(policy);
1312+
1313+ policy = "100 acl signal\n"
1314+ "0 allow task.domain!=\"domain200\"\n"
1315+ "0 allow sig=1\n"
1316+ "1 deny\n";
1317+ set(policy);
1318+ check(policy, kill(1, 1) == 0);
1319+ unset(policy);
1320+
1321+ policy = "100 acl signal\n"
1322+ "0 deny task.domain=\"domain200\"\n"
1323+ "0 allow\n";
1324+ set(policy);
1325+ check(policy, kill(1, 1) == EOF);
1326+ unset(policy);
1327+
1328+ policy = "100 acl signal\n"
1329+ "0 deny sig=1 task.domain=\"domain200\"\n"
1330+ "0 allow\n";
1331+ set(policy);
1332+ check(policy, kill(1, 1) == EOF);
1333+ unset(policy);
1334+}
1335+
1336+static int fork_exec(char *envp[])
1337+{
1338+ int ret_ignored;
1339+ int pipe_fd[2] = { EOF, EOF };
1340+ int err = 0;
1341+ pid_t pid;
1342+ if (pipe(pipe_fd)) {
1343+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1344+ exit(1);
1345+ }
1346+ pid = fork();
1347+ if (pid == 0) {
1348+ char *argv[2] = { BINDIR "/true", NULL };
1349+ execve(BINDIR "/true", argv, envp);
1350+ err = errno;
1351+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1352+ _exit(0);
1353+ }
1354+ close(pipe_fd[1]);
1355+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1356+ close(pipe_fd[0]);
1357+ wait(NULL);
1358+ errno = err;
1359+ return err ? EOF : 0;
1360+}
1361+
1362+static void test_environ(void)
1363+{
1364+ char *policy;
1365+ char *envp[2];
1366+ envp[1] = NULL;
1367+
1368+ policy = "100 acl environ name=\"PATH2\"\n"
1369+ "0 allow value=\"/\"\n"
1370+ "1 deny\n";
1371+ set(policy);
1372+ envp[0] = "PATH2=/";
1373+ check(policy, fork_exec(envp) == 0);
1374+ unset(policy);
1375+
1376+ policy = "100 acl environ name=\"PATH2\"\n"
1377+ "0 allow value!=\"/\"\n"
1378+ "1 deny\n";
1379+ set(policy);
1380+ envp[0] = "PATH2=/";
1381+ check(policy, fork_exec(envp) == EOF);
1382+ unset(policy);
1383+
1384+ policy = "100 acl environ name=\"PATH2\"\n"
1385+ "0 deny value!=\"/\"\n"
1386+ "1 allow\n";
1387+ set(policy);
1388+ envp[0] = "PATH2=/";
1389+ check(policy, fork_exec(envp) == 0);
1390+ unset(policy);
1391+
1392+ policy = "100 acl environ name=\"PATH2\"\n"
1393+ "0 deny value=\"/\"\n"
1394+ "1 allow\n";
1395+ set(policy);
1396+ envp[0] = "PATH2=/";
1397+ check(policy, fork_exec(envp) == EOF);
1398+ unset(policy);
1399+
1400+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1401+ "0 allow envp[\"PATH2\"]=\"/\"\n"
1402+ "1 deny\n";
1403+ set(policy);
1404+ envp[0] = "PATH2=/";
1405+ check(policy, fork_exec(envp) == 0);
1406+ unset(policy);
1407+
1408+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1409+ "0 allow envp[\"PATH2\"]!=\"/\"\n"
1410+ "1 deny\n";
1411+ set(policy);
1412+ envp[0] = "PATH2=/";
1413+ check(policy, fork_exec(envp) == EOF);
1414+ unset(policy);
1415+
1416+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1417+ "0 allow envp[\"PATH2\"]!=NULL\n"
1418+ "1 deny\n";
1419+ set(policy);
1420+ envp[0] = "PATH2";
1421+ check(policy, fork_exec(envp) == 0);
1422+ unset(policy);
1423+
1424+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1425+ "0 allow envp[\"PATH2\"]!=NULL\n"
1426+ "1 deny\n";
1427+ set(policy);
1428+ envp[0] = "PATH2=";
1429+ check(policy, fork_exec(envp) == 0);
1430+ unset(policy);
1431+
1432+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1433+ "0 allow envp[\"PATH2\"]!=NULL\n"
1434+ "1 deny\n";
1435+ set(policy);
1436+ envp[0] = "PATH2=/";
1437+ check(policy, fork_exec(envp) == 0);
1438+ unset(policy);
1439+
1440+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1441+ "0 allow envp[\"PATH2\"]=NULL\n"
1442+ "1 deny\n";
1443+ set(policy);
1444+ envp[0] = "PATH2";
1445+ check(policy, fork_exec(envp) == EOF);
1446+ unset(policy);
1447+
1448+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1449+ "0 allow envp[\"PATH2\"]=NULL\n"
1450+ "1 deny\n";
1451+ set(policy);
1452+ envp[0] = "PATH2=";
1453+ check(policy, fork_exec(envp) == EOF);
1454+ unset(policy);
1455+
1456+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1457+ "0 allow envp[\"PATH2\"]=NULL\n"
1458+ "1 deny\n";
1459+ set(policy);
1460+ envp[0] = "PATH2=/";
1461+ check(policy, fork_exec(envp) == EOF);
1462+ unset(policy);
1463+
1464+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1465+ "0 allow envp[\"\"]=NULL\n"
1466+ "1 deny\n";
1467+ set(policy);
1468+ envp[0] = "";
1469+ check(policy, fork_exec(envp) == EOF);
1470+ unset(policy);
1471+
1472+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1473+ "0 allow envp[\"\"]!=NULL\n"
1474+ "1 deny\n";
1475+ set(policy);
1476+ envp[0] = "";
1477+ check(policy, fork_exec(envp) == 0);
1478+ unset(policy);
1479+
1480+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1481+ "0 allow envp[\"\"]!=NULL\n"
1482+ "1 deny\n";
1483+ set(policy);
1484+ envp[0] = "=";
1485+ check(policy, fork_exec(envp) == 0);
1486+ unset(policy);
1487+
1488+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1489+ "0 allow envp[\"\"]!=NULL\n"
1490+ "1 deny\n";
1491+ set(policy);
1492+ envp[0] = "=/";
1493+ check(policy, fork_exec(envp) == 0);
1494+ unset(policy);
1495+}
1496+
1497+static int fork_exec2(char *argv[], char *envp[])
1498+{
1499+ int ret_ignored;
1500+ int pipe_fd[2] = { EOF, EOF };
1501+ int err = 0;
1502+ pid_t pid;
1503+ if (pipe(pipe_fd)) {
1504+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1505+ exit(1);
1506+ }
1507+ pid = fork();
1508+ if (pid == 0) {
1509+ execve(BINDIR "/true", argv, envp);
1510+ err = errno;
1511+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1512+ _exit(0);
1513+ }
1514+ close(pipe_fd[1]);
1515+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1516+ close(pipe_fd[0]);
1517+ wait(NULL);
1518+ errno = err;
1519+ return err ? EOF : 0;
1520+}
1521+
1522+static void test_file_execute(void)
1523+{
1524+ char *policy;
1525+ char *argv[5];
1526+ char *envp[5];
1527+ memset(argv, 0, sizeof(argv));
1528+ memset(envp, 0, sizeof(envp));
1529+
1530+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1531+ "0 allow argc=1\n"
1532+ "1 deny\n";
1533+ set(policy);
1534+ argv[0]="true";
1535+ check(policy, fork_exec2(argv, envp) == 0);
1536+ unset(policy);
1537+
1538+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1539+ "0 allow argc!=1\n"
1540+ "1 deny\n";
1541+ set(policy);
1542+ check(policy, fork_exec2(argv, envp) == EOF);
1543+ unset(policy);
1544+
1545+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1546+ "0 deny argc!=1\n"
1547+ "1 allow\n";
1548+ set(policy);
1549+ check(policy, fork_exec2(argv, envp) == 0);
1550+ unset(policy);
1551+
1552+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1553+ "0 deny argc=1\n"
1554+ "1 allow\n";
1555+ set(policy);
1556+ check(policy, fork_exec2(argv, envp) == EOF);
1557+ unset(policy);
1558+
1559+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1560+ "0 deny argv[0]!=\"true\"\n"
1561+ "1 allow\n";
1562+ set(policy);
1563+ check(policy, fork_exec2(argv, envp) == 0);
1564+ unset(policy);
1565+
1566+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1567+ "0 deny argv[0]=\"true\"\n"
1568+ "1 allow\n";
1569+ set(policy);
1570+ check(policy, fork_exec2(argv, envp) == EOF);
1571+ unset(policy);
1572+
1573+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1574+ "0 allow argv[0]!=\"true\"\n"
1575+ "1 deny\n";
1576+ set(policy);
1577+ check(policy, fork_exec2(argv, envp) == EOF);
1578+ unset(policy);
1579+
1580+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1581+ "0 allow argv[0]=\"true\"\n"
1582+ "1 deny\n";
1583+ set(policy);
1584+ check(policy, fork_exec2(argv, envp) == 0);
1585+ unset(policy);
1586+
1587+ policy = "string_group EXEC_ARGV0 false\n"
1588+ "string_group EXEC_ARGV0 true\n"
1589+ "100 acl execute path=\"" BINDIR "/true\"\n"
1590+ "0 deny argv[0]!=@EXEC_ARGV0\n"
1591+ "1 allow\n";
1592+ set(policy);
1593+ check(policy, fork_exec2(argv, envp) == 0);
1594+ unset2(policy);
1595+
1596+ policy = "string_group EXEC_ARGV0 false\n"
1597+ "string_group EXEC_ARGV0 true\n"
1598+ "100 acl execute path=\"" BINDIR "/true\"\n"
1599+ "0 deny argv[0]=@EXEC_ARGV0\n"
1600+ "1 allow\n";
1601+ set(policy);
1602+ check(policy, fork_exec2(argv, envp) == EOF);
1603+ unset2(policy);
1604+
1605+ policy = "string_group EXEC_ARGV0 false\n"
1606+ "string_group EXEC_ARGV0 true\n"
1607+ "100 acl execute path=\"" BINDIR "/true\"\n"
1608+ "0 allow argv[0]!=@EXEC_ARGV0\n"
1609+ "1 deny\n";
1610+ set(policy);
1611+ check(policy, fork_exec2(argv, envp) == EOF);
1612+ unset2(policy);
1613+
1614+ policy = "string_group EXEC_ARGV0 false\n"
1615+ "string_group EXEC_ARGV0 true\n"
1616+ "100 acl execute path=\"" BINDIR "/true\"\n"
1617+ "0 allow argv[0]=@EXEC_ARGV0\n"
1618+ "1 deny\n";
1619+ set(policy);
1620+ check(policy, fork_exec2(argv, envp) == 0);
1621+ unset2(policy);
1622+
1623+
1624+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1625+ "0 allow envc=1\n"
1626+ "1 deny\n";
1627+ set(policy);
1628+ envp[0]="PATH=/";
1629+ check(policy, fork_exec2(argv, envp) == 0);
1630+ unset(policy);
1631+
1632+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1633+ "0 allow envc!=1\n"
1634+ "1 deny\n";
1635+ set(policy);
1636+ check(policy, fork_exec2(argv, envp) == EOF);
1637+ unset(policy);
1638+
1639+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1640+ "0 deny envc!=1\n"
1641+ "1 allow\n";
1642+ set(policy);
1643+ check(policy, fork_exec2(argv, envp) == 0);
1644+ unset(policy);
1645+
1646+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1647+ "0 deny envc=1\n"
1648+ "1 allow\n";
1649+ set(policy);
1650+ check(policy, fork_exec2(argv, envp) == EOF);
1651+ unset(policy);
1652+
1653+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1654+ "0 deny envp[\"PATH\"]!=\"/\"\n"
1655+ "1 allow\n";
1656+ set(policy);
1657+ check(policy, fork_exec2(argv, envp) == 0);
1658+ unset(policy);
1659+
1660+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1661+ "0 deny envp[\"PATH\"]=\"/\"\n"
1662+ "1 allow\n";
1663+ set(policy);
1664+ check(policy, fork_exec2(argv, envp) == EOF);
1665+ unset(policy);
1666+
1667+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1668+ "0 allow envp[\"PATH\"]!=\"/\"\n"
1669+ "1 deny\n";
1670+ set(policy);
1671+ check(policy, fork_exec2(argv, envp) == EOF);
1672+ unset(policy);
1673+
1674+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1675+ "0 allow envp[\"PATH\"]=\"/\"\n"
1676+ "1 deny\n";
1677+ set(policy);
1678+ check(policy, fork_exec2(argv, envp) == 0);
1679+ unset(policy);
1680+
1681+ policy = "string_group PATH_VALUES " BINDIR "\n"
1682+ "string_group PATH_VALUES /\n"
1683+ "string_group PATH_VALUES /sbin\n"
1684+ "100 acl execute path=\"" BINDIR "/true\"\n"
1685+ "0 deny envp[\"PATH\"]!=@PATH_VALUES\n"
1686+ "1 allow\n";
1687+ set(policy);
1688+ check(policy, fork_exec2(argv, envp) == 0);
1689+ unset2(policy);
1690+
1691+ policy = "string_group PATH_VALUES " BINDIR "\n"
1692+ "string_group PATH_VALUES /\n"
1693+ "string_group PATH_VALUES /sbin\n"
1694+ "100 acl execute path=\"" BINDIR "/true\"\n"
1695+ "0 deny envp[\"PATH\"]=@PATH_VALUES\n"
1696+ "1 allow\n";
1697+ set(policy);
1698+ check(policy, fork_exec2(argv, envp) == EOF);
1699+ unset2(policy);
1700+
1701+ policy = "string_group PATH_VALUES " BINDIR "\n"
1702+ "string_group PATH_VALUES /\n"
1703+ "string_group PATH_VALUES /sbin\n"
1704+ "100 acl execute path=\"" BINDIR "/true\"\n"
1705+ "0 allow envp[\"PATH\"]!=@PATH_VALUES\n"
1706+ "1 deny\n";
1707+ set(policy);
1708+ check(policy, fork_exec2(argv, envp) == EOF);
1709+ unset2(policy);
1710+
1711+ policy = "string_group PATH_VALUES " BINDIR "\n"
1712+ "string_group PATH_VALUES /\n"
1713+ "string_group PATH_VALUES /sbin\n"
1714+ "100 acl execute path=\"" BINDIR "/true\"\n"
1715+ "0 allow envp[\"PATH\"]=@PATH_VALUES\n"
1716+ "1 deny\n";
1717+ set(policy);
1718+ check(policy, fork_exec2(argv, envp) == 0);
1719+ unset2(policy);
1720+
1721+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1722+ "0 deny envp[\"PATH\"]!=NULL\n"
1723+ "1 allow\n";
1724+ set(policy);
1725+ check(policy, fork_exec2(argv, envp) == EOF);
1726+ unset(policy);
1727+
1728+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1729+ "0 deny envp[\"PATH\"]=NULL\n"
1730+ "1 allow\n";
1731+ set(policy);
1732+ check(policy, fork_exec2(argv, envp) == 0);
1733+ unset(policy);
1734+
1735+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1736+ "0 allow envp[\"PATH\"]!=NULL\n"
1737+ "1 deny\n";
1738+ set(policy);
1739+ check(policy, fork_exec2(argv, envp) == 0);
1740+ unset(policy);
1741+
1742+ policy = "100 acl execute path=\"" BINDIR "/true\"\n"
1743+ "0 allow envp[\"PATH\"]=NULL\n"
1744+ "1 deny\n";
1745+ set(policy);
1746+ check(policy, fork_exec2(argv, envp) == EOF);
1747+ unset(policy);
1748+}
1749+
1750+static void test_file_misc(void)
1751+{
1752+ int fd;
1753+ const pid_t pid = getpid();
1754+ char buffer[1024];
1755+ memset(buffer, 0, sizeof(buffer));
1756+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1757+ "10 allow path!=NULL\n"
1758+ "20 deny\n", pid);
1759+ set(buffer);
1760+ fd = open("/dev/null", O_RDONLY);
1761+ check(buffer, fd != EOF);
1762+ close(fd);
1763+ unset(buffer);
1764+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1765+ "10 allow path=NULL\n"
1766+ "20 deny\n", pid);
1767+ set(buffer);
1768+ fd = open("/dev/null", O_RDONLY);
1769+ check(buffer, fd == EOF);
1770+ close(fd);
1771+ unset(buffer);
1772+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1773+ "10 deny path=NULL\n"
1774+ "20 allow\n", pid);
1775+ set(buffer);
1776+ fd = open("/dev/null", O_RDONLY);
1777+ check(buffer, fd != EOF);
1778+ close(fd);
1779+ unset(buffer);
1780+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1781+ "10 deny path!=NULL\n"
1782+ "20 allow\n", pid);
1783+ set(buffer);
1784+ fd = open("/dev/null", O_RDONLY);
1785+ check(buffer, fd == EOF);
1786+ close(fd);
1787+ unset(buffer);
1788+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1789+ "10 allow path=path\n"
1790+ "20 deny\n", pid);
1791+ set(buffer);
1792+ fd = open("/dev/null", O_RDONLY);
1793+ check(buffer, fd != EOF);
1794+ close(fd);
1795+ unset(buffer);
1796+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1797+ "10 allow path!=path\n"
1798+ "20 deny\n", pid);
1799+ set(buffer);
1800+ fd = open("/dev/null", O_RDONLY);
1801+ check(buffer, fd == EOF);
1802+ close(fd);
1803+ unset(buffer);
1804+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1805+ "10 deny path!=path\n"
1806+ "20 allow\n", pid);
1807+ set(buffer);
1808+ fd = open("/dev/null", O_RDONLY);
1809+ check(buffer, fd != EOF);
1810+ close(fd);
1811+ unset(buffer);
1812+ snprintf(buffer, sizeof(buffer) - 1, "100 acl read task.pid=%u\n"
1813+ "10 deny path=path\n"
1814+ "20 allow\n", pid);
1815+ set(buffer);
1816+ fd = open("/dev/null", O_RDONLY);
1817+ check(buffer, fd == EOF);
1818+ close(fd);
1819+ unset(buffer);
1820+ snprintf(buffer, sizeof(buffer) - 1,
1821+ "string_group STRING_GROUP1 /dev/null\n"
1822+ "100 acl read task.pid=%u\n"
1823+ "10 allow path=@STRING_GROUP1\n"
1824+ "20 deny\n", pid);
1825+ set(buffer);
1826+ fd = open("/dev/null", O_RDONLY);
1827+ check(buffer, fd != EOF);
1828+ close(fd);
1829+ unset2(buffer);
1830+ snprintf(buffer, sizeof(buffer) - 1,
1831+ "string_group STRING_GROUP1 /dev/null\n"
1832+ "100 acl read task.pid=%u\n"
1833+ "10 allow path!=@STRING_GROUP1\n"
1834+ "20 deny\n", pid);
1835+ set(buffer);
1836+ fd = open("/dev/null", O_RDONLY);
1837+ check(buffer, fd == EOF);
1838+ close(fd);
1839+ unset2(buffer);
1840+ snprintf(buffer, sizeof(buffer) - 1,
1841+ "string_group STRING_GROUP1 /dev/null\n"
1842+ "100 acl read task.pid=%u\n"
1843+ "10 deny path!=@STRING_GROUP1\n"
1844+ "20 allow\n", pid);
1845+ set(buffer);
1846+ fd = open("/dev/null", O_RDONLY);
1847+ check(buffer, fd != EOF);
1848+ close(fd);
1849+ unset2(buffer);
1850+ snprintf(buffer, sizeof(buffer) - 1,
1851+ "string_group STRING_GROUP1 /dev/null\n"
1852+ "100 acl read task.pid=%u\n"
1853+ "10 deny path=@STRING_GROUP1\n"
1854+ "20 allow\n", pid);
1855+ set(buffer);
1856+ fd = open("/dev/null", O_RDONLY);
1857+ check(buffer, fd == EOF);
1858+ close(fd);
1859+ unset2(buffer);
1860+ snprintf(buffer, sizeof(buffer) - 1,
1861+ "number_group NUMBER_GROUP1 0666\n"
1862+ "100 acl read task.pid=%u\n"
1863+ "10 deny path.perm!=@NUMBER_GROUP1\n"
1864+ "20 allow\n", pid);
1865+ set(buffer);
1866+ fd = open("/dev/null", O_RDONLY);
1867+ check(buffer, fd != EOF);
1868+ close(fd);
1869+ unset2(buffer);
1870+ snprintf(buffer, sizeof(buffer) - 1,
1871+ "number_group NUMBER_GROUP1 0666\n"
1872+ "100 acl read task.pid=%u\n"
1873+ "10 deny path.perm=@NUMBER_GROUP1\n"
1874+ "20 allow\n", pid);
1875+ set(buffer);
1876+ fd = open("/dev/null", O_RDONLY);
1877+ check(buffer, fd == EOF);
1878+ close(fd);
1879+ unset2(buffer);
1880+ snprintf(buffer, sizeof(buffer) - 1,
1881+ "100 acl read task.pid=%u\n"
1882+ "10 deny path.perm!=owner_read\n"
1883+ "20 allow\n", pid);
1884+ set(buffer);
1885+ fd = open("/dev/null", O_RDONLY);
1886+ check(buffer, fd != EOF);
1887+ close(fd);
1888+ unset2(buffer);
1889+ snprintf(buffer, sizeof(buffer) - 1,
1890+ "100 acl read task.pid=%u\n"
1891+ "10 deny path.perm=owner_read\n"
1892+ "20 allow\n", pid);
1893+ set(buffer);
1894+ fd = open("/dev/null", O_RDONLY);
1895+ check(buffer, fd == EOF);
1896+ close(fd);
1897+ unset2(buffer);
1898+ snprintf(buffer, sizeof(buffer) - 1,
1899+ "100 acl read task.pid=%u\n"
1900+ "10 deny path.perm!=group_write\n"
1901+ "20 allow\n", pid);
1902+ set(buffer);
1903+ fd = open("/dev/null", O_RDONLY);
1904+ check(buffer, fd != EOF);
1905+ close(fd);
1906+ unset2(buffer);
1907+ snprintf(buffer, sizeof(buffer) - 1,
1908+ "100 acl read task.pid=%u\n"
1909+ "10 deny path.perm=group_write\n"
1910+ "20 allow\n", pid);
1911+ set(buffer);
1912+ fd = open("/dev/null", O_RDONLY);
1913+ check(buffer, fd == EOF);
1914+ close(fd);
1915+ unset2(buffer);
1916+ snprintf(buffer, sizeof(buffer) - 1,
1917+ "100 acl read task.pid=%u\n"
1918+ "10 deny path.perm!=others_read\n"
1919+ "20 allow\n", pid);
1920+ set(buffer);
1921+ fd = open("/dev/null", O_RDONLY);
1922+ check(buffer, fd != EOF);
1923+ close(fd);
1924+ unset2(buffer);
1925+ snprintf(buffer, sizeof(buffer) - 1,
1926+ "100 acl read task.pid=%u\n"
1927+ "10 deny path.perm=others_read\n"
1928+ "20 allow\n", pid);
1929+ set(buffer);
1930+ fd = open("/dev/null", O_RDONLY);
1931+ check(buffer, fd == EOF);
1932+ close(fd);
1933+ unset2(buffer);
1934+ snprintf(buffer, sizeof(buffer) - 1,
1935+ "100 acl read task.pid=%u\n"
1936+ "10 deny path.perm=path.parent.perm\n"
1937+ "20 allow\n", pid);
1938+ set(buffer);
1939+ fd = open("/dev/null", O_RDONLY);
1940+ check(buffer, fd != EOF);
1941+ close(fd);
1942+ unset2(buffer);
1943+ snprintf(buffer, sizeof(buffer) - 1,
1944+ "100 acl read task.pid=%u\n"
1945+ "10 deny path.perm!=path.parent.perm\n"
1946+ "20 allow\n", pid);
1947+ set(buffer);
1948+ fd = open("/dev/null", O_RDONLY);
1949+ check(buffer, fd == EOF);
1950+ close(fd);
1951+ unset2(buffer);
1952+ snprintf(buffer, sizeof(buffer) - 1,
1953+ "100 acl execute task.ppid=%u\n"
1954+ "10 allow path=exec\n"
1955+ "20 deny\n", pid);
1956+ set(buffer);
1957+ check(buffer, fork_exec(NULL) == 0);
1958+ unset(buffer);
1959+ snprintf(buffer, sizeof(buffer) - 1,
1960+ "100 acl execute task.ppid=%u\n"
1961+ "10 allow path!=exec\n"
1962+ "20 deny\n", pid);
1963+ set(buffer);
1964+ check(buffer, fork_exec(NULL) == EOF);
1965+ unset(buffer);
1966+ snprintf(buffer, sizeof(buffer) - 1,
1967+ "100 acl execute task.ppid=%u\n"
1968+ "10 deny path=exec\n"
1969+ "20 allow\n", pid);
1970+ set(buffer);
1971+ check(buffer, fork_exec(NULL) == EOF);
1972+ unset(buffer);
1973+ snprintf(buffer, sizeof(buffer) - 1,
1974+ "100 acl execute task.ppid=%u\n"
1975+ "10 deny path!=exec\n"
1976+ "20 allow\n", pid);
1977+ set(buffer);
1978+ check(buffer, fork_exec(NULL) == 0);
1979+ unset(buffer);
1980+}
1981+
1982+static void reset_policy(void)
1983+{
1984+ FILE *fp2 = fopen(POLDIR "/policy", "r");
1985+ FILE *fp1 = fopen(POLDIR "/policy", "w");
1986+ if (!fp1 || !fp2) {
1987+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
1988+ exit(1);
1989+ }
1990+ while (1) {
1991+ const int c = fgetc(fp2);
1992+ if (c == EOF)
1993+ break;
1994+ fputc(c, fp1);
1995+ if (c == '\n')
1996+ fprintf(fp1, "delete ");
1997+ }
1998+ fclose(fp2);
1999+ fclose(fp1);
2000+
2001+ /* Do not leave the init process in stopped state. */
2002+ kill(1, SIGCONT);
2003+
2004+ /* Undo mount("/", MS_REC|MS_SHARED) made by systemd. */
2005+ mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
2006+}
2007+
2008+int main(int argc, char *argv[])
2009+{
2010+ reset_policy();
2011+
2012+ fp = fopen(POLDIR "/policy", "w");
2013+ if (!fp) {
2014+ fprintf(stderr, " Can't open " POLDIR "/policy\n");
2015+ return 1;
2016+ }
2017+ fprintf(fp, "quota audit[0]"
2018+ " allowed=1024 unmatched=1024 denied=1024\n");
2019+ fflush(fp);
2020+
2021+ test_task_transition();
2022+ test_file_read();
2023+ test_file_write();
2024+ test_file_create();
2025+ test_file_unlink();
2026+ test_file_link();
2027+ test_file_rename();
2028+ test_network_inet_stream();
2029+ test_network_inet_dgram();
2030+ test_network_inet_raw();
2031+ test_network_inet6_stream();
2032+ test_network_inet6_dgram();
2033+ test_capability();
2034+ test_ptrace();
2035+ test_signal();
2036+ test_environ();
2037+ test_file_execute();
2038+ test_file_misc();
2039+ return 0;
2040+}
--- tags/caitsith-tools/0.2.1/kernel_test/caitsith_wildcard_test.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/kernel_test/caitsith_wildcard_test.c (revision 219)
@@ -0,0 +1,692 @@
1+#include <stdio.h>
2+#include <string.h>
3+#include <stdlib.h>
4+
5+#define bool _Bool
6+#define true 1
7+#define false 0
8+#define u32 unsigned int
9+#define u8 unsigned char
10+
11+struct cs_path_info {
12+ const char *name;
13+ u32 hash; /* = full_name_hash(name, strlen(name)) */
14+ u32 total_len; /* = strlen(name) */
15+ u32 const_len; /* = cs_const_part_length(name) */
16+};
17+
18+static void out_of_memory(void)
19+{
20+ fprintf(stderr, "Out of memory\n");
21+ exit(1);
22+}
23+
24+/* Copied from Linux kernel source code. */
25+static unsigned int full_name_hash(const unsigned char *name, unsigned int len)
26+{
27+ unsigned long hash = 0;
28+ while (len--) {
29+ unsigned long c = *name++;
30+ hash = (hash + (c << 4) + (c >> 4)) * 11;
31+ }
32+ return (unsigned int) hash;
33+}
34+
35+/**
36+ * cs_pathcmp - strcmp() for "struct cs_path_info" structure.
37+ *
38+ * @a: Pointer to "struct cs_path_info".
39+ * @b: Pointer to "struct cs_path_info".
40+ *
41+ * Returns true if @a != @b, false otherwise.
42+ */
43+static inline bool cs_pathcmp(const struct cs_path_info *a,
44+ const struct cs_path_info *b)
45+{
46+ return a->hash != b->hash || strcmp(a->name, b->name);
47+}
48+
49+/**
50+ * cs_const_part_length - Evaluate the initial length without a pattern in a token.
51+ *
52+ * @filename: The string to evaluate. Maybe NULL.
53+ *
54+ * Returns the initial length without a pattern in @filename.
55+ */
56+static int cs_const_part_length(const char *filename)
57+{
58+ char c;
59+ int len = 0;
60+ if (!filename)
61+ return 0;
62+ while (1) {
63+ c = *filename++;
64+ if (!c)
65+ break;
66+ if (c != '\\') {
67+ len++;
68+ continue;
69+ }
70+ c = *filename++;
71+ switch (c) {
72+ case '0': /* "\ooo" */
73+ case '1':
74+ case '2':
75+ case '3':
76+ c = *filename++;
77+ if (c < '0' || c > '7')
78+ break;
79+ c = *filename++;
80+ if (c < '0' || c > '7')
81+ break;
82+ len += 4;
83+ continue;
84+ }
85+ break;
86+ }
87+ return len;
88+}
89+
90+/**
91+ * cs_fill_path_info - Fill in "struct cs_path_info" members.
92+ *
93+ * @ptr: Pointer to "struct cs_path_info" to fill in.
94+ *
95+ * Returns nothing.
96+ *
97+ * The caller sets "struct cs_path_info"->name.
98+ */
99+static void cs_fill_path_info(struct cs_path_info *ptr)
100+{
101+ const char *name = ptr->name;
102+ const int len = strlen(name);
103+ ptr->total_len = len;
104+ ptr->const_len = cs_const_part_length(name);
105+ ptr->hash = full_name_hash((const unsigned char *) name, len);
106+}
107+
108+/**
109+ * cs_byte_range - Check whether the string is a \ooo style octal value.
110+ *
111+ * @str: Pointer to the string.
112+ *
113+ * Returns true if @str is a \ooo style octal value, false otherwise.
114+ */
115+static bool cs_byte_range(const char *str)
116+{
117+ return *str >= '0' && *str++ <= '3' &&
118+ *str >= '0' && *str++ <= '7' &&
119+ *str >= '0' && *str <= '7';
120+}
121+
122+/**
123+ * cs_decimal - Check whether the character is a decimal character.
124+ *
125+ * @c: The character to check.
126+ *
127+ * Returns true if @c is a decimal character, false otherwise.
128+ */
129+static bool cs_decimal(const char c)
130+{
131+ return c >= '0' && c <= '9';
132+}
133+
134+/**
135+ * cs_hexadecimal - Check whether the character is a hexadecimal character.
136+ *
137+ * @c: The character to check.
138+ *
139+ * Returns true if @c is a hexadecimal character, false otherwise.
140+ */
141+static bool cs_hexadecimal(const char c)
142+{
143+ return (c >= '0' && c <= '9') ||
144+ (c >= 'A' && c <= 'F') ||
145+ (c >= 'a' && c <= 'f');
146+}
147+
148+/**
149+ * cs_alphabet_char - Check whether the character is an alphabet.
150+ *
151+ * @c: The character to check.
152+ *
153+ * Returns true if @c is an alphabet character, false otherwise.
154+ */
155+static bool cs_alphabet_char(const char c)
156+{
157+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
158+}
159+
160+/**
161+ * cs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
162+ *
163+ * @filename: The start of string to check.
164+ * @filename_end: The end of string to check.
165+ * @pattern: The start of pattern to compare.
166+ * @pattern_end: The end of pattern to compare.
167+ *
168+ * Returns true if @filename matches @pattern, false otherwise.
169+ */
170+static bool cs_file_matches_pattern2(const char *filename,
171+ const char *filename_end,
172+ const char *pattern,
173+ const char *pattern_end)
174+{
175+ while (filename < filename_end && pattern < pattern_end) {
176+ char c;
177+ if (*pattern != '\\') {
178+ if (*filename++ != *pattern++)
179+ return false;
180+ continue;
181+ }
182+ c = *filename;
183+ pattern++;
184+ switch (*pattern) {
185+ int i;
186+ int j;
187+ case '?':
188+ if (c == '/') {
189+ return false;
190+ } else if (c == '\\') {
191+ if (cs_byte_range(filename + 1))
192+ filename += 3;
193+ else
194+ return false;
195+ }
196+ break;
197+ case '+':
198+ if (!cs_decimal(c))
199+ return false;
200+ break;
201+ case 'x':
202+ if (!cs_hexadecimal(c))
203+ return false;
204+ break;
205+ case 'a':
206+ if (!cs_alphabet_char(c))
207+ return false;
208+ break;
209+ case '0':
210+ case '1':
211+ case '2':
212+ case '3':
213+ if (c == '\\' && cs_byte_range(filename + 1)
214+ && !strncmp(filename + 1, pattern, 3)) {
215+ filename += 3;
216+ pattern += 2;
217+ break;
218+ }
219+ return false; /* Not matched. */
220+ case '*':
221+ case '@':
222+ for (i = 0; i <= filename_end - filename; i++) {
223+ if (cs_file_matches_pattern2(filename + i,
224+ filename_end,
225+ pattern + 1,
226+ pattern_end))
227+ return true;
228+ c = filename[i];
229+ if (c == '.' && *pattern == '@')
230+ break;
231+ if (c != '\\')
232+ continue;
233+ if (cs_byte_range(filename + i + 1))
234+ i += 3;
235+ else
236+ break; /* Bad pattern. */
237+ }
238+ return false; /* Not matched. */
239+ default:
240+ j = 0;
241+ c = *pattern;
242+ if (c == '$') {
243+ while (cs_decimal(filename[j]))
244+ j++;
245+ } else if (c == 'X') {
246+ while (cs_hexadecimal(filename[j]))
247+ j++;
248+ } else if (c == 'A') {
249+ while (cs_alphabet_char(filename[j]))
250+ j++;
251+ }
252+ for (i = 1; i <= j; i++) {
253+ if (cs_file_matches_pattern2(filename + i,
254+ filename_end,
255+ pattern + 1,
256+ pattern_end))
257+ return true;
258+ }
259+ return false; /* Not matched or bad pattern. */
260+ }
261+ filename++;
262+ pattern++;
263+ }
264+ /* Ignore trailing "\*" and "\@" in @pattern. */
265+ while (*pattern == '\\' &&
266+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
267+ pattern += 2;
268+ return filename == filename_end && pattern == pattern_end;
269+}
270+
271+/**
272+ * cs_file_matches_pattern - Pattern matching without '/' character.
273+ *
274+ * @filename: The start of string to check.
275+ * @filename_end: The end of string to check.
276+ * @pattern: The start of pattern to compare.
277+ * @pattern_end: The end of pattern to compare.
278+ *
279+ * Returns true if @filename matches @pattern, false otherwise.
280+ */
281+static bool cs_file_matches_pattern(const char *filename,
282+ const char *filename_end,
283+ const char *pattern,
284+ const char *pattern_end)
285+{
286+ const char *pattern_start = pattern;
287+ bool first = true;
288+ bool result;
289+ if (filename_end > filename && memchr(filename, '/', filename_end - filename)) {
290+ printf("'");
291+ fwrite(filename, 1, filename_end - filename, stdout);
292+ printf("', '");
293+ fwrite(pattern, 1, pattern_end - pattern, stdout);
294+ printf("'\n");
295+ }
296+ if (pattern_end > pattern && memchr(pattern, '/', pattern_end - pattern)) {
297+ printf("'");
298+ fwrite(filename, 1, filename_end - filename, stdout);
299+ printf("', '");
300+ fwrite(pattern, 1, pattern_end - pattern, stdout);
301+ printf("'\n");
302+ }
303+ while (pattern < pattern_end - 1) {
304+ /* Split at "\-" pattern. */
305+ if (*pattern++ != '\\' || *pattern++ != '-')
306+ continue;
307+ result = cs_file_matches_pattern2(filename, filename_end,
308+ pattern_start, pattern - 2);
309+ if (first)
310+ result = !result;
311+ if (result)
312+ return false;
313+ first = false;
314+ pattern_start = pattern;
315+ }
316+ result = cs_file_matches_pattern2(filename, filename_end,
317+ pattern_start, pattern_end);
318+ return first ? result : !result;
319+}
320+
321+/**
322+ * cs_path_matches_pattern2 - Do pathname pattern matching.
323+ *
324+ * @f: The start of string to check.
325+ * @p: The start of pattern to compare.
326+ *
327+ * Returns true if @f matches @p, false otherwise.
328+ */
329+static bool cs_path_matches_pattern2(const char *f, const char *p)
330+{
331+ const char *f_delimiter;
332+ const char *p_delimiter;
333+ while (*f && *p) {
334+ f_delimiter = strchr(f + 1, '/');
335+ if (!f_delimiter)
336+ f_delimiter = f + strlen(f);
337+ p_delimiter = strchr(p + 1, '/');
338+ if (!p_delimiter)
339+ p_delimiter = p + strlen(p);
340+ if (*p == '/' && *(p + 1) == '\\') {
341+ if (*(p + 2) == '(') {
342+ /* Check zero repetition. */
343+ if (cs_path_matches_pattern2(f, p_delimiter))
344+ return true;
345+ /* Check one or more repetition. */
346+ goto repetition;
347+ }
348+ if (*(p + 2) == '{')
349+ goto repetition;
350+ }
351+ if ((*f == '/' || *p == '/') && *f++ != *p++)
352+ return false;
353+ if (!cs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
354+ return false;
355+ f = f_delimiter;
356+ p = p_delimiter;
357+ }
358+ /* Ignore trailing "\*" and "\@" in @pattern. */
359+ while (*p == '\\' && (*(p + 1) == '*' || *(p + 1) == '@'))
360+ p += 2;
361+ return !*f && !*p;
362+repetition:
363+ do {
364+ /* Compare current component with pattern. */
365+ if (!cs_file_matches_pattern(f + 1, f_delimiter,
366+ p + 3, p_delimiter - 2))
367+ break;
368+ /* Proceed to next component. */
369+ f = f_delimiter;
370+ if (!*f)
371+ break;
372+ /* Continue comparison. */
373+ if (cs_path_matches_pattern2(f, p_delimiter))
374+ return true;
375+ f_delimiter = strchr(f + 1, '/');
376+ } while (f_delimiter);
377+ return false; /* Not matched. */
378+}
379+
380+/**
381+ * cs_path_matches_pattern - Check whether the given filename matches the given pattern.
382+ *
383+ * @filename: The filename to check.
384+ * @pattern: The pattern to compare.
385+ *
386+ * Returns true if matches, false otherwise.
387+ *
388+ * The following patterns are available.
389+ * \ooo Octal representation of a byte.
390+ * \* Zero or more repetitions of characters other than '/'.
391+ * \@ Zero or more repetitions of characters other than '/' or '.'.
392+ * \? 1 byte character other than '/'.
393+ * \$ One or more repetitions of decimal digits.
394+ * \+ 1 decimal digit.
395+ * \X One or more repetitions of hexadecimal digits.
396+ * \x 1 hexadecimal digit.
397+ * \A One or more repetitions of alphabet characters.
398+ * \a 1 alphabet character.
399+ *
400+ * \- Subtraction operator.
401+ *
402+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
403+ * /dir/dir/dir/ ).
404+ *
405+ * /\(dir\)/ '/' + 'Zero or more repetitions of dir/' (e.g. / /dir/
406+ * /dir/dir/ ).
407+ */
408+static bool cs_path_matches_pattern(const struct cs_path_info *filename,
409+ const struct cs_path_info *pattern)
410+{
411+ const char *f = filename->name;
412+ const char *p = pattern->name;
413+ const int len = pattern->const_len;
414+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
415+ if (len == pattern->total_len)
416+ return !cs_pathcmp(filename, pattern);
417+ /* Compare the initial length without patterns. */
418+ if (len) {
419+ if (strncmp(f, p, len))
420+ return false;
421+ f += len - 1;
422+ p += len - 1;
423+ }
424+ return cs_path_matches_pattern2(f, p);
425+}
426+
427+/**
428+ * cs_correct_word - Check whether the given string follows the naming rules.
429+ *
430+ * @string: The string to check.
431+ * @allow_pattern: True if allow use of patterns, false otherwise.
432+ *
433+ * Returns true if @string follows the naming rules, false otherwise.
434+ */
435+static bool cs_correct_word(const char *string, bool allow_pattern)
436+{
437+ u8 recursion = 20;
438+ const char *const start = string;
439+ u8 in_repetition = 0;
440+ if (!*string)
441+ goto out;
442+ while (*string) {
443+ unsigned char c = *string++;
444+ if (in_repetition && c == '/')
445+ goto out;
446+ if (c <= ' ' || c >= 127)
447+ goto out;
448+ if (c != '\\')
449+ continue;
450+ c = *string++;
451+ if (c >= '0' && c <= '3') {
452+ unsigned char d;
453+ unsigned char e;
454+ d = *string++;
455+ if (d < '0' || d > '7')
456+ goto out;
457+ e = *string++;
458+ if (e < '0' || e > '7')
459+ goto out;
460+ c = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
461+ if (c <= ' ' || c >= 127 || c == '\\')
462+ continue;
463+ goto out;
464+ }
465+ if (!allow_pattern)
466+ goto out;
467+ switch (c) {
468+ case '+': /* "\+" */
469+ case '?': /* "\?" */
470+ case 'x': /* "\x" */
471+ case 'a': /* "\a" */
472+ case '-': /* "\-" */
473+ continue;
474+ }
475+ /* Reject too deep wildcard that consumes too much stack. */
476+ if (!recursion--)
477+ goto out;
478+ switch (c) {
479+ case '*': /* "\*" */
480+ case '@': /* "\@" */
481+ case '$': /* "\$" */
482+ case 'X': /* "\X" */
483+ case 'A': /* "\A" */
484+ continue;
485+ case '{': /* "/\{" */
486+ if (string - 3 < start || *(string - 3) != '/')
487+ goto out;
488+ in_repetition = 1;
489+ continue;
490+ case '}': /* "\}/" */
491+ if (in_repetition != 1 || *string++ != '/')
492+ goto out;
493+ in_repetition = 0;
494+ continue;
495+ case '(': /* "/\(" */
496+ if (string - 3 < start || *(string - 3) != '/')
497+ goto out;
498+ in_repetition = 2;
499+ continue;
500+ case ')': /* "\)/" */
501+ if (in_repetition != 2 || *string++ != '/')
502+ goto out;
503+ in_repetition = 0;
504+ continue;
505+ }
506+ goto out;
507+ }
508+ if (in_repetition)
509+ goto out;
510+ return true;
511+out:
512+ return false;
513+}
514+
515+/**
516+ * cs_get_name - Allocate memory for string data.
517+ *
518+ * @name: The string to save.
519+ *
520+ * Returns pointer to "struct cs_path_info" on success, NULL otherwise.
521+ */
522+static struct cs_path_info *cs_get_name(const char *name)
523+{
524+ struct cs_path_info *ptr =
525+ (struct cs_path_info *) malloc(sizeof(struct cs_path_info));
526+ if (!ptr)
527+ out_of_memory();
528+ ptr->name = strdup(name);
529+ if (!ptr->name)
530+ out_of_memory();
531+ cs_fill_path_info(ptr);
532+ return ptr;
533+}
534+
535+/**
536+ * cs_put_name - Free memory for string data.
537+ *
538+ * @name: Pointer to "struct cs_path_info". Maybe NULL.
539+ *
540+ * Returns nothing.
541+ */
542+static void cs_put_name(struct cs_path_info *name)
543+{
544+ if (name) {
545+ free((void *) name->name);
546+ free(name);
547+ }
548+}
549+
550+/**
551+ * cs_normalize_line - Format string.
552+ *
553+ * @buffer: The line to normalize.
554+ *
555+ * Returns nothing.
556+ *
557+ * Leading and trailing whitespaces are removed.
558+ * Multiple whitespaces are packed into single space.
559+ */
560+static void cs_normalize_line(char *buffer)
561+{
562+ unsigned char *sp = (unsigned char *) buffer;
563+ unsigned char *dp = (unsigned char *) buffer;
564+ bool first = true;
565+ while (*sp && (*sp <= ' ' || *sp >= 127))
566+ sp++;
567+ while (*sp) {
568+ if (!first)
569+ *dp++ = ' ';
570+ first = false;
571+ while (*sp > ' ' && *sp < 127)
572+ *dp++ = *sp++;
573+ while (*sp && (*sp <= ' ' || *sp >= 127))
574+ sp++;
575+ }
576+ *dp = '\0';
577+}
578+
579+static struct testcase {
580+ const char *pathname;
581+ const char *pattern;
582+ _Bool match;
583+} testcases[] = {
584+ { "/tmp/000", "/tmp/\\*", 1 },
585+ { "/tmp/000", "/tmp/\\@", 1 },
586+ { "/tmp/000", "/tmp/\\?\\?\\?", 1 },
587+ { "/tmp/000", "/tmp/\\*\\$\\@\\$", 1 },
588+ { "/tmp/000\\040111", "/tmp/\\*", 1 },
589+ { "/tmp/000\\040111", "/tmp/\\X", 0 },
590+ { "/tmp/000\\040111", "/tmp/\\$\\?\\$", 1 },
591+ { "/tmp/000111", "/tmp/\\(\\*\\)/\\*", 1 },
592+ { "/tmp/000/111", "/tmp/\\(\\*\\)/\\*", 1 },
593+ { "/tmp/0/0/0/1/1/1", "/tmp/\\(\\*\\)/\\*", 1 },
594+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\$\\}/\\$", 1 },
595+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\a\\}/\\$", 0 },
596+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\$\\-\\a\\}/\\$", 1 },
597+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\x\\-\\a\\}/\\$", 1 },
598+ { "/tmp/\\001/\\002/\\040/^/$", "/tmp/\\{\\*\\-\\a\\}/\\?", 1 },
599+ { "/tmp/\\001/\\002/\\040/^/$", "/tmp/\\{\\*\\-\\a\\-\\x\\}/\\?", 1 },
600+ { "/tmp/$", "/tmp/\\*\\-\\a\\-\\x", 1 },
601+ { "/bin/true", "/bin/\\*", 1 },
602+ { "/bin/true", "/bin\\@\\*/\\*", 1 },
603+ { "/usr/local/", "/usr/\\*/", 1 },
604+ { "/usr/local/", "/usr/\\*\\*\\@\\*/", 1 },
605+ { "pipe:[12345]", "pipe:[\\$]", 1 },
606+ { "socket:[family=1:type=2:protocol=3]", "socket:[family=1:type=2:protocol=\\$]", 1 },
607+ { "http://tomoyo.osdn.jp/", "\\*/\\*/\\*/", 1 },
608+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\*", 1 },
609+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\*\\*\\@\\*\\@", 1 },
610+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\@\\*/\\*\\@/\\*\\@\\*\\@\\*", 1 },
611+ { "http://tomoyo.osdn.jp/1.8/index.html", "http://\\{\\*\\}/\\@.html", 1 },
612+ { "http://tomoyo.osdn.jp/index.html", "\\*://\\@.osdn.jp/\\*", 1 },
613+ { "http://tomoyo.osdn.jp/index.html", "\\*://\\@.osdn.jp/\\*", 1 },
614+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/security/ccsecurity/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
615+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/security/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
616+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
617+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x//ccs-patch///security//ccsecurity///?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\-.\\-..\\-\\*%\\*\\}/?root=tomoyo\\*\\*", 1 },
618+ { "/var/www/html/test/test/test/index.html", "/var/www/html/\\{test\\}/\\*.html", 1 },
619+ { "/etc/skel/", "/etc/\\{\\*\\}/\\*/", 0 },
620+ { "/etc/passwd", "/etc/\\{\\*\\}/\\*", 0 },
621+ { "/bin/true", "/bin/\\*/", 0 },
622+ { "/bin/", "/bin/\\*", 1 },
623+ { "/bin/", "/bin/\\@", 1 },
624+ { "/bin/", "/bin/\\@\\@", 1 },
625+ { "http://tomoyo.osdn.jp/", "\\*/\\*/\\*/\\?", 0 },
626+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\@", 0 },
627+ { "http://tomoyo.osdn.jp/index.html", "http://\\*/\\@", 0 },
628+ { "socket:[family=1:type=2:protocol=3]", "/\\{\\*\\}/socket:[\\*]", 0 },
629+ { "/", "/\\(\\*\\)/\\*", 1 },
630+ { "/", "/\\{\\*\\}/\\*", 0 },
631+ { "/foo/", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 1 },
632+ { "/foo/", "/foo/\\{\\*\\}/\\*", 0 },
633+ { "/foo/bar/", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 1 },
634+ { "/foo/bar/", "/foo/\\{\\*\\}/\\*", 1 },
635+ { "/foo/bar", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/bar", 1 },
636+ { "/foo/bar", "/foo/\\{\\*\\}/bar", 0 },
637+ { "/foo/bar", "/foo/\\*/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 0 },
638+ { "/foo/bar/", "/foo/\\(\\*\\)/", 1 },
639+ { "/foo/bar/", "/foo/\\*/\\(\\*\\)/", 1 },
640+ { "/foo/bar/", "/foo/\\*/\\*/\\(\\*\\)/", 0 },
641+ { "/foo/bar/", "/foo/\\*/\\(\\*\\)/\\*/", 0 },
642+ { "/foo/", "/foo/\\(\\*\\)/", 1 },
643+ { "abc", "abc", 1 },
644+ { "abc", "\\A\\A\\A", 1 },
645+ { "abc", "\\X\\X\\X", 1 },
646+ { "abc", "\\*\\*\\*", 1 },
647+ { "abc", "\\@\\@\\@", 1 },
648+ { "abc", "\\a\\@\\x", 1 },
649+ { "abc", "\\?\\?\\?", 1 },
650+ { "abc", "\\?\\@\\?\\*", 1 },
651+ { "abc", "\\?\\@\\?\\*\\?", 1 },
652+ { "abc", "def", 0 },
653+ { "abc/def", "\\*/\\(\\X\\)/\\X", 1 },
654+ { "abc/def", "\\*/\\{\\X\\}/\\X", 0 },
655+ { "abc/def/012", "\\*/\\(\\X\\)/\\X", 1 },
656+ { "abc/def/012", "\\*/\\{\\X\\}/\\X", 1 },
657+ { "abc/def/012/345/6789", "\\*/\\(\\X\\)/\\X", 1 },
658+ { "abc/def/012/345/6789", "\\*/\\{\\X\\}/\\X", 1 },
659+ { "abc/345/012/def/6789", "\\*/\\(\\$\\)/\\X", 0 },
660+ { "abc/345/012/def/6789", "\\*/\\(\\*\\)/\\*/", 0 },
661+ { "abc/345/012/def/6789/////1//23///", "\\*/\\(\\*\\)/\\*/", 1 },
662+ { "abc/345/012/def/6789/////1//23//./", "\\*/\\(\\*\\)/\\?/", 1 },
663+ { "abc/345/012/def/6789//1//23//.", "\\*/\\(\\*\\)/\\?/", 0 },
664+ { "abc/345/012/def/6789//1//23//", "\\*/\\(\\*\\)/\\?", 0 },
665+ { "abc", "abc/\\*", 0 },
666+ { "abc/", "abc/\\*", 1 },
667+ { NULL, NULL, 0 },
668+};
669+
670+int main(int argc, char *argv[])
671+{
672+ struct testcase *ptr;
673+ struct cs_path_info *path;
674+ struct cs_path_info *pattern;
675+ for (ptr = testcases; ptr->pathname; ptr++) {
676+ if (!cs_correct_word(ptr->pathname, 0)) {
677+ printf("Bad path: %s\n", ptr->pathname);
678+ continue;
679+ } else if (!cs_correct_word(ptr->pattern, 1)) {
680+ printf("Bad pattern: %s\n", ptr->pattern);
681+ continue;
682+ }
683+ path = cs_get_name(ptr->pathname);
684+ pattern = cs_get_name(ptr->pattern);
685+ if (cs_path_matches_pattern(path, pattern) != ptr->match)
686+ printf("Failed (\"%s\", \"%s\") == %d\n",
687+ ptr->pathname, ptr->pattern, ptr->match);
688+ cs_put_name(path);
689+ cs_put_name(pattern);
690+ }
691+ return 0;
692+}
--- tags/caitsith-tools/0.2.1/sbin/caitsith-init.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/sbin/caitsith-init.c (revision 219)
@@ -0,0 +1,218 @@
1+/*
2+ * caitsith-init.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is executed automatically by kernel
11+ * when execution of /sbin/init is requested.
12+ *
13+ * This program is free software; you can redistribute it and/or modify it
14+ * under the terms of the GNU General Public License v2 as published by the
15+ * Free Software Foundation.
16+ *
17+ * This program is distributed in the hope that it will be useful, but WITHOUT
18+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20+ * more details.
21+ *
22+ * You should have received a copy of the GNU General Public License along with
23+ * this program; if not, write to the Free Software Foundation, Inc.,
24+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25+ */
26+#define _FILE_OFFSET_BITS 64
27+#define _LARGEFILE_SOURCE
28+#define _LARGEFILE64_SOURCE
29+#include <stdio.h>
30+#include <string.h>
31+#include <stdlib.h>
32+#include <sys/types.h>
33+#include <sys/stat.h>
34+#include <sys/wait.h>
35+#include <sys/mount.h>
36+#include <fcntl.h>
37+#include <unistd.h>
38+#include <dirent.h>
39+#include <limits.h>
40+#include <sys/vfs.h>
41+#include <errno.h>
42+
43+static void panic(void)
44+{
45+ printf("Fatal error while loading policy.\n");
46+ fflush(stdout);
47+ while (1)
48+ sleep(100);
49+}
50+
51+#define policy_dir "/etc/caitsith/policy"
52+static const char *proc_policy = "/sys/kernel/security/caitsith/policy";
53+static _Bool proc_unmount = 0;
54+static _Bool sys_unmount = 0;
55+static _Bool security_unmount = 0;
56+
57+static char buffer[8192];
58+
59+static void copy_files(const char *src, const char *dest)
60+{
61+ int sfd;
62+ int dfd = open(dest, O_WRONLY);
63+ if (dfd == EOF) {
64+ if (errno != ENOENT)
65+ panic();
66+ return;
67+ }
68+ sfd = open(src, O_RDONLY);
69+ if (sfd != EOF) {
70+ while (1) {
71+ int ret_ignored;
72+ int len = read(sfd, buffer, sizeof(buffer));
73+ if (len <= 0)
74+ break;
75+ ret_ignored = write(dfd, buffer, len);
76+ }
77+ close(sfd);
78+ }
79+ close(dfd);
80+}
81+
82+static void show_stat(void)
83+{
84+ unsigned int acl = 0;
85+ unsigned int size = -1;
86+ FILE *fp = fopen(proc_policy, "r");
87+ if (!fp)
88+ return;
89+ while (memset(buffer, 0, sizeof(buffer)) &&
90+ fgets(buffer, sizeof(buffer) - 1, fp)) {
91+ unsigned int priority;
92+ unsigned char operation;
93+ if (sscanf(buffer, "%u acl %c", &priority, &operation) == 2)
94+ acl++;
95+ else if (size == -1)
96+ sscanf(buffer, "stat Memory used by policy: %u",
97+ &size);
98+ }
99+ fclose(fp);
100+ printf("%u ACL entr%s.\n", acl, acl > 1 ? "ies" : "y");
101+ if (size != -1)
102+ printf("%u KB used by policy.\n", (size + 1023) / 1024);
103+}
104+
105+int main(int argc, char *argv[])
106+{
107+ struct stat buf;
108+
109+ /* Mount /proc if not mounted. */
110+ if (lstat("/proc/self/", &buf) || !S_ISDIR(buf.st_mode))
111+ proc_unmount = !mount("/proc", "/proc/", "proc", 0, NULL);
112+ /* Mount /sys if not mounted. */
113+ if (lstat("/sys/kernel/security/", &buf) || !S_ISDIR(buf.st_mode))
114+ sys_unmount = !mount("/sys", "/sys", "sysfs", 0, NULL);
115+ /* Mount /sys/kernel/security if not mounted. */
116+ if (lstat("/sys/kernel/security/caitsith/", &buf) ||
117+ !S_ISDIR(buf.st_mode))
118+ security_unmount = !mount("none", "/sys/kernel/security",
119+ "securityfs", 0, NULL);
120+
121+ /*
122+ * Open /dev/console if stdio are not connected.
123+ *
124+ * WARNING: Don't let this program be invoked implicitly
125+ * if you are not operating from console.
126+ * Otherwise, you will get unable to respond to prompt
127+ * if something went wrong.
128+ */
129+ if (access("/proc/self/fd/0", R_OK)) {
130+ close(0);
131+ close(1);
132+ close(2);
133+ open("/dev/console", O_RDONLY);
134+ open("/dev/console", O_WRONLY);
135+ open("/dev/console", O_WRONLY);
136+ }
137+
138+ /* Load kernel module if needed. */
139+ if (lstat(proc_policy, &buf) && lstat("/proc/caitsith", &buf)) {
140+ if (!access("/etc/caitsith/caitsith-load-module", X_OK)) {
141+ const pid_t pid = fork();
142+ switch (pid) {
143+ case 0:
144+ execl("/etc/caitsith/caitsith-load-module",
145+ "/etc/caitsith/caitsith-load-module",
146+ NULL);
147+ _exit(0);
148+ case -1:
149+ panic();
150+ }
151+ while (waitpid(pid, NULL, __WALL) == EOF &&
152+ errno == EINTR);
153+ }
154+ }
155+
156+ /* Try proc interface if securityfs interface does not exist. */
157+ if (lstat(proc_policy, &buf) || !S_ISREG(buf.st_mode))
158+ proc_policy = "/proc/caitsith/policy";
159+
160+ /* Stop if policy interface doesn't exist. */
161+ if (lstat(proc_policy, &buf) || !S_ISREG(buf.st_mode)) {
162+ printf("FATAL: Policy interface %s does not exist.\n",
163+ proc_policy);
164+ fflush(stdout);
165+ while (1)
166+ sleep(100);
167+ }
168+
169+ /*
170+ * Unmount and execute /sbin/init if this program was executed by
171+ * passing init=/sbin/caitsith-init . The kernel will try to execute
172+ * this program again with getpid() != 1 when /sbin/init starts.
173+ */
174+ if (getpid() == 1) {
175+ if (security_unmount)
176+ umount("/sys/kernel/security/");
177+ if (sys_unmount)
178+ umount("/sys/");
179+ if (proc_unmount)
180+ umount("/proc/");
181+ argv[0] = "/sbin/init";
182+ execv(argv[0], argv);
183+ printf("FATAL: Failed to execute %s\n", argv[0]);
184+ fflush(stdout);
185+ while (1)
186+ sleep(100);
187+ }
188+
189+ /* Load policy. */
190+ if (!chdir(policy_dir))
191+ copy_files("current", proc_policy);
192+
193+ /* Do additional initialization. */
194+ if (!access("/etc/caitsith/caitsith-post-init", X_OK)) {
195+ const pid_t pid = fork();
196+ switch (pid) {
197+ case 0:
198+ execl("/etc/caitsith/caitsith-post-init",
199+ "/etc/caitsith/caitsith-post-init", NULL);
200+ _exit(0);
201+ case -1:
202+ panic();
203+ }
204+ while (waitpid(pid, NULL, __WALL) == EOF &&
205+ errno == EINTR);
206+ }
207+
208+ show_stat();
209+
210+ if (security_unmount)
211+ umount("/sys/kernel/security/");
212+ if (sys_unmount)
213+ umount("/sys/");
214+ if (proc_unmount)
215+ umount("/proc");
216+
217+ return 0;
218+}
--- tags/caitsith-tools/0.2.1/sbin/Makefile (nonexistent)
+++ tags/caitsith-tools/0.2.1/sbin/Makefile (revision 219)
@@ -0,0 +1,17 @@
1+include ../Include.make
2+
3+BUILD_FILES = caitsith-init
4+
5+all: $(BUILD_FILES)
6+
7+install: all
8+ mkdir -p -m 0755 $(INSTALLDIR)$(SBINDIR)
9+ $(INSTALL) -m 0700 $(BUILD_FILES) $(INSTALLDIR)$(SBINDIR)
10+
11+.c:
12+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $<
13+
14+clean:
15+ rm -f -- $(BUILD_FILES)
16+
17+.PHONY: clean install
--- tags/caitsith-tools/0.2.1/usr_lib_caitsith/audit-exec-param.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_lib_caitsith/audit-exec-param.c (revision 219)
@@ -0,0 +1,87 @@
1+/*
2+ * audit-exec-param.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include <stdio.h>
24+#include <stdlib.h>
25+#include <unistd.h>
26+#include <syslog.h>
27+#include <string.h>
28+#include <sys/types.h>
29+#include <sys/stat.h>
30+#include <fcntl.h>
31+#include <errno.h>
32+
33+int main(int raw_argc, char *raw_argv[])
34+{
35+ int i;
36+ int argc;
37+ int envc;
38+ char *filename;
39+ char **argv;
40+ char **envp;
41+ if (1) {
42+ int fd = open("/proc/caitsith/.execute_handler", 0);
43+ close(fd);
44+ if (fd == EOF && errno != ENOENT) {
45+ fprintf(stderr, "FATAL: I'm not execute_handler.\n");
46+ return 1;
47+ }
48+ }
49+ if (raw_argc < 7)
50+ return 1;
51+ filename = raw_argv[4];
52+ argc = atoi(raw_argv[5]);
53+ envc = atoi(raw_argv[6]);
54+ if (raw_argc != argc + envc + 7)
55+ return 1;
56+ for (i = 5; i < argc + 5; i++)
57+ raw_argv[i] = raw_argv[i + 2];
58+ raw_argv[argc + 5] = NULL;
59+ for (i = argc + 6; i < argc + envc + 6; i++)
60+ raw_argv[i] = raw_argv[i + 1];
61+ raw_argv[argc + envc + 6] = NULL;
62+ argv = raw_argv + 5;
63+ envp = raw_argv + argc + 6;
64+ /*
65+ * Check parameters passed to execve() request.
66+ */
67+ if (1) {
68+ openlog(raw_argv[0], LOG_NDELAY, LOG_USER);
69+ syslog(LOG_INFO, "Domain = %s\n", raw_argv[1]);
70+ syslog(LOG_INFO, "Caller Program = %s\n", raw_argv[2]);
71+ syslog(LOG_INFO, "Process Status = %s\n", raw_argv[3]);
72+ syslog(LOG_INFO, "Requested Program = %s\n", filename);
73+ syslog(LOG_INFO, "argc=%d\n", argc);
74+ syslog(LOG_INFO, "envc=%d\n", envc);
75+ for (i = 0; i < argc; i++)
76+ syslog(LOG_INFO, "argv[%d] = %s\n", i, argv[i]);
77+ for (i = 0; i < envc; i++)
78+ syslog(LOG_INFO, "envp[%d] = %s\n", i, envp[i]);
79+ closelog();
80+ }
81+ /*
82+ * Continue if filename and argv[] and envp[] are appropriate.
83+ */
84+ if (1)
85+ execve(filename, argv, envp);
86+ return 1;
87+}
--- tags/caitsith-tools/0.2.1/usr_lib_caitsith/caitsith-agent.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_lib_caitsith/caitsith-agent.c (revision 219)
@@ -0,0 +1,385 @@
1+/*
2+ * caitsith-agent.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#define _GNU_SOURCE
24+#include <stdio.h>
25+#include <string.h>
26+#include <stdlib.h>
27+#include <sys/types.h>
28+#include <sys/socket.h>
29+#include <netinet/in.h>
30+#include <arpa/inet.h>
31+#include <sys/stat.h>
32+#include <fcntl.h>
33+#include <unistd.h>
34+#include <poll.h>
35+#include <signal.h>
36+#include <dirent.h>
37+#include <sys/mount.h>
38+#include <sched.h>
39+
40+static _Bool wait_data(const int fd)
41+{
42+ struct pollfd pfd = { .fd = fd, .events = POLLIN};
43+ poll(&pfd, 1, -1);
44+ return 1;
45+}
46+
47+static void show_tasklist(FILE *fp, const _Bool show_all)
48+{
49+ int status_fd = open(".process_status", O_RDWR);
50+ DIR *dir = opendir("/proc/");
51+ if (status_fd == EOF || !dir) {
52+ if (status_fd != EOF)
53+ close(status_fd);
54+ if (dir)
55+ closedir(dir);
56+ return;
57+ }
58+ fputc(0, fp);
59+ while (1) {
60+ int ret_ignored;
61+ FILE *status_fp;
62+ pid_t ppid = 1;
63+ char *name = NULL;
64+ char buffer[1024];
65+ char test[16];
66+ unsigned int pid;
67+ struct dirent *dent = readdir(dir);
68+ if (!dent)
69+ break;
70+ if (dent->d_type != DT_DIR ||
71+ sscanf(dent->d_name, "%u", &pid) != 1 || !pid)
72+ continue;
73+ memset(buffer, 0, sizeof(buffer));
74+ if (!show_all) {
75+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/exe",
76+ pid);
77+ if (readlink(buffer, test, sizeof(test)) <= 0)
78+ continue;
79+ }
80+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
81+ status_fp = fopen(buffer, "r");
82+ if (status_fp) {
83+ while (memset(buffer, 0, sizeof(buffer)) &&
84+ fgets(buffer, sizeof(buffer) - 1, status_fp)) {
85+ if (!strncmp(buffer, "Name:\t", 6)) {
86+ char *cp = buffer + 6;
87+ memmove(buffer, cp, strlen(cp) + 1);
88+ cp = strchr(buffer, '\n');
89+ if (cp)
90+ *cp = '\0';
91+ name = strdup(buffer);
92+ }
93+ if (sscanf(buffer, "PPid: %u", &ppid) == 1)
94+ break;
95+ }
96+ fclose(status_fp);
97+ }
98+ snprintf(buffer, sizeof(buffer) - 1, "%u\n", pid);
99+ ret_ignored = write(status_fd, buffer, strlen(buffer));
100+ memset(buffer, 0, sizeof(buffer));
101+ ret_ignored = read(status_fd, buffer, sizeof(buffer));
102+ if (!buffer[0])
103+ continue;
104+ fprintf(fp, "PID=%u PPID=%u NAME=", pid, ppid);
105+ if (name) {
106+ const char *cp = name;
107+ while (1) {
108+ unsigned char c = *cp++;
109+ if (!c)
110+ break;
111+ if (c == '\\') {
112+ c = *cp++;
113+ if (c == '\\')
114+ fprintf(fp, "\\\\");
115+ else if (c == 'n')
116+ fprintf(fp, "\\012");
117+ else
118+ break;
119+ } else if (c > ' ' && c <= 126) {
120+ fputc(c, fp);
121+ } else {
122+ fprintf(fp, "\\%c%c%c",
123+ (c >> 6) + '0',
124+ ((c >> 3) & 7) + '0',
125+ (c & 7) + '0');
126+ }
127+ }
128+ free(name);
129+ } else {
130+ fprintf(fp, "<UNKNOWN>");
131+ }
132+ fputc('\n', fp);
133+ ret_ignored = fwrite(buffer, strlen(buffer), 1, fp);
134+ while (1) {
135+ int len = read(status_fd, buffer, sizeof(buffer));
136+ if (len <= 0)
137+ break;
138+ ret_ignored = fwrite(buffer, len, 1, fp);
139+ }
140+ fputc('\n', fp);
141+ }
142+ fputc(0, fp);
143+ closedir(dir);
144+ close(status_fd);
145+ fflush(fp);
146+}
147+
148+static void handle_audit(const int client)
149+{
150+ int ret_ignored;
151+ const int fd = open("audit", O_RDONLY);
152+ if (fd == EOF)
153+ return;
154+ /* Return \0 to indicate success. */
155+ ret_ignored = write(client, "", 1);
156+ while (wait_data(fd)) {
157+ char buffer[4096];
158+ const int len = read(fd, buffer, sizeof(buffer));
159+ if (!len)
160+ continue;
161+ if (len == EOF || write(client, buffer, len) != len)
162+ break;
163+ }
164+ close(fd);
165+}
166+
167+static void handle_query(const int client)
168+{
169+ int ret_ignored;
170+ const int fd = open("query", O_RDWR);
171+ if (fd == EOF)
172+ return;
173+ /* Return \0 to indicate success. */
174+ ret_ignored = write(client, "", 1);
175+ while (wait_data(client)) {
176+ char buffer[4096];
177+ int len = recv(client, buffer, sizeof(buffer), MSG_DONTWAIT);
178+ int nonzero_len;
179+ if (len <= 0)
180+ break;
181+restart:
182+ for (nonzero_len = 0 ; nonzero_len < len; nonzero_len++)
183+ if (!buffer[nonzero_len])
184+ break;
185+ if (nonzero_len) {
186+ if (write(fd, buffer, nonzero_len) != nonzero_len)
187+ break;
188+ } else {
189+ while (wait_data(fd)) {
190+ char buffer2[4096];
191+ const int len = read(fd, buffer2,
192+ sizeof(buffer2));
193+ if (!len)
194+ continue;
195+ if (len == EOF ||
196+ write(client, buffer2, len) != len) {
197+ shutdown(client, SHUT_RDWR);
198+ break;
199+ }
200+ if (!buffer2[len - 1])
201+ break;
202+ }
203+ nonzero_len = 1;
204+ }
205+ len -= nonzero_len;
206+ memmove(buffer, buffer + nonzero_len, len);
207+ if (len)
208+ goto restart;
209+ }
210+ close(fd);
211+}
212+
213+static _Bool verbose = 0;
214+
215+static void handle_policy(const int client, const char *filename)
216+{
217+ int ret_ignored;
218+ char *cp = strrchr(filename, '/');
219+ int fd = open(cp ? cp + 1 : filename, O_RDWR);
220+ if (fd == EOF)
221+ goto out;
222+ /* Return \0 to indicate success. */
223+ if (write(client, "", 1) != 1)
224+ goto out;
225+ if (verbose) {
226+ ret_ignored = write(2, "opened ", 7);
227+ ret_ignored = write(2, filename, strlen(filename));
228+ ret_ignored = write(2, "\n", 1);
229+ }
230+ while (wait_data(client)) {
231+ char buffer[4096];
232+ int len = recv(client, buffer, sizeof(buffer), MSG_DONTWAIT);
233+ int nonzero_len;
234+ if (len <= 0)
235+ break;
236+restart:
237+ for (nonzero_len = 0 ; nonzero_len < len; nonzero_len++)
238+ if (!buffer[nonzero_len])
239+ break;
240+ if (nonzero_len) {
241+ if (write(fd, buffer, nonzero_len) != nonzero_len)
242+ break;
243+ if (verbose)
244+ ret_ignored = write(1, buffer, nonzero_len);
245+ } else {
246+ while (1) {
247+ char buffer2[4096];
248+ const int len = read(fd, buffer2,
249+ sizeof(buffer2));
250+ if (len == 0)
251+ break;
252+ /* Don't send \0 because it is EOF marker. */
253+ if (len < 0 || memchr(buffer2, '\0', len) ||
254+ write(client, buffer2, len) != len)
255+ goto out;
256+ }
257+ /* Return \0 to indicate EOF. */
258+ if (write(client, "", 1) != 1)
259+ goto out;
260+ nonzero_len = 1;
261+ }
262+ len -= nonzero_len;
263+ memmove(buffer, buffer + nonzero_len, len);
264+ if (len)
265+ goto restart;
266+ }
267+out:
268+ if (verbose)
269+ ret_ignored = write(2, "disconnected\n", 13);
270+}
271+
272+static void do_child(const int client)
273+{
274+ int i;
275+ char buffer[1024];
276+ /* Read filename. */
277+ for (i = 0; i < sizeof(buffer); i++) {
278+ if (read(client, buffer + i, 1) != 1)
279+ goto out;
280+ if (!buffer[i])
281+ break;
282+ }
283+ if (!memchr(buffer, '\0', sizeof(buffer)))
284+ goto out;
285+ if (!strcmp(buffer, "proc:query"))
286+ handle_query(client);
287+ else if (!strcmp(buffer, "proc:audit"))
288+ handle_audit(client);
289+ else if (!strncmp(buffer, "proc:", 5)) {
290+ /* Open /proc/\$/ for reading. */
291+ FILE *fp = fdopen(client, "w");
292+ if (fp) {
293+ show_tasklist(fp, !strcmp(buffer + 5,
294+ "all_process_status"));
295+ fclose(fp);
296+ }
297+ } else
298+ handle_policy(client, buffer);
299+out:
300+ close(client);
301+}
302+
303+int main(int argc, char *argv[])
304+{
305+ const int listener = socket(AF_INET, SOCK_STREAM, 0);
306+ struct sockaddr_in addr;
307+ socklen_t size = sizeof(addr);
308+ char *port;
309+ if (chdir("/proc/caitsith/") &&
310+ chdir("/sys/kernel/security/caitsith/") &&
311+ (unshare(CLONE_NEWNS) ||
312+ mount("none", "/sys/kernel/security/", "securityfs", 0, NULL) ||
313+ chdir("/sys/kernel/security/caitsith/")))
314+ return 1;
315+ {
316+ int i;
317+ for (i = 1; i < argc; i++) {
318+ if (strcmp(argv[i], "--verbose"))
319+ continue;
320+ verbose = 1;
321+ argc--;
322+ for (; i < argc; i++)
323+ argv[i] = argv[i + 1];
324+ break;
325+ }
326+ }
327+ if (argc != 2) {
328+usage:
329+ fprintf(stderr, "%s listen_address:listen_port\n", argv[0]);
330+ return 1;
331+ }
332+ port = strchr(argv[1], ':');
333+ if (!port)
334+ goto usage;
335+ *port++ = '\0';
336+ memset(&addr, 0, sizeof(addr));
337+ addr.sin_family = AF_INET;
338+ addr.sin_addr.s_addr = inet_addr(argv[1]);
339+ addr.sin_port = htons(atoi(port));
340+ if (bind(listener, (struct sockaddr *) &addr, sizeof(addr)) ||
341+ listen(listener, 5) ||
342+ getsockname(listener, (struct sockaddr *) &addr, &size)) {
343+ close(listener);
344+ return 1;
345+ }
346+ {
347+ const unsigned int ip = ntohl(addr.sin_addr.s_addr);
348+ printf("Listening at %u.%u.%u.%u:%u\n",
349+ (unsigned char) (ip >> 24), (unsigned char) (ip >> 16),
350+ (unsigned char) (ip >> 8), (unsigned char) ip,
351+ ntohs(addr.sin_port));
352+ fflush(stdout);
353+ }
354+ close(0);
355+ if (!verbose) {
356+ close(1);
357+ close(2);
358+ }
359+ signal(SIGCHLD, SIG_IGN);
360+ while (1) {
361+ socklen_t size = sizeof(addr);
362+ const int client = accept(listener, (struct sockaddr *) &addr,
363+ &size);
364+ if (client == EOF) {
365+ if (verbose)
366+ fprintf(stderr, "accept() failed\n");
367+ continue;
368+ }
369+ switch (fork()) {
370+ case 0:
371+ close(listener);
372+ do_child(client);
373+ _exit(0);
374+ case -1:
375+ if (verbose)
376+ fprintf(stderr, "fork() failed\n");
377+ close(client);
378+ break;
379+ default:
380+ close(client);
381+ }
382+ }
383+ close(listener);
384+ return 1;
385+}
--- tags/caitsith-tools/0.2.1/usr_lib_caitsith/init_policy.c (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_lib_caitsith/init_policy.c (revision 219)
@@ -0,0 +1,709 @@
1+/*
2+ * init_policy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.2 2016/10/05
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#define _FILE_OFFSET_BITS 64
24+#define _LARGEFILE_SOURCE
25+#define _LARGEFILE64_SOURCE
26+#include <stdio.h>
27+#include <string.h>
28+#include <stdlib.h>
29+#include <sys/types.h>
30+#include <sys/stat.h>
31+#include <unistd.h>
32+#include <dirent.h>
33+#include <limits.h>
34+#include <sys/vfs.h>
35+#include <time.h>
36+#include <errno.h>
37+
38+#if defined(__GLIBC__)
39+/**
40+ * get_realpath - Wrapper for realpath(3).
41+ *
42+ * @path: Pathname to resolve.
43+ *
44+ * Returns realpath of @path on success, NULL otherwise.
45+ *
46+ * Caller must free() the returned pointer if this function did not return
47+ * NULL.
48+ */
49+static inline char *get_realpath(const char *path)
50+{
51+ return realpath(path, NULL);
52+}
53+#else
54+/**
55+ * get_realpath - Fallback routine for realpath(3).
56+ *
57+ * @path: Pathname to resolve.
58+ *
59+ * Returns realpath of @path on success, NULL otherwise.
60+ *
61+ * realpath(@path, NULL) works on GLIBC, but will SIGSEGV on others.
62+ *
63+ * Caller must free() the returned pointer if this function did not return
64+ * NULL.
65+ */
66+static char *get_realpath(const char *path)
67+{
68+ struct stat buf;
69+ static const int pwd_len = PATH_MAX * 2;
70+ char *dir = strdup(path);
71+ char *pwd = malloc(pwd_len);
72+ char *basename = NULL;
73+ int len;
74+ if (!dir || !pwd)
75+ goto out;
76+ if (stat(dir, &buf))
77+ goto out;
78+ len = strlen(dir);
79+ while (len > 1 && dir[len - 1] == '/')
80+ dir[--len] = '\0';
81+ while (!lstat(dir, &buf) && S_ISLNK(buf.st_mode)) {
82+ char *new_dir;
83+ char *old_dir = dir;
84+ memset(pwd, 0, pwd_len);
85+ if (readlink(dir, pwd, pwd_len - 1) < 1)
86+ goto out;
87+ if (pwd[0] == '/') {
88+ dir[0] = '\0';
89+ } else {
90+ char *cp = strrchr(dir, '/');
91+ if (cp)
92+ *cp = '\0';
93+ }
94+ len = strlen(dir) + strlen(pwd) + 4;
95+ new_dir = malloc(len);
96+ if (new_dir)
97+ snprintf(new_dir, len - 1, "%s/%s", dir, pwd);
98+ dir = new_dir;
99+ free(old_dir);
100+ if (!dir)
101+ goto out;
102+ }
103+ if (!dir)
104+ goto out;
105+ basename = strrchr(dir, '/');
106+ if (basename)
107+ *basename++ = '\0';
108+ else
109+ basename = "";
110+ if (chdir(dir))
111+ goto out;
112+ memset(pwd, 0, pwd_len);
113+ if (!getcwd(pwd, pwd_len - 1))
114+ goto out;
115+ if (strcmp(pwd, "/"))
116+ len = strlen(pwd);
117+ else
118+ len = 0;
119+ snprintf(pwd + len, pwd_len - len - 1, "/%s", basename);
120+ free(dir);
121+ return pwd;
122+out:
123+ free(dir);
124+ free(pwd);
125+ return NULL;
126+}
127+#endif
128+
129+#define elementof(x) (sizeof(x) / sizeof(x[0]))
130+
131+/**
132+ * scandir_file_filter - Callback for scandir().
133+ *
134+ * @buf: Pointer to "const struct dirent".
135+ *
136+ * Returns non 0 if @buf seems to be a file, 0 otherwise.
137+ *
138+ * Since several kernels have a bug that leaves @buf->d_type == DT_UNKNOWN,
139+ * we allow it for now and recheck it later.
140+ */
141+static int scandir_file_filter(const struct dirent *buf)
142+{
143+ return (buf->d_type == DT_REG || buf->d_type == DT_UNKNOWN) &&
144+ strcmp(buf->d_name, ".") && strcmp(buf->d_name, "..");
145+}
146+
147+/**
148+ * revalidate_path - Recheck file's attribute.
149+ *
150+ * @path: Pathname to check.
151+ *
152+ * Returns type of @path.
153+ *
154+ * This is needed by buggy kernels that report DT_UNKNOWN upon scandir().
155+ */
156+static unsigned char revalidate_path(const char *path)
157+{
158+ struct stat buf;
159+ unsigned char type = DT_UNKNOWN;
160+ if (!lstat(path, &buf)) {
161+ if (S_ISREG(buf.st_mode))
162+ type = DT_REG;
163+ else if (S_ISDIR(buf.st_mode))
164+ type = DT_DIR;
165+ else if (S_ISLNK(buf.st_mode))
166+ type = DT_LNK;
167+ }
168+ return type;
169+}
170+
171+/* File handle to /etc/caitsith/policy/current . */
172+static FILE *filp = NULL;
173+
174+/**
175+ * printf_encoded - Print a word to the policy file, with escaping as needed.
176+ *
177+ * @str: Word to print. Needn't to follow CaitSith's escape rules.
178+ *
179+ * Returns nothing.
180+ *
181+ * If @str starts with "/proc/", it is converted with "proc:/".
182+ */
183+static void printf_encoded(const char *str)
184+{
185+ if (!strncmp(str, "/proc/", 6)) {
186+ fprintf(filp, "proc:");
187+ str += 5;
188+ }
189+ while (1) {
190+ const char c = *str++;
191+ if (!c)
192+ break;
193+ if (c > ' ' && c < 127 && c != '\\')
194+ fputc(c, filp);
195+ else
196+ fprintf(filp, "\\%c%c%c", (c >> 6) + '0',
197+ ((c >> 3) & 7) + '0', (c & 7) + '0');
198+ }
199+}
200+
201+static void make_default_domain_transition(const char *path)
202+{
203+ fprintf(filp, " 10 allow path=\"");
204+ printf_encoded(path);
205+ fprintf(filp, "\" transition=\"");
206+ printf_encoded(path);
207+ fprintf(filp, "\"\n");
208+}
209+
210+
211+/* Shared buffer for scandir(). */
212+static char path[8192];
213+
214+/**
215+ * scan_executable_files - Find executable files in the specific directory.
216+ *
217+ * @dir: Directory name to scan.
218+ *
219+ * Returns nothing.
220+ */
221+static void scan_executable_files(const char *dir)
222+{
223+ struct dirent **namelist;
224+ int n = scandir(dir, &namelist, scandir_file_filter, 0);
225+ int i;
226+ if (n < 0)
227+ return;
228+ for (i = 0; i < n; i++) {
229+ unsigned char type = namelist[i]->d_type;
230+ snprintf(path, sizeof(path) - 1, "%s/%s", dir,
231+ namelist[i]->d_name);
232+ if (type == DT_UNKNOWN)
233+ type = revalidate_path(path);
234+ if (type == DT_REG && !access(path, X_OK))
235+ make_default_domain_transition(path);
236+ free(namelist[i]);
237+ }
238+ free(namelist);
239+}
240+
241+/**
242+ * scan_modprobe_and_hotplug - Mark modprobe and hotplug as domain_transition entries.
243+ *
244+ * Returns nothing.
245+ */
246+static void scan_modprobe_and_hotplug(void)
247+{
248+ static const char * const files[2] = {
249+ "/proc/sys/kernel/modprobe", "/proc/sys/kernel/hotplug"
250+ };
251+ int i;
252+ for (i = 0; i < elementof(files); i++) {
253+ char *ret_ignored;
254+ char buffer[PATH_MAX + 1];
255+ char *cp;
256+ FILE *fp = fopen(files[i], "r");
257+ if (!fp)
258+ continue;
259+ memset(buffer, 0, sizeof(buffer));
260+ ret_ignored = fgets(buffer, sizeof(buffer) - 1, fp);
261+ fclose(fp);
262+ cp = strrchr(buffer, '\n');
263+ if (cp)
264+ *cp = '\0';
265+ if (!buffer[0])
266+ continue;
267+ cp = get_realpath(buffer);
268+ if (!cp)
269+ continue;
270+ /* We ignore /bin/true if /proc/sys/kernel/modprobe said so. */
271+ if (strcmp(cp, "/bin/true") && !access(cp, X_OK))
272+ make_default_domain_transition(cp);
273+ free(cp);
274+ }
275+}
276+
277+/**
278+ * scan_init_dir - Mark programs under /etc/init.d/ directory as default domain transition entries.
279+ *
280+ * Returns nothing.
281+ */
282+static void scan_init_dir(void)
283+{
284+ char *dir = get_realpath("/etc/init.d/");
285+ if (!dir)
286+ return;
287+ scan_executable_files(dir);
288+ free(dir);
289+}
290+
291+/**
292+ * scan_daemons - Mark daemon programs as default domain transition entries.
293+ *
294+ * Returns nothing.
295+ */
296+static void scan_daemons(void)
297+{
298+ static const char * const files[] = {
299+ "/sbin/cardmgr",
300+ "/sbin/getty",
301+ "/sbin/init",
302+ "/sbin/klogd",
303+ "/sbin/mingetty",
304+ "/sbin/portmap",
305+ "/sbin/rpc.statd",
306+ "/sbin/syslogd",
307+ "/sbin/udevd",
308+ "/usr/X11R6/bin/xfs",
309+ "/usr/bin/dbus-daemon",
310+ "/usr/bin/dbus-daemon-1",
311+ "/usr/bin/jserver",
312+ "/usr/bin/mDNSResponder",
313+ "/usr/bin/nifd",
314+ "/usr/bin/spamd",
315+ "/usr/sbin/acpid",
316+ "/usr/sbin/afpd",
317+ "/usr/sbin/anacron",
318+ "/usr/sbin/apache2",
319+ "/usr/sbin/apmd",
320+ "/usr/sbin/atalkd",
321+ "/usr/sbin/atd",
322+ "/usr/sbin/cannaserver",
323+ "/usr/sbin/cpuspeed",
324+ "/usr/sbin/cron",
325+ "/usr/sbin/crond",
326+ "/usr/sbin/cupsd",
327+ "/usr/sbin/dhcpd",
328+ "/usr/sbin/exim4",
329+ "/usr/sbin/gpm",
330+ "/usr/sbin/hald",
331+ "/usr/sbin/htt",
332+ "/usr/sbin/httpd",
333+ "/usr/sbin/inetd",
334+ "/usr/sbin/logrotate",
335+ "/usr/sbin/lpd",
336+ "/usr/sbin/nmbd",
337+ "/usr/sbin/papd",
338+ "/usr/sbin/rpc.idmapd",
339+ "/usr/sbin/rpc.mountd",
340+ "/usr/sbin/rpc.rquotad",
341+ "/usr/sbin/sendmail.sendmail",
342+ "/usr/sbin/smartd",
343+ "/usr/sbin/smbd",
344+ "/usr/sbin/squid",
345+ "/usr/sbin/sshd",
346+ "/usr/sbin/vmware-guestd",
347+ "/usr/sbin/vsftpd",
348+ "/usr/sbin/xinetd"
349+ };
350+ int i;
351+ for (i = 0; i < elementof(files); i++) {
352+ char *cp = get_realpath(files[i]);
353+ if (!cp)
354+ continue;
355+ if (!access(cp, X_OK))
356+ make_default_domain_transition(cp);
357+ free(cp);
358+ }
359+}
360+
361+/**
362+ * mkdir2 - mkdir() with ignoring EEXIST error.
363+ *
364+ * @dir: Directory to create.
365+ * @mode: Create mode.
366+ *
367+ * Returns 0 on success, EOF otehrwise.
368+ */
369+static int mkdir2(const char *dir, int mode)
370+{
371+ return mkdir(dir, mode) == 0 || errno == EEXIST ? 0 : EOF;
372+}
373+
374+/* Policy directory. Default is "/etc/caitsith/". */
375+static char *policy_dir = NULL;
376+
377+/**
378+ * make_policy_dir - Create policy directories and tools directories.
379+ *
380+ * Returns nothing.
381+ */
382+static void make_policy_dir(void)
383+{
384+ char *dir = policy_dir;
385+ const time_t now = time(NULL);
386+ struct tm *tm = localtime(&now);
387+ char stamp[20] = { };
388+ snprintf(stamp, sizeof(stamp) - 1, "%02d-%02d-%02d.%02d:%02d:%02d",
389+ tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
390+ tm->tm_min, tm->tm_sec);
391+ if (!chdir(policy_dir) && !chdir("policy"))
392+ goto tools_dir;
393+ fprintf(stderr, "Creating policy directory... ");
394+ while (1) {
395+ const char c = *dir++;
396+ if (!c)
397+ break;
398+ if (c != '/')
399+ continue;
400+ *(dir - 1) = '\0';
401+ mkdir(policy_dir, 0700);
402+ *(dir - 1) = '/';
403+ }
404+ if (mkdir2(policy_dir, 0700) || chdir(policy_dir) ||
405+ mkdir2("policy", 0700) || chdir("policy")) {
406+ fprintf(stderr, "failed.\n");
407+ exit(1);
408+ } else {
409+ fprintf(stderr, "OK\n");
410+ }
411+tools_dir:
412+ if (!chdir(policy_dir) && !chdir("tools"))
413+ return;
414+ fprintf(stderr, "Creating configuration directory... ");
415+ mkdir("tools", 0700);
416+ if (!chdir("tools"))
417+ fprintf(stderr, "OK\n");
418+ else {
419+ fprintf(stderr, "failed.\n");
420+ exit(1);
421+ }
422+}
423+
424+/**
425+ * chdir_policy - Change to policy directory.
426+ *
427+ * Returns 1 on success, 0 otherwise.
428+ */
429+static _Bool chdir_policy(void)
430+{
431+ if (chdir(policy_dir) || chdir("policy")) {
432+ fprintf(stderr, "ERROR: Can't chdir to %s/policy/ "
433+ "directory.\n", policy_dir);
434+ return 0;
435+ }
436+ return 1;
437+}
438+
439+/**
440+ * close_file - Close file and rename.
441+ *
442+ * @fp: Pointer to "FILE".
443+ * @condition: Preconditions before rename().
444+ * @old: Temporary file's pathname.
445+ * @new: Final file's pathname.
446+ *
447+ * Returns nothing.
448+ */
449+static void close_file(FILE *fp, _Bool condition, const char *old,
450+ const char *new)
451+{
452+ if (fsync(fileno(fp)) || fclose(fp) || !condition || rename(old, new))
453+ fprintf(stderr, "failed.\n");
454+ else
455+ fprintf(stderr, "OK.\n");
456+}
457+
458+/**
459+ * make_policy - Make /etc/caitsith/policy/current .
460+ *
461+ * Returns nothing.
462+ */
463+static void make_policy(void)
464+{
465+ if (!chdir_policy())
466+ return;
467+ if (!access("current", R_OK))
468+ return;
469+ filp = fopen("current.tmp", "w");
470+ if (!filp) {
471+ fprintf(stderr, "ERROR: Can't create policy.\n");
472+ return;
473+ }
474+ fprintf(stderr, "Creating default policy... ");
475+ fprintf(filp, "POLICY_VERSION=20120401\n");
476+ fprintf(filp, "\n");
477+ fprintf(filp, "quota memory audit 16777216\n");
478+ fprintf(filp, "quota memory query 1048576\n");
479+ fprintf(filp, "quota audit[1] allowed=0 denied=1024 unmatched=1024\n");
480+ fprintf(filp, "\n");
481+ fprintf(filp, "10000 acl execute\n"
482+ " audit 0\n");
483+ scan_modprobe_and_hotplug();
484+ scan_daemons();
485+ scan_init_dir();
486+ fprintf(filp, "\n");
487+ {
488+ char *tools_dir = get_realpath("/usr/sbin");
489+ fprintf(filp, "0 acl modify_policy\n"
490+ " audit 1\n"
491+ " 1 deny task.uid!=0\n"
492+ " 1 deny task.euid!=0\n"
493+ " 100 allow task.exe=\"%s/caitsith-loadpolicy\"\n"
494+ " 100 allow task.exe=\"%s/caitsith-queryd\"\n"
495+ " 10000 deny\n", tools_dir, tools_dir);
496+ }
497+ close_file(filp, chdir_policy(), "current.tmp", "current");
498+ filp = NULL;
499+}
500+
501+/* The name of loadable kernel module to load. */
502+static const char *module_name = "caitsith";
503+
504+/**
505+ * make_module_loader - Make /etc/caitsith/caitsith-load-module .
506+ *
507+ * Returns nothing.
508+ */
509+static void make_module_loader(void)
510+{
511+ FILE *fp;
512+ if (chdir(policy_dir) || !access("caitsith-load-module", X_OK)
513+ || !module_name[0])
514+ return;
515+ fp = fopen("caitsith-load-module.tmp", "w");
516+ if (!fp) {
517+ fprintf(stderr, "ERROR: Can't create module loader.\n");
518+ return;
519+ }
520+ fprintf(stderr, "Creating module loader... ");
521+ fprintf(fp, "#! /bin/sh\n");
522+ fprintf(fp, "export PATH=$PATH:/sbin:/bin\n");
523+ fprintf(fp, "exec modprobe %s\n", module_name);
524+ close_file(fp, !chmod("caitsith-load-module.tmp", 0700),
525+ "caitsith-load-module.tmp", "caitsith-load-module");
526+}
527+
528+/* Content of /etc/caitsith/tools/auditd.conf . */
529+static const char auditd_data[] =
530+"# This file contains sorting rules used by caitsith-auditd command.\n"
531+"\n"
532+"# An audit log consists with two parts delimited by \" / \" sequence.\n"
533+"# You can refer the former part using 'header' keyword, the latter part\n"
534+"# using 'acl' keyword.\n"
535+"#\n"
536+"# Words in each part are separated by a space character. Therefore, you can\n"
537+"# use 'header[index]', 'acl[index]' for referring index'th word of the\n"
538+"# part.\n"
539+"# The index starts from 1, and 0 refers the whole line\n"
540+"# (i.e. 'header[0]' = 'header', 'acl[0]' = 'acl').\n"
541+"#\n"
542+"# Three operators are provided for conditional sorting.\n"
543+"# '.contains' is for 'fgrep keyword' match.\n"
544+"# '.equals' is for 'grep ^keyword$' match.\n"
545+"# '.starts' is for 'grep ^keyword' match.\n"
546+"#\n"
547+"# Sorting rules are defined using multi-lined chunks. A chunk is terminated\n"
548+"# by a 'destination' line which specifies the pathname to write the audit\n"
549+"# log. A 'destination' line is processed only when all preceding 'header'\n"
550+"# and 'acl' lines in that chunk have matched.\n"
551+"# Evaluation stops at the first processed 'destination' line.\n"
552+"# Therefore, no audit logs are written more than once.\n"
553+"#\n"
554+"# More specific matches should be placed before less specific matches.\n"
555+"# For example:\n"
556+"#\n"
557+"# header.contains result=denied\n"
558+"# acl.contains task.domain=\"/usr/sbin/httpd\"\n"
559+"# destination /var/log/caitsith/httpd_denied.log\n"
560+"#\n"
561+"# This chunk should be placed before the chunk that matches logs with\n"
562+"# result=denied. If placed after, the audit logs for /usr/sbin/httpd will\n"
563+"# be sent to /var/log/caitsith/denied.log .\n"
564+"\n"
565+"# Please use CaitSith's escape rule (e.g. '\\040' rather than '\\ ' for\n"
566+"# representing a ' ' in a word).\n"
567+"\n"
568+"# Send all allowed logs to /dev/null.\n"
569+"header.contains result=allowed\n"
570+"destination /dev/null\n"
571+"\n"
572+"# Send all unmatched logs to /var/log/caitsith/unmatched.log\n"
573+"header.contains result=unmatched\n"
574+"destination /var/log/caitsith/unmatched.log\n"
575+"\n"
576+"# Send all denied logs to /var/log/caitsith/denied.log\n"
577+"header.contains result=denied\n"
578+"destination /var/log/caitsith/denied.log\n"
579+"\n";
580+
581+/**
582+ * make_auditd_conf - Make /etc/caitsith/tools/auditd.conf .
583+ *
584+ * Returns nothing.
585+ */
586+static void make_auditd_conf(void)
587+{
588+ FILE *fp;
589+ if (chdir(policy_dir) || chdir("tools") ||
590+ !access("auditd.conf", R_OK))
591+ return;
592+ fp = fopen("auditd.tmp", "w");
593+ if (!fp) {
594+ fprintf(stderr, "ERROR: Can't create configuration file.\n");
595+ return;
596+ }
597+ fprintf(stderr, "Creating configuration file for caitsith-auditd ... ");
598+ fprintf(fp, "%s", auditd_data);
599+ close_file(fp, !chmod("auditd.tmp", 0644), "auditd.tmp",
600+ "auditd.conf");
601+}
602+
603+/* Content of /etc/caitsith/tools/notifyd.conf . */
604+static const char notifyd_data[] =
605+"# This file contains configuration used by caitsith-notifyd command.\n"
606+"\n"
607+"# caitsith-notifyd is a daemon that notifies the occurrence of an access\n"
608+"# request that is about to be rejected by CaitSith.\n"
609+"#\n"
610+"# time_to_wait is grace time in second before rejecting the request.\n"
611+"# For example, if you specify 30, you will be given 30 seconds for starting\n"
612+"# caitsith-queryd command and responding to the policy violation event.\n"
613+"# You should avoid specifying too large value (e.g. 3600) because\n"
614+"# the request will remain pending for that period if you can't respond.\n"
615+"#\n"
616+"# action_to_take is a command line you want to use for notification.\n"
617+"# The command specified by this parameter must read the policy violation\n"
618+"# notification from standard input. For example, mail, curl and xmessage\n"
619+"# commands can read from standard input.\n"
620+"# This parameter is passed to execve(). Thus, please use a wrapper program\n"
621+"# if you need shell processing (e.g. wildcard expansion, environment\n"
622+"# variables).\n"
623+"#\n"
624+"# minimal_interval is grace time in second before re-notifying the next\n"
625+"# occurrence of policy violation. You can specify 60 to limit notification\n"
626+"# to once per a minute, 3600 to limit notification to once per an hour.\n"
627+"# You can specify 0 to unlimit, but notifying of every policy violation\n"
628+"# events (e.g. sending a mail) might annoy you because policy violation\n"
629+"# can occur in clusters if once occurred.\n"
630+"\n"
631+"# Please use CaitSith's escape rule (e.g. '\\040' rather than '\\ ' for\n"
632+"# representing a ' ' in a word).\n"
633+"\n"
634+"# Examples:\n"
635+"#\n"
636+"# time_to_wait 180\n"
637+"# action_to_take mail admin@example.com\n"
638+"#\n"
639+"# Wait for 180 seconds before rejecting the request.\n"
640+"# The occurrence is notified by sending mail to admin@example.com\n"
641+"# (if SMTP service is available).\n"
642+"#\n"
643+"# time_to_wait 0\n"
644+"# action_to_take curl --data-binary @- https://your.server/path_to_cgi\n"
645+"#\n"
646+"# Reject the request immediately.\n"
647+"# The occurrence is notified by executing curl command.\n"
648+"#\n"
649+"time_to_wait 0\n"
650+"action_to_take mail -s Notification\\040from\\040caitsith-notifyd root@localhost\n"
651+"minimal_interval 60\n"
652+"\n";
653+
654+/**
655+ * make_notifyd_conf - Make /etc/caitsith/tools/notifyd.conf .
656+ *
657+ * Returns nothing.
658+ */
659+static void make_notifyd_conf(void)
660+{
661+ FILE *fp;
662+ if (chdir(policy_dir) || chdir("tools") ||
663+ !access("notifyd.conf", R_OK))
664+ return;
665+ fp = fopen("notifyd.tmp", "w");
666+ if (!fp) {
667+ fprintf(stderr, "ERROR: Can't create configuration file.\n");
668+ return;
669+ }
670+ fprintf(stderr, "Creating configuration file for caitsith-notifyd ... ");
671+ fprintf(fp, "%s", notifyd_data);
672+ close_file(fp, !chmod("notifyd.tmp", 0644), "notifyd.tmp",
673+ "notifyd.conf");
674+}
675+
676+int main(int argc, char *argv[])
677+{
678+ int i;
679+ const char *dir = NULL;
680+ for (i = 1; i < argc; i++) {
681+ char *arg = argv[i];
682+ if (*arg == '-' && *(arg + 1) == '-')
683+ arg += 2;
684+ if (!strncmp(arg, "root=", 5)) {
685+ if (chroot(arg + 5) || chdir("/")) {
686+ fprintf(stderr, "Can't chroot to '%s'\n",
687+ arg + 5);
688+ return 1;
689+ }
690+ } else if (!strncmp(arg, "policy_dir=", 11)) {
691+ dir = arg + 11;
692+ } else if (!strncmp(arg, "module_name=", 12)) {
693+ module_name = arg + 12;
694+ } else {
695+ fprintf(stderr, "Unknown option: '%s'\n", argv[i]);
696+ return 1;
697+ }
698+ }
699+ if (!dir)
700+ dir = "/etc/caitsith";
701+ policy_dir = strdup(dir);
702+ memset(path, 0, sizeof(path));
703+ make_policy_dir();
704+ make_policy();
705+ make_module_loader();
706+ make_auditd_conf();
707+ make_notifyd_conf();
708+ return 0;
709+}
--- tags/caitsith-tools/0.2.1/usr_lib_caitsith/Makefile (nonexistent)
+++ tags/caitsith-tools/0.2.1/usr_lib_caitsith/Makefile (revision 219)
@@ -0,0 +1,18 @@
1+include ../Include.make
2+
3+BUILD_FILES = audit-exec-param caitsith-agent init_policy
4+
5+all: $(BUILD_FILES)
6+
7+install: all
8+ mkdir -p -m 0755 $(INSTALLDIR)/$(USRLIBDIR)/caitsith
9+ $(INSTALL) -m 0755 $(BUILD_FILES) $(INSTALLDIR)/$(USRLIBDIR)/caitsith/
10+ $(INSTALL) -m 0644 ../README.caitsith ../COPYING.caitsith $(INSTALLDIR)/$(USRLIBDIR)/caitsith/
11+
12+.c:
13+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $<
14+
15+clean:
16+ rm -f -- $(BUILD_FILES)
17+
18+.PHONY: clean install
--- tags/caitsith-tools/0.2.1/Makefile (nonexistent)
+++ tags/caitsith-tools/0.2.1/Makefile (revision 219)
@@ -0,0 +1,21 @@
1+all:
2+ $(MAKE) -C sbin all
3+ $(MAKE) -C usr_sbin all
4+ $(MAKE) -C usr_lib_caitsith all
5+
6+install: all
7+ $(MAKE) -C sbin install
8+ $(MAKE) -C usr_sbin install
9+ $(MAKE) -C usr_lib_caitsith install
10+
11+clean:
12+##
13+## I don't enable "find" line because older versions does not support -delete
14+## action.
15+##
16+# find -name '*~' -delete
17+ $(MAKE) -C sbin clean
18+ $(MAKE) -C usr_sbin clean
19+ $(MAKE) -C usr_lib_caitsith clean
20+
21+.PHONY: clean install
Show on old repository browser