1/* 2 * Copyright (c) 2012 Apple Computer, 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// SOSRegressionUtilities.c 26// 27 28#include <AssertMacros.h> 29#include <stdio.h> 30#include <Security/SecItem.h> 31 32#include <utilities/SecCFWrappers.h> 33#include <utilities/debugging.h> 34 35#include <SecureObjectSync/SOSAccount.h> 36#include <SecureObjectSync/SOSCircle.h> 37#include <SecureObjectSync/SOSInternal.h> 38#include <SecureObjectSync/SOSPeerInfoInternal.h> 39 40#include <SOSCloudKeychainClient.h> 41#include "SOSRegressionUtilities.h" 42#include "SOSInternal.h" 43 44#if TARGET_OS_IPHONE 45#include <MobileGestalt.h> 46#endif 47 48static const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC; 49 50// MARK: ----- SOS General ----- 51 52const char *cloudKeychainProxyPath = "/System/Library/Frameworks/Security.framework/Resources/CloudKeychainProxy.bundle/CloudKeychainProxy"; 53 54static const char *basecfabsoluteTimeToString(CFAbsoluteTime abstime, CFTimeZoneRef tz) 55{ 56 CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(abstime, NULL); 57 char str[20]; 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)) 60 str[0]=0; 61 char *data = (char *)malloc(20); 62 strncpy(data, str, 20); 63 return data; 64} 65 66const char *cfabsoluteTimeToString(CFAbsoluteTime abstime) 67{ 68 return basecfabsoluteTimeToString(abstime, NULL); 69} 70 71const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime) 72{ 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,}; 81 size_t sz; 82 83 require(tz = CFTimeZoneCopySystem(), xit); 84 require(locale = CFLocaleCreate(NULL, CFSTR("en_US")), xit); 85 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); 90 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); 95xit: 96 CFReleaseSafe(tz); 97 CFReleaseSafe(formatter); 98 CFReleaseSafe(locale); 99 CFReleaseSafe(date); 100 CFReleaseSafe(cftime_string); 101 return time_string; 102} 103 104#include <sys/stat.h> 105 106static int file_exist (const char *filename) 107{ 108 struct stat buffer; 109 return (stat (filename, &buffer) == 0); 110} 111 112bool XPCServiceInstalled(void) 113{ 114 return file_exist(cloudKeychainProxyPath); 115} 116 117void registerForKVSNotifications(const void *observer, CFStringRef name, CFNotificationCallback callBack) 118{ 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); 123} 124 125void testPutObjectInCloudAndSync(CFStringRef key, CFTypeRef object, CFErrorRef *error, dispatch_group_t dgroup, dispatch_queue_t processQueue) 126{ 127 testPutObjectInCloud(key, object, error, dgroup, processQueue); 128 testSynchronize(processQueue, dgroup); 129} 130 131void testPutObjectInCloud(CFStringRef key, CFTypeRef object, CFErrorRef *error, dispatch_group_t dgroup, dispatch_queue_t processQueue) 132{ 133 secerror("testPutObjectInCloud: key: %@, %@", key, object); 134 CFDictionaryRef objects = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, key, object, NULL); 135 if (objects) 136 { 137 dispatch_group_enter(dgroup); 138 SOSCloudKeychainPutObjectsInCloud(objects, processQueue, ^ (CFDictionaryRef returnedValues, CFErrorRef error) 139 { 140 secerror("testPutObjectInCloud returned: %@", returnedValues); 141 if (error) 142 { 143 secerror("testPutObjectInCloud returned: %@", error); 144 CFRelease(error); 145 } 146 dispatch_group_leave(dgroup); 147 }); 148 CFRelease(objects); 149 } 150} 151 152CFTypeRef testGetObjectFromCloud(CFStringRef key, dispatch_queue_t processQueue, dispatch_group_t dgroup) 153{ 154 // TODO: make sure we return NULL, not CFNull 155 secerror("start"); 156 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); 157 CFArrayAppendValue(keysToGet, key); 158 159 __block CFTypeRef object = NULL; 160 161 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); 162 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); 163 164 dispatch_group_enter(dgroup); 165 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, ^ (CFDictionaryRef returnedValues, CFErrorRef error) 166 { 167 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues); 168 if (returnedValues) 169 { 170 object = (CFTypeRef)CFDictionaryGetValue(returnedValues, key); 171 if (object) 172 CFRetain(object); 173 } 174 if (error) 175 { 176 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error); 177 // CFRelease(*error); 178 } 179 dispatch_group_leave(dgroup); 180 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object); 181 dispatch_semaphore_signal(waitSemaphore); 182 }); 183 184 dispatch_semaphore_wait(waitSemaphore, finishTime); 185 dispatch_release(waitSemaphore); 186 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull 187 { 188 CFRelease(object); 189 object = NULL; 190 } 191 secerror("returned: %@", object); 192 return object; 193} 194 195CFTypeRef testGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup) 196{ 197 __block CFTypeRef object = NULL; 198 199 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); 200 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); 201 202 dispatch_group_enter(dgroup); 203 204 CloudKeychainReplyBlock replyBlock = 205 ^ (CFDictionaryRef returnedValues, CFErrorRef error) 206 { 207 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues); 208 object = returnedValues; 209 if (object) 210 CFRetain(object); 211 if (error) 212 { 213 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error); 214 // CFRelease(*error); 215 } 216 dispatch_group_leave(dgroup); 217 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object); 218 dispatch_semaphore_signal(waitSemaphore); 219 }; 220 221 if (!keysToGet) 222 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock); 223 else 224 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock); 225 226 dispatch_semaphore_wait(waitSemaphore, finishTime); 227 dispatch_release(waitSemaphore); 228 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull 229 { 230 CFRelease(object); 231 object = NULL; 232 } 233 secerror("returned: %@", object); 234 return object; 235} 236 237bool testRegisterKeys(CFArrayRef keysToRegister, dispatch_queue_t processQueue, dispatch_group_t dgroup) 238{ 239 __block bool result = false; 240 241 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); 242 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); 243 244 dispatch_group_enter(dgroup); 245 SOSCloudKeychainRegisterKeysAndGet(keysToRegister, processQueue, 246 ^ (CFDictionaryRef returnedValues, CFErrorRef error) 247 { 248 secerror("testRegisterKeys returned: %@", returnedValues); 249 if (error) 250 { 251 secerror("testRegisterKeys returned: %@", error); 252 CFRelease(error); 253 } 254 dispatch_group_leave(dgroup); 255 result = true; 256 dispatch_semaphore_signal(waitSemaphore); 257 }, 258 ^ (CFDictionaryRef returnedValues) 259 { 260 secerror("testRegisterKeys returned: %@", returnedValues); 261 dispatch_group_leave(dgroup); 262 result = true; 263 dispatch_semaphore_signal(waitSemaphore); 264 }); 265 266 dispatch_semaphore_wait(waitSemaphore, finishTime); 267 dispatch_release(waitSemaphore); 268// printTimeNow("finished registerKeysForKVS"); 269 return result; 270} 271 272bool testSynchronize(dispatch_queue_t processQueue, dispatch_group_t dgroup) 273{ 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); 277 278 dispatch_group_enter(dgroup); 279 280 SOSCloudKeychainSynchronize(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error) 281 { 282 result = true; 283 dispatch_group_leave(dgroup); 284 dispatch_semaphore_signal(waitSemaphore); 285 }); 286 287 dispatch_semaphore_wait(waitSemaphore, finishTime); 288 dispatch_release(waitSemaphore); 289 return result; 290} 291 292bool testClearAll(dispatch_queue_t processQueue, dispatch_group_t dgroup) 293{ 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); 297 298 dispatch_group_enter(dgroup); 299 300 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error) 301 { 302 result = true; 303 secerror("SOSCloudKeychainClearAll returned: %@", error); 304 dispatch_group_leave(dgroup); 305 dispatch_semaphore_signal(waitSemaphore); 306 }); 307 308 dispatch_semaphore_wait(waitSemaphore, finishTime); 309 dispatch_release(waitSemaphore); 310 secerror("SOSCloudKeychainClearAll exit"); 311 return result; 312} 313 314void unregisterFromKVSNotifications(const void *observer) 315{ 316 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer); 317} 318 319// 320// MARK: SOSPeerInfo creation helpers 321// 322 323CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name) 324{ 325 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 326 kPIUserDefinedDeviceName, name, 327 NULL); 328} 329 330 331SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error) 332{ 333 SOSPeerInfoRef result = NULL; 334 SecKeyRef publicKey = NULL; 335 CFDictionaryRef gestalt = NULL; 336 337 require(outSigningKey, exit); 338 339 GeneratePermanentECPair(256, &publicKey, outSigningKey); 340 341 gestalt = SOSCreatePeerGestaltFromName(name); 342 require(gestalt, exit); 343 344 result = SOSPeerInfoCreate(NULL, gestalt, *outSigningKey, error); 345 346exit: 347 CFReleaseNull(gestalt); 348 CFReleaseNull(publicKey); 349 350 return result; 351} 352 353SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error) 354{ 355 SOSFullPeerInfoRef result = NULL; 356 SecKeyRef publicKey = NULL; 357 CFDictionaryRef gestalt = NULL; 358 359 require(outSigningKey, exit); 360 361 GeneratePermanentECPair(256, &publicKey, outSigningKey); 362 363 gestalt = SOSCreatePeerGestaltFromName(name); 364 require(gestalt, exit); 365 366 result = SOSFullPeerInfoCreate(NULL, gestalt, *outSigningKey, error); 367 368exit: 369 CFReleaseNull(gestalt); 370 CFReleaseNull(publicKey); 371 372 return result; 373} 374 375// MARK: ----- MAC Address ----- 376 377/* 378 * Name: GetHardwareAdress 379 * 380 * Parameters: None. 381 * 382 * Returns: Nothing 383 * 384 * Description: Retrieve the hardare address for a specified network interface 385 * 386 */ 387 388#include <stdlib.h> 389#include <string.h> 390 391#include <sys/socket.h> 392#include <netinet/in.h> 393#include <sys/sysctl.h> 394#include <net/if.h> 395#include <net/if_dl.h> 396#include <net/route.h> 397 398#include <unistd.h> 399#include <netdb.h> 400#include <sys/stat.h> 401 402static int getHardwareAddress(const char *interfaceName, size_t maxLenAllowed, size_t *outActualLength, char *outHardwareAddress) 403{ 404 char *end; 405 struct if_msghdr *ifm; 406 struct sockaddr_dl *sdl; 407 char *buf; 408 int result; 409 size_t buffSize; 410 int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 }; 411 412 buf = 0; 413 *outActualLength = 0; 414 result = -1; 415 // see how much space is needed 416 require_noerr(result = sysctl(mib, 6, NULL, &buffSize, NULL, 0), xit); 417 418 // allocate the buffer 419 require(buf = malloc(buffSize), xit); 420 421 // get the interface info 422 require_noerr(result = sysctl(mib, 6, buf, &buffSize, NULL, 0), xit); 423 424 ifm = (struct if_msghdr *) buf; 425 end = buf + buffSize; 426 do 427 { 428 if (ifm->ifm_type == RTM_IFINFO) // should always be true 429 { 430 sdl = (struct sockaddr_dl *) (ifm + 1); 431 if ( sdl->sdl_nlen == strlen( interfaceName ) && ( bcmp( sdl->sdl_data, interfaceName, sdl->sdl_nlen ) == 0 ) ) 432 { 433 if ( sdl->sdl_alen > 0 ) 434 { 435 size_t hardwareLen; 436 437 result = 0; // indicate found the interface 438 hardwareLen = sdl->sdl_alen; 439 if ( hardwareLen > maxLenAllowed ) 440 { 441 hardwareLen = maxLenAllowed; 442 result = -2; // indicate truncation of the address 443 } 444 memcpy( outHardwareAddress, sdl->sdl_data + sdl->sdl_nlen, hardwareLen ); 445 *outActualLength = hardwareLen; 446 break; 447 448 } 449 } 450 } 451 ifm = (struct if_msghdr *) ((char*)ifm + ifm->ifm_msglen); 452 } while ( (char*)ifm < end ); 453 454xit: 455 if (buf) 456 free(buf); 457 458 return result; 459} 460 461// MARK: ----- cloudTransportTests ----- 462 463CFStringRef myMacAddress(void) 464{ 465 // 6 bytes, no ":"s 466 CFStringRef result = NULL; 467 const char *interfaceName = "en0"; 468 size_t maxLenAllowed = 1024; 469 size_t outActualLength = 0; 470 char outHardwareAddress[1024]; 471 472 require_noerr(getHardwareAddress(interfaceName, maxLenAllowed, &outActualLength, outHardwareAddress), xit); 473 require(outActualLength==6, xit); 474 unsigned char buf[32]={0,}; 475 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); 480 481 result = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)buf, kCFStringEncodingUTF8); 482 483xit: 484 return result; 485} 486