* src/runcon.c: New program.
authorJim Meyering <jim@meyering.net>
Fri, 2 Feb 2007 17:58:41 +0000 (18:58 +0100)
committerJim Meyering <jim@meyering.net>
Thu, 29 Mar 2007 19:37:06 +0000 (21:37 +0200)
* src/Makefile.am (bin_PROGRAMS): Add runcon.
(runcon_LDADD): Define.
* README: Add runcon to the list of programs.
* AUTHORS: Add this: runcon: Russell Coker
* tests/help-version: Add runcon as an exception.
* man/Makefile.am (dist_man_MANS): Add runcon.1.
(runcon.1): New dependency.
* po/POTFILES.in: Add src/runcon.c.

AUTHORS
ChangeLog-selinux
README
man/Makefile.am
man/runcon.x [new file with mode: 0644]
po/ChangeLog
po/POTFILES.in
src/Makefile.am
src/runcon.c [new file with mode: 0644]
tests/help-version

diff --git a/AUTHORS b/AUTHORS
index 11e02c5..9a8b2c9 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -61,6 +61,7 @@ pwd: Jim Meyering
 readlink: Dmitry V. Levin
 rm: Paul Rubin, David MacKenzie, Richard Stallman, Jim Meyering
 rmdir: David MacKenzie
+runcon: Russell Coker
 seq: Ulrich Drepper
 sha1sum: Ulrich Drepper, Scott Miller, David Madore
 sha224sum: Ulrich Drepper, Scott Miller, David Madore
index 7a27296..63df994 100644 (file)
@@ -1,3 +1,14 @@
+2007-02-02  Jim Meyering  <jim@meyering.net>
+
+       * src/runcon.c: New program.
+       * src/Makefile.am (bin_PROGRAMS): Add runcon.
+       (runcon_LDADD): Define.
+       * README: Add runcon to the list of programs.
+       * AUTHORS: Add this: runcon: Russell Coker
+       * tests/help-version: Add runcon as an exception.
+       * man/Makefile.am (dist_man_MANS): Add runcon.1.
+       (runcon.1): New dependency.
+
 2007-01-31  Jim Meyering  <jim@meyering.net>
 
        mkfifo, mknod: Accept new "-Z, --context=C" option.
