1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <sys/xattr.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <selinux/selinux.h>
12 #include <selinux/label.h>
13 #include <selinux/restorecon.h>
14
15 #include "restore.h"
16
usage(const char * progname)17 static void usage(const char *progname)
18 {
19 fprintf(stderr,
20 "\nusage: %s [-vnrmdD] [-e directory] [-f specfile] pathname\n"
21 "\nWhere:\n\t"
22 "-v Display digest generated by specfile set.\n\t"
23 "-n Do not append \"Match\" or \"No Match\" to displayed digests.\n\t"
24 "-r Recursively descend directories.\n\t"
25 "-m Do not read /proc/mounts for entries to be excluded.\n\t"
26 "-d Delete non-matching digest entries.\n\t"
27 "-D Delete all digest entries.\n\t"
28 "-e Directory to exclude (repeat option for more than one directory).\n\t"
29 "-f Optional specfile for calculating the digest.\n\t"
30 "pathname Path to search for xattr \"security.restorecon_last\" entries.\n\n",
31 progname);
32 exit(-1);
33 }
34
main(int argc,char ** argv)35 int main(int argc, char **argv)
36 {
37 int opt, rc;
38 unsigned int xattr_flags = 0, delete_digest = 0, recurse = 0;
39 unsigned int delete_all_digests = 0, ignore_mounts = 0;
40 bool display_digest = false;
41 char *sha1_buf, **specfiles, *fc_file = NULL;
42 unsigned char *fc_digest = NULL;
43 size_t i, fc_digest_len = 0, num_specfiles;
44
45 struct stat sb;
46 struct selabel_handle *hnd = NULL;
47 struct dir_xattr *current, *next, **xattr_list = NULL;
48
49 bool no_comment = true;
50
51 if (argc < 2)
52 usage(argv[0]);
53
54 if (is_selinux_enabled() <= 0) {
55 fprintf(stderr,
56 "SELinux must be enabled to perform this operation.\n");
57 exit(-1);
58 }
59
60 exclude_list = NULL;
61
62 while ((opt = getopt(argc, argv, "vnrmdDe:f:")) > 0) {
63 switch (opt) {
64 case 'v':
65 display_digest = true;
66 break;
67 case 'n':
68 no_comment = false;
69 break;
70 case 'r':
71 recurse = SELINUX_RESTORECON_XATTR_RECURSE;
72 break;
73 case 'm':
74 ignore_mounts = SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS;
75 break;
76 case 'd':
77 delete_digest =
78 SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS;
79 break;
80 case 'D':
81 delete_all_digests =
82 SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS;
83 break;
84 case 'e':
85 if (lstat(optarg, &sb) < 0 && errno != EACCES) {
86 fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n",
87 optarg, strerror(errno));
88 break;
89 }
90 add_exclude(optarg);
91 break;
92 case 'f':
93 fc_file = optarg;
94 break;
95 default:
96 usage(argv[0]);
97 }
98 }
99
100 if (optind >= argc) {
101 fprintf(stderr, "No pathname specified\n");
102 exit(-1);
103 }
104
105 struct selinux_opt selinux_opts[] = {
106 { SELABEL_OPT_PATH, fc_file },
107 { SELABEL_OPT_DIGEST, (char *)1 }
108 };
109
110 hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2);
111 if (!hnd) {
112 switch (errno) {
113 case EOVERFLOW:
114 fprintf(stderr, "Error: Number of specfiles or"
115 " specfile buffer caused an overflow.\n");
116 break;
117 default:
118 fprintf(stderr, "Error: selabel_open: %s\n",
119 strerror(errno));
120 }
121 exit(-1);
122 }
123
124 /* Use own handle as need to allow different file_contexts. */
125 selinux_restorecon_set_sehandle(hnd);
126
127 if (display_digest) {
128 if (selabel_digest(hnd, &fc_digest, &fc_digest_len,
129 &specfiles, &num_specfiles) < 0) {
130 fprintf(stderr,
131 "Error: selabel_digest: Digest not available.\n");
132 selabel_close(hnd);
133 exit(-1);
134 }
135
136 sha1_buf = malloc(fc_digest_len * 2 + 1);
137 if (!sha1_buf) {
138 fprintf(stderr,
139 "Error allocating digest buffer: %s\n",
140 strerror(errno));
141 selabel_close(hnd);
142 exit(-1);
143 }
144
145 for (i = 0; i < fc_digest_len; i++)
146 sprintf((&sha1_buf[i * 2]), "%02x", fc_digest[i]);
147
148 printf("specfiles SHA1 digest: %s\n", sha1_buf);
149
150 printf("calculated using the following specfile(s):\n");
151 if (specfiles) {
152 for (i = 0; i < num_specfiles; i++)
153 printf("%s\n", specfiles[i]);
154 }
155 free(sha1_buf);
156 printf("\n");
157 }
158
159 if (exclude_list)
160 selinux_restorecon_set_exclude_list
161 ((const char **)exclude_list);
162
163 xattr_flags = delete_digest | delete_all_digests |
164 ignore_mounts | recurse;
165
166 if (selinux_restorecon_xattr(argv[optind], xattr_flags, &xattr_list)) {
167 fprintf(stderr,
168 "Error selinux_restorecon_xattr: %s\n",
169 strerror(errno));
170 rc = -1;
171 goto out;
172 }
173
174 if (xattr_list) {
175 current = *xattr_list;
176 while (current) {
177 next = current->next;
178 printf("%s ", current->directory);
179
180 switch (current->result) {
181 case MATCH:
182 printf("Digest: %s%s", current->digest,
183 no_comment ? " Match\n" : "\n");
184 break;
185 case NOMATCH:
186 printf("Digest: %s%s", current->digest,
187 no_comment ? " No Match\n" : "\n");
188 break;
189 case DELETED_MATCH:
190 printf("Deleted Digest: %s%s", current->digest,
191 no_comment ? " Match\n" : "\n");
192 break;
193 case DELETED_NOMATCH:
194 printf("Deleted Digest: %s%s",
195 current->digest,
196 no_comment ? " No Match\n" : "\n");
197 break;
198 case ERROR:
199 printf("Digest: %s Error removing xattr\n",
200 current->digest);
201 break;
202 }
203 current = next;
204 }
205 /* Free memory */
206 current = *xattr_list;
207 while (current) {
208 next = current->next;
209 free(current->directory);
210 free(current->digest);
211 free(current);
212 current = next;
213 }
214 }
215
216 rc = 0;
217 out:
218 selabel_close(hnd);
219 restore_finish();
220 return rc;
221 }
222