1/* 2 * Copyright (c) 1998-2013 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#include "DABase.h" 25 26#include "DAInternal.h" 27 28#include <fcntl.h> 29#include <paths.h> 30#include <sysexits.h> 31#include <vproc.h> 32#include <sys/attr.h> 33#include <sys/stat.h> 34#include <CommonCrypto/CommonDigest.h> 35#include <CoreFoundation/CFBundlePriv.h> 36#include <SystemConfiguration/SCDynamicStoreCopySpecificPrivate.h> 37 38static vproc_transaction_t __vproc_transaction = NULL; 39static size_t __vproc_transaction_count = 0; 40 41__private_extern__ int ___chattr( const char * path, ___attr_t attr, ___attr_t noattr ) 42{ 43 /* 44 * Change file flags. 45 */ 46 47 struct __chattrbuf 48 { 49 uint32_t size; 50 uint8_t reserved0032[8]; 51 ___attr_t attr; 52 uint8_t reserved0112[22]; 53 }; 54 55 typedef struct __chattrbuf __chattrbuf; 56 57 struct attrlist attributes; 58 __chattrbuf buffer; 59 int status; 60 61 attributes.bitmapcount = ATTR_BIT_MAP_COUNT; 62 attributes.commonattr = ATTR_CMN_FNDRINFO; 63 attributes.dirattr = 0; 64 attributes.fileattr = 0; 65 attributes.forkattr = 0; 66 attributes.volattr = 0; 67 68 status = getattrlist( path, &attributes, &buffer, sizeof( buffer ), 0 ); 69 70 if ( status == 0 ) 71 { 72 buffer.attr = OSSwapHostToBigInt16( ( OSSwapBigToHostInt16( buffer.attr ) & ~noattr ) | attr ); 73 74 status = setattrlist( path, &attributes, ( ( uint8_t * ) &buffer ) + sizeof( buffer.size ), sizeof( buffer ) - sizeof( buffer.size ), 0 ); 75 } 76 77 return status; 78} 79 80__private_extern__ int ___isautofs( const char * path ) 81{ 82 /* 83 * Test for the autofs file system. 84 */ 85 86 struct statfs * mountList; 87 int mountListCount; 88 int mountListIndex; 89 90 mountListCount = getfsstat( NULL, 0, MNT_NOWAIT ); 91 92 if ( mountListCount > 0 ) 93 { 94 mountList = malloc( mountListCount * sizeof( struct statfs ) ); 95 96 if ( mountList ) 97 { 98 mountListCount = getfsstat( mountList, mountListCount * sizeof( struct statfs ), MNT_NOWAIT ); 99 100 if ( mountListCount > 0 ) 101 { 102 for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ ) 103 { 104 if ( strcmp( mountList[mountListIndex].f_fstypename, "autofs" ) == 0 ) 105 { 106 if ( strncmp( mountList[mountListIndex].f_mntonname, path, strlen( mountList[mountListIndex].f_mntonname ) ) == 0 ) 107 { 108 break; 109 } 110 } 111 } 112 } 113 114 free( mountList ); 115 } 116 } 117 118 return ( mountListIndex < mountListCount ); 119} 120 121__private_extern__ int ___mkdir( const char * path, mode_t mode ) 122{ 123 /* 124 * Make a directory. 125 */ 126 127 int status; 128 129 status = -1; 130 131 if ( path ) 132 { 133 char * template; 134 135 asprintf( &template, "%s.XXXXXX", path ); 136 137 if ( template ) 138 { 139 status = mkdtemp( template ) ? 0 : -1; 140 141 if ( status == 0 ) 142 { 143 status = chmod( template, mode ); 144 145 if ( status == 0 ) 146 { 147 status = rename( template, path ); 148 } 149 150 if ( status ) 151 { 152 rmdir( template ); 153 } 154 } 155 156 free( template ); 157 } 158 } 159 160 return status; 161} 162 163__private_extern__ void ___vproc_transaction_begin( void ) 164{ 165 if ( __vproc_transaction_count == 0 ) 166 { 167 __vproc_transaction = vproc_transaction_begin( NULL ); 168 } 169 170 __vproc_transaction_count++; 171} 172 173__private_extern__ void ___vproc_transaction_end( void ) 174{ 175 __vproc_transaction_count--; 176 177 if ( __vproc_transaction_count == 0 ) 178 { 179 vproc_transaction_end( NULL, __vproc_transaction ); 180 181 __vproc_transaction = NULL; 182 } 183} 184 185__private_extern__ const void * ___CFArrayGetValue( CFArrayRef array, const void * value ) 186{ 187 /* 188 * Retrieves a value in the array which hashes the same as the specified value. 189 */ 190 191 CFIndex index; 192 193 index = CFArrayGetFirstIndexOfValue( array, CFRangeMake( 0, CFArrayGetCount( array ) ), value ); 194 195 return ( index == kCFNotFound ) ? NULL : CFArrayGetValueAtIndex( array, index ); 196} 197 198__private_extern__ void ___CFArrayIntersect( CFMutableArrayRef array1, CFArrayRef array2 ) 199{ 200 /* 201 * Forms the intersection with the given array. 202 */ 203 204 CFIndex count; 205 CFIndex index; 206 207 count = CFArrayGetCount( array1 ); 208 209 for ( index = count - 1; index > -1; index-- ) 210 { 211 const void * value; 212 213 value = CFArrayGetValueAtIndex( array1, index ); 214 215 if ( ___CFArrayContainsValue( array2, value ) == FALSE ) 216 { 217 CFArrayRemoveValueAtIndex( array1, index ); 218 } 219 } 220} 221 222__private_extern__ CFStringRef ___CFBundleCopyLocalizedStringInDirectory( CFURLRef bundleURL, CFStringRef key, CFStringRef value, CFStringRef table ) 223{ 224 /* 225 * Returns a localized string from a bundle's strings file without needing to create a 226 * CFBundle object. 227 */ 228 229 CFBundleRef bundle; 230 CFStringRef string = NULL; 231 232 bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); 233 234 if ( bundle ) 235 { 236 _CFBundleSetStringsFilesShared( bundle, FALSE ); 237 238 string = CFBundleCopyLocalizedString( bundle, key, value, table ); 239 240 CFRelease( bundle ); 241 } 242 243 return string; 244} 245 246__private_extern__ CFURLRef ___CFBundleCopyResourceURLInDirectory( CFURLRef bundleURL, CFStringRef resourcePath ) 247{ 248 /* 249 * Obtains the location of a resource contained in the specified bundle directory without 250 * requiring the creation of a bundle instance. This variant will accept one argument to 251 * describe the subDirName, resourceName, and resourceType. For instance, a resourcePath 252 * of "../hfs.tiff" would break down correctly. 253 */ 254 255 CFURLRef resourceURL = NULL; 256 CFURLRef resourcePathURL = NULL; 257 258 resourcePathURL = CFURLCreateWithFileSystemPathRelativeToBase( kCFAllocatorDefault, resourcePath, kCFURLPOSIXPathStyle, FALSE, NULL ); 259 260 if ( resourcePathURL ) 261 { 262 CFStringRef resourceName; 263 264 resourceName = CFURLCopyLastPathComponent( resourcePathURL ); 265 266 if ( resourceName ) 267 { 268 CFURLRef resourceSubDirNameURL; 269 270 resourceSubDirNameURL = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault, resourcePathURL ); 271 272 if ( resourceSubDirNameURL ) 273 { 274 CFStringRef resourceSubDirName; 275 276 resourceSubDirName = CFURLCopyFileSystemPath( resourceSubDirNameURL, kCFURLPOSIXPathStyle ); 277 278 if ( resourceSubDirName ) 279 { 280 resourceURL = CFBundleCopyResourceURLInDirectory( bundleURL, resourceName, NULL, resourceSubDirName ); 281 282 CFRelease( resourceSubDirName ); 283 } 284 285 CFRelease( resourceSubDirNameURL ); 286 } 287 288 CFRelease( resourceName ); 289 } 290 291 CFRelease( resourcePathURL ); 292 } 293 294 return resourceURL; 295} 296 297__private_extern__ CFDataRef ___CFDataCreateFromString( CFAllocatorRef allocator, CFStringRef string ) 298{ 299 /* 300 * Creates a CFData object using the specified string. The string is validated to ensure it 301 * is in the appropriate form, that is, that it contain a sequence of hexadecimal characters. 302 */ 303 304 CFMutableDataRef data; 305 306 data = CFDataCreateMutable( allocator, 0 ); 307 308 if ( data ) 309 { 310 CFIndex index; 311 CFIndex length; 312 313 length = CFStringGetLength( string ); 314 315 for ( index = 0; index + 1 < length; index += 2 ) 316 { 317 UInt8 byte; 318 UniChar character1; 319 UniChar character2; 320 321 character1 = CFStringGetCharacterAtIndex( string, index ); 322 character2 = CFStringGetCharacterAtIndex( string, index + 1 ); 323 324 if ( isxdigit( character1 ) == 0 ) break; 325 if ( isxdigit( character2 ) == 0 ) break; 326 327 character1 = tolower( character1 ) - '0'; 328 character2 = tolower( character2 ) - '0'; 329 330 byte = ( ( ( character1 > 9 ) ? ( character1 + '0' - 'a' + 10 ) : character1 ) << 4 ) | 331 ( ( ( character2 > 9 ) ? ( character2 + '0' - 'a' + 10 ) : character2 ) ); 332 333 CFDataAppendBytes( data, &byte, 1 ); 334 } 335 336 for ( ; index < length; index++ ) 337 { 338 UniChar character; 339 340 character = CFStringGetCharacterAtIndex( string, index ); 341 342 if ( isspace( character ) == 0 ) break; 343 } 344 345 if ( index < length ) 346 { 347 CFDataSetLength( data, 0 ); 348 } 349 350 if ( CFDataGetLength( data ) == 0 ) 351 { 352 CFRelease( data ); 353 data = NULL; 354 } 355 } 356 357 return data; 358} 359 360__private_extern__ CFDictionaryRef ___CFDictionaryCreateFromXMLString( CFAllocatorRef allocator, CFStringRef string ) 361{ 362 /* 363 * Creates a CFDictionary object using the specified XML string. 364 */ 365 366 CFDataRef data; 367 CFDictionaryRef dictionary = NULL; 368 369 data = CFStringCreateExternalRepresentation( kCFAllocatorDefault, string, kCFStringEncodingUTF8, 0 ); 370 371 if ( data ) 372 { 373 CFTypeRef object; 374 375 object = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL ); 376 377 if ( object ) 378 { 379 if ( CFGetTypeID( object ) == CFDictionaryGetTypeID( ) ) 380 { 381 dictionary = CFRetain( object ); 382 } 383 384 CFRelease( object ); 385 } 386 387 CFRelease( data ); 388 } 389 390 return dictionary; 391} 392 393__private_extern__ const void * ___CFDictionaryGetAnyValue( CFDictionaryRef dictionary ) 394{ 395 /* 396 * Retrieves the value associated with the first key from CFDictionaryGetKeysAndValues(). 397 */ 398 399 CFIndex count; 400 const void * value = NULL; 401 402 count = CFDictionaryGetCount( dictionary ); 403 404 if ( count ) 405 { 406 CFTypeRef * values; 407 408 values = malloc( count * sizeof( CFDictionaryRef ) ); 409 410 if ( values ) 411 { 412 CFDictionaryGetKeysAndValues( dictionary, NULL, values ); 413 414 value = values[0]; 415 416 free( values ); 417 } 418 } 419 420 return value; 421} 422 423__private_extern__ char * ___CFStringCreateCStringWithFormatAndArguments( const char * format, va_list arguments ) 424{ 425 /* 426 * Creates a C string buffer from a printf-style list. The string encoding is presumed to 427 * be UTF-8. The result is a reference to a C string buffer or NULL if there was a problem 428 * in creating the buffer. The caller is responsible for releasing the buffer with free(). 429 */ 430 431 char * buffer = NULL; 432 433 if ( format ) 434 { 435 CFStringRef formatAsString; 436 437 formatAsString = CFStringCreateWithCString( kCFAllocatorDefault, format, kCFStringEncodingUTF8 ); 438 439 if ( formatAsString ) 440 { 441 CFStringRef bufferAsString; 442 443 bufferAsString = CFStringCreateWithFormatAndArguments( kCFAllocatorDefault, NULL, formatAsString, arguments ); 444 445 if ( bufferAsString ) 446 { 447 buffer = ___CFStringCopyCString( bufferAsString ); 448 449 CFRelease( bufferAsString ); 450 } 451 452 CFRelease( formatAsString ); 453 } 454 } 455 456 return buffer; 457} 458 459__private_extern__ Boolean ___CFStringGetCString( CFStringRef string, char * buffer, CFIndex length ) 460{ 461 /* 462 * Copies the character contents of a CFString object to a local C string buffer after 463 * converting the characters to UTF-8. It will copy as many characters as will fit in 464 * the provided buffer. 465 */ 466 467 length--; 468 469 CFStringGetBytes( string, CFRangeMake( 0, CFStringGetLength( string ) ), kCFStringEncodingUTF8, 0, FALSE, ( void * ) buffer, length, &length ); 470 471 buffer[length] = 0; 472 473 return length ? TRUE : FALSE; 474} 475 476__private_extern__ void ___CFStringInsertFormat( CFMutableStringRef string, CFIndex index, CFStringRef format, ... ) 477{ 478 /* 479 * Inserts a formatted string at a specified location in the character buffer of a mutable 480 * CFString object. 481 */ 482 483 va_list arguments; 484 485 va_start( arguments, format ); 486 487 ___CFStringInsertFormatAndArguments( string, index, format, arguments ); 488 489 va_end( arguments ); 490} 491 492__private_extern__ void ___CFStringInsertFormatAndArguments( CFMutableStringRef string, CFIndex index, CFStringRef format, va_list arguments ) 493{ 494 /* 495 * Inserts a formatted string at a specified location in the character buffer of a mutable 496 * CFString object. 497 */ 498 499 CFStringRef insert; 500 501 insert = CFStringCreateWithFormatAndArguments( kCFAllocatorDefault, NULL, format, arguments ); 502 503 if ( insert ) 504 { 505 CFStringInsert( string, index, insert ); 506 507 CFRelease( insert ); 508 } 509} 510 511__private_extern__ void ___CFStringPad( CFMutableStringRef string, CFStringRef pad, CFIndex length, CFIndex index ) 512{ 513 /* 514 * Enlarges the string represented by a CFString object, padding it with specified characters. 515 */ 516 517 if ( length > CFStringGetLength( string ) ) 518 { 519 CFStringPad( string, pad, length, index ); 520 } 521} 522 523__private_extern__ CFUUIDRef ___CFUUIDCreateFromName( CFAllocatorRef allocator, CFUUIDRef space, CFDataRef name ) 524{ 525 /* 526 * Creates a UUID from a unique "name" in the given "name space". See version 3 UUID. 527 */ 528 529 CC_MD5_CTX md5c; 530 CFUUIDBytes uuid; 531 532 assert( sizeof( uuid ) == CC_MD5_DIGEST_LENGTH ); 533 534 uuid = CFUUIDGetUUIDBytes( space ); 535 536 CC_MD5_Init( &md5c ); 537 CC_MD5_Update( &md5c, &uuid, sizeof( uuid ) ); 538 CC_MD5_Update( &md5c, CFDataGetBytePtr( name ), CFDataGetLength( name ) ); 539 CC_MD5_Final( ( void * ) &uuid, &md5c ); 540 541 uuid.byte6 = 0x30 | ( uuid.byte6 & 0x0F ); 542 uuid.byte8 = 0x80 | ( uuid.byte8 & 0x3F ); 543 544 return CFUUIDCreateFromUUIDBytes( allocator, uuid ); 545} 546 547__private_extern__ CFUUIDRef ___CFUUIDCreateFromString( CFAllocatorRef allocator, CFStringRef string ) 548{ 549 /* 550 * Creates a CFUUID object using the specified string. The string is validated to ensure it 551 * is in the appropriate form. One would expect CFUUIDCreateFromString() to accomplish this, 552 * but it does not at this time. 553 */ 554 555 UInt32 index; 556 UInt32 length; 557 558 length = CFStringGetLength( string ); 559 560 for ( index = 0; index < length; index++ ) 561 { 562 UniChar character; 563 564 character = CFStringGetCharacterAtIndex( string, index ); 565 566 if ( index < 36 ) 567 { 568 if ( index == 8 || index == 13 || index == 18 || index == 23 ) 569 { 570 if ( character != '-' ) break; 571 } 572 else 573 { 574 if ( isxdigit( character ) == 0 ) break; 575 } 576 } 577 else 578 { 579 if ( isspace( character ) == 0 ) break; 580 } 581 } 582 583 return ( index < length ) ? NULL : CFUUIDCreateFromString( allocator, string ); 584} 585 586__private_extern__ CFStringRef ___CFURLCopyRawDeviceFileSystemPath( CFURLRef url, CFURLPathStyle pathStyle ) 587{ 588 /* 589 * Obtains the path portion of the specified URL, with the last path component prepended 590 * with an "r" to indicate the "raw" or "character" device variant of the specified URL. 591 */ 592 593 CFStringRef path; 594 595 path = CFURLCopyFileSystemPath( url, pathStyle ); 596 597 if ( path ) 598 { 599 CFStringRef node; 600 601 node = CFURLCopyLastPathComponent( url ); 602 603 if ( node ) 604 { 605 CFMutableStringRef string; 606 607 string = CFStringCreateMutableCopy( CFGetAllocator( url ), 0, path ); 608 609 if ( string ) 610 { 611 CFIndex index; 612 613 index = CFStringGetLength( path ) - CFStringGetLength( node ); 614 615 CFStringInsert( string, index, CFSTR( "r" ) ); 616 617 CFRelease( path ); 618 619 path = string; 620 } 621 622 CFRelease( node ); 623 } 624 } 625 626 return path; 627} 628 629__private_extern__ kern_return_t ___IORegistryEntryGetPath( io_registry_entry_t entry, const io_name_t plane, ___io_path_t path ) 630{ 631 /* 632 * Create a path for a registry entry. 633 */ 634 635 IOReturn status; 636 637 status = IORegistryEntryGetPath( entry, plane, path ); 638 639 if ( status == kIOReturnBadArgument ) 640 { 641 io_registry_entry_t parent; 642 643 status = IORegistryEntryGetParentEntry( entry, plane, &parent ); 644 645 if ( status == kIOReturnSuccess ) 646 { 647 status = ___IORegistryEntryGetPath( parent, plane, path ); 648 649 if ( status == kIOReturnSuccess ) 650 { 651 io_name_t name; 652 653 status = IORegistryEntryGetNameInPlane( entry, plane, name ); 654 655 if ( status == kIOReturnSuccess ) 656 { 657 io_name_t location; 658 659 status = IORegistryEntryGetLocationInPlane( entry, plane, location ); 660 661 if ( status == kIOReturnSuccess ) 662 { 663 if ( strlen( path ) + strlen( "/" ) + strlen( name ) + strlen( "@" ) + strlen( location ) < sizeof( ___io_path_t ) ) 664 { 665 strlcat( path, "/", sizeof( ___io_path_t ) ); 666 strlcat( path, name, sizeof( ___io_path_t ) ); 667 strlcat( path, "@", sizeof( ___io_path_t ) ); 668 strlcat( path, location, sizeof( ___io_path_t ) ); 669 } 670 else 671 { 672 status = kIOReturnBadArgument; 673 } 674 } 675 else 676 { 677 if ( strlen( path ) + strlen( "/" ) + strlen( name ) < sizeof( ___io_path_t ) ) 678 { 679 strlcat( path, "/", sizeof( ___io_path_t ) ); 680 strlcat( path, name, sizeof( ___io_path_t ) ); 681 682 status = kIOReturnSuccess; 683 } 684 else 685 { 686 status = kIOReturnBadArgument; 687 } 688 } 689 } 690 } 691 692 IOObjectRelease( parent ); 693 } 694 } 695 696 return status; 697} 698 699__private_extern__ CFArrayRef ___SCDynamicStoreCopyConsoleInformation( SCDynamicStoreRef store ) 700{ 701 CFMutableArrayRef userList; 702 703 userList = ( void * ) SCDynamicStoreCopyConsoleInformation( store ); 704 705 if ( userList ) 706 { 707 CFMutableArrayRef array; 708 709 array = CFArrayCreateMutableCopy( kCFAllocatorDefault, 0, userList ); 710 711 CFRelease( userList ); 712 713 userList = array; 714 715 if ( userList ) 716 { 717 CFIndex count; 718 CFIndex index; 719 720 count = CFArrayGetCount( userList ); 721 722 for ( index = count - 1; index > -1; index-- ) 723 { 724 CFDictionaryRef dictionary; 725 726 dictionary = CFArrayGetValueAtIndex( userList, index ); 727 728 if ( CFDictionaryGetValue( dictionary, kSCConsoleSessionLoginDone ) == kCFBooleanFalse ) 729 { 730 CFArrayRemoveValueAtIndex( userList, index ); 731 } 732 } 733 734 if ( CFArrayGetCount( userList ) == 0 ) 735 { 736 CFRelease( userList ); 737 738 userList = NULL; 739 } 740 } 741 } 742///w:start 743 else 744 { 745 CFStringRef user; 746 747 user = ___SCDynamicStoreCopyConsoleUser( store, NULL, NULL ); 748 749 if ( user ) 750 { 751 CFMutableDictionaryRef dictionary; 752 753 dictionary = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 754 755 if ( dictionary ) 756 { 757 CFDictionarySetValue( dictionary, kSCConsoleSessionUserName, user ); 758 759 userList = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); 760 761 if ( userList ) 762 { 763 CFArrayAppendValue( userList, dictionary ); 764 } 765 766 CFRelease( dictionary ); 767 } 768 769 CFRelease( user ); 770 } 771 } 772///w:stop 773 774 return userList; 775} 776 777__private_extern__ CFStringRef ___SCDynamicStoreCopyConsoleUser( SCDynamicStoreRef store, uid_t * uid, gid_t * gid ) 778{ 779 CFStringRef user; 780 781 if ( gid ) 782 { 783 *gid = ___GID_WHEEL; 784 } 785 786 if ( uid ) 787 { 788 *uid = ___UID_ROOT; 789 } 790 791 user = SCDynamicStoreCopyConsoleUser( store, uid, gid ); 792///w:start 793 if ( user ) 794 { 795 if ( CFEqual( user, CFSTR( "loginwindow" ) ) ) 796 { 797 if ( gid ) 798 { 799 *gid = ___GID_WHEEL; 800 } 801 802 if ( uid ) 803 { 804 *uid = ___UID_ROOT; 805 } 806 807 CFRelease( user ); 808 809 user = NULL; 810 } 811 } 812///w:stop 813 814 return user; 815} 816