6 #import <Security/Authorization.h>
7 #import <Security/AuthorizationDB.h>
8 #import <Security/AuthorizationTagsPriv.h>
9 #import <Foundation/Foundation.h>
10 #import "authd/debugging.h"
11 #import "authdtestlist.h"
13 void runRaft(NSString *arguments);
14 int authd_03_uiauthorization(int argc, char *const *argv);
15 bool getCredentials(void);
17 #define AuthorizationFreeItemSetNull(IS) { AuthorizationItemSet *_is = (IS); \
18 if (_is) { (IS) = NULL; AuthorizationFreeItemSet(_is); } }
20 #define SAMPLE_RIGHT "com.apple.security.syntheticinput"
21 #define SAMPLE_SHARED_RIGHT "system.preferences"
22 #define SAMPLE_PASSWORD_RIGHT "system.csfde.requestpassword"
24 NSString *correctUsername;
25 NSString *correctPassword;
27 #define INCORRECT_UNAME "fs;lgp-984-25opsdakflasdg"
28 #define INCORRECT_PWD "654sa65gsqihr6hhsfd'lbo[0q2,m23-odasdf"
30 #define SA_TIMEOUT (20)
32 #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 #define RAFT_CANCEL @"target.processes()[\"SecurityAgent\"].mainWindow().buttons()[\"Cancel\"].click();quit();"
36 AuthorizationItem validCredentials[] = {
37 {AGENT_USERNAME, 0, NULL, 0},
38 {AGENT_PASSWORD, 0, NULL, 0}
41 AuthorizationItem invalidCredentials[] = {
42 {AGENT_USERNAME, strlen(INCORRECT_UNAME), (void *)INCORRECT_UNAME, 0},
43 {AGENT_PASSWORD, strlen(INCORRECT_PWD), (void *)INCORRECT_PWD,0}
48 static dispatch_once_t onceToken = 0;
49 dispatch_once(&onceToken, ^{
50 NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:@"/etc/credentials.plist"];
51 correctUsername = dict[@"username"];
52 correctPassword = dict[@"password"];
53 if (correctUsername) {
54 validCredentials[0].value = (void *)correctUsername.UTF8String;
55 if (validCredentials[0].value) {
56 validCredentials[0].valueLength = strlen(correctUsername.UTF8String);
59 if (correctPassword) {
60 validCredentials[1].value = (void *)correctPassword.UTF8String;
61 if (validCredentials[1].value) {
62 validCredentials[1].valueLength = strlen(correctPassword.UTF8String);
66 return (correctUsername != nil) && (correctPassword != nil);
69 void runRaft(NSString *arguments)
71 NSTask *task = [[NSTask alloc] init];
72 [task setLaunchPath:@"/usr/local/bin/raft"];
73 [task setArguments:@[ @"-b", @"-o", arguments]];
78 int authd_01_authorizationdb(int argc, char *const *argv)
82 CFDictionaryRef outDict = NULL;
83 OSStatus status = AuthorizationRightGet(SAMPLE_RIGHT, &outDict);
84 ok(status == errAuthorizationSuccess, "AuthorizationRightGet existing right");
85 CFReleaseNull(outDict);
87 status = AuthorizationRightGet("non-existing-right", &outDict);
88 ok(status == errAuthorizationDenied, "AuthorizationRightGet non-existing right");
93 int authd_02_basicauthorization(int argc, char *const *argv)
96 if (!getCredentials()) {
97 fail("Not able to read credentials for current user!");
100 AuthorizationRef authorizationRef;
102 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
103 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
105 AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0};
106 AuthorizationRights myRights = {1, &myItems};
107 AuthorizationRights *authorizedRights = NULL;
108 AuthorizationEnvironment environment = {sizeof(validCredentials)/sizeof(AuthorizationItem), validCredentials};
109 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagDefaults, &authorizedRights);
110 ok(status == errAuthorizationDenied, "Standard authorization without kAuthorizationFlagExtendRights");
111 AuthorizationFreeItemSetNull(authorizedRights);
113 status = AuthorizationCopyRights(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights, &authorizedRights);
114 ok(status == errAuthorizationInteractionNotAllowed, "Authorization fail with UI not allowed");
115 AuthorizationFreeItemSetNull(authorizedRights);
117 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
118 ok(status == errAuthorizationSuccess, "Standard authorization");
119 AuthorizationFreeItemSetNull(authorizedRights);
121 AuthorizationItem extendedItems = {SAMPLE_SHARED_RIGHT, 0, NULL, 0};
122 AuthorizationRights extendedRights = {1, &extendedItems};
124 status = AuthorizationCopyRights(authorizationRef, &extendedRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
125 ok(status == errAuthorizationSuccess, "Extending authorization rights");
126 AuthorizationFreeItemSetNull(authorizedRights);
128 AuthorizationItem pwdExtractItems = {SAMPLE_PASSWORD_RIGHT, 0, NULL, 0};
129 AuthorizationRights pwdExtractRight = {1, &pwdExtractItems};
131 // check that non-entitled process cannot extract password from AuthorizationRef
132 status = AuthorizationCopyRights(authorizationRef, &pwdExtractRight, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
133 Boolean passwordFound = false;
134 if (status == errAuthorizationSuccess) {
135 AuthorizationItemSet *returnedInfo;
136 status = AuthorizationCopyInfo(authorizationRef, NULL, &returnedInfo);
137 if (status == errSecSuccess && returnedInfo) {
138 for (uint32_t index = 0; index < returnedInfo->count; ++index) {
139 AuthorizationItem item = returnedInfo->items[index];
140 if (strncpy((char *)item.name, kAuthorizationEnvironmentPassword, strlen(kAuthorizationEnvironmentPassword)) == 0) {
141 passwordFound = true;
144 AuthorizationFreeItemSetNull(returnedInfo);
148 ok(status == errAuthorizationSuccess && passwordFound == false, "Extracting password from AuthorizationRef");
149 AuthorizationFreeItemSetNull(authorizedRights);
152 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
156 int authd_03_uiauthorization(int argc, char *const *argv)
159 if (!getCredentials()) {
160 fail("Not able to read credentials for current user!");
163 AuthorizationRef authorizationRef;
165 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
166 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
168 AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0};
169 AuthorizationRights myRights = {1, &myItems};
171 NSString *raftFillValid = [NSString stringWithFormat:RAFT_FILL, correctUsername.UTF8String, correctPassword.UTF8String];
173 dispatch_semaphore_t sem = dispatch_semaphore_create(0);
175 AuthorizationAsyncCallback internalBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
176 AuthorizationFreeItemSetNull(blockAuthorizedRights);
177 ok(err == errAuthorizationInternal, "Async authorization interal error");
178 dispatch_semaphore_signal(sem);
180 AuthorizationAsyncCallback denyBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
181 AuthorizationFreeItemSetNull(blockAuthorizedRights);
182 ok(err == errAuthorizationDenied, "Async authorization denial");
183 dispatch_semaphore_signal(sem);
185 AuthorizationAsyncCallback allowBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
186 AuthorizationFreeItemSetNull(blockAuthorizedRights);
187 ok(err == errAuthorizationSuccess, "Async authorization");
188 dispatch_semaphore_signal(sem);
190 AuthorizationAsyncCallback cancelBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) {
191 AuthorizationFreeItemSetNull(blockAuthorizedRights);
192 ok(err == errAuthorizationCanceled, "Async authorization cancel");
193 dispatch_semaphore_signal(sem);
195 AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, cancelBlock);
196 sleep(3); // give some time to SecurityAgent to appear
197 runRaft(RAFT_CANCEL);
198 if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) {
199 fail("Async authorization cancel");
201 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
203 AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, allowBlock);
204 sleep(3); // give some time to SecurityAgent to appear
205 runRaft(raftFillValid);
206 if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) {
207 fail("Async authorization");
208 } AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
213 int authd_04_executewithprivileges(int argc, char *const *argv)
215 const int NUMBER_OF_ITERATIONS = 10;
216 plan_tests(2 + 4 * NUMBER_OF_ITERATIONS);
218 if (!getCredentials()) {
219 fail("Not able to read credentials for current user!");
222 AuthorizationRef authorizationRef;
223 OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
224 ok(status == errAuthorizationSuccess, "AuthorizationRef create");
226 AuthorizationItem myItems = { kAuthorizationRightExecute, 0, NULL, 0};
227 AuthorizationRights myRights = {1, &myItems};
228 AuthorizationRights *authorizedRights = NULL;
229 AuthorizationEnvironment environment = {sizeof(validCredentials)/sizeof(AuthorizationItem), validCredentials};
230 status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights);
231 ok(status == errAuthorizationSuccess, "Standard authorization");
232 AuthorizationFreeItemSetNull(authorizedRights);
234 for (int i = 0; i < NUMBER_OF_ITERATIONS; ++i) {
235 NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
236 static const char *toolArgv[3];
237 NSString *arg = [NSString stringWithFormat:@"%s %@", "/usr/bin/whoami && /bin/echo", guid];
238 NSString *expected = [NSString stringWithFormat:@"root\n%@", guid];
240 toolArgv[1] = arg.UTF8String;
244 status = AuthorizationExecuteWithPrivileges(authorizationRef, "/bin/zsh", 0, (char *const *)toolArgv, &output);
245 ok(status == errAuthorizationSuccess, "AuthorizationExecuteWithPrivileges call succeess");
252 size_t bytesRead = 0;
253 size_t totalBytesRead = 0;
254 size_t buffSize = sizeof(buffer);
255 memset(buffer, 0, buffSize);
256 while ((bytesRead = fread (buffer, 1, buffSize, output) > 0)) {
257 totalBytesRead += bytesRead; // overwriting buffer is OK since we are reading just a small amount of data
260 ok(ferror(output) == 0, "Authorized tool pipe closed did not end with ferror");
261 if (ferror(output)) {
262 // test failed, ferror happened
267 ok(feof(output), "Authorized tool pipe closed with feof");
269 // test failed, feof not happened
275 if (strncmp(buffer, expected.UTF8String, guid.length) == 0) {
276 pass("Authorized tool output matches");
278 fail("AuthorizationExecuteWithPrivileges output %s does not match %s", buffer, expected.UTF8String);
282 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);