2 * Copyright (c) 2012 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // SOSRegressionUtilities.c
28 #include <AssertMacros.h>
30 #include <Security/SecItem.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/debugging.h>
35 #include <SecureObjectSync/SOSAccount.h>
36 #include <SecureObjectSync/SOSCircle.h>
37 #include <SecureObjectSync/SOSInternal.h>
38 #include <SecureObjectSync/SOSPeerInfoInternal.h>
40 #include <SOSCloudKeychainClient.h>
41 #include "SOSRegressionUtilities.h"
42 #include "SOSInternal.h"
45 #include <MobileGestalt.h>
48 static const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
50 // MARK: ----- SOS General -----
52 const char *cloudKeychainProxyPath
= "/System/Library/Frameworks/Security.framework/Resources/CloudKeychainProxy.bundle/CloudKeychainProxy";
54 static const char *basecfabsoluteTimeToString(CFAbsoluteTime abstime
, CFTimeZoneRef tz
)
56 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
58 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
59 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
61 char *data
= (char *)malloc(20);
62 strncpy(data
, str
, 20);
66 const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
68 return basecfabsoluteTimeToString(abstime
, NULL
);
71 const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime
)
73 // Caller must release using free
74 CFDateFormatterRef formatter
= NULL
;
75 CFTimeZoneRef tz
= NULL
;
76 CFLocaleRef locale
= NULL
;
77 CFDateRef date
= NULL
;
78 CFStringRef cftime_string
= NULL
;
79 char *time_string
= NULL
;
80 char buffer
[1024] = {0,};
83 require(tz
= CFTimeZoneCopySystem(), xit
);
84 require(locale
= CFLocaleCreate(NULL
, CFSTR("en_US")), xit
);
86 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterShortStyle
, kCFDateFormatterShortStyle
), xit
);
87 CFDateFormatterSetFormat(formatter
, CFSTR("MM/dd/yy HH:mm:ss.SSS zzz"));
88 require(date
= CFDateCreate(kCFAllocatorDefault
, abstime
), xit
);
89 require(cftime_string
= CFDateFormatterCreateStringWithDate(kCFAllocatorDefault
, formatter
, date
), xit
);
91 CFStringGetCString(cftime_string
, buffer
, 1024, kCFStringEncodingUTF8
);
92 sz
= strnlen(buffer
, 1024);
93 time_string
= (char *)malloc(sz
);
94 strncpy(time_string
, buffer
, sz
+1);
97 CFReleaseSafe(formatter
);
98 CFReleaseSafe(locale
);
100 CFReleaseSafe(cftime_string
);
104 #include <sys/stat.h>
106 static int file_exist (const char *filename
)
109 return (stat (filename
, &buffer
) == 0);
112 bool XPCServiceInstalled(void)
114 return file_exist(cloudKeychainProxyPath
);
117 void registerForKVSNotifications(const void *observer
, CFStringRef name
, CFNotificationCallback callBack
)
119 // observer is basically a context; name may not be null
120 CFNotificationCenterRef center
= CFNotificationCenterGetDarwinNotifyCenter();
121 CFNotificationSuspensionBehavior suspensionBehavior
= CFNotificationSuspensionBehaviorDeliverImmediately
; //ignored?
122 CFNotificationCenterAddObserver(center
, observer
, callBack
, name
, NULL
, suspensionBehavior
);
125 void testPutObjectInCloudAndSync(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
127 testPutObjectInCloud(key
, object
, error
, dgroup
, processQueue
);
128 testSynchronize(processQueue
, dgroup
);
131 void testPutObjectInCloud(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
133 secerror("testPutObjectInCloud: key: %@, %@", key
, object
);
134 CFDictionaryRef objects
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, key
, object
, NULL
);
137 dispatch_group_enter(dgroup
);
138 SOSCloudKeychainPutObjectsInCloud(objects
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
140 secerror("testPutObjectInCloud returned: %@", returnedValues
);
143 secerror("testPutObjectInCloud returned: %@", error
);
146 dispatch_group_leave(dgroup
);
152 CFTypeRef
testGetObjectFromCloud(CFStringRef key
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
154 // TODO: make sure we return NULL, not CFNull
156 CFMutableArrayRef keysToGet
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
157 CFArrayAppendValue(keysToGet
, key
);
159 __block CFTypeRef object
= NULL
;
161 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
162 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
164 dispatch_group_enter(dgroup
);
165 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
167 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
170 object
= (CFTypeRef
)CFDictionaryGetValue(returnedValues
, key
);
176 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
177 // CFRelease(*error);
179 dispatch_group_leave(dgroup
);
180 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
181 dispatch_semaphore_signal(waitSemaphore
);
184 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
185 dispatch_release(waitSemaphore
);
186 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
191 secerror("returned: %@", object
);
195 CFTypeRef
testGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
197 __block CFTypeRef object
= NULL
;
199 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
200 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
202 dispatch_group_enter(dgroup
);
204 CloudKeychainReplyBlock replyBlock
=
205 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
207 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
208 object
= returnedValues
;
213 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
214 // CFRelease(*error);
216 dispatch_group_leave(dgroup
);
217 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
218 dispatch_semaphore_signal(waitSemaphore
);
222 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
224 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
226 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
227 dispatch_release(waitSemaphore
);
228 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
233 secerror("returned: %@", object
);
237 bool testRegisterKeys(CFArrayRef keysToRegister
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
239 __block
bool result
= false;
241 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
242 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
244 dispatch_group_enter(dgroup
);
245 SOSCloudKeychainRegisterKeysAndGet(keysToRegister
, processQueue
,
246 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
248 secerror("testRegisterKeys returned: %@", returnedValues
);
251 secerror("testRegisterKeys returned: %@", error
);
254 dispatch_group_leave(dgroup
);
256 dispatch_semaphore_signal(waitSemaphore
);
258 ^ (CFDictionaryRef returnedValues
)
260 secerror("testRegisterKeys returned: %@", returnedValues
);
261 dispatch_group_leave(dgroup
);
263 dispatch_semaphore_signal(waitSemaphore
);
266 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
267 dispatch_release(waitSemaphore
);
268 // printTimeNow("finished registerKeysForKVS");
272 bool testSynchronize(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
274 __block
bool result
= false;
275 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
276 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
278 dispatch_group_enter(dgroup
);
280 SOSCloudKeychainSynchronize(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
283 dispatch_group_leave(dgroup
);
284 dispatch_semaphore_signal(waitSemaphore
);
287 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
288 dispatch_release(waitSemaphore
);
292 bool testClearAll(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
294 __block
bool result
= false;
295 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
296 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
298 dispatch_group_enter(dgroup
);
300 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
303 secerror("SOSCloudKeychainClearAll returned: %@", error
);
304 dispatch_group_leave(dgroup
);
305 dispatch_semaphore_signal(waitSemaphore
);
308 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
309 dispatch_release(waitSemaphore
);
310 secerror("SOSCloudKeychainClearAll exit");
314 void unregisterFromKVSNotifications(const void *observer
)
316 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer
);
320 // MARK: SOSPeerInfo creation helpers
323 CFDictionaryRef
SOSCreatePeerGestaltFromName(CFStringRef name
)
325 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
326 kPIUserDefinedDeviceName
, name
,
331 SOSPeerInfoRef
SOSCreatePeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
333 SOSPeerInfoRef result
= NULL
;
334 SecKeyRef publicKey
= NULL
;
335 CFDictionaryRef gestalt
= NULL
;
337 require(outSigningKey
, exit
);
339 GeneratePermanentECPair(256, &publicKey
, outSigningKey
);
341 gestalt
= SOSCreatePeerGestaltFromName(name
);
342 require(gestalt
, exit
);
344 result
= SOSPeerInfoCreate(NULL
, gestalt
, *outSigningKey
, error
);
347 CFReleaseNull(gestalt
);
348 CFReleaseNull(publicKey
);
353 SOSFullPeerInfoRef
SOSCreateFullPeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
355 SOSFullPeerInfoRef result
= NULL
;
356 SecKeyRef publicKey
= NULL
;
357 CFDictionaryRef gestalt
= NULL
;
359 require(outSigningKey
, exit
);
361 GeneratePermanentECPair(256, &publicKey
, outSigningKey
);
363 gestalt
= SOSCreatePeerGestaltFromName(name
);
364 require(gestalt
, exit
);
366 result
= SOSFullPeerInfoCreate(NULL
, gestalt
, *outSigningKey
, error
);
369 CFReleaseNull(gestalt
);
370 CFReleaseNull(publicKey
);
375 // MARK: ----- MAC Address -----
378 * Name: GetHardwareAdress
384 * Description: Retrieve the hardare address for a specified network interface
391 #include <sys/socket.h>
392 #include <netinet/in.h>
393 #include <sys/sysctl.h>
395 #include <net/if_dl.h>
396 #include <net/route.h>
400 #include <sys/stat.h>
402 static int getHardwareAddress(const char *interfaceName
, size_t maxLenAllowed
, size_t *outActualLength
, char *outHardwareAddress
)
405 struct if_msghdr
*ifm
;
406 struct sockaddr_dl
*sdl
;
410 int mib
[6] = {CTL_NET
, AF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, 0 };
413 *outActualLength
= 0;
415 // see how much space is needed
416 require_noerr(result
= sysctl(mib
, 6, NULL
, &buffSize
, NULL
, 0), xit
);
418 // allocate the buffer
419 require(buf
= malloc(buffSize
), xit
);
421 // get the interface info
422 require_noerr(result
= sysctl(mib
, 6, buf
, &buffSize
, NULL
, 0), xit
);
424 ifm
= (struct if_msghdr
*) buf
;
425 end
= buf
+ buffSize
;
428 if (ifm
->ifm_type
== RTM_IFINFO
) // should always be true
430 sdl
= (struct sockaddr_dl
*) (ifm
+ 1);
431 if ( sdl
->sdl_nlen
== strlen( interfaceName
) && ( bcmp( sdl
->sdl_data
, interfaceName
, sdl
->sdl_nlen
) == 0 ) )
433 if ( sdl
->sdl_alen
> 0 )
437 result
= 0; // indicate found the interface
438 hardwareLen
= sdl
->sdl_alen
;
439 if ( hardwareLen
> maxLenAllowed
)
441 hardwareLen
= maxLenAllowed
;
442 result
= -2; // indicate truncation of the address
444 memcpy( outHardwareAddress
, sdl
->sdl_data
+ sdl
->sdl_nlen
, hardwareLen
);
445 *outActualLength
= hardwareLen
;
451 ifm
= (struct if_msghdr
*) ((char*)ifm
+ ifm
->ifm_msglen
);
452 } while ( (char*)ifm
< end
);
461 // MARK: ----- cloudTransportTests -----
463 CFStringRef
myMacAddress(void)
466 CFStringRef result
= NULL
;
467 const char *interfaceName
= "en0";
468 size_t maxLenAllowed
= 1024;
469 size_t outActualLength
= 0;
470 char outHardwareAddress
[1024];
472 require_noerr(getHardwareAddress(interfaceName
, maxLenAllowed
, &outActualLength
, outHardwareAddress
), xit
);
473 require(outActualLength
==6, xit
);
474 unsigned char buf
[32]={0,};
476 unsigned char *ps
= (unsigned char *)buf
;
477 unsigned char *pa
= (unsigned char *)outHardwareAddress
;
478 for (int ix
= 0; ix
< 6; ix
++, pa
++)
479 ps
+= sprintf((char *)ps
, "%02x", *pa
);
481 result
= CFStringCreateWithCString(kCFAllocatorDefault
, (const char *)buf
, kCFStringEncodingUTF8
);