From c6922b6f7e3ed8c0d565f588df3bd4daf6635f2b Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Fri, 2 Feb 2007 18:58:41 +0100 Subject: * 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. * po/POTFILES.in: Add src/runcon.c. --- src/Makefile.am | 4 +- src/runcon.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/runcon.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 853773038..0da57e357 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 000000000..ac0b90661 --- /dev/null +++ b/src/runcon.c @@ -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 +#include +#include +#include +#include +#ifdef HAVE_SELINUX_FLASK_H +# include +#else +# define SECCLASS_PROCESS 0 +#endif +#include +#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); + } +} -- cgit v1.2.3-54-g00ecf