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