mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'
This commit is contained in:
@@ -0,0 +1,459 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user