#include "DASupport.h"
#include "vsdb.h"
#include "DABase.h"
#include "DAFileSystem.h"
#include "DAInternal.h"
#include "DALog.h"
#include "DAMain.h"
#include "DAThread.h"
#include <dirent.h>
#include <fsproperties.h>
#include <fstab.h>
#include <libgen.h>
#include <pthread.h>
#include <sys/loadable_fs.h>
#include <sys/stat.h>
#include <SystemConfiguration/SystemConfiguration.h>
struct __DAAuthorizeWithCallbackContext
{
DAAuthorizeCallback callback;
void * callbackContext;
DADiskRef disk;
_DAAuthorizeOptions options;
char * right;
DASessionRef session;
DAReturn status;
gid_t userGID;
uid_t userUID;
};
typedef struct __DAAuthorizeWithCallbackContext __DAAuthorizeWithCallbackContext;
static pthread_mutex_t __gDAAuthorizeWithCallbackLock = PTHREAD_MUTEX_INITIALIZER;
int __DAAuthorizeWithCallback( void * parameter )
{
__DAAuthorizeWithCallbackContext * context = parameter;
pthread_mutex_lock( &__gDAAuthorizeWithCallbackLock );
context->status = DAAuthorize( context->session, context->options, context->disk, context->userUID, context->userGID, context->right );
pthread_mutex_unlock( &__gDAAuthorizeWithCallbackLock );
return 0;
}
void __DAAuthorizeWithCallbackCallback( int status, void * parameter )
{
__DAAuthorizeWithCallbackContext * context = parameter;
( context->callback )( context->status, context->callbackContext );
if ( context->disk ) CFRelease( context->disk );
if ( context->session ) CFRelease( context->session );
free( context->right );
free( context );
}
DAReturn DAAuthorize( DASessionRef session,
_DAAuthorizeOptions options,
DADiskRef disk,
uid_t userUID,
gid_t userGID,
const char * right )
{
DAReturn status;
status = kDAReturnNotPrivileged;
if ( status )
{
if ( ( options & _kDAAuthorizeOptionIsOwner ) )
{
uid_t diskUID;
diskUID = DADiskGetUserUID( disk );
if ( diskUID == userUID )
{
status = kDAReturnSuccess;
}
}
}
if ( status )
{
AuthorizationRef authorization;
authorization = NULL;
if ( session == NULL )
{
CFIndex count;
CFIndex index;
count = CFArrayGetCount( gDASessionList );
for ( index = 0; index < count; index++, session = NULL )
{
session = ( void * ) CFArrayGetValueAtIndex( gDASessionList, index );
if ( strcmp( _DASessionGetName( session ), "SystemUIServer" ) == 0 )
{
break;
}
}
}
if ( session )
authorization = DASessionGetAuthorization( session );
if ( authorization )
{
AuthorizationFlags flags;
AuthorizationItem item;
char * name;
AuthorizationRights rights;
flags = kAuthorizationFlagExtendRights;
if ( ( options & _kDAAuthorizeOptionAuthenticateAdministrator ) )
{
flags |= kAuthorizationFlagInteractionAllowed;
}
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue )
{
asprintf( &name, "system.volume.removable.%s", right );
}
else
{
if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
{
asprintf( &name, "system.volume.internal.%s", right );
}
else
{
asprintf( &name, "system.volume.external.%s", right );
}
}
if ( name )
{
item.flags = 0;
item.name = name;
item.value = NULL;
item.valueLength = 0;
rights.count = 1;
rights.items = &item;
status = AuthorizationCopyRights( authorization, &rights, NULL, flags, NULL );
if ( status )
{
status = kDAReturnNotPrivileged;
}
free( name );
}
}
}
return status;
}
void DAAuthorizeWithCallback( DASessionRef session,
_DAAuthorizeOptions options,
DADiskRef disk,
uid_t userUID,
gid_t userGID,
DAAuthorizeCallback callback,
void * callbackContext,
const char * right )
{
DAReturn status;
status = DAAuthorize( session, ( options & ~_kDAAuthorizeOptionAuthenticateAdministrator ), disk, userUID, userGID, right );
if ( status )
{
__DAAuthorizeWithCallbackContext * context;
context = malloc( sizeof( __DAAuthorizeWithCallbackContext ) );
if ( context )
{
if ( disk ) CFRetain( disk );
if ( session ) CFRetain( session );
context->callback = callback;
context->callbackContext = callbackContext;
context->disk = disk;
context->options = options;
context->right = strdup( right );
context->session = session;
context->status = kDAReturnNotPrivileged;
context->userGID = userGID;
context->userUID = userUID;
DAThreadExecute( __DAAuthorizeWithCallback, context, __DAAuthorizeWithCallbackCallback, context );
}
else
{
( callback )( kDAReturnNotPrivileged, callbackContext );
}
}
else
{
( callback )( kDAReturnSuccess, callbackContext );
}
}
static struct timespec __gDAFileSystemListTime = { 0, 0 };
const CFStringRef kDAFileSystemKey = CFSTR( "DAFileSystem" );
static void __DAFileSystemProbeListAppendValue( const void * key, const void * value, void * context )
{
CFMutableDictionaryRef probe;
probe = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, value );
if ( probe )
{
CFDictionarySetValue( probe, kDAFileSystemKey, context );
CFArrayAppendValue( gDAFileSystemProbeList, probe );
CFRelease( probe );
}
}
static CFComparisonResult __DAFileSystemProbeListCompare( const void * value1, const void * value2, void * context )
{
CFNumberRef order1 = CFDictionaryGetValue( value1, CFSTR( kFSProbeOrderKey ) );
CFNumberRef order2 = CFDictionaryGetValue( value2, CFSTR( kFSProbeOrderKey ) );
if ( order1 == NULL ) return kCFCompareGreaterThan;
if ( order2 == NULL ) return kCFCompareLessThan;
return CFNumberCompare( order1, order2, NULL );
}
void DAFileSystemListRefresh( void )
{
struct stat status;
if ( stat( FS_DIR_LOCATION, &status ) == 0 )
{
if ( __gDAFileSystemListTime.tv_sec != status.st_mtimespec.tv_sec ||
__gDAFileSystemListTime.tv_nsec != status.st_mtimespec.tv_nsec )
{
CFURLRef base;
__gDAFileSystemListTime.tv_sec = status.st_mtimespec.tv_sec;
__gDAFileSystemListTime.tv_nsec = status.st_mtimespec.tv_nsec;
CFArrayRemoveAllValues( gDAFileSystemList );
CFArrayRemoveAllValues( gDAFileSystemProbeList );
base = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, CFSTR( FS_DIR_LOCATION ), kCFURLPOSIXPathStyle, TRUE );
if ( base )
{
DIR * folder;
folder = opendir( FS_DIR_LOCATION );
if ( folder )
{
struct dirent * item;
DALogDebugHeader( "filesystems have been refreshed." );
while ( ( item = readdir( folder ) ) )
{
char * suffix;
suffix = item->d_name + strlen( item->d_name ) - strlen( FS_DIR_SUFFIX );
if ( suffix > item->d_name )
{
if ( strcmp( suffix, FS_DIR_SUFFIX ) == 0 )
{
CFURLRef path;
path = CFURLCreateFromFileSystemRepresentationRelativeToBase( kCFAllocatorDefault,
( void * ) item->d_name,
strlen( item->d_name ),
TRUE,
base );
if ( path )
{
DAFileSystemRef filesystem;
filesystem = DAFileSystemCreate( kCFAllocatorDefault, path );
if ( filesystem )
{
CFDictionaryRef probe;
DALogDebug( " created filesystem, id = %@.", filesystem );
CFArrayAppendValue( gDAFileSystemList, filesystem );
probe = DAFileSystemGetProbeList( filesystem );
if ( probe )
{
CFDictionaryApplyFunction( probe, __DAFileSystemProbeListAppendValue, filesystem );
}
CFRelease( filesystem );
}
CFRelease( path );
}
}
}
}
closedir( folder );
}
CFRelease( base );
}
CFArraySortValues( gDAFileSystemProbeList,
CFRangeMake( 0, CFArrayGetCount( gDAFileSystemProbeList ) ),
__DAFileSystemProbeListCompare,
NULL );
}
}
}
static struct timespec __gDAMountMapListTime1 = { 0, 0 };
static struct timespec __gDAMountMapListTime2 = { 0, 0 };
const CFStringRef kDAMountMapMountAutomaticKey = CFSTR( "DAMountAutomatic" );
const CFStringRef kDAMountMapMountOptionsKey = CFSTR( "DAMountOptions" );
const CFStringRef kDAMountMapMountPathKey = CFSTR( "DAMountPath" );
const CFStringRef kDAMountMapProbeIDKey = CFSTR( "DAProbeID" );
const CFStringRef kDAMountMapProbeKindKey = CFSTR( "DAProbeKind" );
static CFDictionaryRef __DAMountMapCreate1( CFAllocatorRef allocator, struct fstab * fs )
{
CFMutableDictionaryRef map = NULL;
if ( strcmp( fs->fs_type, FSTAB_SW ) )
{
char * idAsCString = fs->fs_spec;
strsep( &idAsCString, "=" );
if ( idAsCString )
{
CFStringRef idAsString;
idAsString = CFStringCreateWithCString( kCFAllocatorDefault, idAsCString, kCFStringEncodingUTF8 );
if ( idAsString )
{
CFTypeRef id = NULL;
if ( strcmp( fs->fs_spec, "UUID" ) == 0 )
{
id = _DAFileSystemCreateUUIDFromString( kCFAllocatorDefault, idAsString );
}
else if ( strcmp( fs->fs_spec, "LABEL" ) == 0 )
{
id = CFRetain( idAsString );
}
else if ( strcmp( fs->fs_spec, "DEVICE" ) == 0 )
{
id = ___CFDictionaryCreateFromXMLString( kCFAllocatorDefault, idAsString );
}
if ( id )
{
map = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if ( map )
{
CFMutableStringRef options;
options = CFStringCreateMutable( kCFAllocatorDefault, 0 );
if ( options )
{
char * argument = NULL;
char * arguments = fs->fs_mntops;
CFBooleanRef automatic = NULL;
while ( ( argument = strsep( &arguments, "," ) ) )
{
if ( strcmp( argument, "auto" ) == 0 )
{
automatic = kCFBooleanTrue;
}
else if ( strcmp( argument, "noauto" ) == 0 )
{
automatic = kCFBooleanFalse;
}
else
{
CFStringAppendCString( options, argument, kCFStringEncodingUTF8 );
CFStringAppendCString( options, ",", kCFStringEncodingUTF8 );
}
}
if ( automatic )
{
CFDictionarySetValue( map, kDAMountMapMountAutomaticKey, automatic );
}
if ( CFStringGetLength( options ) )
{
CFStringTrim( options, CFSTR( "," ) );
CFDictionarySetValue( map, kDAMountMapMountOptionsKey, options );
}
CFRelease( options );
}
if ( strcmp( fs->fs_file, "none" ) )
{
CFURLRef path;
path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) fs->fs_file, strlen( fs->fs_file ), TRUE );
if ( path )
{
CFDictionarySetValue( map, kDAMountMapMountPathKey, path );
CFRelease( path );
}
}
if ( strcmp( fs->fs_vfstype, "auto" ) )
{
CFStringRef kind;
kind = CFStringCreateWithCString( kCFAllocatorDefault, fs->fs_vfstype, kCFStringEncodingUTF8 );
if ( kind )
{
CFDictionarySetValue( map, kDAMountMapProbeKindKey, kind );
CFRelease( kind );
}
}
CFDictionarySetValue( map, kDAMountMapProbeIDKey, id );
}
CFRelease( id );
}
CFRelease( idAsString );
}
}
}
return map;
}
void DAMountMapListRefresh1( void )
{
struct stat status;
if ( stat( _PATH_FSTAB, &status ) == 0 )
{
if ( __gDAMountMapListTime1.tv_sec != status.st_mtimespec.tv_sec ||
__gDAMountMapListTime1.tv_nsec != status.st_mtimespec.tv_nsec )
{
__gDAMountMapListTime1.tv_sec = status.st_mtimespec.tv_sec;
__gDAMountMapListTime1.tv_nsec = status.st_mtimespec.tv_nsec;
CFArrayRemoveAllValues( gDAMountMapList1 );
if ( setfsent( ) )
{
struct fstab * item;
while ( ( item = getfsent( ) ) )
{
CFDictionaryRef map;
map = __DAMountMapCreate1( kCFAllocatorDefault, item );
if ( map )
{
CFArrayAppendValue( gDAMountMapList1, map );
CFRelease( map );
}
}
endfsent( );
}
}
}
}
static CFDictionaryRef __DAMountMapCreate2( CFAllocatorRef allocator, struct vsdb * vs )
{
CFStringRef idAsString;
CFMutableDictionaryRef map = NULL;
idAsString = CFStringCreateWithCString( kCFAllocatorDefault, vs->vs_spec, kCFStringEncodingUTF8 );
if ( idAsString )
{
CFTypeRef id;
id = _DAFileSystemCreateUUIDFromString( kCFAllocatorDefault, idAsString );
if ( id )
{
map = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if ( map )
{
CFMutableStringRef options;
options = CFStringCreateMutable( kCFAllocatorDefault, 0 );
if ( options )
{
if ( ( vs->vs_ops & VSDB_PERM ) )
{
CFStringAppend( options, CFSTR( "owners" ) );
CFStringAppend( options, CFSTR( "," ) );
}
else
{
CFStringAppend( options, CFSTR( "noowners" ) );
CFStringAppend( options, CFSTR( "," ) );
}
if ( CFStringGetLength( options ) )
{
CFStringTrim( options, CFSTR( "," ) );
CFDictionarySetValue( map, kDAMountMapMountOptionsKey, options );
}
CFRelease( options );
}
CFDictionarySetValue( map, kDAMountMapProbeIDKey, id );
}
CFRelease( id );
}
CFRelease( idAsString );
}
return map;
}
void DAMountMapListRefresh2( void )
{
struct stat status;
if ( stat( _PATH_VSDB, &status ) == 0 )
{
if ( __gDAMountMapListTime2.tv_sec != status.st_mtimespec.tv_sec ||
__gDAMountMapListTime2.tv_nsec != status.st_mtimespec.tv_nsec )
{
__gDAMountMapListTime2.tv_sec = status.st_mtimespec.tv_sec;
__gDAMountMapListTime2.tv_nsec = status.st_mtimespec.tv_nsec;
CFArrayRemoveAllValues( gDAMountMapList2 );
if ( setvsent( ) )
{
struct vsdb * item;
while ( ( item = getvsent( ) ) )
{
CFDictionaryRef map;
map = __DAMountMapCreate2( kCFAllocatorDefault, item );
if ( map )
{
CFArrayAppendValue( gDAMountMapList2, map );
CFRelease( map );
}
}
endvsent( );
}
}
}
}
static struct timespec __gDAPreferenceListTime = { 0, 0 };
const CFStringRef kDAPreferenceMountDeferExternalKey = CFSTR( "DAMountDeferExternal" );
const CFStringRef kDAPreferenceMountDeferInternalKey = CFSTR( "DAMountDeferInternal" );
const CFStringRef kDAPreferenceMountDeferRemovableKey = CFSTR( "DAMountDeferRemovable" );
const CFStringRef kDAPreferenceMountTrustExternalKey = CFSTR( "DAMountTrustExternal" );
const CFStringRef kDAPreferenceMountTrustInternalKey = CFSTR( "DAMountTrustInternal" );
const CFStringRef kDAPreferenceMountTrustRemovableKey = CFSTR( "DAMountTrustRemovable" );
void DAPreferenceListRefresh( void )
{
struct stat status;
if ( stat( ___PREFS_DEFAULT_DIR, &status ) == 0 )
{
if ( __gDAPreferenceListTime.tv_sec != status.st_mtimespec.tv_sec ||
__gDAPreferenceListTime.tv_nsec != status.st_mtimespec.tv_nsec )
{
SCPreferencesRef preferences;
__gDAPreferenceListTime.tv_sec = status.st_mtimespec.tv_sec;
__gDAPreferenceListTime.tv_nsec = status.st_mtimespec.tv_nsec;
CFDictionaryRemoveAllValues( gDAPreferenceList );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey, kCFBooleanTrue );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferInternalKey, kCFBooleanFalse );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, kCFBooleanTrue );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey, kCFBooleanFalse );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustInternalKey, kCFBooleanTrue );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustRemovableKey, kCFBooleanFalse );
preferences = SCPreferencesCreate( kCFAllocatorDefault, CFSTR( "autodiskmount" ), CFSTR( "autodiskmount.xml" ) );
if ( preferences )
{
CFTypeRef value;
value = SCPreferencesGetValue( preferences, CFSTR( "AutomountDisksWithoutUserLogin" ) );
if ( value == kCFBooleanTrue )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey, kCFBooleanFalse );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, kCFBooleanFalse );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey, kCFBooleanTrue );
}
else if ( value == kCFBooleanFalse )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey, kCFBooleanFalse );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, kCFBooleanTrue );
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey, kCFBooleanTrue );
}
CFRelease( preferences );
}
preferences = SCPreferencesCreate( kCFAllocatorDefault, CFSTR( _kDADaemonName ), CFSTR( _kDADaemonName ".plist" ) );
if ( preferences )
{
CFTypeRef value;
value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferExternalKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey, value );
}
}
value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferInternalKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferInternalKey, value );
}
}
value = SCPreferencesGetValue( preferences, kDAPreferenceMountDeferRemovableKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey, value );
}
}
value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustExternalKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey, value );
}
}
value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustInternalKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustInternalKey, value );
}
}
value = SCPreferencesGetValue( preferences, kDAPreferenceMountTrustRemovableKey );
if ( value )
{
if ( CFGetTypeID( value ) == CFBooleanGetTypeID( ) )
{
CFDictionarySetValue( gDAPreferenceList, kDAPreferenceMountTrustRemovableKey, value );
}
}
CFRelease( preferences );
}
}
}
}
struct __DAUnit
{
DAUnitState state;
};
typedef struct __DAUnit __DAUnit;
Boolean DAUnitGetState( DADiskRef disk, DAUnitState state )
{
CFNumberRef key;
key = DADiskGetDescription( disk, kDADiskDescriptionMediaBSDUnitKey );
if ( key )
{
CFMutableDataRef data;
data = ( CFMutableDataRef ) CFDictionaryGetValue( gDAUnitList, key );
if ( data )
{
__DAUnit * unit;
unit = ( void * ) CFDataGetMutableBytePtr( data );
return ( unit->state & state ) ? TRUE : FALSE;
}
}
return FALSE;
}
void DAUnitSetState( DADiskRef disk, DAUnitState state, Boolean value )
{
CFNumberRef key;
key = DADiskGetDescription( disk, kDADiskDescriptionMediaBSDUnitKey );
if ( key )
{
CFMutableDataRef data;
data = ( CFMutableDataRef ) CFDictionaryGetValue( gDAUnitList, key );
if ( data )
{
__DAUnit * unit;
unit = ( void * ) CFDataGetMutableBytePtr( data );
unit->state &= ~state;
unit->state |= value ? state : 0;
}
else
{
data = CFDataCreateMutable( kCFAllocatorDefault, sizeof( __DAUnit ) );
if ( data )
{
__DAUnit * unit;
unit = ( void * ) CFDataGetMutableBytePtr( data );
unit->state = value ? state : 0;
CFDictionarySetValue( gDAUnitList, key, data );
CFRelease( data );
}
}
}
}