/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include "DAServer.h" #include "DAServerServer.h" #include "DABase.h" #include "DACallback.h" #include "DADialog.h" #include "DADisk.h" #include "DAFileSystem.h" #include "DAInternal.h" #include "DALog.h" #include "DAMain.h" #include "DAMount.h" #include "DAPrivate.h" #include "DAQueue.h" #include "DASession.h" #include "DAStage.h" #include "DASupport.h" #include #include #include #include #include #include #include #include ///w:start #include #include ///w:stop static CFMachPortRef __gDAServer = NULL; static mach_port_t __gDAServerPort = NULL; static mach_msg_header_t * __gDAServerReply = NULL; static DADiskRef __DADiskListGetDisk( const char * diskID ) { CFIndex count; CFIndex index; count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); if ( strcmp( DADiskGetID( disk ), diskID ) == 0 ) { return disk; } } return NULL; } static DADiskRef __DADiskListGetDiskWithIOMedia( io_service_t media ) { CFIndex count; CFIndex index; count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); if ( IOObjectIsEqualTo( DADiskGetIOMedia( disk ), media ) ) { return disk; } } return NULL; } static void __DAMediaDisappearedUnmountCallback( int status, void * context ) { CFURLRef path = context; DAMountRemoveMountPoint( path ); CFRelease( path ); } static void __DAMediaPropertyChangedCallback( void * context, io_service_t service ) { DADiskRef disk; disk = __DADiskListGetDiskWithIOMedia( service ); if ( disk ) { CFMutableArrayRef keys; keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); if ( keys ) { CFMutableDictionaryRef properties = NULL; IORegistryEntryCreateCFProperties( service, &properties, CFGetAllocator( disk ), 0 ); if ( properties ) { CFTypeRef object; object = CFDictionaryGetValue( properties, CFSTR( kIOMediaContentKey ) ); if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaContentKey, object ) ) { DADiskSetDescription( disk, kDADiskDescriptionMediaContentKey, object ); CFArrayAppendValue( keys, kDADiskDescriptionMediaContentKey ); } if ( CFArrayGetCount( keys ) ) { DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID ); DALogDebug( " updated disk, id = %@.", disk ); if ( DADiskGetState( disk, kDADiskStateStagedAppear ) ) { DADiskDescriptionChangedCallback( disk, keys ); } } CFRelease( properties ); } CFRelease( keys ); } } } static DASessionRef __DASessionListGetSession( mach_port_t sessionID ) { CFIndex count; CFIndex index; count = CFArrayGetCount( gDASessionList ); for ( index = 0; index < count; index++ ) { DASessionRef session; session = ( void * ) CFArrayGetValueAtIndex( gDASessionList, index ); if ( DASessionGetID( session ) == sessionID ) { return session; } } return NULL; } void _DAConfigurationCallback( SCDynamicStoreRef session, CFArrayRef keys, void * info ) { CFStringRef key; DALogDebugHeader( "configd [0] -> %s", gDAProcessNameID ); key = SCDynamicStoreKeyCreateConsoleUser( kCFAllocatorDefault ); assert( key ); if ( ___CFArrayContainsValue( keys, key ) ) { /* * A console user has logged in or logged out. */ gid_t userGID; uid_t userUID; userGID = gDAConsoleUserGID; userUID = gDAConsoleUserUID; if ( gDAConsoleUser ) { CFRelease( gDAConsoleUser ); } gDAConsoleUser = SCDynamicStoreCopyConsoleUser( session, &gDAConsoleUserUID, &gDAConsoleUserGID ); if ( gDAConsoleUser ) { CFIndex count; CFIndex index; ///w:start CFArrayRef users; users = SCDynamicStoreCopyConsoleInformation( session ); ///w:stop DALogDebug( " console user = %@ [%d].", gDAConsoleUser, gDAConsoleUserUID ); /* * A console user has logged in. */ count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); ///w:start /* * Set the BSD permissions for this media object. */ if ( DADiskGetUserRUID( disk ) == ___UID_UNKNOWN ) { mode_t deviceMode; uid_t deviceUser; deviceMode = 0640; deviceUser = gDAConsoleUserUID; if ( users ) { if ( CFArrayGetCount( users ) > 1 ) { deviceMode = 0666; deviceUser = ___UID_ROOT; } } if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse ) { deviceMode &= 0444; } chmod( DADiskGetBSDPath( disk, TRUE ), deviceMode ); chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode ); chown( DADiskGetBSDPath( disk, TRUE ), deviceUser, -1 ); chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 ); } if ( users ) { if ( session ) { continue; } } ///w:stop /* * Mount this volume. */ if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue ) { if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) ) { DADiskMount( disk, NULL, CFSTR( "automatic" ), NULL ); } } } DAStageSignal( ); ///w:start if ( users ) { CFRelease( users ); } ///w:stop } else { CFIndex count; CFIndex index; DALogDebug( " console user = none." ); /* * A console user has logged out. */ count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); ///w:start /* * Set the BSD permissions for this media object. */ if ( DADiskGetUserRUID( disk ) == ___UID_UNKNOWN ) { mode_t deviceMode; uid_t deviceUser; deviceMode = 0640; deviceUser = ___UID_ROOT; if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse ) { deviceMode &= 0444; } chmod( DADiskGetBSDPath( disk, TRUE ), deviceMode ); chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode ); chown( DADiskGetBSDPath( disk, TRUE ), deviceUser, -1 ); chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 ); } ///w:stop /* * Unmount this volume. */ if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue ) { if ( DADiskGetOption( disk, kDADiskOptionEjectUponLogout ) ) { DADiskUnmount( disk, NULL ); DADiskEject( disk, NULL ); } else if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) ) { DADiskUnmount( disk, NULL ); } else { if ( DADiskGetUserEUID( disk ) ) { if ( DADiskGetUserEUID( disk ) == userUID ) { DADiskUnmount( disk, NULL ); } } } } } for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); /* * Eject this disk. */ if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue ) { if ( DADiskGetOption( disk, kDADiskOptionEjectUponLogout ) ) { DADiskEject( disk, NULL ); } } } DAStageSignal( ); } } CFRelease( key ); } void _DAMediaAppearedCallback( void * context, io_iterator_t notification ) { /* * Process the appearance of media objects in I/O Kit. */ io_service_t media; ///w:start CFArrayRef users; users = SCDynamicStoreCopyConsoleInformation( NULL ); ///w:stop /* * Iterate through the media objects. */ while ( ( media = IOIteratorNext( notification ) ) ) { DADiskRef disk; /* * Determine whether this is a re-registration. */ disk = __DADiskListGetDiskWithIOMedia( media ); if ( disk ) { __DAMediaPropertyChangedCallback( NULL, media ); DAUnitSetState( disk, kDAUnitStateEjected, FALSE ); } else { /* * Create a disk object for this media object. */ DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID ); disk = DADiskCreateFromIOMedia( kCFAllocatorDefault, media ); if ( disk ) { /* * Determine whether a media object disappearance and appearance occurred. We must do this * since the I/O Kit appearance queue is separate from the I/O Kit disappearance queue, and * we are in the midst of processing the appearance queue when we see a duplicate, which is * to say, there is a disappearance on the queue we have not processed yet and must process * it first. The appearances and disappearances within each queue do occur in proper order. */ if ( ___CFArrayContainsValue( gDADiskList, disk ) ) { /* * Process the disappearance. */ assert( context == NULL ); _DAMediaDisappearedCallback( disk, gDAMediaDisappearedNotification ); assert( ___CFArrayContainsValue( gDADiskList, disk ) == FALSE ); } /* * Set the BSD permissions for this media object. */ if ( DADiskGetUserRUID( disk ) == ___UID_UNKNOWN ) { if ( gDAConsoleUser ) { ///w:start mode_t deviceMode; uid_t deviceUser; deviceMode = 0640; deviceUser = gDAConsoleUserUID; if ( users ) { if ( CFArrayGetCount( users ) > 1 ) { deviceMode = 0666; deviceUser = ___UID_ROOT; } } if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse ) { deviceMode &= 0444; } chmod( DADiskGetBSDPath( disk, TRUE ), deviceMode ); chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode ); chown( DADiskGetBSDPath( disk, TRUE ), deviceUser, -1 ); chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 ); ///w:stop ___DADisplayUpdateActivity( ); } } else { if ( DADiskGetMode( disk ) ) { chmod( DADiskGetBSDPath( disk, TRUE ), DADiskGetMode( disk ) & 0666 ); chmod( DADiskGetBSDPath( disk, FALSE ), DADiskGetMode( disk ) & 0666 ); } if ( DADiskGetUserRGID( disk ) ) { chown( DADiskGetBSDPath( disk, TRUE ), -1, DADiskGetUserRGID( disk ) ); chown( DADiskGetBSDPath( disk, FALSE ), -1, DADiskGetUserRGID( disk ) ); } if ( DADiskGetUserRUID( disk ) ) { chown( DADiskGetBSDPath( disk, TRUE ), DADiskGetUserRUID( disk ), -1 ); chown( DADiskGetBSDPath( disk, FALSE ), DADiskGetUserRUID( disk ), -1 ); } } /* * Set the BSD link for this media object. */ if ( DADiskGetBSDLink( disk, TRUE ) ) { int status; status = strncmp( DADiskGetBSDLink( disk, TRUE ), _PATH_DEV "disk", strlen( _PATH_DEV "disk" ) ); if ( status ) { status = link( DADiskGetBSDPath( disk, TRUE ), DADiskGetBSDLink( disk, TRUE ) ); if ( status == 0 ) { status = link( DADiskGetBSDPath( disk, FALSE ), DADiskGetBSDLink( disk, FALSE ) ); if ( status ) { unlink( DADiskGetBSDLink( disk, TRUE ) ); } } } if ( status ) { DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID ); DALogError( "unable to link %@ to %s.", disk, DADiskGetBSDLink( disk, TRUE ) ); DADiskSetBSDLink( disk, TRUE, NULL ); DADiskSetBSDLink( disk, FALSE, NULL ); } } /* * Add the disk object to our tables. */ DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID ); DALogDebug( " created disk, id = %@.", disk ); DAUnitSetState( disk, kDAUnitStateStagedUnreadable, FALSE ); DAUnitSetState( disk, kDAUnitStateEjected, FALSE ); CFArrayInsertValueAtIndex( gDADiskList, 0, disk ); CFRelease( disk ); } if ( context ) { io_service_t service; service = ( io_service_t ) context; if ( IOObjectIsEqualTo( media, service ) ) { notification = NULL; } } } IOObjectRelease( media ); } DAStageSignal( ); ///w:start if ( users ) { CFRelease( users ); } ///w:stop } void _DAMediaDisappearedCallback( void * context, io_iterator_t notification ) { /* * Process the disappearance of media objects in I/O Kit. */ io_service_t media; /* * Iterate through the media objects. */ while ( ( media = IOIteratorNext( notification ) ) ) { DADiskRef disk; /* * Obtain the disk object for this media object. */ disk = __DADiskListGetDiskWithIOMedia( media ); /* * Determine whether a media object appearance and disappearance occurred. We must do this * since the I/O Kit appearance queue is separate from the I/O Kit disappearance queue, and * we are in the midst of processing the disappearance queue when we see one missing, which * is to say, there is an appearance on the queue we haven't processed yet and must process * it first. The appearances and disappearances within each queue do occur in proper order. */ if ( disk == NULL ) { /* * Process the appearance. */ if ( context == NULL ) { _DAMediaAppearedCallback( ( void * ) media, gDAMediaAppearedNotification ); disk = __DADiskListGetDiskWithIOMedia( media ); } } if ( disk ) { CFURLRef path; /* * Remove the disk object from our tables. */ DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID ); DALogDebug( " removed disk, id = %@.", disk ); if ( DADiskGetBSDLink( disk, TRUE ) ) { unlink( DADiskGetBSDLink( disk, TRUE ) ); unlink( DADiskGetBSDLink( disk, FALSE ) ); } path = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); if ( path ) { CFRetain( path ); DADialogShowDeviceRemoval( ); DAFileSystemUnmountWithArguments( DADiskGetFileSystem( disk ), path, __DAMediaDisappearedUnmountCallback, ( void * ) path, kDAFileSystemUnmountArgumentForce, NULL ); } if ( _gDAClassic == disk ) { CFRelease( _gDAClassic ); _gDAClassic = NULL; } DAQueueReleaseDisk( disk ); if ( DADiskGetState( disk, kDADiskStateStagedAppear ) ) { DADiskDisappearedCallback( disk ); } DADiskSetState( disk, kDADiskStateZombie, TRUE ); if ( context ) { if ( CFEqual( disk, context ) ) { notification = NULL; } } ___CFArrayRemoveValue( gDADiskList, disk ); } IOObjectRelease( media ); } DAStageSignal( ); } void _DANotifyCallback( CFMachPortRef port, void * parameter, CFIndex messageSize, void * info ) { CFIndex count; CFIndex index; count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); if ( DADiskGetDescription( disk, kDADiskDescriptionMediaPathKey ) == NULL ) { DADiskRefresh( disk, NULL ); } } } void _DAServerCallback( CFMachPortRef port, void * parameter, CFIndex messageSize, void * info ) { mach_msg_header_t * message = parameter; if ( message->msgh_id == MACH_NOTIFY_DEAD_NAME ) { mach_dead_name_notification_t * notification = parameter; _DAServerSessionRelease( message->msgh_local_port ); mach_port_deallocate( mach_task_self( ), notification->not_port ); } else if ( DAServer_server( message, __gDAServerReply ) ) { kern_return_t status; status = ( __gDAServerReply->msgh_bits & MACH_MSGH_BITS_COMPLEX ) ? KERN_SUCCESS : ( ( mig_reply_error_t * ) __gDAServerReply )->RetCode; /* * Any resources present in the request message are the responsibility of the service * function, if it is successful in responding to the request. Success is defined in * two ways: * * o KERN_SUCCESS: This says that the userŐs request was processed, and all incoming * resources have been recorded or deallocated by the server routine. * o MIG_NO_REPLY: This says that the userŐs request was accepted, and all incoming * resources have been recorded or deallocated by the server routine. * * A reply should always be returned for any message received, unless the return code * from the server was MIG_NO_REPLY or the request message does not have a reply port. */ if ( status != MIG_NO_REPLY ) { if ( status != KERN_SUCCESS ) { message->msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy( message ); } if ( __gDAServerReply->msgh_remote_port ) { status = mach_msg_send( __gDAServerReply ); if ( status == MACH_SEND_INVALID_DEST ) { mach_msg_destroy( __gDAServerReply ); } } } } } kern_return_t _DAServerDiskCopyDescription( mach_port_t _session, caddr_t _disk, vm_address_t * _description, mach_msg_type_number_t * _descriptionSize ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { CFDataRef description; description = DADiskGetSerialization( disk ); if ( description ) { *_description = ___CFDataCopyBytes( description, _descriptionSize ); if ( *_description ) { DALogDebug( " copied disk description, id = %@.", disk ); status = kDAReturnSuccess; } } } } } if ( status ) { DALogDebug( "unable to copy disk description, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskGetOptions( mach_port_t _session, caddr_t _disk, int32_t * _options ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { *_options = DADiskGetOptions( disk ); DALogDebug( " got disk options, id = %@, options = 0x%08X.", disk, *_options ); status = kDAReturnSuccess; } } } if ( status ) { DALogDebug( "unable to get disk options, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskGetUserRUID( mach_port_t _session, caddr_t _disk, uid_t * _userUID ) { kern_return_t status; status = kDAReturnBadArgument; if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; disk = __DADiskListGetDisk( _disk ); if ( disk ) { *_userUID = DADiskGetUserRUID( disk ); status = kDAReturnSuccess; } } } return status; } kern_return_t _DAServerDiskIsClaimed( mach_port_t _session, caddr_t _disk, boolean_t * _claimed ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { *_claimed = DADiskGetClaim( disk ) ? TRUE : FALSE; DALogDebug( " got disk claim state, id = %@, claimed = %s.", disk, *_claimed ? "true" : "false" ); status = kDAReturnSuccess; } } } if ( status ) { DALogDebug( "unable to get disk claim state, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskRefresh( mach_port_t _session, caddr_t _disk ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { if ( DADiskGetState( disk, kDADiskStateStagedAppear ) ) { if ( DADiskGetOption( disk, kDADiskOptionPrivate ) == FALSE ) { if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue ) { DALogDebug( " refreshed disk, id = %@.", disk ); status = _DADiskRefresh( disk ); } } } } else { struct statfs * mountList; int mountListCount; int mountListIndex; mountListCount = getmntinfo( &mountList, MNT_NOWAIT ); for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ ) { if ( strcmp( mountList[mountListIndex].f_mntonname, _disk ) == 0 ) { break; } } if ( mountListIndex < mountListCount ) { CFURLRef path; path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, mountList[mountListIndex].f_mntonname, strlen( mountList[mountListIndex].f_mntonname ), TRUE ); if ( path ) { disk = DADiskCreateFromVolumePath( kCFAllocatorDefault, path ); if ( disk ) { DALogDebug( " created disk, id = %@.", disk ); CFArrayInsertValueAtIndex( gDADiskList, 0, disk ); DAStageSignal( ); status = kDAReturnSuccess; CFRelease( disk ); } CFRelease( path ); } } } } } if ( status ) { DALogDebug( "unable to refresh disk, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskSetAdoption( mach_port_t _session, caddr_t _disk, boolean_t _adoption, security_token_t _token ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { if ( _adoption ) { status = DAAuthorize( session, kDAAuthorizeOptionDefault, NULL, _token.val[0], _token.val[1], _kDAAuthorizeRightAdopt ); } else { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightAdopt ); } if ( status == kDAReturnSuccess ) { DALogDebug( " set disk adoption, id = %@, adoption = %s.", disk, _adoption ? "true" : "false" ); status = _DADiskSetAdoption( disk, _adoption ); } } } } if ( status ) { DALogDebug( "unable to set disk adoption, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskSetClassic( mach_port_t _session, caddr_t _disk ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { if ( _gDAClassic ) { CFRelease( _gDAClassic ); } CFRetain( disk ); _gDAClassic = disk; DALogDebug( " set disk classic, id = %@.", disk ); DADiskClassicCallback( disk ); status = kDAReturnSuccess; } } } if ( status ) { DALogDebug( "unable to set disk classic, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskSetEncoding( mach_port_t _session, caddr_t _disk, int32_t encoding, security_token_t _token ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightEncode ); if ( status == kDAReturnSuccess ) { DALogDebug( " set disk encoding, id = %@, encoding = %d.", disk, encoding ); status = _DADiskSetEncoding( disk, encoding ); } } } } if ( status ) { DALogDebug( "unable to set disk encoding, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskSetOptions( mach_port_t _session, caddr_t _disk, int32_t _options, int32_t _value ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { DALogDebug( " set disk options, id = %@, options = 0x%08X, value = %s.", disk, _options, _value ? "true" : "false" ); if ( DADiskGetState( disk, kDADiskStateStagedAppear ) ) { if ( ( _options & kDADiskOptionPrivate ) ) { if ( _value ) { if ( DADiskGetOption( disk, kDADiskOptionPrivate ) == FALSE ) { DADiskDisappearedCallback( disk ); DAStageSignal( ); } } else { if ( DADiskGetOption( disk, kDADiskOptionPrivate ) ) { DADiskSetOption( disk, kDADiskOptionPrivate, FALSE ); DADiskAppearedCallback( disk ); DAStageSignal( ); } } } } DADiskSetOptions( disk, _options, _value ); status = kDAReturnSuccess; } } } if ( status ) { DALogDebug( "unable to set disk options, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerDiskUnclaim( mach_port_t _session, caddr_t _disk ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _disk ); if ( disk ) { DACallbackRef callback; callback = DADiskGetClaim( disk ); if ( callback ) { if ( DACallbackGetSession( callback ) == session ) { DALogDebug( " unclaimed disk, id = %@.", disk ); DADiskSetClaim( disk, NULL ); status = kDAReturnSuccess; } } } } } if ( status ) { DALogDebug( "unable to unclaim disk, id = %s (status code 0x%08X).", _disk, status ); } return status; } kern_return_t _DAServerSessionCopyCallbackQueue( mach_port_t _session, vm_address_t * _queue, mach_msg_type_number_t * _queueSize ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { CFMutableArrayRef callbacks; DALogDebugHeader( "%s -> %@", gDAProcessNameID, session ); callbacks = DASessionGetCallbackQueue( session ); if ( callbacks ) { CFIndex count; CFIndex index; CFDataRef queue; count = CFArrayGetCount( callbacks ); for ( index = 0; index < count; index++ ) { DACallbackRef callback; callback = ( void * ) CFArrayGetValueAtIndex( callbacks, index ); DACallbackSetDisk( callback, NULL ); DACallbackSetSession( callback, NULL ); ///w:start CFDictionaryRemoveValue( ( void * ) callback, _kDACallbackMatchKey ); ///w:stop } queue = _DASerialize( kCFAllocatorDefault, callbacks ); if ( queue ) { *_queue = ___CFDataCopyBytes( queue, _queueSize ); if ( *_queue ) { DALogDebug( " dispatched callback queue." ); status = kDAReturnSuccess; } CFRelease( queue ); } CFArrayRemoveAllValues( callbacks ); } DASessionSetState( session, kDASessionStateTimeout, FALSE ); } } if ( status ) { DALogDebug( "unable to copy callback queue (status code 0x%08X).", status ); } return status; } kern_return_t _DAServerSessionCreate( mach_port_t _session, mach_port_t _client, caddr_t _name, pid_t _pid, AuthorizationExternalForm _rights, mach_port_t * _server ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "%s [%d] -> %s", _name, _pid, gDAProcessNameID ); if ( _session ) { DASessionRef session; /* * Create the session. */ session = DASessionCreate( kCFAllocatorDefault, _client, _name, _pid, _rights ); if ( session ) { DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); DALogDebug( " created session, id = %@.", session ); *_server = DASessionGetServerPort( session ); /* * Add the session object to our tables. */ CFArrayAppendValue( gDASessionList, session ); /* * Add the session to our run loop. */ DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode ); CFRelease( session ); status = kDAReturnSuccess; } } if ( status ) { DALogDebug( "unable to create session, id = %s [%d].", _name, _pid ); } return status; } kern_return_t _DAServerSessionQueueRequest( mach_port_t _session, int32_t _kind, caddr_t _argument0, int32_t _argument1, vm_address_t _argument2, mach_msg_type_number_t _argument2Size, vm_address_t _argument3, mach_msg_type_number_t _argument3Size, vm_offset_t _address, vm_offset_t _context, security_token_t _token ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DADiskRef disk; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); disk = __DADiskListGetDisk( _argument0 ); if ( disk ) { CFTypeRef argument2 = NULL; CFTypeRef argument3 = NULL; DACallbackRef callback; DARequestRef request; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); if ( _argument2 ) { argument2 = _DAUnserializeWithBytes( kCFAllocatorDefault, _argument2, _argument2Size ); } if ( _argument3 ) { argument3 = _DAUnserializeWithBytes( kCFAllocatorDefault, _argument3, _argument3Size ); } callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, _kind, 0, NULL, NULL ); request = DARequestCreate( kCFAllocatorDefault, _kind, disk, _argument1, argument2, argument3, _token.val[0], _token.val[1], callback ); if ( request ) { switch ( _kind ) { case _kDADiskEject: { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightUnmount ); break; } case _kDADiskMount: { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightMount ); break; } case _kDADiskRename: { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightRename ); break; } case _kDADiskUnmount: { status = DAAuthorize( session, kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightUnmount ); break; } default: { status = kDAReturnSuccess; break; } } if ( status == kDAReturnSuccess ) { DAQueueRequest( request ); DALogDebug( " queued solicitation, id = %08X:%08X, kind = %s, disk = %@, options = 0x%08X.", _address, _context, _DARequestKindGetName( _kind ), disk, _argument1 ); } CFRelease( request ); } if ( callback ) { CFRelease( callback ); } if ( argument2 ) { CFRelease( argument2 ); } if ( argument3 ) { CFRelease( argument3 ); } } } } if ( status ) { DALogDebug( "unable to queue solicitation, id = %08X:%08X, kind = %s, disk = %s (status code 0x%08X).", _address, _context, _DACallbackKindGetName( _kind ), _argument0, status ); } return status; } kern_return_t _DAServerSessionQueueResponse( mach_port_t _session, vm_offset_t _address, vm_offset_t _context, int32_t _kind, caddr_t _disk, vm_address_t _response, mach_msg_type_number_t _responseSize, int32_t _responseID ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { CFTypeRef response = NULL; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); if ( _response ) { response = _DAUnserializeWithBytes( kCFAllocatorDefault, _response, _responseSize ); } if ( _DAResponseDispatch( response, _responseID ) == FALSE ) { DALogDebug( " dispatched response, id = %08X:%08X, kind = %s, disk = %s, orphaned.", _address, _context, _DACallbackKindGetName( _kind ), _disk ); } if ( response ) { CFRelease( response ); } status = kDAReturnSuccess; } } if ( status ) { DALogDebug( "unable to dispatch response, id = %08X:%08X, disk = %s (status code 0x%08X).", _address, _context, _disk, status ); } return status; } kern_return_t _DAServerSessionRegisterCallback( mach_port_t _session, vm_offset_t _address, vm_offset_t _context, int32_t _kind, int32_t _order, vm_address_t _match, mach_msg_type_number_t _matchSize, vm_address_t _watch, mach_msg_type_number_t _watchSize ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DACallbackRef callback; CFDictionaryRef match = NULL; CFArrayRef watch = NULL; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); if ( _match ) { match = _DAUnserializeDiskDescriptionWithBytes( kCFAllocatorDefault, _match, _matchSize ); } if ( _watch ) { watch = _DAUnserializeWithBytes( kCFAllocatorDefault, _watch, _watchSize ); } callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, _kind, _order, match, watch ); if ( callback ) { DASessionRegisterCallback( session, callback ); DALogDebug( " registered callback, id = %08X:%08X, kind = %s.", _address, _context, _DACallbackKindGetName( _kind ) ); if ( DACallbackGetKind( callback ) == _kDADiskAppearedCallback ) { CFIndex count; CFIndex index; count = CFArrayGetCount( gDADiskList ); for ( index = 0; index < count; index++ ) { DADiskRef disk; disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index ); if ( DADiskGetState( disk, kDADiskStateStagedAppear ) ) { DAQueueCallback( callback, disk, NULL ); } } if ( gDAIdle ) { DAQueueCallbacks( session, _kDAIdleCallback, NULL, NULL ); DASessionSetState( session, kDASessionStateIdle, TRUE ); } } else if ( DACallbackGetKind( callback ) == _kDADiskClassicCallback ) { if ( _gDAClassic ) { DAQueueCallback( callback, _gDAClassic, NULL ); } } else if ( DACallbackGetKind( callback ) == _kDAIdleCallback ) { if ( gDAIdle ) { DAQueueCallback( callback, NULL, NULL ); DASessionSetState( session, kDASessionStateIdle, TRUE ); } } ///w:start else if ( DACallbackGetKind( callback ) == _kDADiskEjectApprovalCallback ) { if ( strcmp( _DASessionGetName( session ), "SystemUIServer" ) == 0 ) { CFStringRef key; key = SCDynamicStoreKeyCreateConsoleUser( kCFAllocatorDefault ); if ( key ) { CFMutableArrayRef keys; keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); if ( keys ) { CFArrayAppendValue( keys, key ); _DAConfigurationCallback( NULL, keys, NULL ); CFRelease( keys ); } CFRelease( key ); } } } ///w:stop CFRelease( callback ); status = kDAReturnSuccess; } if ( match ) { CFRelease( match ); } if ( watch ) { CFRelease( watch ); } } } if ( status ) { DALogDebug( "unable to register callback, id = %08X:%08X, kind = %s (status code 0x%08X).", _address, _context, _DACallbackKindGetName( _kind ), status ); } return status; } kern_return_t _DAServerSessionRelease( mach_port_t _session ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { CFMutableArrayRef callbacks; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); DALogDebug( " removed session, id = %@.", session ); callbacks = DASessionGetCallbackQueue( session ); if ( callbacks ) { CFArrayRemoveAllValues( callbacks ); } callbacks = DASessionGetCallbackRegister( session ); if ( callbacks ) { CFArrayRemoveAllValues( callbacks ); } DAQueueReleaseSession( session ); /* * Remove the session from our run loop. */ DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode ); /* * Remove the session object from our tables. */ DASessionSetState( session, kDASessionStateZombie, TRUE ); ___CFArrayRemoveValue( gDASessionList, session ); status = kDAReturnSuccess; } } if ( status ) { DALogDebug( "unable to release session, id = ? [?]:%d.", _session ); } return status; } kern_return_t _DAServerSessionUnregisterCallback( mach_port_t _session, vm_offset_t _address, vm_offset_t _context ) { kern_return_t status; status = kDAReturnBadArgument; DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID ); if ( _session ) { DASessionRef session; session = __DASessionListGetSession( _session ); if ( session ) { DACallbackRef callback; DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID ); callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, 0, 0, NULL, NULL ); if ( callback ) { DASessionUnregisterCallback( session, callback ); DALogDebug( " unregistered callback, id = %08X:%08X.", _address, _context ); CFRelease( callback ); status = kDAReturnSuccess; } } } if ( status ) { DALogDebug( "unable to unregister callback, id = %08X:%08X (status code 0x%08X).", _address, _context, status ); } return status; } CFRunLoopSourceRef DAServerCreateRunLoopSource( CFAllocatorRef allocator, CFIndex order ) { /* * Create a CFRunLoopSource for DAServer remote procedure calls. */ CFRunLoopSourceRef source = NULL; /* * Initialize our minimal state. */ if ( __gDAServer == NULL ) { mach_port_t bootstrapPort; mach_port_t privatePort; kern_return_t status; /* * Obtain the bootstrap port. */ status = task_get_bootstrap_port( mach_task_self( ), &bootstrapPort ); if ( status == KERN_SUCCESS ) { /* * Register the Disk Arbitration master port. */ if ( __gDAServerPort == NULL ) { status = bootstrap_create_server( bootstrapPort, "/usr/sbin/diskarbitrationd", getuid( ), FALSE, &privatePort ); if ( status == KERN_SUCCESS ) { mach_port_t port; status = bootstrap_create_service( privatePort, _kDAServiceName, &port ); if ( status == KERN_SUCCESS ) { status = bootstrap_check_in( privatePort, _kDAServiceName, &__gDAServerPort ); mach_port_deallocate( mach_task_self( ), port ); } mach_port_deallocate( mach_task_self( ), privatePort ); } } mach_port_deallocate( mach_task_self( ), bootstrapPort ); } if ( __gDAServerPort ) { /* * Create the Disk Arbitration master port. */ __gDAServer = CFMachPortCreateWithPort( allocator, __gDAServerPort, _DAServerCallback, NULL, NULL ); if ( __gDAServer ) { __gDAServerReply = malloc( DAServer_subsystem.maxsize ); assert( __gDAServerReply ); } } } /* * Obtain the CFRunLoopSource for our CFMachPort. */ if ( __gDAServer ) { source = CFMachPortCreateRunLoopSource( allocator, __gDAServer, order ); } return source; } DAServerStatus DAServerInitialize( void ) { mach_port_t bootstrapPort; kern_return_t status; /* * Obtain the bootstrap port. */ status = task_get_bootstrap_port( mach_task_self( ), &bootstrapPort ); if ( status == KERN_SUCCESS ) { /* * Obtain the Disk Arbitration master port. */ status = bootstrap_check_in( bootstrapPort, _kDAServiceName, &__gDAServerPort ); switch ( status ) { case BOOTSTRAP_SUCCESS: { return kDAServerStatusInitialize; } case BOOTSTRAP_UNKNOWN_SERVICE: { return kDAServerStatusInactive; } default: { return kDAServerStatusActive; } } mach_port_deallocate( mach_task_self( ), bootstrapPort ); } else { return kDAServerStatusInactive; } }