mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-08-18 01:18:51 +02:00
6f5700ac8a
* 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.
250 lines
6.6 KiB
C
250 lines
6.6 KiB
C
/*
|
|
* 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);
|
|
}
|
|
}
|