1 /* runcon -- run command with specified security context
2 Copyright (C) 2005-2024 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/>. */
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:
39 * 4 Y user:role:type:range
46 #include <selinux/selinux.h>
47 #include <selinux/context.h>
48 #include <sys/types.h>
52 /* The official name of this program (e.g., no 'g' prefix). */
53 #define PROGRAM_NAME "runcon"
55 #define AUTHORS proper_name ("Russell Coker")
57 static struct option
const long_options
[] =
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}
72 if (status
!= EXIT_SUCCESS
)
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
);
81 Run a program in a different SELinux security context.\n\
82 With neither CONTEXT nor COMMAND, print the current security context.\n\
85 emit_mandatory_arg_note ();
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\
95 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
96 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
97 emit_exec_status (PROGRAM_NAME
);
98 emit_ancillary_info (PROGRAM_NAME
);
104 main (int argc
, char **argv
)
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;
118 initialize_main (&argc
, &argv
);
119 set_program_name (argv
[0]);
120 setlocale (LC_ALL
, "");
121 bindtextdomain (PACKAGE
, LOCALEDIR
);
122 textdomain (PACKAGE
);
124 initialize_exit_failure (EXIT_CANCELED
);
125 atexit (close_stdout
);
129 int option_index
= 0;
130 int c
= getopt_long (argc
, argv
, "+r:t:u:l:c", long_options
,
138 error (EXIT_CANCELED
, 0, _("multiple roles"));
143 error (EXIT_CANCELED
, 0, _("multiple types"));
148 error (EXIT_CANCELED
, 0, _("multiple users"));
153 error (EXIT_CANCELED
, 0, _("multiple levelranges"));
157 compute_trans
= true;
160 case_GETOPT_HELP_CHAR
;
161 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
163 usage (EXIT_CANCELED
);
168 if (argc
- optind
== 0)
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
);
177 if (!(user
|| role
|| type
|| range
|| compute_trans
))
181 error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
182 usage (EXIT_CANCELED
);
184 context
= argv
[optind
++];
189 error (0, 0, _("no command specified"));
190 usage (EXIT_CANCELED
);
193 if (is_selinux_enabled () != 1)
194 error (EXIT_CANCELED
, 0, _("%s may be used only on a SELinux kernel"),
199 con
= context_new (context
);
201 error (EXIT_CANCELED
, errno
, _("failed to create security context: %s"),
206 if (getcon (&cur_context
) < 0)
207 error (EXIT_CANCELED
, errno
, _("failed to get current context"));
209 /* We will generate context based on process transition */
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"),
221 error (EXIT_CANCELED
, errno
, _("failed to compute a new context"));
223 freecon (file_context
);
224 freecon (cur_context
);
226 /* set cur_context equal to new_context */
227 cur_context
= new_context
;
230 con
= context_new (cur_context
);
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"),
237 if (type
&& context_type_set (con
, type
))
238 error (EXIT_CANCELED
, errno
, _("failed to set new type: %s"),
240 if (range
&& context_range_set (con
, range
))
241 error (EXIT_CANCELED
, errno
, _("failed to set new range: %s"),
243 if (role
&& context_role_set (con
, role
))
244 error (EXIT_CANCELED
, errno
, _("failed to set new role: %s"),
248 if (security_check_context (context_str (con
)) < 0)
249 error (EXIT_CANCELED
, errno
, _("invalid context: %s"),
250 quote (context_str (con
)));
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
);
258 (compute_trans
? execv
: execvp
) (argv
[optind
], argv
+ optind
);
260 int exit_status
= errno
== ENOENT
? EXIT_ENOENT
: EXIT_CANNOT_INVOKE
;
261 error (0, errno
, "%s", quote (argv
[optind
]));