1#include <Security/SecKeychain.h> 2#include <Security/SecKeychainPriv.h> 3#include <stdlib.h> 4#include <unistd.h> 5 6#include "testenv.h" 7#include "testleaks.h" 8#include "testmore.h" 9#include "testsecevent.h" 10 11void tests(int dont_skip) 12{ 13 const char *user = getenv("USER"); 14 ok((user != NULL && strlen(user) != 0), "USER must be non-nil and non-zero length"); 15 fprintf(stdout, "Testing login for user \"%s\"\n", user); 16 17 ok_status(test_sec_event_register(kSecEveryEventMask), 18 "register for all events"); 19 20 // test SecKeychainLogin for $USER with password "test" 21 ok_status(SecKeychainLogin(strlen(user), user, 4, "test"), "login user"); 22 23 // wait for a list changed event 24 is_sec_event(kSecKeychainListChangedEvent, NULL, NULL, NULL, 25 "list changed event"); 26 no_sec_event("no event"); 27 28 // get the default keychain (should be login.keychain if none is explicitly set) 29 SecKeychainRef default_keychain = NULL; 30 ok_status(SecKeychainCopyDefault(&default_keychain), "get default"); 31 32 // test status of default keychain (should be read/write and unlocked) 33 SecKeychainStatus status = 0; 34 ok_status(SecKeychainGetStatus(default_keychain, &status), "get status"); 35 is(status, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus, 36 "default should be read/write/unlocked"); 37 38 // get the path for the default keychain 39 char path[1024]; 40 UInt32 path_len = sizeof(path) - 1; 41 ok_status(SecKeychainGetPath(default_keychain, &path_len, path), 42 "get path"); 43 fprintf(stdout, "Default keychain path is %s\n", path); 44 path[path_len] = 0; 45 const char *login_path = "Library/Keychains/login.keychain"; 46 cmp_ok(path_len, >, strlen(login_path), "path len is enough"); 47 eq_string(path + path_len - strlen(login_path), login_path, "check path"); 48 49 // check retain count on default keychain (why??) 50 is(CFGetRetainCount(default_keychain), 1, "default retain count is 1"); 51 CFRelease(default_keychain); 52 default_keychain = NULL; 53 54 // lock and unlock events have been removed because they can't be made reliable 55 56 ok_status(test_sec_event_deregister(), "deregister events."); 57 58 // rename login.keychain to $USER to simulate a Panther-style keychain 59 char testuser_path[1024]; 60 sprintf(testuser_path, "Library/Keychains/%s", user); 61 ok_unix(rename(login_path, testuser_path), 62 "rename login.keychain to $USER"); 63 64 // login and verify that SecKeychainLogin cleans up the $USER keychain 65 // (either by renaming to $USER.keychain, or renaming to login.keychain) 66 ok_status(SecKeychainLogin(strlen(user), user, 4, "test"), "login again"); 67 68 // get the default keychain (should be login.keychain if none is explicitly set) 69 ok_status(SecKeychainCopyDefault(&default_keychain), "get default"); 70 path_len = sizeof(path) - 1; 71 ok_status(SecKeychainGetPath(default_keychain, &path_len, path), 72 "get path"); 73 path[path_len] = 0; 74 cmp_ok(path_len, >, strlen(testuser_path), "path len is enough"); 75 76 // lock the default keychain 77 ok_status(SecKeychainLock(default_keychain), "lock default"); 78 CFRelease(default_keychain); 79 80 ok(tests_end(1), "cleanup"); 81} 82 83int main(int argc, char *const *argv) 84{ 85 int dont_skip = argc > 1 && !strcmp(argv[1], "-s"); 86 plan_tests(21); 87 88 if (!tests_begin(argc, argv)) 89 BAIL_OUT("tests_begin failed"); 90 91 tests(dont_skip); 92 ok_leaks("no leaks"); 93 94 return 0; 95} 96