diff --git a/README b/README
index 13ef2dc..62853c2 100644 (file)
--- a/README
+++ b/README
@@ -10,11 +10,11 @@ The programs that can be built with this package are:
   [ base64 basename cat chcon chgrp chmod chown chroot cksum comm cp
   csplit cut date dd df dir dircolors dirname du echo env expand expr
   factor false fmt fold groups head hostid hostname id install join
-  kill link ln logname ls md5sum mkdir mkfifo mknod mv nice nl nohup od
-  paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir seq
-  sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf sleep sort
-  split stat stty su sum sync tac tail tee test touch tr true tsort tty
-  uname unexpand uniq unlink uptime users vdir wc who whoami yes
+  kill link ln logname ls md5sum mkdir mkfifo mknod mv nice nl nohup
+  od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir
+  runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf
+  sleep sort split stat stty su sum sync tac tail tee test touch tr true
+  tsort tty uname unexpand uniq unlink uptime users vdir wc who whoami yes
 
 See the file NEWS for a list of major changes in the current release.
 
index 8c5f610..650306e 100644 (file)
@@ -25,7 +25,8 @@ dist_man_MANS = \
   link.1 ln.1 logname.1 \
   ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nl.1 nohup.1 od.1 \
   paste.1 pathchk.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \
-  rm.1 rmdir.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
+  rm.1 rmdir.1 runcon.1 seq.1 \
+  sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
   shred.1 shuf.1 sleep.1 sort.1 split.1 stat.1 \
   su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \
   tty.1 unexpand.1 uniq.1 unlink.1 vdir.1 wc.1 \
@@ -105,6 +106,7 @@ pwd.1:              $(common_dep)   $(srcdir)/pwd.x         ../src/pwd.c
 readlink.1:    $(common_dep)   $(srcdir)/readlink.x    ../src/readlink.c
 rm.1:          $(common_dep)   $(srcdir)/rm.x          ../src/rm.c
 rmdir.1:       $(common_dep)   $(srcdir)/rmdir.x       ../src/rmdir.c
+runcon.1:      $(common_dep)   $(srcdir)/runcon.x      ../src/runcon.c
 seq.1:         $(common_dep)   $(srcdir)/seq.x         ../src/seq.c
 sha1sum.1:     $(common_dep)   $(srcdir)/sha1sum.x     ../src/md5sum.c
 sha224sum.1:   $(common_dep)   $(srcdir)/sha224sum.x   ../src/md5sum.c
diff --git a/man/runcon.x b/man/runcon.x
new file mode 100644 (file)
index 0000000..d2df13e
--- /dev/null
@@ -0,0 +1,14 @@
+[NAME]
+runcon \- run command with specified security context
+[DESCRIPTION]
+Run COMMAND with completely-specified CONTEXT, or with current or
+transitioned security context modified by one or more of LEVEL,
+ROLE, TYPE, and USER.
+.PP
+If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified,
+the first argument is used as the complete context.  Any additional
+arguments after \fICOMMAND\fR are interpreted as arguments to the
+command.
+.PP
+Note that only carefully-chosen contexts are likely to successfully
+run.
index ad54a09..709c42e 100644 (file)
@@ -1,3 +1,7 @@
+2007-02-02  Jim Meyering  <jim@meyering.net>
+
+       * POTFILES.in: Add src/runcon.c.
+
 2007-01-13  Jim Meyering  <jim@meyering.net>
 
        * POTFILES.in: Add src/chcon.c.
index 8592947..c9679f1 100644 (file)
@@ -91,6 +91,7 @@ src/readlink.c
 src/remove.c
 src/rm.c
 src/rmdir.c
+src/runcon.c
 src/seq.c
 src/setuidgid.c
 src/shred.c
index 8537730..0da57e3 100644 (file)
@@ -26,7 +26,8 @@ bin_PROGRAMS = [ chcon chgrp chown chmod cp dd dircolors du \
   nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \
   shuf sort split sum tac tail tr tsort unexpand uniq wc \
   basename date dirname echo env expr factor false \
-  hostname id kill logname pathchk printenv printf pwd seq sleep tee \
+  hostname id kill logname pathchk printenv printf pwd \
+  runcon seq sleep tee \
   test true tty whoami yes \
   base64 \
   $(OPTIONAL_BIN_PROGS) $(DF_PROG)
@@ -67,6 +68,7 @@ mkdir_LDADD = $(LDADD) $(LIB_SELINUX)
 mkfifo_LDADD = $(LDADD) $(LIB_SELINUX)
 mknod_LDADD = $(LDADD) $(LIB_SELINUX)
 mv_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
+runcon_LDADD = $(LDADD) $(LIB_SELINUX)
 pathchk_LDADD = $(LDADD) $(LIB_EACCESS)
 rm_LDADD = $(LDADD) $(LIB_EACCESS)
 test_LDADD = $(LDADD) $(LIB_EACCESS)
diff --git a/src/runcon.c b/src/runcon.c
new file mode 100644 (file)
index 0000000..ac0b906
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#ifdef HAVE_SELINUX_FLASK_H
+# include <selinux/flask.h>
+#else
+# define SECCLASS_PROCESS 0
+#endif
+#include <sys/types.h>
+#include "system.h"
+#include "error.h"
+#include "quote.h"
+#include "quotearg.h"
+
+/* The official name of this program (e.g., no `g' prefix).  */
+#define PROGRAM_NAME "runcon"
+
+#define AUTHORS "Russell Coker"
+
+static struct option long_options[] = {
+  {"role", required_argument, NULL, 'r'},
+  {"type", required_argument, NULL, 't'},
+  {"user", required_argument, NULL, 'u'},
+  {"range", required_argument, NULL, 'l'},
+  {"compute", no_argument, NULL, 'c'},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
+  {NULL, 0, NULL, 0}
+};
+
+/* The name the program was run with. */
+char *program_name;
+
+void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+            program_name);
+  else
+    {
+      printf (_("\
+Usage: %s CONTEXT COMMAND [args]\n\
+  or:  %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
+"), program_name, program_name);
+      fputs (_("\
+Run a program in a different security context.\n\
+With neither CONTEXT nor COMMAND, print the current security context.\n\
+\n\
+  CONTEXT            Complete security context\n\
+  -c, --compute      compute process transition context before modifying\n\
+  -t, --type=TYPE    type (for same role as parent)\n\
+  -u, --user=USER    user identity\n\
+  -r, --role=ROLE    role\n\
+  -l, --range=RANGE  levelrange\n\
+\n\
+"), stdout);
+      fputs (HELP_OPTION_DESCRIPTION, stdout);
+      fputs (VERSION_OPTION_DESCRIPTION, stdout);
+    }
+  exit (status);
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+  char *role = NULL;
+  char *range = NULL;
+  char *user = NULL;
+  char *type = NULL;
+  char *context = NULL;
+  security_context_t cur_context = NULL;
+  security_context_t file_context = NULL;
+  security_context_t new_context = NULL;
+  bool compute_trans = false;
+
+  context_t con;
+
+  initialize_main (&argc, &argv);
+  program_name = argv[0];
+  setlocale (LC_ALL, "");
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  atexit (close_stdout);
+
+  while (1)
+    {
+      int c;
+      int option_index = 0;
+      c = getopt_long (argc, argv, "r:t:u:l:c", long_options, &option_index);
+      if (c == -1)
+       break;
+      switch (c)
+       {
+       case 'r':
+         if (role)
+           error (EXIT_FAILURE, 0, _("multiple roles"));
+         role = optarg;
+         break;
+       case 't':
+         if (type)
+           error (EXIT_FAILURE, 0, _("multiple types"));
+         type = optarg;
+         break;
+       case 'u':
+         if (user)
+           error (EXIT_FAILURE, 0, _("multiple users"));
+         user = optarg;
+         break;
+       case 'l':
+         if (range)
+           error (EXIT_FAILURE, 0, _("multiple levelranges"));
+         range = optarg;
+         break;
+       case 'c':
+         compute_trans = true;
+         break;
+
+       case_GETOPT_HELP_CHAR;
+       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+       default:
+         usage (EXIT_FAILURE);
+         break;
+       }
+    }
+
+  if (argc - optind == 0)
+    {
+      if (getcon (&cur_context) < 0)
+       error (EXIT_FAILURE, errno, _("failed to get current context"));
+      fputs (cur_context, stdout);
+      fputc ('\n', stdout);
+      exit (EXIT_SUCCESS);
+    }
+
+  if (!(user || role || type || range || compute_trans))
+    {
+      if (optind >= argc)
+       {
+         error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
+         usage (1);
+       }
+      context = argv[optind++];
+    }
+
+  if (optind >= argc)
+    {
+      error (0, 0, _("no command specified"));
+      usage (1);
+    }
+
+  if (is_selinux_enabled () != 1)
+    error (EXIT_FAILURE, 0,
+          _("runcon may be used only on a SELinux kernel."));
+
+  if (context)
+    {
+      con = context_new (context);
+      if (!con)
+       error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
+              quotearg_colon (context));
+    }
+  else
+    {
+      if (getcon (&cur_context) < 0)
+       error (EXIT_FAILURE, errno, _("failed to get current context"));
+
+      /* We will generate context based on process transition */
+      if (compute_trans)
+       {
+         /* Get context of file to be executed */
+         if (getfilecon (argv[optind], &file_context) == -1)
+           error (EXIT_FAILURE, errno,
+                  _("failed to get security context of %s"),
+                  quote (argv[optind]));
+         /* compute result of process transition */
+         if (security_compute_create (cur_context, file_context,
+                                      SECCLASS_PROCESS, &new_context) != 0)
+           error (EXIT_FAILURE, errno,
+                  _("failed to compute a new context"));
+         /* free contexts */
+         freecon (file_context);
+         freecon (cur_context);
+
+         /* set cur_context equal to new_context */
+         cur_context = new_context;
+       }
+
+      con = context_new (cur_context);
+      if (!con)
+       error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
+              quotearg_colon (cur_context));
+      if (user && context_user_set (con, user))
+       error (EXIT_FAILURE, errno, _("failed to set new user %s"), user);
+      if (type && context_type_set (con, type))
+       error (EXIT_FAILURE, errno, _("failed to set new type %s"), type);
+      if (range && context_range_set (con, range))
+       error (EXIT_FAILURE, errno, _("failed to set new range %s"), range);
+      if (role && context_role_set (con, role))
+       error (EXIT_FAILURE, errno, _("failed to set new role %s"), role);
+    }
+
+  if (security_check_context (context_str (con)) < 0)
+    error (EXIT_FAILURE, errno, _("invalid context: %s"),
+          quotearg_colon (context_str (con)));
+
+  if (setexeccon (context_str (con)) != 0)
+    error (EXIT_FAILURE, errno, _("unable to set security context %s"),
+          quote (context_str (con)));
+  if (cur_context != NULL)
+    freecon (cur_context);
+
+  execvp (argv[optind], argv + optind);
+
+  {
+    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+    error (0, errno, "%s", argv[optind]);
+    exit (exit_status);
+  }
+}
index d3c9bfb..3dea4d1 100755 (executable)
@@ -72,6 +72,7 @@ for lang in C fr da; do
     # Skip `test'; it doesn't accept --help or --version.
     test $i = test && continue;
     test $i = chcon && continue;
+    test $i = runcon && continue;
 
     # false fails even when invoked with --help or --version.
     if test $i = false; then
@@ -197,7 +198,7 @@ lbracket_args=": ]"
 
 for i in $all_programs; do
   # Skip these.
-  case $i in chroot|stty|tty|false|chcon) continue;; esac
+  case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac
 
   rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out
   echo > $tmp_in