1/*
2 * Copyright (c) 2000-2004,2011-2014 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
25//
26//CoreFoundation related utilities
27//
28#ifndef _H_CFUTILITIES
29#define _H_CFUTILITIES
30
31#include <security_utilities/utilities.h>
32#include <security_utilities/globalizer.h>
33#include <CoreFoundation/CoreFoundation.h>
34#include <algorithm>
35#include <Security/SecBase.h>
36#undef check
37
38
39namespace Security {
40
41
42//
43// Traits of popular CF types
44//
45template <class CFType> struct CFTraits { };
46
47template <> struct CFTraits<CFTypeRef> {
48	static bool check(CFTypeRef ref) { return true; }
49};
50
51#define __SEC_CFTYPE(name) \
52	template <> struct CFTraits<name##Ref> { \
53		static CFTypeID cfid() { return name##GetTypeID(); } \
54		static bool check(CFTypeRef ref) { return CFGetTypeID(ref) == cfid(); } \
55	};
56
57__SEC_CFTYPE(CFNull)
58__SEC_CFTYPE(CFBoolean)
59__SEC_CFTYPE(CFNumber)
60__SEC_CFTYPE(CFString)
61__SEC_CFTYPE(CFData)
62__SEC_CFTYPE(CFDate)
63__SEC_CFTYPE(CFURL)
64__SEC_CFTYPE(CFBundle)
65__SEC_CFTYPE(CFArray)
66__SEC_CFTYPE(CFDictionary)
67__SEC_CFTYPE(CFSet)
68
69
70//
71// Initialize-only self-releasing CF object handler (lightweight).
72//
73template <class CFType> class CFRef {
74public:
75    CFRef() : mRef(NULL) { }
76    CFRef(CFType ref) : mRef(ref) { }
77    ~CFRef() { this->release(); }
78	CFRef(const CFRef &ref) : mRef(ref) {}
79	template <class _T> CFRef(const CFRef<_T> &ref) : mRef(ref) {}
80
81	CFRef(CFTypeRef ref, OSStatus err)
82		: mRef(CFType(ref))
83	{
84		if (ref && !CFTraits<CFType>::check(ref))
85			MacOSError::throwMe(err);
86	}
87
88	CFRef &take(CFType ref)
89	{ this->release(); mRef = ref; return *this; }
90
91	CFType yield()
92	{ CFType r = mRef; mRef = NULL; return r; }
93
94    CFRef &operator = (CFType ref)
95    { if (ref) CFRetain(ref); return take(ref); }
96
97	CFRef &operator = (const CFRef &ref)
98	{ if (ref) CFRetain(ref); return take(ref); }
99
100	// take variant for when newly created CFType is returned
101	// via a ptr-to-CFType argument.
102	CFType *take()
103	{ if (mRef) CFRelease(mRef); mRef = NULL; return &mRef; }
104
105    operator CFType () const { return mRef; }
106    operator bool () const { return mRef != NULL; }
107    bool operator ! () const { return mRef == NULL; }
108
109	CFType get() const { return mRef; }
110
111	CFType &aref()
112	{ take(NULL); return mRef; }
113
114	CFType retain() const
115	{ if (mRef) CFRetain(mRef); return mRef; }
116
117	void release() const
118	{ if (mRef) CFRelease(mRef); }
119
120	template <class NewType>
121	bool is() const { return CFTraits<NewType>::check(mRef); }
122
123	template <class OldType>
124	static CFType check(OldType cf, OSStatus err)
125	{
126		if (cf && !CFTraits<CFType>::check(cf))
127			MacOSError::throwMe(err);
128		return CFType(cf);
129	}
130
131	template <class NewType>
132	NewType as() const { return NewType(mRef); }
133
134	template <class NewType>
135	NewType as(OSStatus err) const { return CFRef<NewType>::check(mRef, err); }
136
137private:
138    CFType mRef;
139};
140
141
142template <class CFType> class CFCopyRef : public CFRef<CFType> {
143	typedef CFRef<CFType> _Base;
144public:
145    CFCopyRef() { }
146    CFCopyRef(CFType ref) : _Base(ref) { this->retain(); }
147    CFCopyRef(const CFCopyRef &ref) : _Base(ref) { this->retain(); }
148	template <class _T> CFCopyRef(const CFRef<_T> &ref) : _Base(ref) { this->retain(); }
149	CFCopyRef(CFTypeRef ref, OSStatus err) : _Base(ref, err) { this->retain(); }
150
151	CFCopyRef &take(CFType ref)
152	{ _Base::take(ref); return *this; }
153
154    CFCopyRef &operator = (CFType ref)
155    { if (ref) CFRetain(ref); return take(ref); }
156
157	CFCopyRef &operator = (const CFCopyRef &ref)
158	{ _Base::operator = (ref); return *this; }
159
160	template <class _T> CFCopyRef &operator = (const CFRef<_T> &ref)
161	{ _Base::operator = (ref); return *this; }
162};
163
164
165//
166// A simple function that turns a non-array CFTypeRef into
167// an array of one with that element. This will retain its argument
168// (directly or indirectly).
169//
170inline CFArrayRef cfArrayize(CFTypeRef arrayOrItem)
171{
172    if (arrayOrItem == NULL)
173        return NULL;		// NULL is NULL
174    else if (CFGetTypeID(arrayOrItem) == CFArrayGetTypeID()) {
175		CFRetain(arrayOrItem);
176        return CFArrayRef(arrayOrItem);		// already an array
177    } else {
178        return CFArrayCreate(NULL,
179            (const void **)&arrayOrItem, 1, &kCFTypeArrayCallBacks);
180    }
181}
182
183
184//
185// An empty CFArray.
186// Since CFArrays are type-neutral, a single immutable empty array will
187// serve for all uses. So keep it.
188//
189struct CFEmptyArray {
190	operator CFArrayRef () { return mArray; }
191	CFEmptyArray();
192private:
193	CFArrayRef mArray;
194};
195
196extern ModuleNexus<CFEmptyArray> cfEmptyArray;
197
198
199//
200// Translate CFStringRef or CFURLRef to (UTF8-encoded) C++ string.
201// If release==true, a CFRelease will be performed on the CFWhatever argument
202// whether the call succeeds or not(!).
203//
204string cfString(CFStringRef str);	// extract UTF8 string
205string cfString(CFURLRef url);	// path of file: URL (only)
206string cfString(CFBundleRef bundle);	// path to bundle root
207
208string cfStringRelease(CFStringRef str CF_CONSUMED);	// extract UTF8 string
209string cfStringRelease(CFURLRef url CF_CONSUMED);	// path of file: URL (only)
210string cfStringRelease(CFBundleRef bundle CF_CONSUMED);	// path to bundle root
211
212
213string cfString(CFTypeRef anything, OSStatus err);		// dynamic form; throws err on NULL
214
215
216//
217// Handle CFNumberRefs.
218// This is nasty because CFNumber does not support unsigned types, and there's really no portably-safe
219// way of working around this. So the handling of unsigned numbers is "almost correct."
220//
221template <class Number>
222struct CFNumberTraits;
223
224template <> struct CFNumberTraits<char> {
225	static const CFNumberType cfnType = kCFNumberCharType;
226	typedef char ValueType;
227};
228template <> struct CFNumberTraits<short> {
229	static const CFNumberType cfnType = kCFNumberShortType;
230	typedef short ValueType;
231};
232template <> struct CFNumberTraits<int> {
233	static const CFNumberType cfnType = kCFNumberIntType;
234	typedef int ValueType;
235};
236template <> struct CFNumberTraits<long> {
237	static const CFNumberType cfnType = kCFNumberLongType;
238	typedef long ValueType;
239};
240template <> struct CFNumberTraits<long long> {
241	static const CFNumberType cfnType = kCFNumberLongLongType;
242	typedef long long ValueType;
243};
244template <> struct CFNumberTraits<float> {
245	static const CFNumberType cfnType = kCFNumberFloatType;
246	typedef float ValueType;
247};
248template <> struct CFNumberTraits<double> {
249	static const CFNumberType cfnType = kCFNumberDoubleType;
250	typedef double ValueType;
251};
252
253template <> struct CFNumberTraits<unsigned char> {
254	static const CFNumberType cfnType = kCFNumberIntType;
255	typedef int ValueType;
256};
257template <> struct CFNumberTraits<unsigned short> {
258	static const CFNumberType cfnType = kCFNumberIntType;
259	typedef int ValueType;
260};
261template <> struct CFNumberTraits<unsigned int> {
262	static const CFNumberType cfnType = kCFNumberLongLongType;
263	typedef long long ValueType;
264};
265template <> struct CFNumberTraits<unsigned long> {
266	static const CFNumberType cfnType = kCFNumberLongLongType;
267	typedef long long ValueType;
268};
269template <> struct CFNumberTraits<unsigned long long> {
270	static const CFNumberType cfnType = kCFNumberLongLongType;
271	typedef long long ValueType;
272};
273
274template <class Number>
275Number cfNumber(CFNumberRef number)
276{
277	typename CFNumberTraits<Number>::ValueType value;
278	if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value))
279		return (Number)value;
280	else
281		CFError::throwMe();
282}
283
284template <class Number>
285Number cfNumber(CFNumberRef number, Number defaultValue)
286{
287	typename CFNumberTraits<Number>::ValueType value;
288	if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value))
289		return value;
290	else
291		return defaultValue;
292}
293
294template <class Number>
295CFNumberRef makeCFNumber(Number value)
296{
297	typename CFNumberTraits<Number>::ValueType cfValue = value;
298	return CFNumberCreate(NULL, CFNumberTraits<Number>::cfnType, &cfValue);
299}
300
301// legacy form
302inline uint32_t cfNumber(CFNumberRef number) { return cfNumber<uint32_t>(number); }
303
304
305//
306// Translate strings into CFStrings
307//
308inline CFStringRef makeCFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8)
309{
310	return s ? CFStringCreateWithCString(NULL, s, encoding) : NULL;
311}
312
313inline CFStringRef makeCFString(const string &s, CFStringEncoding encoding = kCFStringEncodingUTF8)
314{
315	return CFStringCreateWithCString(NULL, s.c_str(), encoding);
316}
317
318inline CFStringRef makeCFString(CFDataRef data, CFStringEncoding encoding = kCFStringEncodingUTF8)
319{
320	return CFStringCreateFromExternalRepresentation(NULL, data, encoding);
321}
322
323
324//
325// Create CFURL objects from various sources
326//
327CFURLRef makeCFURL(const char *s, bool isDirectory = false, CFURLRef base = NULL);
328CFURLRef makeCFURL(CFStringRef s, bool isDirectory = false, CFURLRef base = NULL);
329
330inline CFURLRef makeCFURL(const string &s, bool isDirectory = false, CFURLRef base = NULL)
331{
332	return makeCFURL(s.c_str(), isDirectory, base);
333}
334
335
336//
337// Make temporary CF objects.
338//
339class CFTempString : public CFRef<CFStringRef> {
340public:
341	template <class Source>
342	CFTempString(Source s) : CFRef<CFStringRef>(makeCFString(s)) { }
343};
344
345class CFTempURL : public CFRef<CFURLRef> {
346public:
347	template <class Source>
348	CFTempURL(Source s, bool isDirectory = false, CFURLRef base = NULL)
349		: CFRef<CFURLRef>(makeCFURL(s, isDirectory, base)) { }
350};
351
352
353//
354// A temporary CFNumber
355//
356class CFTempNumber : public CFRef<CFNumberRef> {
357public:
358	template <class Value>
359	CFTempNumber(Value value) : CFRef<CFNumberRef>(makeCFNumber(value)) { }
360};
361
362
363//
364// A temporary CFData.
365//
366class CFTempData : public CFRef<CFDataRef> {
367public:
368	CFTempData(const void *data, size_t length)
369		: CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)data, length)) { }
370
371	template <class Dataoid>
372	CFTempData(const Dataoid &dataoid)
373		: CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)dataoid.data(), dataoid.length())) { }
374};
375
376class CFTempDataWrap : public CFRef<CFDataRef> {
377public:
378	CFTempDataWrap(const void *data, size_t length)
379		: CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, length, kCFAllocatorNull)) { }
380
381	template <class Dataoid>
382	CFTempDataWrap(const Dataoid &dataoid)
383		: CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)dataoid.data(), dataoid.length(), kCFAllocatorNull)) { }
384};
385
386
387//
388// Create CFData objects from various sources.
389//
390inline CFDataRef makeCFData(const void *data, size_t size)
391{
392	return CFDataCreate(NULL, (const UInt8 *)data, size);
393}
394
395inline CFDataRef makeCFData(CFDictionaryRef dictionary)
396{
397	return CFPropertyListCreateXMLData(NULL, dictionary);
398}
399
400template <class Data>
401inline CFDataRef makeCFData(const Data &source)
402{
403	return CFDataCreate(NULL, reinterpret_cast<const UInt8 *>(source.data()), source.length());
404}
405
406inline CFDataRef makeCFDataMalloc(const void *data, size_t size)
407{
408	return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, size, kCFAllocatorMalloc);
409}
410
411template <class Data>
412inline CFDataRef makeCFDataMalloc(const Data &source)
413{
414	return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)source.data(), source.length(), kCFAllocatorMalloc);
415}
416
417
418//
419// Create a CFDataRef from malloc'ed data, exception-safely
420//
421class CFMallocData {
422public:
423	CFMallocData(size_t size)
424		: mData(::malloc(size)), mSize(size)
425	{
426		if (!mData)
427			UnixError::throwMe();
428	}
429
430	~CFMallocData()
431	{
432		if (mData)
433			::free(mData);
434	}
435
436	template <class T>
437	operator T * ()
438	{ return static_cast<T *>(mData); }
439
440	operator CFDataRef ();
441
442	void *data()				{ return mData; }
443	const void *data() const	{ return mData; }
444	size_t length() const		{ return mSize; }
445
446private:
447	void *mData;
448	size_t mSize;
449};
450
451
452//
453// Make CFDictionaries from stuff
454//
455CFDictionaryRef makeCFDictionary(unsigned count, ...);					// key/value pairs
456CFMutableDictionaryRef makeCFMutableDictionary();						// empty
457CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...);	// (count) key/value pairs
458CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict);	// copy of dictionary
459
460CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) CF_RETURNS_RETAINED;// interpret plist form
461CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) CF_RETURNS_RETAINED; // ditto
462
463
464//
465// Parsing out a CFDictionary without losing your lunch
466//
467class CFDictionary : public CFCopyRef<CFDictionaryRef> {
468	typedef CFCopyRef<CFDictionaryRef> _Base;
469public:
470	CFDictionary(CFDictionaryRef ref, OSStatus error) : _Base(ref), mDefaultError(error)
471	{ if (!ref) MacOSError::throwMe(error); }
472	CFDictionary(CFTypeRef ref, OSStatus error) : _Base(ref, error), mDefaultError(error)
473	{ if (!ref) MacOSError::throwMe(error); }
474	CFDictionary(OSStatus error) : _Base(NULL), mDefaultError(error) { }
475
476	using CFCopyRef<CFDictionaryRef>::get;
477
478	CFTypeRef get(CFStringRef key)		{ return CFDictionaryGetValue(*this, key); }
479	CFTypeRef get(const char *key)		{ return CFDictionaryGetValue(*this, CFTempString(key)); }
480
481	template <class CFType>
482	CFType get(CFStringRef key, OSStatus err = errSecSuccess) const
483	{
484		CFTypeRef elem = CFDictionaryGetValue(*this, key);
485		return CFRef<CFType>::check(elem, err ? err : mDefaultError);
486	}
487
488	template <class CFType>
489	CFType get(const char *key, OSStatus err = errSecSuccess) const
490	{ return get<CFType>(CFTempString(key), err); }
491
492	void apply(CFDictionaryApplierFunction func, void *context)
493	{ return CFDictionaryApplyFunction(*this, func, context); }
494
495private:
496	template <class T>
497	struct Applier {
498		T *object;
499		void (T::*func)(CFTypeRef key, CFTypeRef value);
500		static void apply(CFTypeRef key, CFTypeRef value, void *context)
501		{ Applier *me = (Applier *)context; return ((me->object)->*(me->func))(key, value); }
502	};
503
504	template <class Key, class Value>
505	struct BlockApplier {
506		void (^action)(Key key, Value value);
507		static void apply(CFTypeRef key, CFTypeRef value, void* context)
508		{ BlockApplier *me = (BlockApplier *)context; return me->action(Key(key), Value(value)); }
509	};
510
511public:
512	template <class T>
513	void apply(T *object, void (T::*func)(CFTypeRef key, CFTypeRef value))
514	{ Applier<T> app; app.object = object; app.func = func; return apply(app.apply, &app); }
515
516	template <class Key = CFTypeRef, class Value = CFTypeRef>
517	void apply(void (^action)(Key key, Value value))
518	{ BlockApplier<Key, Value> app; app.action = action; return apply(app.apply, &app); }
519
520private:
521	OSStatus mDefaultError;
522};
523
524
525//
526// CFURLAccess wrappers for specific purposes
527//
528CFDataRef cfLoadFile(CFURLRef url);
529CFDataRef cfLoadFile(int fd, size_t bytes);
530inline CFDataRef cfLoadFile(CFStringRef path) { return cfLoadFile(CFTempURL(path)); }
531inline CFDataRef cfLoadFile(const std::string &path) { return cfLoadFile(CFTempURL(path)); }
532inline CFDataRef cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); }
533
534
535//
536// Internally used STL adapters. Should probably be in utilities.h.
537//
538template <class Self>
539Self projectPair(const Self &me)
540{ return me; }
541
542template <class First, class Second>
543Second projectPair(const pair<First, Second> &me)
544{ return me.second; }
545
546
547//
548// A CFToVector turns a CFArrayRef of items into a flat
549// C vector of some type, using a conversion function
550// (from CFTypeRef) specified. As a special bonus, if
551// you provide a CFTypeRef (other than CFArrayRef), it
552// will be transparently handled as an array-of-one.
553// The array will be automatically released on destruction
554// of the CFToVector object. Any internal structure shared
555// with the CFTypeRef inputs will be left alone.
556//
557template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)>
558class CFToVector {
559public:
560    CFToVector(CFArrayRef arrayRef);
561    ~CFToVector()						{ delete[] mVector; }
562    operator UInt32 () const			{ return mCount; }
563    operator VectorBase *() const		{ return mVector; }
564    bool empty() const					{ return mCount == 0; }
565
566	VectorBase *begin() const			{ return mVector; }
567	VectorBase *end() const				{ return mVector + mCount; }
568
569    VectorBase &operator [] (UInt32 ix) const { assert(ix < mCount); return mVector[ix]; }
570
571private:
572    VectorBase *mVector;
573    UInt32 mCount;
574};
575
576template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)>
577CFToVector<VectorBase, CFRefType, convert>::CFToVector(CFArrayRef arrayRef)
578{
579    if (arrayRef == NULL) {
580        mCount = 0;
581        mVector = NULL;
582    } else {
583        mCount = (UInt32)CFArrayGetCount(arrayRef);
584        mVector = new VectorBase[mCount];
585        for (UInt32 n = 0; n < mCount; n++)
586            mVector[n] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef, n)));
587    }
588}
589
590
591//
592// Make CFArrays from stuff.
593//
594template <class Iterator, class Generator>
595inline CFArrayRef makeCFArray(Generator &generate, Iterator first, Iterator last)
596{
597	// how many elements?
598	size_t size = distance(first, last);
599
600	// do the CFArrayCreate tango
601    auto_array<CFTypeRef> vec(size);
602    for (UInt32 n = 0; n < size; n++)
603        vec[n] = generate(projectPair(*first++));
604    assert(first == last);
605    return CFArrayCreate(NULL, (const void **)vec.get(), size, &kCFTypeArrayCallBacks);
606}
607
608template <class Container, class Generator>
609inline CFArrayRef makeCFArray(Generator &generate, const Container &container)
610{
611	return makeCFArray(generate, container.begin(), container.end());
612}
613
614CFArrayRef makeCFArray(CFIndex count, ...) CF_RETURNS_RETAINED;
615CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) CF_RETURNS_RETAINED;
616
617
618} // end namespace Security
619
620#endif //_H_CFUTILITIES
621