1// 2// main.c 3// iCloudStats 4// 5// Created by local on 7/20/13. 6// 7// 8 9#include <CoreFoundation/CoreFoundation.h> 10 11#import "SOSCloudCircle.h" 12#import <Security/Security.h> 13 14static const CFStringRef gMessageTracerPrefix = CFSTR("com.apple.message."); 15static const CFStringRef gClientIsUsingiCloudKeychainSyncing = CFSTR("com.apple.icloudkeychain.deviceIsUsingICloudKeychain"); 16static const CFStringRef gNumberOfPeers = CFSTR("com.apple.icloudkeychain.numberOfPeers"); 17static const CFStringRef gNumberOfItemsBeingSynced = CFSTR("com.apple.icloudkeychain.numberOfItemsBeingSynced"); 18 19#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 20static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.icloudkeychain"; 21#endif 22 23#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 24static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.icloudkeychain"; 25#endif 26 27#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) 28#include <asl.h> 29 30 31static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value) 32{ 33 bool result = false; 34 35 if (NULL == key) 36 { 37 return result; 38 } 39 40 aslmsg mAsl = NULL; 41 mAsl = asl_new(ASL_TYPE_MSG); 42 if (NULL == mAsl) 43 { 44 return result; 45 } 46 47 48 CFStringRef key_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), gMessageTracerPrefix, key); 49 if (NULL == key_str) 50 { 51 asl_free(mAsl); 52 return result; 53 } 54 55 CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value); 56 if (NULL == value_str) 57 { 58 asl_free(mAsl); 59 CFRelease(key_str); 60 return result; 61 } 62 63 CFIndex key_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key_str), kCFStringEncodingUTF8); 64 key_str_numBytes += 1; // For null 65 char key_buffer[key_str_numBytes]; 66 memset(key_buffer, 0, key_str_numBytes); 67 if (!CFStringGetCString(key_str, key_buffer, key_str_numBytes, kCFStringEncodingUTF8)) 68 { 69 asl_free(mAsl); 70 CFRelease(key_str); 71 CFRelease(value_str); 72 return result; 73 } 74 CFRelease(key_str); 75 76 CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8); 77 value_str_numBytes += 1; // For null 78 char value_buffer[value_str_numBytes]; 79 memset(value_buffer, 0, value_str_numBytes); 80 if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8)) 81 { 82 asl_free(mAsl); 83 CFRelease(value_str); 84 return result; 85 } 86 CFRelease(value_str); 87 88 asl_set(mAsl, key_buffer, value_buffer); 89 asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "%s", gTopLevelKeyForiCloudKeychainTracing); 90 asl_free(mAsl); 91 return true; 92} 93#endif 94 95#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 96#import <AggregateDictionary/ADClient.h> 97 98static bool iOS_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value) 99{ 100 if (NULL == key) 101 { 102 return false; 103 } 104 105 if (0LL == value) 106 { 107 ADClientClearScalarKey(key); 108 } 109 110 ADClientSetValueForScalarKey(key, value); 111 return true; 112} 113#endif 114 115static bool ClientIsInCircle() 116{ 117 bool result = false; 118 CFErrorRef error = NULL; 119 SOSCCStatus status = kSOSCCError; 120 121 status = SOSCCThisDeviceIsInCircle(&error); 122 if (NULL != error) 123 { 124 CFRelease(error); 125 } 126 else 127 { 128 switch (status) 129 { 130 case kSOSCCInCircle: 131 { 132 result = true; 133 } 134 break; 135 136 // kSOSCCRequestPending 137 // While this device will be in a circle, it is not in 138 // one yet. For now, this will be treated as if the device 139 // was not in a circle and will wait for the device to 140 // be in a circle and have that turn on this daemon with 141 // launchctl 142 case kSOSCCRequestPending: 143 case kSOSCCCircleAbsent: 144 case kSOSCCError: 145 default: 146 break; 147 } 148 } 149 return result; 150} 151 152 153static bool sendTraceMessage(CFStringRef key, int64_t value) 154{ 155 156#if (TARGET_IPHONE_SIMULATOR) 157 return false; 158#endif 159 160#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 161 return OSX_SetCloudKeychainTraceValueForKey(key, value); 162#endif 163 164#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 165 return iOS_SetCloudKeychainTraceValueForKey(key, value); 166#endif 167 168} 169 170static int64_t GetNumberOfPeers() 171{ 172 int64_t result = 0LL; 173 174 CFErrorRef error = NULL; 175 CFArrayRef peers = NULL; 176 177 peers = SOSCCCopyPeerPeerInfo(&error); 178 if (NULL != error) 179 { 180 CFRelease(error); 181 if (NULL != peers) 182 { 183 CFRelease(peers); 184 } 185 return result; 186 } 187 188 if (NULL != peers) 189 { 190 result = (int64_t)CFArrayGetCount(peers); 191 CFRelease(peers); 192 } 193 194 return result; 195} 196 197static int64_t GetNumberOfItemsBeingSyncedForType(CFTypeRef class) 198{ 199 int64_t result = 0; 200 201 CFTypeRef keys[] = {kSecClass, kSecAttrSynchronizable, kSecMatchLimit, kSecReturnAttributes}; 202 CFTypeRef values[] = {class, kCFBooleanTrue, kSecMatchLimitAll, kCFBooleanTrue}; 203 204 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, (sizeof(keys)/sizeof(keys[0])), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 205 206 if (NULL == query) 207 { 208 return result; 209 } 210 211 CFArrayRef query_result = NULL; 212 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&query_result); 213 CFRelease(query); 214 if (noErr != status || NULL == query_result) 215 { 216 if (NULL != query_result) 217 { 218 CFRelease(query_result); 219 } 220 return result; 221 } 222 223 result = (int64_t)CFArrayGetCount(query_result); 224 CFRelease(query_result); 225 return result; 226} 227 228static int64_t GetNumberOfItemsBeingSynced() 229{ 230 int64_t result = 0; 231 232 result = GetNumberOfItemsBeingSyncedForType(kSecClassInternetPassword); 233 result += GetNumberOfItemsBeingSyncedForType(kSecClassGenericPassword); 234 235 return result; 236} 237 238 239int main(int argc, const char * argv[]) 240{ 241 int64_t value = 0; 242 if (!ClientIsInCircle()) 243 { 244 // This will clear the value in the backend database if it had been previously set 245 sendTraceMessage(gClientIsUsingiCloudKeychainSyncing, value); 246 return 0; 247 } 248 249 value = 1; 250 sendTraceMessage(gClientIsUsingiCloudKeychainSyncing, value); 251 252 value = GetNumberOfPeers(); 253 sendTraceMessage(gNumberOfPeers, value); 254 255 value = GetNumberOfItemsBeingSynced(); 256 sendTraceMessage(gNumberOfItemsBeingSynced, value); 257 258 return 0; 259} 260 261