doc: od --strings: clarify operation
[coreutils.git] / src / runcon.c
blob7f54ca25e1fedf91d4df4165d769fe30274de69f
1 /* runcon -- run command with specified security context
2 Copyright (C) 2005-2023 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 <https://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 #include <sys/types.h>
49 #include "system.h"
50 #include "die.h"
51 #include "error.h"
52 #include "quote.h"
54 /* The official name of this program (e.g., no 'g' prefix). */
55 #define PROGRAM_NAME "runcon"
57 #define AUTHORS proper_name ("Russell Coker")
59 static struct option const long_options[] =
61 {"role", required_argument, NULL, 'r'},
62 {"type", required_argument, NULL, 't'},
63 {"user", required_argument, NULL, 'u'},
64 {"range", required_argument, NULL, 'l'},
65 {"compute", no_argument, NULL, 'c'},
66 {GETOPT_HELP_OPTION_DECL},
67 {GETOPT_VERSION_OPTION_DECL},
68 {NULL, 0, NULL, 0}
71 void
72 usage (int status)
74 if (status != EXIT_SUCCESS)
75 emit_try_help ();
76 else
78 printf (_("\
79 Usage: %s CONTEXT COMMAND [args]\n\
80 or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
81 "), program_name, program_name);
82 fputs (_("\
83 Run a program in a different SELinux security context.\n\
84 With neither CONTEXT nor COMMAND, print the current security context.\n\
85 "), stdout);
87 emit_mandatory_arg_note ();
89 fputs (_("\
90 CONTEXT Complete security context\n\
91 -c, --compute compute process transition context before modifying\n\
92 -t, --type=TYPE type (for same role as parent)\n\
93 -u, --user=USER user identity\n\
94 -r, --role=ROLE role\n\
95 -l, --range=RANGE levelrange\n\
96 "), stdout);
97 fputs (HELP_OPTION_DESCRIPTION, stdout);
98 fputs (VERSION_OPTION_DESCRIPTION, stdout);
99 emit_exec_status (PROGRAM_NAME);
100 emit_ancillary_info (PROGRAM_NAME);
102 exit (status);
106 main (int argc, char **argv)
108 char *role = NULL;
109 char *range = NULL;
110 char *user = NULL;
111 char *type = NULL;
112 char *context = NULL;
113 char *cur_context = NULL;
114 char *file_context = NULL;
115 char *new_context = NULL;
116 bool compute_trans = false;
118 context_t con;
120 initialize_main (&argc, &argv);
121 set_program_name (argv[0]);
122 setlocale (LC_ALL, "");
123 bindtextdomain (PACKAGE, LOCALEDIR);
124 textdomain (PACKAGE);
126 initialize_exit_failure (EXIT_CANCELED);
127 atexit (close_stdout);
129 while (true)
131 int option_index = 0;
132 int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,
133 &option_index);
134 if (c == -1)
135 break;
136 switch (c)
138 case 'r':
139 if (role)
140 die (EXIT_CANCELED, 0, _("multiple roles"));
141 role = optarg;
142 break;
143 case 't':
144 if (type)
145 die (EXIT_CANCELED, 0, _("multiple types"));
146 type = optarg;
147 break;
148 case 'u':
149 if (user)
150 die (EXIT_CANCELED, 0, _("multiple users"));
151 user = optarg;
152 break;
153 case 'l':
154 if (range)
155 die (EXIT_CANCELED, 0, _("multiple levelranges"));
156 range = optarg;
157 break;
158 case 'c':
159 compute_trans = true;
160 break;
162 case_GETOPT_HELP_CHAR;
163 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
164 default:
165 usage (EXIT_CANCELED);
166 break;
170 if (argc - optind == 0)
172 if (getcon (&cur_context) < 0)
173 die (EXIT_CANCELED, errno, _("failed to get current context"));
174 fputs (cur_context, stdout);
175 fputc ('\n', stdout);
176 return EXIT_SUCCESS;
179 if (!(user || role || type || range || compute_trans))
181 if (optind >= argc)
183 error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
184 usage (EXIT_CANCELED);
186 context = argv[optind++];
189 if (optind >= argc)
191 error (0, 0, _("no command specified"));
192 usage (EXIT_CANCELED);
195 if (is_selinux_enabled () != 1)
196 die (EXIT_CANCELED, 0, _("%s may be used only on a SELinux kernel"),
197 program_name);
199 if (context)
201 con = context_new (context);
202 if (!con)
203 die (EXIT_CANCELED, errno, _("failed to create security context: %s"),
204 quote (context));
206 else
208 if (getcon (&cur_context) < 0)
209 die (EXIT_CANCELED, errno, _("failed to get current context"));
211 /* We will generate context based on process transition */
212 if (compute_trans)
214 /* Get context of file to be executed */
215 if (getfilecon (argv[optind], &file_context) == -1)
216 die (EXIT_CANCELED, errno,
217 _("failed to get security context of %s"),
218 quoteaf (argv[optind]));
219 /* compute result of process transition */
220 if (security_compute_create (cur_context, file_context,
221 string_to_security_class ("process"),
222 &new_context) != 0)
223 die (EXIT_CANCELED, errno, _("failed to compute a new context"));
224 /* free contexts */
225 freecon (file_context);
226 freecon (cur_context);
228 /* set cur_context equal to new_context */
229 cur_context = new_context;
232 con = context_new (cur_context);
233 if (!con)
234 die (EXIT_CANCELED, errno, _("failed to create security context: %s"),
235 quote (cur_context));
236 if (user && context_user_set (con, user))
237 die (EXIT_CANCELED, errno, _("failed to set new user: %s"),
238 quote (user));
239 if (type && context_type_set (con, type))
240 die (EXIT_CANCELED, errno, _("failed to set new type: %s"),
241 quote (type));
242 if (range && context_range_set (con, range))
243 die (EXIT_CANCELED, errno, _("failed to set new range: %s"),
244 quote (range));
245 if (role && context_role_set (con, role))
246 die (EXIT_CANCELED, errno, _("failed to set new role: %s"),
247 quote (role));
250 if (security_check_context (context_str (con)) < 0)
251 die (EXIT_CANCELED, errno, _("invalid context: %s"),
252 quote (context_str (con)));
254 if (setexeccon (context_str (con)) != 0)
255 die (EXIT_CANCELED, errno, _("unable to set security context %s"),
256 quote (context_str (con)));
257 if (cur_context != NULL)
258 freecon (cur_context);
260 (compute_trans ? execv : execvp) (argv[optind], argv + optind);
262 int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
263 error (0, errno, "%s", quote (argv[optind]));
264 return exit_status;