build: update gnulib submodule to latest
[coreutils.git] / src / chcon.c
blob4f51d70d471025df16b566c9ce76e40d400fa8c9
1 /* chcon -- change security context of files
2 Copyright (C) 2005-2015 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/>. */
17 #include <config.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <getopt.h>
22 #include "system.h"
23 #include "dev-ino.h"
24 #include "error.h"
25 #include "ignore-value.h"
26 #include "quote.h"
27 #include "root-dev-ino.h"
28 #include "selinux-at.h"
29 #include "xfts.h"
31 /* The official name of this program (e.g., no 'g' prefix). */
32 #define PROGRAM_NAME "chcon"
34 #define AUTHORS \
35 proper_name ("Russell Coker"), \
36 proper_name ("Jim Meyering")
38 /* If nonzero, and the systems has support for it, change the context
39 of symbolic links rather than any files they point to. */
40 static bool affect_symlink_referent;
42 /* If true, change the modes of directories recursively. */
43 static bool recurse;
45 /* Level of verbosity. */
46 static bool verbose;
48 /* Pointer to the device and inode numbers of '/', when --recursive.
49 Otherwise NULL. */
50 static struct dev_ino *root_dev_ino;
52 /* The name of the context file is being given. */
53 static char const *specified_context;
55 /* Specific components of the context */
56 static char const *specified_user;
57 static char const *specified_role;
58 static char const *specified_range;
59 static char const *specified_type;
61 /* For long options that have no equivalent short option, use a
62 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
63 enum
65 DEREFERENCE_OPTION = CHAR_MAX + 1,
66 NO_PRESERVE_ROOT,
67 PRESERVE_ROOT,
68 REFERENCE_FILE_OPTION
71 static struct option const long_options[] =
73 {"recursive", no_argument, NULL, 'R'},
74 {"dereference", no_argument, NULL, DEREFERENCE_OPTION},
75 {"no-dereference", no_argument, NULL, 'h'},
76 {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
77 {"preserve-root", no_argument, NULL, PRESERVE_ROOT},
78 {"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
79 {"user", required_argument, NULL, 'u'},
80 {"role", required_argument, NULL, 'r'},
81 {"type", required_argument, NULL, 't'},
82 {"range", required_argument, NULL, 'l'},
83 {"verbose", no_argument, NULL, 'v'},
84 {GETOPT_HELP_OPTION_DECL},
85 {GETOPT_VERSION_OPTION_DECL},
86 {NULL, 0, NULL, 0}
89 /* Given a security context, CONTEXT, derive a context_t (*RET),
90 setting any portions selected via the global variables, specified_user,
91 specified_role, etc. */
92 static int
93 compute_context_from_mask (char const *context, context_t *ret)
95 bool ok = true;
96 context_t new_context = context_new (context);
97 if (!new_context)
99 error (0, errno, _("failed to create security context: %s"),
100 quote (context));
101 return 1;
104 #define SET_COMPONENT(C, comp) \
105 do \
107 if (specified_ ## comp \
108 && context_ ## comp ## _set ((C), specified_ ## comp)) \
110 error (0, errno, \
111 _("failed to set %s security context component to %s"), \
112 #comp, quote (specified_ ## comp)); \
113 ok = false; \
116 while (0)
118 SET_COMPONENT (new_context, user);
119 SET_COMPONENT (new_context, range);
120 SET_COMPONENT (new_context, role);
121 SET_COMPONENT (new_context, type);
123 if (!ok)
125 int saved_errno = errno;
126 context_free (new_context);
127 errno = saved_errno;
128 return 1;
131 *ret = new_context;
132 return 0;
135 /* Change the context of FILE, using specified components.
136 If it is a directory and -R is given, recurse.
137 Return 0 if successful, 1 if errors occurred. */
139 static int
140 change_file_context (int fd, char const *file)
142 char *file_context = NULL;
143 context_t context IF_LINT (= 0);
144 char const * context_string;
145 int errors = 0;
147 if (specified_context == NULL)
149 int status = (affect_symlink_referent
150 ? getfileconat (fd, file, &file_context)
151 : lgetfileconat (fd, file, &file_context));
153 if (status < 0 && errno != ENODATA)
155 error (0, errno, _("failed to get security context of %s"),
156 quote (file));
157 return 1;
160 /* If the file doesn't have a context, and we're not setting all of
161 the context components, there isn't really an obvious default.
162 Thus, we just give up. */
163 if (file_context == NULL)
165 error (0, 0, _("can't apply partial context to unlabeled file %s"),
166 quote (file));
167 return 1;
170 if (compute_context_from_mask (file_context, &context))
171 return 1;
173 context_string = context_str (context);
175 else
177 context_string = specified_context;
180 if (file_context == NULL || ! STREQ (context_string, file_context))
182 int fail = (affect_symlink_referent
183 ? setfileconat (fd, file, se_const (context_string))
184 : lsetfileconat (fd, file, se_const (context_string)));
186 if (fail)
188 errors = 1;
189 error (0, errno, _("failed to change context of %s to %s"),
190 quote_n (0, file), quote_n (1, context_string));
194 if (specified_context == NULL)
196 context_free (context);
197 freecon (file_context);
200 return errors;
203 /* Change the context of FILE.
204 Return true if successful. This function is called
205 once for every file system object that fts encounters. */
207 static bool
208 process_file (FTS *fts, FTSENT *ent)
210 char const *file_full_name = ent->fts_path;
211 char const *file = ent->fts_accpath;
212 const struct stat *file_stats = ent->fts_statp;
213 bool ok = true;
215 switch (ent->fts_info)
217 case FTS_D:
218 if (recurse)
220 if (ROOT_DEV_INO_CHECK (root_dev_ino, ent->fts_statp))
222 /* This happens e.g., with "chcon -R --preserve-root ... /"
223 and with "chcon -RH --preserve-root ... symlink-to-root". */
224 ROOT_DEV_INO_WARN (file_full_name);
225 /* Tell fts not to traverse into this hierarchy. */
226 fts_set (fts, ent, FTS_SKIP);
227 /* Ensure that we do not process "/" on the second visit. */
228 ignore_value (fts_read (fts));
229 return false;
231 return true;
233 break;
235 case FTS_DP:
236 if (! recurse)
237 return true;
238 break;
240 case FTS_NS:
241 /* For a top-level file or directory, this FTS_NS (stat failed)
242 indicator is determined at the time of the initial fts_open call.
243 With programs like chmod, chown, and chgrp, that modify
244 permissions, it is possible that the file in question is
245 accessible when control reaches this point. So, if this is
246 the first time we've seen the FTS_NS for this file, tell
247 fts_read to stat it "again". */
248 if (ent->fts_level == 0 && ent->fts_number == 0)
250 ent->fts_number = 1;
251 fts_set (fts, ent, FTS_AGAIN);
252 return true;
254 error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name));
255 ok = false;
256 break;
258 case FTS_ERR:
259 error (0, ent->fts_errno, "%s", quote (file_full_name));
260 ok = false;
261 break;
263 case FTS_DNR:
264 error (0, ent->fts_errno, _("cannot read directory %s"),
265 quote (file_full_name));
266 ok = false;
267 break;
269 case FTS_DC: /* directory that causes cycles */
270 if (cycle_warning_required (fts, ent))
272 emit_cycle_warning (file_full_name);
273 return false;
275 break;
277 default:
278 break;
281 if (ent->fts_info == FTS_DP
282 && ok && ROOT_DEV_INO_CHECK (root_dev_ino, file_stats))
284 ROOT_DEV_INO_WARN (file_full_name);
285 ok = false;
288 if (ok)
290 if (verbose)
291 printf (_("changing security context of %s\n"),
292 quote (file_full_name));
294 if (change_file_context (fts->fts_cwd_fd, file) != 0)
295 ok = false;
298 if ( ! recurse)
299 fts_set (fts, ent, FTS_SKIP);
301 return ok;
304 /* Recursively operate on the specified FILES (the last entry
305 of which is NULL). BIT_FLAGS controls how fts works.
306 Return true if successful. */
308 static bool
309 process_files (char **files, int bit_flags)
311 bool ok = true;
313 FTS *fts = xfts_open (files, bit_flags, NULL);
315 while (1)
317 FTSENT *ent;
319 ent = fts_read (fts);
320 if (ent == NULL)
322 if (errno != 0)
324 /* FIXME: try to give a better message */
325 error (0, errno, _("fts_read failed"));
326 ok = false;
328 break;
331 ok &= process_file (fts, ent);
334 if (fts_close (fts) != 0)
336 error (0, errno, _("fts_close failed"));
337 ok = false;
340 return ok;
343 void
344 usage (int status)
346 if (status != EXIT_SUCCESS)
347 emit_try_help ();
348 else
350 printf (_("\
351 Usage: %s [OPTION]... CONTEXT FILE...\n\
352 or: %s [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...\n\
353 or: %s [OPTION]... --reference=RFILE FILE...\n\
355 program_name, program_name, program_name);
356 fputs (_("\
357 Change the SELinux security context of each FILE to CONTEXT.\n\
358 With --reference, change the security context of each FILE to that of RFILE.\n\
359 "), stdout);
361 emit_mandatory_arg_note ();
363 fputs (_("\
364 --dereference affect the referent of each symbolic link (this is\n\
365 the default), rather than the symbolic link itself\n\
366 -h, --no-dereference affect symbolic links instead of any referenced file\n\
367 "), stdout);
368 fputs (_("\
369 -u, --user=USER set user USER in the target security context\n\
370 -r, --role=ROLE set role ROLE in the target security context\n\
371 -t, --type=TYPE set type TYPE in the target security context\n\
372 -l, --range=RANGE set range RANGE in the target security context\n\
373 "), stdout);
374 fputs (_("\
375 --no-preserve-root do not treat '/' specially (the default)\n\
376 --preserve-root fail to operate recursively on '/'\n\
377 "), stdout);
378 fputs (_("\
379 --reference=RFILE use RFILE's security context rather than specifying\n\
380 a CONTEXT value\n\
381 "), stdout);
382 fputs (_("\
383 -R, --recursive operate on files and directories recursively\n\
384 "), stdout);
385 fputs (_("\
386 -v, --verbose output a diagnostic for every file processed\n\
387 "), stdout);
388 fputs (_("\
390 The following options modify how a hierarchy is traversed when the -R\n\
391 option is also specified. If more than one is specified, only the final\n\
392 one takes effect.\n\
394 -H if a command line argument is a symbolic link\n\
395 to a directory, traverse it\n\
396 -L traverse every symbolic link to a directory\n\
397 encountered\n\
398 -P do not traverse any symbolic links (default)\n\
400 "), stdout);
401 fputs (HELP_OPTION_DESCRIPTION, stdout);
402 fputs (VERSION_OPTION_DESCRIPTION, stdout);
403 emit_ancillary_info (PROGRAM_NAME);
405 exit (status);
409 main (int argc, char **argv)
411 /* Bit flags that control how fts works. */
412 int bit_flags = FTS_PHYSICAL;
414 /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
415 specified. */
416 int dereference = -1;
418 bool ok;
419 bool preserve_root = false;
420 bool component_specified = false;
421 char *reference_file = NULL;
422 int optc;
424 initialize_main (&argc, &argv);
425 set_program_name (argv[0]);
426 setlocale (LC_ALL, "");
427 bindtextdomain (PACKAGE, LOCALEDIR);
428 textdomain (PACKAGE);
430 atexit (close_stdout);
432 while ((optc = getopt_long (argc, argv, "HLPRhvu:r:t:l:", long_options, NULL))
433 != -1)
435 switch (optc)
437 case 'H': /* Traverse command-line symlinks-to-directories. */
438 bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
439 break;
441 case 'L': /* Traverse all symlinks-to-directories. */
442 bit_flags = FTS_LOGICAL;
443 break;
445 case 'P': /* Traverse no symlinks-to-directories. */
446 bit_flags = FTS_PHYSICAL;
447 break;
449 case 'h': /* --no-dereference: affect symlinks */
450 dereference = 0;
451 break;
453 case DEREFERENCE_OPTION: /* --dereference: affect the referent
454 of each symlink */
455 dereference = 1;
456 break;
458 case NO_PRESERVE_ROOT:
459 preserve_root = false;
460 break;
462 case PRESERVE_ROOT:
463 preserve_root = true;
464 break;
466 case REFERENCE_FILE_OPTION:
467 reference_file = optarg;
468 break;
470 case 'R':
471 recurse = true;
472 break;
474 case 'f':
475 /* ignore */
476 break;
478 case 'v':
479 verbose = true;
480 break;
482 case 'u':
483 specified_user = optarg;
484 component_specified = true;
485 break;
487 case 'r':
488 specified_role = optarg;
489 component_specified = true;
490 break;
492 case 't':
493 specified_type = optarg;
494 component_specified = true;
495 break;
497 case 'l':
498 specified_range = optarg;
499 component_specified = true;
500 break;
502 case_GETOPT_HELP_CHAR;
503 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
504 default:
505 usage (EXIT_FAILURE);
509 if (recurse)
511 if (bit_flags == FTS_PHYSICAL)
513 if (dereference == 1)
514 error (EXIT_FAILURE, 0,
515 _("-R --dereference requires either -H or -L"));
516 affect_symlink_referent = false;
518 else
520 if (dereference == 0)
521 error (EXIT_FAILURE, 0, _("-R -h requires -P"));
522 affect_symlink_referent = true;
525 else
527 bit_flags = FTS_PHYSICAL;
528 affect_symlink_referent = (dereference != 0);
531 if (argc - optind < (reference_file || component_specified ? 1 : 2))
533 if (argc <= optind)
534 error (0, 0, _("missing operand"));
535 else
536 error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
537 usage (EXIT_FAILURE);
540 if (reference_file)
542 char *ref_context = NULL;
544 if (getfilecon (reference_file, &ref_context) < 0)
545 error (EXIT_FAILURE, errno, _("failed to get security context of %s"),
546 quote (reference_file));
548 specified_context = ref_context;
550 else if (component_specified)
552 /* FIXME: it's already null, so this is a no-op. */
553 specified_context = NULL;
555 else
557 specified_context = argv[optind++];
558 if (security_check_context (se_const (specified_context)) < 0)
559 error (EXIT_FAILURE, errno, _("invalid context: %s"),
560 quote (specified_context));
563 if (reference_file && component_specified)
565 error (0, 0, _("conflicting security context specifiers given"));
566 usage (EXIT_FAILURE);
569 if (recurse && preserve_root)
571 static struct dev_ino dev_ino_buf;
572 root_dev_ino = get_root_dev_ino (&dev_ino_buf);
573 if (root_dev_ino == NULL)
574 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
575 quote ("/"));
577 else
579 root_dev_ino = NULL;
582 ok = process_files (argv + optind, bit_flags | FTS_NOSTAT);
584 return ok ? EXIT_SUCCESS : EXIT_FAILURE;