xref: /aosp_15_r20/external/selinux/policycoreutils/setfiles/restore.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /*
2  * Note that the restorecond(8) service build links with these functions.
3  * Therefore any changes here should also be tested against that utility.
4  */
5 
6 #include "restore.h"
7 #include <glob.h>
8 
9 #ifndef GLOB_BRACE
10 #define GLOB_BRACE 0
11 #endif
12 
13 #ifndef GLOB_TILDE
14 #define GLOB_TILDE 0
15 #endif
16 
17 char **exclude_list;
18 int exclude_count;
19 
restore_init(struct restore_opts * opts)20 void restore_init(struct restore_opts *opts)
21 {
22 	int rc;
23 
24 	struct selinux_opt selinux_opts[] = {
25 		{ SELABEL_OPT_VALIDATE, opts->selabel_opt_validate },
26 		{ SELABEL_OPT_PATH, opts->selabel_opt_path },
27 		{ SELABEL_OPT_DIGEST, opts->selabel_opt_digest }
28 	};
29 
30 	opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 3);
31 	if (!opts->hnd) {
32 		perror(opts->selabel_opt_path ? opts->selabel_opt_path : selinux_file_context_path());
33 		exit(1);
34 	}
35 
36 	opts->restorecon_flags = 0;
37 	opts->restorecon_flags = opts->nochange | opts->verbose |
38 			   opts->progress | opts->set_specctx  |
39 			   opts->add_assoc | opts->ignore_digest |
40 			   opts->recurse | opts->userealpath |
41 			   opts->xdev | opts->abort_on_error |
42 			   opts->syslog_changes | opts->log_matches |
43 			   opts->ignore_noent | opts->ignore_mounts |
44 			   opts->mass_relabel | opts->conflict_error |
45 			   opts->count_errors;
46 
47 	/* Use setfiles, restorecon and restorecond own handles */
48 	selinux_restorecon_set_sehandle(opts->hnd);
49 
50 	if (opts->rootpath) {
51 		rc = selinux_restorecon_set_alt_rootpath(opts->rootpath);
52 		if (rc) {
53 			fprintf(stderr,
54 				"selinux_restorecon_set_alt_rootpath error: %s.\n",
55 				strerror(errno));
56 			exit(-1);
57 		}
58 	}
59 
60 	if (exclude_list)
61 		selinux_restorecon_set_exclude_list
62 						 ((const char **)exclude_list);
63 }
64 
restore_finish(void)65 void restore_finish(void)
66 {
67 	int i;
68 
69 	if (exclude_list) {
70 		for (i = 0; exclude_list[i]; i++)
71 			free(exclude_list[i]);
72 		free(exclude_list);
73 	}
74 }
75 
process_glob(char * name,struct restore_opts * opts,size_t nthreads,long unsigned * skipped_errors)76 int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
77 		 long unsigned *skipped_errors)
78 {
79 	glob_t globbuf;
80 	size_t i, len;
81 	int rc, errors;
82 
83 	memset(&globbuf, 0, sizeof(globbuf));
84 
85 	errors = glob(name, GLOB_TILDE | GLOB_PERIOD |
86 			  GLOB_NOCHECK | GLOB_BRACE, NULL, &globbuf);
87 	if (errors)
88 		return errors;
89 
90 	for (i = 0; i < globbuf.gl_pathc; i++) {
91 		len = strlen(globbuf.gl_pathv[i]);
92 		if (len > 2 && strcmp(&globbuf.gl_pathv[i][len - 2], "/.") == 0)
93 			continue;
94 		if (len > 3 && strcmp(&globbuf.gl_pathv[i][len - 3], "/..") == 0)
95 			continue;
96 		rc = selinux_restorecon_parallel(globbuf.gl_pathv[i],
97 						 opts->restorecon_flags,
98 						 nthreads);
99 		if (rc < 0)
100 			errors = rc;
101 		else if (opts->restorecon_flags & SELINUX_RESTORECON_COUNT_ERRORS)
102 			*skipped_errors += selinux_restorecon_get_skipped_errors();
103 	}
104 
105 	globfree(&globbuf);
106 
107 	return errors;
108 }
109 
add_exclude(const char * directory)110 void add_exclude(const char *directory)
111 {
112 	char **tmp_list;
113 
114 	if (directory == NULL || directory[0] != '/') {
115 		fprintf(stderr, "Full path required for exclude: %s.\n",
116 			    directory);
117 		exit(-1);
118 	}
119 
120 	/* Add another two entries, one for directory, and the other to
121 	 * terminate the list.
122 	 */
123 	tmp_list = realloc(exclude_list, sizeof(char *) * (exclude_count + 2));
124 	if (!tmp_list) {
125 		fprintf(stderr, "realloc failed while excluding %s.\n",
126 			    directory);
127 		exit(-1);
128 	}
129 	exclude_list = tmp_list;
130 
131 	exclude_list[exclude_count] = strdup(directory);
132 	if (!exclude_list[exclude_count]) {
133 		fprintf(stderr, "strdup failed while excluding %s.\n",
134 			    directory);
135 		exit(-1);
136 	}
137 	exclude_count++;
138 	exclude_list[exclude_count] = NULL;
139 }
140