• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <errno.h>
2 #include <getopt.h>
3 #include <limits.h>
4 #include <selinux/label.h>
5 #include <selinux/selinux.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
usage(const char * progname)13 static __attribute__ ((__noreturn__)) void usage(const char *progname)
14 {
15 	fprintf(stderr,
16 		"usage:  %s [-V] [-N] [-n] [-m type] [-f file_contexts_file] [-p prefix] [-P policy_root_path] filepath...\n",
17 		progname);
18 	exit(1);
19 }
20 
printmatchpathcon(struct selabel_handle * hnd,const char * path,int header,int mode,int notrans)21 static int printmatchpathcon(struct selabel_handle *hnd, const char *path, int header, int mode, int notrans)
22 {
23 	char *buf = NULL;
24 	int rc;
25 
26 	if (notrans) {
27 		rc = selabel_lookup_raw(hnd, &buf, path, mode);
28 	} else {
29 		rc = selabel_lookup(hnd, &buf, path, mode);
30 	}
31 	if (rc < 0) {
32 		if (errno == ENOENT) {
33 			buf = strdup("<<none>>");
34 		} else {
35 			fprintf(stderr, "selabel_lookup(%s) failed: %s\n", path,
36 				strerror(errno));
37 			return 1;
38 		}
39 	}
40 	if (header)
41 		printf("%s\t%s\n", path, buf);
42 	else
43 		printf("%s\n", buf);
44 
45 	freecon(buf);
46 	return 0;
47 }
48 
string_to_mode(char * s)49 static mode_t string_to_mode(char *s)
50 {
51 	switch (s[0]) {
52 	case 'b':
53 		return S_IFBLK;
54 	case 'c':
55 		return S_IFCHR;
56 	case 'd':
57 		return S_IFDIR;
58 	case 'p':
59 		return S_IFIFO;
60 	case 'l':
61 		return S_IFLNK;
62 	case 's':
63 		return S_IFSOCK;
64 	case 'f':
65 		return S_IFREG;
66 	default:
67 		return -1;
68 	}
69 	return -1;
70 }
71 
main(int argc,char ** argv)72 int main(int argc, char **argv)
73 {
74 	int i, force_mode = 0;
75 	int header = 1, opt;
76 	int verify = 0;
77 	int notrans = 0;
78 	int error = 0;
79 	int quiet = 0;
80 	struct selabel_handle *hnd;
81 	struct selinux_opt options[SELABEL_NOPT] = {};
82 
83 	if (argc < 2)
84 		usage(argv[0]);
85 
86 	while ((opt = getopt(argc, argv, "m:Nnf:P:p:Vq")) > 0) {
87 		switch (opt) {
88 		case 'n':
89 			header = 0;
90 			break;
91 		case 'm':
92 			force_mode = string_to_mode(optarg);
93 			if (force_mode < 0) {
94 				fprintf(stderr, "%s: mode %s is invalid\n", argv[0], optarg);
95 				exit(1);
96 			}
97 			break;
98 		case 'V':
99 			verify = 1;
100 			break;
101 		case 'N':
102 			notrans = 1;
103 			break;
104 		case 'f':
105 			options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
106 			options[SELABEL_OPT_PATH].value = optarg;
107 			break;
108 		case 'P':
109 			if (selinux_set_policy_root(optarg) < 0 ) {
110 				fprintf(stderr,
111 					"Error setting policy root  %s:  %s\n",
112 					optarg,
113 					errno ? strerror(errno) : "invalid");
114 				exit(1);
115 			}
116 			break;
117 		case 'p':
118 			// This option has been deprecated since libselinux 2.5 (2016):
119 			// https://github.com/SELinuxProject/selinux/commit/26e05da0fc2d0a4bd274320968a88f8acbb3b6a6
120 			fprintf(stderr, "Warning: using %s -p is deprecated\n", argv[0]);
121 			options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
122 			options[SELABEL_OPT_SUBSET].value = optarg;
123 			break;
124 		case 'q':
125 			quiet = 1;
126 			break;
127 		default:
128 			usage(argv[0]);
129 		}
130 	}
131 	hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT);
132 	if (!hnd) {
133 		fprintf(stderr,
134 			"Error while opening file contexts database: %s\n",
135 			strerror(errno));
136 		return -1;
137 	}
138 	for (i = optind; i < argc; i++) {
139 		int rc, mode = 0;
140 		struct stat buf;
141 		char *path = argv[i];
142 		int len = strlen(path);
143 		if (len > 1  && path[len - 1 ] == '/')
144 			path[len - 1 ] = '\0';
145 
146 		if (lstat(path, &buf) == 0)
147 			mode = buf.st_mode;
148 		if (force_mode)
149 			mode = force_mode;
150 
151 		if (verify) {
152 			rc = selinux_file_context_verify(path, mode);
153 
154 			if (quiet) {
155 				if (rc == 1)
156 					continue;
157 				else
158 					exit(1);
159 			}
160 
161 			if (rc == -1) {
162 				printf("%s error: %s\n", path, strerror(errno));
163 				exit(1);
164 			} else if (rc == 1) {
165 				printf("%s verified.\n", path);
166 			} else {
167 				char * con;
168 				error = 1;
169 				if (notrans)
170 					rc = lgetfilecon_raw(path, &con);
171 				else
172 					rc = lgetfilecon(path, &con);
173 
174 				if (rc >= 0) {
175 					printf("%s has context %s, should be ",
176 					       path, con);
177 					printmatchpathcon(hnd, path, 0, mode, notrans);
178 					freecon(con);
179 				} else {
180 					printf
181 					    ("actual context unknown: %s, should be ",
182 					     strerror(errno));
183 					printmatchpathcon(hnd, path, 0, mode, notrans);
184 				}
185 			}
186 		} else {
187 			error |= printmatchpathcon(hnd, path, header, mode, notrans);
188 		}
189 	}
190 	selabel_close(hnd);
191 	return error;
192 }
193