mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
460 lines
11 KiB
C++
460 lines
11 KiB
C++
// OpenVPN -- An application to securely tunnel IP networks
|
|
// over a single port, with support for SSL/TLS-based
|
|
// session authentication and key exchange,
|
|
// packet encryption, packet authentication, and
|
|
// packet compression.
|
|
//
|
|
// Copyright (C) 2012-2017 OpenVPN Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
// as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program in the COPYING file.
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef OPENVPN_APPLECRYPTO_CF_CF_H
|
|
#define OPENVPN_APPLECRYPTO_CF_CF_H
|
|
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <exception>
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
// Wrapper classes for Apple Core Foundation objects.
|
|
|
|
#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \
|
|
template <> \
|
|
struct Type<cftype> \
|
|
{ \
|
|
static CFTypeRef cast(CFTypeRef obj) \
|
|
{ \
|
|
if (obj && CFGetTypeID(obj) == idmeth()) \
|
|
return obj; \
|
|
else \
|
|
return nullptr; \
|
|
} \
|
|
}; \
|
|
typedef Wrap<cftype> cls; \
|
|
inline cls castmeth(CFTypeRef obj) \
|
|
{ \
|
|
CFTypeRef o = Type<cftype>::cast(obj); \
|
|
if (o) \
|
|
return cls(cftype(o), GET); \
|
|
else \
|
|
return cls(); \
|
|
}
|
|
|
|
namespace openvpn {
|
|
namespace CF
|
|
{
|
|
enum Rule {
|
|
CREATE, // create rule
|
|
GET // get rule
|
|
};
|
|
|
|
template <typename T> struct Type {};
|
|
|
|
template <typename T>
|
|
class Wrap
|
|
{
|
|
public:
|
|
Wrap() : obj_(nullptr) {}
|
|
|
|
explicit Wrap(T obj, const Rule rule=CREATE)
|
|
{
|
|
if (rule == GET && obj)
|
|
CFRetain(obj);
|
|
obj_ = obj;
|
|
}
|
|
|
|
Wrap(const Wrap& other)
|
|
{
|
|
obj_ = other.obj_;
|
|
if (obj_)
|
|
CFRetain(obj_);
|
|
}
|
|
|
|
Wrap& operator=(const Wrap& other)
|
|
{
|
|
if (other.obj_)
|
|
CFRetain(other.obj_);
|
|
if (obj_)
|
|
CFRelease(obj_);
|
|
obj_ = other.obj_;
|
|
return *this;
|
|
}
|
|
|
|
Wrap(Wrap&& other) noexcept
|
|
{
|
|
obj_ = other.obj_;
|
|
other.obj_ = nullptr;
|
|
}
|
|
|
|
Wrap& operator=(Wrap&& other) noexcept
|
|
{
|
|
if (obj_)
|
|
CFRelease(obj_);
|
|
obj_ = other.obj_;
|
|
other.obj_ = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
void swap(Wrap& other)
|
|
{
|
|
std::swap(obj_, other.obj_);
|
|
}
|
|
|
|
void reset(T obj=nullptr, const Rule rule=CREATE)
|
|
{
|
|
if (rule == GET && obj)
|
|
CFRetain(obj);
|
|
if (obj_)
|
|
CFRelease(obj_);
|
|
obj_ = obj;
|
|
}
|
|
|
|
bool defined() const { return obj_ != nullptr; }
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return defined();
|
|
}
|
|
|
|
T operator()() const { return obj_; }
|
|
|
|
CFTypeRef generic() const { return (CFTypeRef)obj_; }
|
|
|
|
static T cast(CFTypeRef obj) { return T(Type<T>::cast(obj)); }
|
|
|
|
static Wrap from_generic(CFTypeRef obj, const Rule rule=CREATE)
|
|
{
|
|
return Wrap(cast(obj), rule);
|
|
}
|
|
|
|
T release()
|
|
{
|
|
T ret = obj_;
|
|
obj_ = nullptr;
|
|
return ret;
|
|
}
|
|
|
|
CFTypeRef generic_release()
|
|
{
|
|
T ret = obj_;
|
|
obj_ = nullptr;
|
|
return (CFTypeRef)ret;
|
|
}
|
|
|
|
// Intended for use with Core Foundation methods that require
|
|
// a T* for saving a create-rule return value
|
|
T* mod_ref()
|
|
{
|
|
if (obj_)
|
|
{
|
|
CFRelease(obj_);
|
|
obj_ = nullptr;
|
|
}
|
|
return &obj_;
|
|
}
|
|
|
|
void show() const
|
|
{
|
|
if (obj_)
|
|
CFShow(obj_);
|
|
else
|
|
std::cerr << "CF_UNDEFINED" << std::endl;
|
|
}
|
|
|
|
virtual ~Wrap()
|
|
{
|
|
if (obj_)
|
|
CFRelease(obj_);
|
|
}
|
|
|
|
private:
|
|
Wrap& operator=(T obj) = delete; // prevent use because no way to pass rule parameter
|
|
|
|
T obj_;
|
|
};
|
|
|
|
// common CF types
|
|
|
|
OPENVPN_CF_WRAP(String, string_cast, CFStringRef, CFStringGetTypeID)
|
|
OPENVPN_CF_WRAP(Number, number_cast, CFNumberRef, CFNumberGetTypeID)
|
|
OPENVPN_CF_WRAP(Bool, bool_cast, CFBooleanRef, CFBooleanGetTypeID)
|
|
OPENVPN_CF_WRAP(Data, data_cast, CFDataRef, CFDataGetTypeID)
|
|
OPENVPN_CF_WRAP(Array, array_cast, CFArrayRef, CFArrayGetTypeID)
|
|
OPENVPN_CF_WRAP(MutableArray, mutable_array_cast, CFMutableArrayRef, CFArrayGetTypeID)
|
|
OPENVPN_CF_WRAP(Dict, dict_cast, CFDictionaryRef, CFDictionaryGetTypeID)
|
|
OPENVPN_CF_WRAP(MutableDict, mutable_dict_cast, CFMutableDictionaryRef, CFDictionaryGetTypeID)
|
|
OPENVPN_CF_WRAP(Error, error_cast, CFErrorRef, CFErrorGetTypeID);
|
|
|
|
// generic CFTypeRef wrapper
|
|
|
|
typedef Wrap<CFTypeRef> Generic;
|
|
|
|
inline Generic generic_cast(CFTypeRef obj)
|
|
{
|
|
return Generic(obj, GET);
|
|
}
|
|
|
|
// constructors
|
|
|
|
inline String string(const char *str)
|
|
{
|
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str, kCFStringEncodingUTF8));
|
|
}
|
|
|
|
inline String string(CFStringRef str)
|
|
{
|
|
return String(str, GET);
|
|
}
|
|
|
|
inline String string(const String& str)
|
|
{
|
|
return String(str);
|
|
}
|
|
|
|
inline String string(const std::string& str)
|
|
{
|
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str.c_str(), kCFStringEncodingUTF8));
|
|
}
|
|
|
|
inline String string(const std::string* str)
|
|
{
|
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str->c_str(), kCFStringEncodingUTF8));
|
|
}
|
|
|
|
inline Number number_from_int(const int n)
|
|
{
|
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &n));
|
|
}
|
|
|
|
inline Number number_from_int32(const SInt32 n)
|
|
{
|
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &n));
|
|
}
|
|
|
|
inline Number number_from_long_long(const long long n)
|
|
{
|
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &n));
|
|
}
|
|
|
|
inline Number number_from_index(const CFIndex n)
|
|
{
|
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &n));
|
|
}
|
|
|
|
inline Data data(const void *bytes, CFIndex length)
|
|
{
|
|
return Data(CFDataCreate(kCFAllocatorDefault, (const UInt8 *)bytes, length));
|
|
}
|
|
|
|
inline Array array(const void **values, CFIndex numValues)
|
|
{
|
|
return Array(CFArrayCreate(kCFAllocatorDefault, values, numValues, &kCFTypeArrayCallBacks));
|
|
}
|
|
|
|
inline Dict dict(const void **keys, const void **values, CFIndex numValues)
|
|
{
|
|
return Dict(CFDictionaryCreate(kCFAllocatorDefault,
|
|
keys,
|
|
values,
|
|
numValues,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
}
|
|
|
|
inline Dict const_dict(MutableDict& mdict)
|
|
{
|
|
return Dict(mdict(), CF::GET);
|
|
}
|
|
|
|
inline Array const_array(MutableArray& marray)
|
|
{
|
|
return Array(marray(), CF::GET);
|
|
}
|
|
|
|
inline Dict empty_dict()
|
|
{
|
|
return Dict(CFDictionaryCreate(kCFAllocatorDefault,
|
|
nullptr,
|
|
nullptr,
|
|
0,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
}
|
|
|
|
inline MutableArray mutable_array(const CFIndex capacity=0)
|
|
{
|
|
return MutableArray(CFArrayCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeArrayCallBacks));
|
|
}
|
|
|
|
inline MutableDict mutable_dict(const CFIndex capacity=0)
|
|
{
|
|
return MutableDict(CFDictionaryCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
|
}
|
|
|
|
template <typename DICT>
|
|
inline MutableDict mutable_dict_copy(const DICT& dict, const CFIndex capacity=0)
|
|
{
|
|
if (dict.defined())
|
|
return MutableDict(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity, dict()));
|
|
else
|
|
return mutable_dict(capacity);
|
|
}
|
|
|
|
inline Error error(CFStringRef domain, CFIndex code, CFDictionaryRef userInfo)
|
|
{
|
|
return Error(CFErrorCreate(kCFAllocatorDefault, domain, code, userInfo));
|
|
}
|
|
|
|
// accessors
|
|
|
|
template <typename ARRAY>
|
|
inline CFIndex array_len(const ARRAY& array)
|
|
{
|
|
if (array.defined())
|
|
return CFArrayGetCount(array());
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
template <typename DICT>
|
|
inline CFIndex dict_len(const DICT& dict)
|
|
{
|
|
if (dict.defined())
|
|
return CFDictionaryGetCount(dict());
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
template <typename ARRAY>
|
|
inline CFTypeRef array_index(const ARRAY& array, const CFIndex idx)
|
|
{
|
|
if (array.defined() && CFArrayGetCount(array()) > idx)
|
|
return CFArrayGetValueAtIndex(array(), idx);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
template <typename DICT, typename KEY>
|
|
inline CFTypeRef dict_index(const DICT& dict, const KEY& key)
|
|
{
|
|
if (dict.defined())
|
|
{
|
|
String keystr = string(key);
|
|
if (keystr.defined())
|
|
return CFDictionaryGetValue(dict(), keystr());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// string methods
|
|
|
|
struct cppstring_error : public std::exception
|
|
{
|
|
virtual const char* what() const throw()
|
|
{
|
|
return "cppstring_error";
|
|
}
|
|
};
|
|
|
|
inline std::string cppstring(CFStringRef str)
|
|
{
|
|
const CFStringEncoding encoding = kCFStringEncodingUTF8;
|
|
if (str)
|
|
{
|
|
const CFIndex len = CFStringGetLength(str);
|
|
if (len > 0)
|
|
{
|
|
const CFIndex maxsize = CFStringGetMaximumSizeForEncoding(len, encoding);
|
|
char *buf = new char[maxsize];
|
|
const Boolean status = CFStringGetCString(str, buf, maxsize, encoding);
|
|
if (status)
|
|
{
|
|
std::string ret(buf);
|
|
delete [] buf;
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
delete [] buf;
|
|
throw cppstring_error();
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
inline std::string cppstring(const String& str)
|
|
{
|
|
return cppstring(str());
|
|
}
|
|
|
|
inline std::string description(CFTypeRef obj)
|
|
{
|
|
if (obj)
|
|
{
|
|
String s(CFCopyDescription(obj));
|
|
return cppstring(s);
|
|
}
|
|
else
|
|
return "UNDEF";
|
|
}
|
|
|
|
// format an array of strings (non-string elements in array are ignored)
|
|
template <typename ARRAY>
|
|
inline std::string array_to_string(const ARRAY& array, const char delim=',')
|
|
{
|
|
std::ostringstream os;
|
|
const CFIndex len = array_len(array);
|
|
if (len)
|
|
{
|
|
bool sep = false;
|
|
for (CFIndex i = 0; i < len; ++i)
|
|
{
|
|
const String v(string_cast(array_index(array, i)));
|
|
if (v.defined())
|
|
{
|
|
if (sep)
|
|
os << delim;
|
|
os << cppstring(v);
|
|
sep = true;
|
|
}
|
|
}
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
inline bool string_equal(const String& s1, const String& s2, const CFStringCompareFlags compareOptions = 0)
|
|
{
|
|
return s1.defined() && s2.defined() && CFStringCompare(s1(), s2(), compareOptions) == kCFCompareEqualTo;
|
|
}
|
|
|
|
// property lists
|
|
inline Data plist(CFTypeRef obj)
|
|
{
|
|
return Data(CFPropertyListCreateData(kCFAllocatorDefault,
|
|
obj,
|
|
kCFPropertyListBinaryFormat_v1_0,
|
|
0,
|
|
nullptr));
|
|
}
|
|
|
|
} // namespace CF
|
|
} // namespace openvpn
|
|
|
|
#endif // OPENVPN_APPLECRYPTO_CF_CF_H
|