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 17 static __attribute__((__noreturn__)) 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 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