3 // AuthorizationTestTool
5 // Copyright © 2017 Apple, Inc. All rights reserved.
8 #import <Foundation/Foundation.h>
10 #define DEFAULT_DB "/System/Library/Security/authorization.plist"
11 #define START_TAG @"("
13 #define START_TAG_PLACEHOLDER @"<"
14 #define END_TAG_PLACEHOLDER @">"
16 typedef NS_ENUM(NSInteger, atOutputType)
32 otVpnEntitledAndGroup,
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);
47 NSString *itemDescription(atOutputType type, id arg)
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";
62 return [NSString stringWithFormat:@"At least %@ from the following:", arg];
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];
70 return [NSString stringWithFormat:@"Unknown item %ld", (long)type];
75 NSString *itemName(atOutputType 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";
92 return [NSString stringWithFormat:@"unknown-item-%ld", (long)type];
97 void addDataOutput(NSMutableDictionary *output, NSDictionary *content, atOutputType type, id defaultValue, Boolean writeIfNotFound)
99 id data = content[itemName(type)];
101 if (!writeIfNotFound)
105 output[[NSNumber numberWithInteger:type]] = itemDescription(type, data);
108 void processOutput(NSArray *arr, NSMutableArray *output, NSUInteger level)
110 for (id element in arr) {
111 if ([element isKindOfClass:[NSArray class]]) {
112 processOutput(element, output, level + 1);
115 [output addObject:element];
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];
122 [output addObject:[NSString stringWithFormat:@"\t%@", element]];
129 NSArray *parseRight(NSDictionary *db, NSString *name, NSUInteger level)
131 NSDictionary *content = db[@"rights"][name];
133 content = db[@"rules"][name];
137 printf("Error: Unable to find section %s\n", name.UTF8String);
141 NSString *class = content[@"class"];
143 printf("Error: Unable to get class from %s\n", name.UTF8String);
147 NSMutableDictionary *output = [NSMutableDictionary new];
148 addDataOutput(output, content, otEntitlement, nil, NO);
149 addDataOutput(output, content, otAppleSigned, nil, NO);
151 NSArray *mechanisms = nil;
152 if ([class isEqualToString:@"rule"]) {
153 addDataOutput(output, content, otKofn, nil, YES);
155 id rule = content[@"rule"];
157 if ([rule isKindOfClass:[NSString class]]) {
158 rules = [NSArray arrayWithObject:rule];
163 NSMutableArray *ruleDetails = [NSMutableArray new];
165 for(NSUInteger i = 0; i < rules.count; ++i) {
166 NSArray *result = parseRight(db, rules[i], level + 1);
168 [ruleDetails addObject:result];
171 output[[NSNumber numberWithInteger:otRules]] = ruleDetails;
172 } else if ([class isEqualToString:@"user"]) {
173 output[[NSNumber numberWithInteger:otUser]] = @"* user credentials required *";
176 addDataOutput(output, content, otRequiredGroup, nil, NO);
179 addDataOutput(output, content, otTimeout, @INT32_MAX, NO);
182 addDataOutput(output, content, otTries, @10000, NO);
184 // shared (default false)
185 addDataOutput(output, content, otShared, @NO, YES);
188 addDataOutput(output, content, otAllowRoot, @NO, NO);
191 addDataOutput(output, content, otSessionOwner, @NO, NO);
194 addDataOutput(output, content, otShowUi, @YES, YES);
197 addDataOutput(output, content, otExtractPassword, @NO, NO);
199 // entitled and group
200 addDataOutput(output, content, otEntitledAndGroup, @NO, NO);
202 // vpn entitled and group
203 addDataOutput(output, content, otVpnEntitledAndGroup, @NO, NO);
206 addDataOutput(output, content, otExtractPassword, @NO, NO);
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);
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);
223 NSMutableArray *mechanismsDetails = [NSMutableArray new];
224 if ([mechanisms isKindOfClass:[NSArray class]]) {
225 if (mechanisms.count > 1) {
226 [mechanismsDetails addObject:START_TAG_PLACEHOLDER];
228 for(NSUInteger i = 0; i < mechanisms.count; ++i) {
229 [mechanismsDetails addObject:mechanisms[i]];
231 if (mechanisms.count > 1) {
232 [mechanismsDetails addObject:END_TAG_PLACEHOLDER];
234 if (mechanismsDetails.count) {
235 output[[NSNumber numberWithInteger:otMechanismsHeader]] = @"All of the following mechanisms:";
236 output[[NSNumber numberWithInteger:otMechanisms]] = mechanismsDetails;
239 printf("Warning: rule %s - mechanisms is not an array\n", name.UTF8String);
244 output[[NSNumber numberWithInteger:otHeader]] = START_TAG_PLACEHOLDER;
245 output[[NSNumber numberWithInteger:otFooter]] = END_TAG_PLACEHOLDER;
248 NSArray *sortedKeys = [[output allKeys] sortedArrayUsingSelector: @selector(compare:)];
249 NSMutableArray *result = [NSMutableArray new];
250 processOutput([output objectsForKeys:sortedKeys notFoundMarker:@""], result, 1);
254 int main(int argc, const char * argv[])
261 file = [NSString stringWithUTF8String:argv[1]];
262 right = [NSString stringWithUTF8String:argv[2]];
263 } else if (argc == 2) {
264 right = [NSString stringWithUTF8String:argv[1]];
267 NSString *binaryName = [[NSString stringWithUTF8String:argv[0]] lastPathComponent];
268 printf("Usage: %s [right [definitions.plist]]\n", binaryName.UTF8String);
271 NSDictionary *db = [[NSDictionary alloc] initWithContentsOfFile:file];
273 printf("Error: authorization definition file %s was not found or is invalid.\n", file.UTF8String);
277 NSDictionary *rightContent = db[@"rights"][right];
279 printf("Error: right %s was not found in %s\n", right.UTF8String, file.UTF8String);
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);