policycoreutils/policycoreutils-rhat.patch
2011-09-02 09:24:40 -04:00

3803 lines
112 KiB
Diff

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
@@ -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")
+ 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
+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:
+ 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()
@@ -68,6 +117,14 @@ def main():
else:
log = None
+ # Get the attibutes from the binary
+ attrs = None
+ if not options.no_attrs:
+ 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:
@@ -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()
diff --git a/policycoreutils/newrole/newrole.c b/policycoreutils/newrole/newrole.c
index 99d0ed7..3f08d37 100644
--- a/policycoreutils/newrole/newrole.c
+++ b/policycoreutils/newrole/newrole.c
@@ -1030,10 +1030,11 @@ int main(int argc, char *argv[])
* if it makes sense to continue to run newrole, and setting up
* a scrubbed environment.
*/
- if (drop_capabilities(FALSE)) {
+/* if (drop_capabilities(FALSE)) {
perror(_("Sorry, newrole failed to drop capabilities\n"));
return -1;
}
+*/
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
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)
+ 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/*
-
-
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
-
diff --git a/policycoreutils/restorecond/restorecond_user.conf b/policycoreutils/restorecond/restorecond_user.conf
new file mode 100644
index 0000000..e0c2871
--- /dev/null
+++ b/policycoreutils/restorecond/restorecond_user.conf
@@ -0,0 +1,7 @@
+~/*
+~/public_html/*
+~/.gnome2/*
+~/local/*
+~/.fonts/*
+~/.cache/*
+~/.config/*
diff --git a/policycoreutils/restorecond/user.c b/policycoreutils/restorecond/user.c
new file mode 100644
index 0000000..ade3fb8
--- /dev/null
+++ b/policycoreutils/restorecond/user.c
@@ -0,0 +1,246 @@
+/*
+ * restorecond
+ *
+ * Copyright (C) 2006-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; 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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ * Authors:
+ * 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
+ (message, INTERFACE, "Stop")) {
+
+ /* 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);
+
+ /* 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;
+ }
+ 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);
+
+ 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;
+
+ /* 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;
+ }
+
+
+ /* 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;
+ }
+ int fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+ if (debug_mode)
+ g_warning ("Lock file: %s", ptr);
+
+ 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);
+
+#ifdef HAVE_DBUS
+ if (dbus_server(loop) != 0)
+#endif /* HAVE_DBUS */
+ if (local_server(loop))
+ goto end;
+
+ read_config(master_fd, watch_file);
+
+ if (watch_list_isempty()) goto end;
+
+ set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
+
+ GIOChannel *c = g_io_channel_unix_new(master_fd);
+
+ g_io_add_watch_full( c,
+ G_PRIORITY_HIGH,
+ G_IO_IN|G_IO_ERR|G_IO_HUP,
+ io_channel_callback, NULL, NULL);
+
+ g_main_loop_run (loop);
+
+end:
+ g_main_loop_unref (loop);
+ return 0;
+}
+
diff --git a/policycoreutils/restorecond/watch.c b/policycoreutils/restorecond/watch.c
new file mode 100644
index 0000000..6a833c3
--- /dev/null
+++ b/policycoreutils/restorecond/watch.c
@@ -0,0 +1,272 @@
+#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;
+
+ if (exclude(path)) goto end;
+
+ globbuf.gl_offs = 1;
+ if (glob(path,
+ 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);
+ goto end;
+ }
+ 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)
+ syslog(LOG_ERR, "Unable to watch (%s) %s\n",
+ path, strerror(errno));
+ goto end;
+ }
+
+ 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);
+
+end:
+ free(x);
+ return;
+}
+
+/*
+ A file was in a direcroty has been created. This function checks to
+ 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.");
+
+ 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
+*/
+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;
+
+ 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.");
+
+ 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
+ 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"
-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
- 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")
+ 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
}
diff --git a/policycoreutils/sandbox/seunshare.8 b/policycoreutils/sandbox/seunshare.8
index a9b846b..06610c0 100644
--- a/policycoreutils/sandbox/seunshare.8
+++ 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.
+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..671d97c 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>
+#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);
+}
+
+/**
* Take care of any signal setup.
*/
static int set_signal_handles(void)
@@ -88,12 +109,17 @@ static int set_signal_handles(void)
(void)sigprocmask(SIG_SETMASK, &empty, NULL);
- /* Terminate on SIGHUP. */
+ /* Terminate on SIGHUP */
if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
perror("Unable to set SIGHUP handler");
return -1;
}
+ 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){
}
/**
- * 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.
- */
-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;
- }
- 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)
/* 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) {
+/**
+ * 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)
- printf("Mount %s on %s\n", src, dst);
- if (mount(dst, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
+ printf(_("Mounting %s on %s\n"), src, dst);
+
+ 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;
}
-
- 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;
}
-
- 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)
+ /* verify whether we mounted what we expected to mount */
+ if (verify_directory(dst, src_st, NULL) < 0) return -1;
+
+ /* bind mount /tmp on /var/tmp too */
+ if (is_tmp) {
+ if (verbose)
+ printf(_("Mounting /tmp on /var/tmp\n"));
+
+ 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;
+ }
+ 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;
+ }
+ }
+
+ return 0;
+
+}
+
+/**
+ * Error logging used by cgroups code.
+ */
+static int sandbox_error(const char *string)
+{
+ fprintf(stderr, string);
+ syslog(LOG_AUTHPRIV | LOG_ALERT, string);
+ exit(-1);
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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;
+ 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.");
+ 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")) {
+ 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.");
+ 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.");
+ 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");
+ goto err;
+ }
+
+ if (mem == NULL) {
+ if (memusage > current_mem) {
+ sandbox_error("Attempting to use more memory than allowed!");
+ 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");
+ goto err;
+ }
+
+ rc = cgroup_create_cgroup(sandbox_group, 1);
+ if (rc != 0) {
+ sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n");
+ goto err;
+ }
+
+ cgroup_attach_task(sandbox_group);
+
+ rc = 0;
+err:
+ fclose(fp);
+ free(str);
+ free(mem);
+ free(cgroupname);
+ free(cpus);
+ return rc;
+}
+
+/*
+ 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)
+{
+ 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) {
+ 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;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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;
+
+ /* 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) {
+ 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;
-
- int flag_index; /* flag index in argv[] */
int clflag; /* holds codes for command line flags */
- char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
+ int usecgroups = 0;
+ int kill_all = 0;
+
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'},
{"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) {
}
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) {
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;
+ tmpdir_s = optarg;
+ break;
+ case 'k':
+ kill_all = 1;
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':
- verbose = 1;
+ verbose++;
+ break;
+ case 'c':
+ usecgroups = 1;
break;
case 'C':
cap_set = CAPNG_SELECT_CAPS;
break;
case 'Z':
- scontext = strdup(optarg);
+ execcon = optarg;
break;
default:
fprintf(stderr, "%s\n", USAGE_STRING);
@@ -342,97 +908,131 @@ int main(int argc, char **argv) {
}
if (! homedir_s && ! tmpdir_s) {
- fprintf(stderr, _("Error: tmpdir and/or homedir required \n"),
- "%s\n", USAGE_STRING);
+ 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);
+ fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
return -1;
}
- 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;
+
+ /* 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);
+
+ /* 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))
+ /* 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();
+ /* spawn child process */
+ child = fork();
if (child == -1) {
perror(_("Unable to fork"));
- 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);
- }
- }
+ if (child == 0) {
+ char *display = NULL;
+ 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);
+ /* 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;
}
}
-
- if (display)
+ if ((rc = clearenv()) != 0) {
+ perror(_("Failed to clear environment"));
+ goto childerr;
+ }
+ if (display)
rc |= setenv("DISPLAY", display, 1);
rc |= setenv("HOME", pwd->pw_dir, 1);
rc |= setenv("SHELL", pwd->pw_shell, 1);
rc |= setenv("USER", pwd->pw_name, 1);
rc |= setenv("LOGNAME", pwd->pw_name, 1);
rc |= setenv("PATH", DEFAULT_PATH, 1);
-
+ if (rc != 0) {
+ fprintf(stderr, _("Failed to construct environment\n"));
+ goto childerr;
+ }
+
+ /* 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"));
- exit(-1);
+ goto childerr;
}
setsid();
execv(argv[optind], argv + optind);
+ fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
+childerr:
free(display);
- perror("execv");
exit(-1);
- } else {
- waitpid(child, &status, 0);
}
- free(tmpdir_s);
- free(homedir_s);
- free(scontext);
+ drop_caps();
+
+ /* 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);
+
+ if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
+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`"
diff --git a/policycoreutils/semanage/default_encoding/Makefile b/policycoreutils/semanage/default_encoding/Makefile
new file mode 100644
index 0000000..e15a877
--- /dev/null
+++ b/policycoreutils/semanage/default_encoding/Makefile
@@ -0,0 +1,8 @@
+all:
+ 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
--- /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)
+{
+ 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
diff --git a/policycoreutils/sepolgen-ifgen/Makefile b/policycoreutils/sepolgen-ifgen/Makefile
new file mode 100644
index 0000000..99f8fd0
--- /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
+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
--- /dev/null
+++ b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c
@@ -0,0 +1,232 @@
+/* Authors: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003,2010 Tresys Technology, LLC
+ *
+ * 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");
+ free(policydb);
+ return NULL;
+ }
+
+ ret = policydb_read(policydb, &pf, 1);
+ if (ret) {
+ fprintf(stderr,
+ "error(s) encountered while parsing configuration\n");
+ free(policydb);
+ return NULL;
+ }
+
+ fclose(fp);
+
+ 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]);
+ return -1;
+ }
+
+ /* Open the policy. */
+ p = load_policy(argv[1]);
+ if (p == NULL)
+ return -1;
+
+ /* Open the output policy. */
+ fp = fopen(argv[2], "w");
+ if (fp == NULL) {
+ fprintf(stderr, "error opening output file\n");
+ policydb_destroy(p);
+ free(p);
+ return -1;
+ }
+
+ /* 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..15f2bf0 100644
--- a/policycoreutils/setfiles/restore.c
+++ b/policycoreutils/setfiles/restore.c
@@ -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);
@@ -318,11 +319,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 +396,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 +407,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;
@@ -568,7 +574,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 +587,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..fb8eaf9 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;
+ const 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..6cb7d3d 100644
--- a/policycoreutils/setfiles/restorecon.8
+++ b/policycoreutils/setfiles/restorecon.8
@@ -4,10 +4,10 @@ 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
@@ -32,6 +32,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
diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8
index 7f700ca..c77431a 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] [\-vv] [\-W] [\-F] spec_file pathname...
.SH "DESCRIPTION"
This manual page describes the
.BR setfiles
@@ -47,6 +47,9 @@ directory to exclude (repeat option for more than one directory.)
.B \-F
Force reset of context to match file_context for customizable files
.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.
.TP
diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
index fa0cd6a..eb8a7aa 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,
@@ -217,7 +217,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 +280,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 +450,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);
}