policycoreutils/policycoreutils-rhat.patch

4064 lines
119 KiB
Diff
Raw Normal View History

diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile
index 86ed03f..3e95698 100644
--- a/policycoreutils/Makefile
+++ b/policycoreutils/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = setfiles semanage load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po
+SUBDIRS = setfiles semanage semanage/default_encoding load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool po
INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null)
diff --git a/policycoreutils/audit2allow/audit2allow b/policycoreutils/audit2allow/audit2allow
index 5435e9d..e9d5882 100644
--- a/policycoreutils/audit2allow/audit2allow
+++ b/policycoreutils/audit2allow/audit2allow
@@ -1,4 +1,4 @@
-#! /usr/bin/python -E
+#! /usr/bin/python -Es
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
#
# Copyright (C) 2006-2007 Red Hat
@@ -28,6 +28,7 @@ import sepolgen.objectmodel as objectmodel
import sepolgen.defaults as defaults
import sepolgen.module as module
from sepolgen.sepolgeni18n import _
+import selinux.audit2why as audit2why
class AuditToPolicy:
VERSION = "%prog .1"
@@ -46,6 +47,7 @@ class AuditToPolicy:
help="audit messages since last boot conflicts with -i")
parser.add_option("-a", "--all", action="store_true", dest="audit", default=False,
help="read input from audit log - conflicts with -i")
+ parser.add_option("-p", "--policy", dest="policy", default=None, help="Policy file to use for analysis")
parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False,
help="read input from dmesg - conflicts with --all and --input")
parser.add_option("-i", "--input", dest="input",
@@ -102,7 +104,7 @@ class AuditToPolicy:
if name:
options.requires = True
if not module.is_valid_name(name):
- sys.stderr.write("only letters and numbers allowed in module names\n")
+ sys.stderr.write('error: module names must begin with a letter, optionally followed by letters, numbers, "-", "_", "."\n')
sys.exit(2)
# Make -M and -o conflict
@@ -231,29 +233,12 @@ class AuditToPolicy:
def __output_audit2why(self):
import selinux
- import selinux.audit2why as audit2why
import seobject
- audit2why.init()
for i in self.__parser.avc_msgs:
- rc, bools = audit2why.analyze(i.scontext.to_string(), i.tcontext.to_string(), i.tclass, i.accesses)
+ rc = i.type
+ bools = i.bools
if rc >= 0:
print "%s\n\tWas caused by:" % i.message
- if rc == audit2why.NOPOLICY:
- raise RuntimeError("Must call policy_init first")
- if rc == audit2why.BADTCON:
- print "Invalid Target Context %s\n" % i.tcontext
- continue
- if rc == audit2why.BADSCON:
- print "Invalid Source Context %s\n" % i.scontext
- continue
- if rc == audit2why.BADSCON:
- print "Invalid Type Class %s\n" % i.tclass
- continue
- if rc == audit2why.BADPERM:
- print "Invalid permission %s\n" % i.accesses
- continue
- if rc == audit2why. BADCOMPUTE:
- raise RuntimeError("Error during access vector computation")
if rc == audit2why.ALLOW:
print "\t\tUnknown - would be allowed by active policy\n",
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
@@ -350,11 +335,19 @@ class AuditToPolicy:
def main(self):
try:
self.__parse_options()
+ if self.__options.policy:
+ audit2why.init(self.__options.policy)
+ else:
+ audit2why.init()
+
self.__read_input()
self.__process_input()
self.__output()
except KeyboardInterrupt:
sys.exit(0)
+ except ValueError, e:
+ print e
+ sys.exit(1)
if __name__ == "__main__":
app = AuditToPolicy()
diff --git a/policycoreutils/audit2allow/audit2allow.1 b/policycoreutils/audit2allow/audit2allow.1
index fd9eb88..a854a45 100644
--- a/policycoreutils/audit2allow/audit2allow.1
+++ b/policycoreutils/audit2allow/audit2allow.1
@@ -67,6 +67,9 @@ Generate module/require output <modulename>
.B "\-M <modulename>"
Generate loadable module package, conflicts with -o
.TP
+.B "\-p <policyfile>" | "\-\-policy <policyfile>"
+Policy file to use for analysis
+.TP
.B "\-o <outputfile>" | "\-\-output <outputfile>"
append output to
.I <outputfile>
diff --git a/policycoreutils/audit2allow/sepolgen-ifgen b/policycoreutils/audit2allow/sepolgen-ifgen
index 0acbf7e..ef4bec3 100644
--- a/policycoreutils/audit2allow/sepolgen-ifgen
+++ b/policycoreutils/audit2allow/sepolgen-ifgen
@@ -28,6 +28,10 @@
import sys
import os
+import tempfile
+import subprocess
+
+import selinux
import sepolgen.refparser as refparser
import sepolgen.defaults as defaults
@@ -35,6 +39,7 @@ import sepolgen.interfaces as interfaces
VERSION = "%prog .1"
+ATTR_HELPER = "/usr/bin/sepolgen-ifgen-attr-helper"
def parse_options():
from optparse import OptionParser
2011-03-30 18:42:36 +00:00
@@ -44,14 +49,58 @@ def parse_options():
help="filename to store output")
parser.add_option("-i", "--interfaces", dest="headers", default=defaults.headers(),
help="location of the interface header files")
+ parser.add_option("-a", "--attribute_info", dest="attribute_info")
2011-03-30 18:42:36 +00:00
+ parser.add_option("-p", "--policy", dest="policy_path")
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="print debuging output")
parser.add_option("-d", "--debug", action="store_true", default=False,
help="extra debugging output")
+ parser.add_option("--no_attrs", action="store_true", default=False,
+ help="do not retrieve attribute access from kernel policy")
options, args = parser.parse_args()
return options
2011-03-30 18:42:36 +00:00
+def get_policy():
+ i = selinux.security_policyvers()
+ p = selinux.selinux_binary_policy_path() + "." + str(i)
+ while i > 0 and not os.path.exists(p):
+ i = i - 1
+ p = selinux.selinux_binary_policy_path() + "." + str(i)
+ if i > 0:
+ return p
+ return None
+
+def get_attrs(policy_path):
+ try:
2011-03-30 18:42:36 +00:00
+ if not policy_path:
+ policy_path = get_policy()
+ if not policy_path:
+ sys.stderr.write("No installed policy to check\n")
+ return None
+ outfile = tempfile.NamedTemporaryFile()
+ except IOError, e:
+ sys.stderr.write("could not open attribute output file\n")
+ return None
+ except OSError:
+ # SELinux Disabled Machine
+ return None
+
+ fd = open("/dev/null","w")
+ ret = subprocess.Popen([ATTR_HELPER, policy_path, outfile.name], stdout=fd).wait()
+ fd.close()
+ if ret != 0:
+ sys.stderr.write("could not run attribute helper")
+ return None
+
+ attrs = interfaces.AttributeSet()
+ try:
+ attrs.from_file(outfile)
+ except:
+ print "error parsing attribute info"
+ return None
+
+ return attrs
def main():
options = parse_options()
2011-03-30 18:42:36 +00:00
@@ -68,6 +117,14 @@ def main():
else:
log = None
+ # Get the attibutes from the binary
+ attrs = None
+ if not options.no_attrs:
2011-03-30 18:42:36 +00:00
+ attrs = get_attrs(options.policy_path)
+ if attrs is None:
+ return 1
+
+ # Parse the headers
try:
headers = refparser.parse_headers(options.headers, output=log, debug=options.debug)
except ValueError, e:
2011-03-30 18:42:36 +00:00
@@ -76,7 +133,7 @@ def main():
return 1
if_set = interfaces.InterfaceSet(output=log)
- if_set.add_headers(headers)
+ if_set.add_headers(headers, attributes=attrs)
if_set.to_file(f)
f.close()
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/newrole/newrole.c b/policycoreutils/newrole/newrole.c
index 99d0ed7..3f08d37 100644
2011-01-21 20:11:31 +00:00
--- a/policycoreutils/newrole/newrole.c
+++ b/policycoreutils/newrole/newrole.c
@@ -1030,10 +1030,11 @@ int main(int argc, char *argv[])
2011-01-21 20:11:31 +00:00
* if it makes sense to continue to run newrole, and setting up
* a scrubbed environment.
*/
- if (drop_capabilities(FALSE)) {
2011-01-21 20:11:31 +00:00
+/* if (drop_capabilities(FALSE)) {
perror(_("Sorry, newrole failed to drop capabilities\n"));
2011-01-21 20:11:31 +00:00
return -1;
}
2011-01-21 20:11:31 +00:00
+*/
if (set_signal_handles())
return -1;
diff --git a/policycoreutils/restorecond/Makefile b/policycoreutils/restorecond/Makefile
index 3f235e6..03a4544 100644
--- a/policycoreutils/restorecond/Makefile
+++ b/policycoreutils/restorecond/Makefile
@@ -1,17 +1,28 @@
# Installation directories.
PREFIX ?= ${DESTDIR}/usr
SBINDIR ?= $(PREFIX)/sbin
+LIBDIR ?= $(PREFIX)/lib
MANDIR = $(PREFIX)/share/man
+AUTOSTARTDIR = $(DESTDIR)/etc/xdg/autostart
+DBUSSERVICEDIR = $(DESTDIR)/usr/share/dbus-1/services
+
+autostart_DATA = sealertauto.desktop
INITDIR = $(DESTDIR)/etc/rc.d/init.d
SELINUXDIR = $(DESTDIR)/etc/selinux
+DBUSFLAGS = -DHAVE_DBUS -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/usr/lib/dbus-1.0/include
+DBUSLIB = -ldbus-glib-1 -ldbus-1
+
CFLAGS ?= -g -Werror -Wall -W
-override CFLAGS += -I$(PREFIX)/include -D_FILE_OFFSET_BITS=64
-LDLIBS += -lselinux -L$(PREFIX)/lib
+override CFLAGS += -I$(PREFIX)/include $(DBUSFLAGS) -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/lib/glib-2.0/include
+
+LDLIBS += -lselinux $(DBUSLIB) -lglib-2.0 -L$(LIBDIR)
all: restorecond
-restorecond: restorecond.o utmpwatcher.o stringslist.o
+restorecond.o utmpwatcher.o stringslist.o user.o watch.o: restorecond.h
+
+restorecond: ../setfiles/restore.o restorecond.o utmpwatcher.o stringslist.o user.o watch.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
install: all
@@ -22,7 +33,12 @@ install: all
-mkdir -p $(INITDIR)
install -m 755 restorecond.init $(INITDIR)/restorecond
-mkdir -p $(SELINUXDIR)
- install -m 600 restorecond.conf $(SELINUXDIR)/restorecond.conf
+ install -m 644 restorecond.conf $(SELINUXDIR)/restorecond.conf
+ install -m 644 restorecond_user.conf $(SELINUXDIR)/restorecond_user.conf
+ -mkdir -p $(AUTOSTARTDIR)
+ install -m 644 restorecond.desktop $(AUTOSTARTDIR)/restorecond.desktop
+ -mkdir -p $(DBUSSERVICEDIR)
+ install -m 600 org.selinux.Restorecond.service $(DBUSSERVICEDIR)/org.selinux.Restorecond.service
relabel: install
/sbin/restorecon $(SBINDIR)/restorecond
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/restorecond/org.selinux.Restorecond.service b/policycoreutils/restorecond/org.selinux.Restorecond.service
new file mode 100644
index 0000000..0ef5f0b
--- /dev/null
+++ b/policycoreutils/restorecond/org.selinux.Restorecond.service
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.selinux.Restorecond
+Exec=/usr/sbin/restorecond -u
diff --git a/policycoreutils/restorecond/restorecond.8 b/policycoreutils/restorecond/restorecond.8
index b149dcb..4622d2b 100644
--- a/policycoreutils/restorecond/restorecond.8
+++ b/policycoreutils/restorecond/restorecond.8
@@ -3,7 +3,7 @@
restorecond \- daemon that watches for file creation and then sets the default SELinux file context
.SH "SYNOPSIS"
-.B restorecond [\-d]
+.B restorecond [\-d] [\-f restorecond_file ] [\-u] [\-v]
.P
.SH "DESCRIPTION"
@@ -19,13 +19,22 @@ the correct file context associated with the policy.
.B \-d
Turns on debugging mode. Application will stay in the foreground and lots of
debugs messages start printing.
+.TP
+.B \-f restorecond_file
+Use alternative restorecond.conf file.
+.TP
+.B \-u
+Turns on user mode. Runs restorecond in the user session and reads /etc/selinux/restorecond_user.conf. Uses dbus to make sure only one restorecond is running per user session.
+.TP
+.B \-v
+Turns on verbose debugging. (Report missing files)
.SH "AUTHOR"
-This man page was written by Dan Walsh <dwalsh@redhat.com>.
-The program was written by Dan Walsh <dwalsh@redhat.com>.
+This man page and program was written by Dan Walsh <dwalsh@redhat.com>.
.SH "FILES"
/etc/selinux/restorecond.conf
+/etc/selinux/restorecond_user.conf
.SH "SEE ALSO"
.BR restorecon (8),
diff --git a/policycoreutils/restorecond/restorecond.c b/policycoreutils/restorecond/restorecond.c
index 4952632..89f5d97 100644
--- a/policycoreutils/restorecond/restorecond.c
+++ b/policycoreutils/restorecond/restorecond.c
@@ -30,9 +30,11 @@
* and makes sure that there security context matches the systems defaults
*
* USAGE:
- * restorecond [-d] [-v]
+ * restorecond [-d] [-u] [-v] [-f restorecond_file ]
*
* -d Run in debug mode
+ * -f Use alternative restorecond_file
+ * -u Run in user mode
* -v Run in verbose mode (Report missing files)
*
* EXAMPLE USAGE:
@@ -48,297 +50,38 @@
#include <signal.h>
#include <string.h>
#include <unistd.h>
-#include <ctype.h>
+#include "../setfiles/restore.h"
#include <sys/types.h>
-#include <sys/stat.h>
#include <syslog.h>
#include <limits.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
#include <fcntl.h>
-
#include "restorecond.h"
-#include "stringslist.h"
#include "utmpwatcher.h"
-extern char *dirname(char *path);
+const char *homedir;
static int master_fd = -1;
-static int master_wd = -1;
-static int terminate = 0;
-
-#include <selinux/selinux.h>
-#include <utmp.h>
-
-/* size of the event structure, not counting name */
-#define EVENT_SIZE (sizeof (struct inotify_event))
-/* reasonable guess as to size of 1024 events */
-#define BUF_LEN (1024 * (EVENT_SIZE + 16))
-static int debug_mode = 0;
-static int verbose_mode = 0;
-
-static void restore(const char *filename, int exact);
-
-struct watchList {
- struct watchList *next;
- int wd;
- char *dir;
- struct stringsList *files;
-};
-struct watchList *firstDir = NULL;
-
-/* Compare two contexts to see if their differences are "significant",
- * or whether the only difference is in the user. */
-static int only_changed_user(const char *a, const char *b)
-{
- char *rest_a, *rest_b; /* Rest of the context after the user */
- if (!a || !b)
- return 0;
- rest_a = strchr(a, ':');
- rest_b = strchr(b, ':');
- if (!rest_a || !rest_b)
- return 0;
- return (strcmp(rest_a, rest_b) == 0);
-}
+static char *server_watch_file = "/etc/selinux/restorecond.conf";
+static char *user_watch_file = "/etc/selinux/restorecond_user.conf";
+static char *watch_file;
+static struct restore_opts r_opts;
-/*
- A file was in a direcroty has been created. This function checks to
- see if it is one that we are watching.
-*/
-
-static int watch_list_find(int wd, const char *file)
-{
- struct watchList *ptr = NULL;
- ptr = firstDir;
-
- if (debug_mode)
- printf("%d: File=%s\n", wd, file);
- while (ptr != NULL) {
- if (ptr->wd == wd) {
- int exact=0;
- if (strings_list_find(ptr->files, file, &exact) == 0) {
- char *path = NULL;
- if (asprintf(&path, "%s/%s", ptr->dir, file) <
- 0)
- exitApp("Error allocating memory.");
- restore(path, exact);
- free(path);
- return 0;
- }
- if (debug_mode)
- strings_list_print(ptr->files);
-
- /* Not found in this directory */
- return -1;
- }
- ptr = ptr->next;
- }
- /* Did not find a directory */
- return -1;
-}
-
-static void watch_list_free(int fd)
-{
- struct watchList *ptr = NULL;
- struct watchList *prev = NULL;
- ptr = firstDir;
-
- while (ptr != NULL) {
- inotify_rm_watch(fd, ptr->wd);
- strings_list_free(ptr->files);
- free(ptr->dir);
- prev = ptr;
- ptr = ptr->next;
- free(prev);
- }
- firstDir = NULL;
-}
-
-/*
- Set the file context to the default file context for this system.
- Same as restorecon.
-*/
-static void restore(const char *filename, int exact)
-{
- int retcontext = 0;
- security_context_t scontext = NULL;
- security_context_t prev_context = NULL;
- struct stat st;
- int fd = -1;
- if (debug_mode)
- printf("restore %s\n", filename);
-
- fd = open(filename, O_NOFOLLOW | O_RDONLY);
- if (fd < 0) {
- if (verbose_mode)
- syslog(LOG_ERR, "Unable to open file (%s) %s\n",
- filename, strerror(errno));
- return;
- }
-
- if (fstat(fd, &st) != 0) {
- syslog(LOG_ERR, "Unable to stat file (%s) %s\n", filename,
- strerror(errno));
- close(fd);
- return;
- }
-
- if (!(st.st_mode & S_IFDIR) && st.st_nlink > 1) {
- if (exact) {
- syslog(LOG_ERR,
- "Will not restore a file with more than one hard link (%s) %s\n",
- filename, strerror(errno));
- }
- close(fd);
- return;
- }
-
- if (matchpathcon(filename, st.st_mode, &scontext) < 0) {
- if (errno == ENOENT)
- return;
- syslog(LOG_ERR, "matchpathcon(%s) failed %s\n", filename,
- strerror(errno));
- return;
- }
- retcontext = fgetfilecon_raw(fd, &prev_context);
-
- if (retcontext >= 0 || errno == ENODATA) {
- if (retcontext < 0)
- prev_context = NULL;
- if (retcontext < 0 || (strcmp(prev_context, scontext) != 0)) {
-
- if (only_changed_user(scontext, prev_context) != 0) {
- free(scontext);
- free(prev_context);
- close(fd);
- return;
- }
-
- if (fsetfilecon(fd, scontext) < 0) {
- if (errno != EOPNOTSUPP)
- syslog(LOG_ERR,
- "set context %s->%s failed:'%s'\n",
- filename, scontext, strerror(errno));
- if (retcontext >= 0)
- free(prev_context);
- free(scontext);
- close(fd);
- return;
- }
- syslog(LOG_WARNING, "Reset file context %s: %s->%s\n",
- filename, prev_context, scontext);
- }
- if (retcontext >= 0)
- free(prev_context);
- } else {
- if (errno != EOPNOTSUPP)
- syslog(LOG_ERR, "get context on %s failed: '%s'\n",
- filename, strerror(errno));
- }
- free(scontext);
- close(fd);
-}
-
-static void process_config(int fd, FILE * cfg)
-{
- char *line_buf = NULL;
- size_t len = 0;
-
- while (getline(&line_buf, &len, cfg) > 0) {
- char *buffer = line_buf;
- while (isspace(*buffer))
- buffer++;
- if (buffer[0] == '#')
- continue;
- int l = strlen(buffer) - 1;
- if (l <= 0)
- continue;
- buffer[l] = 0;
- if (buffer[0] == '~')
- utmpwatcher_add(fd, &buffer[1]);
- else {
- watch_list_add(fd, buffer);
- }
- }
- free(line_buf);
-}
-
-/*
- Read config file ignoring Comment lines
- Files specified one per line. Files with "~" will be expanded to the logged in users
- homedirs.
-*/
-
-static void read_config(int fd)
-{
- char *watch_file_path = "/etc/selinux/restorecond.conf";
-
- FILE *cfg = NULL;
- if (debug_mode)
- printf("Read Config\n");
-
- watch_list_free(fd);
-
- cfg = fopen(watch_file_path, "r");
- if (!cfg)
- exitApp("Error reading config file.");
- process_config(fd, cfg);
- fclose(cfg);
-
- inotify_rm_watch(fd, master_wd);
- master_wd =
- inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY);
- if (master_wd == -1)
- exitApp("Error watching config file.");
-}
-
-/*
- Inotify watch loop
-*/
-static int watch(int fd)
-{
- char buf[BUF_LEN];
- int len, i = 0;
- len = read(fd, buf, BUF_LEN);
- if (len < 0) {
- if (terminate == 0) {
- syslog(LOG_ERR, "Read error (%s)", strerror(errno));
- return 0;
- }
- syslog(LOG_ERR, "terminated");
- return -1;
- } else if (!len)
- /* BUF_LEN too small? */
- return -1;
- while (i < len) {
- struct inotify_event *event;
- event = (struct inotify_event *)&buf[i];
- if (debug_mode)
- printf("wd=%d mask=%u cookie=%u len=%u\n",
- event->wd, event->mask,
- event->cookie, event->len);
-
- if (event->mask & ~IN_IGNORED) {
- if (event->wd == master_wd)
- read_config(fd);
- else {
- switch (utmpwatcher_handle(fd, event->wd)) {
- case -1: /* Message was not for utmpwatcher */
- if (event->len)
- watch_list_find(event->wd, event->name);
- break;
-
- case 1: /* utmp has changed need to reload */
- read_config(fd);
- break;
+#include <selinux/selinux.h>
- default: /* No users logged in or out */
- break;
- }
- }
- }
+int debug_mode = 0;
+int terminate = 0;
+int master_wd = -1;
+int run_as_user = 0;
- i += EVENT_SIZE + event->len;
- }
- return 0;
+static void done(void) {
+ watch_list_free(master_fd);
+ close(master_fd);
+ utmpwatcher_free();
+ matchpathcon_fini();
}
static const char *pidfile = "/var/run/restorecond.pid";
@@ -377,7 +120,7 @@ static void term_handler()
static void usage(char *program)
{
- printf("%s [-d] [-v] \n", program);
+ printf("%s [-d] [-f restorecond_file ] [-u] [-v] \n", program);
exit(0);
}
@@ -393,74 +136,35 @@ void exitApp(const char *msg)
to see if it is one that we are watching.
*/
-void watch_list_add(int fd, const char *path)
-{
- struct watchList *ptr = NULL;
- struct watchList *prev = NULL;
- char *x = strdup(path);
- if (!x)
- exitApp("Out of Memory");
- char *dir = dirname(x);
- char *file = basename(path);
- ptr = firstDir;
-
- restore(path, 1);
-
- while (ptr != NULL) {
- if (strcmp(dir, ptr->dir) == 0) {
- strings_list_add(&ptr->files, file);
- free(x);
- return;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- ptr = calloc(1, sizeof(struct watchList));
-
- if (!ptr)
- exitApp("Out of Memory");
-
- ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO);
- if (ptr->wd == -1) {
- free(ptr);
- syslog(LOG_ERR, "Unable to watch (%s) %s\n",
- path, strerror(errno));
- return;
- }
-
- ptr->dir = strdup(dir);
- if (!ptr->dir)
- exitApp("Out of Memory");
-
- strings_list_add(&ptr->files, file);
- if (prev)
- prev->next = ptr;
- else
- firstDir = ptr;
-
- if (debug_mode)
- printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file);
-
- free(x);
-}
-
int main(int argc, char **argv)
{
int opt;
struct sigaction sa;
-#ifndef DEBUG
- /* Make sure we are root */
- if (getuid() != 0) {
- fprintf(stderr, "You must be root to run this program.\n");
- return 1;
- }
-#endif
- /* Make sure we are root */
- if (is_selinux_enabled() != 1) {
- fprintf(stderr, "Daemon requires SELinux be enabled to run.\n");
- return 1;
- }
+ memset(&r_opts, 0, sizeof(r_opts));
+
+ r_opts.progress = 0;
+ r_opts.count = 0;
+ r_opts.debug = 0;
+ r_opts.change = 1;
+ r_opts.verbose = 0;
+ r_opts.logging = 0;
+ r_opts.rootpath = NULL;
+ r_opts.rootpathlen = 0;
+ r_opts.outfile = NULL;
+ r_opts.force = 0;
+ r_opts.hard_links = 0;
+ r_opts.abort_on_error = 0;
+ r_opts.add_assoc = 0;
+ r_opts.expand_realpath = 0;
+ r_opts.fts_flags = FTS_PHYSICAL;
+ r_opts.selabel_opt_validate = NULL;
+ r_opts.selabel_opt_path = NULL;
+ r_opts.ignore_enoent = 1;
+
+ restore_init(&r_opts);
+ /* If we are not running SELinux then just exit */
+ if (is_selinux_enabled() != 1) return 0;
/* Register sighandlers */
sa.sa_flags = 0;
@@ -470,36 +174,59 @@ int main(int argc, char **argv)
set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
- master_fd = inotify_init();
- if (master_fd < 0)
- exitApp("inotify_init");
-
- while ((opt = getopt(argc, argv, "dv")) > 0) {
+ exclude_non_seclabel_mounts();
+ atexit( done );
+ while ((opt = getopt(argc, argv, "df:uv")) > 0) {
switch (opt) {
case 'd':
debug_mode = 1;
break;
+ case 'f':
+ watch_file = optarg;
+ break;
+ case 'u':
+ run_as_user = 1;
+ break;
case 'v':
- verbose_mode = 1;
+ r_opts.verbose++;
break;
case '?':
usage(argv[0]);
}
}
- read_config(master_fd);
+
+ master_fd = inotify_init();
+ if (master_fd < 0)
+ exitApp("inotify_init");
+
+ uid_t uid = getuid();
+ struct passwd *pwd = getpwuid(uid);
+ if (!pwd)
2011-03-30 18:42:36 +00:00
+ exitApp("getpwuid");
+
+ homedir = pwd->pw_dir;
+ if (uid != 0) {
+ if (run_as_user)
+ return server(master_fd, user_watch_file);
+ if (start() != 0)
+ return server(master_fd, user_watch_file);
+ return 0;
+ }
+
+ watch_file = server_watch_file;
+ read_config(master_fd, watch_file);
if (!debug_mode)
daemon(0, 0);
write_pid_file();
- while (watch(master_fd) == 0) {
+ while (watch(master_fd, watch_file) == 0) {
};
watch_list_free(master_fd);
close(master_fd);
matchpathcon_fini();
- utmpwatcher_free();
if (pidfile)
unlink(pidfile);
diff --git a/policycoreutils/restorecond/restorecond.conf b/policycoreutils/restorecond/restorecond.conf
index 3fc9376..58b723a 100644
--- a/policycoreutils/restorecond/restorecond.conf
+++ b/policycoreutils/restorecond/restorecond.conf
@@ -4,8 +4,5 @@
/etc/mtab
/var/run/utmp
/var/log/wtmp
-~/*
-/root/.ssh
+/root/*
/root/.ssh/*
-
-
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/restorecond/restorecond.desktop b/policycoreutils/restorecond/restorecond.desktop
new file mode 100644
index 0000000..23ff89d
--- /dev/null
+++ b/policycoreutils/restorecond/restorecond.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=File Context maintainer
+Exec=/usr/sbin/restorecond -u
+Comment=Fix file context in owned by the user
+Encoding=UTF-8
+Type=Application
+StartupNotify=false
diff --git a/policycoreutils/restorecond/restorecond.h b/policycoreutils/restorecond/restorecond.h
index e1666bf..8c85ef0 100644
--- a/policycoreutils/restorecond/restorecond.h
+++ b/policycoreutils/restorecond/restorecond.h
@@ -24,7 +24,22 @@
#ifndef RESTORED_CONFIG_H
#define RESTORED_CONFIG_H
-void exitApp(const char *msg);
-void watch_list_add(int inotify_fd, const char *path);
+extern int debug_mode;
+extern const char *homedir;
+extern int terminate;
+extern int master_wd;
+extern int run_as_user;
+
+extern int start(void);
+extern int server(int, const char *watch_file);
+
+extern void exitApp(const char *msg);
+extern void read_config(int fd, const char *watch_file);
+
+extern int watch(int fd, const char *watch_file);
+extern void watch_list_add(int inotify_fd, const char *path);
+extern int watch_list_find(int wd, const char *file);
+extern void watch_list_free(int fd);
+extern int watch_list_isempty();
#endif
diff --git a/policycoreutils/restorecond/restorecond.init b/policycoreutils/restorecond/restorecond.init
index b966db6..775c52b 100644
--- a/policycoreutils/restorecond/restorecond.init
+++ b/policycoreutils/restorecond/restorecond.init
@@ -26,7 +26,7 @@ PATH=/sbin:/bin:/usr/bin:/usr/sbin
# Source function library.
. /etc/rc.d/init.d/functions
-[ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled || exit 0
+[ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled || exit 7
# Check that we are root ... so non-root users stop here
test $EUID = 0 || exit 4
@@ -75,16 +75,15 @@ case "$1" in
status restorecond
RETVAL=$?
;;
- restart|reload)
+ force-reload|restart|reload)
restart
;;
condrestart)
[ -e /var/lock/subsys/restorecond ] && restart || :
;;
*)
- echo $"Usage: $0 {start|stop|restart|reload|condrestart}"
+ echo $"Usage: $0 {start|stop|restart|force-reload|status|condrestart}"
RETVAL=3
esac
exit $RETVAL
-
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/restorecond/restorecond_user.conf b/policycoreutils/restorecond/restorecond_user.conf
new file mode 100644
index 0000000..e0c2871
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/restorecond/restorecond_user.conf
@@ -0,0 +1,7 @@
+~/*
+~/public_html/*
+~/.gnome2/*
+~/local/*
+~/.fonts/*
+~/.cache/*
+~/.config/*
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/restorecond/user.c b/policycoreutils/restorecond/user.c
new file mode 100644
index 0000000..ade3fb8
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/restorecond/user.c
@@ -0,0 +1,246 @@
2011-01-21 20:11:31 +00:00
+/*
+ * restorecond
+ *
+ * Copyright (C) 2006-2009 Red Hat
2011-01-21 20:11:31 +00:00
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
2011-01-21 20:11:31 +00:00
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+.*
2011-01-21 20:11:31 +00:00
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
2011-01-21 20:11:31 +00:00
+ * 02111-1307 USA
+ *
+ * Authors:
2011-01-21 20:11:31 +00:00
+ * Dan Walsh <dwalsh@redhat.com>
+ *
+*/
+
+#define _GNU_SOURCE
+#include <sys/inotify.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "restorecond.h"
+#include "stringslist.h"
+#include <glib.h>
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data);
+
+static const char *PATH="/org/selinux/Restorecond";
+//static const char *BUSNAME="org.selinux.Restorecond";
+static const char *INTERFACE="org.selinux.RestorecondIface";
+static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'";
+
+
+static DBusHandlerResult
+signal_filter (DBusConnection *connection __attribute__ ((__unused__)), DBusMessage *message, void *user_data)
+{
+ /* User data is the event loop we are running in */
+ GMainLoop *loop = user_data;
+
+ /* A signal from the bus saying we are about to be disconnected */
+ if (dbus_message_is_signal
2011-01-21 20:11:31 +00:00
+ (message, INTERFACE, "Stop")) {
+
2011-01-21 20:11:31 +00:00
+ /* Tell the main loop to quit */
+ g_main_loop_quit (loop);
+ /* We have handled this message, don't pass it on */
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ /* A Ping signal on the com.burtonini.dbus.Signal interface */
+ else if (dbus_message_is_signal (message, INTERFACE, "Start")) {
+ DBusError error;
+ dbus_error_init (&error);
+ g_print("Start received\n");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int dbus_server(GMainLoop *loop) {
+ DBusConnection *bus;
+ DBusError error;
+ dbus_error_init (&error);
+ bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ if (bus) {
+ dbus_connection_setup_with_g_main (bus, NULL);
+
2011-01-21 20:11:31 +00:00
+ /* listening to messages from all objects as no path is specified */
+ dbus_bus_add_match (bus, RULE, &error); // see signals from the given interfacey
+ dbus_connection_add_filter (bus, signal_filter, loop, NULL);
+ return 0;
+ }
2011-01-21 20:11:31 +00:00
+ return -1;
+}
+
+#endif
+#include <selinux/selinux.h>
+#include <sys/file.h>
+
+/* size of the event structure, not counting name */
+#define EVENT_SIZE (sizeof (struct inotify_event))
+/* reasonable guess as to size of 1024 events */
+#define BUF_LEN (1024 * (EVENT_SIZE + 16))
+
+static gboolean
+io_channel_callback
+ (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data __attribute__((__unused__)))
+{
+
+ char buffer[BUF_LEN+1];
+ gsize bytes_read;
+ unsigned int i = 0;
+
+ if (condition & G_IO_IN) {
+ /* Data is available. */
+ g_io_channel_read
+ (source, buffer,
+ sizeof (buffer),
+ &bytes_read);
+
+ while (i < bytes_read) {
+ struct inotify_event *event;
+ event = (struct inotify_event *)&buffer[i];
+ if (debug_mode)
+ printf("wd=%d mask=%u cookie=%u len=%u\n",
+ event->wd, event->mask,
+ event->cookie, event->len);
+ if (event->len)
+ watch_list_find(event->wd, event->name);
+
2011-01-21 20:11:31 +00:00
+ i += EVENT_SIZE + event->len;
+ }
+ }
+
+ /* An error happened while reading
+ the file. */
+
+ if (condition & G_IO_NVAL)
+ return FALSE;
+
+ /* We have reached the end of the
+ file. */
+
+ if (condition & G_IO_HUP) {
+ g_io_channel_close (source);
+ return FALSE;
+ }
+
+ /* Returning TRUE will make sure
+ the callback remains associated
+ to the channel. */
+
+ return TRUE;
+}
+
+int start() {
+#ifdef HAVE_DBUS
+ DBusConnection *bus;
+ DBusError error;
+ DBusMessage *message;
+
2011-01-21 20:11:31 +00:00
+ /* Get a connection to the session bus */
+ dbus_error_init (&error);
+ bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ if (!bus) {
+ if (debug_mode)
+ g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
+ dbus_error_free (&error);
+ return 1;
+ }
+
2011-01-21 20:11:31 +00:00
+
+ /* Create a new signal "Start" on the interface,
+ * from the object */
+ message = dbus_message_new_signal (PATH,
+ INTERFACE, "Start");
+ /* Send the signal */
+ dbus_connection_send (bus, message, NULL);
+ /* Free the signal now we have finished with it */
+ dbus_message_unref (message);
+#endif /* HAVE_DBUS */
+ return 0;
+}
+
+static int local_server() {
+ // ! dbus, run as local service
+ char *ptr=NULL;
+ if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) {
+ if (debug_mode)
+ perror("asprintf");
+ return -1;
+ }
2011-01-21 20:11:31 +00:00
+ int fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+ if (debug_mode)
+ g_warning ("Lock file: %s", ptr);
+
2011-01-21 20:11:31 +00:00
+ free(ptr);
+ if (fd < 0) {
+ if (debug_mode)
+ perror("open");
+ return -1;
+ }
+ if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
+ if (debug_mode)
+ perror("flock");
+ return -1;
+ }
+ return 0;
+}
+
+int server(int master_fd, const char *watch_file) {
+ GMainLoop *loop;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
2011-01-21 20:11:31 +00:00
+#ifdef HAVE_DBUS
+ if (dbus_server(loop) != 0)
2011-01-21 20:11:31 +00:00
+#endif /* HAVE_DBUS */
+ if (local_server(loop))
2011-03-30 18:42:36 +00:00
+ goto end;
2011-01-21 20:11:31 +00:00
+
+ read_config(master_fd, watch_file);
+
2011-03-30 18:42:36 +00:00
+ if (watch_list_isempty()) goto end;
2011-01-21 20:11:31 +00:00
+
+ set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
+
2011-01-21 20:11:31 +00:00
+ GIOChannel *c = g_io_channel_unix_new(master_fd);
+
2011-01-21 20:11:31 +00:00
+ g_io_add_watch_full( c,
+ G_PRIORITY_HIGH,
+ G_IO_IN|G_IO_ERR|G_IO_HUP,
+ io_channel_callback, NULL, NULL);
+
2011-01-21 20:11:31 +00:00
+ g_main_loop_run (loop);
2011-03-30 18:42:36 +00:00
+
+end:
+ g_main_loop_unref (loop);
2011-01-21 20:11:31 +00:00
+ return 0;
+}
+
diff --git a/policycoreutils/restorecond/watch.c b/policycoreutils/restorecond/watch.c
new file mode 100644
index 0000000..6a833c3
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/restorecond/watch.c
@@ -0,0 +1,272 @@
2011-01-21 20:11:31 +00:00
+#define _GNU_SOURCE
+#include <sys/inotify.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include "../setfiles/restore.h"
+#include <glob.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <selinux/selinux.h>
+#include "restorecond.h"
+#include "stringslist.h"
+#include "utmpwatcher.h"
+
+/* size of the event structure, not counting name */
+#define EVENT_SIZE (sizeof (struct inotify_event))
+/* reasonable guess as to size of 1024 events */
+#define BUF_LEN (1024 * (EVENT_SIZE + 16))
+
+
+struct watchList {
+ struct watchList *next;
+ int wd;
+ char *dir;
+ struct stringsList *files;
+};
+struct watchList *firstDir = NULL;
+
+int watch_list_isempty() {
+ return firstDir == NULL;
+}
+
+void watch_list_add(int fd, const char *path)
+{
+ struct watchList *ptr = NULL;
+ size_t i = 0;
+ struct watchList *prev = NULL;
+ glob_t globbuf;
+ char *x = strdup(path);
+ if (!x) exitApp("Out of Memory");
+ char *file = basename(x);
+ char *dir = dirname(x);
+ ptr = firstDir;
+
2011-03-30 18:42:36 +00:00
+ if (exclude(path)) goto end;
2011-01-21 20:11:31 +00:00
+
+ globbuf.gl_offs = 1;
+ if (glob(path,
2011-01-21 20:11:31 +00:00
+ GLOB_TILDE | GLOB_PERIOD,
+ NULL,
+ &globbuf) >= 0) {
+ for (i=0; i < globbuf.gl_pathc; i++) {
+ int len = strlen(globbuf.gl_pathv[i]) -2;
+ if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0) continue;
+ if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0) continue;
+ if (process_one_realpath(globbuf.gl_pathv[i], 0) > 0)
+ process_one_realpath(globbuf.gl_pathv[i], 1);
+ }
+ globfree(&globbuf);
+ }
+
+ while (ptr != NULL) {
+ if (strcmp(dir, ptr->dir) == 0) {
+ strings_list_add(&ptr->files, file);
2011-03-30 18:42:36 +00:00
+ goto end;
2011-01-21 20:11:31 +00:00
+ }
+ prev = ptr;
+ ptr = ptr->next;
+ }
+ ptr = calloc(1, sizeof(struct watchList));
+
+ if (!ptr) exitApp("Out of Memory");
+
+ ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO);
+ if (ptr->wd == -1) {
+ free(ptr);
+ if (! run_as_user)
2011-01-21 20:11:31 +00:00
+ syslog(LOG_ERR, "Unable to watch (%s) %s\n",
+ path, strerror(errno));
2011-03-30 18:42:36 +00:00
+ goto end;
2011-01-21 20:11:31 +00:00
+ }
+
+ ptr->dir = strdup(dir);
+ if (!ptr->dir)
+ exitApp("Out of Memory");
+
+ strings_list_add(&ptr->files, file);
+ if (prev)
+ prev->next = ptr;
+ else
+ firstDir = ptr;
+
+ if (debug_mode)
+ printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file);
+
2011-03-30 18:42:36 +00:00
+end:
2011-01-21 20:11:31 +00:00
+ free(x);
2011-03-30 18:42:36 +00:00
+ return;
2011-01-21 20:11:31 +00:00
+}
+
+/*
+ A file was in a direcroty has been created. This function checks to
2011-01-21 20:11:31 +00:00
+ see if it is one that we are watching.
+*/
+
+int watch_list_find(int wd, const char *file)
+{
+ struct watchList *ptr = NULL;
+ ptr = firstDir;
+ if (debug_mode)
+ printf("%d: File=%s\n", wd, file);
+ while (ptr != NULL) {
+ if (ptr->wd == wd) {
+ int exact=0;
+ if (strings_list_find(ptr->files, file, &exact) == 0) {
+ char *path = NULL;
+ if (asprintf(&path, "%s/%s", ptr->dir, file) <
+ 0)
+ exitApp("Error allocating memory.");
+
2011-01-21 20:11:31 +00:00
+ process_one_realpath(path, 0);
+ free(path);
+ return 0;
+ }
+ if (debug_mode)
+ strings_list_print(ptr->files);
+
+ /* Not found in this directory */
+ return -1;
+ }
+ ptr = ptr->next;
+ }
+ /* Did not find a directory */
+ return -1;
+}
+
+void watch_list_free(int fd)
+{
+ struct watchList *ptr = NULL;
+ struct watchList *prev = NULL;
+ ptr = firstDir;
+
+ while (ptr != NULL) {
+ inotify_rm_watch(fd, ptr->wd);
+ strings_list_free(ptr->files);
+ free(ptr->dir);
+ prev = ptr;
+ ptr = ptr->next;
+ free(prev);
+ }
+ firstDir = NULL;
+}
+
+/*
+ Inotify watch loop
2011-01-21 20:11:31 +00:00
+*/
+int watch(int fd, const char *watch_file)
+{
+ char buf[BUF_LEN];
+ int len, i = 0;
+ if (firstDir == NULL) return 0;
+
+ len = read(fd, buf, BUF_LEN);
+ if (len < 0) {
+ if (terminate == 0) {
+ syslog(LOG_ERR, "Read error (%s)", strerror(errno));
+ return 0;
+ }
+ syslog(LOG_ERR, "terminated");
+ return -1;
+ } else if (!len)
+ /* BUF_LEN too small? */
+ return -1;
+ while (i < len) {
+ struct inotify_event *event;
+ event = (struct inotify_event *)&buf[i];
+ if (debug_mode)
+ printf("wd=%d mask=%u cookie=%u len=%u\n",
+ event->wd, event->mask,
+ event->cookie, event->len);
+ if (event->wd == master_wd)
+ read_config(fd, watch_file);
+ else {
+ switch (utmpwatcher_handle(fd, event->wd)) {
+ case -1: /* Message was not for utmpwatcher */
+ if (event->len)
+ watch_list_find(event->wd, event->name);
+ break;
+ case 1: /* utmp has changed need to reload */
+ read_config(fd, watch_file);
+ break;
+
2011-01-21 20:11:31 +00:00
+ default: /* No users logged in or out */
+ break;
+ }
+ }
+
+ i += EVENT_SIZE + event->len;
+ }
+ return 0;
+}
+
+static void process_config(int fd, FILE * cfg)
+{
+ char *line_buf = NULL;
+ size_t len = 0;
+
+ while (getline(&line_buf, &len, cfg) > 0) {
+ char *buffer = line_buf;
+ while (isspace(*buffer))
+ buffer++;
+ if (buffer[0] == '#')
+ continue;
+ int l = strlen(buffer) - 1;
+ if (l <= 0)
+ continue;
+ buffer[l] = 0;
+ if (buffer[0] == '~') {
+ if (run_as_user) {
+ char *ptr=NULL;
+ if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) < 0)
+ exitApp("Error allocating memory.");
+
2011-01-21 20:11:31 +00:00
+ watch_list_add(fd, ptr);
+ free(ptr);
+ } else {
+ utmpwatcher_add(fd, &buffer[1]);
+ }
+ } else {
+ watch_list_add(fd, buffer);
+ }
+ }
+ free(line_buf);
+}
+
+/*
+ Read config file ignoring Comment lines
2011-01-21 20:11:31 +00:00
+ Files specified one per line. Files with "~" will be expanded to the logged in users
+ homedirs.
+*/
+
+void read_config(int fd, const char *watch_file_path)
+{
+
+ FILE *cfg = NULL;
+ if (debug_mode)
+ printf("Read Config\n");
+
+ watch_list_free(fd);
+
+ cfg = fopen(watch_file_path, "r");
+ if (!cfg){
+ perror(watch_file_path);
+ exitApp("Error reading config file");
+ }
+ process_config(fd, cfg);
+ fclose(cfg);
+
+ inotify_rm_watch(fd, master_wd);
+ master_wd =
+ inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY);
+ if (master_wd == -1)
+ exitApp("Error watching config file.");
+}
diff --git a/policycoreutils/run_init/run_init.c b/policycoreutils/run_init/run_init.c
index 9db766c..068e24c 100644
--- a/policycoreutils/run_init/run_init.c
+++ b/policycoreutils/run_init/run_init.c
@@ -414,10 +414,17 @@ int main(int argc, char *argv[])
* execvp or using a exec(1) recycles pty's, and does not open a new
* one.
*/
+#ifdef USE_OPEN_INIT_PTY
if (execvp("/usr/sbin/open_init_pty", argv)) {
perror("execvp");
exit(-1);
}
+#else
+ if (execvp(argv[1], argv + 1)) {
+ perror("execvp");
+ exit(-1);
+ }
+#endif
return 0;
} /* main() */
diff --git a/policycoreutils/sandbox/Makefile b/policycoreutils/sandbox/Makefile
index 21df0c4..924999d 100644
--- a/policycoreutils/sandbox/Makefile
+++ b/policycoreutils/sandbox/Makefile
@@ -7,8 +7,8 @@ SBINDIR ?= $(PREFIX)/sbin
MANDIR ?= $(PREFIX)/share/man
LOCALEDIR ?= /usr/share/locale
SHAREDIR ?= $(PREFIX)/share/sandbox
-override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\""
-LDLIBS += -lselinux -lcap-ng
+override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\"" -Wall -Werror -Wextra
+LDLIBS += -lcgroup -lselinux -lcap-ng
all: sandbox seunshare sandboxX.sh start
@@ -22,7 +22,7 @@ install: all
install -m 644 sandbox.8 $(MANDIR)/man8/
install -m 644 seunshare.8 $(MANDIR)/man8/
-mkdir -p $(MANDIR)/man5
- install -m 644 sandbox.conf.5 $(MANDIR)/man5/
+ install -m 644 sandbox.conf.5 $(MANDIR)/man5/sandbox.5
-mkdir -p $(SBINDIR)
install -m 4755 seunshare $(SBINDIR)/
-mkdir -p $(SHAREDIR)
diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox
index edae667..486cd4e 100644
--- a/policycoreutils/sandbox/sandbox
+++ b/policycoreutils/sandbox/sandbox
@@ -29,7 +29,6 @@ import commands
import setools
PROGNAME = "policycoreutils"
2011-03-30 18:42:36 +00:00
-HOMEDIR=pwd.getpwuid(os.getuid()).pw_dir
SEUNSHARE = "/usr/sbin/seunshare"
SANDBOXSH = "/usr/share/sandbox/sandboxX.sh"
import gettext
@@ -258,9 +257,9 @@ Policy defines the following types for use with the -t:
pass
usage = _("""
-sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] command
+sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] command
-sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S
+sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S
%s
""") % types
@@ -309,6 +308,10 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
parser.add_option("-l", "--level", dest="level",
help=_("MCS/MLS level for the sandbox"))
+ parser.add_option("-c", "--cgroups",
+ action="store_true", dest="usecgroup", default=False,
+ help=_("Use cgroups to limit this sandbox."))
+
parser.add_option("-C", "--capabilities",
action="store_true", dest="usecaps", default=False,
help="Allow apps requiring capabilities to run within the sandbox.")
@@ -370,30 +373,29 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
def __setup_dir(self):
if self.__options.level or self.__options.session:
return
2011-03-30 18:42:36 +00:00
- sandboxdir = HOMEDIR + "/.sandbox"
- if not os.path.exists(sandboxdir):
- os.mkdir(sandboxdir)
if self.__options.homedir:
selinux.chcon(self.__options.homedir, self.__filecon, recursive=True)
self.__homedir = self.__options.homedir
else:
selinux.setfscreatecon(self.__filecon)
- self.__homedir = mkdtemp(dir=sandboxdir, prefix=".sandbox")
+ self.__homedir = mkdtemp(dir="/tmp", prefix=".sandbox_home_")
if self.__options.tmpdir:
selinux.chcon(self.__options.tmpdir, self.__filecon, recursive=True)
self.__tmpdir = self.__options.tmpdir
else:
selinux.setfscreatecon(self.__filecon)
- self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox")
2011-03-30 18:42:36 +00:00
+ self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox_tmp_")
selinux.setfscreatecon(None)
self.__copyfiles()
def __execute(self):
try:
cmds = [ SEUNSHARE, "-Z", self.__execcon ]
- if self.__options.usecaps == True:
+ if self.__options.usecgroup:
+ cmds.append('-c')
+ if self.__options.usecaps:
cmds.append('-C')
if self.__mount:
cmds += [ "-t", self.__tmpdir, "-h", self.__homedir ]
diff --git a/policycoreutils/sandbox/sandbox.8 b/policycoreutils/sandbox/sandbox.8
index e3b7ea7..2b37e63 100644
--- a/policycoreutils/sandbox/sandbox.8
+++ b/policycoreutils/sandbox/sandbox.8
@@ -3,11 +3,11 @@
sandbox \- Run cmd under an SELinux sandbox
.SH SYNOPSIS
.B sandbox
-[-C] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd
+[-C] [-c] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd
.br
.B sandbox
-[-C] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S
+[-C] [-c] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S
.br
.SH DESCRIPTION
.PP
@@ -60,10 +60,19 @@ Default to /usr/bin/matchbox-window-manager.
Create an X based Sandbox for gui apps, temporary files for
$HOME and /tmp, secondary Xserver, defaults to sandbox_x_t
.TP
+\fB\-c\fR
+Use control groups to control this copy of sandbox. Specify parameters in /etc/sysconfig/sandbox. Max memory usage and cpu usage are to be specified in percent. You can specify which CPUs to use by numbering them 0,1,2... etc.
+.TP
\fB\-C\fR
Use capabilities within the sandbox. By default applications executed within the sandbox will not be allowed to use capabilities (setuid apps), with the -C flag, you can use programs requiring capabilities.
.PP
.SH "SEE ALSO"
.TP
-runcon(1)
+runcon(1), seunshare(8), selinux(8)
.PP
+
+.SH AUTHOR
+This manual page was written by
+.I Dan Walsh <dwalsh@redhat.com>
+and
+.I Thomas Liu <tliu@fedoraproject.org>
diff --git a/policycoreutils/sandbox/sandbox.init b/policycoreutils/sandbox/sandbox.init
index ff8b3ef..66aadfd 100644
--- a/policycoreutils/sandbox/sandbox.init
+++ b/policycoreutils/sandbox/sandbox.init
@@ -10,17 +10,12 @@
#
# chkconfig: 345 1 99
#
-# Description: sandbox and other apps that want to use pam_namespace
-# on /var/tmp, /tmp and home directories, requires this script
-# to be run at boot time.
-# This script sets up the / mount point and all of its
-# subdirectories as shared. The script sets up
-# /tmp, /var/tmp, /home and any homedirs listed in
-# /etc/sysconfig/sandbox and all of their subdirectories
-# as unshared.
-# All processes that use pam_namespace will see
-# modifications to the global mountspace, except for the
-# unshared directories.
+# description: sandbox, xguest and other apps that want to use pam_namespace \
+# require this script be run at boot. This service script does \
+# not actually run any service but sets up: \
+# /var/tmp, /tmp and home directories to be used by these tools.\
+# If you do not use sandbox, xguest or pam_namespace you can turn \
+# this service off.\
#
# Source function library.
@@ -41,15 +36,6 @@ start() {
touch $LOCKFILE
mount --make-rshared / || return $?
- mount --rbind /tmp /tmp || return $?
- mount --rbind /var/tmp /var/tmp || return $?
- mount --make-private /tmp || return $?
- mount --make-private /var/tmp || return $?
- for h in $HOMEDIRS; do
- mount --rbind $h $h || return $?
- mount --make-private $h || return $?
- done
-
return 0
}
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/sandbox/seunshare.8 b/policycoreutils/sandbox/seunshare.8
index a9b846b..06610c0 100644
--- a/policycoreutils/sandbox/seunshare.8
2011-01-21 20:11:31 +00:00
+++ b/policycoreutils/sandbox/seunshare.8
@@ -3,7 +3,7 @@
seunshare \- Run cmd with alternate homedir, tmpdir and/or SELinux context
.SH SYNOPSIS
.B seunshare
-[ -v ] [ -c ] [ -C ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args]
+[ -v ] [ -c ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args]
.br
.SH DESCRIPTION
.PP
@@ -16,7 +16,7 @@ within the specified context, using the alternate home directory and /tmp direct
Alternate homedir to be used by the application. Homedir must be owned by the user.
.TP
\fB\-t\ tmpdir
-Use alternate temporary directory to mount on /tmp. tmpdir must be owned by the user.
2011-03-30 18:42:36 +00:00
+Use alternate tempory directory to mount on /tmp. tmpdir must be owned by the user.
.TP
\fB\-c --cgroups\fR
Use cgroups to control this copy of seunshare. Specify parameters in /etc/sysconfig/sandbox. Max memory usage and cpu usage are to be specified in percent. You can specify which CPUs to use by numbering them 0,1,2... etc.
@@ -24,6 +24,9 @@ Use cgroups to control this copy of seunshare. Specify parameters in /etc/sysco
\fB\-C --capabilities\fR
Allow apps executed within the namespace to use capabilities. Default is no capabilities.
.TP
+\fB\-k --kill\fR
+Kill all processes with matching MCS level.
+.TP
\fB\-Z\ context
Use alternate SELinux context while runing the executable.
.TP
diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c
index f9bf12c..594aff4 100644
--- a/policycoreutils/sandbox/seunshare.c
+++ b/policycoreutils/sandbox/seunshare.c
@@ -1,27 +1,35 @@
+/*
+ * Authors: Dan Walsh <dwalsh@redhat.com>
+ * Authors: Thomas Liu <tliu@fedoraproject.org>
+ */
+
#define _GNU_SOURCE
#include <signal.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <syslog.h>
#include <sys/mount.h>
2011-03-30 18:42:36 +00:00
+#include <glob.h>
#include <pwd.h>
#include <sched.h>
+#include <libcgroup.h>
#include <string.h>
#include <stdio.h>
+#include <regex.h>
#include <unistd.h>
+#include <sys/fsuid.h>
#include <stdlib.h>
#include <cap-ng.h>
#include <getopt.h> /* for getopt_long() form of getopt() */
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
+#include <fcntl.h>
#include <selinux/selinux.h>
#include <selinux/context.h> /* for context-mangling functions */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <dirent.h>
#ifdef USE_NLS
#include <locale.h> /* for setlocale() */
@@ -39,10 +47,16 @@
#define MS_PRIVATE 1<<18
#endif
+#ifndef PACKAGE
+#define PACKAGE "policycoreutils" /* the name of this package lang translation */
+#endif
+
+#define BUF_SIZE 1024
#define DEFAULT_PATH "/usr/bin:/bin"
-#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [-t tmpdir] [-h homedir] [-Z context] -- executable [args]")
+#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -c ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ")
static int verbose = 0;
+static int child = 0;
static capng_select_t cap_set = CAPNG_SELECT_BOTH;
@@ -74,6 +88,13 @@ static int drop_privs(uid_t uid)
}
/**
+ * If the user sends a siginto to seunshare, kill the child's session
+ */
+void handler(int sig) {
+ if (child > 0) kill(-child,sig);
2011-03-30 18:42:36 +00:00
+}
+
+/**
* Take care of any signal setup.
2011-03-30 18:42:36 +00:00
*/
static int set_signal_handles(void)
@@ -88,12 +109,17 @@ static int set_signal_handles(void)
2011-03-30 18:42:36 +00:00
(void)sigprocmask(SIG_SETMASK, &empty, NULL);
- /* Terminate on SIGHUP. */
+ /* Terminate on SIGHUP */
if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
2011-03-30 18:42:36 +00:00
perror("Unable to set SIGHUP handler");
return -1;
2011-03-30 18:42:36 +00:00
}
+ if (signal(SIGINT, handler) == SIG_ERR) {
+ perror("Unable to set SIGINT handler");
+ return -1;
+ }
+
return 0;
}
@@ -139,26 +165,6 @@ static int spawn_command(const char *cmd, uid_t uid){
}
2011-03-30 18:42:36 +00:00
/**
- * This function makes sure the mounted directory is owned by the user executing
- * seunshare.
- * If so, it returns 0. If it can not figure this out or they are different, it returns -1.
- */
2011-03-30 18:42:36 +00:00
-static int verify_mount(const char *mntdir, struct passwd *pwd) {
- struct stat sb;
- if (stat(mntdir, &sb) == -1) {
- fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, strerror(errno));
- return -1;
- }
2011-03-30 18:42:36 +00:00
- if (sb.st_uid != pwd->pw_uid) {
- errno = EPERM;
- syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir);
- perror(_("Invalid mount point, reporting to administrator"));
- return -1;
- }
- return 0;
-}
-
-/**
* Check file/directory ownership, struct stat * must be passed to the
* functions.
*/
@@ -236,7 +242,7 @@ static int verify_shell(const char *shell_name)
2011-03-30 18:42:36 +00:00
/* check the shell skipping newline char */
if (!strcmp(shell_name, buf)) {
- rc = 1;
+ rc = 0;
break;
}
}
@@ -244,43 +250,600 @@ static int verify_shell(const char *shell_name)
return rc;
}
-static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) {
2011-03-30 18:42:36 +00:00
+/**
+ * Mount directory and check that we mounted the right directory.
+ */
+static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
+{
+ int flags = MS_REC;
+ int is_tmp = 0;
+
if (verbose)
2011-03-30 18:42:36 +00:00
- printf("Mount %s on %s\n", src, dst);
- if (mount(dst, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
2011-03-30 18:42:36 +00:00
+ printf(_("Mounting %s on %s\n"), src, dst);
+
2011-03-30 18:42:36 +00:00
+ if (strcmp("/tmp", dst) == 0) {
+ flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
+ is_tmp = 1;
+ }
+
+ /* mount directory */
+ if (mount(dst, dst, NULL, MS_BIND | flags, NULL) < 0) {
fprintf(stderr, _("Failed to mount %s on %s: %s\n"), dst, dst, strerror(errno));
return -1;
}
2011-03-30 18:42:36 +00:00
-
- if (mount(dst, dst, NULL, MS_PRIVATE | MS_REC, NULL) < 0) {
+ if (mount(dst, dst, NULL, MS_PRIVATE | flags, NULL) < 0) {
fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno));
return -1;
}
2011-03-30 18:42:36 +00:00
-
- if (mount(src, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
+ if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
return -1;
}
- if (verify_mount(dst, pwd) < 0)
2011-03-30 18:42:36 +00:00
+ /* verify whether we mounted what we expected to mount */
+ if (verify_directory(dst, src_st, NULL) < 0) return -1;
+
2011-03-30 18:42:36 +00:00
+ /* bind mount /tmp on /var/tmp too */
+ if (is_tmp) {
+ if (verbose)
+ printf(_("Mounting /tmp on /var/tmp\n"));
+
2011-03-30 18:42:36 +00:00
+ if (mount("/var/tmp", "/var/tmp", NULL, MS_BIND | flags, NULL) < 0) {
+ fprintf(stderr, _("Failed to mount /var/tmp on /var/tmp: %s\n"), strerror(errno));
+ return -1;
+ }
2011-03-30 18:42:36 +00:00
+ if (mount("/var/tmp", "/var/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) {
+ fprintf(stderr, _("Failed to make /var/tmp private: %s\n"), strerror(errno));
+ return -1;
+ }
+ if (mount("/tmp", "/var/tmp", NULL, MS_BIND | flags, NULL) < 0) {
+ fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
+ return -1;
+ }
+ }
+
2011-03-30 18:42:36 +00:00
+ return 0;
+
+}
+
2011-03-30 18:42:36 +00:00
+/**
+ * Error logging used by cgroups code.
+ */
+static int sandbox_error(const char *string)
+{
+ fprintf(stderr, string);
+ syslog(LOG_AUTHPRIV | LOG_ALERT, string);
+ exit(-1);
+}
+
2011-03-30 18:42:36 +00:00
+/**
+ * Regular expression match.
+ */
+static int match(const char *string, char *pattern)
+{
+ int status;
+ regex_t re;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
+ return 0;
+ }
+ status = regexec(&re, string, (size_t)0, NULL, 0);
+ regfree(&re);
+ if (status != 0) {
+ return 0;
+ }
+ return 1;
+}
+
2011-03-30 18:42:36 +00:00
+/**
+ * Apply cgroups settings from the /etc/sysconfig/sandbox config file.
+ */
+static int setup_cgroups()
+{
+ char *cpus = NULL; /* which CPUs to use */
+ char *cgroupname = NULL;/* name for the cgroup */
+ char *mem = NULL; /* string for memory amount to pass to cgroup */
+ int64_t memusage = 0; /* amount of memory to use max (percent) */
+ int cpupercentage = 0; /* what percentage of cpu to allow usage */
+ FILE* fp;
+ char buf[BUF_SIZE];
+ char *tok = NULL;
2011-03-30 18:42:36 +00:00
+ int rc = -1;
+ char *str = NULL;
+ const char* fname = "/etc/sysconfig/sandbox";
+
+ if ((fp = fopen(fname, "rt")) == NULL) {
+ fprintf(stderr, "Error opening sandbox config file.");
2011-03-30 18:42:36 +00:00
+ return rc;
+ }
+ while(fgets(buf, BUF_SIZE, fp) != NULL) {
+ /* Skip comments */
+ if (buf[0] == '#') continue;
+
+ /* Copy the string, ignoring whitespace */
+ int len = strlen(buf);
+ free(str);
+ str = malloc((len + 1) * sizeof(char));
+ if (!str)
+ goto err;
+
+ int ind = 0;
+ int i;
+ for (i = 0; i < len; i++) {
+ char cur = buf[i];
+ if (cur != ' ' && cur != '\t') {
+ str[ind] = cur;
+ ind++;
+ }
+ }
+ str[ind] = '\0';
+
+ tok = strtok(str, "=\n");
+ if (tok != NULL) {
+ if (!strcmp(tok, "CPUAFFINITY")) {
+ tok = strtok(NULL, "=\n");
+ cpus = strdup(tok);
+ if (!strcmp(cpus, "ALL")) {
2011-03-30 18:42:36 +00:00
+ free(cpus);
+ cpus = NULL;
+ }
+ } else if (!strcmp(tok, "MEMUSAGE")) {
+ tok = strtok(NULL, "=\n");
+ if (match(tok, "^[0-9]+[kKmMgG%]")) {
+ char *ind = strchr(tok, '%');
+ if (ind != NULL) {
+ *ind = '\0';;
+ memusage = atoi(tok);
+ } else {
+ mem = strdup(tok);
+ }
+ } else {
+ fprintf(stderr, "Error parsing config file.");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+
+ } else if (!strcmp(tok, "CPUUSAGE")) {
+ tok = strtok(NULL, "=\n");
+ if (match(tok, "^[0-9]+\%")) {
+ char* ind = strchr(tok, '%');
+ *ind = '\0';
+ cpupercentage = atoi(tok);
+ } else {
+ fprintf(stderr, "Error parsing config file.");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+ } else if (!strcmp(tok, "NAME")) {
+ tok = strtok(NULL, "=\n");
+ cgroupname = strdup(tok);
+ } else {
+ continue;
+ }
+ }
+
+ }
+ if (mem == NULL) {
+ long phypz = sysconf(_SC_PHYS_PAGES);
+ long psize = sysconf(_SC_PAGE_SIZE);
+ memusage = phypz * psize * (float) memusage / 100.0;
+ }
+
+ cgroup_init();
+
+ int64_t current_runtime = 0;
+ int64_t current_period = 0 ;
+ int64_t current_mem = 0;
+ char *curr_cpu_path = NULL;
+ char *curr_mem_path = NULL;
+ int ret = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path);
+ if (ret) {
+ sandbox_error("Error while trying to get current controller path.\n");
+ } else {
+ struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path);
+ cgroup_get_cgroup(curr);
+ cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", &current_runtime);
+ cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", &current_period);
+ }
+
+ ret = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path);
+ if (ret) {
+ sandbox_error("Error while trying to get current controller path.\n");
+ } else {
+ struct cgroup *curr = cgroup_new_cgroup(curr_mem_path);
+ cgroup_get_cgroup(curr);
+ cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", &current_mem);
+ }
+
+ if (((float) cpupercentage) / 100.0> (float)current_runtime / (float) current_period) {
+ sandbox_error("CPU usage restricted!\n");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+
+ if (mem == NULL) {
+ if (memusage > current_mem) {
+ sandbox_error("Attempting to use more memory than allowed!");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+ }
+
+ long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
+
+ struct sched_param sp;
+ sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
+ sched_setscheduler(getpid(), SCHED_FIFO, &sp);
+ struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname);
+ cgroup_add_controller(sandbox_group, "memory");
+ cgroup_add_controller(sandbox_group, "cpu");
+
+ if (mem == NULL) {
+ if (memusage > 0) {
+ cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage);
+ }
+ } else {
+ cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem);
+ }
+ if (cpupercentage > 0) {
+ cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us",
+ (float) cpupercentage / 100.0 * 60000);
+ cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs);
+ }
+ if (cpus != NULL) {
+ cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus);
+ }
+
+ uint64_t allocated_mem;
+ if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) {
+ sandbox_error("Attempting to use more memory than allowed!\n");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+
2011-03-30 18:42:36 +00:00
+ rc = cgroup_create_cgroup(sandbox_group, 1);
+ if (rc != 0) {
+ sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n");
2011-03-30 18:42:36 +00:00
+ goto err;
+ }
+
+ cgroup_attach_task(sandbox_group);
2011-03-30 18:42:36 +00:00
+
+ rc = 0;
+err:
2011-07-05 21:18:12 +00:00
+ fclose(fp);
+ free(str);
2011-03-30 18:42:36 +00:00
+ free(mem);
+ free(cgroupname);
+ free(cpus);
+ return rc;
+}
+
+/*
2011-03-30 18:42:36 +00:00
+ If path is empy or ends with "/." or "/.. return -1 else return 0;
+ */
+static int bad_path(const char *path) {
+ const char *ptr;
+ ptr = path;
+ while (*ptr) ptr++;
+ if (ptr == path) return -1; // ptr null
+ ptr--;
+ if (ptr != path && *ptr == '.') {
+ ptr--;
+ if (*ptr == '/') return -1; // path ends in /.
+ if (*ptr == '.') {
+ if (ptr != path) {
+ ptr--;
+ if (*ptr == '/') return -1; // path ends in /..
+ }
+ }
+ }
+ return 0;
+}
+
+static int rsynccmd(const char * src, const char *dst, char **cmdbuf)
2011-03-30 18:42:36 +00:00
+{
+ char *buf = NULL;
+ char *newbuf = NULL;
+ glob_t fglob;
+ fglob.gl_offs = 0;
+ int flags = GLOB_PERIOD;
+ unsigned int i = 0;
+ int rc = -1;
+
+ /* match glob for all files in src dir */
+ if (asprintf(&buf, "%s/*", src) == -1) {
+ fprintf(stderr, "Out of memory\n");
+ return -1;
+ }
+
+ if (glob(buf, flags, NULL, &fglob) != 0) {
+ free(buf); buf = NULL;
return -1;
+ }
+
+ free(buf); buf = NULL;
+
+ for ( i=0; i < fglob.gl_pathc; i++) {
+ const char *path = fglob.gl_pathv[i];
+
+ if (bad_path(path)) continue;
+
+ if (!buf) {
+ if (asprintf(&newbuf, "\'%s\'", path) == -1) {
+ fprintf(stderr, "Out of memory\n");
+ goto err;
+ }
+ } else {
+ if (asprintf(&newbuf, "%s \'%s\'", buf, path) == -1) {
+ fprintf(stderr, "Out of memory\n");
+ goto err;
+ }
+ }
+
+ free(buf); buf = newbuf;
+ newbuf = NULL;
+ }
+
+ if (buf) {
2011-03-30 18:42:36 +00:00
+ if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) {
+ fprintf(stderr, "Out of memory\n");
+ goto err;
+ }
+ *cmdbuf=newbuf;
+ }
+ else {
+ *cmdbuf=NULL;
+ }
+ rc = 0;
+
+err:
+ free(buf); buf = NULL;
+ globfree(&fglob);
+ return rc;
+}
+
2011-03-30 18:42:36 +00:00
+/**
+ * Clean up runtime temporary directory. Returns 0 if no problem was detected,
+ * >0 if some error was detected, but errors here are treated as non-fatal and
+ * left to tmpwatch to finish incomplete cleanup.
+ */
+static int cleanup_tmpdir(const char *tmpdir, const char *src,
+ struct passwd *pwd, int copy_content)
+{
+ char *cmdbuf = NULL;
+ int rc = 0;
+
+ /* rsync files back */
+ if (copy_content) {
+ if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
+ fprintf(stderr, _("Out of memory\n"));
+ cmdbuf = NULL;
+ rc++;
+ }
+ if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
+ fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
+ rc++;
+ }
+ free(cmdbuf); cmdbuf = NULL;
+ }
+
+ /* remove files from the runtime temporary directory */
+ if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
+ fprintf(stderr, _("Out of memory\n"));
+ cmdbuf = NULL;
+ rc++;
+ }
+ /* this may fail if there's root-owned file left in the runtime tmpdir */
+ if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
+ free(cmdbuf); cmdbuf = NULL;
+
+ /* remove runtime temporary directory */
+ setfsuid(0);
+ if (rmdir(tmpdir) == -1)
+ fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
+ setfsuid(pwd->pw_uid);
+
+ return 0;
+}
+
2011-03-30 18:42:36 +00:00
+/**
+ * seunshare will create a tmpdir in /tmp, with root ownership. The parent
+ * process waits for it child to exit to attempt to remove the directory. If
+ * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
+ * to clean it up.
+ */
+static char *create_tmpdir(const char *src, struct stat *src_st,
+ struct stat *out_st, struct passwd *pwd, security_context_t execcon)
+{
+ char *tmpdir = NULL;
+ char *cmdbuf = NULL;
+ int fd_t = -1, fd_s = -1;
+ struct stat tmp_st;
+ security_context_t con = NULL;
+
+ /* get selinux context */
+ if (execcon) {
+ setfsuid(pwd->pw_uid);
+ if ((fd_s = open(src, O_RDONLY)) < 0) {
+ fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
+ goto err;
+ }
+ if (fstat(fd_s, &tmp_st) == -1) {
+ fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
+ goto err;
+ }
+ if (!equal_stats(src_st, &tmp_st)) {
+ fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
+ goto err;
+ }
+ if (fgetfilecon(fd_s, &con) == -1) {
+ fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
+ goto err;
+ }
+
+ /* ok to not reach this if there is an error */
+ setfsuid(0);
+ }
+
+ if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
+ fprintf(stderr, _("Out of memory\n"));
+ tmpdir = NULL;
+ goto err;
+ }
+ if (mkdtemp(tmpdir) == NULL) {
+ fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
+ goto err;
+ }
+
+ /* temporary directory must be owned by root:user */
+ if (verify_directory(tmpdir, NULL, out_st) < 0) {
+ goto err;
+ }
+
+ if (check_owner_uid(0, tmpdir, out_st) < 0)
+ goto err;
+
+ if (check_owner_gid(getgid(), tmpdir, out_st) < 0)
+ goto err;
2011-03-30 18:42:36 +00:00
+
+ /* change permissions of the temporary directory */
+ if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
+ fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
+ goto err;
+ }
+ if (fstat(fd_t, &tmp_st) == -1) {
+ fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
+ goto err;
+ }
+ if (!equal_stats(out_st, &tmp_st)) {
+ fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
+ goto err;
+ }
+ if (fchmod(fd_t, 01770) == -1) {
+ fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
+ goto err;
+ }
+ /* re-stat again to pick change mode */
+ if (fstat(fd_t, out_st) == -1) {
+ fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
+ goto err;
+ }
+
+ /* copy selinux context */
+ if (execcon) {
+ if (fsetfilecon(fd_t, con) == -1) {
2011-03-30 18:42:36 +00:00
+ fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
+ goto err;
+ }
+ }
+
+ setfsuid(pwd->pw_uid);
+
+ if (rsynccmd(src, tmpdir, &cmdbuf) < 0) {
+ goto err;
+ }
+
+ /* ok to not reach this if there is an error */
+ setfsuid(0);
+
+ if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
+ fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
+ cleanup_tmpdir(tmpdir, src, pwd, 0);
+ goto err;
+ }
+
+ goto good;
+err:
+ free(tmpdir); tmpdir = NULL;
+good:
+ free(cmdbuf); cmdbuf = NULL;
+ freecon(con); con = NULL;
+ if (fd_t >= 0) close(fd_t);
+ if (fd_s >= 0) close(fd_s);
+ return tmpdir;
+}
+
+#define PROC_BASE "/proc"
+
+static int
+killall (security_context_t execcon)
+{
+ DIR *dir;
+ security_context_t scon;
+ struct dirent *de;
+ pid_t *pid_table, pid, self;
+ int i;
+ int pids, max_pids;
+ int running = 0;
+ self = getpid();
+ if (!(dir = opendir(PROC_BASE))) {
+ return -1;
+ }
+ max_pids = 256;
+ pid_table = malloc(max_pids * sizeof (pid_t));
+ if (!pid_table) {
+ (void)closedir(dir);
+ return -1;
+ }
+ pids = 0;
+ context_t con;
+ con = context_new(execcon);
+ const char *mcs = context_range_get(con);
+ printf("mcs=%s\n", mcs);
+ while ((de = readdir (dir)) != NULL) {
+ if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
+ continue;
+
+ if (pids == max_pids) {
+ if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) {
+ (void)closedir(dir);
+ return -1;
+ }
+ max_pids *= 2;
+ }
+ pid_table[pids++] = pid;
+ }
+
+ (void)closedir(dir);
+
+ for (i = 0; i < pids; i++) {
+ pid_t id = pid_table[i];
+
+ if (getpidcon(id, &scon) == 0) {
+
+ context_t pidcon = context_new(scon);
+ /* Attempt to kill remaining processes */
+ if (strcmp(context_range_get(pidcon), mcs) == 0)
+ kill(id, SIGKILL);
+
+ context_free(pidcon);
+ freecon(scon);
+ }
+ running++;
+ }
+
+ context_free(con);
+ free(pid_table);
+ return running;
}
int main(int argc, char **argv) {
- int rc;
int status = -1;
+ security_context_t execcon = NULL;
- security_context_t scontext = NULL;
2011-03-30 18:42:36 +00:00
-
- int flag_index; /* flag index in argv[] */
int clflag; /* holds codes for command line flags */
2011-03-30 18:42:36 +00:00
- char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
+ int usecgroups = 0;
+ int kill_all = 0;
2011-03-30 18:42:36 +00:00
+
char *homedir_s = NULL; /* homedir spec'd by user in argv[] */
+ char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
+ char *tmpdir_r = NULL; /* tmpdir created by seunshare */
+
+ struct stat st_homedir;
+ struct stat st_tmpdir_s;
+ struct stat st_tmpdir_r;
const struct option long_options[] = {
{"homedir", 1, 0, 'h'},
2011-03-30 18:42:36 +00:00
{"tmpdir", 1, 0, 't'},
+ {"kill", 1, 0, 'k'},
{"verbose", 1, 0, 'v'},
+ {"cgroups", 1, 0, 'c'},
{"context", 1, 0, 'Z'},
{"capabilities", 1, 0, 'C'},
{NULL, 0, 0, 0}
@@ -294,6 +857,12 @@ int main(int argc, char **argv) {
}
*/
+#ifdef USE_NLS
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+
struct passwd *pwd=getpwuid(uid);
if (!pwd) {
perror(_("getpwduid failed"));
@@ -301,7 +870,7 @@ int main(int argc, char **argv) {
2011-03-30 18:42:36 +00:00
}
if (verify_shell(pwd->pw_shell) < 0) {
- fprintf(stderr, _("Error! Shell is not valid.\n"));
+ fprintf(stderr, _("Error: User shell is not valid\n"));
return -1;
}
@@ -312,28 +881,25 @@ int main(int argc, char **argv) {
switch (clflag) {
2011-03-30 18:42:36 +00:00
case 't':
- if (!(tmpdir_s = realpath(optarg, NULL))) {
- fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
- return -1;
- }
- if (verify_mount(tmpdir_s, pwd) < 0) return -1;
2011-03-30 18:42:36 +00:00
+ tmpdir_s = optarg;
+ break;
+ case 'k':
+ kill_all = 1;
2011-03-30 18:42:36 +00:00
break;
case 'h':
- if (!(homedir_s = realpath(optarg, NULL))) {
- fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
- return -1;
- }
- if (verify_mount(homedir_s, pwd) < 0) return -1;
- if (verify_mount(pwd->pw_dir, pwd) < 0) return -1;
+ homedir_s = optarg;
break;
case 'v':
2011-03-30 18:42:36 +00:00
- verbose = 1;
+ verbose++;
+ break;
+ case 'c':
+ usecgroups = 1;
break;
case 'C':
cap_set = CAPNG_SELECT_CAPS;
break;
case 'Z':
- scontext = strdup(optarg);
2011-03-30 18:42:36 +00:00
+ execcon = optarg;
break;
default:
fprintf(stderr, "%s\n", USAGE_STRING);
@@ -342,97 +908,144 @@ int main(int argc, char **argv) {
}
2011-03-30 18:42:36 +00:00
if (! homedir_s && ! tmpdir_s) {
- fprintf(stderr, _("Error: tmpdir and/or homedir required \n"),
- "%s\n", USAGE_STRING);
2011-03-30 18:42:36 +00:00
+ fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
return -1;
}
if (argc - optind < 1) {
- fprintf(stderr, _("Error: executable required \n %s \n"), USAGE_STRING);
2011-03-30 18:42:36 +00:00
+ fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
return -1;
}
2011-03-30 18:42:36 +00:00
- if (set_signal_handles())
+ if (execcon && is_selinux_enabled() != 1) {
+ fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
return -1;
+ }
- if (unshare(CLONE_NEWNS) < 0) {
- perror(_("Failed to unshare"));
+ if (set_signal_handles())
return -1;
- }
- if (homedir_s && tmpdir_s && (strncmp(pwd->pw_dir, tmpdir_s, strlen(pwd->pw_dir)) == 0)) {
- if (seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
- return -1;
- if (seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
- return -1;
- } else {
- if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
- return -1;
-
- if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
- return -1;
- }
+ if (usecgroups && setup_cgroups() < 0)
+ return -1;
2011-03-30 18:42:36 +00:00
+
+ /* set fsuid to ruid */
+ /* Changing fsuid is usually required when user-specified directory is
+ * on an NFS mount. It's also desired to avoid leaking info about
+ * existence of the files not accessible to the user. */
+ setfsuid(uid);
+
2011-03-30 18:42:36 +00:00
+ /* verify homedir and tmpdir */
+ if (homedir_s && (
+ verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
+ check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
+ if (tmpdir_s && (
+ verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
+ check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
+ setfsuid(0);
- if (drop_privs(uid))
2011-03-30 18:42:36 +00:00
+ /* create runtime tmpdir */
+ if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
+ &st_tmpdir_r, pwd, execcon)) == NULL) {
+ fprintf(stderr, _("Failed to create runtime temporary directory\n"));
return -1;
+ }
- int child = fork();
2011-03-30 18:42:36 +00:00
+ /* spawn child process */
+ child = fork();
if (child == -1) {
perror(_("Unable to fork"));
2011-03-30 18:42:36 +00:00
- return -1;
+ goto err;
}
- if (!child) {
- char *display=NULL;
- /* Construct a new environment */
- char *d = getenv("DISPLAY");
- if (d) {
- display = strdup(d);
- if (!display) {
- perror(_("Out of memory"));
- exit(-1);
- }
- }
2011-03-30 18:42:36 +00:00
+ if (child == 0) {
+ char *display = NULL;
+ char *LANG = NULL;
2011-03-30 18:42:36 +00:00
+ int rc = -1;
- if ((rc = clearenv())) {
- perror(_("Unable to clear environment"));
- free(display);
- exit(-1);
+ if (unshare(CLONE_NEWNS) < 0) {
+ perror(_("Failed to unshare"));
+ goto childerr;
}
- if (scontext) {
- if (setexeccon(scontext)) {
- fprintf(stderr, _("Could not set exec context to %s.\n"),
- scontext);
- free(display);
- exit(-1);
2011-03-30 18:42:36 +00:00
+ /* assume fsuid==ruid after this point */
+ setfsuid(uid);
+
+ /* mount homedir and tmpdir, in this order */
+ if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir,
+ &st_homedir) != 0) goto childerr;
+ if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp",
+ &st_tmpdir_r) != 0) goto childerr;
+
+ if (drop_privs(uid) != 0) goto childerr;
+
+ /* construct a new environment */
+ if ((display = getenv("DISPLAY")) != NULL) {
+ if ((display = strdup(display)) == NULL) {
+ perror(_("Out of memory"));
+ goto childerr;
}
2011-03-30 18:42:36 +00:00
}
-
- if (display)
+
+ /* construct a new environment */
+ if ((LANG = getenv("LANG")) != NULL) {
+ if ((LANG = strdup(LANG)) == NULL) {
+ perror(_("Out of memory"));
+ goto childerr;
+ }
+ }
+
2011-03-30 18:42:36 +00:00
+ if ((rc = clearenv()) != 0) {
+ perror(_("Failed to clear environment"));
+ goto childerr;
+ }
+ if (display)
2011-03-30 18:42:36 +00:00
rc |= setenv("DISPLAY", display, 1);
+ if (LANG)
+ rc |= setenv("LANG", LANG, 1);
2011-03-30 18:42:36 +00:00
rc |= setenv("HOME", pwd->pw_dir, 1);
rc |= setenv("SHELL", pwd->pw_shell, 1);
2011-03-30 18:42:36 +00:00
rc |= setenv("USER", pwd->pw_name, 1);
rc |= setenv("LOGNAME", pwd->pw_name, 1);
rc |= setenv("PATH", DEFAULT_PATH, 1);
-
2011-03-30 18:42:36 +00:00
+ if (rc != 0) {
+ fprintf(stderr, _("Failed to construct environment\n"));
+ goto childerr;
+ }
+
2011-03-30 18:42:36 +00:00
+ /* selinux context */
+ if (execcon && setexeccon(execcon) != 0) {
+ fprintf(stderr, _("Could not set exec context to %s.\n"), execcon);
+ goto childerr;
+ }
+
if (chdir(pwd->pw_dir)) {
perror(_("Failed to change dir to homedir"));
2011-03-30 18:42:36 +00:00
- exit(-1);
+ goto childerr;
}
2011-03-30 18:42:36 +00:00
setsid();
execv(argv[optind], argv + optind);
2011-03-30 18:42:36 +00:00
+ fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
+childerr:
free(display);
2011-03-30 18:42:36 +00:00
- perror("execv");
+ free(LANG);
exit(-1);
2011-03-30 18:42:36 +00:00
- } else {
- waitpid(child, &status, 0);
}
2011-03-30 18:42:36 +00:00
- free(tmpdir_s);
- free(homedir_s);
- free(scontext);
2011-03-30 18:42:36 +00:00
+ drop_caps();
+
2011-03-30 18:42:36 +00:00
+ /* parent waits for child exit to do the cleanup */
+ waitpid(child, &status, 0);
+ status_to_retval(status, status);
+
+ /* Make sure all child processes exit */
+ kill(-child,SIGTERM);
+
+ if (execcon && kill_all)
+ killall(execcon);
2011-03-30 18:42:36 +00:00
+
+ if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
2011-03-30 18:42:36 +00:00
+err:
+ free(tmpdir_r);
return status;
}
diff --git a/policycoreutils/scripts/fixfiles b/policycoreutils/scripts/fixfiles
index e4e5f0d..27dcccf 100755
--- a/policycoreutils/scripts/fixfiles
+++ b/policycoreutils/scripts/fixfiles
@@ -103,7 +103,7 @@ exclude_dirs_from_relabelling() {
exclude_dirs() {
exclude=
- for i in /home /root /tmp /dev; do
+ for i in /var/lib/BackupPC /home /tmp /dev; do
[ -e $i ] && exclude="$exclude -e $i";
done
exclude="$exclude `exclude_dirs_from_relabelling`"
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/semanage/default_encoding/Makefile b/policycoreutils/semanage/default_encoding/Makefile
new file mode 100644
index 0000000..e15a877
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/Makefile
@@ -0,0 +1,8 @@
+all:
2011-01-21 20:11:31 +00:00
+ LDFLAGS="" python setup.py build
+
+install: all
+ LDFLAGS="" python setup.py install --root=$(DESTDIR)/
+
+clean:
+ rm -rf build *~
diff --git a/policycoreutils/semanage/default_encoding/default_encoding.c b/policycoreutils/semanage/default_encoding/default_encoding.c
new file mode 100644
index 0000000..2ba4870
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/default_encoding.c
@@ -0,0 +1,59 @@
+/*
+ * Authors:
+ * John Dennis <jdennis@redhat.com>
+ *
+ * Copyright (C) 2009 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <Python.h>
+
+PyDoc_STRVAR(setdefaultencoding_doc,
+"setdefaultencoding(encoding='utf-8')\n\
+\n\
+Set the current default string encoding used by the Unicode implementation.\n\
+Defaults to utf-8."
+);
+
+static PyObject *
+setdefaultencoding(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"utf-8", NULL};
+ char *encoding;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:setdefaultencoding", kwlist, &encoding))
+ return NULL;
+
+ if (PyUnicode_SetDefaultEncoding(encoding))
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef methods[] = {
+ {"setdefaultencoding", (PyCFunction)setdefaultencoding, METH_VARARGS|METH_KEYWORDS, setdefaultencoding_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+
+PyMODINIT_FUNC
+initdefault_encoding_utf8(void)
2011-01-21 20:11:31 +00:00
+{
+ PyObject* m;
+
+ PyUnicode_SetDefaultEncoding("utf-8");
+ m = Py_InitModule3("default_encoding_utf8", methods, "Forces the default encoding to utf-8");
+}
diff --git a/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py b/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py
new file mode 100644
index 0000000..ccb6b8b
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/policycoreutils/__init__.py
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2006,2007,2008, 2009 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
diff --git a/policycoreutils/semanage/default_encoding/setup.py b/policycoreutils/semanage/default_encoding/setup.py
new file mode 100644
index 0000000..e2befdb
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/setup.py
@@ -0,0 +1,38 @@
+# Authors:
+# John Dennis <jdennis@redhat.com>
+#
+# Copyright (C) 2009 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from distutils.core import setup, Extension
+
+default_encoding_utf8 = Extension('policycoreutils.default_encoding_utf8', ['default_encoding.c'])
+
+setup(name = 'policycoreutils-default-encoding',
+ version = '0.1',
+ description = 'Forces the default encoding in Python to be utf-8',
+ long_description = 'Forces the default encoding in Python to be utf-8',
+ author = 'John Dennis',
+ author_email = 'jdennis@redhat.com',
+ maintainer = 'John Dennis',
+ maintainer_email = 'jdennis@redhat.com',
+ license = 'GPLv3+',
+ platforms = 'posix',
+ url = '',
+ download_url = '',
+ ext_modules = [default_encoding_utf8],
+ packages=["policycoreutils"],
+)
diff --git a/policycoreutils/semanage/semanage b/policycoreutils/semanage/semanage
index 0140cd2..2c0cfdd 100644
--- a/policycoreutils/semanage/semanage
+++ b/policycoreutils/semanage/semanage
@@ -20,6 +20,7 @@
# 02111-1307 USA
#
#
+import policycoreutils.default_encoding_utf8
import sys, getopt, re
import seobject
import selinux
@@ -32,7 +33,7 @@ gettext.textdomain(PROGNAME)
try:
gettext.install(PROGNAME,
localedir="/usr/share/locale",
- unicode=False,
+ unicode=True,
codeset = 'utf-8')
except IOError:
import __builtin__
@@ -283,11 +284,14 @@ Object-specific Options (see above):
equal = a
if o == "--enable":
- set_action(o)
+ if disable:
+ raise ValueError(_("You can't disable and enable at the same time"))
+
enable = True
if o == "--disable":
- set_action(o)
+ if enable:
+ raise ValueError(_("You can't disable and enable at the same time"))
disable = True
if o == "-F" or o == "--file":
@@ -338,9 +342,11 @@ Object-specific Options (see above):
if o == "--on" or o == "-1":
value = "on"
+ modify = True
if o == "--off" or o == "-0":
value = "off"
+ modify = True
if object == "login":
OBJECT = seobject.loginRecords(store)
@@ -362,6 +368,8 @@ Object-specific Options (see above):
if object == "boolean":
OBJECT = seobject.booleanRecords(store)
+ if use_file:
+ modify = True
if object == "module":
OBJECT = seobject.moduleRecords(store)
@@ -500,31 +508,36 @@ Object-specific Options (see above):
if len(sys.argv) < 3:
usage(_("Requires 2 or more arguments"))
- gopts, cmds = getopt.getopt(sys.argv[1:],
- '01adf:i:lhmno:p:s:FCDR:L:r:t:T:P:S:',
- ['add',
- 'delete',
- 'deleteall',
- 'ftype=',
- 'file',
- 'help',
- 'input=',
- 'list',
- 'modify',
- 'noheading',
- 'localist',
- 'off',
- 'on',
- 'output=',
- 'proto=',
- 'seuser=',
- 'store=',
- 'range=',
- 'level=',
- 'roles=',
- 'type=',
- 'prefix='
- ])
+ try:
+ gopts, cmds = getopt.getopt(sys.argv[1:],
+ '01adf:i:lhmno:p:s:FCDR:L:r:t:T:P:S:',
+ ['add',
+ 'delete',
+ 'deleteall',
+ 'ftype=',
+ 'file',
+ 'help',
+ 'input=',
+ 'list',
+ 'modify',
+ 'noheading',
+ 'localist',
+ 'off',
+ 'on',
+ 'output=',
+ 'proto=',
+ 'seuser=',
+ 'store=',
+ 'range=',
+ 'level=',
+ 'roles=',
+ 'type=',
+ 'trans=',
+ 'prefix='
+ ])
+ except getopt.error, error:
+ usage(_("Options Error %s ") % error.msg)
+
for o, a in gopts:
if o == "-S" or o == '--store':
store = a
@@ -554,8 +567,6 @@ Object-specific Options (see above):
else:
process_args(sys.argv[1:])
- except getopt.error, error:
- usage(_("Options Error %s ") % error.msg)
except ValueError, error:
errorExit(error.args[0])
except KeyError, error:
@@ -564,3 +575,5 @@ Object-specific Options (see above):
errorExit(error.args[1])
except OSError, error:
errorExit(error.args[1])
+ except RuntimeError, error:
+ errorExit(error.args[0])
diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py
index 6842b07..7f11c4e 100644
--- a/policycoreutils/semanage/seobject.py
+++ b/policycoreutils/semanage/seobject.py
@@ -1,5 +1,5 @@
#! /usr/bin/python -E
-# Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat
+# Copyright (C) 2005-2011 2009 Red Hat
# see file 'COPYING' for use and warranty information
#
# semanage is a tool for managing SELinux configuration files
@@ -30,11 +30,10 @@ from IPy import IP
import gettext
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
gettext.textdomain(PROGNAME)
-try:
- gettext.install(PROGNAME, localedir = "/usr/share/locale", unicode = 1)
-except IOError:
- import __builtin__
- __builtin__.__dict__['_'] = unicode
+
+import gettext
+translation=gettext.translation(PROGNAME, localedir = "/usr/share/locale", fallback=True)
+_=translation.ugettext
import syslog
@@ -161,10 +160,12 @@ def untranslate(trans, prepend = 1):
return trans
else:
return raw
-
+
class semanageRecords:
transaction = False
handle = None
+ store = None
+
def __init__(self, store):
global handle
@@ -182,7 +183,7 @@ class semanageRecords:
if not semanageRecords.transaction and store != "":
semanage_select_store(handle, store, SEMANAGE_CON_DIRECT);
- semanageRecords.store = store
+ semanageRecords.store = store
if not semanage_is_managed(handle):
semanage_handle_destroy(handle)
@@ -253,9 +254,13 @@ class moduleRecords(semanageRecords):
return l
def list(self, heading = 1, locallist = 0):
+ all = self.get_all()
+ if len(all) == 0:
+ return
+
if heading:
print "\n%-25s%-10s\n" % (_("Modules Name"), _("Version"))
- for t in self.get_all():
+ for t in all:
if t[2] == 0:
disabled = _("Disabled")
else:
@@ -328,11 +333,14 @@ class permissiveRecords(semanageRecords):
name = semanage_module_get_name(mod)
if name and name.startswith("permissive_"):
l.append(name.split("permissive_")[1])
+
return l
def list(self, heading = 1, locallist = 0):
import setools
all = map(lambda y: y["name"], filter(lambda x: x["permissive"], setools.seinfo(setools.TYPE)))
+ if len(all) == 0:
+ return
if heading:
print "\n%-25s\n" % (_("Builtin Permissive Types"))
@@ -340,6 +348,10 @@ class permissiveRecords(semanageRecords):
for t in all:
if t not in customized:
print t
+
+ if len(customized) == 0:
+ return
+
if heading:
print "\n%-25s\n" % (_("Customized Permissive Types"))
for t in customized:
@@ -420,7 +432,9 @@ class loginRecords(semanageRecords):
if rc < 0:
raise ValueError(_("Could not check if login mapping for %s is defined") % name)
if exists:
- raise ValueError(_("Login mapping for %s is already defined") % name)
+ semanage_seuser_key_free(k)
+ return self.__modify(name, sename, serange)
+
if name[0] == '%':
try:
grp.getgrnam(name[1:])
@@ -588,7 +602,10 @@ class loginRecords(semanageRecords):
def list(self,heading = 1, locallist = 0):
ddict = self.get_all(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
if is_mls_enabled == 1:
if heading:
print "\n%-25s %-25s %-25s\n" % (_("Login Name"), _("SELinux User"), _("MLS/MCS Range"))
@@ -627,7 +644,8 @@ class seluserRecords(semanageRecords):
if rc < 0:
raise ValueError(_("Could not check if SELinux user %s is defined") % name)
if exists:
- raise ValueError(_("SELinux user %s is already defined") % name)
+ semanage_user_key_free(k)
+ return self.__modify(name, roles, selevel, serange, prefix)
(rc, u) = semanage_user_create(self.sh)
if rc < 0:
@@ -820,7 +838,10 @@ class seluserRecords(semanageRecords):
def list(self, heading = 1, locallist = 0):
ddict = self.get_all(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
if is_mls_enabled == 1:
if heading:
print "\n%-15s %-10s %-10s %-30s" % ("", _("Labeling"), _("MLS/"), _("MLS/"))
@@ -864,6 +885,7 @@ class portRecords(semanageRecords):
return ( k, proto_d, low, high )
def __add(self, port, proto, serange, type):
+
if is_mls_enabled == 1:
if serange == "":
serange = "s0"
@@ -926,6 +948,7 @@ class portRecords(semanageRecords):
self.commit()
def __modify(self, port, proto, serange, setype):
+
if serange == "" and setype == "":
if is_mls_enabled == 1:
raise ValueError(_("Requires setype or serange"))
@@ -1073,11 +1096,14 @@ class portRecords(semanageRecords):
return l
def list(self, heading = 1, locallist = 0):
- if heading:
- print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number"))
ddict = self.get_all_by_type(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
+ if heading:
+ print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number"))
for i in keys:
rec = "%-30s %-8s " % i
rec += "%s" % ddict[i][0]
@@ -1136,7 +1162,8 @@ class nodeRecords(semanageRecords):
(rc, exists) = semanage_node_exists(self.sh, k)
if exists:
- raise ValueError(_("Addr %s already defined") % addr)
+ semanage_node_key_free(k)
+ return self.__modify(addr, mask, self.protocol[proto], serange, ctype)
(rc, node) = semanage_node_create(self.sh)
if rc < 0:
@@ -1152,7 +1179,6 @@ class nodeRecords(semanageRecords):
if rc < 0:
raise ValueError(_("Could not set mask for %s") % addr)
-
rc = semanage_context_set_user(self.sh, con, "system_u")
if rc < 0:
raise ValueError(_("Could not set user in addr context for %s") % addr)
@@ -1204,12 +1230,11 @@ class nodeRecords(semanageRecords):
if not exists:
raise ValueError(_("Addr %s is not defined") % addr)
- (rc, node) = semanage_node_query(self.sh, k)
+ (rc, node) = semanage_node_query_local(self.sh, k)
if rc < 0:
raise ValueError(_("Could not query addr %s") % addr)
con = semanage_node_get_con(node)
-
if serange != "":
semanage_context_set_mls(self.sh, con, untranslate(serange))
if setype != "":
@@ -1296,11 +1321,14 @@ class nodeRecords(semanageRecords):
return l
def list(self, heading = 1, locallist = 0):
- if heading:
- print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context")
ddict = self.get_all(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
+ if heading:
+ print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context")
if is_mls_enabled:
for k in keys:
val = ''
@@ -1334,7 +1362,8 @@ class interfaceRecords(semanageRecords):
if rc < 0:
raise ValueError(_("Could not check if interface %s is defined") % interface)
if exists:
- raise ValueError(_("Interface %s already defined") % interface)
+ semanage_iface_key_free(k)
+ return self.__modify(interface, serange, ctype)
(rc, iface) = semanage_iface_create(self.sh)
if rc < 0:
@@ -1483,11 +1512,14 @@ class interfaceRecords(semanageRecords):
return l
def list(self, heading = 1, locallist = 0):
- if heading:
- print "%-30s %s\n" % (_("SELinux Interface"), _("Context"))
ddict = self.get_all(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
+ if heading:
+ print "%-30s %s\n" % (_("SELinux Interface"), _("Context"))
if is_mls_enabled:
for k in keys:
print "%-30s %s:%s:%s:%s " % (k,ddict[k][0], ddict[k][1],ddict[k][2], translate(ddict[k][3], False))
@@ -1592,7 +1624,8 @@ class fcontextRecords(semanageRecords):
raise ValueError(_("Could not check if file context for %s is defined") % target)
if exists:
- raise ValueError(_("File context for %s already defined") % target)
+ semanage_fcontext_key_free(k)
+ return self.__modify(target, type, ftype, serange, seuser)
(rc, fcontext) = semanage_fcontext_create(self.sh)
if rc < 0:
@@ -1783,11 +1816,14 @@ class fcontextRecords(semanageRecords):
return l
def list(self, heading = 1, locallist = 0 ):
- if heading:
- print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context"))
fcon_dict = self.get_all(locallist)
keys = fcon_dict.keys()
+ if len(keys) == 0:
+ return
keys.sort()
+
+ if heading:
+ print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context"))
for k in keys:
if fcon_dict[k]:
if is_mls_enabled:
@@ -1814,6 +1850,18 @@ class booleanRecords(semanageRecords):
self.dict["1"] = 1
self.dict["0"] = 0
+ try:
+ rc, self.current_booleans = selinux.security_get_boolean_names()
+ rc, ptype = selinux.selinux_getpolicytype()
+ except:
+ self.current_booleans = []
+ ptype = None
+
+ if self.store == None or self.store == ptype:
+ self.modify_local = True
+ else:
+ self.modify_local = False
+
def __mod(self, name, value):
(rc, k) = semanage_bool_key_create(self.sh, name)
if rc < 0:
@@ -1833,9 +1881,10 @@ class booleanRecords(semanageRecords):
else:
raise ValueError(_("You must specify one of the following values: %s") % ", ".join(self.dict.keys()) )
- rc = semanage_bool_set_active(self.sh, k, b)
- if rc < 0:
- raise ValueError(_("Could not set active value of boolean %s") % name)
+ if self.modify_local and name in self.current_booleans:
+ rc = semanage_bool_set_active(self.sh, k, b)
+ if rc < 0:
+ raise ValueError(_("Could not set active value of boolean %s") % name)
rc = semanage_bool_modify_local(self.sh, k, b)
if rc < 0:
raise ValueError(_("Could not modify boolean %s") % name)
@@ -1918,8 +1967,12 @@ class booleanRecords(semanageRecords):
value = []
name = semanage_bool_get_name(boolean)
value.append(semanage_bool_get_value(boolean))
- value.append(selinux.security_get_boolean_pending(name))
- value.append(selinux.security_get_boolean_active(name))
+ if self.modify_local and boolean in self.current_booleans:
+ value.append(selinux.security_get_boolean_pending(name))
+ value.append(selinux.security_get_boolean_active(name))
+ else:
+ value.append(value[0])
+ value.append(value[0])
ddict[name] = value
return ddict
@@ -1952,11 +2005,13 @@ class booleanRecords(semanageRecords):
if ddict[k]:
print "%s=%s" % (k, ddict[k][2])
return
- if heading:
- print "%-40s %s\n" % (_("SELinux boolean"), _("Description"))
ddict = self.get_all(locallist)
keys = ddict.keys()
+ if len(keys) == 0:
+ return
+
+ if heading:
+ print "%-30s %s %s %s\n" % (_("SELinux boolean"),_("State"), _("Default"), _("Description"))
for k in keys:
if ddict[k]:
- print "%-30s -> %-5s %s" % (k, on_off[ddict[k][2]], self.get_desc(k))
-
+ print "%-30s (%-5s,%5s) %s" % (k, on_off[selinux.security_get_boolean_active(k)], on_off[ddict[k][2]], self.get_desc(k))
diff --git a/policycoreutils/sepolgen-ifgen/.gitignore b/policycoreutils/sepolgen-ifgen/.gitignore
new file mode 100644
index 0000000..3816d2e
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/.gitignore
@@ -0,0 +1 @@
+sepolgen-ifgen-attr-helper
2011-01-21 20:11:31 +00:00
diff --git a/policycoreutils/sepolgen-ifgen/Makefile b/policycoreutils/sepolgen-ifgen/Makefile
new file mode 100644
index 0000000..99f8fd0
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/Makefile
@@ -0,0 +1,25 @@
+# Installation directories.
+PREFIX ?= ${DESTDIR}/usr
+BINDIR ?= $(PREFIX)/bin
+LIBDIR ?= ${PREFIX}/lib
+INCLUDEDIR ?= $(PREFIX)/include
+
+CFLAGS ?= -Werror -Wall -W
2011-01-21 20:11:31 +00:00
+override CFLAGS += -I$(INCLUDEDIR)
+LDLIBS = $(LIBDIR)/libsepol.a
+
+all: sepolgen-ifgen-attr-helper
+
+sepolgen-ifgen-attr-helper: sepolgen-ifgen-attr-helper.o
+
+install: all
+ -mkdir -p $(BINDIR)
+ install -m 755 sepolgen-ifgen-attr-helper $(BINDIR)
+
+clean:
+ rm -f *~ *.o sepolgen-ifgen-attr-helper
+
+indent:
+ ../../scripts/Lindent $(wildcard *.[ch])
+
+relabel: ;
diff --git a/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c
new file mode 100644
index 0000000..1ce37b0
2011-01-21 20:11:31 +00:00
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c
@@ -0,0 +1,232 @@
2011-01-21 20:11:31 +00:00
+/* Authors: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003,2010 Tresys Technology, LLC
+ *
2011-01-21 20:11:31 +00:00
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ * Adapted from dispol.c.
+ *
+ * This program is used by sepolgen-ifgen to get the access for all of
+ * the attributes in the policy so that it can resolve the
+ * typeattribute statements in the interfaces.
+ *
+ * It outputs the attribute access in a similar format to what sepolgen
+ * uses to store interface vectors:
+ * [Attribute sandbox_x_domain]
+ * sandbox_x_domain,samba_var_t,file,ioctl,read,getattr,lock,open
+ * sandbox_x_domain,samba_var_t,dir,getattr,search,open
+ * sandbox_x_domain,initrc_var_run_t,file,ioctl,read,getattr,lock,open
+ *
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/util.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct val_to_name {
+ unsigned int val;
+ char *name;
+};
+
+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ struct val_to_name *v = data;
+ perm_datum_t *perdatum;
+
+ perdatum = (perm_datum_t *) datum;
+
+ if (v->val == perdatum->s.value) {
+ v->name = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp,
+ FILE *fp)
+{
+ struct val_to_name v;
+ class_datum_t *cladatum;
+ char *perm = NULL;
+ unsigned int i;
+ int rc;
+ uint32_t tclass = key->target_class;
+
+ cladatum = policydbp->class_val_to_struct[tclass - 1];
+ for (i = 0; i < cladatum->permissions.nprim; i++) {
+ if (av & (1 << i)) {
+ v.val = i + 1;
+ rc = hashtab_map(cladatum->permissions.table,
+ perm_name, &v);
+ if (!rc && cladatum->comdatum) {
+ rc = hashtab_map(cladatum->comdatum->
+ permissions.table, perm_name,
+ &v);
+ }
+ if (rc)
+ perm = v.name;
+ if (perm) {
+ fprintf(fp, ",%s", perm);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int render_key(avtab_key_t *key, policydb_t *p, FILE *fp)
+{
+ char *stype, *ttype, *tclass;
+ stype = p->p_type_val_to_name[key->source_type - 1];
+ ttype = p->p_type_val_to_name[key->target_type - 1];
+ tclass = p->p_class_val_to_name[key->target_class - 1];
+ if (stype && ttype) {
+ fprintf(fp, "%s,%s,%s", stype, ttype, tclass);
+ } else {
+ fprintf(stderr, "error rendering key\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+struct callback_data
+{
+ uint32_t attr;
+ policydb_t *policy;
+ FILE *fp;
+};
+
+int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args)
+{
+ struct callback_data *cb_data = (struct callback_data *)args;
+
+ if (key->source_type != cb_data->attr)
+ return 0;
+
+ if (!(key->specified & AVTAB_AV && key->specified & AVTAB_ALLOWED))
+ return 0;
+
+ render_key(key, cb_data->policy, cb_data->fp);
+ render_access_mask(datum->data, key, cb_data->policy, cb_data->fp);
+ fprintf(cb_data->fp, "\n");
+
+ return 0;
+}
+
+static int attribute_callback(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ struct callback_data *cb_data = (struct callback_data *)datap;
+ type_datum_t *t = (type_datum_t *)datum;
+
+ if (t->flavor == TYPE_ATTRIB) {
+ fprintf(cb_data->fp, "[Attribute %s]\n", key);
+ cb_data->attr = t->s.value;
+ if (avtab_map(&cb_data->policy->te_avtab, output_avrule, cb_data) < 0)
+ return -1;
+ if (avtab_map(&cb_data->policy->te_cond_avtab, output_avrule, cb_data) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static policydb_t *load_policy(const char *filename)
+{
+ policydb_t *policydb;
+ struct policy_file pf;
+ FILE *fp;
+ int ret;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "Can't open '%s': %s\n",
+ filename, strerror(errno));
+ return NULL;
+ }
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_STDIO;
+ pf.fp = fp;
+
+ policydb = malloc(sizeof(policydb_t));
+ if (policydb == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+
+ if (policydb_init(policydb)) {
+ fprintf(stderr, "Out of memory!\n");
2011-03-30 18:42:36 +00:00
+ free(policydb);
2011-01-21 20:11:31 +00:00
+ return NULL;
+ }
+
+ ret = policydb_read(policydb, &pf, 1);
+ if (ret) {
+ fprintf(stderr,
+ "error(s) encountered while parsing configuration\n");
2011-03-30 18:42:36 +00:00
+ free(policydb);
2011-01-21 20:11:31 +00:00
+ return NULL;
+ }
+
+ fclose(fp);
+
2011-01-21 20:11:31 +00:00
+ return policydb;
+
+}
+
+void usage(char *progname)
+{
+ printf("usage: %s policy_file out_file\n", progname);
+}
+
+int main(int argc, char **argv)
+{
+ policydb_t *p;
+ struct callback_data cb_data;
+ FILE *fp;
+
+ if (argc != 3) {
+ usage(argv[0]);
2011-03-30 18:42:36 +00:00
+ return -1;
2011-01-21 20:11:31 +00:00
+ }
+
+ /* Open the policy. */
+ p = load_policy(argv[1]);
+ if (p == NULL)
2011-03-30 18:42:36 +00:00
+ return -1;
2011-01-21 20:11:31 +00:00
+
+ /* Open the output policy. */
+ fp = fopen(argv[2], "w");
+ if (fp == NULL) {
+ fprintf(stderr, "error opening output file\n");
+ policydb_destroy(p);
+ free(p);
2011-03-30 18:42:36 +00:00
+ return -1;
2011-01-21 20:11:31 +00:00
+ }
+
+ /* Find all of the attributes and output their access. */
+ cb_data.policy = p;
+ cb_data.fp = fp;
+
+ if (hashtab_map(p->p_types.table, attribute_callback, &cb_data)) {
+ printf("error finding attributes\n");
+ }
+
+ policydb_destroy(p);
+ free(p);
+ fclose(fp);
+
+ return 0;
+}
diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c
index 48ffcad..7cff7e4 100644
--- a/policycoreutils/setfiles/restore.c
+++ b/policycoreutils/setfiles/restore.c
@@ -1,5 +1,6 @@
#include "restore.h"
#include <glob.h>
+#include <selinux/context.h>
#define SKIP -2
#define ERR -1
@@ -33,7 +34,6 @@ struct edir {
static file_spec_t *fl_head;
static int filespec_add(ino_t ino, const security_context_t con, const char *file);
-static int only_changed_user(const char *a, const char *b);
struct restore_opts *r_opts = NULL;
static void filespec_destroy(void);
static void filespec_eval(void);
@@ -60,9 +60,10 @@ void restore_init(struct restore_opts *opts)
r_opts = opts;
struct selinux_opt selinux_opts[] = {
{ SELABEL_OPT_VALIDATE, r_opts->selabel_opt_validate },
- { SELABEL_OPT_PATH, r_opts->selabel_opt_path }
+ { SELABEL_OPT_PATH, r_opts->selabel_opt_path },
+ { SELABEL_OPT_SUBSET, r_opts->selabel_opt_subset }
};
- r_opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2);
+ r_opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 3);
if (!r_opts->hnd) {
perror(r_opts->selabel_opt_path);
exit(1);
@@ -104,8 +105,7 @@ static int restore(FTSENT *ftsent)
{
char *my_file = strdupa(ftsent->fts_path);
int ret;
- char *context, *newcon;
- int user_only_changed = 0;
+ security_context_t curcon = NULL, newcon = NULL;
if (match(my_file, ftsent->fts_statp, &newcon) < 0)
/* Check for no matching specification. */
@@ -143,74 +143,105 @@ static int restore(FTSENT *ftsent)
printf("%s: %s matched by %s\n", r_opts->progname, my_file, newcon);
}
+ /*
+ * Do not relabel if their is no default specification for this file
+ */
+
+ if (strcmp(newcon, "<<none>>") == 0) {
+ goto out;
+ }
+
/* Get the current context of the file. */
- ret = lgetfilecon_raw(ftsent->fts_accpath, &context);
+ ret = lgetfilecon_raw(ftsent->fts_accpath, &curcon);
if (ret < 0) {
if (errno == ENODATA) {
- context = NULL;
+ curcon = NULL;
} else {
fprintf(stderr, "%s get context on %s failed: '%s'\n",
r_opts->progname, my_file, strerror(errno));
goto err;
}
- user_only_changed = 0;
- } else
- user_only_changed = only_changed_user(context, newcon);
+ }
+
/* lgetfilecon returns number of characters and ret needs to be reset
* to 0.
*/
ret = 0;
/*
- * Do not relabel the file if the matching specification is
- * <<none>> or the file is already labeled according to the
- * specification.
+ * Do not relabel the file if the file is already labeled according to
+ * the specification.
*/
- if ((strcmp(newcon, "<<none>>") == 0) ||
- (context && (strcmp(context, newcon) == 0))) {
- freecon(context);
+ if (curcon && (strcmp(curcon, newcon) == 0)) {
goto out;
}
- if (!r_opts->force && context && (is_context_customizable(context) > 0)) {
+ if (!r_opts->force && curcon && (is_context_customizable(curcon) > 0)) {
if (r_opts->verbose > 1) {
fprintf(stderr,
"%s: %s not reset customized by admin to %s\n",
- r_opts->progname, my_file, context);
+ r_opts->progname, my_file, curcon);
}
- freecon(context);
goto out;
}
- if (r_opts->verbose) {
- /* If we're just doing "-v", trim out any relabels where
- * the user has r_opts->changed but the role and type are the
- * same. For "-vv", emit everything. */
- if (r_opts->verbose > 1 || !user_only_changed) {
- printf("%s reset %s context %s->%s\n",
- r_opts->progname, my_file, context ?: "", newcon);
+ /*
+ * Do not change label unless this is a force or the type is different
+ */
+ if (!r_opts->force && curcon) {
+ int types_differ = 0;
+ context_t cona;
+ context_t conb;
+ int err = 0;
+ cona = context_new(curcon);
+ if (! cona) {
+ goto out;
+ }
+ conb = context_new(newcon);
+ if (! conb) {
+ context_free(cona);
+ goto out;
+ }
+
+ types_differ = strcmp(context_type_get(cona), context_type_get(conb));
+ if (types_differ) {
+ err |= context_user_set(conb, context_user_get(cona));
+ err |= context_role_set(conb, context_role_get(cona));
+ err |= context_range_set(conb, context_range_get(cona));
+ if (!err) {
+ freecon(newcon);
+ newcon = strdup(context_str(conb));
+ }
+ }
+ context_free(cona);
+ context_free(conb);
+
+ if (!types_differ || err) {
+ goto out;
}
}
- if (r_opts->logging && !user_only_changed) {
- if (context)
+ if (r_opts->verbose) {
+ printf("%s reset %s context %s->%s\n",
+ r_opts->progname, my_file, curcon ?: "", newcon);
+ }
+
+ if (r_opts->logging) {
+ if (curcon)
syslog(LOG_INFO, "relabeling %s from %s to %s\n",
- my_file, context, newcon);
+ my_file, curcon, newcon);
else
syslog(LOG_INFO, "labeling %s to %s\n",
my_file, newcon);
}
- if (r_opts->outfile && !user_only_changed)
+ if (r_opts->outfile)
fprintf(r_opts->outfile, "%s\n", my_file);
- if (context)
- freecon(context);
-
/*
* Do not relabel the file if -n was used.
*/
- if (!r_opts->change || user_only_changed)
+ if (!r_opts->change)
goto out;
/*
@@ -318,11 +349,16 @@ static int process_one(char *name, int recurse_this_path)
ftsent = fts_read(fts_handle);
- if (ftsent != NULL) {
- /* Keep the inode of the first one. */
- dev_num = ftsent->fts_statp->st_dev;
+ if (ftsent == NULL) {
+ fprintf(stderr,
+ "%s: error while labeling %s: %s\n",
+ r_opts->progname, namelist[0], strerror(errno));
+ goto err;
}
+ /* Keep the inode of the first one. */
+ dev_num = ftsent->fts_statp->st_dev;
+
do {
rc = 0;
/* Skip the post order nodes. */
@@ -390,7 +426,7 @@ int process_one_realpath(char *name, int recurse)
{
int rc = 0;
char *p;
- struct stat sb;
+ struct stat64 sb;
if (r_opts == NULL){
fprintf(stderr,
@@ -401,7 +437,7 @@ int process_one_realpath(char *name, int recurse)
if (!r_opts->expand_realpath) {
return process_one(name, recurse);
} else {
- rc = lstat(name, &sb);
+ rc = lstat64(name, &sb);
if (rc < 0) {
if (r_opts->ignore_enoent && errno == ENOENT)
return 0;
@@ -486,22 +522,6 @@ int add_exclude(const char *directory)
return 0;
}
-/* Compare two contexts to see if their differences are "significant",
- * or whether the only difference is in the user. */
-static int only_changed_user(const char *a, const char *b)
-{
- char *rest_a, *rest_b; /* Rest of the context after the user */
- if (r_opts->force)
- return 0;
- if (!a || !b)
- return 0;
- rest_a = strchr(a, ':');
- rest_b = strchr(b, ':');
- if (!rest_a || !rest_b)
- return 0;
- return (strcmp(rest_a, rest_b) == 0);
-}
-
/*
* Evaluate the association hash table distribution.
*/
@@ -568,7 +588,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil
{
file_spec_t *prevfl, *fl;
int h, ret;
- struct stat sb;
+ struct stat64 sb;
if (!fl_head) {
fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
@@ -581,7 +601,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil
for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
prevfl = fl, fl = fl->next) {
if (ino == fl->ino) {
- ret = lstat(fl->file, &sb);
+ ret = lstat64(fl->file, &sb);
if (ret < 0 || sb.st_ino != ino) {
freecon(fl->con);
free(fl->file);
diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h
index ac27222..3909d15 100644
--- a/policycoreutils/setfiles/restore.h
+++ b/policycoreutils/setfiles/restore.h
@@ -40,6 +40,7 @@ struct restore_opts {
int fts_flags; /* Flags to fts, e.g. follow links, follow mounts */
const char *selabel_opt_validate;
const char *selabel_opt_path;
+ char *selabel_opt_subset;
};
void restore_init(struct restore_opts *opts);
diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8
index c8ea4bb..0eb7293 100644
--- a/policycoreutils/setfiles/restorecon.8
+++ b/policycoreutils/setfiles/restorecon.8
@@ -4,22 +4,27 @@ restorecon \- restore file(s) default SELinux security contexts.
.SH "SYNOPSIS"
.B restorecon
-.I [\-o outfilename ] [\-R] [\-n] [\-p] [\-v] [\-e directory ] pathname...
+.I [\-o outfilename ] [\-R] [\-n] [\-p] [\-v] [\-e directory ] [\-L labelprefix ] pathname...
.P
.B restorecon
-.I \-f infilename [\-o outfilename ] [\-e directory ] [\-R] [\-n] [\-p] [\-v] [\-F]
+.I \-f infilename [\-o outfilename ] [\-e directory ] [\-L labelprefix ] [\-R] [\-n] [\-p] [\-v] [\-F]
.SH "DESCRIPTION"
This manual page describes the
.BR restorecon
program.
.P
-This program is primarily used to set the security context
+This program is primarily used to reset the security context (type)
(extended attributes) on one or more files.
.P
It can be run at any time to correct errors, to add support for
new policy, or with the \-n option it can just check whether the file
contexts are all as you expect.
+.P
+If a file object does not have a context, restorecon will write the default
+context to the file object's extended attributes. If a file object has a
+context, restorecon will only modify the type portion of the security context.
+The -F option will force a replacement of the entire context.
.SH "OPTIONS"
.TP
@@ -32,6 +37,12 @@ infilename contains a list of files to be processed by application. Use \- for s
.B \-e directory
directory to exclude (repeat option for more than one directory.)
.TP
+.B \-L labelprefix
+Tells selinux to only use the file context that match this prefix for labeling, -L can be called multiple times. Can speed up labeling if you are only doing one directory.
+
+# restorecon -R -v -L /dev /dev
+
+.TP
.B \-R \-r
change files and directories file labels recursively
.TP
@@ -47,11 +58,8 @@ show progress by printing * every 1000 files.
.B \-v
show changes in file labels.
.TP
-.B \-vv
-show changes in file labels, if type, role, or user are changing.
-.TP
.B \-F
-Force reset of context to match file_context for customizable files, or the user section, if it has changed.
+Force reset of context to match file_context for customizable files, and the default file context, changing the user, role, range portion as well as the type.
.TP
.SH "ARGUMENTS"
.B pathname...
diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8
index 7f700ca..5902e8e 100644
--- a/policycoreutils/setfiles/setfiles.8
+++ b/policycoreutils/setfiles/setfiles.8
@@ -4,7 +4,7 @@ setfiles \- set file SELinux security contexts.
.SH "SYNOPSIS"
.B setfiles
-.I [\-c policy ] [\-d] [\-l] [\-n] [\-e directory ] [\-o filename ] [\-q] [\-s] [\-v] [\-vv] [\-W] [\-F] spec_file pathname...
+.I [\-c policy ] [\-d] [\-l] [\-n] [\-e directory ] [\-o filename ] [\-L labelprefix ] [\-q] [\-s] [\-v] [\-W] [\-F] spec_file pathname...
.SH "DESCRIPTION"
This manual page describes the
.BR setfiles
@@ -17,6 +17,11 @@ program is initially run as part of the SE Linux installation process.
It can also be run at any time to correct errors, to add support for
new policy, or with the \-n option it can just check whether the file
contexts are all as you expect.
+.P
+If a file object does not have a context, setfiles will write the default
+context to the file object's extended attributes. If a file object has a
+context, setfiles will only modify the type portion of the security context.
+The -F option will force a replacement of the entire context.
.SH "OPTIONS"
.TP
@@ -45,7 +50,10 @@ use an alternate root path
directory to exclude (repeat option for more than one directory.)
.TP
.B \-F
-Force reset of context to match file_context for customizable files
+Force reset of context to match file_context for customizable files, and the default file context, changing the user, role, range portion as well as the type.
+.TP
+.B \-L labelprefix
+Tells selinux to only use the file context that match this prefix for labeling, -L can be called multiple times. Can speed up labeling if you are only doing one directory.
.TP
.B \-o filename
save list of files with incorrect context in filename.
@@ -55,10 +63,7 @@ take a list of files from standard input instead of using a pathname on the
command line.
.TP
.B \-v
-show changes in file labels, if type or role are changing.
-.TP
-.B \-vv
-show changes in file labels, if type, role, or user are changing.
+show changes in file labels
.TP
.B \-W
display warnings about entries that had no matching files.
diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
index fa0cd6a..590a4e0 100644
--- a/policycoreutils/setfiles/setfiles.c
+++ b/policycoreutils/setfiles/setfiles.c
@@ -39,7 +39,7 @@ void usage(const char *const name)
{
if (iamrestorecon) {
fprintf(stderr,
- "usage: %s [-iFnprRv0] [-e excludedir ] [-o filename ] [-f filename | pathname... ]\n",
+ "usage: %s [-iFnprRv0] [ -L labelprefix ] [-e excludedir ] [-o filename ] [-f filename | pathname... ]\n",
name);
} else {
fprintf(stderr,
@@ -160,6 +160,7 @@ int main(int argc, char **argv)
r_opts.outfile = NULL;
r_opts.force = 0;
r_opts.hard_links = 1;
+ r_opts.selabel_opt_subset = 0;
altpath = NULL;
@@ -217,7 +218,7 @@ int main(int argc, char **argv)
exclude_non_seclabel_mounts();
/* Process any options. */
- while ((opt = getopt(argc, argv, "c:de:f:ilnpqrsvo:FRW0")) > 0) {
+ while ((opt = getopt(argc, argv, "c:de:f:ilnpqrsvo:FL:RW0")) > 0) {
switch (opt) {
case 'c':
{
@@ -280,6 +281,23 @@ int main(int argc, char **argv)
case 'n':
r_opts.change = 0;
break;
+ case 'L':
+ if (r_opts.selabel_opt_subset) {
+ if (asprintf((char**) &(r_opts.selabel_opt_subset),"%s;%s",r_opts.selabel_opt_subset,optarg) < 0) {
+ fprintf(stderr, "Can't allocate memory for labeling prefix %s:%s\n",
+ optarg, strerror(errno));
+ exit(1);
+ }
+ }
+ else {
+ r_opts.selabel_opt_subset = strdup(optarg);
+ if (! r_opts.selabel_opt_subset) {
+ fprintf(stderr, "Can't allocate memory for labeling prefix %s:%s\n",
+ optarg, strerror(errno));
+ exit(1);
+ }
+ }
+ break;
case 'o':
if (strcmp(optarg, "-") == 0) {
r_opts.outfile = stdout;
@@ -433,7 +451,11 @@ int main(int argc, char **argv)
if (r_opts.outfile)
fclose(r_opts.outfile);
- if (r_opts.progress && r_opts.count >= STAR_COUNT)
- printf("\n");
+ if (r_opts.progress && r_opts.count >= STAR_COUNT)
+ printf("\n");
+
+ free(r_opts.progname);
+ free(r_opts.selabel_opt_subset);
+ free(r_opts.rootpath);
exit(errors);
}