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 "DAInternal.h"
25
26#include <paths.h>
27#include <DiskArbitration/DiskArbitration.h>
28
29__private_extern__ const char * _kDAAuthorizeRightAdopt   = "adopt";
30__private_extern__ const char * _kDAAuthorizeRightEncode  = "encode";
31__private_extern__ const char * _kDAAuthorizeRightMount   = "mount";
32__private_extern__ const char * _kDAAuthorizeRightRename  = "rename";
33__private_extern__ const char * _kDAAuthorizeRightUnmount = "unmount";
34
35__private_extern__ const CFStringRef _kDACallbackAddressKey       = CFSTR( "DACallbackAddress"   );
36__private_extern__ const CFStringRef _kDACallbackArgument0Key     = CFSTR( "DACallbackArgument0" );
37__private_extern__ const CFStringRef _kDACallbackArgument1Key     = CFSTR( "DACallbackArgument1" );
38__private_extern__ const CFStringRef _kDACallbackContextKey       = CFSTR( "DACallbackContext"   );
39__private_extern__ const CFStringRef _kDACallbackDiskKey          = CFSTR( "DACallbackDisk"      );
40__private_extern__ const CFStringRef _kDACallbackKindKey          = CFSTR( "DACallbackKind"      );
41__private_extern__ const CFStringRef _kDACallbackMatchKey         = CFSTR( "DACallbackMatch"     );
42__private_extern__ const CFStringRef _kDACallbackOrderKey         = CFSTR( "DACallbackOrder"     );
43__private_extern__ const CFStringRef _kDACallbackSessionKey       = CFSTR( "DACallbackSession"   );
44__private_extern__ const CFStringRef _kDACallbackTimeKey          = CFSTR( "DACallbackTime"      );
45__private_extern__ const CFStringRef _kDACallbackWatchKey         = CFSTR( "DACallbackWatch"     );
46
47__private_extern__ const CFStringRef _kDADiskIDKey                = CFSTR( "DADiskID"            );
48
49__private_extern__ const CFStringRef _kDADissenterProcessIDKey    = CFSTR( "DAProcessID"         );
50__private_extern__ const CFStringRef _kDADissenterStatusKey       = CFSTR( "DAStatus"            );
51__private_extern__ const CFStringRef _kDADissenterStatusStringKey = CFSTR( "DAStatusString"      );
52
53__private_extern__ const CFStringRef _kDARequestArgument1Key      = CFSTR( "DARequestArgument1"  );
54__private_extern__ const CFStringRef _kDARequestArgument2Key      = CFSTR( "DARequestArgument2"  );
55__private_extern__ const CFStringRef _kDARequestArgument3Key      = CFSTR( "DARequestArgument3"  );
56__private_extern__ const CFStringRef _kDARequestCallbackKey       = CFSTR( "DARequestCallback"   );
57__private_extern__ const CFStringRef _kDARequestDiskKey           = CFSTR( "DARequestDisk"       );
58__private_extern__ const CFStringRef _kDARequestDissenterKey      = CFSTR( "DARequestDissenter"  );
59__private_extern__ const CFStringRef _kDARequestKindKey           = CFSTR( "DARequestKind"       );
60__private_extern__ const CFStringRef _kDARequestLinkKey           = CFSTR( "DARequestLink"       );
61__private_extern__ const CFStringRef _kDARequestStateKey          = CFSTR( "DARequestState"      );
62__private_extern__ const CFStringRef _kDARequestUserGIDKey        = CFSTR( "DARequestUserGID"    );
63__private_extern__ const CFStringRef _kDARequestUserUIDKey        = CFSTR( "DARequestUserUID"    );
64
65const CFStringRef kDADiskDescriptionVolumeKindKey      = CFSTR( "DAVolumeKind"      );
66const CFStringRef kDADiskDescriptionVolumeMountableKey = CFSTR( "DAVolumeMountable" );
67const CFStringRef kDADiskDescriptionVolumeNameKey      = CFSTR( "DAVolumeName"      );
68const CFStringRef kDADiskDescriptionVolumeNetworkKey   = CFSTR( "DAVolumeNetwork"   );
69const CFStringRef kDADiskDescriptionVolumePathKey      = CFSTR( "DAVolumePath"      );
70const CFStringRef kDADiskDescriptionVolumeUUIDKey      = CFSTR( "DAVolumeUUID"      );
71
72const CFStringRef kDADiskDescriptionMediaBlockSizeKey  = CFSTR( "DAMediaBlockSize"  );
73const CFStringRef kDADiskDescriptionMediaBSDMajorKey   = CFSTR( "DAMediaBSDMajor"   );
74const CFStringRef kDADiskDescriptionMediaBSDMinorKey   = CFSTR( "DAMediaBSDMinor"   );
75const CFStringRef kDADiskDescriptionMediaBSDNameKey    = CFSTR( "DAMediaBSDName"    );
76const CFStringRef kDADiskDescriptionMediaBSDUnitKey    = CFSTR( "DAMediaBSDUnit"    );
77const CFStringRef kDADiskDescriptionMediaContentKey    = CFSTR( "DAMediaContent"    );
78const CFStringRef kDADiskDescriptionMediaEjectableKey  = CFSTR( "DAMediaEjectable"  );
79const CFStringRef kDADiskDescriptionMediaIconKey       = CFSTR( "DAMediaIcon"       );
80const CFStringRef kDADiskDescriptionMediaKindKey       = CFSTR( "DAMediaKind"       );
81const CFStringRef kDADiskDescriptionMediaLeafKey       = CFSTR( "DAMediaLeaf"       );
82const CFStringRef kDADiskDescriptionMediaNameKey       = CFSTR( "DAMediaName"       );
83const CFStringRef kDADiskDescriptionMediaPathKey       = CFSTR( "DAMediaPath"       );
84const CFStringRef kDADiskDescriptionMediaRemovableKey  = CFSTR( "DAMediaRemovable"  );
85const CFStringRef kDADiskDescriptionMediaSizeKey       = CFSTR( "DAMediaSize"       );
86const CFStringRef kDADiskDescriptionMediaTypeKey       = CFSTR( "DAMediaType"       );
87const CFStringRef kDADiskDescriptionMediaUUIDKey       = CFSTR( "DAMediaUUID"       );
88const CFStringRef kDADiskDescriptionMediaWholeKey      = CFSTR( "DAMediaWhole"      );
89const CFStringRef kDADiskDescriptionMediaWritableKey   = CFSTR( "DAMediaWritable"   );
90
91const CFStringRef kDADiskDescriptionDeviceGUIDKey      = CFSTR( "DADeviceGUID"      );
92const CFStringRef kDADiskDescriptionDeviceInternalKey  = CFSTR( "DADeviceInternal"  );
93const CFStringRef kDADiskDescriptionDeviceModelKey     = CFSTR( "DADeviceModel"     );
94const CFStringRef kDADiskDescriptionDevicePathKey      = CFSTR( "DADevicePath"      );
95const CFStringRef kDADiskDescriptionDeviceProtocolKey  = CFSTR( "DADeviceProtocol"  );
96const CFStringRef kDADiskDescriptionDeviceRevisionKey  = CFSTR( "DADeviceRevision"  );
97const CFStringRef kDADiskDescriptionDeviceUnitKey      = CFSTR( "DADeviceUnit"      );
98const CFStringRef kDADiskDescriptionDeviceVendorKey    = CFSTR( "DADeviceVendor"    );
99
100const CFStringRef kDADiskDescriptionBusNameKey         = CFSTR( "DABusName"         );
101const CFStringRef kDADiskDescriptionBusPathKey         = CFSTR( "DABusPath"         );
102
103const CFStringRef kDADiskDescriptionAppearanceTimeKey  = CFSTR( "DAAppearanceTime"  );
104
105const CFStringRef kDADiskDescriptionMediaMatchKey      = CFSTR( "DAMediaMatch"      );
106
107static const char * __kDAKindNameList[] =
108{
109    "disk appeared",
110    "disk claim",
111    "disk claim release",
112    "disk description changed",
113    "disk disappeared",
114    "disk eject",
115    "disk eject approval",
116    "disk mount",
117    "disk mount approval",
118    "disk peek",
119    "disk probe",
120    "disk refresh",
121    "disk rename",
122    "disk unmount",
123    "disk unmount approval",
124    "idle"
125};
126
127extern CFIndex __CFBinaryPlistWriteToStream( CFPropertyListRef plist, CFTypeRef stream );
128
129__private_extern__ int ___statfs( const char * path, struct statfs * buf, int flags )
130{
131    struct statfs * mountList;
132    int             mountListCount;
133    int             mountListIndex;
134    int             status;
135
136    status = -1;
137
138    mountListCount = getfsstat( NULL, 0, MNT_NOWAIT );
139
140    if ( mountListCount > 0 )
141    {
142        mountList = malloc( mountListCount * sizeof( struct statfs ) );
143
144        if ( mountList )
145        {
146            mountListCount = getfsstat( mountList, mountListCount * sizeof( struct statfs ), flags );
147
148            if ( mountListCount > 0 )
149            {
150                for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
151                {
152                    if ( strcmp( mountList[mountListIndex].f_mntonname, path ) == 0 )
153                    {
154                        status = 0;
155
156                        *buf = mountList[mountListIndex];
157
158                        if ( mountList[mountListIndex].f_owner == geteuid( ) )
159                        {
160                            break;
161                        }
162                    }
163                }
164            }
165
166            free( mountList );
167        }
168    }
169
170    return status;
171}
172
173__private_extern__ Boolean ___CFArrayContainsValue( CFArrayRef array, const void * value )
174{
175    return CFArrayContainsValue( array, CFRangeMake( 0, CFArrayGetCount( array ) ), value );
176}
177
178__private_extern__ void ___CFArrayRemoveValue( CFMutableArrayRef array, const void * value )
179{
180    CFIndex index;
181
182    index = CFArrayGetFirstIndexOfValue( array, CFRangeMake( 0, CFArrayGetCount( array ) ), value );
183
184    if ( index != kCFNotFound )
185    {
186        CFArrayRemoveValueAtIndex( array, index );
187    }
188}
189
190__private_extern__ vm_address_t ___CFDataCopyBytes( CFDataRef data, mach_msg_type_number_t * length )
191{
192    vm_address_t bytes = 0;
193
194    *length = CFDataGetLength( data );
195
196    vm_allocate( mach_task_self( ), &bytes, *length, TRUE );
197
198    if ( bytes )
199    {
200        bcopy( CFDataGetBytePtr( data ), ( void * ) bytes, *length );
201    }
202
203    return bytes;
204}
205
206__private_extern__ SInt64 ___CFDictionaryGetIntegerValue( CFDictionaryRef dictionary, const void * key )
207{
208    CFNumberRef number;
209    SInt64      value  = 0;
210
211    number = CFDictionaryGetValue( dictionary, key );
212
213    if ( number )
214    {
215        CFNumberGetValue( number, kCFNumberSInt64Type, &value );
216    }
217
218    return value;
219}
220
221__private_extern__ void ___CFDictionarySetIntegerValue( CFMutableDictionaryRef dictionary, const void * key, SInt64 value )
222{
223    CFNumberRef number;
224
225    number = CFNumberCreate( CFGetAllocator( dictionary ), kCFNumberSInt64Type, &value );
226
227    if ( number )
228    {
229        CFDictionarySetValue( dictionary, key, number );
230
231        CFRelease( number );
232    }
233}
234
235__private_extern__ CFNumberRef ___CFNumberCreateWithIntegerValue( CFAllocatorRef allocator, SInt64 value )
236{
237    CFNumberRef number;
238
239    number = CFNumberCreate( allocator, kCFNumberSInt64Type, &value );
240
241    return number;
242}
243
244__private_extern__ SInt64 ___CFNumberGetIntegerValue( CFNumberRef number )
245{
246    SInt64 value = 0;
247
248    CFNumberGetValue( number, kCFNumberSInt64Type, &value );
249
250    return value;
251}
252
253__private_extern__ char * ___CFStringCopyCString( CFStringRef string )
254{
255    /*
256     * Creates a C string buffer from a CFString object.  The string encoding is presumed to be
257     * UTF-8.  The result is a reference to a C string buffer or NULL if there was a problem in
258     * creating the buffer.  The caller is responsible for releasing the buffer with free().
259     */
260
261    char * buffer = NULL;
262
263    if ( string )
264    {
265        CFIndex length;
266        CFRange range;
267
268        range = CFRangeMake( 0, CFStringGetLength( string ) );
269
270        if ( CFStringGetBytes( string, range, kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &length ) )
271        {
272            buffer = malloc( length + 1 );
273
274            if ( buffer )
275            {
276                CFStringGetBytes( string, range, kCFStringEncodingUTF8, 0, FALSE, ( void * ) buffer, length, NULL );
277
278                buffer[length] = 0;
279            }
280        }
281    }
282
283    return buffer;
284}
285
286__private_extern__ char * ___CFURLCopyFileSystemRepresentation( CFURLRef url )
287{
288    /*
289     * Creates a buffer with the file system's native string representation of URL's path.
290     * The result is a reference to a C buffer or NULL if there was a problem in creating
291     * the buffer.  The caller is responsible for releasing the buffer with free().
292     */
293
294    char * path = NULL;
295
296    if ( url )
297    {
298        CFStringRef string;
299
300        string = CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle );
301
302        if ( string )
303        {
304            path = ___CFStringCopyCString( string );
305
306            CFRelease( string );
307        }
308    }
309
310    return path;
311}
312
313__private_extern__ const char * _DACallbackKindGetName( _DACallbackKind kind )
314{
315    return __kDAKindNameList[kind];
316}
317
318__private_extern__ const char * _DARequestKindGetName( _DARequestKind kind )
319{
320    return __kDAKindNameList[kind];
321}
322
323__private_extern__ CFDataRef _DASerialize( CFAllocatorRef allocator, CFTypeRef object )
324{
325    CFDataRef data;
326
327    data = CFDataCreateMutable( allocator, 0 );
328
329    if ( data )
330    {
331        if ( __CFBinaryPlistWriteToStream( object, data ) == 0 )
332        {
333            CFRelease( data );
334
335            data = NULL;
336        }
337    }
338
339    return data;
340}
341
342__private_extern__ CFDataRef _DASerializeDiskDescription( CFAllocatorRef allocator, CFDictionaryRef description )
343{
344    CFDataRef data = NULL;
345
346    if ( description )
347    {
348        CFMutableDictionaryRef copy;
349
350        copy = CFDictionaryCreateMutableCopy( allocator, 0, description );
351
352        if ( copy )
353        {
354            CFTypeRef object;
355
356            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaUUIDKey );
357
358            if ( object )
359            {
360                object = CFUUIDCreateString( allocator, object );
361
362                if ( object )
363                {
364                    CFDictionarySetValue( copy, kDADiskDescriptionMediaUUIDKey, object );
365
366                    CFRelease( object );
367                }
368            }
369
370            object = CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey );
371
372            if ( object )
373            {
374                object = CFURLCopyFileSystemPath( object, kCFURLPOSIXPathStyle );
375
376                if ( object )
377                {
378                    CFDictionarySetValue( copy, kDADiskDescriptionVolumePathKey, object );
379
380                    CFRelease( object );
381                }
382            }
383
384            object = CFDictionaryGetValue( description, kDADiskDescriptionVolumeUUIDKey );
385
386            if ( object )
387            {
388                object = CFUUIDCreateString( allocator, object );
389
390                if ( object )
391                {
392                    CFDictionarySetValue( copy, kDADiskDescriptionVolumeUUIDKey, object );
393
394                    CFRelease( object );
395                }
396            }
397
398            data = _DASerialize( allocator, copy );
399
400            CFRelease( copy );
401        }
402    }
403
404    return data;
405}
406
407__private_extern__ CFTypeRef _DAUnserialize( CFAllocatorRef allocator, CFDataRef data )
408{
409    return CFPropertyListCreateFromXMLData( allocator, data, kCFPropertyListImmutable, NULL );
410}
411
412__private_extern__ CFMutableDictionaryRef _DAUnserializeDiskDescription( CFAllocatorRef allocator, CFDataRef data )
413{
414    CFMutableDictionaryRef description;
415
416    description = ( void * ) CFPropertyListCreateFromXMLData( allocator, data, kCFPropertyListMutableContainers, NULL );
417
418    if ( description )
419    {
420        CFTypeRef object;
421
422        object = CFDictionaryGetValue( description, kDADiskDescriptionMediaUUIDKey );
423
424        if ( object )
425        {
426            object = CFUUIDCreateFromString( allocator, object );
427
428            if ( object )
429            {
430                CFDictionarySetValue( description, kDADiskDescriptionMediaUUIDKey, object );
431
432                CFRelease( object );
433            }
434        }
435
436        object = CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey );
437
438        if ( object )
439        {
440            object = CFURLCreateWithFileSystemPath( allocator, object, kCFURLPOSIXPathStyle, TRUE );
441
442            if ( object )
443            {
444                CFDictionarySetValue( description, kDADiskDescriptionVolumePathKey, object );
445
446                CFRelease( object );
447            }
448        }
449
450        object = CFDictionaryGetValue( description, kDADiskDescriptionVolumeUUIDKey );
451
452        if ( object )
453        {
454            object = CFUUIDCreateFromString( allocator, object );
455
456            if ( object )
457            {
458                CFDictionarySetValue( description, kDADiskDescriptionVolumeUUIDKey, object );
459
460                CFRelease( object );
461            }
462        }
463    }
464
465    return description;
466}
467
468__private_extern__ CFMutableDictionaryRef _DAUnserializeDiskDescriptionWithBytes( CFAllocatorRef allocator, vm_address_t bytes, vm_size_t length )
469{
470    CFMutableDictionaryRef description = NULL;
471
472    if ( bytes )
473    {
474        CFDataRef data;
475
476        data = CFDataCreateWithBytesNoCopy( allocator, ( void * ) bytes, length, kCFAllocatorNull );
477
478        if ( data )
479        {
480            description = _DAUnserializeDiskDescription( allocator, data );
481
482            CFRelease( data );
483        }
484    }
485
486    return description;
487}
488
489__private_extern__ CFTypeRef _DAUnserializeWithBytes( CFAllocatorRef allocator, vm_address_t bytes, vm_size_t length )
490{
491    CFTypeRef object = NULL;
492
493    if ( bytes )
494    {
495        CFDataRef data;
496
497        data = CFDataCreateWithBytesNoCopy( allocator, ( void * ) bytes, length, kCFAllocatorNull );
498
499        if ( data )
500        {
501            object = _DAUnserialize( allocator, data );
502
503            CFRelease( data );
504        }
505    }
506
507    return object;
508}
509
510__private_extern__ char * _DAVolumeCopyID( const struct statfs * fs )
511{
512    char * id;
513
514    if ( strncmp( fs->f_mntfromname, _PATH_DEV, strlen( _PATH_DEV ) ) )
515    {
516        asprintf( &id, "%s?owner=%u", fs->f_mntonname, fs->f_owner );
517    }
518    else
519    {
520        asprintf( &id, "%s", fs->f_mntfromname );
521    }
522
523    return id;
524}
525
526__private_extern__ char * _DAVolumeGetID( const struct statfs * fs )
527{
528    static char id[ sizeof( fs->f_mntonname ) + strlen( "?owner=" ) + strlen( "4294967295" ) ];
529
530    if ( strncmp( fs->f_mntfromname, _PATH_DEV, strlen( _PATH_DEV ) ) )
531    {
532        snprintf( id, sizeof( id ), "%s?owner=%u", fs->f_mntonname, fs->f_owner );
533    }
534    else
535    {
536        snprintf( id, sizeof( id ), "%s", fs->f_mntfromname );
537    }
538
539    return id;
540}
541