/* runcon -- run command with specified security context                        This is the runcon utility
   Copyright (C) 2005-2018 Free Software Foundation, Inc.                       
                                                                                
   This program is free software: you can redistribute it and/or modify         
   it under the terms of the GNU General Public License as published by         
   the Free Software Foundation, either version 3 of the License, or            
   (at your option) any later version.                                          
                                                                                
   This program is distributed in the hope that it will be useful,              
   but WITHOUT ANY WARRANTY; without even the implied warranty of               
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                
   GNU General Public License for more details.                                 
                                                                                
   You should have received a copy of the GNU General Public License            
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */   The GNUv3 license
                                                                                
/*                                                                              
 * 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>                                                             Provides system specific information
#include <stdio.h>                                                              Provides standard I/O capability
#include <getopt.h>                                                             ...!includes auto-comment...
#include <selinux/selinux.h>                                                    ...!includes auto-comment......!includes auto-comment...
#include <selinux/context.h>                                                    ...!includes auto-comment...
#include <sys/types.h>                                                          Provides system data types
#include "system.h"                                                             ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "runcon"                                                   Line 55
                                                                                
#define AUTHORS proper_name ("Russell Coker")                                   Line 57
                                                                                
static struct option const long_options[] =                                     Line 59
{                                                                               
  {"role", required_argument, NULL, 'r'},                                       Line 61
  {"type", required_argument, NULL, 't'},                                       Line 62
  {"user", required_argument, NULL, 'u'},                                       Line 63
  {"range", required_argument, NULL, 'l'},                                      Line 64
  {"compute", no_argument, NULL, 'c'},                                          Line 65
  {GETOPT_HELP_OPTION_DECL},                                                    Line 66
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 67
  {NULL, 0, NULL, 0}                                                            Line 68
};                                                                              Block 1
                                                                                
void                                                                            Line 71
usage (int status)                                                              Line 72
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 74
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 76
    {                                                                           
      printf (_("\                                                              Line 78
Usage: %s CONTEXT COMMAND [args]\n\                                             Line 79
  or:  %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\     Line 80
"), program_name, program_name);                                                Line 81
      fputs (_("\                                                               Line 82
Run a program in a different SELinux security context.\n\                       Line 83
With neither CONTEXT nor COMMAND, print the current security context.\n\        Line 84
"), stdout);                                                                    Line 85
                                                                                
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 89
  CONTEXT            Complete security context\n\                               Line 90
  -c, --compute      compute process transition context before modifying\n\     Line 91
  -t, --type=TYPE    type (for same role as parent)\n\                          Line 92
  -u, --user=USER    user identity\n\                                           Line 93
  -r, --role=ROLE    role\n\                                                    Line 94
  -l, --range=RANGE  levelrange\n\                                              Line 95
\n\                                                                             
"), stdout);                                                                    Line 97
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 98
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 99
      emit_ancillary_info (PROGRAM_NAME);                                       Line 100
    }                                                                           
  exit (status);                                                                Line 102
}                                                                               Block 2
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 106
{                                                                               
  char *role = NULL;                                                            Line 108
  char *range = NULL;                                                           Line 109
  char *user = NULL;                                                            Line 110
  char *type = NULL;                                                            Line 111
  char *context = NULL;                                                         Line 112
  char *cur_context = NULL;                                                     Line 113
  char *file_context = NULL;                                                    Line 114
  char *new_context = NULL;                                                     Line 115
  bool compute_trans = false;                                                   Line 116
                                                                                
  context_t con;                                                                Line 118
                                                                                
  initialize_main (&argc, &argv);                                               VMS-specific entry point handling wildcard expansion
  set_program_name (argv[0]);                                                   Retains program name and discards path
  setlocale (LC_ALL, "");                                                       Sets up internationalization (i18n)
  bindtextdomain (PACKAGE, LOCALEDIR);                                          Assigns i18n directorySets text domain for _() [gettext()] function
  textdomain (PACKAGE);                                                         Sets text domain for _() [gettext()] function
                                                                                
  atexit (close_stdout);                                                        Close stdout on exit (see gnulib)
                                                                                
  while (1)                                                                     Line 128
    {                                                                           
      int option_index = 0;                                                     Line 130
      int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,              Line 131
                           &option_index);                                      Line 132
      if (c == -1)                                                              Line 133
        break;                                                                  Line 134
      switch (c)                                                                Line 135
        {                                                                       
        case 'r':                                                               Line 137
          if (role)                                                             Line 138
            die (EXIT_FAILURE, 0, _("multiple roles"));                         Line 139
          role = optarg;                                                        Line 140
          break;                                                                Line 141
        case 't':                                                               Line 142
          if (type)                                                             Line 143
            die (EXIT_FAILURE, 0, _("multiple types"));                         Line 144
          type = optarg;                                                        Line 145
          break;                                                                Line 146
        case 'u':                                                               Line 147
          if (user)                                                             Line 148
            die (EXIT_FAILURE, 0, _("multiple users"));                         Line 149
          user = optarg;                                                        Line 150
          break;                                                                Line 151
        case 'l':                                                               Line 152
          if (range)                                                            Line 153
            die (EXIT_FAILURE, 0, _("multiple levelranges"));                   Line 154
          range = optarg;                                                       Line 155
          break;                                                                Line 156
        case 'c':                                                               Line 157
          compute_trans = true;                                                 Line 158
          break;                                                                Line 159
                                                                                
        case_GETOPT_HELP_CHAR;                                                  Line 161
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 162
        default:                                                                Line 163
          usage (EXIT_FAILURE);                                                 Line 164
          break;                                                                Line 165
        }                                                                       
    }                                                                           
                                                                                
  if (argc - optind == 0)                                                       Line 169
    {                                                                           
      if (getcon (&cur_context) < 0)                                            Line 171
        die (EXIT_FAILURE, errno, _("failed to get current context"));          Line 172
      fputs (cur_context, stdout);                                              Line 173
      fputc ('\n', stdout);                                                     Line 174
      return EXIT_SUCCESS;                                                      Line 175
    }                                                                           
                                                                                
  if (!(user || role || type || range || compute_trans))                        Line 178
    {                                                                           
      if (optind >= argc)                                                       Line 180
        {                                                                       
          error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));   Line 182
          usage (EXIT_FAILURE);                                                 Line 183
        }                                                                       
      context = argv[optind++];                                                 Line 185
    }                                                                           
                                                                                
  if (optind >= argc)                                                           Line 188
    {                                                                           
      error (0, 0, _("no command specified"));                                  Line 190
      usage (EXIT_FAILURE);                                                     Line 191
    }                                                                           
                                                                                
  if (is_selinux_enabled () != 1)                                               ...!common auto-comment...
    die (EXIT_FAILURE, 0, _("%s may be used only on a SELinux kernel"),         Line 195
         program_name);                                                         Line 196
                                                                                
  if (context)                                                                  Line 198
    {                                                                           
      con = context_new (context);                                              Line 200
      if (!con)                                                                 Line 201
        die (EXIT_FAILURE, errno, _("failed to create security context: %s"),   Line 202
             quote (context));                                                  Line 203
    }                                                                           
  else                                                                          Line 205
    {                                                                           
      if (getcon (&cur_context) < 0)                                            Line 207
        die (EXIT_FAILURE, errno, _("failed to get current context"));          Line 208
                                                                                
      /* We will generate context based on process transition */                
      if (compute_trans)                                                        Line 211
        {                                                                       
          /* Get context of file to be executed */                              
          if (getfilecon (argv[optind], &file_context) == -1)                   Line 214
            die (EXIT_FAILURE, errno,                                           Line 215
                 _("failed to get security context of %s"),                     Line 216
                 quoteaf (argv[optind]));                                       Line 217
          /* compute result of process transition */                            
          if (security_compute_create (cur_context, file_context,               Line 219
                                       string_to_security_class ("process"),    Line 220
                                       &new_context) != 0)                      Line 221
            die (EXIT_FAILURE, errno, _("failed to compute a new context"));    Line 222
          /* free contexts */                                                   
          freecon (file_context);                                               Line 224
          freecon (cur_context);                                                Line 225
                                                                                
          /* set cur_context equal to new_context */                            
          cur_context = new_context;                                            Line 228
        }                                                                       
                                                                                
      con = context_new (cur_context);                                          Line 231
      if (!con)                                                                 Line 232
        die (EXIT_FAILURE, errno, _("failed to create security context: %s"),   Line 233
             quote (cur_context));                                              Line 234
      if (user && context_user_set (con, user))                                 Line 235
        die (EXIT_FAILURE, errno, _("failed to set new user: %s"),              Line 236
             quote (user));                                                     Line 237
      if (type && context_type_set (con, type))                                 Line 238
        die (EXIT_FAILURE, errno, _("failed to set new type: %s"),              Line 239
             quote (type));                                                     Line 240
      if (range && context_range_set (con, range))                              Line 241
        die (EXIT_FAILURE, errno, _("failed to set new range: %s"),             Line 242
             quote (range));                                                    Line 243
      if (role && context_role_set (con, role))                                 Line 244
        die (EXIT_FAILURE, errno, _("failed to set new role: %s"),              Line 245
             quote (role));                                                     Line 246
    }                                                                           
                                                                                
  if (security_check_context (context_str (con)) < 0)                           Line 249
    die (EXIT_FAILURE, errno, _("invalid context: %s"),                         Line 250
         quote (context_str (con)));                                            Line 251
                                                                                
  if (setexeccon (context_str (con)) != 0)                                      Line 253
    die (EXIT_FAILURE, errno, _("unable to set security context %s"),           Line 254
         quote (context_str (con)));                                            Line 255
  if (cur_context != NULL)                                                      Line 256
    freecon (cur_context);                                                      Line 257
                                                                                
  execvp (argv[optind], argv + optind);                                         Line 259
                                                                                
  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;         Line 261
  error (0, errno, "%s", quote (argv[optind]));                                 Line 262
  return exit_status;                                                           Line 263
}                                                                               Block 3