int
tests_end(int result)
{
	setup("tests_end");
	/* Restore previous cwd and remove scratch dir. */
	return (ok_unix(fchdir(current_dir), "fchdir") &&
		ok_unix(close(current_dir), "close") &&
		ok_unix(rmdir_recursive(scratch_dir), "rmdir_recursive"));
}
void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_before_reset)
{
    CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random());
    CFStringRef keychain_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@Library/Keychains"), tmp_dir);
    
    CFStringPerformWithCString(keychain_dir, ^(const char *keychain_dir_string) {
        ok_unix(mkpath_np(keychain_dir_string, 0755), "Create temp dir %s", keychain_dir_string);
    });
/* Create an empty keychain file that can't be read or written and make sure
   securityd can deal with it. */
static void tests(void)
{
#ifndef NO_SERVER
    plan_skip_all("No testing against server.");
#else
    const char *home_dir = getenv("HOME");
    char keychain_dir[1000];
    char keychain_name[1000];
    sprintf(keychain_dir, "%s/Library/Keychains", home_dir);
    sprintf(keychain_name, "%s/keychain-2-debug.db", keychain_dir);

    ensureKeychainExists();
    int fd;
    ok_unix(fd = open(keychain_name, O_RDWR | O_CREAT | O_TRUNC, 0644),
        "create keychain file '%s'", keychain_name);
    ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_name);
    ok_unix(close(fd), "close keychain file '%s'", keychain_name);

    kc_dbhandle_reset();

    int v_eighty = 80;
    CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
    const char *v_data = "test";
    CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
    CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net"));
    CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith"));
    CFDictionaryAddValue(query, kSecAttrPort, eighty);
    CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP);
    CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault);
    CFDictionaryAddValue(query, kSecValueData, pwdata);
    ok_status(SecItemAdd(query, NULL), "add internet password");
    is_status(SecItemAdd(query, NULL), errSecDuplicateItem,
	"add internet password again");

    ok_status(SecItemCopyMatching(query, NULL), "Found the item we added");

    ok_status(SecItemDelete(query),"Deleted the item we added");

    CFReleaseSafe(eighty);
    CFReleaseSafe(pwdata);
    CFReleaseSafe(query);
