aboutsummaryrefslogtreecommitdiffstats
path: root/diskdev_cmds/setclass.tproj/setclass.c
blob: 306547bdec22b1ba7f01b52785cac22fe4cc85e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
 */
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/attr.h>

/* from sys/cprotect.h */

#define PROTECTION_CLASS_A 1
#define PROTECTION_CLASS_B 2
#define PROTECTION_CLASS_C 3
#define PROTECTION_CLASS_D 4
#define PROTECTION_CLASS_E 5
#define PROTECTION_CLASS_F 6

void 
usage(void)
{
	printf("usage: setclass <path> [A-F]\n");
	printf("\tsets <path> to a protection class from A to F.\n");
	printf("\tIf no class is specified, reports the current class for <path>.\n");
	exit(0);
}

int
chartoclass(char c)
{
	switch (c) {
		/* directory 'unset' operation */
	case '0':
		return 0;
	case 'A':
	case 'a':
		return PROTECTION_CLASS_A;
	case 'B':
	case 'b':
		return PROTECTION_CLASS_B;
	case 'C':
	case 'c':
		return PROTECTION_CLASS_C;
	case 'D':
	case 'd':
		return PROTECTION_CLASS_D;
	case 'E':
	case 'e': 
		return PROTECTION_CLASS_E;
	case 'F':
	case 'f':
		return PROTECTION_CLASS_F;
	default:
		usage();
		exit(0);
	}
	return 0;
}

char
classtochar(int class)
{
	if (class < 0) {
		/* negative classes are invalid */
		return -1;
	}

	/* otherwise, it must be >= 0... */
	if (class == 0) {
		/* Directories are allowed to be "unset" */
		return 0;
	}
	return 'A' + (class - 1);
}

int 
main(int argc, char **argv)
{
	int error = 0, class = 0, do_set = 0;
	static struct attrlist req = {
		.bitmapcount = ATTR_BIT_MAP_COUNT,
		.commonattr = ATTR_CMN_DATA_PROTECT_FLAGS
	};

	if ((argc < 2) || (argc > 3))
		usage();

	if (argv[2]) {
		do_set = 1;
		class = chartoclass(*argv[2]);
	}

	/*
	 * setclass and getclass for `argv[1]` using setattrlist(2) and
	 * getattrlist(2) respectively.
	 */
	if (do_set) {
		struct {
			uint32_t prot_class;
		} __attribute__((packed, aligned(4))) attrs = {
			.prot_class = class
		};

		error = setattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
							 FSOPT_NOFOLLOW);
		if (error) {
			char new_class = classtochar(class);
			if (new_class == 0) {
				warn("could not set protection class of %s to (directory none)",
					 argv[1]);
			}
			else {
				warn("could not set protection class of %s to %c", argv[1],
					 new_class);
			}
		}
	}
	else {
		req.commonattr |= ATTR_CMN_RETURNED_ATTRS;

		struct {
			uint32_t len;
			attribute_set_t returned;
			uint32_t prot_class;
		} __attribute__((packed, aligned(4))) attrs;

		error = getattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
							 FSOPT_NOFOLLOW);
		if (error == -1 || attrs.len != sizeof(attrs) ||
			attrs.returned.commonattr != req.commonattr) {
			if (error == -1) {
				error = errno;
			}
			else {
				error = EINVAL;
			}
			err(error, "could not get protection class");
		}
		else {
			class = attrs.prot_class;
			char new_class = classtochar(class);
			if (new_class == 0) {
				printf("%s is in protection class (directory none) \n", argv[1]);
			}
			else {
				printf("%s is in protection class %c\n", argv[1], new_class);
			}
		}
	}

	return error;
}