]> git.saurik.com Git - apple/security.git/blob - OSX/authorizationdump/main.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / authorizationdump / main.m
1 //
2 // main.m
3 // AuthorizationTestTool
4 //
5 // Copyright © 2017 Apple, Inc. All rights reserved.
6 //
7
8 #import <Foundation/Foundation.h>
9
10 #define DEFAULT_DB "/System/Library/Security/authorization.plist"
11 #define START_TAG @"("
12 #define END_TAG @")"
13 #define START_TAG_PLACEHOLDER @"<"
14 #define END_TAG_PLACEHOLDER @">"
15
16 typedef NS_ENUM(NSInteger, atOutputType)
17 {
18 otHeader,
19 otUser,
20 otTries,
21 otShared,
22 otTimeout,
23 otShowUi,
24 otRequiredGroup,
25 otEntitlement,
26 otAllowRoot,
27 otSessionOwner,
28 otAllow,
29 otDeny,
30 otExtractPassword,
31 otEntitledAndGroup,
32 otVpnEntitledAndGroup,
33 otAppleSigned,
34 otKofn,
35 otRules,
36 otMechanismsHeader,
37 otMechanisms,
38 otFooter,
39 };
40
41 NSString *itemDescription(atOutputType type, id arg);
42 NSString *itemName(atOutputType type);
43 void addDataOutput(NSMutableDictionary *output, NSDictionary *content, atOutputType type, id defaultValue, Boolean writeIfNotFound);
44 void processOutput(NSArray *input, NSMutableArray *output, NSUInteger level);
45 NSArray *parseRight(NSDictionary *db, NSString *name, NSUInteger level);
46
47 NSString *itemDescription(atOutputType type, id arg)
48 {
49 switch (type){
50 case otTries: return [NSString stringWithFormat:@"Tries: %@", arg];
51 case otShared: return [NSString stringWithFormat:@"Shared: %@", arg];
52 case otTimeout: return [NSString stringWithFormat:@"Timeout: %@", arg];
53 case otShowUi: return [NSString stringWithFormat:@"Show UI if necessary: %@", arg];
54 case otRequiredGroup: return [NSString stringWithFormat:@"Require user from group: %@", arg];
55 case otEntitlement: return [NSString stringWithFormat:@"Require entitlement: %@", arg];
56 case otAllowRoot: return [NSString stringWithFormat:@"Auto-allow if caller process is root: %@", arg];
57 case otSessionOwner: return [NSString stringWithFormat:@"Session owner required: %@", arg];
58 case otAllow: return @"Always allowed";
59 case otDeny: return @"Always denied";
60 case otKofn:
61 if (arg)
62 return [NSString stringWithFormat:@"At least %@ from the following:", arg];
63 else
64 return [NSString stringWithFormat:@"All from following:"];
65 case otExtractPassword: return [NSString stringWithFormat:@"Extractable password: %@", arg];
66 case otEntitledAndGroup: return [NSString stringWithFormat:@"Entitled and group: %@", arg];
67 case otVpnEntitledAndGroup: return [NSString stringWithFormat:@"VPN entitled and group: %@", arg];
68 case otAppleSigned: return [NSString stringWithFormat:@"Requires Apple signature: %@", arg];
69 default:
70 return [NSString stringWithFormat:@"Unknown item %ld", (long)type];
71 }
72 return nil;
73 }
74
75 NSString *itemName(atOutputType type)
76 {
77 switch (type){
78 case otTries: return @"tries";
79 case otShared: return @"shared";
80 case otTimeout: return @"timeout";
81 case otShowUi: return @"authenticate-user";
82 case otRequiredGroup: return @"group";
83 case otAllowRoot: return @"allow-root";
84 case otSessionOwner: return @"session-owner";
85 case otExtractPassword: return @"extract-password";
86 case otEntitledAndGroup: return @"entitled-group";
87 case otVpnEntitledAndGroup: return @"vpn-entitled-group";
88 case otAppleSigned: return @"require-apple-signed";
89 case otKofn: return @"k-of-n";
90 case otMechanisms: return @"mechanism";
91 default:
92 return [NSString stringWithFormat:@"unknown-item-%ld", (long)type];
93 }
94 return nil;
95 }
96
97 void addDataOutput(NSMutableDictionary *output, NSDictionary *content, atOutputType type, id defaultValue, Boolean writeIfNotFound)
98 {
99 id data = content[itemName(type)];
100 if (data == nil) {
101 if (!writeIfNotFound)
102 return;
103 data = defaultValue;
104 }
105 output[[NSNumber numberWithInteger:type]] = itemDescription(type, data);
106 }
107
108 void processOutput(NSArray *arr, NSMutableArray *output, NSUInteger level)
109 {
110 for (id element in arr) {
111 if ([element isKindOfClass:[NSArray class]]) {
112 processOutput(element, output, level + 1);
113 } else {
114 if (level == 1) {
115 [output addObject:element];
116 } else {
117 if ([START_TAG_PLACEHOLDER isEqualToString:element]){
118 [output addObject:START_TAG];
119 } else if ([END_TAG_PLACEHOLDER isEqualToString:element]){
120 [output addObject:END_TAG];
121 } else {
122 [output addObject:[NSString stringWithFormat:@"\t%@", element]];
123 }
124 }
125 }
126 }
127 }
128
129 NSArray *parseRight(NSDictionary *db, NSString *name, NSUInteger level)
130 {
131 NSDictionary *content = db[@"rights"][name];
132 if (!content) {
133 content = db[@"rules"][name];
134 }
135
136 if (!content) {
137 printf("Error: Unable to find section %s\n", name.UTF8String);
138 return 0;
139 }
140
141 NSString *class = content[@"class"];
142 if (!class) {
143 printf("Error: Unable to get class from %s\n", name.UTF8String);
144 return 0;
145 }
146
147 NSMutableDictionary *output = [NSMutableDictionary new];
148 addDataOutput(output, content, otEntitlement, nil, NO);
149 addDataOutput(output, content, otAppleSigned, nil, NO);
150
151 NSArray *mechanisms = nil;
152 if ([class isEqualToString:@"rule"]) {
153 addDataOutput(output, content, otKofn, nil, YES);
154
155 id rule = content[@"rule"];
156 NSArray *rules;
157 if ([rule isKindOfClass:[NSString class]]) {
158 rules = [NSArray arrayWithObject:rule];
159 } else {
160 rules = rule;
161 }
162
163 NSMutableArray *ruleDetails = [NSMutableArray new];
164
165 for(NSUInteger i = 0; i < rules.count; ++i) {
166 NSArray *result = parseRight(db, rules[i], level + 1);
167 if (result) {
168 [ruleDetails addObject:result];
169 }
170 }
171 output[[NSNumber numberWithInteger:otRules]] = ruleDetails;
172 } else if ([class isEqualToString:@"user"]) {
173 output[[NSNumber numberWithInteger:otUser]] = @"* user credentials required *";
174
175 // group
176 addDataOutput(output, content, otRequiredGroup, nil, NO);
177
178 // timeout
179 addDataOutput(output, content, otTimeout, @INT32_MAX, NO);
180
181 // tries
182 addDataOutput(output, content, otTries, @10000, NO);
183
184 // shared (default false)
185 addDataOutput(output, content, otShared, @NO, YES);
186
187 // allow-root
188 addDataOutput(output, content, otAllowRoot, @NO, NO);
189
190 // session owner
191 addDataOutput(output, content, otSessionOwner, @NO, NO);
192
193 // show ui
194 addDataOutput(output, content, otShowUi, @YES, YES);
195
196 // extract password
197 addDataOutput(output, content, otExtractPassword, @NO, NO);
198
199 // entitled and group
200 addDataOutput(output, content, otEntitledAndGroup, @NO, NO);
201
202 // vpn entitled and group
203 addDataOutput(output, content, otVpnEntitledAndGroup, @NO, NO);
204
205 // password only
206 addDataOutput(output, content, otExtractPassword, @NO, NO);
207
208 // mechanisms
209 mechanisms = content[@"mechanisms"];
210 } else if ([class isEqualToString:@"evaluate-mechanisms"]) {
211 addDataOutput(output, content, otShared, @YES, YES);
212 addDataOutput(output, content, otExtractPassword, @NO, NO);
213
214 // mechanisms
215 mechanisms = content[@"mechanisms"];
216 } else if ([class isEqualToString:@"allow"]) {
217 addDataOutput(output, content, otAllow, nil, YES);
218 } else if ([class isEqualToString:@"deny"]) {
219 addDataOutput(output, content, otDeny, nil, YES);
220 }
221
222 if (mechanisms) {
223 NSMutableArray *mechanismsDetails = [NSMutableArray new];
224 if ([mechanisms isKindOfClass:[NSArray class]]) {
225 if (mechanisms.count > 1) {
226 [mechanismsDetails addObject:START_TAG_PLACEHOLDER];
227 }
228 for(NSUInteger i = 0; i < mechanisms.count; ++i) {
229 [mechanismsDetails addObject:mechanisms[i]];
230 }
231 if (mechanisms.count > 1) {
232 [mechanismsDetails addObject:END_TAG_PLACEHOLDER];
233 }
234 if (mechanismsDetails.count) {
235 output[[NSNumber numberWithInteger:otMechanismsHeader]] = @"All of the following mechanisms:";
236 output[[NSNumber numberWithInteger:otMechanisms]] = mechanismsDetails;
237 }
238 } else {
239 printf("Warning: rule %s - mechanisms is not an array\n", name.UTF8String);
240 }
241 }
242
243 if (level > 1) {
244 output[[NSNumber numberWithInteger:otHeader]] = START_TAG_PLACEHOLDER;
245 output[[NSNumber numberWithInteger:otFooter]] = END_TAG_PLACEHOLDER;
246 }
247
248 NSArray *sortedKeys = [[output allKeys] sortedArrayUsingSelector: @selector(compare:)];
249 NSMutableArray *result = [NSMutableArray new];
250 processOutput([output objectsForKeys:sortedKeys notFoundMarker:@""], result, 1);
251 return result;
252 }
253
254 int main(int argc, const char * argv[])
255 {
256 @autoreleasepool {
257
258 NSString *file;
259 NSString *right;
260 if (argc > 2) {
261 file = [NSString stringWithUTF8String:argv[1]];
262 right = [NSString stringWithUTF8String:argv[2]];
263 } else if (argc == 2) {
264 right = [NSString stringWithUTF8String:argv[1]];
265 file = @DEFAULT_DB;
266 } else {
267 NSString *binaryName = [[NSString stringWithUTF8String:argv[0]] lastPathComponent];
268 printf("Usage: %s [right [definitions.plist]]\n", binaryName.UTF8String);
269 exit(-1);
270 }
271 NSDictionary *db = [[NSDictionary alloc] initWithContentsOfFile:file];
272 if (!db) {
273 printf("Error: authorization definition file %s was not found or is invalid.\n", file.UTF8String);
274 exit(-1);
275 }
276
277 NSDictionary *rightContent = db[@"rights"][right];
278 if (!rightContent) {
279 printf("Error: right %s was not found in %s\n", right.UTF8String, file.UTF8String);
280 exit(-1);
281 }
282
283 NSArray *result = parseRight(db, right, 1);
284 printf("Authorization right %s\n", right.UTF8String);
285 for (NSString *line in result) {
286 printf("%s\n", line.UTF8String);
287 }
288 }
289 return 0;
290 }