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(const char * s)33 static mode_t string_to_mode(const 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;
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 links[num_links] = strdup(argv[i]);
105 if (!links[num_links]) {
106 fprintf(stderr, "ERROR: strdup failed.\n");
107 exit(1);
108 }
109 }
110 }
111
112 options[0].value = file;
113 options[1].value = validate;
114
115 hnd = selabel_open(SELABEL_CTX_FILE, options, 2);
116 if (!hnd) {
117 fprintf(stderr, "ERROR: selabel_open - Could not obtain "
118 "handle: %s\n",
119 strerror(errno));
120 rc = -1;
121 goto out;
122 }
123
124 if (raw)
125 rc = selabel_lookup_best_match_raw(hnd, &context, path,
126 (const char **)links, mode);
127 else
128 rc = selabel_lookup_best_match(hnd, &context, path,
129 (const char **)links, mode);
130
131 selabel_close(hnd);
132
133 if (rc) {
134 switch (errno) {
135 case ENOENT:
136 fprintf(stderr, "ERROR: selabel_lookup_best_match "
137 "failed to find a valid context.\n");
138 break;
139 case EINVAL:
140 fprintf(stderr, "ERROR: selabel_lookup_best_match "
141 "failed to validate context, or path / mode "
142 "are invalid.\n");
143 break;
144 default:
145 fprintf(stderr, "selabel_lookup_best_match ERROR: "
146 "%s\n", strerror(errno));
147 }
148 } else {
149 printf("Best match context: %s\n", context);
150 freecon(context);
151 }
152
153 out:
154 if (links) {
155 for (i = 0; links[i]; i++)
156 free(links[i]);
157 free(links);
158 }
159
160 return rc;
161 }
162