ls: --color now highlights hard linked files, too
[coreutils/bo.git] / src / runcon.c
blobfce83e52aa7199ea0ff4c3ba6397063399b5a208
1 /* runcon -- run command with specified security context
2 Copyright (C) 2005-2008 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 * runcon [ context |
19 * ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] )
20 * command [arg1 [arg2 ...] ]
22 * attempt to run the specified command with the specified context.
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
30 * Contexts are interpreted as follows:
32 * Number of MLS
33 * components system?
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
43 #include <config.h>
44 #include <stdio.h>
45 #include <getopt.h>
46 #include <selinux/selinux.h>
47 #include <selinux/context.h>
48 #ifdef HAVE_SELINUX_FLASK_H
49 # include <selinux/flask.h>
50 #else
51 # define SECCLASS_PROCESS 0
52 #endif
53 #include <sys/types.h>
54 #include "system.h"
55 #include "error.h"
56 #include "quote.h"
57 #include "quotearg.h"
59 /* The official name of this program (e.g., no `g' prefix). */
60 #define PROGRAM_NAME "runcon"
62 #define AUTHORS proper_name ("Russell Coker")
64 static struct option const long_options[] =
66 {"role", required_argument, NULL, 'r'},
67 {"type", required_argument, NULL, 't'},
68 {"user", required_argument, NULL, 'u'},
69 {"range", required_argument, NULL, 'l'},
70 {"compute", no_argument, NULL, 'c'},
71 {GETOPT_HELP_OPTION_DECL},
72 {GETOPT_VERSION_OPTION_DECL},
73 {NULL, 0, NULL, 0}
76 void
77 usage (int status)
79 if (status != EXIT_SUCCESS)
80 fprintf (stderr, _("Try `%s --help' for more information.\n"),
81 program_name);
82 else
84 printf (_("\
85 Usage: %s CONTEXT COMMAND [args]\n\
86 or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
87 "), program_name, program_name);
88 fputs (_("\
89 Run a program in a different security context.\n\
90 With neither CONTEXT nor COMMAND, print the current security context.\n\
91 \n\
92 CONTEXT Complete security context\n\
93 -c, --compute compute process transition context before modifying\n\
94 -t, --type=TYPE type (for same role as parent)\n\
95 -u, --user=USER user identity\n\
96 -r, --role=ROLE role\n\
97 -l, --range=RANGE levelrange\n\
98 \n\
99 "), stdout);
100 fputs (HELP_OPTION_DESCRIPTION, stdout);
101 fputs (VERSION_OPTION_DESCRIPTION, stdout);
102 emit_bug_reporting_address ();
104 exit (status);
108 main (int argc, char **argv)
110 char *role = NULL;
111 char *range = NULL;
112 char *user = NULL;
113 char *type = NULL;
114 char *context = NULL;
115 security_context_t cur_context = NULL;
116 security_context_t file_context = NULL;
117 security_context_t new_context = NULL;
118 bool compute_trans = false;
120 context_t con;
122 initialize_main (&argc, &argv);
123 set_program_name (argv[0]);
124 setlocale (LC_ALL, "");
125 bindtextdomain (PACKAGE, LOCALEDIR);
126 textdomain (PACKAGE);
128 atexit (close_stdout);
130 while (1)
132 int option_index = 0;
133 int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,
134 &option_index);
135 if (c == -1)
136 break;
137 switch (c)
139 case 'r':
140 if (role)
141 error (EXIT_FAILURE, 0, _("multiple roles"));
142 role = optarg;
143 break;
144 case 't':
145 if (type)
146 error (EXIT_FAILURE, 0, _("multiple types"));
147 type = optarg;
148 break;
149 case 'u':
150 if (user)
151 error (EXIT_FAILURE, 0, _("multiple users"));
152 user = optarg;
153 break;
154 case 'l':
155 if (range)
156 error (EXIT_FAILURE, 0, _("multiple levelranges"));
157 range = optarg;
158 break;
159 case 'c':
160 compute_trans = true;
161 break;
163 case_GETOPT_HELP_CHAR;
164 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
165 default:
166 usage (EXIT_FAILURE);
167 break;
171 if (argc - optind == 0)
173 if (getcon (&cur_context) < 0)
174 error (EXIT_FAILURE, errno, _("failed to get current context"));
175 fputs (cur_context, stdout);
176 fputc ('\n', stdout);
177 exit (EXIT_SUCCESS);
180 if (!(user || role || type || range || compute_trans))
182 if (optind >= argc)
184 error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
185 usage (1);
187 context = argv[optind++];
190 if (optind >= argc)
192 error (0, 0, _("no command specified"));
193 usage (1);
196 if (is_selinux_enabled () != 1)
197 error (EXIT_FAILURE, 0,
198 _("runcon may be used only on a SELinux kernel"));
200 if (context)
202 con = context_new (context);
203 if (!con)
204 error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
205 quotearg_colon (context));
207 else
209 if (getcon (&cur_context) < 0)
210 error (EXIT_FAILURE, errno, _("failed to get current context"));
212 /* We will generate context based on process transition */
213 if (compute_trans)
215 /* Get context of file to be executed */
216 if (getfilecon (argv[optind], &file_context) == -1)
217 error (EXIT_FAILURE, errno,
218 _("failed to get security context of %s"),
219 quote (argv[optind]));
220 /* compute result of process transition */
221 if (security_compute_create (cur_context, file_context,
222 SECCLASS_PROCESS, &new_context) != 0)
223 error (EXIT_FAILURE, errno,
224 _("failed to compute a new context"));
225 /* free contexts */
226 freecon (file_context);
227 freecon (cur_context);
229 /* set cur_context equal to new_context */
230 cur_context = new_context;
233 con = context_new (cur_context);
234 if (!con)
235 error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
236 quotearg_colon (cur_context));
237 if (user && context_user_set (con, user))
238 error (EXIT_FAILURE, errno, _("failed to set new user %s"), user);
239 if (type && context_type_set (con, type))
240 error (EXIT_FAILURE, errno, _("failed to set new type %s"), type);
241 if (range && context_range_set (con, range))
242 error (EXIT_FAILURE, errno, _("failed to set new range %s"), range);
243 if (role && context_role_set (con, role))
244 error (EXIT_FAILURE, errno, _("failed to set new role %s"), role);
247 if (security_check_context (context_str (con)) < 0)
248 error (EXIT_FAILURE, errno, _("invalid context: %s"),
249 quotearg_colon (context_str (con)));
251 if (setexeccon (context_str (con)) != 0)
252 error (EXIT_FAILURE, errno, _("unable to set security context %s"),
253 quote (context_str (con)));
254 if (cur_context != NULL)
255 freecon (cur_context);
257 execvp (argv[optind], argv + optind);
260 int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
261 error (0, errno, "%s", argv[optind]);
262 exit (exit_status);