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 "DASupport.h"
25
26#include "vsdb.h"
27#include "DABase.h"
28#include "DAFileSystem.h"
29#include "DAInternal.h"
30#include "DALog.h"
31#include "DAMain.h"
32#include "DAThread.h"
33
34#include <dirent.h>
35#include <fsproperties.h>
36#include <fstab.h>
37#include <libgen.h>
38#include <pthread.h>
39#include <sys/loadable_fs.h>
40#include <sys/stat.h>
41#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
42#include <SystemConfiguration/SystemConfiguration.h>
43
44struct __DAAuthorizeWithCallbackContext
45{
46    DAAuthorizeCallback callback;
47    void *              callbackContext;
48    DADiskRef           disk;
49    _DAAuthorizeOptions options;
50    char *              right;
51    DASessionRef        session;
52    DAReturn            status;
53    gid_t               userGID;
54    uid_t               userUID;
55};
56
57typedef struct __DAAuthorizeWithCallbackContext __DAAuthorizeWithCallbackContext;
58
59static pthread_mutex_t __gDAAuthorizeWithCallbackLock = PTHREAD_MUTEX_INITIALIZER;
60
61int __DAAuthorizeWithCallback( void * parameter )
62{
63    __DAAuthorizeWithCallbackContext * context = parameter;
64
65    pthread_mutex_lock( &__gDAAuthorizeWithCallbackLock );
66
67    context->status = DAAuthorize( context->session, context->options, context->disk, context->userUID, context->userGID, context->right );
68
69    pthread_mutex_unlock( &__gDAAuthorizeWithCallbackLock );
70
71    return 0;
72}
73
74void __DAAuthorizeWithCallbackCallback( int status, void * parameter )
75{
76    __DAAuthorizeWithCallbackContext * context = parameter;
77
78    ( context->callback )( context->status, context->callbackContext );
79
80    if ( context->disk    )  CFRelease( context->disk );
81    if ( context->session )  CFRelease( context->session );
82
83    free( context->right );
84    free( context );
85}
86
87DAReturn DAAuthorize( DASessionRef        session,
88                      _DAAuthorizeOptions options,
89                      DADiskRef           disk,
90                      uid_t               userUID,
91                      gid_t               userGID,
92                      const char *        right )
93{
94    DAReturn status;
95
96    status = kDAReturnNotPrivileged;
97
98    if ( status )
99    {
100        if ( ( options & _kDAAuthorizeOptionIsOwner ) )
101        {
102            uid_t diskUID;
103
104            diskUID = DADiskGetUserUID( disk );
105
106            if ( diskUID == userUID )
107            {
108                status = kDAReturnSuccess;
109            }
110        }
111    }
112
113    if ( status )
114    {
115        AuthorizationRef authorization;
116
117        authorization = DASessionGetAuthorization( session );
118
119        if ( authorization )
120        {
121            AuthorizationFlags  flags;
122            AuthorizationItem   item;
123            char *              name;
124            AuthorizationRights rights;
125
126            flags = kAuthorizationFlagExtendRights;
127
128            if ( ( options & _kDAAuthorizeOptionAuthenticateAdministrator ) )
129            {
130                flags |= kAuthorizationFlagInteractionAllowed;
131
132                asprintf( &name, "system.volume.workgroup.%s", right );
133            }
134            else
135            {
136                if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeNetworkKey ) == kCFBooleanTrue )
137                {
138                    asprintf( &name, "system.volume.network.%s", right );
139                }
140                else
141                {
142                    CFTypeRef object;
143
144                    object = DADiskGetDescription( disk, kDADiskDescriptionDeviceProtocolKey );
145
146                    if ( object && CFEqual( object, CFSTR( kIOPropertyPhysicalInterconnectTypeVirtual ) ) )
147                    {
148                        asprintf( &name, "system.volume.virtual.%s", right );
149                    }
150                    else
151                    {
152                        if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue )
153                        {
154                            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaTypeKey ) )
155                            {
156                                asprintf( &name, "system.volume.optical.%s", right );
157                            }
158                            else
159                            {
160                                asprintf( &name, "system.volume.removable.%s", right );
161                            }
162                        }
163                        else
164                        {
165                            if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
166                            {
167                                asprintf( &name, "system.volume.internal.%s", right );
168                            }
169                            else
170                            {
171                                asprintf( &name, "system.volume.external.%s", right );
172                            }
173                        }
174                    }
175                }
176            }
177
178            if ( name )
179            {
180                item.flags       = 0;
181                item.name        = name;
182                item.value       = NULL;
183                item.valueLength = 0;
184
185                rights.count = 1;
186                rights.items = &item;
187
188                status = AuthorizationCopyRights( authorization, &rights, NULL, flags, NULL );
189
190                if ( status )
191                {
192                    status = kDAReturnNotPrivileged;
193                }
194
195                free( name );
196            }
197        }
198    }
199
200    return status;
201}
202
203void DAAuthorizeWithCallback( DASessionRef        session,
204                              _DAAuthorizeOptions options,
205                              DADiskRef           disk,
206                              uid_t               userUID,
207                              gid_t               userGID,
208                              DAAuthorizeCallback callback,
209                              void *              callbackContext,
210                              const char *        right )
211{
212    __DAAuthorizeWithCallbackContext * context;
213
214    context = malloc( sizeof( __DAAuthorizeWithCallbackContext ) );
215
216    if ( context )
217    {
218        if ( disk    )  CFRetain( disk );
219        if ( session )  CFRetain( session );
220
221        context->callback        = callback;
222        context->callbackContext = callbackContext;
223        context->disk            = disk;
224        context->options         = options;
225        context->right           = strdup( right );
226        context->session         = session;
227        context->status          = kDAReturnNotPrivileged;
228        context->userGID         = userGID;
229        context->userUID         = userUID;
230
231        DAThreadExecute( __DAAuthorizeWithCallback, context, __DAAuthorizeWithCallbackCallback, context );
232    }
233    else
234    {
235        ( callback )( kDAReturnNotPrivileged, callbackContext );
236    }
237}
238
239static struct timespec __gDAFileSystemListTime = { 0, 0 };
240
241const CFStringRef kDAFileSystemKey = CFSTR( "DAFileSystem" );
242
243static void __DAFileSystemProbeListAppendValue( const void * key, const void * value, void * context )
244{
245    CFMutableDictionaryRef probe;
246
247    probe = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, value );
248
249    if ( probe )
250    {
251        CFDictionarySetValue( probe, kDAFileSystemKey, context );
252        CFArrayAppendValue( gDAFileSystemProbeList, probe );
253        CFRelease( probe );
254    }
255}
256
257static CFComparisonResult __DAFileSystemProbeListCompare( const void * value1, const void * value2, void * context )
258{
259    CFNumberRef order1 = CFDictionaryGetValue( value1, CFSTR( kFSProbeOrderKey ) );
260    CFNumberRef order2 = CFDictionaryGetValue( value2, CFSTR( kFSProbeOrderKey ) );
261
262    if ( order1 == NULL )  return kCFCompareGreaterThan;
263    if ( order2 == NULL )  return kCFCompareLessThan;
264
265    return CFNumberCompare( order1, order2, NULL );
266}
267
268void DAFileSystemListRefresh( void )
269{
270    struct stat status;
271
272    /*
273     * Determine whether the file system list is up-to-date.
274     */
275
276    if ( stat( FS_DIR_LOCATION, &status ) )
277    {
278        __gDAFileSystemListTime.tv_sec  = 0;
279        __gDAFileSystemListTime.tv_nsec = 0;
280    }
281
282    if ( __gDAFileSystemListTime.tv_sec  != status.st_mtimespec.tv_sec  ||
283         __gDAFileSystemListTime.tv_nsec != status.st_mtimespec.tv_nsec )
284    {
285        CFURLRef base;
286
287        __gDAFileSystemListTime.tv_sec  = status.st_mtimespec.tv_sec;
288        __gDAFileSystemListTime.tv_nsec = status.st_mtimespec.tv_nsec;
289
290        /*
291         * Clear the file system list.
292         */
293
294        CFArrayRemoveAllValues( gDAFileSystemList );
295        CFArrayRemoveAllValues( gDAFileSystemProbeList );
296
297        /*
298         * Build the file system list.
299         */
300
301        base = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, CFSTR( FS_DIR_LOCATION ), kCFURLPOSIXPathStyle, TRUE );
302
303        if ( base )
304        {
305            DIR * folder;
306
307            /*
308             * Scan the filesystems in the file system folder.
309             */
310
311            folder = opendir( FS_DIR_LOCATION );
312
313            if ( folder )
314            {
315                struct dirent * item;
316
317                DALogDebugHeader( "filesystems have been refreshed." );
318
319                while ( ( item = readdir( folder ) ) )
320                {
321                    char * suffix;
322
323                    suffix = item->d_name + strlen( item->d_name ) - strlen( FS_DIR_SUFFIX );
324
325                    if ( suffix > item->d_name )
326                    {
327                        if ( strcmp( suffix, FS_DIR_SUFFIX ) == 0 )
328                        {
329                            CFURLRef path;
330
331                            path = CFURLCreateFromFileSystemRepresentationRelativeToBase( kCFAllocatorDefault,
332                                                                                          ( void * ) item->d_name,
333                                                                                          strlen( item->d_name ),
334                                                                                          TRUE,
335                                                                                          base );
336
337                            if ( path )
338                            {
339                                DAFileSystemRef filesystem;
340
341                                /*
342                                 * Create a file system object for this file system.
343                                 */
344
345                                filesystem = DAFileSystemCreate( kCFAllocatorDefault, path );
346
347                                if ( filesystem )
348                                {
349                                    CFDictionaryRef probe;
350
351                                    /*
352                                     * Add this file system object to our list.
353                                     */
354
355                                    DALogDebug( "  created filesystem, id = %@.", filesystem );
356
357                                    CFArrayAppendValue( gDAFileSystemList, filesystem );
358
359                                    probe = DAFileSystemGetProbeList( filesystem );
360
361                                    if ( probe )
362                                    {
363                                        CFDictionaryApplyFunction( probe, __DAFileSystemProbeListAppendValue, filesystem );
364                                    }
365
366                                    CFRelease( filesystem );
367                                }
368
369                                CFRelease( path );
370                            }
371                        }
372                    }
373                }
374
375                closedir( folder );
376            }
377
378            CFRelease( base );
379        }
380
381        /*
382         * Order the probe list.
383         */
384
385        CFArraySortValues( gDAFileSystemProbeList,
386                           CFRangeMake( 0, CFArrayGetCount( gDAFileSystemProbeList ) ),
387                           __DAFileSystemProbeListCompare,
388                           NULL );
389    }
390}
391
392static struct timespec __gDAMountMapListTime1 = { 0, 0 };
393static struct timespec __gDAMountMapListTime2 = { 0, 0 };
394
395const CFStringRef kDAMountMapMountAutomaticKey = CFSTR( "DAMountAutomatic" );
396const CFStringRef kDAMountMapMountOptionsKey   = CFSTR( "DAMountOptions"   );
397const CFStringRef kDAMountMapMountPathKey      = CFSTR( "DAMountPath"      );
398const CFStringRef kDAMountMapProbeIDKey        = CFSTR( "DAProbeID"        );
399const CFStringRef kDAMountMapProbeKindKey      = CFSTR( "DAProbeKind"      );
400
401static CFDictionaryRef __DAMountMapCreate1( CFAllocatorRef allocator, struct fstab * fs )
402{
403    CFMutableDictionaryRef map = NULL;
404
405    if ( strcmp( fs->fs_type, FSTAB_SW ) )
406    {
407        char * idAsCString = fs->fs_spec;
408
409        strsep( &idAsCString, "=" );
410
411        if ( idAsCString )
412        {
413            CFStringRef idAsString;
414
415            idAsString = CFStringCreateWithCString( kCFAllocatorDefault, idAsCString, kCFStringEncodingUTF8 );
416
417            if ( idAsString )
418            {
419                CFTypeRef id = NULL;
420
421                if ( strcmp( fs->fs_spec, "UUID" ) == 0 )
422                {
423                    id = ___CFUUIDCreateFromString( kCFAllocatorDefault, idAsString );
424                }
425                else if ( strcmp( fs->fs_spec, "LABEL" ) == 0 )
426                {
427                    id = CFRetain( idAsString );
428                }
429                else if ( strcmp( fs->fs_spec, "DEVICE" ) == 0 )
430                {
431                    id = ___CFDictionaryCreateFromXMLString( kCFAllocatorDefault, idAsString );
432                }
433
434                if ( id )
435                {
436                    map = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
437
438                    if ( map )
439                    {
440                        CFMutableStringRef options;
441
442                        options = CFStringCreateMutable( kCFAllocatorDefault, 0 );
443
444                        if ( options )
445                        {
446                            char *       argument  = NULL;
447                            char *       arguments = fs->fs_mntops;
448                            CFBooleanRef automatic = NULL;
449
450                            while ( ( argument = strsep( &arguments, "," ) ) )
451                            {
452                                if ( strcmp( argument, "auto" ) == 0 )
453                                {
454                                    automatic = kCFBooleanTrue;
455                                }
456                                else if ( strcmp( argument, "noauto" ) == 0 )
457                                {
458                                    automatic = kCFBooleanFalse;
459                                }
460                                else
461                                {
462                                    CFStringAppendCString( options, argument, kCFStringEncodingUTF8 );
463                                    CFStringAppendCString( options, ",", kCFStringEncodingUTF8 );
464                                }
465                            }
466
467                            if ( automatic )
468                            {
469                                CFDictionarySetValue( map, kDAMountMapMountAutomaticKey, automatic );
470                            }
471
472                            if ( CFStringGetLength( options ) )
473                            {
474                                CFStringTrim( options, CFSTR( "," ) );
475
476                                CFDictionarySetValue( map, kDAMountMapMountOptionsKey, options );
477                            }
478
479                            CFRelease( options );
480                        }
481
482                        if ( strcmp( fs->fs_file, "none" ) )
483                        {
484                            CFURLRef path;
485
486                            path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) fs->fs_file, strlen( fs->fs_file ), TRUE );
487
488                            if ( path )
489                            {
490                                CFDictionarySetValue( map, kDAMountMapMountPathKey, path );
491
492                                CFRelease( path );
493                            }
494                        }
495
496                        if ( strcmp( fs->fs_vfstype, "auto" ) )
497                        {
498                            CFStringRef kind;
499
500                            kind = CFStringCreateWithCString( kCFAllocatorDefault, fs->fs_vfstype, kCFStringEncodingUTF8 );
501
502                            if ( kind )
503                            {
504                                CFDictionarySetValue( map, kDAMountMapProbeKindKey, kind );
505
506                                CFRelease( kind );
507                            }
508                        }
509
510                        CFDictionarySetValue( map, kDAMountMapProbeIDKey, id );
511                    }
512
513                    CFRelease( id );
514                }
515
516                CFRelease( idAsString );
517            }
518        }
519    }
520
521    return map;
522}
523
524void DAMountMapListRefresh1( void )
525{
526    struct stat status;
527
528    /*
529     * Determine whether the mount map list is up-to-date.
530     */
531
532    if ( stat( _PATH_FSTAB, &status ) )
533    {
534        __gDAMountMapListTime1.tv_sec  = 0;
535        __gDAMountMapListTime1.tv_nsec = 0;
536    }
537
538    if ( __gDAMountMapListTime1.tv_sec  != status.st_mtimespec.tv_sec  ||
539         __gDAMountMapListTime1.tv_nsec != status.st_mtimespec.tv_nsec )
540    {
541        __gDAMountMapListTime1.tv_sec  = status.st_mtimespec.tv_sec;
542        __gDAMountMapListTime1.tv_nsec = status.st_mtimespec.tv_nsec;
543
544        /*
545         * Clear the mount map list.
546         */
547
548        CFArrayRemoveAllValues( gDAMountMapList1 );
549
550        /*
551         * Build the mount map list.
552         */
553
554        if ( setfsent( ) )
555        {
556            struct fstab * item;
557
558            while ( ( item = getfsent( ) ) )
559            {
560                CFDictionaryRef map;
561
562                map = __DAMountMapCreate1( kCFAllocatorDefault, item );
563
564                if ( map )
565                {
566                    CFArrayAppendValue( gDAMountMapList1, map );
567
568                    CFRelease( map );
569                }
570            }
571
572            endfsent( );
573        }
574    }
575}
576
577static CFDictionaryRef __DAMountMapCreate2( CFAllocatorRef allocator, struct vsdb * vs )
578{
579    CFStringRef            idAsString;
580    CFMutableDictionaryRef map = NULL;
581
582    idAsString = CFStringCreateWithCString( kCFAllocatorDefault, vs->vs_spec, kCFStringEncodingUTF8 );
583
584    if ( idAsString )
585    {
586        CFTypeRef id;
587
588        id = _DAFileSystemCreateUUIDFromString( kCFAllocatorDefault, idAsString );
589
590        if ( id )
591        {
592            map = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
593
594            if ( map )
595            {
596                CFMutableStringRef options;
597
598                options = CFStringCreateMutable( kCFAllocatorDefault, 0 );
599
600                if ( options )
601                {
602                    if ( ( vs->vs_ops & VSDB_PERM ) )
603                    {
604                        CFStringAppend( options, CFSTR( "owners" ) );
605                        CFStringAppend( options, CFSTR( "," ) );
606                    }
607                    else
608                    {
609                        CFStringAppend( options, CFSTR( "noowners" ) );
610                        CFStringAppend( options, CFSTR( "," ) );
611                    }
612
613                    if ( CFStringGetLength( options ) )
614                    {
615                        CFStringTrim( options, CFSTR( "," ) );
616
617                        CFDictionarySetValue( map, kDAMountMapMountOptionsKey, options );
618                    }
619
620                    CFRelease( options );
621                }
622
623                CFDictionarySetValue( map, kDAMountMapProbeIDKey, id );
624            }
625
626            CFRelease( id );
627        }
628
629        CFRelease( idAsString );
630    }
631
632    return map;
633}
634
635void DAMountMapListRefresh2( void )
636{
637    struct stat status;
638
639    /*
640     * Determine whether the mount map list is up-to-date.
641     */
642
643    if ( stat( _PATH_VSDB, &status ) )
644    {
645        __gDAMountMapListTime2.tv_sec  = 0;
646        __gDAMountMapListTime2.tv_nsec = 0;
647    }
648
649    if ( __gDAMountMapListTime2.tv_sec  != status.st_mtimespec.tv_sec  ||
650         __gDAMountMapListTime2.tv_nsec != status.st_mtimespec.tv_nsec )
651    {
652        __gDAMountMapListTime2.tv_sec  = status.st_mtimespec.tv_sec;
653        __gDAMountMapListTime2.tv_nsec = status.st_mtimespec.tv_nsec;
654
655        /*
656         * Clear the mount map list.
657         */
658
659        CFArrayRemoveAllValues( gDAMountMapList2 );
660
661        /*
662         * Build the mount map list.
663         */
664
665        if ( setvsent( ) )
666        {
667            struct vsdb * item;
668
669            while ( ( item = getvsent( ) ) )
670            {
671                CFDictionaryRef map;
672
673                map = __DAMountMapCreate2( kCFAllocatorDefault, item );
674
675                if ( map )
676                {
677                    CFArrayAppendValue( gDAMountMapList2, map );
678
679                    CFRelease( map );
680                }
681            }
682
683            endvsent( );
684        }
685    }
686}
687
688static struct timespec __gDAPreferenceListTime1 = { 0, 0 };
689static struct timespec __gDAPreferenceListTime2 = { 0, 0 };
690
691const CFStringRef kDAPreferenceMountDeferExternalKey  = CFSTR( "DAMountDeferExternal"  );
692const CFStringRef kDAPreferenceMountDeferInternalKey  = CFSTR( "DAMountDeferInternal"  );
693const CFStringRef kDAPreferenceMountDeferRemovableKey = CFSTR( "DAMountDeferRemovable" );
694const CFStringRef kDAPreferenceMountTrustExternalKey  = CFSTR( "DAMountTrustExternal"  );
695const CFStringRef kDAPreferenceMountTrustInternalKey  = CFSTR( "DAMountTrustInternal"  );
696const CFStringRef kDAPreferenceMountTrustRemovableKey = CFSTR( "DAMountTrustRemovable" );
697
698void DAPreferenceListRefresh( void )
699{
700    struct stat status1;
701    struct stat status2;
702
703    /*
704     * Determine whether the preference list is up-to-date.
705     */
706
707    if ( stat( ___PREFS_DEFAULT_DIR "/" "autodiskmount.plist", &status1 ) )
708    {
709        __gDAPreferenceListTime1.tv_sec  = 0;
710        __gDAPreferenceListTime1.tv_nsec = 0;
711    }
712
713    if ( stat( ___PREFS_DEFAULT_DIR "/" _kDADaemonName ".plist", &status2 ) )
714    {
715        __gDAPreferenceListTime2.tv_sec  = 0;
716        __gDAPreferenceListTime2.tv_nsec = 0;
717    }
718
719    if ( __gDAPreferenceListTime1.tv_sec  != status1.st_mtimespec.tv_sec  ||
720         __gDAPreferenceListTime1.tv_nsec != status1.st_mtimespec.tv_nsec ||
721         __gDAPreferenceListTime2.tv_sec  != status2.st_mtimespec.tv_sec  ||
722         __gDAPreferenceListTime2.tv_nsec != status2.st_mtimespec.tv_nsec )
723    {
724        SCPreferencesRef preferences;
725
726        __gDAPreferenceListTime1.tv_sec  = status1.st_mtimespec.tv_sec;
727        __gDAPreferenceListTime1.tv_nsec = status1.st_mtimespec.tv_nsec;
728        __gDAPreferenceListTime2.tv_sec  = status2.st_mtimespec.tv_sec;
729        __gDAPreferenceListTime2.tv_nsec = status2.st_mtimespec.tv_nsec;
730
731        /*
732         * Clear the preference list.
733         */
734
735        CFDictionaryRemoveAllValues( gDAPreferenceList );
736
737        /*
738         * Build the preference list.
739         */
740
741        preferences = SCPreferencesCreate( kCFAllocatorDefault, CFSTR( "autodiskmount" ), CFSTR( "autodiskmount.plist" ) );
742
743        if ( preferences )
744        {
745            CFTypeRef value;
746
747            value = SCPreferencesGetValue( preferences, CFSTR( "AutomountDisksWithoutUserLogin" ) );
748
749            if ( value == kCFBooleanTrue )
750            {
751                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey,  kCFBooleanFalse );
752                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, kCFBooleanFalse );
753                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey,  kCFBooleanTrue  );
754            }
755            else if ( value == kCFBooleanFalse )
756            {
757                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey,  kCFBooleanFalse );
758                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, kCFBooleanTrue  );
759                CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey,  kCFBooleanTrue  );
760            }
761
762            CFRelease( preferences );
763        }
764
765        preferences = SCPreferencesCreate( kCFAllocatorDefault, CFSTR( _kDADaemonName ), CFSTR( _kDADaemonName ".plist" ) );
766
767        if ( preferences )
768        {
769            CFTypeRef value;
770
771            value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferExternalKey );
772
773            if ( value )
774            {
775                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
776                {
777                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey, value );
778                }
779            }
780
781            value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferInternalKey );
782
783            if ( value )
784            {
785                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
786                {
787                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferInternalKey, value );
788                }
789            }
790
791            value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferRemovableKey );
792
793            if ( value )
794            {
795                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
796                {
797                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, value );
798                }
799            }
800
801            value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustExternalKey );
802
803            if ( value )
804            {
805                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
806                {
807                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey, value );
808                }
809            }
810
811            value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustInternalKey );
812
813            if ( value )
814            {
815                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
816                {
817                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustInternalKey, value );
818                }
819            }
820
821            value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustRemovableKey );
822
823            if ( value )
824            {
825                if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
826                {
827                    CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustRemovableKey, value );
828                }
829            }
830
831            CFRelease( preferences );
832        }
833    }
834}
835
836struct __DAUnit
837{
838    DAUnitState state;
839};
840
841typedef struct __DAUnit __DAUnit;
842
843Boolean DAUnitGetState( DADiskRef disk, DAUnitState state )
844{
845    CFNumberRef key;
846
847    key = DADiskGetDescription( disk, kDADiskDescriptionMediaBSDUnitKey );
848
849    if ( key )
850    {
851        CFMutableDataRef data;
852
853        data = ( CFMutableDataRef ) CFDictionaryGetValue( gDAUnitList, key );
854
855        if ( data )
856        {
857            __DAUnit * unit;
858
859            unit = ( void * ) CFDataGetMutableBytePtr( data );
860
861            return ( unit->state & state ) ? TRUE : FALSE;
862        }
863    }
864
865    return FALSE;
866}
867
868void DAUnitSetState( DADiskRef disk, DAUnitState state, Boolean value )
869{
870    CFNumberRef key;
871
872    key = DADiskGetDescription( disk, kDADiskDescriptionMediaBSDUnitKey );
873
874    if ( key )
875    {
876        CFMutableDataRef data;
877
878        data = ( CFMutableDataRef ) CFDictionaryGetValue( gDAUnitList, key );
879
880        if ( data )
881        {
882            __DAUnit * unit;
883
884            unit = ( void * ) CFDataGetMutableBytePtr( data );
885
886            unit->state &= ~state;
887            unit->state |= value ? state : 0;
888        }
889        else
890        {
891            data = CFDataCreateMutable( kCFAllocatorDefault, sizeof( __DAUnit ) );
892
893            if ( data )
894            {
895                __DAUnit * unit;
896
897                unit = ( void * ) CFDataGetMutableBytePtr( data );
898
899                unit->state = value ? state : 0;
900
901                CFDictionarySetValue( gDAUnitList, key, data );
902
903                CFRelease( data );
904            }
905        }
906    }
907}
908