1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <getopt.h>
5 #include <errno.h>
6 #include <sys/stat.h>
7 #include <selinux/selinux.h>
8 #include <selinux/label.h>
9
usage(const char * progname)10 static __attribute__ ((__noreturn__)) void usage(const char *progname)
11 {
12 fprintf(stderr,
13 "usage: %s [-v] [-r] -p path [-m mode] [-f file] [link...]\n\n"
14 "Where:\n\t"
15 "-v Validate file_contxts entries against loaded policy.\n\t"
16 "-r Use \"raw\" function.\n\t"
17 "-p Path to check for best match using the link(s) provided.\n\t"
18 "-m Optional mode (b, c, d, p, l, s or f) Defaults to 0.\n\t"
19 "-f Optional file containing the specs (defaults to\n\t"
20 " those used by loaded policy).\n\t"
21 "link Zero or more links to check against, the order of\n\t"
22 " precedence for best match is:\n\t\t"
23 " 1) An exact match for the real path (if no links), or\n\t\t"
24 " 2) An exact match for any of the links (aliases), or\n\t\t"
25 " 3) The longest fixed prefix match.\n\n"
26 "Example:\n\t"
27 "%s -p /dev/initctl /run/systemd/initctl/fifo\n\t"
28 " Find best matching context for the specified path using one link.\n\n",
29 progname, progname);
30 exit(1);
31 }
32
string_to_mode(char * s)33 static mode_t string_to_mode(char *s)
34 {
35 switch (s[0]) {
36 case 'b':
37 return S_IFBLK;
38 case 'c':
39 return S_IFCHR;
40 case 'd':
41 return S_IFDIR;
42 case 'p':
43 return S_IFIFO;
44 case 'l':
45 return S_IFLNK;
46 case 's':
47 return S_IFSOCK;
48 case 'f':
49 return S_IFREG;
50 }
51 return 0;
52 }
53
main(int argc,char ** argv)54 int main(int argc, char **argv)
55 {
56 int raw = 0, mode = 0, rc, opt, i, num_links, string_len;
57 char *validate = NULL, *path = NULL, *context = NULL, *file = NULL;
58 char **links = NULL;
59
60 struct selabel_handle *hnd;
61 struct selinux_opt options[] = {
62 { SELABEL_OPT_PATH, file },
63 { SELABEL_OPT_VALIDATE, validate }
64 };
65
66 if (argc < 3)
67 usage(argv[0]);
68
69 while ((opt = getopt(argc, argv, "f:vrp:m:")) > 0) {
70 switch (opt) {
71 case 'f':
72 file = optarg;
73 break;
74 case 'v':
75 validate = (char *)1;
76 break;
77 case 'r':
78 raw = 1;
79 break;
80 case 'p':
81 path = optarg;
82 break;
83 case 'm':
84 mode = string_to_mode(optarg);
85 break;
86 default:
87 usage(argv[0]);
88 }
89 }
90
91 /* Count links */
92 for (i = optind, num_links = 0; i < argc; i++, num_links++)
93 ;
94
95 if (num_links) {
96 links = calloc(num_links + 1, sizeof(char *));
97
98 if (!links) {
99 fprintf(stderr, "ERROR: calloc failed.\n");
100 exit(1);
101 }
102
103 for (i = optind, num_links = 0; i < argc; i++, num_links++) {
104 string_len = strlen(argv[i]) + 1;
105 links[num_links] = malloc(string_len);
106 if (!links[num_links]) {
107 fprintf(stderr, "ERROR: malloc failed.\n");
108 exit(1);
109 }
110 strcpy(links[num_links], argv[i]);
111 }
112 }
113
114 options[0].value = file;
115 options[1].value = validate;
116
117 hnd = selabel_open(SELABEL_CTX_FILE, options, 2);
118 if (!hnd) {
119 fprintf(stderr, "ERROR: selabel_open - Could not obtain "
120 "handle.\n");
121 rc = -1;
122 goto out;
123 }
124
125 if (raw)
126 rc = selabel_lookup_best_match_raw(hnd, &context, path,
127 (const char **)links, mode);
128 else
129 rc = selabel_lookup_best_match(hnd, &context, path,
130 (const char **)links, mode);
131
132 selabel_close(hnd);
133
134 if (rc) {
135 switch (errno) {
136 case ENOENT:
137 fprintf(stderr, "ERROR: selabel_lookup_best_match "
138 "failed to find a valid context.\n");
139 break;
140 case EINVAL:
141 fprintf(stderr, "ERROR: selabel_lookup_best_match "
142 "failed to validate context, or path / mode "
143 "are invalid.\n");
144 break;
145 default:
146 fprintf(stderr, "selabel_lookup_best_match ERROR: "
147 "%s\n", strerror(errno));
148 }
149 } else {
150 printf("Best match context: %s\n", context);
151 freecon(context);
152 }
153
154 out:
155 if (links) {
156 for (i = 0; links[i]; i++)
157 free(links[i]);
158 free(links);
159 }
160
161 return rc;
162 }
163