OpenVPN 3 Core Library
Loading...
Searching...
No Matches
cf.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#ifndef OPENVPN_APPLECRYPTO_CF_CF_H
13#define OPENVPN_APPLECRYPTO_CF_CF_H
14
15#include <string>
16#include <iostream>
17#include <sstream>
18#include <algorithm>
19#include <utility>
20#include <exception>
21
22#include <CoreFoundation/CoreFoundation.h>
23
24// Wrapper classes for Apple Core Foundation objects.
25
26#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \
27 template <> \
28 struct Type<cftype> \
29 { \
30 static CFTypeRef cast(CFTypeRef obj) \
31 { \
32 if (obj && CFGetTypeID(obj) == idmeth()) \
33 return obj; \
34 else \
35 return nullptr; \
36 } \
37 }; \
38 typedef Wrap<cftype> cls; \
39 inline cls castmeth(CFTypeRef obj) \
40 { \
41 CFTypeRef o = Type<cftype>::cast(obj); \
42 if (o) \
43 return cls(cftype(o), GET); \
44 else \
45 return cls(); \
46 }
47
48namespace openvpn::CF {
49enum Rule
50{
51 CREATE, // create rule
52 GET // get rule
53};
54
55template <typename T>
56struct Type
57{
58};
59
60template <typename T>
61class Wrap
62{
63 public:
65 : obj_(nullptr)
66 {
67 }
68
69 explicit Wrap(T obj, const Rule rule = CREATE)
70 {
71 if (rule == GET && obj)
72 CFRetain(obj);
73 obj_ = obj;
74 }
75
76 Wrap(const Wrap &other)
77 {
78 obj_ = other.obj_;
79 if (obj_)
80 CFRetain(obj_);
81 }
82
83 Wrap &operator=(const Wrap &other)
84 {
85 if (other.obj_)
86 CFRetain(other.obj_);
87 if (obj_)
88 CFRelease(obj_);
89 obj_ = other.obj_;
90 return *this;
91 }
92
93 Wrap(Wrap &&other) noexcept
94 {
95 obj_ = other.obj_;
96 other.obj_ = nullptr;
97 }
98
99 Wrap &operator=(Wrap &&other) noexcept
100 {
101 if (obj_)
102 CFRelease(obj_);
103 obj_ = other.obj_;
104 other.obj_ = nullptr;
105 return *this;
106 }
107
108 void swap(Wrap &other)
109 {
110 std::swap(obj_, other.obj_);
111 }
112
113 void reset(T obj = nullptr, const Rule rule = CREATE)
114 {
115 if (rule == GET && obj)
116 CFRetain(obj);
117 if (obj_)
118 CFRelease(obj_);
119 obj_ = obj;
120 }
121
122 bool defined() const
123 {
124 return obj_ != nullptr;
125 }
126
127 explicit operator bool() const noexcept
128 {
129 return defined();
130 }
131
132 T operator()() const
133 {
134 return obj_;
135 }
136
137 CFTypeRef generic() const
138 {
139 return (CFTypeRef)obj_;
140 }
141
142 static T cast(CFTypeRef obj)
143 {
144 return T(Type<T>::cast(obj));
145 }
146
147 static Wrap from_generic(CFTypeRef obj, const Rule rule = CREATE)
148 {
149 return Wrap(cast(obj), rule);
150 }
151
153 {
154 T ret = obj_;
155 obj_ = nullptr;
156 return ret;
157 }
158
159 CFTypeRef generic_release()
160 {
161 T ret = obj_;
162 obj_ = nullptr;
163 return (CFTypeRef)ret;
164 }
165
166 // Intended for use with Core Foundation methods that require
167 // a T* for saving a create-rule return value
169 {
170 if (obj_)
171 {
172 CFRelease(obj_);
173 obj_ = nullptr;
174 }
175 return &obj_;
176 }
177
178 void show() const
179 {
180 if (obj_)
181 CFShow(obj_);
182 else
183 std::cerr << "CF_UNDEFINED" << std::endl;
184 }
185
186 virtual ~Wrap()
187 {
188 if (obj_)
189 CFRelease(obj_);
190 }
191
192 private:
193 Wrap &operator=(T obj) = delete; // prevent use because no way to pass rule parameter
194
196};
197
198// common CF types
199
200OPENVPN_CF_WRAP(String, string_cast, CFStringRef, CFStringGetTypeID)
201OPENVPN_CF_WRAP(Number, number_cast, CFNumberRef, CFNumberGetTypeID)
202OPENVPN_CF_WRAP(Bool, bool_cast, CFBooleanRef, CFBooleanGetTypeID)
203OPENVPN_CF_WRAP(Data, data_cast, CFDataRef, CFDataGetTypeID)
204OPENVPN_CF_WRAP(Array, array_cast, CFArrayRef, CFArrayGetTypeID)
205OPENVPN_CF_WRAP(MutableArray, mutable_array_cast, CFMutableArrayRef, CFArrayGetTypeID)
206OPENVPN_CF_WRAP(Dict, dict_cast, CFDictionaryRef, CFDictionaryGetTypeID)
207OPENVPN_CF_WRAP(MutableDict, mutable_dict_cast, CFMutableDictionaryRef, CFDictionaryGetTypeID)
208OPENVPN_CF_WRAP(Error, error_cast, CFErrorRef, CFErrorGetTypeID);
209
210// generic CFTypeRef wrapper
211
212typedef Wrap<CFTypeRef> Generic;
213
214inline Generic generic_cast(CFTypeRef obj)
215{
216 return Generic(obj, GET);
217}
218
219// constructors
220
221inline String string(const char *str)
222{
223 return String(CFStringCreateWithCString(kCFAllocatorDefault, str, kCFStringEncodingUTF8));
224}
225
226inline String string(CFStringRef str)
227{
228 return String(str, GET);
229}
230
231inline String string(const String &str)
232{
233 return String(str);
234}
235
236inline String string(const std::string &str)
237{
238 return String(CFStringCreateWithCString(kCFAllocatorDefault, str.c_str(), kCFStringEncodingUTF8));
239}
240
241inline String string(const std::string *str)
242{
243 return String(CFStringCreateWithCString(kCFAllocatorDefault, str->c_str(), kCFStringEncodingUTF8));
244}
245
246inline Number number_from_int(const int n)
247{
248 return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &n));
249}
250
251inline Number number_from_int32(const SInt32 n)
252{
253 return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &n));
254}
255
256inline Number number_from_long_long(const long long n)
257{
258 return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &n));
259}
260
261inline Number number_from_index(const CFIndex n)
262{
263 return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &n));
264}
265
266inline Data data(const void *bytes, CFIndex length)
267{
268 return Data(CFDataCreate(kCFAllocatorDefault, (const UInt8 *)bytes, length));
269}
270
271inline Array array(const void **values, CFIndex numValues)
272{
273 return Array(CFArrayCreate(kCFAllocatorDefault, values, numValues, &kCFTypeArrayCallBacks));
274}
275
276inline Dict dict(const void **keys, const void **values, CFIndex numValues)
277{
278 return Dict(CFDictionaryCreate(kCFAllocatorDefault,
279 keys,
280 values,
281 numValues,
282 &kCFTypeDictionaryKeyCallBacks,
283 &kCFTypeDictionaryValueCallBacks));
284}
285
286inline Dict const_dict(MutableDict &mdict)
287{
288 return Dict(mdict(), CF::GET);
289}
290
291inline Array const_array(MutableArray &marray)
292{
293 return Array(marray(), CF::GET);
294}
295
296inline Dict empty_dict()
297{
298 return Dict(CFDictionaryCreate(kCFAllocatorDefault,
299 nullptr,
300 nullptr,
301 0,
302 &kCFTypeDictionaryKeyCallBacks,
303 &kCFTypeDictionaryValueCallBacks));
304}
305
306inline MutableArray mutable_array(const CFIndex capacity = 0)
307{
308 return MutableArray(CFArrayCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeArrayCallBacks));
309}
310
311inline MutableDict mutable_dict(const CFIndex capacity = 0)
312{
313 return MutableDict(CFDictionaryCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
314}
315
316template <typename DICT>
317inline MutableDict mutable_dict_copy(const DICT &dict, const CFIndex capacity = 0)
318{
319 if (dict.defined())
320 return MutableDict(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity, dict()));
321 else
322 return mutable_dict(capacity);
323}
324
325inline Error error(CFStringRef domain, CFIndex code, CFDictionaryRef userInfo)
326{
327 return Error(CFErrorCreate(kCFAllocatorDefault, domain, code, userInfo));
328}
329
330// accessors
331
332template <typename ARRAY>
333inline CFIndex array_len(const ARRAY &array)
334{
335 if (array.defined())
336 return CFArrayGetCount(array());
337 else
338 return 0;
339}
340
341template <typename DICT>
342inline CFIndex dict_len(const DICT &dict)
343{
344 if (dict.defined())
345 return CFDictionaryGetCount(dict());
346 else
347 return 0;
348}
349
350template <typename ARRAY>
351inline CFTypeRef array_index(const ARRAY &array, const CFIndex idx)
352{
353 if (array.defined() && CFArrayGetCount(array()) > idx)
354 return CFArrayGetValueAtIndex(array(), idx);
355 else
356 return nullptr;
357}
358
359template <typename DICT, typename KEY>
360inline CFTypeRef dict_index(const DICT &dict, const KEY &key)
361{
362 if (dict.defined())
363 {
364 String keystr = string(key);
365 if (keystr.defined())
366 return CFDictionaryGetValue(dict(), keystr());
367 }
368 return nullptr;
369}
370
371// string methods
372
373struct cppstring_error : public std::exception
374{
375 const char *what() const noexcept override
376 {
377 return "cppstring_error";
378 }
379};
380
381inline std::string cppstring(CFStringRef str)
382{
383 const CFStringEncoding encoding = kCFStringEncodingUTF8;
384 if (str)
385 {
386 const CFIndex len = CFStringGetLength(str);
387 if (len > 0)
388 {
389 const CFIndex maxsize = CFStringGetMaximumSizeForEncoding(len, encoding);
390 char *buf = new char[maxsize];
391 const Boolean status = CFStringGetCString(str, buf, maxsize, encoding);
392 if (status)
393 {
394 std::string ret(buf);
395 delete[] buf;
396 return ret;
397 }
398 else
399 {
400 delete[] buf;
401 throw cppstring_error();
402 }
403 }
404 }
405 return "";
406}
407
408inline std::string cppstring(const String &str)
409{
410 return cppstring(str());
411}
412
413inline std::string description(CFTypeRef obj)
414{
415 if (obj)
416 {
417 String s(CFCopyDescription(obj));
418 return cppstring(s);
419 }
420 else
421 return "UNDEF";
422}
423
424// format an array of strings (non-string elements in array are ignored)
425template <typename ARRAY>
426inline std::string array_to_string(const ARRAY &array, const char delim = ',')
427{
428 std::ostringstream os;
429 const CFIndex len = array_len(array);
430 if (len)
431 {
432 bool sep = false;
433 for (CFIndex i = 0; i < len; ++i)
434 {
435 const String v(string_cast(array_index(array, i)));
436 if (v.defined())
437 {
438 if (sep)
439 os << delim;
440 os << cppstring(v);
441 sep = true;
442 }
443 }
444 }
445 return os.str();
446}
447
448inline bool string_equal(const String &s1, const String &s2, const CFStringCompareFlags compareOptions = 0)
449{
450 return s1.defined() && s2.defined() && CFStringCompare(s1(), s2(), compareOptions) == kCFCompareEqualTo;
451}
452
453// property lists
454inline Data plist(CFTypeRef obj)
455{
456 return Data(CFPropertyListCreateData(kCFAllocatorDefault,
457 obj,
458 kCFPropertyListBinaryFormat_v1_0,
459 0,
460 nullptr));
461}
462
463} // namespace openvpn::CF
464
465#endif // OPENVPN_APPLECRYPTO_CF_CF_H
#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth)
Definition cf.hpp:26
Wrap & operator=(T obj)=delete
T operator()() const
Definition cf.hpp:132
Wrap(Wrap &&other) noexcept
Definition cf.hpp:93
void swap(Wrap &other)
Definition cf.hpp:108
void show() const
Definition cf.hpp:178
static Wrap from_generic(CFTypeRef obj, const Rule rule=CREATE)
Definition cf.hpp:147
CFTypeRef generic_release()
Definition cf.hpp:159
Wrap & operator=(const Wrap &other)
Definition cf.hpp:83
Wrap & operator=(Wrap &&other) noexcept
Definition cf.hpp:99
static T cast(CFTypeRef obj)
Definition cf.hpp:142
Wrap(T obj, const Rule rule=CREATE)
Definition cf.hpp:69
T * mod_ref()
Definition cf.hpp:168
bool defined() const
Definition cf.hpp:122
Wrap(const Wrap &other)
Definition cf.hpp:76
void reset(T obj=nullptr, const Rule rule=CREATE)
Definition cf.hpp:113
virtual ~Wrap()
Definition cf.hpp:186
@ CREATE
Definition cf.hpp:51
Data data(const void *bytes, CFIndex length)
Definition cf.hpp:266
CFIndex array_len(const ARRAY &array)
Definition cf.hpp:333
MutableArray mutable_array(const CFIndex capacity=0)
Definition cf.hpp:306
std::string array_to_string(const ARRAY &array, const char delim=',')
Definition cf.hpp:426
MutableDict mutable_dict_copy(const DICT &dict, const CFIndex capacity=0)
Definition cf.hpp:317
Array array(const void **values, CFIndex numValues)
Definition cf.hpp:271
Number number_from_int(const int n)
Definition cf.hpp:246
Dict empty_dict()
Definition cf.hpp:296
Array const_array(MutableArray &marray)
Definition cf.hpp:291
Generic generic_cast(CFTypeRef obj)
Definition cf.hpp:214
CFTypeRef array_index(const ARRAY &array, const CFIndex idx)
Definition cf.hpp:351
Number number_from_long_long(const long long n)
Definition cf.hpp:256
CFIndex dict_len(const DICT &dict)
Definition cf.hpp:342
String string(const char *str)
Definition cf.hpp:221
Wrap< CFTypeRef > Generic
Definition cf.hpp:212
std::string cppstring(CFStringRef str)
Definition cf.hpp:381
Number number_from_index(const CFIndex n)
Definition cf.hpp:261
Error error(CFStringRef domain, CFIndex code, CFDictionaryRef userInfo)
Definition cf.hpp:325
Number number_from_int32(const SInt32 n)
Definition cf.hpp:251
bool string_equal(const String &s1, const String &s2, const CFStringCompareFlags compareOptions=0)
Definition cf.hpp:448
Dict dict(const void **keys, const void **values, CFIndex numValues)
Definition cf.hpp:276
MutableDict mutable_dict(const CFIndex capacity=0)
Definition cf.hpp:311
std::string description(CFTypeRef obj)
Definition cf.hpp:413
Dict const_dict(MutableDict &mdict)
Definition cf.hpp:286
CFTypeRef dict_index(const DICT &dict, const KEY &key)
Definition cf.hpp:360
Data plist(CFTypeRef obj)
Definition cf.hpp:454
const char * what() const noexcept override
Definition cf.hpp:375
os<< "Session Name: "<< tbc-> session_name<< '\n';os<< "Layer: "<< tbc-> layer str()<< '\n'
std::string ret
std::ostringstream os