]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSAccountTesting.h
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / SOSAccountTesting.h
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 <Security/SecureObjectSync/SOSAccount.h>
30 #include <Security/SecureObjectSync/SOSAccountPriv.h>
31 #include <Security/SecureObjectSync/SOSTransport.h>
32 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
33 #include "SOSTransportTestTransports.h"
34 //
35 // Account comparison
36 //
37
38 #define kAccountsAgreeTestMin 9
39 #define kAccountsAgreeTestPerPeer 1
40 #define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))
41
42 static void SOSAccountResetToTest(SOSAccountRef a, CFStringRef accountName) {
43 SOSUnregisterTransportKeyParameter(a->key_transport);
44
45 CFReleaseNull(a->circle_transport);
46 CFReleaseNull(a->kvs_message_transport);
47 CFReleaseNull(a->key_transport);
48
49 SOSAccountEnsureFactoryCirclesTest(a, accountName);
50 }
51
52
53 static SOSAccountRef SOSAccountCreateBasicTest(CFAllocatorRef allocator,
54 CFStringRef accountName,
55 CFDictionaryRef gestalt,
56 SOSDataSourceFactoryRef factory) {
57 SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory);
58
59 return a;
60 }
61
62 static SOSAccountRef SOSAccountCreateTest(CFAllocatorRef allocator,
63 CFStringRef accountName,
64 CFDictionaryRef gestalt,
65 SOSDataSourceFactoryRef factory) {
66 SOSAccountRef a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory);
67
68 SOSAccountResetToTest(a, accountName);
69
70 return a;
71 }
72
73 static SOSAccountRef SOSAccountCreateTestFromData(CFAllocatorRef allocator,
74 CFDataRef data,
75 CFStringRef accountName,
76 SOSDataSourceFactoryRef factory) {
77 SOSAccountRef a = SOSAccountCreateFromData(allocator, data, factory, NULL);
78 if (!a) {
79 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(accountName);
80 a = SOSAccountCreate(allocator, gestalt, factory);
81 CFReleaseNull(gestalt);
82 }
83
84 SOSAccountResetToTest(a, accountName);
85
86 return a;
87 }
88
89
90 static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccountRef account,
91 CFStringRef user_account, CFDataRef user_password,
92 CFErrorRef *error)
93 {
94 bool success = false;
95 success = SOSAccountAssertUserCredentials(account, user_account, user_password, error);
96 require_quiet(success, done);
97
98 success = SOSAccountGenerationSignatureUpdate(account, error);
99
100 done:
101 return success;
102 }
103
104
105
106 static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFSetRef allowed_peers)
107 {
108 CFArrayForEach(peers, ^(const void *value) {
109 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
110
111 CFErrorRef leftError = NULL;
112 CFErrorRef rightError = NULL;
113
114 ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFSetContainsValue(allowed_peers, pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers);
115
116 CFReleaseNull(leftError);
117 CFReleaseNull(rightError);
118 });
119 }
120
121 static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountRef right, bool check_peers)
122 {
123 CFErrorRef error = NULL;
124 {
125 CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error);
126 ok(leftPeers, "Left peers (%@) - %s", error, label);
127 CFReleaseNull(error);
128
129 CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error);
130 ok(rightPeers, "Right peers (%@) - %s", error, label);
131 CFReleaseNull(error);
132
133 ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers);
134
135 if (check_peers) {
136 CFMutableSetRef allowed_identities = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
137
138 SOSFullPeerInfoRef leftFullPeer = SOSAccountCopyAccountIdentityPeerInfo(left, kCFAllocatorDefault, NULL);
139
140 if (leftFullPeer)
141 CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(leftFullPeer));
142
143 CFReleaseNull(leftFullPeer);
144
145 SOSFullPeerInfoRef rightFullPeer = SOSAccountCopyAccountIdentityPeerInfo(right, kCFAllocatorDefault, NULL);
146
147 if (rightFullPeer)
148 CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(rightFullPeer));
149
150 CFReleaseNull(rightFullPeer);
151
152 unretired_peers_is_subset(label, leftPeers, allowed_identities);
153
154 CFReleaseNull(allowed_identities);
155 }
156
157 CFReleaseNull(leftPeers);
158 CFReleaseNull(rightPeers);
159 }
160 {
161 CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error);
162 ok(leftConcurringPeers, "Left peers (%@) - %s", error, label);
163
164 CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error);
165 ok(rightConcurringPeers, "Right peers (%@) - %s", error, label);
166
167 ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers);
168
169 CFReleaseNull(leftConcurringPeers);
170 CFReleaseNull(rightConcurringPeers);
171 }
172 {
173 CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error);
174 ok(leftApplicants, "Left Applicants (%@) - %s", error, label);
175
176 CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error);
177 ok(rightApplicants, "Left Applicants (%@) - %s", error, label);
178
179 ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants);
180
181 CFReleaseNull(leftApplicants);
182 CFReleaseNull(rightApplicants);
183 }
184 }
185
186 static inline void accounts_agree(char *label, SOSAccountRef left, SOSAccountRef right)
187 {
188 accounts_agree_internal(label, left, right, true);
189 }
190
191
192 //
193 // Change handling
194 //
195
196 static inline CFStringRef CFArrayCopyCompactDescription(CFArrayRef array) {
197 if (!isArray(array))
198 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Not an array! %@>"), array);
199
200 CFMutableStringRef result = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
201
202 __block CFStringRef separator = CFSTR("");
203 CFArrayForEach(array, ^(const void *value) {
204 CFStringAppendFormat(result, NULL, CFSTR("%@%@"), separator, value);
205 separator = CFSTR(",");
206 });
207
208 CFStringAppend(result, CFSTR("]"));
209
210 CFReleaseSafe(separator);
211
212 return result;
213 }
214
215 static inline CFStringRef SOSAccountCopyName(SOSAccountRef account) {
216 SOSPeerInfoRef pi = SOSAccountGetMyPeerInfo(account);
217
218 return pi ? CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerName(pi)) : CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%@"), account);
219 }
220
221 static inline CFStringRef CopyChangesDescription(CFDictionaryRef changes) {
222
223 CFStringRef pendingChanges = CFDictionaryCopyCompactDescription((CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull));
224
225 CFMutableStringRef peerTable = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
226
227 __block CFStringRef separator = CFSTR("");
228
229 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
230 if (CFGetTypeID(key) == SOSAccountGetTypeID()) {
231 CFStringRef accountName = SOSAccountCopyName((SOSAccountRef) key);
232 CFStringRef arrayDescription = CFArrayCopyCompactDescription(value);
233
234 CFStringAppendFormat(peerTable, NULL, CFSTR("%@%@:%@"), separator, accountName, arrayDescription);
235 separator = CFSTR(", ");
236
237 CFReleaseSafe(accountName);
238 CFReleaseSafe(arrayDescription);
239 }
240 });
241
242 CFStringAppend(peerTable, CFSTR("]"));
243
244 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<TestChanges %@ %@>"), pendingChanges, peerTable);
245 CFReleaseNull(pendingChanges);
246 CFReleaseNull(peerTable);
247
248 return result;
249 };
250
251 static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFMutableDictionaryRef overlay) {
252 CFMutableSetRef keysToRemove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
253
254 CFDictionaryForEach(overlay, ^(const void *key, const void *value) {
255 const void *current_value = CFDictionaryGetValue(target, key);
256 if (CFEqualSafe(current_value, value) || (isNull(value) && current_value == NULL)) {
257 CFSetAddValue(keysToRemove, key);
258 } else {
259 CFDictionarySetValue(target, key, value);
260 }
261 });
262
263 CFSetForEach(keysToRemove, ^(const void *value) {
264 CFDictionaryRemoveValue(overlay, value);
265 });
266
267 CFReleaseNull(keysToRemove);
268 }
269
270 static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) {
271 CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) {
272 CFArrayAppendValue(keys, key);
273 });
274 }
275
276 static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccountRef sender)
277 {
278 __block bool changes_added = false;
279 CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
280 CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary);
281 CFReleaseNull(emptyDictionary);
282
283 CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues);
284
285 CFDictionaryForEach(changesRecord, ^(const void *key, const void *value) {
286 if (isArray(value) && (sender == NULL || sender != key)) {
287 CFArrayAppendKeys((CFMutableArrayRef) value, newKeysAndValues);
288 if (CFDictionaryGetCount(newKeysAndValues))
289 changes_added = true;
290 }
291 });
292
293 if (changes_added)
294 secnotice("changes", "Changes from %@: %@", sender, newKeysAndValues);
295
296 CFDictionaryRemoveAllValues(newKeysAndValues);
297
298 return changes_added;
299 }
300
301 static bool FillAllChanges(CFMutableDictionaryRef changes) {
302 __block bool changed = false;
303
304 CFMutableSetRef changedAccounts = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL);
305
306 CFArrayForEach(key_transports, ^(const void *value) {
307 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value;
308 if (AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt))) {
309 changed |= true;
310 CFSetAddValue(changedAccounts, SOSTransportKeyParameterTestGetAccount(tpt));
311 }
312 SOSTransportKeyParameterTestClearChanges(tpt);
313 });
314 CFArrayForEach(circle_transports, ^(const void *value) {
315 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
316 if (AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt))) {
317 changed |= true;
318 CFSetAddValue(changedAccounts, SOSTransportCircleTestGetAccount(tpt));
319 }
320 SOSTransportCircleTestClearChanges(tpt);
321 });
322 CFArrayForEach(message_transports, ^(const void *value) {
323 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value;
324 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull);
325 if (AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt))) {
326 changed |= true;
327 CFSetAddValue(changedAccounts, SOSTransportMessageTestGetAccount(tpt));
328 }
329 SOSTransportMessageTestClearChanges(tpt);
330 });
331
332 secnotice("process-changes", "Accounts with change (%@): %@", changed ? CFSTR("YES") : CFSTR("NO"), changedAccounts);
333
334 CFReleaseNull(changedAccounts);
335
336 return changed;
337 }
338
339 static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount)
340 {
341 CFArrayForEach(key_transports, ^(const void *value) {
342 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value;
343 if(CFEqualSafe(forAccount, SOSTransportKeyParameterTestGetAccount(tpt))){
344 AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt));
345 SOSTransportKeyParameterTestClearChanges(tpt);
346 }
347 });
348 CFArrayForEach(circle_transports, ^(const void *value) {
349 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
350 if(CFEqualSafe(forAccount, SOSTransportCircleTestGetAccount(tpt))){
351 AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt));
352 SOSTransportCircleTestClearChanges(tpt);
353 }
354 });
355 CFArrayForEach(message_transports, ^(const void *value) {
356 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value;
357 if(CFEqualSafe(forAccount, SOSTransportMessageTestGetAccount(tpt))){
358 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull);
359 AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt));
360 SOSTransportMessageTestClearChanges(tpt);
361 }
362 });
363
364 }
365
366 static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccountRef account, ...)
367 {
368 SOSAccountRef next_account = account;
369 va_list argp;
370 va_start(argp, account);
371 while(next_account != NULL) {
372 FillChanges(changes, next_account);
373 next_account = va_arg(argp, SOSAccountRef);
374 }
375 }
376
377 static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary)
378 {
379 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
380
381 CFArrayAppendKeys(result, dictionary);
382
383 return result;
384 }
385
386 #define kFeedChangesToTestCount 1
387 static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account)
388 {
389 CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull);
390
391 if (!isDictionary(full_list))
392 return; // Nothing recorded to send!
393
394 CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, account);
395
396 if (!isArray(account_pending_keys)) {
397 CFReleaseNull(account_pending_keys);
398
399 account_pending_keys = CFDictionaryCopyKeys(full_list);
400 CFDictionaryAddValue(changes, account, account_pending_keys);
401 CFReleaseSafe(account_pending_keys); // The dictionary keeps it, we don't retain it here.
402 }
403
404 CFMutableArrayRef handled = NULL;
405
406 secnotice("changes", "Changes for %@: %@", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef) account->key_transport), account_pending_keys);
407
408 CFErrorRef error = NULL;
409 CFMutableDictionaryRef account_pending_messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
410 CFArrayForEach(account_pending_keys, ^(const void *value) {
411 CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value));
412 });
413
414 ok(handled = SOSTransportDispatchMessages(account, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error);
415
416 if (isArray(handled)) {
417 CFArrayForEach(handled, ^(const void *value) {
418 CFArrayRemoveAllValue(account_pending_keys, value);
419 });
420 }
421 CFReleaseNull(account_pending_messages);
422 CFReleaseNull(handled);
423 CFReleaseNull(error);
424 }
425
426 #define kFeedChangesToMultieTestCountPer 1
427
428 static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp)
429 {
430 SOSAccountRef account = NULL;
431 while((account = va_arg(argp, SOSAccountRef)) != NULL) {
432 FeedChangesTo(changes, account);
433 }
434 }
435
436 static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...)
437 {
438 va_list argp;
439 va_start(argp, changes);
440
441 FeedChangesToMultiV(changes, argp);
442
443 va_end(argp);
444 }
445
446 static inline void InjectChangeToMulti(CFMutableDictionaryRef changes,
447 CFStringRef changeKey, CFTypeRef changeValue, ...)
448 {
449 CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
450 changeKey, changeValue,
451 NULL);
452 AddNewChanges(changes, changes_to_send, NULL);
453 CFReleaseNull(changes_to_send);
454
455 va_list argp;
456 va_start(argp, changeValue);
457 FeedChangesToMultiV(changes, argp);
458 va_end(argp);
459 }
460
461 static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp)
462 {
463 bool result = FillAllChanges(changes);
464
465 FeedChangesToMultiV(changes, argp);
466
467 return result;
468 }
469
470
471 static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...)
472 {
473 va_list argp;
474 va_start(argp, changes);
475
476 bool result = ProcessChangesOnceV(changes, argp);
477
478 va_end(argp);
479
480 return result;
481 }
482
483 static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...)
484 {
485 va_list argp;
486 va_start(argp, changes);
487
488 int result = 0;
489 bool new_data = false;
490 do {
491 va_list argp_copy;
492 va_copy(argp_copy, argp);
493
494 new_data = ProcessChangesOnceV(changes, argp_copy);
495
496 ++result;
497
498 va_end(argp_copy);
499 } while (new_data);
500
501 va_end(argp);
502
503 return result;
504
505 }
506
507 //
508 // MARK: Account creation
509 //
510
511
512 static inline SOSAccountRef CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name)
513 {
514 SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
515 SOSDataSourceRef ds = SOSTestDataSourceCreate();
516 SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds);
517 SOSEngineRef engine = SOSEngineCreate(ds, NULL);
518 ds->engine = engine;
519 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(name);
520
521 SOSAccountRef result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory);
522
523 CFReleaseNull(gestalt);
524
525 return result;
526 }
527
528 static inline SOSAccountRef CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name)
529 {
530 SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
531 SOSDataSourceRef ds = SOSTestDataSourceCreate();
532 SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds);
533 SOSEngineRef engine = SOSEngineCreate(ds, NULL);
534 ds->engine = engine;
535
536 SOSAccountRef result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory);
537
538 return result;
539 }
540
541
542
543 static inline int countPeers(SOSAccountRef account) {
544 CFErrorRef error = NULL;
545 CFArrayRef peers;
546
547 peers = SOSAccountCopyPeers(account, &error);
548 int retval = (int) CFArrayGetCount(peers);
549 CFReleaseNull(error);
550 CFReleaseNull(peers);
551 return retval;
552 }
553
554 static inline int countActivePeers(SOSAccountRef account) {
555 CFErrorRef error = NULL;
556 CFArrayRef peers;
557
558 peers = SOSAccountCopyActivePeers(account, &error);
559 int retval = (int) CFArrayGetCount(peers);
560 CFReleaseNull(error);
561 CFReleaseNull(peers);
562 return retval;
563 }
564
565 static inline int countActiveValidPeers(SOSAccountRef account) {
566 CFErrorRef error = NULL;
567 CFArrayRef peers;
568
569 peers = SOSAccountCopyActiveValidPeers(account, &error);
570 int retval = (int) CFArrayGetCount(peers);
571 CFReleaseNull(error);
572 CFReleaseNull(peers);
573 return retval;
574 }
575
576 static inline int countApplicants(SOSAccountRef account) {
577 CFErrorRef error = NULL;
578 CFArrayRef applicants = SOSAccountCopyApplicants(account, &error);
579 int retval = 0;
580
581 if(applicants) retval = (int)CFArrayGetCount(applicants);
582 CFReleaseNull(error);
583 CFReleaseNull(applicants);
584 return retval;
585 }
586
587
588 static inline void showActiveValidPeers(SOSAccountRef account) {
589 CFErrorRef error = NULL;
590 CFArrayRef peers;
591
592 peers = SOSAccountCopyActiveValidPeers(account, &error);
593 CFArrayForEach(peers, ^(const void *value) {
594 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
595 ok(0, "Active Valid Peer %@", pi);
596 });
597 CFReleaseNull(peers);
598 }
599
600 #endif