]> git.saurik.com Git - apple/security.git/blob - OSX/authd/tests/authdtests.m
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / authd / tests / authdtests.m
1 //
2 // authdtests.m
3 //
4 //
5
6 #import <Security/Authorization.h>
7 #import <Security/AuthorizationPriv.h>
8 #import <Security/AuthorizationDB.h>
9 #import <Security/AuthorizationTagsPriv.h>
10 #import <Foundation/Foundation.h>
11 #import "authd/debugging.h"
12 #import "authdtestlist.h"
13
14 void runRaft(NSString *arguments);
15 int authd_03_uiauthorization(int argc, char *const *argv);
16 bool getCredentials(void);
17
18 #define AuthorizationFreeItemSetNull(IS) { AuthorizationItemSet *_is = (IS); \
19 if (_is) { (IS) = NULL; AuthorizationFreeItemSet(_is); } }
20
21 #define SAMPLE_RIGHT "com.apple.security.syntheticinput"
22 #define SAMPLE_SHARED_RIGHT "system.preferences"
23 #define SAMPLE_PASSWORD_RIGHT "system.csfde.requestpassword"
24
25 NSString *correctUsername;
26 NSString *correctPassword;
27
28 #define INCORRECT_UNAME "fs;lgp-984-25opsdakflasdg"
29 #define INCORRECT_PWD "654sa65gsqihr6hhsfd'lbo[0q2,m23-odasdf"
30
31 #define SA_TIMEOUT (20)
32
33 #define RAFT_FILL @"target.processes()[\"SecurityAgent\"].mainWindow().textFields()[\"User Name:\"].click();keyboard.typeString_withModifiersMask_(\"a\", (kUIACommandKeyMask));keyboard.typeVirtualKey_(117);keyboard.typeString_(\"%s\");target.processes()[\"SecurityAgent\"].mainWindow().textFields()[\"Password:\"].click();keyboard.typeString_withModifiersMask_(\"a\", (kUIACommandKeyMask));keyboard.typeVirtualKey_(117);keyboard.typeString_(\"%s\");target.processes()[\"SecurityAgent\"].mainWindow().buttons()[\"OK\"].click();quit();"
34
35 #define RAFT_CANCEL @"target.processes()[\"SecurityAgent\"].mainWindow().buttons()[\"Cancel\"].click();quit();"
36
37 AuthorizationItem validCredentials[] = {
38 {AGENT_USERNAME, 0, NULL, 0},
39 {AGENT_PASSWORD, 0, NULL, 0}
40 };
41
42 AuthorizationItem invalidCredentials[] = {
43 {AGENT_USERNAME, strlen(INCORRECT_UNAME), (void *)INCORRECT_UNAME, 0},
44 {AGENT_PASSWORD, strlen(INCORRECT_PWD), (void *)INCORRECT_PWD,0}
45 };
46
47 bool getCredentials()
48 {
49 static dispatch_once_t onceToken = 0;
50 dispatch_once(&onceToken, ^{
51 NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:@"/etc/credentials.plist"];
52 correctUsername = dict[@"username"];
53 correctPassword = dict[@"password"];
54 if (correctUsername) {
55 validCredentials[0].value = (void *)correctUsername.UTF8String;
56 if (validCredentials[0].value) {
57 validCredentials[0].valueLength = strlen(correctUsername.UTF8String);
58 }
59 }
60 if (correctPassword) {
61 validCredentials[1].value = (void *)correctPassword.UTF8String;
62 if (validCredentials[1].value) {
63 validCredentials[1].valueLength = strlen(correctPassword.UTF8String);
64 }
65 }
66 });
67 return (correctUsername != nil) && (correctPassword != nil);
68 }
69
70 void runRaft(NSString *arguments)
71 {
72 NSTask *task = [[NSTask alloc] init];
73 [task setLaunchPath:@"/usr/local/bin/raft"];
74 [task setArguments:@[ @"-b", @"-o", arguments]];
75 [task launch];
76 [task waitUntilExit];
77 }
78
79 int authd_01_authorizationdb(int argc, char *const *argv)
80 {
81 plan_tests(2);
82
83 CFDictionaryRef outDict = NULL;
84 OSStatus status = AuthorizationRightGet(SAMPLE_RIGHT, &outDict);
85 ok(status == errAuthorizationSuccess, "AuthorizationRightGet existing right");
86 CFReleaseNull(outDict);
87
88 status = AuthorizationRightGet("non-existing-right", &outDict);
89 ok(status == errAuthorizationDenied, "AuthorizationRightGet non-existing right");
90
91 return 0;
92 }
93
94 int authd_02_basicauthorization(int argc, char *const *argv)
95 {
96 plan_tests(6);
97 if (!getCredentials()) {
98 fail("Not able to read credentials for current user!");
99 }
100
101 AuthorizationRef authorizationRef;
102
103 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
104 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
105
106 AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0};
107 AuthorizationRights myRights = {1, &myItems};
108 AuthorizationRights *authorizedRights = NULL;
109 AuthorizationEnvironment environment = {sizeof(validCredentials)/sizeof(AuthorizationItem), validCredentials};
110 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagDefaults, &authorizedRights);
111 ok(status == errAuthorizationDenied, "Standard authorization without kAuthorizationFlagExtendRights");
112 AuthorizationFreeItemSetNull(authorizedRights);
113
114 status = AuthorizationCopyRights(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights, &authorizedRights);
115 ok(status == errAuthorizationInteractionNotAllowed, "Authorization fail with UI not allowed");
116 AuthorizationFreeItemSetNull(authorizedRights);
117
118 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
119 ok(status == errAuthorizationSuccess, "Standard authorization");
120 AuthorizationFreeItemSetNull(authorizedRights);
121
122 AuthorizationItem extendedItems = {SAMPLE_SHARED_RIGHT, 0, NULL, 0};
123 AuthorizationRights extendedRights = {1, &extendedItems};
124
125 status = AuthorizationCopyRights(authorizationRef, &extendedRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
126 ok(status == errAuthorizationSuccess, "Extending authorization rights");
127 AuthorizationFreeItemSetNull(authorizedRights);
128
129 AuthorizationItem pwdExtractItems = {SAMPLE_PASSWORD_RIGHT, 0, NULL, 0};
130 AuthorizationRights pwdExtractRight = {1, &pwdExtractItems};
131
132 // check that non-entitled process cannot extract password from AuthorizationRef
133 status = AuthorizationCopyRights(authorizationRef, &pwdExtractRight, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
134 Boolean passwordFound = false;
135 if (status == errAuthorizationSuccess) {
136 AuthorizationItemSet *returnedInfo;
137 status = AuthorizationCopyInfo(authorizationRef, NULL, &returnedInfo);
138 if (status == errSecSuccess && returnedInfo) {
139 for (uint32_t index = 0; index < returnedInfo->count; ++index) {
140 AuthorizationItem item = returnedInfo->items[index];
141 if (strncpy((char *)item.name, kAuthorizationEnvironmentPassword, strlen(kAuthorizationEnvironmentPassword)) == 0) {
142 passwordFound = true;
143 }
144 }
145 AuthorizationFreeItemSetNull(returnedInfo);
146 }
147 }
148
149 ok(status == errAuthorizationSuccess && passwordFound == false, "Extracting password from AuthorizationRef");
150 AuthorizationFreeItemSetNull(authorizedRights);
151
152
153 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
154 return 0;
155 }
156
157 int authd_03_uiauthorization(int argc, char *const *argv)
158 {
159 plan_tests(3);
160 if (!getCredentials()) {
161 fail("Not able to read credentials for current user!");
162 }
163
164 AuthorizationRef authorizationRef;
165
166 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
167 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
168
169 AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0};
170 AuthorizationRights myRights = {1, &myItems};
171
172 NSString *raftFillValid = [NSString stringWithFormat:RAFT_FILL, correctUsername.UTF8String, correctPassword.UTF8String];
173
174 dispatch_semaphore_t sem = dispatch_semaphore_create(0);
175 /*
176 AuthorizationAsyncCallback internalBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
177 AuthorizationFreeItemSetNull(blockAuthorizedRights);
178 ok(err == errAuthorizationInternal, "Async authorization interal error");
179 dispatch_semaphore_signal(sem);
180 };
181 AuthorizationAsyncCallback denyBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
182 AuthorizationFreeItemSetNull(blockAuthorizedRights);
183 ok(err == errAuthorizationDenied, "Async authorization denial");
184 dispatch_semaphore_signal(sem);
185 };*/
186 AuthorizationAsyncCallback allowBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
187 AuthorizationFreeItemSetNull(blockAuthorizedRights);
188 ok(err == errAuthorizationSuccess, "Async authorization");
189 dispatch_semaphore_signal(sem);
190 };
191 AuthorizationAsyncCallback cancelBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
192 AuthorizationFreeItemSetNull(blockAuthorizedRights);
193 ok(err == errAuthorizationCanceled, "Async authorization cancel");
194 dispatch_semaphore_signal(sem);
195 };
196 AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, cancelBlock);
197 sleep(3); // give some time to SecurityAgent to appear
198 runRaft(RAFT_CANCEL);
199 if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) {
200 fail("Async authorization cancel");
201 }
202 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
203
204 AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, allowBlock);
205 sleep(3); // give some time to SecurityAgent to appear
206 runRaft(raftFillValid);
207 if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) {
208 fail("Async authorization");
209 } AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
210
211 return 0;
212 }
213
214 int authd_04_executewithprivileges(int argc, char *const *argv)
215 {
216 const int NUMBER_OF_ITERATIONS = 10;
217 plan_tests(2 + 4 * NUMBER_OF_ITERATIONS);
218
219 if (!getCredentials()) {
220 fail("Not able to read credentials for current user!");
221 }
222
223 AuthorizationRef authorizationRef;
224 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
225 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
226
227 AuthorizationItem myItems = { kAuthorizationRightExecute, 0, NULL, 0};
228 AuthorizationRights myRights = {1, &myItems};
229 AuthorizationRights *authorizedRights = NULL;
230 AuthorizationEnvironment environment = {sizeof(validCredentials)/sizeof(AuthorizationItem), validCredentials};
231 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
232 ok(status == errAuthorizationSuccess, "Standard authorization");
233 AuthorizationFreeItemSetNull(authorizedRights);
234
235 for (int i = 0; i < NUMBER_OF_ITERATIONS; ++i) {
236 NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
237 static const char *toolArgv[3];
238 NSString *arg = [NSString stringWithFormat:@"%s %@", "/usr/bin/whoami && /bin/echo", guid];
239 NSString *expected = [NSString stringWithFormat:@"root\n%@", guid];
240 toolArgv[0] = "-c";
241 toolArgv[1] = arg.UTF8String;
242 toolArgv[2] = NULL;
243 FILE *output = NULL;
244
245 status = AuthorizationExecuteWithPrivileges(authorizationRef, "/bin/zsh", 0, (char *const *)toolArgv, &output);
246 ok(status == errAuthorizationSuccess, "AuthorizationExecuteWithPrivileges call succeess");
247
248 if (status != 0) {
249 break;
250 }
251
252 char buffer[1024];
253 size_t bytesRead = 0;
254 size_t totalBytesRead = 0;
255 size_t buffSize = sizeof(buffer);
256 memset(buffer, 0, buffSize);
257 while ((bytesRead = fread (buffer, 1, buffSize, output) > 0)) {
258 totalBytesRead += bytesRead; // overwriting buffer is OK since we are reading just a small amount of data
259 }
260
261 ok(ferror(output) == 0, "Authorized tool pipe closed did not end with ferror");
262 if (ferror(output)) {
263 // test failed, ferror happened
264 fclose(output);
265 return 0;
266 }
267
268 ok(feof(output), "Authorized tool pipe closed with feof");
269 if (!feof(output)) {
270 // test failed, feof not happened
271 fclose(output);
272 return 0;
273 }
274
275 fclose(output);
276 if (strncmp(buffer, expected.UTF8String, guid.length) == 0) {
277 pass("Authorized tool output matches");
278 } else {
279 fail("AuthorizationExecuteWithPrivileges output %s does not match %s", buffer, expected.UTF8String);
280 }
281 }
282
283 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
284 return 0;
285 }
286
287 int authd_05_rightproperties(int argc, char *const *argv)
288 {
289 plan_tests(5);
290
291 NSDictionary *properties;
292 CFDictionaryRef cfProperties;
293 NSString *group;
294 NSNumber *passwordOnly;
295
296 OSStatus status = AuthorizationCopyRightProperties("system.csfde.requestpassword", &cfProperties);
297 properties = CFBridgingRelease(cfProperties);
298 if (status != errAuthorizationSuccess) {
299 fail("AuthorizationCopyRightProperties failed with %d", (int)status);
300 goto done;
301 }
302
303 pass("AuthorizationCopyRightProperties call succeess");
304 passwordOnly = properties[@(kAuthorizationRuleParameterPasswordOnly)];
305 ok(passwordOnly.boolValue, "Returned system.csfde.requestpassword as password only right");
306 group = properties[@(kAuthorizationRuleParameterGroup)];
307 ok([group isEqualToString:@"admin"], "Returned admin as a required group for system.csfde.requestpassword");
308
309 status = AuthorizationCopyRightProperties("com.apple.Safari.allow-unsigned-app-extensions", &cfProperties);
310 properties = CFBridgingRelease(cfProperties);
311 if (status != errAuthorizationSuccess) {
312 fail("AuthorizationCopyRightProperties failed with %d", (int)status);
313 goto done;
314 }
315 group = properties[@(kAuthorizationRuleParameterGroup)];
316 passwordOnly = properties[@(kAuthorizationRuleParameterPasswordOnly)];
317 ok(group.length == 0 && passwordOnly.boolValue == NO, "Returned safari right as non-password only, no specific group");
318
319 status = AuthorizationCopyRightProperties("non-existing-right", &cfProperties);
320 ok(status == errAuthorizationSuccess, "Returned success for default for unknown right: %d", (int)status);
321
322 done:
323 return 0;
324 }