PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/policycoreutils-2.1.12/setfiles/setfiles.c

#
C | 485 lines | 390 code | 62 blank | 33 comment | 83 complexity | 7d0366f092b2b306e21606b3e608af50 MD5 | raw file
Possible License(s): GPL-2.0
  1. #include "restore.h"
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <stdio_ext.h>
  5. #include <ctype.h>
  6. #include <regex.h>
  7. #include <sys/vfs.h>
  8. #define __USE_XOPEN_EXTENDED 1 /* nftw */
  9. #include <libgen.h>
  10. #ifdef USE_AUDIT
  11. #include <libaudit.h>
  12. #ifndef AUDIT_FS_RELABEL
  13. #define AUDIT_FS_RELABEL 2309
  14. #endif
  15. #endif
  16. /* cmdline opts*/
  17. static char *policyfile = NULL;
  18. static int warn_no_match = 0;
  19. static int null_terminated = 0;
  20. static struct restore_opts r_opts;
  21. #define STAT_BLOCK_SIZE 1
  22. #define SETFILES "setfiles"
  23. #define RESTORECON "restorecon"
  24. static int iamrestorecon;
  25. /* Behavior flags determined based on setfiles vs. restorecon */
  26. static int ctx_validate; /* Validate contexts */
  27. static const char *altpath; /* Alternate path to file_contexts */
  28. void usage(const char *const name)
  29. {
  30. if (iamrestorecon) {
  31. fprintf(stderr,
  32. "usage: %s [-iFnprRv0] [ -L labelprefix ] [-e excludedir ] [-o filename ] [-f filename | pathname... ]\n",
  33. name);
  34. } else {
  35. fprintf(stderr,
  36. "usage: %s [-dnpqvW] [-o filename] [-r alt_root_path ] spec_file pathname...\n"
  37. "usage: %s -c policyfile spec_file\n"
  38. "usage: %s -s [-dnpqvW] [-o filename ] spec_file\n", name, name,
  39. name);
  40. }
  41. exit(1);
  42. }
  43. static int nerr = 0;
  44. void inc_err()
  45. {
  46. nerr++;
  47. if (nerr > 9 && !r_opts.debug) {
  48. fprintf(stderr, "Exiting after 10 errors.\n");
  49. exit(1);
  50. }
  51. }
  52. void set_rootpath(const char *arg)
  53. {
  54. int len;
  55. r_opts.rootpath = strdup(arg);
  56. if (NULL == r_opts.rootpath) {
  57. fprintf(stderr, "%s: insufficient memory for r_opts.rootpath\n",
  58. r_opts.progname);
  59. exit(1);
  60. }
  61. /* trim trailing /, if present */
  62. len = strlen(r_opts.rootpath);
  63. while (len && ('/' == r_opts.rootpath[len - 1]))
  64. r_opts.rootpath[--len] = 0;
  65. r_opts.rootpathlen = len;
  66. }
  67. int canoncon(char **contextp)
  68. {
  69. char *context = *contextp, *tmpcon;
  70. int rc = 0;
  71. if (policyfile) {
  72. if (sepol_check_context(context) < 0) {
  73. fprintf(stderr, "invalid context %s\n", context);
  74. exit(1);
  75. }
  76. } else if (security_canonicalize_context_raw(context, &tmpcon) == 0) {
  77. free(context);
  78. *contextp = tmpcon;
  79. } else if (errno != ENOENT) {
  80. rc = -1;
  81. inc_err();
  82. }
  83. return rc;
  84. }
  85. #ifndef USE_AUDIT
  86. static void maybe_audit_mass_relabel(int mass_relabel __attribute__((unused)),
  87. int mass_relabel_errs __attribute__((unused)))
  88. {
  89. #else
  90. static void maybe_audit_mass_relabel(int mass_relabel, int mass_relabel_errs)
  91. {
  92. int audit_fd = -1;
  93. int rc = 0;
  94. if (!mass_relabel) /* only audit a forced full relabel */
  95. return;
  96. audit_fd = audit_open();
  97. if (audit_fd < 0) {
  98. fprintf(stderr, "Error connecting to audit system.\n");
  99. exit(-1);
  100. }
  101. rc = audit_log_user_message(audit_fd, AUDIT_FS_RELABEL,
  102. "op=mass relabel", NULL, NULL, NULL, !mass_relabel_errs);
  103. if (rc <= 0) {
  104. fprintf(stderr, "Error sending audit message: %s.\n",
  105. strerror(errno));
  106. /* exit(-1); -- don't exit atm. as fix for eff_cap isn't in most kernels */
  107. }
  108. audit_close(audit_fd);
  109. #endif
  110. }
  111. int main(int argc, char **argv)
  112. {
  113. struct stat sb;
  114. int opt, i;
  115. char *input_filename = NULL;
  116. int use_input_file = 0;
  117. char *buf = NULL;
  118. size_t buf_len;
  119. int recurse; /* Recursive descent. */
  120. char *base;
  121. int mass_relabel = 0, errors = 0;
  122. int num_prefixes = 0;
  123. const char *null_array[1] = { NULL };
  124. memset(&r_opts, 0, sizeof(r_opts));
  125. /* Initialize variables */
  126. r_opts.progress = 0;
  127. r_opts.count = 0;
  128. r_opts.nfile = 0;
  129. r_opts.debug = 0;
  130. r_opts.change = 1;
  131. r_opts.verbose = 0;
  132. r_opts.logging = 0;
  133. r_opts.rootpath = NULL;
  134. r_opts.rootpathlen = 0;
  135. r_opts.outfile = NULL;
  136. r_opts.force = 0;
  137. r_opts.hard_links = 1;
  138. r_opts.selabel_opt_prefixes = null_array;
  139. altpath = NULL;
  140. r_opts.progname = strdup(argv[0]);
  141. if (!r_opts.progname) {
  142. fprintf(stderr, "%s: Out of memory!\n", argv[0]);
  143. exit(1);
  144. }
  145. base = basename(r_opts.progname);
  146. if (!strcmp(base, SETFILES)) {
  147. /*
  148. * setfiles:
  149. * Recursive descent,
  150. * Does not expand paths via realpath,
  151. * Aborts on errors during the file tree walk,
  152. * Try to track inode associations for conflict detection,
  153. * Does not follow mounts,
  154. * Validates all file contexts at init time.
  155. */
  156. iamrestorecon = 0;
  157. recurse = 1;
  158. r_opts.expand_realpath = 0;
  159. r_opts.abort_on_error = 1;
  160. r_opts.add_assoc = 1;
  161. r_opts.fts_flags = FTS_PHYSICAL | FTS_XDEV;
  162. ctx_validate = 1;
  163. } else {
  164. /*
  165. * restorecon:
  166. * No recursive descent unless -r/-R,
  167. * Expands paths via realpath,
  168. * Do not abort on errors during the file tree walk,
  169. * Do not try to track inode associations for conflict detection,
  170. * Follows mounts,
  171. * Does lazy validation of contexts upon use.
  172. */
  173. if (strcmp(base, RESTORECON) && !r_opts.quiet)
  174. printf("Executed with an unrecognized name (%s), defaulting to %s behavior.\n", base, RESTORECON);
  175. iamrestorecon = 1;
  176. recurse = 0;
  177. r_opts.expand_realpath = 1;
  178. r_opts.abort_on_error = 0;
  179. r_opts.add_assoc = 0;
  180. r_opts.fts_flags = FTS_PHYSICAL;
  181. ctx_validate = 0;
  182. /* restorecon only: silent exit if no SELinux.
  183. Allows unconditional execution by scripts. */
  184. if (is_selinux_enabled() <= 0)
  185. exit(0);
  186. }
  187. /* This must happen before getopt. */
  188. r_opts.nfile = exclude_non_seclabel_mounts();
  189. /* Process any options. */
  190. while ((opt = getopt(argc, argv, "c:de:f:ilnpqrsvo:FL:RW0")) > 0) {
  191. switch (opt) {
  192. case 'c':
  193. {
  194. FILE *policystream;
  195. if (iamrestorecon)
  196. usage(argv[0]);
  197. policyfile = optarg;
  198. policystream = fopen(policyfile, "r");
  199. if (!policystream) {
  200. fprintf(stderr,
  201. "Error opening %s: %s\n",
  202. policyfile, strerror(errno));
  203. exit(1);
  204. }
  205. __fsetlocking(policystream,
  206. FSETLOCKING_BYCALLER);
  207. if (sepol_set_policydb_from_file(policystream) <
  208. 0) {
  209. fprintf(stderr,
  210. "Error reading policy %s: %s\n",
  211. policyfile, strerror(errno));
  212. exit(1);
  213. }
  214. fclose(policystream);
  215. ctx_validate = 1;
  216. break;
  217. }
  218. case 'e':
  219. remove_exclude(optarg);
  220. if (lstat(optarg, &sb) < 0 && errno != EACCES) {
  221. fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n",
  222. optarg, strerror(errno));
  223. break;
  224. }
  225. if (add_exclude(optarg))
  226. exit(1);
  227. break;
  228. case 'f':
  229. use_input_file = 1;
  230. input_filename = optarg;
  231. break;
  232. case 'd':
  233. r_opts.debug = 1;
  234. break;
  235. case 'i':
  236. r_opts.ignore_enoent = 1;
  237. break;
  238. case 'l':
  239. r_opts.logging = 1;
  240. break;
  241. case 'F':
  242. r_opts.force = 1;
  243. break;
  244. case 'n':
  245. r_opts.change = 0;
  246. break;
  247. case 'L':
  248. {
  249. char **new_prefixes;
  250. /* we need 1 for this entry and 1 for the NULL entry */
  251. new_prefixes = malloc(sizeof(*new_prefixes) * (num_prefixes + 2));
  252. if (!new_prefixes) {
  253. fprintf(stderr, "Can't allocate memory for labeling prefix %s:%s\n",
  254. optarg, strerror(errno));
  255. exit(1);
  256. }
  257. memcpy(new_prefixes, r_opts.selabel_opt_prefixes, sizeof(*new_prefixes) * num_prefixes);
  258. new_prefixes[num_prefixes] = strdup(optarg);
  259. if (!new_prefixes[num_prefixes]) {
  260. fprintf(stderr, "Can't allocate memory for labeling prefix %s:%s\n",
  261. optarg, strerror(errno));
  262. exit(1);
  263. }
  264. new_prefixes[num_prefixes + 1] = NULL;
  265. num_prefixes++;
  266. if (r_opts.selabel_opt_prefixes != null_array)
  267. free(r_opts.selabel_opt_prefixes);
  268. r_opts.selabel_opt_prefixes = (const char **)new_prefixes;
  269. break;
  270. }
  271. case 'o':
  272. if (strcmp(optarg, "-") == 0) {
  273. r_opts.outfile = stdout;
  274. break;
  275. }
  276. r_opts.outfile = fopen(optarg, "w");
  277. if (!r_opts.outfile) {
  278. fprintf(stderr, "Error opening %s: %s\n",
  279. optarg, strerror(errno));
  280. usage(argv[0]);
  281. }
  282. __fsetlocking(r_opts.outfile, FSETLOCKING_BYCALLER);
  283. break;
  284. case 'q':
  285. r_opts.quiet = 1;
  286. break;
  287. case 'R':
  288. case 'r':
  289. if (iamrestorecon) {
  290. recurse = 1;
  291. break;
  292. }
  293. if (optind + 1 >= argc) {
  294. fprintf(stderr, "usage: %s -r rootpath\n",
  295. argv[0]);
  296. exit(1);
  297. }
  298. if (NULL != r_opts.rootpath) {
  299. fprintf(stderr,
  300. "%s: only one -r can be specified\n",
  301. argv[0]);
  302. exit(1);
  303. }
  304. set_rootpath(argv[optind++]);
  305. break;
  306. case 's':
  307. use_input_file = 1;
  308. input_filename = "-";
  309. r_opts.add_assoc = 0;
  310. break;
  311. case 'v':
  312. if (r_opts.progress) {
  313. fprintf(stderr,
  314. "Progress and Verbose mutually exclusive\n");
  315. exit(1);
  316. }
  317. r_opts.verbose++;
  318. break;
  319. case 'p':
  320. if (r_opts.verbose) {
  321. fprintf(stderr,
  322. "Progress and Verbose mutually exclusive\n");
  323. usage(argv[0]);
  324. }
  325. r_opts.progress++;
  326. break;
  327. case 'W':
  328. warn_no_match = 1;
  329. break;
  330. case '0':
  331. null_terminated = 1;
  332. break;
  333. case '?':
  334. usage(argv[0]);
  335. }
  336. }
  337. for (i = optind; i < argc; i++) {
  338. if (!strcmp(argv[i], "/")) {
  339. mass_relabel = 1;
  340. if (r_opts.progress)
  341. r_opts.progress++;
  342. }
  343. }
  344. if (!iamrestorecon) {
  345. if (policyfile) {
  346. if (optind != (argc - 1))
  347. usage(argv[0]);
  348. } else if (use_input_file) {
  349. if (optind != (argc - 1)) {
  350. /* Cannot mix with pathname arguments. */
  351. usage(argv[0]);
  352. }
  353. } else {
  354. if (optind > (argc - 2))
  355. usage(argv[0]);
  356. }
  357. /* Use our own invalid context checking function so that
  358. we can support either checking against the active policy or
  359. checking against a binary policy file. */
  360. selinux_set_callback(SELINUX_CB_VALIDATE,
  361. (union selinux_callback)&canoncon);
  362. if (stat(argv[optind], &sb) < 0) {
  363. perror(argv[optind]);
  364. exit(1);
  365. }
  366. if (!S_ISREG(sb.st_mode)) {
  367. fprintf(stderr, "%s: spec file %s is not a regular file.\n",
  368. argv[0], argv[optind]);
  369. exit(1);
  370. }
  371. altpath = argv[optind];
  372. optind++;
  373. }
  374. /* Load the file contexts configuration and check it. */
  375. r_opts.selabel_opt_validate = (ctx_validate ? (char *)1 : NULL);
  376. r_opts.selabel_opt_path = altpath;
  377. if (nerr)
  378. exit(1);
  379. restore_init(&r_opts);
  380. if (use_input_file) {
  381. FILE *f = stdin;
  382. ssize_t len;
  383. int delim;
  384. if (strcmp(input_filename, "-") != 0)
  385. f = fopen(input_filename, "r");
  386. if (f == NULL) {
  387. fprintf(stderr, "Unable to open %s: %s\n", input_filename,
  388. strerror(errno));
  389. usage(argv[0]);
  390. }
  391. __fsetlocking(f, FSETLOCKING_BYCALLER);
  392. delim = (null_terminated != 0) ? '\0' : '\n';
  393. while ((len = getdelim(&buf, &buf_len, delim, f)) > 0) {
  394. buf[len - 1] = 0;
  395. if (!strcmp(buf, "/"))
  396. mass_relabel = 1;
  397. errors |= process_glob(buf, recurse) < 0;
  398. }
  399. if (strcmp(input_filename, "-") != 0)
  400. fclose(f);
  401. } else {
  402. for (i = optind; i < argc; i++) {
  403. errors |= process_glob(argv[i], recurse) < 0;
  404. }
  405. }
  406. maybe_audit_mass_relabel(mass_relabel, errors);
  407. if (warn_no_match)
  408. selabel_stats(r_opts.hnd);
  409. selabel_close(r_opts.hnd);
  410. restore_finish();
  411. if (r_opts.outfile)
  412. fclose(r_opts.outfile);
  413. if (r_opts.progress && r_opts.count >= STAR_COUNT)
  414. printf("\n");
  415. free(r_opts.progname);
  416. i = 0;
  417. while (r_opts.selabel_opt_prefixes[i])
  418. free((void *)r_opts.selabel_opt_prefixes[i++]);
  419. if (r_opts.selabel_opt_prefixes != null_array)
  420. free(r_opts.selabel_opt_prefixes);
  421. free(r_opts.rootpath);
  422. exit(errors);
  423. }