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#ifndef SEC_SOSAccountTesting_h 26#define SEC_SOSAccountTesting_h 27 28#include <CoreFoundation/CoreFoundation.h> 29#include <SecureObjectSync/SOSAccount.h> 30#include <SecureObjectSync/SOSAccountPriv.h> 31#include <SecureObjectSync/SOSTransport.h> 32#include "SOSTransportTestTransports.h" 33// 34// Account comparison 35// 36 37#define kAccountsAgreeTestMin 9 38#define kAccountsAgreeTestPerPeer 1 39#define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x)) 40 41 42static SOSAccountRef SOSAccountCreateBasicTest(CFAllocatorRef allocator, 43 CFStringRef accountName, 44 CFDictionaryRef gestalt, 45 SOSDataSourceFactoryRef factory) { 46 SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory); 47 48 return a; 49} 50 51static SOSAccountRef SOSAccountCreateTest(CFAllocatorRef allocator, 52 CFStringRef accountName, 53 CFDictionaryRef gestalt, 54 SOSDataSourceFactoryRef factory) { 55 SOSAccountRef a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory); 56 57 a->retired_peers = CFDictionaryCreateMutableForCFTypes(allocator); 58 SOSUnregisterTransportKeyParameter(a->key_transport); 59 60 CFReleaseNull(a->circle_transports); 61 CFReleaseNull(a->message_transports); 62 CFReleaseNull(a->key_transport); 63 64 SOSAccountEnsureFactoryCirclesTest(a, accountName); 65 66 return a; 67} 68 69 70static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFArrayRef allowed_peers) 71{ 72 CFArrayForEach(peers, ^(const void *value) { 73 SOSPeerInfoRef pi = (SOSPeerInfoRef) value; 74 CFErrorRef leftError = NULL; 75 CFErrorRef rightError = NULL; 76 77 ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFArrayContainsValue(allowed_peers, CFRangeMake(0, CFArrayGetCount(allowed_peers)), pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers); 78 79 CFReleaseNull(leftError); 80 CFReleaseNull(rightError); 81 }); 82} 83 84static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountRef right, bool check_peers) 85{ 86 CFErrorRef error = NULL; 87 { 88 CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error); 89 ok(leftPeers, "Left peers (%@) - %s", error, label); 90 CFReleaseNull(error); 91 92 CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error); 93 ok(rightPeers, "Right peers (%@) - %s", error, label); 94 CFReleaseNull(error); 95 96 ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers); 97 98 if (check_peers) { 99 CFMutableArrayRef allowed_identities = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); 100 101 CFArrayRef leftIdentities = SOSAccountCopyAccountIdentityPeerInfos(left, kCFAllocatorDefault, &error); 102 ok(leftIdentities, "Get identities (%@)", error); 103 CFReleaseNull(error); 104 105 CFArrayAppendArray(allowed_identities, leftIdentities, CFRangeMake(0, CFArrayGetCount(leftIdentities))); 106 107 CFReleaseNull(leftIdentities); 108 109 CFArrayRef rightIdentities = SOSAccountCopyAccountIdentityPeerInfos(right, kCFAllocatorDefault, &error); 110 ok(rightIdentities, "Get identities (%@)", error); 111 CFReleaseNull(error); 112 113 CFArrayAppendArray(allowed_identities, rightIdentities, CFRangeMake(0, CFArrayGetCount(rightIdentities))); 114 115 CFReleaseNull(rightIdentities); 116 117 unretired_peers_is_subset(label, leftPeers, allowed_identities); 118 } 119 120 CFReleaseNull(leftPeers); 121 CFReleaseNull(rightPeers); 122 } 123 { 124 CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error); 125 ok(leftConcurringPeers, "Left peers (%@) - %s", error, label); 126 127 CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error); 128 ok(rightConcurringPeers, "Right peers (%@) - %s", error, label); 129 130 ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers); 131 132 CFReleaseNull(leftConcurringPeers); 133 CFReleaseNull(rightConcurringPeers); 134 } 135 { 136 CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error); 137 ok(leftApplicants, "Left Applicants (%@) - %s", error, label); 138 139 CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error); 140 ok(rightApplicants, "Left Applicants (%@) - %s", error, label); 141 142 ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants); 143 144 CFReleaseNull(leftApplicants); 145 CFReleaseNull(rightApplicants); 146 } 147} 148 149static inline void accounts_agree(char *label, SOSAccountRef left, SOSAccountRef right) 150{ 151 accounts_agree_internal(label, left, right, true); 152} 153 154 155// 156// Change handling 157// 158 159static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFDictionaryRef overlay) { 160 CFDictionaryForEach(overlay, ^(const void *key, const void *value) { 161 CFDictionarySetValue(target, key, value); 162 }); 163} 164 165static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) { 166 CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) { 167 CFArrayAppendValue(keys, key); 168 }); 169} 170 171static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccountRef sender) 172{ 173 __block bool changes_added = false; 174 CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 175 CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary); 176 CFReleaseNull(emptyDictionary); 177 178 CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues); 179 180 CFDictionaryForEach(changesRecord, ^(const void *key, const void *value) { 181 if (isArray(value) && (sender == NULL || !CFEqual(sender, key))) { 182 CFArrayAppendKeys((CFMutableArrayRef) value, newKeysAndValues); 183 if (CFDictionaryGetCount(newKeysAndValues)) 184 changes_added = true; 185 } 186 }); 187 188 CFDictionaryRemoveAllValues(newKeysAndValues); 189 190 return changes_added; 191} 192 193static bool FillAllChanges(CFMutableDictionaryRef changes) { 194 __block bool changed = false; 195 CFArrayForEach(key_transports, ^(const void *value) { 196 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value; 197 changed |= AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt)); 198 }); 199 CFArrayForEach(circle_transports, ^(const void *value) { 200 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value; 201 changed |= AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt)); 202 }); 203 CFArrayForEach(message_transports, ^(const void *value) { 204 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value; 205 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull); 206 changed |=AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt)); 207 }); 208 209 return changed; 210} 211 212static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount) 213{ 214 CFArrayForEach(key_transports, ^(const void *value) { 215 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value; 216 if(CFEqualSafe(forAccount, SOSTransportKeyParameterTestGetAccount(tpt))){ 217 AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt)); 218 } 219 }); 220 CFArrayForEach(circle_transports, ^(const void *value) { 221 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value; 222 if(CFEqualSafe(forAccount, SOSTransportCircleTestGetAccount(tpt))){ 223 AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt)); 224 } 225 }); 226 CFArrayForEach(message_transports, ^(const void *value) { 227 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value; 228 if(CFEqualSafe(forAccount, SOSTransportMessageTestGetAccount(tpt))){ 229 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull); 230 AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt)); 231 } 232 }); 233 234} 235 236static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccountRef account, ...) 237{ 238 SOSAccountRef next_account = account; 239 va_list argp; 240 va_start(argp, account); 241 while(next_account != NULL) { 242 FillChanges(changes, next_account); 243 next_account = va_arg(argp, SOSAccountRef); 244 } 245} 246 247static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary) 248{ 249 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); 250 251 CFArrayAppendKeys(result, dictionary); 252 253 return result; 254} 255 256#define kFeedChangesToTestCount 1 257static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account) 258{ 259 CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull); 260 261 if (!isDictionary(full_list)) 262 return; // Nothing recorded to send! 263 264 CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, account); 265 if (!isArray(account_pending_keys)) { 266 CFReleaseNull(account_pending_keys); 267 268 account_pending_keys = CFDictionaryCopyKeys(full_list); 269 CFDictionaryAddValue(changes, account, account_pending_keys); 270 CFReleaseSafe(account_pending_keys); // The dictionary keeps it, we don't retain it here. 271 } 272 273 CFMutableArrayRef handled = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); 274 275 secerror("Changes for %@: %@", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef) account->key_transport), account_pending_keys); 276 277 CFErrorRef error = NULL; 278 CFMutableDictionaryRef account_pending_messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 279 CFArrayForEach(account_pending_keys, ^(const void *value) { 280 CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value)); 281 }); 282 283 ok(handled = SOSTransportDispatchMessages(account, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error); 284 285 if (isArray(handled)) { 286 CFArrayForEach(handled, ^(const void *value) { 287 CFArrayRemoveAllValue(account_pending_keys, value); 288 }); 289 } 290 291 CFReleaseNull(handled); 292 CFReleaseNull(error); 293} 294 295#define kFeedChangesToMultieTestCountPer 1 296 297static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp) 298{ 299 SOSAccountRef account = NULL; 300 while((account = va_arg(argp, SOSAccountRef)) != NULL) { 301 FeedChangesTo(changes, account); 302 } 303} 304 305static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...) 306{ 307 va_list argp; 308 va_start(argp, changes); 309 310 FeedChangesToMultiV(changes, argp); 311 312 va_end(argp); 313} 314 315static inline void InjectChangeToMulti(CFMutableDictionaryRef changes, 316 CFStringRef changeKey, CFTypeRef changeValue, ...) 317{ 318 CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, 319 changeKey, changeValue, 320 NULL); 321 AddNewChanges(changes, changes_to_send, NULL); 322 CFReleaseNull(changes_to_send); 323 324 va_list argp; 325 va_start(argp, changeValue); 326 FeedChangesToMultiV(changes, argp); 327 328} 329 330 331static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp) 332{ 333 bool result = FillAllChanges(changes); 334 335 FeedChangesToMultiV(changes, argp); 336 337 return result; 338} 339 340 341static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...) 342{ 343 va_list argp; 344 va_start(argp, changes); 345 346 bool result = ProcessChangesOnceV(changes, argp); 347 348 va_end(argp); 349 350 return result; 351} 352 353static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...) 354{ 355 va_list argp; 356 va_start(argp, changes); 357 358 int result = 0; 359 bool new_data = false; 360 do { 361 va_list argp_copy; 362 va_copy(argp_copy, argp); 363 364 new_data = ProcessChangesOnceV(changes, argp_copy); 365 366 ++result; 367 368 va_end(argp_copy); 369 } while (new_data); 370 371 va_end(argp); 372 373 return result; 374 375} 376 377// 378// MARK: Account creation 379// 380 381static SOSAccountRef CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name) 382{ 383 SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); 384 SOSDataSourceRef ds = SOSTestDataSourceCreate(); 385 SOSTestDataSourceFactoryAddDataSource(factory, data_source_name, ds); 386 SOSEngineRef engine = SOSEngineCreate(ds, NULL); 387 ds->engine = engine; 388 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(name); 389 390 SOSAccountRef result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory); 391 392 CFReleaseNull(gestalt); 393 394 return result; 395} 396 397 398static inline int countPeers(SOSAccountRef account) { 399 CFErrorRef error = NULL; 400 CFArrayRef peers; 401 402 peers = SOSAccountCopyPeers(account, &error); 403 int retval = (int) CFArrayGetCount(peers); 404 CFReleaseNull(error); 405 CFReleaseNull(peers); 406 return retval; 407} 408 409static inline int countActivePeers(SOSAccountRef account) { 410 CFErrorRef error = NULL; 411 CFArrayRef peers; 412 413 peers = SOSAccountCopyActivePeers(account, &error); 414 int retval = (int) CFArrayGetCount(peers); 415 CFReleaseNull(error); 416 CFReleaseNull(peers); 417 return retval; 418} 419 420static inline int countActiveValidPeers(SOSAccountRef account) { 421 CFErrorRef error = NULL; 422 CFArrayRef peers; 423 424 peers = SOSAccountCopyActiveValidPeers(account, &error); 425 int retval = (int) CFArrayGetCount(peers); 426 CFReleaseNull(error); 427 CFReleaseNull(peers); 428 return retval; 429} 430 431static inline int countApplicants(SOSAccountRef account) { 432 CFErrorRef error = NULL; 433 CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); 434 int retval = 0; 435 436 if(applicants) retval = (int)CFArrayGetCount(applicants); 437 CFReleaseNull(error); 438 CFReleaseNull(applicants); 439 return retval; 440} 441 442 443static inline void showActiveValidPeers(SOSAccountRef account) { 444 CFErrorRef error = NULL; 445 CFArrayRef peers; 446 447 peers = SOSAccountCopyActiveValidPeers(account, &error); 448 CFArrayForEach(peers, ^(const void *value) { 449 SOSPeerInfoRef pi = (SOSPeerInfoRef) value; 450 ok(0, "Active Valid Peer %@", pi); 451 }); 452 CFReleaseNull(peers); 453} 454 455#endif 456