1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ArgumentCodersCF.h"
28
29#include "ArgumentDecoder.h"
30#include "ArgumentEncoder.h"
31#include "DataReference.h"
32#include <WebCore/CFURLExtras.h>
33#include <wtf/Vector.h>
34
35#if USE(FOUNDATION)
36#import <Foundation/Foundation.h>
37#endif
38
39#if defined(__has_include) && __has_include(<Security/SecIdentityPriv.h>)
40#include <Security/SecIdentityPriv.h>
41#endif
42
43extern "C" SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey);
44
45#if PLATFORM(IOS)
46#if defined(__has_include) && __has_include(<Security/SecKeyPriv.h>)
47#include <Security/SecKeyPriv.h>
48#endif
49
50extern "C" OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData);
51#endif
52
53#if HAVE(SEC_ACCESS_CONTROL)
54#if defined(__has_include) && __has_include(<Security/SecAccessControlPriv.h>)
55#include <Security/SecAccessControlPriv.h>
56#endif
57
58extern "C" SecAccessControlRef SecAccessControlCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error);
59extern "C" CFDataRef SecAccessControlCopyData(SecAccessControlRef access_control);
60#endif
61
62using namespace WebCore;
63
64namespace IPC {
65
66CFTypeRef tokenNullTypeRef()
67{
68    static CFStringRef tokenNullType = CFSTR("WKNull");
69    return tokenNullType;
70}
71
72enum CFType {
73    CFArray,
74    CFBoolean,
75    CFData,
76    CFDate,
77    CFDictionary,
78    CFNull,
79    CFNumber,
80    CFString,
81    CFURL,
82    SecCertificate,
83#if PLATFORM(IOS)
84    SecIdentity,
85#endif
86#if HAVE(SEC_KEYCHAIN)
87    SecKeychainItem,
88#endif
89#if HAVE(SEC_ACCESS_CONTROL)
90    SecAccessControl,
91#endif
92    Null,
93    Unknown,
94};
95
96static CFType typeFromCFTypeRef(CFTypeRef type)
97{
98    ASSERT(type);
99
100    if (type == tokenNullTypeRef())
101        return Null;
102
103    CFTypeID typeID = CFGetTypeID(type);
104    if (typeID == CFArrayGetTypeID())
105        return CFArray;
106    if (typeID == CFBooleanGetTypeID())
107        return CFBoolean;
108    if (typeID == CFDataGetTypeID())
109        return CFData;
110    if (typeID == CFDateGetTypeID())
111        return CFDate;
112    if (typeID == CFDictionaryGetTypeID())
113        return CFDictionary;
114    if (typeID == CFNullGetTypeID())
115        return CFNull;
116    if (typeID == CFNumberGetTypeID())
117        return CFNumber;
118    if (typeID == CFStringGetTypeID())
119        return CFString;
120    if (typeID == CFURLGetTypeID())
121        return CFURL;
122    if (typeID == SecCertificateGetTypeID())
123        return SecCertificate;
124#if PLATFORM(IOS)
125    if (typeID == SecIdentityGetTypeID())
126        return SecIdentity;
127#endif
128#if HAVE(SEC_KEYCHAIN)
129    if (typeID == SecKeychainItemGetTypeID())
130        return SecKeychainItem;
131#endif
132#if HAVE(SEC_ACCESS_CONTROL)
133    if (typeID == SecAccessControlGetTypeID())
134        return SecAccessControl;
135#endif
136
137    ASSERT_NOT_REACHED();
138    return Unknown;
139}
140
141void encode(ArgumentEncoder& encoder, CFTypeRef typeRef)
142{
143    CFType type = typeFromCFTypeRef(typeRef);
144    encoder.encodeEnum(type);
145
146    switch (type) {
147    case CFArray:
148        encode(encoder, static_cast<CFArrayRef>(typeRef));
149        return;
150    case CFBoolean:
151        encode(encoder, static_cast<CFBooleanRef>(typeRef));
152        return;
153    case CFData:
154        encode(encoder, static_cast<CFDataRef>(typeRef));
155        return;
156    case CFDate:
157        encode(encoder, static_cast<CFDateRef>(typeRef));
158        return;
159    case CFDictionary:
160        encode(encoder, static_cast<CFDictionaryRef>(typeRef));
161        return;
162    case CFNull:
163        return;
164    case CFNumber:
165        encode(encoder, static_cast<CFNumberRef>(typeRef));
166        return;
167    case CFString:
168        encode(encoder, static_cast<CFStringRef>(typeRef));
169        return;
170    case CFURL:
171        encode(encoder, static_cast<CFURLRef>(typeRef));
172        return;
173    case SecCertificate:
174        encode(encoder, (SecCertificateRef)typeRef);
175        return;
176#if PLATFORM(IOS)
177    case SecIdentity:
178        encode(encoder, (SecIdentityRef)(typeRef));
179        return;
180#endif
181#if HAVE(SEC_KEYCHAIN)
182    case SecKeychainItem:
183        encode(encoder, (SecKeychainItemRef)typeRef);
184        return;
185#endif
186#if HAVE(SEC_ACCESS_CONTROL)
187    case SecAccessControl:
188        encode(encoder, (SecAccessControlRef)typeRef);
189        return;
190#endif
191    case Null:
192        return;
193    case Unknown:
194        break;
195    }
196
197    ASSERT_NOT_REACHED();
198}
199
200bool decode(ArgumentDecoder& decoder, RetainPtr<CFTypeRef>& result)
201{
202    CFType type;
203    if (!decoder.decodeEnum(type))
204        return false;
205
206    switch (type) {
207    case CFArray: {
208        RetainPtr<CFArrayRef> array;
209        if (!decode(decoder, array))
210            return false;
211        result = adoptCF(array.leakRef());
212        return true;
213    }
214    case CFBoolean: {
215        RetainPtr<CFBooleanRef> boolean;
216        if (!decode(decoder, boolean))
217            return false;
218        result = adoptCF(boolean.leakRef());
219        return true;
220    }
221    case CFData: {
222        RetainPtr<CFDataRef> data;
223        if (!decode(decoder, data))
224            return false;
225        result = adoptCF(data.leakRef());
226        return true;
227    }
228    case CFDate: {
229        RetainPtr<CFDateRef> date;
230        if (!decode(decoder, date))
231            return false;
232        result = adoptCF(date.leakRef());
233        return true;
234    }
235    case CFDictionary: {
236        RetainPtr<CFDictionaryRef> dictionary;
237        if (!decode(decoder, dictionary))
238            return false;
239        result = adoptCF(dictionary.leakRef());
240        return true;
241    }
242    case CFNull:
243        result = adoptCF(kCFNull);
244        return true;
245    case CFNumber: {
246        RetainPtr<CFNumberRef> number;
247        if (!decode(decoder, number))
248            return false;
249        result = adoptCF(number.leakRef());
250        return true;
251    }
252    case CFString: {
253        RetainPtr<CFStringRef> string;
254        if (!decode(decoder, string))
255            return false;
256        result = adoptCF(string.leakRef());
257        return true;
258    }
259    case CFURL: {
260        RetainPtr<CFURLRef> url;
261        if (!decode(decoder, url))
262            return false;
263        result = adoptCF(url.leakRef());
264        return true;
265    }
266    case SecCertificate: {
267        RetainPtr<SecCertificateRef> certificate;
268        if (!decode(decoder, certificate))
269            return false;
270        result = adoptCF(certificate.leakRef());
271        return true;
272    }
273#if PLATFORM(IOS)
274    case SecIdentity: {
275        RetainPtr<SecIdentityRef> identity;
276        if (!decode(decoder, identity))
277            return false;
278        result = adoptCF(identity.leakRef());
279        return true;
280    }
281#endif
282#if HAVE(SEC_KEYCHAIN)
283    case SecKeychainItem: {
284        RetainPtr<SecKeychainItemRef> keychainItem;
285        if (!decode(decoder, keychainItem))
286            return false;
287        result = adoptCF(keychainItem.leakRef());
288        return true;
289    }
290#endif
291#if HAVE(SEC_ACCESS_CONTROL)
292    case SecAccessControl: {
293        RetainPtr<SecAccessControlRef> accessControl;
294        if (!decode(decoder, accessControl))
295            return false;
296        result = adoptCF(accessControl.leakRef());
297        return true;
298    }
299#endif
300    case Null:
301        result = tokenNullTypeRef();
302        return true;
303    case Unknown:
304        ASSERT_NOT_REACHED();
305        return false;
306    }
307
308    return false;
309}
310
311void encode(ArgumentEncoder& encoder, CFArrayRef array)
312{
313    CFIndex size = CFArrayGetCount(array);
314    Vector<CFTypeRef, 32> values(size);
315
316    CFArrayGetValues(array, CFRangeMake(0, size), values.data());
317
318    encoder << static_cast<uint64_t>(size);
319
320    for (CFIndex i = 0; i < size; ++i) {
321        ASSERT(values[i]);
322
323        encode(encoder, values[i]);
324    }
325}
326
327bool decode(ArgumentDecoder& decoder, RetainPtr<CFArrayRef>& result)
328{
329    uint64_t size;
330    if (!decoder.decode(size))
331        return false;
332
333    RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
334
335    for (size_t i = 0; i < size; ++i) {
336        RetainPtr<CFTypeRef> element;
337        if (!decode(decoder, element))
338            return false;
339
340        CFArrayAppendValue(array.get(), element.get());
341    }
342
343    result = adoptCF(array.leakRef());
344    return true;
345}
346
347void encode(ArgumentEncoder& encoder, CFBooleanRef boolean)
348{
349    encoder << static_cast<bool>(CFBooleanGetValue(boolean));
350}
351
352bool decode(ArgumentDecoder& decoder, RetainPtr<CFBooleanRef>& result)
353{
354    bool boolean;
355    if (!decoder.decode(boolean))
356        return false;
357
358    result = adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse);
359    return true;
360}
361
362void encode(ArgumentEncoder& encoder, CFDataRef data)
363{
364    CFIndex length = CFDataGetLength(data);
365    const UInt8* bytePtr = CFDataGetBytePtr(data);
366
367    encoder << IPC::DataReference(bytePtr, length);
368}
369
370bool decode(ArgumentDecoder& decoder, RetainPtr<CFDataRef>& result)
371{
372    IPC::DataReference dataReference;
373    if (!decoder.decode(dataReference))
374        return false;
375
376    result = adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size()));
377    return true;
378}
379
380void encode(ArgumentEncoder& encoder, CFDateRef date)
381{
382    encoder << static_cast<double>(CFDateGetAbsoluteTime(date));
383}
384
385bool decode(ArgumentDecoder& decoder, RetainPtr<CFDateRef>& result)
386{
387    double absoluteTime;
388    if (!decoder.decode(absoluteTime))
389        return false;
390
391    result = adoptCF(CFDateCreate(0, absoluteTime));
392    return true;
393}
394
395void encode(ArgumentEncoder& encoder, CFDictionaryRef dictionary)
396{
397    CFIndex size = CFDictionaryGetCount(dictionary);
398    Vector<CFTypeRef, 32> keys(size);
399    Vector<CFTypeRef, 32> values(size);
400
401    CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data());
402
403    encoder << static_cast<uint64_t>(size);
404
405    for (CFIndex i = 0; i < size; ++i) {
406        ASSERT(keys[i]);
407        ASSERT(CFGetTypeID(keys[i]) == CFStringGetTypeID());
408        ASSERT(values[i]);
409
410        // Ignore values we don't recognize.
411        if (typeFromCFTypeRef(values[i]) == Unknown)
412            continue;
413
414        encode(encoder, static_cast<CFStringRef>(keys[i]));
415        encode(encoder, values[i]);
416    }
417}
418
419bool decode(ArgumentDecoder& decoder, RetainPtr<CFDictionaryRef>& result)
420{
421    uint64_t size;
422    if (!decoder.decode(size))
423        return false;
424
425    RetainPtr<CFMutableDictionaryRef> dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
426    for (uint64_t i = 0; i < size; ++i) {
427        // Try to decode the key name.
428        RetainPtr<CFStringRef> key;
429        if (!decode(decoder, key))
430            return false;
431
432        RetainPtr<CFTypeRef> value;
433        if (!decode(decoder, value))
434            return false;
435
436        CFDictionarySetValue(dictionary.get(), key.get(), value.get());
437    }
438
439    result = adoptCF(dictionary.leakRef());
440    return true;
441}
442
443void encode(ArgumentEncoder& encoder, CFNumberRef number)
444{
445    CFNumberType numberType = CFNumberGetType(number);
446
447    Vector<uint8_t> buffer(CFNumberGetByteSize(number));
448    bool result = CFNumberGetValue(number, numberType, buffer.data());
449    ASSERT_UNUSED(result, result);
450
451    encoder.encodeEnum(numberType);
452    encoder << IPC::DataReference(buffer);
453}
454
455static size_t sizeForNumberType(CFNumberType numberType)
456{
457    switch (numberType) {
458    case kCFNumberSInt8Type:
459        return sizeof(SInt8);
460    case kCFNumberSInt16Type:
461        return sizeof(SInt16);
462    case kCFNumberSInt32Type:
463        return sizeof(SInt32);
464    case kCFNumberSInt64Type:
465        return sizeof(SInt64);
466    case kCFNumberFloat32Type:
467        return sizeof(Float32);
468    case kCFNumberFloat64Type:
469        return sizeof(Float64);
470    case kCFNumberCharType:
471        return sizeof(char);
472    case kCFNumberShortType:
473        return sizeof(short);
474    case kCFNumberIntType:
475        return sizeof(int);
476    case kCFNumberLongType:
477        return sizeof(long);
478    case kCFNumberLongLongType:
479        return sizeof(long long);
480    case kCFNumberFloatType:
481        return sizeof(float);
482    case kCFNumberDoubleType:
483        return sizeof(double);
484    case kCFNumberCFIndexType:
485        return sizeof(CFIndex);
486    case kCFNumberNSIntegerType:
487#ifdef __LP64__
488        return sizeof(long);
489#else
490        return sizeof(int);
491#endif
492    case kCFNumberCGFloatType:
493#ifdef __LP64__
494        return sizeof(double);
495#else
496        return sizeof(float);
497#endif
498    }
499
500    return 0;
501}
502
503bool decode(ArgumentDecoder& decoder, RetainPtr<CFNumberRef>& result)
504{
505    CFNumberType numberType;
506    if (!decoder.decodeEnum(numberType))
507        return false;
508
509    IPC::DataReference dataReference;
510    if (!decoder.decode(dataReference))
511        return false;
512
513    size_t neededBufferSize = sizeForNumberType(numberType);
514    if (!neededBufferSize || dataReference.size() != neededBufferSize)
515        return false;
516
517    ASSERT(dataReference.data());
518    CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data());
519    result = adoptCF(number);
520
521    return true;
522}
523
524void encode(ArgumentEncoder& encoder, CFStringRef string)
525{
526    CFIndex length = CFStringGetLength(string);
527    CFStringEncoding encoding = CFStringGetFastestEncoding(string);
528
529    CFRange range = CFRangeMake(0, length);
530    CFIndex bufferLength = 0;
531
532    CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength);
533    ASSERT(numConvertedBytes == length);
534
535    Vector<UInt8, 128> buffer(bufferLength);
536    numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength);
537    ASSERT(numConvertedBytes == length);
538
539    encoder.encodeEnum(encoding);
540    encoder << IPC::DataReference(buffer);
541}
542
543bool decode(ArgumentDecoder& decoder, RetainPtr<CFStringRef>& result)
544{
545    CFStringEncoding encoding;
546    if (!decoder.decodeEnum(encoding))
547        return false;
548
549    if (!CFStringIsEncodingAvailable(encoding))
550        return false;
551
552    IPC::DataReference dataReference;
553    if (!decoder.decode(dataReference))
554        return false;
555
556    CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false);
557    if (!string)
558        return false;
559
560    result = adoptCF(string);
561    return true;
562}
563
564void encode(ArgumentEncoder& encoder, CFURLRef url)
565{
566    CFURLRef baseURL = CFURLGetBaseURL(url);
567    encoder << static_cast<bool>(baseURL);
568    if (baseURL)
569        encode(encoder, baseURL);
570
571    URLCharBuffer urlBytes;
572    getURLBytes(url, urlBytes);
573    IPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(urlBytes.data()), urlBytes.size());
574    encoder << dataReference;
575}
576
577bool decode(ArgumentDecoder& decoder, RetainPtr<CFURLRef>& result)
578{
579    RetainPtr<CFURLRef> baseURL;
580    bool hasBaseURL;
581    if (!decoder.decode(hasBaseURL))
582        return false;
583    if (hasBaseURL) {
584        if (!decode(decoder, baseURL))
585            return false;
586    }
587
588    IPC::DataReference urlBytes;
589    if (!decoder.decode(urlBytes))
590        return false;
591
592#if USE(FOUNDATION)
593    // FIXME: Move this to ArgumentCodersCFMac.mm and change this file back to be C++
594    // instead of Objective-C++.
595    if (urlBytes.isEmpty()) {
596        // CFURL can't hold an empty URL, unlike NSURL.
597        // FIXME: This discards base URL, which seems incorrect.
598        result = reinterpret_cast<CFURLRef>([NSURL URLWithString:@""]);
599        return true;
600    }
601#endif
602
603    result = createCFURLFromBuffer(reinterpret_cast<const char*>(urlBytes.data()), urlBytes.size(), baseURL.get());
604    return result;
605}
606
607void encode(ArgumentEncoder& encoder, SecCertificateRef certificate)
608{
609    RetainPtr<CFDataRef> data = adoptCF(SecCertificateCopyData(certificate));
610    encode(encoder, data.get());
611}
612
613bool decode(ArgumentDecoder& decoder, RetainPtr<SecCertificateRef>& result)
614{
615    RetainPtr<CFDataRef> data;
616    if (!decode(decoder, data))
617        return false;
618
619    result = adoptCF(SecCertificateCreateWithData(0, data.get()));
620    return true;
621}
622
623#if PLATFORM(IOS)
624static bool secKeyRefDecodingAllowed;
625
626void setAllowsDecodingSecKeyRef(bool allowsDecodingSecKeyRef)
627{
628    secKeyRefDecodingAllowed = allowsDecodingSecKeyRef;
629}
630
631static CFDataRef copyPersistentRef(SecKeyRef key)
632{
633    // This function differs from SecItemCopyPersistentRef in that it specifies an access group.
634    // This is necessary in case there are multiple copies of the key in the keychain, because we
635    // need a reference to the one that the Networking process will be able to access.
636    CFDataRef persistentRef = nullptr;
637    SecItemCopyMatching((CFDictionaryRef)@{
638        (id)kSecReturnPersistentRef: @YES,
639        (id)kSecValueRef: (id)key,
640        (id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny,
641        (id)kSecAttrAccessGroup: @"com.apple.identities",
642    }, (CFTypeRef*)&persistentRef);
643
644    return persistentRef;
645}
646#endif
647
648void encode(ArgumentEncoder& encoder, SecIdentityRef identity)
649{
650    SecCertificateRef certificate = nullptr;
651    SecIdentityCopyCertificate(identity, &certificate);
652    encode(encoder, certificate);
653    CFRelease(certificate);
654
655    SecKeyRef key = nullptr;
656    SecIdentityCopyPrivateKey(identity, &key);
657
658    CFDataRef keyData = nullptr;
659#if PLATFORM(IOS)
660    keyData = copyPersistentRef(key);
661#endif
662#if PLATFORM(MAC)
663    SecKeychainItemCreatePersistentReference((SecKeychainItemRef)key, &keyData);
664#endif
665    CFRelease(key);
666
667    encoder << !!keyData;
668    if (keyData) {
669        encode(encoder, keyData);
670        CFRelease(keyData);
671    }
672}
673
674bool decode(ArgumentDecoder& decoder, RetainPtr<SecIdentityRef>& result)
675{
676    RetainPtr<SecCertificateRef> certificate;
677    if (!decode(decoder, certificate))
678        return false;
679
680    bool hasKey;
681    if (!decoder.decode(hasKey))
682        return false;
683
684    if (!hasKey)
685        return true;
686
687    RetainPtr<CFDataRef> keyData;
688    if (!decode(decoder, keyData))
689        return false;
690
691    SecKeyRef key = nullptr;
692#if PLATFORM(IOS)
693    if (secKeyRefDecodingAllowed)
694        SecKeyFindWithPersistentRef(keyData.get(), &key);
695#endif
696#if PLATFORM(MAC)
697    SecKeychainItemCopyFromPersistentReference(keyData.get(), (SecKeychainItemRef*)&key);
698#endif
699    if (key) {
700        result = adoptCF(SecIdentityCreate(kCFAllocatorDefault, certificate.get(), key));
701        CFRelease(key);
702    }
703
704    return true;
705}
706
707#if HAVE(SEC_KEYCHAIN)
708void encode(ArgumentEncoder& encoder, SecKeychainItemRef keychainItem)
709{
710    CFDataRef data;
711    if (SecKeychainItemCreatePersistentReference(keychainItem, &data) == errSecSuccess) {
712        encode(encoder, data);
713        CFRelease(data);
714    }
715}
716
717bool decode(ArgumentDecoder& decoder, RetainPtr<SecKeychainItemRef>& result)
718{
719    RetainPtr<CFDataRef> data;
720    if (!IPC::decode(decoder, data))
721        return false;
722
723    SecKeychainItemRef item;
724    if (SecKeychainItemCopyFromPersistentReference(data.get(), &item) != errSecSuccess || !item)
725        return false;
726
727    result = adoptCF(item);
728    return true;
729}
730#endif
731
732#if HAVE(SEC_ACCESS_CONTROL)
733void encode(ArgumentEncoder& encoder, SecAccessControlRef accessControl)
734{
735    RetainPtr<CFDataRef> data = adoptCF(SecAccessControlCopyData(accessControl));
736    if (data)
737        encode(encoder, data.get());
738}
739
740bool decode(ArgumentDecoder& decoder, RetainPtr<SecAccessControlRef>& result)
741{
742    RetainPtr<CFDataRef> data;
743    if (!decode(decoder, data))
744        return false;
745
746    result = adoptCF(SecAccessControlCreateFromData(kCFAllocatorDefault, data.get(), nullptr));
747    if (!result)
748        return false;
749
750    return true;
751}
752
753#endif
754
755} // namespace IPC
756