#endif
}
static int
tests_end(void)
{
#ifdef NO_SERVER
	setup("tests_end");
	/* Restore previous cwd and remove scratch dir. */
	int ok = ok_unix(fchdir(current_dir), "fchdir");
	if (ok)
		ok = ok_unix(close(current_dir), "close");
	if (ok) {
		if (!keep_scratch_dir) {
			ok = ok_unix(rmdir_recursive(scratch_dir), "rmdir_recursive");
		}
	}
    
	return ok;
#else
    return 0;
#endif
}
static int tests_init(void) {
    int ok = 0;
#ifdef NO_SERVER
	char preferences_dir[80];
	char library_dir[70];

	setup("tests_init");

    /* Create scratch dir for tests to run in. */
    sprintf(scratch_dir, "/tmp/tst-%d", getpid());
    if (keep_scratch_dir) {
        printf("running tests with HOME=%s\n", scratch_dir);
    }

    sprintf(library_dir, "%s/Library", scratch_dir);
    sprintf(preferences_dir, "%s/Preferences", library_dir);
    ok =  (ok_unix(mkdir(scratch_dir, 0755), "mkdir") &&
           ok_unix(current_dir = open(".", O_RDONLY), "open") &&
           ok_unix(chdir(scratch_dir), "chdir") &&
           ok_unix(setenv("HOME", scratch_dir, 1), "setenv") &&
           /* @@@ Work around a bug that the prefs code in
            libsecurity_keychain never creates the Library/Preferences
            dir. */
           ok_unix(mkdir(library_dir, 0755), "mkdir") &&
           ok_unix(mkdir(preferences_dir, 0755), "mkdir") &&
           ok(home_var = getenv("HOME"), "getenv"));
    
    if (ok > 0)
        securityd_init(scratch_dir);
#endif

    return ok;
}
int
tests_begin(int argc, char * const *argv)
{
	char library_dir[70];
	char preferences_dir[80];

	setup("tests_begin");

	/* Create scratch dir for tests to run in. */
	sprintf(scratch_dir, "/tmp/tst-%d", getpid());
	sprintf(library_dir, "%s/Library", scratch_dir);
	sprintf(preferences_dir, "%s/Preferences", library_dir);
	return (ok_unix(mkdir(scratch_dir, 0755), "mkdir") &&
		ok_unix(current_dir = open(".", O_RDONLY), "open") &&
		ok_unix(chdir(scratch_dir), "chdir") &&
		ok_unix(setenv("HOME", scratch_dir, 1), "setenv") &&
		/* @@@ Work around a bug that the prefs code in
		  libsecurity_keychain never creates the Library/Preferences
		  dir. */
		ok_unix(mkdir(library_dir, 0755), "mkdir") &&
		ok_unix(mkdir(preferences_dir, 0755), "mkdir") &&
		ok_unix(home_var = getenv("HOME"), "getenv"));
}
int
test_leaks(void)
{
	return 0;
#if 0
	int leaks = 0;
	pid_t child;
	pid_t parent;

	setup("leaks");

	/* Work around the fact that CF calls setenv, which leaks. */
	cf_user_text_encoding_var = getenv("__CF_USER_TEXT_ENCODING");

	ok_unix(parent = getpid(), "getpid");
	int cld_stdout[2] = {};
	ok_unix(child = pipe(cld_stdout), "pipe");
	ok_unix(child = fork(), "fork");
	switch (child)
	{
	case -1:
		break;
	case 0:
	{
		/* child. */

		/* Set childs stdout and stderr to pipe. */
		ok_unix(close(cld_stdout[0]), "close parent end of pipe");
		ok_unix(dup2(cld_stdout[1], 1), "reopen stdout on pipe");
#if 0
		ok_unix(dup2(cld_stdout[1], 2), "reopen stderr on pipe");
#endif

		int argc = 0;
		char *const *argv = NULL;
		char **argvec = (char **)malloc((argc + 2) * sizeof(char *));
		char pidstr[8];
		int ix;
	
		sprintf(pidstr, "%d", parent);
		argvec[0] = "/usr/bin/leaks";
		for (ix = 1; ix < argc; ++ix)
			argvec[ix] = argv[ix];
		argvec[ix] = pidstr;
		argvec[ix + 1] = NULL;

		ok_unix(execv(argvec[0], argvec), "execv");
		_exit(1);
		break;
	}
	default:
	{
		/* Parent. */
		ok_unix(close(cld_stdout[1]), "close child end of pipe");

		/* Set statemachine initial state to 0. */
		int state = 0;
		/* True iff the last char read was a newline. */
		int newline = 1;
		char buf[4098];
		for (;;)
		{
			char *p = buf + 2;
			ssize_t bytes_read;
			bytes_read = read(cld_stdout[0], p, 4096);
			if (bytes_read <= 0)
				break;

			int start = newline ? -2 : 0;
			int ix = 0;
			for (ix = 0; ix < bytes_read; ++ix)
			{
				/* Simple state machine for parsing leaks output.
				 * Looks for
				 *     '[^\n]*\n[^:]*: ([0-9]*)'
				 * and sets leaks to atoi of the ([0-9]*) bit. */
				switch (state)
				{
				case 0: if (p[ix] == '\n') state = 1; break;
				case 1: if (p[ix] == ':') state = 2; break;
				case 2: if (p[ix] == ' ') state = 3; break;
				case 3:
					if (p[ix] <= '0' || p[ix] >='9')
						state = 4;
					else
						leaks = leaks * 10 + p[ix] - '0';
					break;
				case 4: break;
				}

				/* If there is a newline in the input or we are looking
				   at the last char of the buffer it's time to write the
				   output. */
				if (p[ix] == '\n' || ix + 1 >= bytes_read)
				{
					/* If the previous char was a newline we prefix the
					   output with "# ". */
					if (newline)
					{
						p[start] = '#';
						p[start + 1] = ' ';
					}
					fwrite(p + start, ix + 1 - start, 1, stdout);
					if (p[ix] == '\n')
					{
						start = ix - 1;
						newline = 1;
					}
					else
						newline = 0;
				}
			}
		}

		int status = 0;
		for (;;)
		{
			/* Wait for the child to exit. */
			pid_t waited_pid = waitpid(child, &status, 0);
			if (waited_pid == -1)
			{
				int error = errno;
				/* Keep going if we get interupted but bail out on any
				   other error. */
				if (error == EINTR)
					continue;

				ok_unix(waited_pid, "waitpid");
				break;
			}

			if (WIFEXITED(status))
			{
				is(WEXITSTATUS(status), 0, "leaks exit status");
				break;
			}
			else if (WIFSIGNALED(status))
			{
				is(WTERMSIG(status), 0, "leaks terminated by");
				break;
			}
		}
		break;
	}
	}

	return leaks;
#endif
}
示例#8
0
static void tests(void)
{
	char *home = getenv("HOME");
	char kcname1[256], kcname2[256];
	SecKeychainStatus status1, status2;

	if (!home || strlen(home) > 200)
		plan_skip_all("home too big");

	sprintf(kcname1, "%s/kctests/kc1/kc1", home);
	SecKeychainRef kc1 = NULL, kc2 = NULL;
    kc1 = createNewKeychainAt(kcname1, "test");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");
	ok_status(SecKeychainLock(kc1), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecReadPermStatus|kSecWritePermStatus,
			"status (locked) readable writable");
	}

	/* Make keychain non writable. */
	char kcdir1[256];
	sprintf(kcdir1, "%s/kctests/kc1", home);
	ok_unix(chmod(kcdir1, 0555), "chmod kcdir1 0555");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecReadPermStatus, "status (locked) readable");
	ok_status(SecKeychainUnlock(kc1, 4, "test", TRUE), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	/* Reopen the keychain. */
	CFRelease(kc1);
	ok_status(SecKeychainOpen(kcname1, &kc1), "SecKeychainOpen kc1");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	sprintf(kcname2, "%s/kctests/kc2/kc2", home);
    kc2 = createNewKeychainAt(kcname2, "test");
	ok_unix(chmod(kcname2, 0444), "chmod kc2 0444");
	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Reopen the keychain. */
	CFRelease(kc2);
	ok_status(SecKeychainOpen(kcname2, &kc2), "SecKeychainOpen kc2");

	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Restore dir to writable so cleanup code will work ok. */
	ok_unix(chmod(kcdir1, 0755), "chmod kcdir1 0755");
    ok_status(SecKeychainDelete(kc1), "%s: SecKeychainDelete", testName);
	CFRelease(kc1);
    ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", testName);
	CFRelease(kc2);

	bool testWithFreshlyCreatedKeychain = true;
	SecKeychainRef keychain = createNewKeychain("test", "test");
	ok_status(SecKeychainLock(keychain), "SecKeychainLock");

	do {
		SecKeychainStatus keychainStatus = 0;
		is_status(SecKeychainUnlock(keychain, 0, NULL, true), -25293, "SecKeychainUnlock with NULL password (incorrect)");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), 0, "Check it's not unlocked");

		keychainStatus = 0;
		ok_status(SecKeychainUnlock(keychain, strlen("test"), "test", true), "SecKeychainUnlock with correct password");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), kSecUnlockStateStatus, "Check it's unlocked");
		
		ok_status(SecKeychainLock(keychain), "SecKeychainLock");

		if (testWithFreshlyCreatedKeychain)
		{
        CFRelease(keychain);
			testWithFreshlyCreatedKeychain = false;
			ok_status(SecKeychainOpen("test", &keychain), "SecKeychainOpen");
		}
        else {
			testWithFreshlyCreatedKeychain = true;

            ok_status(SecKeychainDelete(keychain), "%s: SecKeychainDelete", testName);
            CFReleaseNull(keychain);
        }
		
	}
	while(!testWithFreshlyCreatedKeychain);

}