• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <sys/xattr.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <selinux/selinux.h>
12 #include <selinux/label.h>
13 #include <selinux/restorecon.h>
14 
15 #include "restore.h"
16 
usage(const char * progname)17 static __attribute__((__noreturn__)) void usage(const char *progname)
18 {
19 	fprintf(stderr,
20 		"\nusage: %s [-vnrmdD] [-e directory] [-f specfile] pathname\n"
21 		"\nWhere:\n\t"
22 		"-v  Display digest generated by specfile set.\n\t"
23 		"-n  Do not append \"Match\" or \"No Match\" to displayed digests.\n\t"
24 		"-r  Recursively descend directories.\n\t"
25 		"-m  Do not read /proc/mounts for entries to be excluded.\n\t"
26 		"-d  Delete non-matching digest entries.\n\t"
27 		"-D  Delete all digest entries.\n\t"
28 		"-e  Directory to exclude (repeat option for more than one directory).\n\t"
29 		"-f  Optional specfile for calculating the digest.\n\t"
30 		"pathname  Path to search for xattr \"security.restorecon_last\" entries.\n\n",
31 		progname);
32 	exit(-1);
33 }
34 
main(int argc,char ** argv)35 int main(int argc, char **argv)
36 {
37 	int opt, rc;
38 	unsigned int xattr_flags = 0, delete_digest = 0, recurse = 0;
39 	unsigned int delete_all_digests = 0, ignore_mounts = 0;
40 	bool display_digest = false;
41 	char *sha1_buf, **specfiles, *fc_file = NULL;
42 	unsigned char *fc_digest = NULL;
43 	size_t i, fc_digest_len = 0, num_specfiles;
44 
45 	struct stat sb;
46 	struct selabel_handle *hnd = NULL;
47 	struct dir_xattr *current, *next, **xattr_list = NULL;
48 
49 	bool no_comment = true;
50 
51 	if (argc < 2)
52 		usage(argv[0]);
53 
54 	if (is_selinux_enabled() <= 0) {
55 		fprintf(stderr,
56 		    "SELinux must be enabled to perform this operation.\n");
57 		exit(-1);
58 	}
59 
60 	exclude_list = NULL;
61 
62 	while ((opt = getopt(argc, argv, "vnrmdDe:f:")) > 0) {
63 		switch (opt) {
64 		case 'v':
65 			display_digest = true;
66 			break;
67 		case 'n':
68 			no_comment = false;
69 			break;
70 		case 'r':
71 			recurse = SELINUX_RESTORECON_XATTR_RECURSE;
72 			break;
73 		case 'm':
74 			ignore_mounts = SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS;
75 			break;
76 		case 'd':
77 			delete_digest =
78 			    SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS;
79 			break;
80 		case 'D':
81 			delete_all_digests =
82 			    SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS;
83 			break;
84 		case 'e':
85 			if (lstat(optarg, &sb) < 0 && errno != EACCES) {
86 				fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n",
87 					optarg, strerror(errno));
88 				break;
89 			}
90 			add_exclude(optarg);
91 			break;
92 		case 'f':
93 			fc_file = optarg;
94 			break;
95 		default:
96 			usage(argv[0]);
97 		}
98 	}
99 
100 	if (optind >= argc) {
101 		fprintf(stderr, "No pathname specified\n");
102 		exit(-1);
103 	}
104 
105 	struct selinux_opt selinux_opts[] = {
106 		{ SELABEL_OPT_PATH, fc_file },
107 		{ SELABEL_OPT_DIGEST, (char *)1 }
108 	};
109 
110 	hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2);
111 	if (!hnd) {
112 		switch (errno) {
113 		case EOVERFLOW:
114 			fprintf(stderr, "Error: Number of specfiles or"
115 				 " specfile buffer caused an overflow.\n");
116 			break;
117 		default:
118 			fprintf(stderr, "Error: selabel_open: %s\n",
119 							    strerror(errno));
120 		}
121 		exit(-1);
122 	}
123 
124 	/* Use own handle as need to allow different file_contexts. */
125 	selinux_restorecon_set_sehandle(hnd);
126 
127 	if (display_digest) {
128 		if (selabel_digest(hnd, &fc_digest, &fc_digest_len,
129 				   &specfiles, &num_specfiles) < 0) {
130 			fprintf(stderr,
131 				"Error: selabel_digest: Digest not available.\n");
132 			selabel_close(hnd);
133 			exit(-1);
134 		}
135 
136 		sha1_buf = malloc(fc_digest_len * 2 + 1);
137 		if (!sha1_buf) {
138 			fprintf(stderr,
139 				"Error allocating digest buffer: %s\n",
140 							    strerror(errno));
141 			selabel_close(hnd);
142 			exit(-1);
143 		}
144 
145 		for (i = 0; i < fc_digest_len; i++)
146 			sprintf((&sha1_buf[i * 2]), "%02x", fc_digest[i]);
147 
148 		printf("specfiles SHA1 digest: %s\n", sha1_buf);
149 
150 		printf("calculated using the following specfile(s):\n");
151 		if (specfiles) {
152 			for (i = 0; i < num_specfiles; i++)
153 				printf("%s\n", specfiles[i]);
154 		}
155 		free(sha1_buf);
156 		printf("\n");
157 	}
158 
159 	if (exclude_list)
160 		selinux_restorecon_set_exclude_list
161 						 ((const char **)exclude_list);
162 
163 	xattr_flags = delete_digest | delete_all_digests |
164 		      ignore_mounts | recurse;
165 
166 	if (selinux_restorecon_xattr(argv[optind], xattr_flags, &xattr_list)) {
167 		fprintf(stderr,
168 			"Error selinux_restorecon_xattr: %s\n",
169 			strerror(errno));
170 		rc = -1;
171 		goto out;
172 	}
173 
174 	if (xattr_list) {
175 		current = *xattr_list;
176 		while (current) {
177 			next = current->next;
178 			printf("%s ", current->directory);
179 
180 			switch (current->result) {
181 			case MATCH:
182 				printf("Digest: %s%s", current->digest,
183 				       no_comment ? " Match\n" : "\n");
184 				break;
185 			case NOMATCH:
186 				printf("Digest: %s%s", current->digest,
187 				       no_comment ? " No Match\n" : "\n");
188 				break;
189 			case DELETED_MATCH:
190 				printf("Deleted Digest: %s%s", current->digest,
191 				       no_comment ? " Match\n" : "\n");
192 				break;
193 			case DELETED_NOMATCH:
194 				printf("Deleted Digest: %s%s",
195 				       current->digest,
196 				       no_comment ? " No Match\n" : "\n");
197 				break;
198 			case ERROR:
199 				printf("Digest: %s Error removing xattr\n",
200 				       current->digest);
201 				break;
202 			}
203 			current = next;
204 		}
205 		/* Free memory */
206 		current = *xattr_list;
207 		while (current) {
208 			next = current->next;
209 			free(current->directory);
210 			free(current->digest);
211 			free(current);
212 			current = next;
213 		}
214 	}
215 
216 	rc = 0;
217 out:
218 	selabel_close(hnd);
219 	restore_finish();
220 	return rc;
221 }
222