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