xref: /aosp_15_r20/external/selinux/libselinux/utils/selabel_lookup_best_match.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
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