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