You've already forked linux-packaging-mono
Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
parent
e49d6f06c0
commit
536cd135cc
@@ -90,7 +90,9 @@ if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${CLR_SANITIZE_LINK_FLAGS} -Wl,--gc-sections")
|
||||
endif ()
|
||||
elseif (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELEASE)
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l AND DEFINED ENV{CROSSCOMPILE})
|
||||
# Use O1 option when the clang version is smaller than 3.9
|
||||
# Otherwise use O3 option in release build
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l AND DEFINED ENV{CROSSCOMPILE} AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9)
|
||||
add_compile_options (-O1)
|
||||
else()
|
||||
add_compile_options (-O3)
|
||||
|
@@ -30,13 +30,14 @@
|
||||
#cmakedefine01 HAVE_PRIVATE_FDS_BITS
|
||||
#cmakedefine01 HAVE_STATFS
|
||||
#cmakedefine01 HAVE_EPOLL
|
||||
#cmakedefine01 HAVE_ACCEPT_4
|
||||
#cmakedefine01 HAVE_ACCEPT4
|
||||
#cmakedefine01 HAVE_KQUEUE
|
||||
#cmakedefine01 HAVE_SENDFILE_4
|
||||
#cmakedefine01 HAVE_SENDFILE_6
|
||||
#cmakedefine01 HAVE_FCOPYFILE
|
||||
#cmakedefine01 HAVE_GETHOSTBYNAME_R
|
||||
#cmakedefine01 HAVE_GETHOSTBYADDR_R
|
||||
#cmakedefine01 HAVE_GETNAMEINFO_SIGNED_FLAGS
|
||||
#cmakedefine01 HAVE_GETPEEREID
|
||||
#cmakedefine01 HAVE_SUPPORT_FOR_DUAL_MODE_IPV4_PACKET_INFO
|
||||
#cmakedefine01 HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
|
||||
@@ -54,6 +55,7 @@
|
||||
#cmakedefine01 HAVE_GETDOMAINNAME_SIZET
|
||||
#cmakedefine01 HAVE_INOTIFY
|
||||
#cmakedefine01 HAVE_CLOCK_MONOTONIC
|
||||
#cmakedefine01 HAVE_CLOCK_REALTIME
|
||||
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
|
||||
#cmakedefine01 HAVE_MACH_TIMEBASE_INFO
|
||||
#cmakedefine01 HAVE_CURLM_ADDED_ALREADY
|
||||
@@ -77,6 +79,7 @@
|
||||
#cmakedefine01 IPV6MR_INTERFACE_UNSIGNED
|
||||
#cmakedefine01 BIND_ADDRLEN_UNSIGNED
|
||||
#cmakedefine01 INOTIFY_RM_WATCH_WD_UNSIGNED
|
||||
#cmakedefine01 HAVE_IN_EXCL_UNLINK
|
||||
|
||||
// Mac OS X has stat64, but it is deprecated since plain stat now
|
||||
// provides the same 64-bit aware struct when targeting OS X > 10.5
|
||||
|
@@ -16,6 +16,28 @@
|
||||
#include <type_traits>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define assert_err(cond, msg, err) do \
|
||||
{ \
|
||||
if(!(cond)) \
|
||||
{ \
|
||||
fprintf(stderr, "%s (%d): error %d: %s. %s (%s failed)\n", __FILE__, __LINE__, err, msg, strerror(err), #cond); \
|
||||
assert(false && "assert_err failed"); \
|
||||
} \
|
||||
} while(0)
|
||||
#define assert_msg(cond, msg, val) do \
|
||||
{ \
|
||||
if(!(cond)) \
|
||||
{ \
|
||||
fprintf(stderr, "%s (%d): error %d: %s (%s failed)\n", __FILE__, __LINE__, val, msg, #cond); \
|
||||
assert(false && "assert_msg failed"); \
|
||||
} \
|
||||
} while(0)
|
||||
#else // DEBUG
|
||||
#define assert_err(cond, msg, err)
|
||||
#define assert_msg(cond, msg, val)
|
||||
#endif // DEBUG
|
||||
|
||||
/**
|
||||
* ResultOf<T> is shorthand for typename std::result_of<T>::type.
|
||||
* Equivalent to C++14 std::result_of_t.
|
||||
|
@@ -18,6 +18,7 @@ set(NATIVE_SOURCES
|
||||
pal_tcpstate.cpp
|
||||
pal_time.cpp
|
||||
pal_uid.cpp
|
||||
pal_datetime.cpp
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
|
@@ -74,7 +74,7 @@ extern "C" void SystemNative_SetKeypadXmit(const char* terminfoString)
|
||||
}
|
||||
|
||||
static bool g_readInProgress = false; // tracks whether a read is currently in progress, such that attributes have been changed
|
||||
static bool g_signalForBreak = true; // tracks whether the terminal should send signals for breaks
|
||||
static bool g_signalForBreak = true; // tracks whether the terminal should send signals for breaks, such that attributes have been changed
|
||||
static bool g_haveInitTermios = false; // whether g_initTermios has been initialized
|
||||
static struct termios g_initTermios = {}; // the initial attributes captured when Console was initialized
|
||||
static struct termios g_preReadTermios = {}; // the original attributes captured before a read; valid if g_readInProgress is true
|
||||
@@ -82,9 +82,18 @@ static struct termios g_currTermios = {}; // the current attributes set durin
|
||||
|
||||
static void UninitializeConsole()
|
||||
{
|
||||
// Put the attributes back to what they were when the console was initially initialized
|
||||
if (g_haveInitTermios)
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &g_initTermios); // ignore any failure
|
||||
// Put the attributes back to what they were when the console was initially initialized.
|
||||
// We only do so, however, if we have explicitly modified the termios; doing so always
|
||||
// can result in problems if the app is in the background, as then attempting to call
|
||||
// tcsetattr on STDIN_FILENO will suspend the app and prevent its shutdown. We also don't
|
||||
// want to, for example, just compare g_currTermios with g_initTermios, as we'd then be
|
||||
// factoring in changes made by other apps or by user code.
|
||||
if (g_haveInitTermios && // we successfully initialized the console
|
||||
(g_readInProgress || !g_signalForBreak)) // we modified attributes
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &g_initTermios);
|
||||
// ignore any failure
|
||||
}
|
||||
}
|
||||
|
||||
static void IncorporateBreak(struct termios *termios, int32_t signalForBreak)
|
||||
@@ -374,7 +383,7 @@ void* SignalHandlerLoop(void* arg)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(signalCode == SIGQUIT || signalCode == SIGINT);
|
||||
assert_msg(signalCode == SIGQUIT || signalCode == SIGINT, "invalid signalCode", static_cast<int>(signalCode));
|
||||
|
||||
// We're now handling SIGQUIT and SIGINT. Invoke the callback, if we have one.
|
||||
CtrlCallback callback = g_ctrlCallback;
|
||||
|
40
external/corefx/src/Native/Unix/System.Native/pal_datetime.cpp
vendored
Normal file
40
external/corefx/src/Native/Unix/System.Native/pal_datetime.cpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#include "pal_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static const int64_t TICKS_PER_SECOND = 10000000; /* 10^7 */
|
||||
#if HAVE_CLOCK_REALTIME
|
||||
static const int64_t NANOSECONDS_PER_TICK = 100;
|
||||
#else
|
||||
static const int64_t TICKS_PER_MICROSECOND = 10; /* 1000 / 100 */
|
||||
#endif
|
||||
|
||||
//
|
||||
// SystemNative_GetSystemTimeAsTicks return the system time as ticks (100 nanoseconds)
|
||||
// since 00:00 01 January 1970 UTC (Unix epoch)
|
||||
//
|
||||
extern "C" int64_t SystemNative_GetSystemTimeAsTicks()
|
||||
{
|
||||
#if HAVE_CLOCK_REALTIME
|
||||
struct timespec time;
|
||||
if (clock_gettime(CLOCK_REALTIME, &time) == 0)
|
||||
{
|
||||
return static_cast<int64_t>(time.tv_sec) * TICKS_PER_SECOND + (time.tv_nsec / NANOSECONDS_PER_TICK);
|
||||
}
|
||||
#else
|
||||
struct timeval time;
|
||||
if (gettimeofday(&time, NULL) == 0)
|
||||
{
|
||||
return static_cast<int64_t>(time.tv_sec) * TICKS_PER_SECOND + (time.tv_usec * TICKS_PER_MICROSECOND);
|
||||
}
|
||||
#endif
|
||||
// in failure we return 00:00 01 January 1970 UTC (Unix epoch)
|
||||
return 0;
|
||||
}
|
@@ -385,7 +385,7 @@ extern "C" int32_t SystemNative_ConvertErrorPalToPlatform(Error error)
|
||||
// note that there is probably a corresponding missing case in the
|
||||
// other direction above, but the compiler can't warn in that case
|
||||
// because the platform values are not part of an enum.
|
||||
assert(false && "Unknown error code");
|
||||
assert_err(false, "Unknown error code", static_cast<int>(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ extern "C" const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffe
|
||||
// The only other valid error codes are 0 for success or EINVAL for
|
||||
// an unknown error, but in the latter case a reasonable string (e.g
|
||||
// "Unknown error: 0x123") is returned.
|
||||
assert(error == 0 || error == EINVAL);
|
||||
assert_err(error == 0 || error == EINVAL, "invalid error", error);
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
|
@@ -45,6 +45,10 @@ extern "C" int32_t SystemNative_EnumerateInterfaceAddresses(IPv4AddressFound onI
|
||||
|
||||
for (ifaddrs* current = headAddr; current != nullptr; current = current->ifa_next)
|
||||
{
|
||||
if (current->ifa_addr == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint32_t interfaceIndex = if_nametoindex(current->ifa_name);
|
||||
// ifa_name may be an aliased interface name.
|
||||
// Use if_indextoname to map back to the true device name.
|
||||
|
@@ -134,12 +134,16 @@ static_assert(PAL_IN_Q_OVERFLOW == IN_Q_OVERFLOW, "");
|
||||
static_assert(PAL_IN_IGNORED == IN_IGNORED, "");
|
||||
static_assert(PAL_IN_ONLYDIR == IN_ONLYDIR, "");
|
||||
static_assert(PAL_IN_DONT_FOLLOW == IN_DONT_FOLLOW, "");
|
||||
#if HAVE_IN_EXCL_UNLINK
|
||||
static_assert(PAL_IN_EXCL_UNLINK == IN_EXCL_UNLINK, "");
|
||||
#endif // HAVE_IN_EXCL_UNLINK
|
||||
static_assert(PAL_IN_ISDIR == IN_ISDIR, "");
|
||||
#endif
|
||||
#endif // HAVE_INOTIFY
|
||||
|
||||
static void ConvertFileStatus(const struct stat_& src, FileStatus* dst)
|
||||
{
|
||||
dst->Dev = static_cast<int64_t>(src.st_dev);
|
||||
dst->Ino = static_cast<int64_t>(src.st_ino);
|
||||
dst->Flags = FILESTATUS_FLAGS_NONE;
|
||||
dst->Mode = static_cast<int32_t>(src.st_mode);
|
||||
dst->Uid = src.st_uid;
|
||||
@@ -213,13 +217,13 @@ static int32_t ConvertOpenFlags(int32_t flags)
|
||||
ret = O_WRONLY;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unknown Open access mode.");
|
||||
assert_msg(false, "Unknown Open access mode", static_cast<int>(flags));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & ~(PAL_O_ACCESS_MODE_MASK | PAL_O_CLOEXEC | PAL_O_CREAT | PAL_O_EXCL | PAL_O_TRUNC | PAL_O_SYNC))
|
||||
{
|
||||
assert(false && "Unknown Open flag.");
|
||||
assert_msg(false, "Unknown Open flag", static_cast<int>(flags));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -260,7 +264,7 @@ extern "C" int32_t SystemNative_Close(intptr_t fd)
|
||||
extern "C" intptr_t SystemNative_Dup(intptr_t oldfd)
|
||||
{
|
||||
int result;
|
||||
while (CheckInterrupted(result = dup(ToFileDescriptor(oldfd))));
|
||||
while (CheckInterrupted(result = fcntl(ToFileDescriptor(oldfd), F_DUPFD_CLOEXEC, 0)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -384,7 +388,7 @@ extern "C" int32_t SystemNative_ReadDirR(DIR* dir, void* buffer, int32_t bufferS
|
||||
// kernel set errno -> failure
|
||||
if (errno != 0)
|
||||
{
|
||||
assert(errno == EBADF); // Invalid directory stream descriptor dir.
|
||||
assert_err(errno == EBADF, "Invalid directory stream descriptor dir", errno);
|
||||
return errno;
|
||||
}
|
||||
return -1;
|
||||
@@ -417,7 +421,7 @@ extern "C" int32_t SystemNative_Pipe(int32_t pipeFds[2], int32_t flags)
|
||||
flags = O_CLOEXEC;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unknown flag.");
|
||||
assert_msg(false, "Unknown pipe flag", static_cast<int>(flags));
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -642,7 +646,7 @@ static int32_t ConvertMMapProtection(int32_t protection)
|
||||
|
||||
if (protection & ~(PAL_PROT_READ | PAL_PROT_WRITE | PAL_PROT_EXEC))
|
||||
{
|
||||
assert(false && "Unknown protection.");
|
||||
assert_msg(false, "Unknown protection", static_cast<int>(protection));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -662,7 +666,7 @@ static int32_t ConvertMMapFlags(int32_t flags)
|
||||
{
|
||||
if (flags & ~(PAL_MAP_SHARED | PAL_MAP_PRIVATE | PAL_MAP_ANONYMOUS))
|
||||
{
|
||||
assert(false && "Unknown MMap flag.");
|
||||
assert_msg(false, "Unknown MMap flag", static_cast<int>(flags));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -682,7 +686,7 @@ static int32_t ConvertMSyncFlags(int32_t flags)
|
||||
{
|
||||
if (flags & ~(PAL_MS_SYNC | PAL_MS_ASYNC | PAL_MS_INVALIDATE))
|
||||
{
|
||||
assert(false && "Unknown MSync flag.");
|
||||
assert_msg(false, "Unknown MSync flag", static_cast<int>(flags));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -774,7 +778,7 @@ extern "C" int32_t SystemNative_MAdvise(void* address, uint64_t length, MemoryAd
|
||||
#endif
|
||||
}
|
||||
|
||||
assert(false && "Unknown MemoryAdvice");
|
||||
assert_msg(false, "Unknown MemoryAdvice", static_cast<int>(advice));
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -849,7 +853,7 @@ extern "C" int64_t SystemNative_SysConf(SysConfName name)
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
assert(false && "Unknown SysConfName");
|
||||
assert_msg(false, "Unknown SysConf name", static_cast<int>(name));
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -1218,6 +1222,9 @@ extern "C" int32_t SystemNative_INotifyAddWatch(intptr_t fd, const char* pathNam
|
||||
assert(pathName != nullptr);
|
||||
|
||||
#if HAVE_INOTIFY
|
||||
#if !HAVE_IN_EXCL_UNLINK
|
||||
mask &= ~static_cast<uint32_t>(PAL_IN_EXCL_UNLINK);
|
||||
#endif
|
||||
return inotify_add_watch(ToFileDescriptor(fd), pathName, mask);
|
||||
#else
|
||||
(void)fd, (void)pathName, (void)mask;
|
||||
|
@@ -24,6 +24,8 @@ struct FileStatus
|
||||
int64_t MTime; // time of last modification
|
||||
int64_t CTime; // time of last status change
|
||||
int64_t BirthTime; // time the file was created
|
||||
int64_t Dev; // ID of the device containing the file
|
||||
int64_t Ino; // inode number of the file
|
||||
};
|
||||
|
||||
/************
|
||||
|
@@ -231,125 +231,10 @@ static int32_t ConvertGetAddrInfoAndGetNameInfoErrorsToPal(int32_t error)
|
||||
return PAL_EAI_NONAME;
|
||||
}
|
||||
|
||||
assert(false && "Unknown AddrInfo error flag");
|
||||
assert_err(false, "Unknown AddrInfo error flag", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int32_t
|
||||
SystemNative_IPv6StringToAddress(const uint8_t* address, const uint8_t* port, uint8_t* buffer, int32_t bufferLength, uint32_t* scope)
|
||||
{
|
||||
assert(buffer != nullptr);
|
||||
assert(bufferLength == NUM_BYTES_IN_IPV6_ADDRESS);
|
||||
assert(scope != nullptr);
|
||||
assert(address != nullptr);
|
||||
|
||||
addrinfo hint;
|
||||
memset(&hint, 0, sizeof(addrinfo));
|
||||
hint.ai_family = AF_INET6;
|
||||
hint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
|
||||
|
||||
addrinfo* info = nullptr;
|
||||
int32_t result = getaddrinfo(reinterpret_cast<const char*>(address), reinterpret_cast<const char*>(port), &hint, &info);
|
||||
if (result == 0)
|
||||
{
|
||||
sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
|
||||
ConvertIn6AddrToByteArray(buffer, bufferLength, addr->sin6_addr);
|
||||
*scope = addr->sin6_scope_id;
|
||||
|
||||
freeaddrinfo(info);
|
||||
}
|
||||
|
||||
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
|
||||
}
|
||||
|
||||
extern "C" int32_t SystemNative_IPv4StringToAddress(const uint8_t* address, uint8_t* buffer, int32_t bufferLength, uint16_t* port)
|
||||
{
|
||||
assert(buffer != nullptr);
|
||||
assert(bufferLength == NUM_BYTES_IN_IPV4_ADDRESS);
|
||||
assert(port != nullptr);
|
||||
assert(address != nullptr);
|
||||
|
||||
in_addr inaddr;
|
||||
int32_t result = inet_aton(reinterpret_cast<const char*>(address), &inaddr);
|
||||
if (result == 0)
|
||||
{
|
||||
return PAL_EAI_NONAME;
|
||||
}
|
||||
|
||||
ConvertInAddrToByteArray(buffer, bufferLength, inaddr);
|
||||
*port = 0; // callers expect this to always be zero
|
||||
|
||||
return PAL_EAI_SUCCESS;
|
||||
}
|
||||
|
||||
static void AppendScopeIfNecessary(uint8_t* string, int32_t stringLength, uint32_t scope)
|
||||
{
|
||||
assert(scope != 0);
|
||||
|
||||
// Find the scope ID, if it exists
|
||||
int i;
|
||||
for (i = 0; i < stringLength && string[i] != '\0'; i++)
|
||||
{
|
||||
if (string[i] == '%')
|
||||
{
|
||||
// Found a scope ID. Assume it's correct and return.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto capacity = static_cast<size_t>(stringLength - i);
|
||||
int n = snprintf(reinterpret_cast<char*>(&string[i]), capacity, "%%%d", scope);
|
||||
assert(static_cast<size_t>(n) < capacity);
|
||||
(void)n; // Silence an unused variable warning in release mode
|
||||
}
|
||||
|
||||
extern "C" int32_t SystemNative_IPAddressToString(
|
||||
const uint8_t* address, int32_t addressLength, bool isIPv6, uint8_t* string, int32_t stringLength, uint32_t scope)
|
||||
{
|
||||
assert(address != nullptr);
|
||||
assert((addressLength == NUM_BYTES_IN_IPV6_ADDRESS) || (addressLength == NUM_BYTES_IN_IPV4_ADDRESS));
|
||||
assert(string != nullptr);
|
||||
|
||||
// These constants differ per platform so the managed side uses the bigger value; therefore, check that
|
||||
// the length is between the two lengths
|
||||
assert((stringLength >= INET_ADDRSTRLEN) && (stringLength <= INET6_ADDRSTRLEN_MANAGED));
|
||||
|
||||
socklen_t len = UnsignedCast(stringLength);
|
||||
|
||||
sockaddr_in inAddr;
|
||||
sockaddr_in6 in6Addr;
|
||||
const sockaddr* addr;
|
||||
socklen_t addrLen;
|
||||
|
||||
if (!isIPv6)
|
||||
{
|
||||
ConvertByteArrayToSockAddrIn(inAddr, address, addressLength);
|
||||
addr = reinterpret_cast<const sockaddr*>(&inAddr);
|
||||
addrLen = sizeof(inAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
in6Addr.sin6_scope_id = scope;
|
||||
ConvertByteArrayToSockAddrIn6(in6Addr, address, addressLength);
|
||||
addr = reinterpret_cast<const sockaddr*>(&in6Addr);
|
||||
addrLen = sizeof(in6Addr);
|
||||
}
|
||||
|
||||
int result = getnameinfo(addr, addrLen, reinterpret_cast<char*>(string), len, nullptr, 0, NI_NUMERICHOST);
|
||||
if (result != 0)
|
||||
{
|
||||
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
|
||||
}
|
||||
|
||||
// Some platforms do not append unknown scope IDs, but the managed code wants this behavior.
|
||||
if (isIPv6 && scope != 0)
|
||||
{
|
||||
AppendScopeIfNecessary(string, stringLength, scope);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int32_t SystemNative_GetHostEntryForName(const uint8_t* address, HostEntry* entry)
|
||||
{
|
||||
if (address == nullptr || entry == nullptr)
|
||||
@@ -411,7 +296,7 @@ static int ConvertGetHostErrorPlatformToPal(int error)
|
||||
return PAL_NO_DATA;
|
||||
|
||||
default:
|
||||
assert(false && "Unknown gethostbyname/gethostbyaddr error code");
|
||||
assert_err(false, "Unknown gethostbyname/gethostbyaddr error code", error);
|
||||
return PAL_HOST_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
@@ -554,29 +439,29 @@ static int GetHostByNameHelper(const uint8_t* hostname, hostent** entry)
|
||||
hostent* result = reinterpret_cast<hostent*>(buffer);
|
||||
char* scratch = reinterpret_cast<char*>(&buffer[sizeof(hostent)]);
|
||||
|
||||
int getHostErrno;
|
||||
int getHostErrno = 0;
|
||||
int err = gethostbyname_r(reinterpret_cast<const char*>(hostname), result, scratch, scratchLen, entry, &getHostErrno);
|
||||
switch (err)
|
||||
if (!err && *entry != nullptr)
|
||||
{
|
||||
case 0:
|
||||
*entry = result;
|
||||
return 0;
|
||||
|
||||
case ERANGE:
|
||||
free(buffer);
|
||||
size_t tmpScratchLen;
|
||||
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
|
||||
{
|
||||
*entry = nullptr;
|
||||
return PAL_NO_MEM;
|
||||
}
|
||||
scratchLen = tmpScratchLen;
|
||||
break;
|
||||
|
||||
default:
|
||||
free(buffer);
|
||||
assert(*entry == result);
|
||||
return 0;
|
||||
}
|
||||
else if (err == ERANGE)
|
||||
{
|
||||
free(buffer);
|
||||
size_t tmpScratchLen;
|
||||
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
|
||||
{
|
||||
*entry = nullptr;
|
||||
return getHostErrno;
|
||||
return PAL_NO_MEM;
|
||||
}
|
||||
scratchLen = tmpScratchLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buffer);
|
||||
*entry = nullptr;
|
||||
return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,29 +518,29 @@ static int GetHostByAddrHelper(const uint8_t* addr, const socklen_t addrLen, int
|
||||
hostent* result = reinterpret_cast<hostent*>(buffer);
|
||||
char* scratch = reinterpret_cast<char*>(&buffer[sizeof(hostent)]);
|
||||
|
||||
int getHostErrno;
|
||||
int getHostErrno = 0;
|
||||
int err = gethostbyaddr_r(addr, addrLen, type, result, scratch, scratchLen, entry, &getHostErrno);
|
||||
switch (err)
|
||||
if (!err && *entry != nullptr)
|
||||
{
|
||||
case 0:
|
||||
*entry = result;
|
||||
return 0;
|
||||
|
||||
case ERANGE:
|
||||
free(buffer);
|
||||
size_t tmpScratchLen;
|
||||
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
|
||||
{
|
||||
*entry = nullptr;
|
||||
return PAL_NO_MEM;
|
||||
}
|
||||
scratchLen = tmpScratchLen;
|
||||
break;
|
||||
|
||||
default:
|
||||
free(buffer);
|
||||
assert(*entry == result);
|
||||
return 0;
|
||||
}
|
||||
else if (err == ERANGE)
|
||||
{
|
||||
free(buffer);
|
||||
size_t tmpScratchLen;
|
||||
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
|
||||
{
|
||||
*entry = nullptr;
|
||||
return getHostErrno;
|
||||
return PAL_NO_MEM;
|
||||
}
|
||||
scratchLen = tmpScratchLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buffer);
|
||||
*entry = nullptr;
|
||||
return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -838,9 +723,16 @@ extern "C" void SystemNative_FreeHostEntry(HostEntry* entry)
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t ConvertGetNameInfoFlagsToNative(int32_t flags)
|
||||
// There were several versions of glibc that had the flags parameter of getnameinfo unsigned
|
||||
#if HAVE_GETNAMEINFO_SIGNED_FLAGS
|
||||
typedef int32_t NativeFlagsType;
|
||||
#else
|
||||
typedef uint32_t NativeFlagsType;
|
||||
#endif
|
||||
|
||||
inline NativeFlagsType ConvertGetNameInfoFlagsToNative(int32_t flags)
|
||||
{
|
||||
int32_t outFlags = 0;
|
||||
NativeFlagsType outFlags = 0;
|
||||
if ((flags & PAL_NI_NAMEREQD) == PAL_NI_NAMEREQD)
|
||||
{
|
||||
outFlags |= NI_NAMEREQD;
|
||||
@@ -867,7 +759,7 @@ extern "C" int32_t SystemNative_GetNameInfo(const uint8_t* address,
|
||||
assert((host != nullptr) || (service != nullptr));
|
||||
assert((hostLength > 0) || (serviceLength > 0));
|
||||
|
||||
int32_t nativeFlags = ConvertGetNameInfoFlagsToNative(flags);
|
||||
NativeFlagsType nativeFlags = ConvertGetNameInfoFlagsToNative(flags);
|
||||
int32_t result;
|
||||
|
||||
if (isIPv6)
|
||||
@@ -1474,7 +1366,7 @@ extern "C" Error SystemNative_GetIPv6MulticastOption(intptr_t socket, int32_t mu
|
||||
int fd = ToFileDescriptor(socket);
|
||||
|
||||
int optionName;
|
||||
if (!GetMulticastOptionName(multicastOption, false, optionName))
|
||||
if (!GetMulticastOptionName(multicastOption, true, optionName))
|
||||
{
|
||||
return PAL_EINVAL;
|
||||
}
|
||||
@@ -1502,7 +1394,7 @@ extern "C" Error SystemNative_SetIPv6MulticastOption(intptr_t socket, int32_t mu
|
||||
int fd = ToFileDescriptor(socket);
|
||||
|
||||
int optionName;
|
||||
if (!GetMulticastOptionName(multicastOption, false, optionName))
|
||||
if (!GetMulticastOptionName(multicastOption, true, optionName))
|
||||
{
|
||||
return PAL_EINVAL;
|
||||
}
|
||||
@@ -1752,7 +1644,7 @@ extern "C" Error SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, in
|
||||
|
||||
socklen_t addrLen = static_cast<socklen_t>(*socketAddressLen);
|
||||
int accepted;
|
||||
#if defined(HAVE_ACCEPT_4) && defined(SOCK_CLOEXEC)
|
||||
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
|
||||
while (CheckInterrupted(accepted = accept4(fd, reinterpret_cast<sockaddr*>(socketAddress), &addrLen, SOCK_CLOEXEC)));
|
||||
#else
|
||||
while (CheckInterrupted(accepted = accept(fd, reinterpret_cast<sockaddr*>(socketAddress), &addrLen)));
|
||||
@@ -2456,7 +2348,8 @@ static Error TryChangeSocketEventRegistrationInner(
|
||||
op = EPOLL_CTL_DEL;
|
||||
}
|
||||
|
||||
epoll_event evt = {.events = GetEPollEvents(newEvents) | EPOLLET, .data = {.ptr = reinterpret_cast<void*>(data)}};
|
||||
epoll_event evt = {.events = GetEPollEvents(newEvents) | static_cast<unsigned int>(EPOLLET),
|
||||
.data = {.ptr = reinterpret_cast<void*>(data)}};
|
||||
int err = epoll_ctl(port, op, socket, &evt);
|
||||
return err == 0 ? PAL_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno);
|
||||
}
|
||||
@@ -2558,7 +2451,7 @@ static SocketEvents GetSocketEvents(int16_t filter, uint16_t flags)
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false && "unexpected kqueue filter type");
|
||||
assert_msg(false, "unexpected kqueue filter type", static_cast<int>(filter));
|
||||
return PAL_SA_NONE;
|
||||
}
|
||||
|
||||
@@ -2840,27 +2733,48 @@ extern "C" Error SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t
|
||||
|
||||
*sent = 0;
|
||||
return SystemNative_ConvertErrorPlatformToPal(errno);
|
||||
|
||||
#elif HAVE_SENDFILE_6
|
||||
off_t len = count;
|
||||
ssize_t res;
|
||||
while (CheckInterrupted(res = sendfile(infd, outfd, static_cast<off_t>(offset), &len, nullptr, 0)));
|
||||
if (res != -1)
|
||||
*sent = 0;
|
||||
while (true) // in case we need to retry for an EINTR
|
||||
{
|
||||
if (len == 0)
|
||||
off_t len = count;
|
||||
ssize_t res = sendfile(infd, outfd, static_cast<off_t>(offset), &len, nullptr, 0);
|
||||
assert(len >= 0);
|
||||
|
||||
// If the call succeeded, store the number of bytes sent, and return. We add
|
||||
// rather than copy len because a previous call to sendfile could have sent bytes
|
||||
// but been interrupted by EINTR, in which case we need to add to that.
|
||||
if (res != -1)
|
||||
{
|
||||
// This indicates EOF
|
||||
*sent = count;
|
||||
*sent += len;
|
||||
return PAL_SUCCESS;
|
||||
}
|
||||
else
|
||||
|
||||
// We got an error. If sendfile "fails" with EINTR or EAGAIN, it may have sent
|
||||
// some data that needs to be counted.
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
{
|
||||
*sent = len;
|
||||
*sent += len;
|
||||
offset += len;
|
||||
count -= len;
|
||||
|
||||
// If we actually transferred everything in spite of the error, return success.
|
||||
assert(count >= 0);
|
||||
if (count == 0) return PAL_SUCCESS;
|
||||
|
||||
// For EINTR, loop around and go again.
|
||||
if (errno == EINTR) continue;
|
||||
}
|
||||
return PAL_SUCCESS;
|
||||
|
||||
// For everything other than EINTR, bail.
|
||||
return SystemNative_ConvertErrorPlatformToPal(errno);
|
||||
}
|
||||
|
||||
*sent = 0;
|
||||
return SystemNative_ConvertErrorPlatformToPal(errno);
|
||||
#else
|
||||
#else
|
||||
// If we ever need to run on a platform that doesn't have sendfile,
|
||||
// we can implement this with a simple read/send loop. For now,
|
||||
// we just mark it as not supported.
|
||||
(void)outfd;
|
||||
(void)infd;
|
||||
(void)offset;
|
||||
|
@@ -293,21 +293,6 @@ struct SocketEvent
|
||||
uint32_t Padding; // Pad out to 8-byte alignment
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts string-representations of IP Addresses to
|
||||
*/
|
||||
extern "C" int32_t SystemNative_IPv6StringToAddress(
|
||||
const uint8_t* address, const uint8_t* port, uint8_t* buffer, int32_t bufferLength, uint32_t* scope);
|
||||
|
||||
extern "C" int32_t SystemNative_IPv4StringToAddress(const uint8_t* address, uint8_t* buffer, int32_t bufferLength, uint16_t* port);
|
||||
|
||||
extern "C" int32_t SystemNative_IPAddressToString(const uint8_t* address,
|
||||
int32_t addressLength,
|
||||
bool isIPv6,
|
||||
uint8_t* string,
|
||||
int32_t stringLength,
|
||||
uint32_t scope = 0);
|
||||
|
||||
extern "C" int32_t SystemNative_GetHostEntryForName(const uint8_t* address, HostEntry* entry);
|
||||
|
||||
extern "C" int32_t SystemNative_GetHostByName(const uint8_t* hostname, HostEntry* entry);
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "pal_config.h"
|
||||
#include "pal_process.h"
|
||||
#include "pal_io.h"
|
||||
#include "pal_utilities.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -136,9 +137,11 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Open pipes for any requests to redirect stdin/stdout/stderr
|
||||
if ((redirectStdin && pipe(stdinFds) != 0) || (redirectStdout && pipe(stdoutFds) != 0) ||
|
||||
(redirectStderr && pipe(stderrFds) != 0))
|
||||
// Open pipes for any requests to redirect stdin/stdout/stderr and set the
|
||||
// close-on-exec flag to the pipe file descriptors.
|
||||
if ((redirectStdin && SystemNative_Pipe(stdinFds, PAL_O_CLOEXEC) != 0) ||
|
||||
(redirectStdout && SystemNative_Pipe(stdoutFds, PAL_O_CLOEXEC) != 0) ||
|
||||
(redirectStderr && SystemNative_Pipe(stderrFds, PAL_O_CLOEXEC) != 0))
|
||||
{
|
||||
success = false;
|
||||
goto done;
|
||||
@@ -163,22 +166,14 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
|
||||
|
||||
if (processId == 0) // processId == 0 if this is child process
|
||||
{
|
||||
// Close the child's copy of the parent end of any open pipes
|
||||
CloseIfOpen(stdinFds[WRITE_END_OF_PIPE]);
|
||||
CloseIfOpen(stdoutFds[READ_END_OF_PIPE]);
|
||||
CloseIfOpen(stderrFds[READ_END_OF_PIPE]);
|
||||
|
||||
// For any redirections that should happen, dup the pipe descriptors onto stdin/out/err.
|
||||
// Then close out the old pipe descriptrs, which we no longer need.
|
||||
// We don't need to explicitly close out the old pipe descriptors as they will be closed on the 'execve' call.
|
||||
if ((redirectStdin && Dup2WithInterruptedRetry(stdinFds[READ_END_OF_PIPE], STDIN_FILENO) == -1) ||
|
||||
(redirectStdout && Dup2WithInterruptedRetry(stdoutFds[WRITE_END_OF_PIPE], STDOUT_FILENO) == -1) ||
|
||||
(redirectStderr && Dup2WithInterruptedRetry(stderrFds[WRITE_END_OF_PIPE], STDERR_FILENO) == -1))
|
||||
{
|
||||
_exit(errno != 0 ? errno : EXIT_FAILURE);
|
||||
}
|
||||
CloseIfOpen(stdinFds[READ_END_OF_PIPE]);
|
||||
CloseIfOpen(stdoutFds[WRITE_END_OF_PIPE]);
|
||||
CloseIfOpen(stderrFds[WRITE_END_OF_PIPE]);
|
||||
|
||||
// Change to the designated working directory, if one was specified
|
||||
if (nullptr != cwd)
|
||||
@@ -285,7 +280,7 @@ static int32_t ConvertRLimitResourcesPalToPlatform(RLimitResources value)
|
||||
return RLIMIT_NOFILE;
|
||||
}
|
||||
|
||||
assert(false && "Unknown RLIMIT value");
|
||||
assert_msg(false, "Unknown RLIMIT value", static_cast<int>(value));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -438,7 +433,7 @@ extern "C" int64_t SystemNative_PathConf(const char* path, PathConfName name)
|
||||
|
||||
if (confValue == -1)
|
||||
{
|
||||
assert(false && "Unknown PathConfName");
|
||||
assert_msg(false, "Unknown PathConfName", static_cast<int>(name));
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
@@ -40,6 +40,11 @@ static_assert(PAL_CURL_VERSION_UNIX_SOCKETS == CURL_VERSION_UNIX_SOCKETS, "");
|
||||
static_assert(PAL_CURL_VERSION_PSL == CURL_VERSION_PSL, "");
|
||||
#endif
|
||||
|
||||
// Based on docs/libcurl/symbols-in-versions in libcurl source tree,
|
||||
// the CURL_VERSION_HTTP2 was introduced in libcurl 7.33.0 and
|
||||
// the CURLPIPE_MULTIPLEX was introduced in libcurl 7.43.0.
|
||||
#define MIN_VERSION_WITH_CURLPIPE_MULTIPLEX 0x074300
|
||||
|
||||
extern "C" int32_t HttpNative_GetSupportedFeatures()
|
||||
{
|
||||
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
|
||||
@@ -48,12 +53,10 @@ extern "C" int32_t HttpNative_GetSupportedFeatures()
|
||||
|
||||
extern "C" int32_t HttpNative_GetSupportsHttp2Multiplexing()
|
||||
{
|
||||
#if HAVE_CURLPIPE_MULTIPLEX
|
||||
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
|
||||
return info != nullptr && (info->features & CURL_VERSION_HTTP2) == CURL_VERSION_HTTP2 ? 1 : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
return info != nullptr &&
|
||||
(info->version_num >= MIN_VERSION_WITH_CURLPIPE_MULTIPLEX) &&
|
||||
((info->features & PAL_CURL_VERSION_HTTP2) == PAL_CURL_VERSION_HTTP2) ? 1 : 0;
|
||||
}
|
||||
|
||||
extern "C" char* HttpNative_GetVersionDescription()
|
||||
@@ -67,39 +70,3 @@ extern "C" char* HttpNative_GetSslVersionDescription()
|
||||
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
|
||||
return info != nullptr && info->ssl_version != nullptr ? strdup(info->ssl_version) : nullptr;
|
||||
}
|
||||
|
||||
// TODO: Remove HttpNative_GetCurlVersionInfo once the build containing the above functions
|
||||
// is available as part of a package.
|
||||
extern "C" int32_t HttpNative_GetCurlVersionInfo(int32_t* age,
|
||||
int32_t* supportsSsl,
|
||||
int32_t* supportsAutoDecompression,
|
||||
int32_t* supportsHttp2Multiplexing)
|
||||
{
|
||||
curl_version_info_data* versionInfo = curl_version_info(CURLVERSION_NOW);
|
||||
|
||||
if (!versionInfo || !age || !supportsSsl || !supportsAutoDecompression || !supportsHttp2Multiplexing)
|
||||
{
|
||||
if (age)
|
||||
*age = 0;
|
||||
if (supportsSsl)
|
||||
*supportsSsl = 0;
|
||||
if (supportsAutoDecompression)
|
||||
*supportsAutoDecompression = 0;
|
||||
if (supportsHttp2Multiplexing)
|
||||
*supportsHttp2Multiplexing = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*age = versionInfo->age;
|
||||
*supportsSsl = (versionInfo->features & CURL_VERSION_SSL) == CURL_VERSION_SSL;
|
||||
*supportsAutoDecompression = (versionInfo->features & CURL_VERSION_LIBZ) == CURL_VERSION_LIBZ;
|
||||
*supportsHttp2Multiplexing =
|
||||
#if HAVE_CURLPIPE_MULTIPLEX
|
||||
(versionInfo->features & CURL_VERSION_HTTP2) == CURL_VERSION_HTTP2;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -67,6 +67,15 @@ extern "C" int32_t AppleCryptoNative_SecKeychainOpen(const char* pszKeychainPath
|
||||
return SecKeychainOpen(pszKeychainPath, pKeychainOut);
|
||||
}
|
||||
|
||||
extern "C" int32_t AppleCryptoNative_SetKeychainNeverLock(SecKeychainRef keychain)
|
||||
{
|
||||
SecKeychainSettings settings = {
|
||||
.version = SEC_KEYCHAIN_SETTINGS_VERS1, .useLockInterval = 0, .lockOnSleep = 0, .lockInterval = INT_MAX,
|
||||
};
|
||||
|
||||
return SecKeychainSetSettings(keychain, &settings);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
EnumerateKeychain(SecKeychainRef keychain, CFStringRef matchType, CFArrayRef* pCertsOut, int32_t* pOSStatus)
|
||||
{
|
||||
|
@@ -60,6 +60,13 @@ pKeychainOut: Receives the SecKeychainRef for the named keychain.
|
||||
*/
|
||||
extern "C" int32_t AppleCryptoNative_SecKeychainOpen(const char* pszKeychainPath, SecKeychainRef* pKeychainOut);
|
||||
|
||||
/*
|
||||
Set a keychain to never (automatically) lock.
|
||||
|
||||
Returns the result of SecKeychainSetSettings to a never-auto-lock policy.
|
||||
*/
|
||||
extern "C" int32_t AppleCryptoNative_SetKeychainNeverLock(SecKeychainRef keychain);
|
||||
|
||||
/*
|
||||
Enumerate the certificate objects within the given keychain.
|
||||
|
||||
|
@@ -488,3 +488,191 @@ extern "C" int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDa
|
||||
*pOSStatus = SecItemExport(cert, dataFormat, 0, &keyParams, ppDataOut);
|
||||
return (*pOSStatus == noErr);
|
||||
}
|
||||
|
||||
static OSStatus AddKeyToKeychain(SecKeyRef privateKey, SecKeychainRef targetKeychain)
|
||||
{
|
||||
// This is quite similar to pal_seckey's ExportImportKey, but
|
||||
// a) is used to put something INTO a keychain, instead of to take it out.
|
||||
// b) Doesn't assume that the input should be CFRelease()d and overwritten.
|
||||
// c) Doesn't return/emit the imported key reference.
|
||||
// d) Works on private keys.
|
||||
SecExternalFormat dataFormat = kSecFormatWrappedPKCS8;
|
||||
CFDataRef exportData = nullptr;
|
||||
|
||||
SecItemImportExportKeyParameters keyParams = {};
|
||||
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
keyParams.passphrase = CFSTR("ExportImportPassphrase");
|
||||
|
||||
OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &exportData);
|
||||
|
||||
SecExternalFormat actualFormat = dataFormat;
|
||||
SecExternalItemType actualType = kSecItemTypePrivateKey;
|
||||
CFArrayRef outItems = nullptr;
|
||||
|
||||
if (status == noErr)
|
||||
{
|
||||
status =
|
||||
SecItemImport(exportData, nullptr, &actualFormat, &actualType, 0, &keyParams, targetKeychain, &outItems);
|
||||
}
|
||||
|
||||
if (exportData != nullptr)
|
||||
CFRelease(exportData);
|
||||
|
||||
CFRelease(keyParams.passphrase);
|
||||
keyParams.passphrase = nullptr;
|
||||
|
||||
if (outItems != nullptr)
|
||||
CFRelease(outItems);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
|
||||
SecKeyRef privateKey,
|
||||
SecKeychainRef targetKeychain,
|
||||
SecIdentityRef* pIdentityOut,
|
||||
int32_t* pOSStatus)
|
||||
{
|
||||
if (pIdentityOut != nullptr)
|
||||
*pIdentityOut = nullptr;
|
||||
if (pOSStatus != nullptr)
|
||||
*pOSStatus = noErr;
|
||||
|
||||
if (cert == nullptr || privateKey == nullptr || targetKeychain == nullptr || pIdentityOut == nullptr ||
|
||||
pOSStatus == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
SecKeychainRef keyKeychain = nullptr;
|
||||
|
||||
OSStatus status = SecKeychainItemCopyKeychain(reinterpret_cast<SecKeychainItemRef>(privateKey), &keyKeychain);
|
||||
SecKeychainItemRef itemCopy = nullptr;
|
||||
|
||||
// This only happens with an ephemeral key, so the keychain we're adding it to is temporary.
|
||||
if (status == errSecNoSuchKeychain)
|
||||
{
|
||||
status = AddKeyToKeychain(privateKey, targetKeychain);
|
||||
}
|
||||
|
||||
if (itemCopy != nullptr)
|
||||
{
|
||||
CFRelease(itemCopy);
|
||||
}
|
||||
|
||||
CFMutableDictionaryRef query = nullptr;
|
||||
|
||||
if (status == noErr)
|
||||
{
|
||||
query = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (query == nullptr)
|
||||
{
|
||||
status = errSecAllocate;
|
||||
}
|
||||
}
|
||||
|
||||
CFArrayRef searchList = nullptr;
|
||||
|
||||
if (status == noErr)
|
||||
{
|
||||
searchList = CFArrayCreate(
|
||||
nullptr, const_cast<const void**>(reinterpret_cast<void**>(&targetKeychain)), 1, &kCFTypeArrayCallBacks);
|
||||
|
||||
if (searchList == nullptr)
|
||||
{
|
||||
status = errSecAllocate;
|
||||
}
|
||||
}
|
||||
|
||||
CFArrayRef itemMatch = nullptr;
|
||||
|
||||
if (status == noErr)
|
||||
{
|
||||
itemMatch = CFArrayCreate(
|
||||
nullptr, const_cast<const void**>(reinterpret_cast<void**>(&cert)), 1, &kCFTypeArrayCallBacks);
|
||||
|
||||
if (itemMatch == nullptr)
|
||||
{
|
||||
status = errSecAllocate;
|
||||
}
|
||||
}
|
||||
|
||||
CFTypeRef result = nullptr;
|
||||
|
||||
if (status == noErr)
|
||||
{
|
||||
CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
|
||||
CFDictionarySetValue(query, kSecMatchSearchList, searchList);
|
||||
CFDictionarySetValue(query, kSecMatchItemList, itemMatch);
|
||||
CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
|
||||
|
||||
status = SecItemCopyMatching(query, &result);
|
||||
|
||||
if (status != noErr && result != nullptr)
|
||||
{
|
||||
CFRelease(result);
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
bool added = false;
|
||||
|
||||
if (status == errSecItemNotFound)
|
||||
{
|
||||
status = SecCertificateAddToKeychain(cert, targetKeychain);
|
||||
|
||||
added = (status == noErr);
|
||||
}
|
||||
|
||||
if (result == nullptr && status == noErr)
|
||||
{
|
||||
status = SecItemCopyMatching(query, &result);
|
||||
}
|
||||
|
||||
if (result != nullptr && status == noErr)
|
||||
{
|
||||
|
||||
if (CFGetTypeID(result) != SecIdentityGetTypeID())
|
||||
{
|
||||
status = errSecItemNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
SecIdentityRef identity = reinterpret_cast<SecIdentityRef>(const_cast<void*>(result));
|
||||
CFRetain(identity);
|
||||
*pIdentityOut = identity;
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
{
|
||||
// The same query that was used to find the identity can be used
|
||||
// to find/delete the certificate, as long as we fix the class to just the cert.
|
||||
CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
|
||||
|
||||
// Ignore the output status, there's no point in telling the user
|
||||
// that the cleanup failed, since that just makes them have a dirty keychain
|
||||
// AND their program didn't work.
|
||||
SecItemDelete(query);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != nullptr)
|
||||
CFRelease(result);
|
||||
|
||||
if (itemMatch != nullptr)
|
||||
CFRelease(itemMatch);
|
||||
|
||||
if (searchList != nullptr)
|
||||
CFRelease(searchList);
|
||||
|
||||
if (query != nullptr)
|
||||
CFRelease(query);
|
||||
|
||||
if (keyKeychain != nullptr)
|
||||
CFRelease(keyKeychain);
|
||||
|
||||
*pOSStatus = status;
|
||||
return status == noErr;
|
||||
}
|
||||
|
@@ -156,3 +156,20 @@ ppDataOut: Receives a CFDataRef with the exported blob
|
||||
pOSStatus: Receives the result of SecItemExport
|
||||
*/
|
||||
extern "C" int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDataOut, int32_t* pOSStatus);
|
||||
|
||||
/*
|
||||
Find a SecIdentityRef for the given cert and private key in the target keychain.
|
||||
If the key does not belong to any keychain it is added to the target keychain and left there.
|
||||
If the certificate does not belong to the target keychain it is added and removed.
|
||||
|
||||
Returns 1 on success, 0 on failure, any other value indicates invalid state.
|
||||
|
||||
Output:
|
||||
pIdentityOut: Receives the SecIdentityRef of the mated cert/key pair.
|
||||
pOSStatus: Receives the result of the last executed system call.
|
||||
*/
|
||||
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
|
||||
SecKeyRef privateKey,
|
||||
SecKeychainRef targetKeychain,
|
||||
SecIdentityRef* pIdentityOut,
|
||||
int32_t* pOSStatus);
|
||||
|
@@ -19,7 +19,7 @@ extern "C" SecPolicyRef AppleCryptoNative_X509ChainCreateDefaultPolicy()
|
||||
|
||||
extern "C" SecPolicyRef AppleCryptoNative_X509ChainCreateRevocationPolicy()
|
||||
{
|
||||
return SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
|
||||
return SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod | kSecRevocationRequirePositiveResponse);
|
||||
}
|
||||
|
||||
extern "C" int32_t
|
||||
@@ -163,6 +163,8 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
|
||||
*pStatus |= PAL_X509ChainInvalidBasicConstraints;
|
||||
else if (CFEqual(keyString, CFSTR("UsageConstraints")))
|
||||
*pStatus |= PAL_X509ChainExplicitDistrust;
|
||||
else if (CFEqual(keyString, CFSTR("RevocationResponseRequired")))
|
||||
*pStatus |= PAL_X509ChainRevocationStatusUnknown;
|
||||
else if (CFEqual(keyString, CFSTR("WeakLeaf")) || CFEqual(keyString, CFSTR("WeakIntermediates")) ||
|
||||
CFEqual(keyString, CFSTR("WeakRoot")))
|
||||
{
|
||||
@@ -175,6 +177,9 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
|
||||
|
||||
else
|
||||
{
|
||||
#ifdef DEBUGGING_UNKNOWN_VALUE
|
||||
printf("%s\n", CFStringGetCStringPtr(keyString, CFStringGetSystemEncoding()));
|
||||
#endif
|
||||
*pStatus |= PAL_X509ChainErrorUnknownValue;
|
||||
}
|
||||
}
|
||||
@@ -233,6 +238,8 @@ extern "C" int32_t AppleCryptoNative_GetOSStatusForChainStatus(PAL_X509ChainStat
|
||||
return errSecCreateChainFailed;
|
||||
case PAL_X509ChainExplicitDistrust:
|
||||
return errSecTrustSettingDeny;
|
||||
case PAL_X509ChainRevocationStatusUnknown:
|
||||
return errSecIncompleteCertRevocationCheck;
|
||||
default:
|
||||
return errSecCoreFoundationUnknown;
|
||||
}
|
||||
|
@@ -56,18 +56,12 @@ endif()
|
||||
|
||||
add_library(objlib OBJECT ${NATIVECRYPTO_SOURCES} ${VERSION_FILE_PATH})
|
||||
|
||||
add_library(System.Security.Cryptography.Native
|
||||
SHARED
|
||||
$<TARGET_OBJECTS:objlib>
|
||||
)
|
||||
|
||||
add_library(System.Security.Cryptography.Native.OpenSsl
|
||||
SHARED
|
||||
$<TARGET_OBJECTS:objlib>
|
||||
)
|
||||
|
||||
# Disable the "lib" prefix.
|
||||
set_target_properties(System.Security.Cryptography.Native PROPERTIES PREFIX "")
|
||||
set_target_properties(System.Security.Cryptography.Native.OpenSsl PROPERTIES PREFIX "")
|
||||
|
||||
if (FEATURE_DISTRO_AGNOSTIC_SSL)
|
||||
@@ -80,19 +74,10 @@ if (FEATURE_DISTRO_AGNOSTIC_SSL)
|
||||
)
|
||||
|
||||
# Link with libdl.so to get the dlopen / dlsym / dlclose
|
||||
target_link_libraries(System.Security.Cryptography.Native
|
||||
dl
|
||||
)
|
||||
|
||||
target_link_libraries(System.Security.Cryptography.Native.OpenSsl
|
||||
dl
|
||||
)
|
||||
else()
|
||||
target_link_libraries(System.Security.Cryptography.Native
|
||||
${OPENSSL_CRYPTO_LIBRARY}
|
||||
${OPENSSL_SSL_LIBRARY}
|
||||
)
|
||||
|
||||
target_link_libraries(System.Security.Cryptography.Native.OpenSsl
|
||||
${OPENSSL_CRYPTO_LIBRARY}
|
||||
${OPENSSL_SSL_LIBRARY}
|
||||
@@ -107,12 +92,6 @@ else()
|
||||
#
|
||||
# So, after compiling, rewrite the references to libcrypto to be more flexible.
|
||||
if (APPLE)
|
||||
add_custom_command(TARGET System.Security.Cryptography.Native POST_BUILD
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib @rpath/libcrypto.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native>
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libssl.1.0.0.dylib @rpath/libssl.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native>
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath @loader_path $<TARGET_FILE:System.Security.Cryptography.Native>
|
||||
)
|
||||
|
||||
add_custom_command(TARGET System.Security.Cryptography.Native.OpenSsl POST_BUILD
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib @rpath/libcrypto.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native.OpenSsl>
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libssl.1.0.0.dylib @rpath/libssl.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native.OpenSsl>
|
||||
@@ -123,5 +102,4 @@ endif()
|
||||
|
||||
include(configure.cmake)
|
||||
|
||||
install_library_and_symbols (System.Security.Cryptography.Native)
|
||||
install_library_and_symbols (System.Security.Cryptography.Native.OpenSsl)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user