1/* 2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include "secd_regressions.h" 26 27#include <securityd/SecDbItem.h> 28#include <utilities/array_size.h> 29#include <utilities/SecCFWrappers.h> 30#include <utilities/SecFileLocations.h> 31#include <utilities/fileIo.h> 32 33#include <securityd/SOSCloudCircleServer.h> 34#include <securityd/SecItemServer.h> 35 36#include <Security/SecBasePriv.h> 37 38#include <AssertMacros.h> 39 40#include <stdio.h> 41#include <unistd.h> 42#include <sys/stat.h> 43#include <pthread.h> 44 45#include "SecdTestKeychainUtilities.h" 46 47#define N_ITEMS (100) 48#define N_THREADS (10) 49#define N_ADDS (20) 50 51static void *do_add(void *arg) 52{ 53 int tid=(int)(arg); 54 55 for(int i=0;i<N_ADDS;i++) { 56 /* Creating a password */ 57 SInt32 v_eighty = (tid+1)*1000+i; 58 CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); 59 const char *v_data = "test"; 60 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); 61 const void *keys[] = { 62 kSecClass, 63 kSecAttrServer, 64 kSecAttrAccount, 65 kSecAttrPort, 66 kSecAttrProtocol, 67 kSecAttrAuthenticationType, 68 kSecValueData 69 }; 70 const void *values[] = { 71 kSecClassInternetPassword, 72 CFSTR("members.spamcop.net"), 73 CFSTR("smith"), 74 eighty, 75 CFSTR("http"), 76 CFSTR("dflt"), 77 pwdata 78 }; 79 80 CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, 81 array_size(keys), NULL, NULL); 82 83 ok_status(SecItemAdd(item, NULL), "add internet password"); 84 } 85 86 return NULL; 87} 88 89 90int secd_05_corrupted_items(int argc, char *const *argv) 91{ 92 plan_tests(1 + N_THREADS*(N_ADDS+1) + N_ITEMS*4 + kSecdTestSetupTestCount); 93 94 /* custom keychain dir */ 95 secd_test_setup_temp_keychain("secd_05_corrupted_items", NULL); 96 97 /* add a password */ 98 const char *v_data = "test"; 99 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); 100 CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 101 CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); 102 CFDictionaryAddValue(query, kSecAttrServer, CFSTR("corrupt.spamcop.net")); 103 CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); 104 CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); 105 CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); 106 CFDictionaryAddValue(query, kSecValueData, pwdata); 107 108 SInt32 i; 109 for(i=1; i<=N_ITEMS; i++) { 110 CFNumberRef port = CFNumberCreate(NULL, kCFNumberSInt32Type, &i); 111 CFDictionarySetValue(query, kSecAttrPort, port); 112 ok_status(SecItemAdd(query, NULL), "add internet password"); 113 CFReleaseNull(port); 114 } 115 116 /* corrupt all the password */ 117 CFStringRef keychain_path_cf = __SecKeychainCopyPath(); 118 119 CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { 120 /* Create a new keychain sqlite db */ 121 sqlite3 *db; 122 123 is(sqlite3_open(keychain_path, &db), SQLITE_OK, "open keychain"); 124 125 char corrupt_item_sql[80]; 126 for(int i=1;i<=N_ITEMS;i++) { 127 ok_unix(snprintf(corrupt_item_sql, sizeof(corrupt_item_sql), "UPDATE inet SET data=X'12345678' WHERE rowid=%d", i)); 128 is(sqlite3_exec(db, corrupt_item_sql, NULL, NULL, NULL), SQLITE_OK, "corrupting keychain item"); 129 } 130 }); 131 132 /* start the adder threads */ 133 pthread_t add_thread[N_THREADS]; 134 void *add_err[N_THREADS] = {NULL,}; 135 136 for(int i=0; i<N_THREADS; i++) 137 pthread_create(&add_thread[i], NULL, do_add, (void*)(intptr_t)i); 138 139 /* query the corrupted items */ 140 CFDictionaryAddValue(query, kSecReturnPersistentRef, kCFBooleanTrue); 141 for(int i=1;i<=N_ITEMS;i++) { 142 CFTypeRef ref = NULL; 143 CFNumberRef port = CFNumberCreate(NULL, kCFNumberSInt32Type, &i); 144 CFDictionarySetValue(query, kSecAttrPort, port); 145 is_status(SecItemCopyMatching(query, &ref), errSecItemNotFound, "Item not found"); 146 CFReleaseNull(port); 147 CFReleaseNull(ref); 148 } 149 150 /* collect the adder threads */ 151 for(int i=0; i<N_THREADS; i++) 152 pthread_join(add_thread[i], &add_err[i]); 153 154 for(int i=0; i<N_THREADS; i++) 155 ok(add_err[i]==NULL, "add thread"); 156 157 158 CFReleaseNull(query); 159 160 return 0; 161} 162