(root)/
coreutils-9.4/
src/
runcon.c
       1  /* runcon -- run command with specified security context
       2     Copyright (C) 2005-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /*
      18   * runcon [ context
      19   *          | ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] )
      20   *          command [arg1 [arg2 ...] ]
      21   *
      22   * attempt to run the specified command with the specified context.
      23   *
      24   * -r role  : use the current context with the specified role
      25   * -t type  : use the current context with the specified type
      26   * -u user  : use the current context with the specified user
      27   * -l level : use the current context with the specified level range
      28   * -c       : compute process transition context before modifying
      29   *
      30   * Contexts are interpreted as follows:
      31   *
      32   * Number of       MLS
      33   * components    system?
      34   *
      35   *     1            -         type
      36   *     2            -         role:type
      37   *     3            Y         role:type:range
      38   *     3            N         user:role:type
      39   *     4            Y         user:role:type:range
      40   *     4            N         error
      41   */
      42  
      43  #include <config.h>
      44  #include <stdio.h>
      45  #include <getopt.h>
      46  #include <selinux/selinux.h>
      47  #include <selinux/context.h>
      48  #include <sys/types.h>
      49  #include "system.h"
      50  #include "quote.h"
      51  
      52  /* The official name of this program (e.g., no 'g' prefix).  */
      53  #define PROGRAM_NAME "runcon"
      54  
      55  #define AUTHORS proper_name ("Russell Coker")
      56  
      57  static struct option const long_options[] =
      58  {
      59    {"role", required_argument, nullptr, 'r'},
      60    {"type", required_argument, nullptr, 't'},
      61    {"user", required_argument, nullptr, 'u'},
      62    {"range", required_argument, nullptr, 'l'},
      63    {"compute", no_argument, nullptr, 'c'},
      64    {GETOPT_HELP_OPTION_DECL},
      65    {GETOPT_VERSION_OPTION_DECL},
      66    {nullptr, 0, nullptr, 0}
      67  };
      68  
      69  void
      70  usage (int status)
      71  {
      72    if (status != EXIT_SUCCESS)
      73      emit_try_help ();
      74    else
      75      {
      76        printf (_("\
      77  Usage: %s CONTEXT COMMAND [args]\n\
      78    or:  %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
      79  "), program_name, program_name);
      80        fputs (_("\
      81  Run a program in a different SELinux security context.\n\
      82  With neither CONTEXT nor COMMAND, print the current security context.\n\
      83  "), stdout);
      84  
      85        emit_mandatory_arg_note ();
      86  
      87        fputs (_("\
      88    CONTEXT            Complete security context\n\
      89    -c, --compute      compute process transition context before modifying\n\
      90    -t, --type=TYPE    type (for same role as parent)\n\
      91    -u, --user=USER    user identity\n\
      92    -r, --role=ROLE    role\n\
      93    -l, --range=RANGE  levelrange\n\
      94  "), stdout);
      95        fputs (HELP_OPTION_DESCRIPTION, stdout);
      96        fputs (VERSION_OPTION_DESCRIPTION, stdout);
      97        emit_exec_status (PROGRAM_NAME);
      98        emit_ancillary_info (PROGRAM_NAME);
      99      }
     100    exit (status);
     101  }
     102  
     103  int
     104  main (int argc, char **argv)
     105  {
     106    char *role = nullptr;
     107    char *range = nullptr;
     108    char *user = nullptr;
     109    char *type = nullptr;
     110    char *context = nullptr;
     111    char *cur_context = nullptr;
     112    char *file_context = nullptr;
     113    char *new_context = nullptr;
     114    bool compute_trans = false;
     115  
     116    context_t con;
     117  
     118    initialize_main (&argc, &argv);
     119    set_program_name (argv[0]);
     120    setlocale (LC_ALL, "");
     121    bindtextdomain (PACKAGE, LOCALEDIR);
     122    textdomain (PACKAGE);
     123  
     124    initialize_exit_failure (EXIT_CANCELED);
     125    atexit (close_stdout);
     126  
     127    while (true)
     128      {
     129        int option_index = 0;
     130        int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,
     131                             &option_index);
     132        if (c == -1)
     133          break;
     134        switch (c)
     135          {
     136          case 'r':
     137            if (role)
     138              error (EXIT_CANCELED, 0, _("multiple roles"));
     139            role = optarg;
     140            break;
     141          case 't':
     142            if (type)
     143              error (EXIT_CANCELED, 0, _("multiple types"));
     144            type = optarg;
     145            break;
     146          case 'u':
     147            if (user)
     148              error (EXIT_CANCELED, 0, _("multiple users"));
     149            user = optarg;
     150            break;
     151          case 'l':
     152            if (range)
     153              error (EXIT_CANCELED, 0, _("multiple levelranges"));
     154            range = optarg;
     155            break;
     156          case 'c':
     157            compute_trans = true;
     158            break;
     159  
     160          case_GETOPT_HELP_CHAR;
     161          case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     162          default:
     163            usage (EXIT_CANCELED);
     164            break;
     165          }
     166      }
     167  
     168    if (argc - optind == 0)
     169      {
     170        if (getcon (&cur_context) < 0)
     171          error (EXIT_CANCELED, errno, _("failed to get current context"));
     172        fputs (cur_context, stdout);
     173        fputc ('\n', stdout);
     174        return EXIT_SUCCESS;
     175      }
     176  
     177    if (!(user || role || type || range || compute_trans))
     178      {
     179        if (optind >= argc)
     180          {
     181            error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
     182            usage (EXIT_CANCELED);
     183          }
     184        context = argv[optind++];
     185      }
     186  
     187    if (optind >= argc)
     188      {
     189        error (0, 0, _("no command specified"));
     190        usage (EXIT_CANCELED);
     191      }
     192  
     193    if (is_selinux_enabled () != 1)
     194      error (EXIT_CANCELED, 0, _("%s may be used only on a SELinux kernel"),
     195             program_name);
     196  
     197    if (context)
     198      {
     199        con = context_new (context);
     200        if (!con)
     201          error (EXIT_CANCELED, errno, _("failed to create security context: %s"),
     202                 quote (context));
     203      }
     204    else
     205      {
     206        if (getcon (&cur_context) < 0)
     207          error (EXIT_CANCELED, errno, _("failed to get current context"));
     208  
     209        /* We will generate context based on process transition */
     210        if (compute_trans)
     211          {
     212            /* Get context of file to be executed */
     213            if (getfilecon (argv[optind], &file_context) == -1)
     214              error (EXIT_CANCELED, errno,
     215                     _("failed to get security context of %s"),
     216                     quoteaf (argv[optind]));
     217            /* compute result of process transition */
     218            if (security_compute_create (cur_context, file_context,
     219                                         string_to_security_class ("process"),
     220                                         &new_context) != 0)
     221              error (EXIT_CANCELED, errno, _("failed to compute a new context"));
     222            /* free contexts */
     223            freecon (file_context);
     224            freecon (cur_context);
     225  
     226            /* set cur_context equal to new_context */
     227            cur_context = new_context;
     228          }
     229  
     230        con = context_new (cur_context);
     231        if (!con)
     232          error (EXIT_CANCELED, errno, _("failed to create security context: %s"),
     233                 quote (cur_context));
     234        if (user && context_user_set (con, user))
     235          error (EXIT_CANCELED, errno, _("failed to set new user: %s"),
     236                 quote (user));
     237        if (type && context_type_set (con, type))
     238          error (EXIT_CANCELED, errno, _("failed to set new type: %s"),
     239                 quote (type));
     240        if (range && context_range_set (con, range))
     241          error (EXIT_CANCELED, errno, _("failed to set new range: %s"),
     242                 quote (range));
     243        if (role && context_role_set (con, role))
     244          error (EXIT_CANCELED, errno, _("failed to set new role: %s"),
     245                 quote (role));
     246      }
     247  
     248    if (security_check_context (context_str (con)) < 0)
     249      error (EXIT_CANCELED, errno, _("invalid context: %s"),
     250             quote (context_str (con)));
     251  
     252    if (setexeccon (context_str (con)) != 0)
     253      error (EXIT_CANCELED, errno, _("unable to set security context %s"),
     254             quote (context_str (con)));
     255    if (cur_context != nullptr)
     256      freecon (cur_context);
     257  
     258    (compute_trans ? execv : execvp) (argv[optind], argv + optind);
     259  
     260    int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
     261    error (0, errno, "%s", quote (argv[optind]));
     262    return exit_status;
     263  }