next portion of selinux updates: chcon, runcon. From
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 11 Mar 2007 22:16:02 +0000 (22:16 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 11 Mar 2007 22:16:02 +0000 (22:16 -0000)
Yuichi Nakamura <himainu-ynakam@miomio.jp>
KaiGai Kohei <busybox@kaigai.gr.jp>

coreutils/id.c
coreutils/install.c
include/libbb.h
libbb/Kbuild
libbb/selinux_common.c [new file with mode: 0644]
selinux/chcon.c [new file with mode: 0644]
selinux/runcon.c [new file with mode: 0644]

index a0364675ff43f1e0ddb27abd7f380fd5d8921521..e183402fa81188c85218d1af00aed1beef9e60e6 100644 (file)
@@ -89,7 +89,7 @@ int id_main(int argc, char **argv)
                if (flags & JUST_CONTEXT) {        
                        selinux_or_die();
                        if (argc - optind == 1) {
-                               bb_error_msg_and_die("can't print security context when user specified");
+                               bb_error_msg_and_die("user name can't be passed with -Z");
                        }
                        
                        if (getcon(&scontext)) {
index 83facad9d304f4761b348a5e2b6d605a7c102b48..1f65407b12b809e80b49d89654a83c5ae1b7f99b 100644 (file)
@@ -1,6 +1,7 @@
 /* vi: set sw=4 ts=4: */
 /*
- *  Copyright (C) 2003 by Glenn McGrath <bug1@iinet.net.au>
+ * Copyright (C) 2003 by Glenn McGrath <bug1@iinet.net.au>
+ * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  *
index e07fa7587537f0fa8a3d9aa4a64618a049e40911..69652b6664c27647e5a3899d935d5033422051a5 100644 (file)
@@ -41,6 +41,7 @@
 
 #if ENABLE_SELINUX
 #include <selinux/selinux.h>
+#include <selinux/context.h>
 #endif
 
 #if ENABLE_LOCALE_SUPPORT
@@ -598,6 +599,8 @@ extern void run_shell(const char *shell, int loginshell, const char *command, co
 #if ENABLE_SELINUX
 extern void renew_current_security_context(void);
 extern void set_current_security_context(security_context_t sid);
+extern context_t set_security_context_component(security_context_t cur_context,
+                                               char *user, char *role, char *type, char *range);
 #endif
 extern void selinux_or_die(void);
 extern int restricted_shell(const char *shell);
index a53b17f44a8f48f3f437ce5cba8064c74f45c792..ffded6a687a777bd64d9a2a61a1a031db3cde836 100644 (file)
@@ -106,6 +106,7 @@ lib-$(CONFIG_SU) += correct_password.o
 lib-$(CONFIG_LOGIN) += correct_password.o
 lib-$(CONFIG_DF) += find_mount_point.o
 lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
+lib-$(CONFIG_SELINUX) += selinux_common.o
 
 # We shouldn't build xregcomp.c if we don't need it - this ensures we don't
 # require regex.h to be in the include dir even if we don't need it thereby
diff --git a/libbb/selinux_common.c b/libbb/selinux_common.c
new file mode 100644 (file)
index 0000000..70d63a4
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * libbb/selinux_common.c
+ *   -- common SELinux utility functions
+ * 
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#include "busybox.h"
+#include <selinux/context.h>
+
+context_t set_security_context_component(security_context_t cur_context,
+                                        char *user, char *role, char *type, char *range)
+{
+       context_t con = context_new(cur_context);
+       if (!con)
+               return NULL;
+
+       if (user && context_user_set(con, user))
+               goto error;
+       if (type && context_type_set(con, type))
+               goto error;
+       if (range && context_range_set(con, range))
+               goto error;
+       if (role && context_role_set(con, role))
+               goto error;
+       return con;
+
+error:
+       context_free(con);
+       return NULL;
+}
diff --git a/selinux/chcon.c b/selinux/chcon.c
new file mode 100644 (file)
index 0000000..d7ff408
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * chcon -- change security context, based on coreutils-5.97-13
+ *
+ * Port to busybox: KaiGai Kohei <kaigai@kaigai.gr.jp>
+ * 
+ * Copyright (C) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#include "busybox.h"
+#include <getopt.h>
+#include <selinux/context.h>
+
+#define OPT_RECURSIVE          (1<<0)  /* 'R' */
+#define OPT_CHANHES            (1<<1)  /* 'c' */
+#define OPT_NODEREFERENCE      (1<<2)  /* 'h' */
+#define OPT_QUIET              (1<<3)  /* 'f' */
+#define OPT_USER               (1<<4)  /* 'u' */
+#define OPT_ROLE               (1<<5)  /* 'r' */
+#define OPT_TYPE               (1<<6)  /* 't' */
+#define OPT_RANGE              (1<<7)  /* 'l' */
+#define OPT_VERBOSE            (1<<8)  /* 'v' */
+#define OPT_REFERENCE          ((1<<9) * ENABLE_FEATURE_CHCON_LONG_OPTIONS)
+#define OPT_COMPONENT_SPECIFIED        (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE)
+
+static char *user = NULL;
+static char *role = NULL;
+static char *type = NULL;
+static char *range = NULL;
+static char *specified_context = NULL;
+
+static int change_filedir_context(const char *fname, struct stat *stbuf, void *userData, int depth)
+{
+       context_t context = NULL;
+       security_context_t file_context = NULL;
+       security_context_t context_string;
+       int rc = FALSE;
+       int status = 0;
+
+       if (option_mask32 & OPT_NODEREFERENCE) {
+               status = lgetfilecon(fname, &file_context);
+       } else {
+               status = getfilecon(fname, &file_context);
+       }
+       if (status < 0 && errno != ENODATA) {
+               if ((option_mask32 & OPT_QUIET) == 0)
+                       bb_error_msg("cannot obtain security context: %s", fname);
+               goto skip;
+       }
+
+       if (file_context == NULL && specified_context == NULL) {
+               bb_error_msg("cannot apply partial context to unlabeled file %s", fname);
+               goto skip;
+       }
+
+       if (specified_context == NULL) {
+               context = set_security_context_component(file_context,
+                                                        user, role, type, range);
+               if (!context) {
+                       bb_error_msg("cannot compute security context from %s", file_context);
+                       goto skip;
+               }
+       } else {
+               context = context_new(specified_context);
+               if (!context) {
+                       bb_error_msg("invalid context: %s", specified_context);
+                       goto skip;
+               }
+       }
+
+       context_string = context_str(context);
+       if (!context_string) {
+               bb_error_msg("cannot obtain security context in text expression");
+               goto skip;
+       }
+
+       if (file_context == NULL || strcmp(context_string, file_context) != 0) {
+               int fail;
+
+               if (option_mask32 & OPT_NODEREFERENCE) {
+                       fail = lsetfilecon(fname, context_string);
+               } else {
+                       fail = setfilecon(fname, context_string);
+               }
+               if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) {
+                       printf(!fail
+                              ? "context of %s changed to %s\n"
+                              : "failed to change context of %s to %s\n",
+                              fname, context_string);
+               }
+               if (!fail) {
+                       rc = TRUE;
+               } else if ((option_mask32 & OPT_QUIET) == 0) {
+                       bb_error_msg("failed to change context of %s to %s",
+                                    fname, context_string);
+               }
+       } else if (option_mask32 & OPT_VERBOSE) {
+               printf("context of %s retained as %s\n", fname, context_string);
+               rc = TRUE;
+       }
+skip:
+       /* FIXME: aren't these work ok on NULL ptr? Remove if() then */
+       if (context)
+               context_free(context);
+       if (file_context)
+               freecon(file_context);
+
+       return rc;
+}
+
+#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+static struct option chcon_options[] = {
+       { "recursive",      0, NULL, 'R' },
+       { "changes",        0, NULL, 'c' },
+       { "no-dereference", 0, NULL, 'h' },
+       { "silent",         0, NULL, 'f' },
+       { "quiet",          0, NULL, 'f' },
+       { "user",           1, NULL, 'u' },
+       { "role",           1, NULL, 'r' },
+       { "type",           1, NULL, 't' },
+       { "range",          1, NULL, 'l' },
+       { "verbose",        0, NULL, 'v' },
+       { "reference",      1, NULL, 0xff }, /* no short option */
+       { NULL,             0, NULL, 0 },
+};
+#endif
+
+int chcon_main(int argc, char *argv[]);
+int chcon_main(int argc, char *argv[])
+{
+       char *reference_file;
+       char *fname;
+       int i, errors = 0;
+
+#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+       applet_long_options = chcon_options;
+#endif
+       opt_complementary = "-1"    /* at least 1 param */
+               ":?:f--v:v--f"      /* 'verbose' and 'quiet' are exclusive */
+               ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff";
+       getopt32(argc, argv, "Rchf:u:r:t:l:v",
+               &user, &role, &type, &range, &reference_file);
+       argv += optind;
+
+#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+       if (option_mask32 & OPT_REFERENCE) {
+               /* FIXME: lgetfilecon() should be used when '-h' is specified.
+                  But current implementation follows the original one. */
+               if (getfilecon(reference_file, &specified_context) < 0)
+                       bb_perror_msg_and_die("getfilecon('%s') failed", reference_file);
+       } else
+#endif
+       if ((option_mask32 & OPT_COMPONENT_SPECIFIED) == 0) {
+               specified_context = *argv++;
+               /* specified_context is never NULL -
+                * "-1" in opt_complementary prevents this. */
+               if (!argv[0])
+                       bb_error_msg_and_die("too few arguments");
+       }
+
+       for (i = 0; (fname = argv[i]) != NULL; i++) {
+               int fname_len = strlen(fname);
+               while (fname_len > 1 && fname[fname_len - 1] == '/')
+                       fname_len--;
+               fname[fname_len] = '\0';
+
+               if (recursive_action(fname,
+                                    option_mask32 & OPT_RECURSIVE,
+                                    FALSE,     /* followLinks */
+                                    FALSE,     /* depthFirst */
+                                    change_filedir_context,
+                                    change_filedir_context,
+                                    NULL, 0) != TRUE)
+                       errors = 1;
+       }
+       return errors;
+}
diff --git a/selinux/runcon.c b/selinux/runcon.c
new file mode 100644 (file)
index 0000000..24e436f
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * runcon [ context |
+ *         ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] )
+ *         command [arg1 [arg2 ...] ]
+ *
+ * attempt to run the specified command with the specified context.
+ *
+ * -r role  : use the current context with the specified role
+ * -t type  : use the current context with the specified type
+ * -u user  : use the current context with the specified user
+ * -l level : use the current context with the specified level range
+ * -c       : compute process transition context before modifying
+ *
+ * Contexts are interpreted as follows:
+ *
+ * Number of       MLS
+ * components    system?
+ *
+ *     1            -         type
+ *     2            -         role:type
+ *     3            Y         role:type:range
+ *     3            N         user:role:type
+ *     4            Y         user:role:type:range
+ *     4            N         error
+ *
+ * Port to busybox: KaiGai Kohei <kaigai@kaigai.gr.jp>
+ *                  - based on coreutils-5.97 (in Fedora Core 6)
+ */
+#include "busybox.h"
+#include <getopt.h>
+#include <selinux/context.h>
+#include <selinux/flask.h>
+
+static context_t runcon_compute_new_context(char *user, char *role, char *type, char *range,
+                                           char *command, int compute_trans)
+{
+       context_t con;
+       security_context_t cur_context;
+
+       if (getcon(&cur_context))
+               bb_error_msg_and_die("cannot get current context");
+
+       if (compute_trans) {
+               security_context_t file_context, new_context;
+
+               if (getfilecon(command, &file_context) < 0)
+                       bb_error_msg_and_die("cannot retrieve attributes of '%s'",
+                                            command);
+               if (security_compute_create(cur_context, file_context,
+                                           SECCLASS_PROCESS, &new_context))
+                       bb_error_msg_and_die("unable to compute a new context");
+               cur_context = new_context;
+       }
+
+       con = context_new(cur_context);
+       if (!con)
+               bb_error_msg_and_die("'%s' is not a valid context", cur_context);
+       if (user && context_user_set(con, user))
+               bb_error_msg_and_die("failed to set new user '%s'", user);
+       if (type && context_type_set(con, type))
+               bb_error_msg_and_die("failed to set new type '%s'", type);
+       if (range && context_range_set(con, range))
+               bb_error_msg_and_die("failed to set new range '%s'", range);
+       if (role && context_role_set(con, role))
+               bb_error_msg_and_die("failed to set new role '%s'", role);
+
+       return con;
+}
+
+#if ENABLE_FEATURE_RUNCON_LONG_OPTIONS
+static const struct option runcon_options[] = {
+       { "user",       1, NULL, 'u' },
+       { "role",       1, NULL, 'r' },
+       { "type",       1, NULL, 't' },
+       { "range",      1, NULL, 'l' },
+       { "compute",    0, NULL, 'c' },
+       { "help",       0, NULL, 'h' },
+       { NULL,         0, NULL, 0 },
+};
+#endif
+
+#define OPTS_ROLE      (1<<0)  /* r */
+#define OPTS_TYPE      (1<<1)  /* t */
+#define OPTS_USER      (1<<2)  /* u */
+#define OPTS_RANGE     (1<<3)  /* l */
+#define OPTS_COMPUTE   (1<<4)  /* c */
+#define OPTS_HELP      (1<<5)  /* h */
+#define OPTS_CONTEXT_COMPONENT         (OPTS_ROLE | OPTS_TYPE | OPTS_USER | OPTS_RANGE)
+
+int runcon_main(int argc, char *argv[]);
+int runcon_main(int argc, char *argv[])
+{
+       char *role = NULL;
+       char *range = NULL;
+       char *user = NULL;
+       char *type = NULL;
+       char *context = NULL;
+       unsigned opts;
+       context_t con;
+
+       selinux_or_die();
+
+#if ENABLE_FEATURE_RUNCON_LONG_OPTIONS
+       applet_long_options = runcon_options;
+#endif
+       opt_complementary = "-1";
+       opts = getopt32(argc, argv, "r:t:u:l:ch", &role, &type, &user, &range);
+       argv += optind;
+
+       if (!(opts & OPTS_CONTEXT_COMPONENT)) {
+               context = *argv++;
+               if (!argv[0])
+                       bb_error_msg_and_die("no command found");
+       }
+
+       if (context) {
+               con = context_new(context);
+               if (!con)
+                       bb_error_msg_and_die("'%s' is not a valid context", context);
+       } else {
+               con = runcon_compute_new_context(user, role, type, range,
+                               argv[0], opts & OPTS_COMPUTE);
+       }
+
+       if (security_check_context(context_str(con)))
+               bb_error_msg_and_die("'%s' is not a valid context",
+                                    context_str(con));
+
+       if (setexeccon(context_str(con)))
+               bb_error_msg_and_die("cannot set up security context '%s'",
+                                    context_str(con));
+
+       execvp(argv[0], argv);
+
+       bb_perror_msg_and_die("cannot execute '%s'", command);
+       return 1;
+}