Home | History | Annotate | Download | only in setfiles
      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