Exemple #1
0
static void ConvertIn6AddrToByteArray(uint8_t* buffer, int32_t bufferLength, const in6_addr& addr)
{
#if HAVE_IN6_U
    assert(bufferLength == ARRAY_SIZE(addr.__in6_u.__u6_addr8));
    memcpy(buffer, addr.__in6_u.__u6_addr8, UnsignedCast(bufferLength));
#else
    assert(bufferLength == ARRAY_SIZE(addr.__u6_addr.__u6_addr8));
    memcpy(buffer, addr.__u6_addr.__u6_addr8, UnsignedCast(bufferLength));
#endif
}
Exemple #2
0
extern "C" int32_t IPAddressToString(const uint8_t* address,
                                     int32_t addressLength,
                                     bool isIPv6,
                                     uint8_t* string,
                                     int32_t stringLength,
                                     uint32_t scope /* = 0*/)
{
    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));
    (void)addressLength;            // Silence compiler warnings about unused variables on release mode
    (void)INET6_ADDRSTRLEN_MANAGED; // Silence compiler warnings about unused variables on release mode

    int32_t result;
    socklen_t len = UnsignedCast(stringLength);

    if (isIPv6)
    {
        sockaddr_in6 addr = {.sin6_scope_id = scope};

        ConvertByteArrayToV6SockAddrIn(addr, address, addressLength);
        result = getnameinfo(reinterpret_cast<const sockaddr*>(&addr),
                             sizeof(sockaddr_in6),
                             reinterpret_cast<char*>(string),
                             len,
                             nullptr,
                             0,
                             NI_NUMERICHOST);
    }
    else
    {
Exemple #3
0
// Because RLIM_INFINITY is different per-platform, use the max value of a uint64 (which is RLIM_INFINITY on Ubuntu)
// to signify RLIM_INIFINITY; on OS X, where RLIM_INFINITY is slightly lower, we'll translate it to the correct value
// here.
static uint64_t ConvertFromNativeRLimitInfinityToManagedIfNecessary(rlim_t value)
{
    if (value == RLIM_INFINITY)
        return UINT64_MAX;

    return UnsignedCast(value);
}
Exemple #4
0
extern "C" void SystemNative_GetControlCharacters(
    int32_t* controlCharacterNames, uint8_t* controlCharacterValues, 
    int32_t controlCharacterLength)
{
    assert(controlCharacterNames != nullptr);
    assert(controlCharacterValues != nullptr);
    assert(controlCharacterLength >= 0);

    memset(controlCharacterValues, 0, sizeof(uint8_t) * UnsignedCast(controlCharacterLength));

#if HAVE_TCGETATTR
    struct termios newtermios = {};
    if (tcgetattr(STDIN_FILENO, &newtermios) >= 0)
    {
        for (int i = 0; i < controlCharacterLength; i++)
        {
            int name = TranslatePalControlCharacterName(controlCharacterNames[i]);
            if (name >= 0)
            {
                controlCharacterValues[i] = newtermios.c_cc[name];
            }
        }
    }
#endif
}
Exemple #5
0
extern "C" int32_t ReadStdinUnbuffered(void* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr || bufferSize == 0);
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = EINVAL;
        return -1;
    }

#if HAVE_TCGETATTR && HAVE_TCSETATTR && HAVE_ECHO && HAVE_ICANON && HAVE_TCSANOW
    struct termios oldtermios = {};
    struct termios newtermios = {};

    if (tcgetattr(STDIN_FILENO, &oldtermios) < 0)
        return -1;

    newtermios = oldtermios;
    newtermios.c_lflag &= static_cast<uint32_t>(~(ECHO | ICANON));
    newtermios.c_cc[VMIN] = 1;
    newtermios.c_cc[VTIME] = 0;
    if (tcsetattr(STDIN_FILENO, TCSANOW, &newtermios) < 0)
        return -1;
    ssize_t count = read(STDIN_FILENO, buffer, UnsignedCast(bufferSize));
    tcsetattr(STDIN_FILENO, TCSANOW, &oldtermios);
    return static_cast<int32_t>(count);
#else
    errno = ENOTSUP;
    return -1;
#endif
}
Exemple #6
0
extern "C" int32_t
CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa)
{
    if (siglen == nullptr)
    {
        assert(false);
        return 0;
    }

    *siglen = 0;

    if (HasNoPrivateKey(rsa))
    {
        ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_VALUE_MISSING, __FILE__, __LINE__);
        return 0;
    }

    // Shared pointer to the metadata about the message digest algorithm
    const EVP_MD* digest = EVP_get_digestbynid(type);

    // If the digest itself isn't known then RSA_R_UNKNOWN_ALGORITHM_TYPE will get reported, but
    // we have to check that the digest size matches what we expect.
    if (digest != nullptr && mlen != EVP_MD_size(digest))
    {
        ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_INVALID_MESSAGE_LENGTH, __FILE__, __LINE__);
        return 0;
    }

    unsigned int unsignedSigLen = 0;
    int32_t ret = RSA_sign(type, m, UnsignedCast(mlen), sigret, &unsignedSigLen, rsa);
    assert(unsignedSigLen <= INT32_MAX);
    *siglen = static_cast<int32_t>(unsignedSigLen);
    return ret;
}
extern "C" void SystemNative_ReadEvents(int32_t sock, NetworkChangeEvent onNetworkChange)
{
    char buffer[4096];
    iovec iov = {buffer, sizeof(buffer)};
    sockaddr_nl sanl;
    msghdr msg = { .msg_name = reinterpret_cast<void*>(&sanl), .msg_namelen = sizeof(sockaddr_nl), .msg_iov = &iov, .msg_iovlen = 1 };
    ssize_t len;
    while (CheckInterrupted(len = recvmsg(sock, &msg, 0)));
    if (len == -1)
    {
        // Probably means the socket has been closed.
        return;
    }

    for (nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buffer); NLMSG_OK(hdr, UnsignedCast(len)); NLMSG_NEXT(hdr, len))
    {
        switch (hdr->nlmsg_type)
        {
            case NLMSG_DONE:
                return; // End of a multi-part message; stop reading.
            case NLMSG_ERROR:
                return;
            case RTM_NEWADDR:
                onNetworkChange(sock, NetworkChangeKind::AddressAdded);
                break;
            case RTM_DELADDR:
                onNetworkChange(sock, NetworkChangeKind::AddressRemoved);
                break;
            case RTM_NEWLINK:
                onNetworkChange(sock, ReadNewLinkMessage(hdr));
                break;
            case RTM_DELLINK:
                onNetworkChange(sock, NetworkChangeKind::LinkRemoved);
                break;
            default:
                break;
        }
    }
}

NetworkChangeKind ReadNewLinkMessage(nlmsghdr* hdr)
{
    assert(hdr != nullptr);
    ifinfomsg* ifimsg;
    ifimsg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr));
    if (ifimsg->ifi_family == AF_INET)
    {
        if ((ifimsg->ifi_flags & IFF_UP) != 0)
        {
            return NetworkChangeKind::LinkAdded;
        }
    }

    return NetworkChangeKind::None;
}
Exemple #8
0
static int IpStringToAddressHelper(const uint8_t* address, const uint8_t* port, bool isIPv6, addrinfo*& info)
{
    assert(address != nullptr);

    addrinfo hint = {.ai_family = isIPv6 ? AF_INET6 : AF_INET, .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV};

    info = nullptr;
    return getaddrinfo(reinterpret_cast<const char*>(address), reinterpret_cast<const char*>(port), &hint, &info);
}

static void ConvertByteArrayToIn6Addr(in6_addr& addr, const uint8_t* buffer, int32_t bufferLength)
{
#if HAVE_IN6_U
    assert(bufferLength == ARRAY_SIZE(addr.__in6_u.__u6_addr8));
    memcpy(addr.__in6_u.__u6_addr8, buffer, UnsignedCast(bufferLength));
#else
    assert(bufferLength == ARRAY_SIZE(addr.__u6_addr.__u6_addr8));
    memcpy(addr.__u6_addr.__u6_addr8, buffer, UnsignedCast(bufferLength));
#endif
}
Exemple #9
0
extern "C" char* SystemNative_GetCwd(char* buffer, int32_t bufferSize)
{
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = EINVAL;
        return nullptr;
    }

    return getcwd(buffer, UnsignedCast(bufferSize));
}
Exemple #10
0
extern "C" int32_t EcDsaSign(const uint8_t* dgst, int32_t dgstlen, uint8_t* sig, int32_t* siglen, EC_KEY* key)
{
    if (!siglen)
    {
        return 0;
    }

    unsigned int unsignedSigLength = UnsignedCast(*siglen);
    int ret = ECDSA_sign(0, dgst, dgstlen, sig, &unsignedSigLength, key);
    *siglen = SignedCast(unsignedSigLength);
    return ret;
}
Exemple #11
0
extern "C" int32_t CryptoNative_HmacUpdate(HMAC_CTX* ctx, const uint8_t* data, int32_t len)
{
    assert(ctx != nullptr);
    assert(data != nullptr || len == 0);
    assert(len >= 0);

    if (len < 0)
    {
        return 0;
    }

    return HMAC_Update(ctx, data, UnsignedCast(len));
}
Exemple #12
0
extern "C" const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr);
    assert(bufferSize > 0);

    if (bufferSize < 0)
        return nullptr;

// Note that we must use strerror_r because plain strerror is not
// thread-safe.
//
// However, there are two versions of strerror_r:
//    - GNU:   char* strerror_r(int, char*, size_t);
//    - POSIX: int   strerror_r(int, char*, size_t);
//
// The former may or may not use the supplied buffer, and returns
// the error message string. The latter stores the error message
// string into the supplied buffer and returns an error code.

#if HAVE_GNU_STRERROR_R
    const char* message = strerror_r(platformErrno, buffer, UnsignedCast(bufferSize));
    assert(message != nullptr);
    return message;
#else
    int error = strerror_r(platformErrno, buffer, UnsignedCast(bufferSize));
    if (error == ERANGE)
    {
        // Buffer is too small to hold the entire message, but has
        // still been filled to the extent possible and null-terminated.
        return nullptr;
    }

    // The only other valid error codes are 0 for success or EINVAL for
    // an unkown error, but in the latter case a reasonable string (e.g
    // "Unknown error: 0x123") is returned.
    assert(error == 0 || error == EINVAL);
    return buffer;
#endif
}
Exemple #13
0
extern "C" int32_t Write(int32_t fd, const void* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr || bufferSize == 0);
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = ERANGE;
        return -1;
    }

    ssize_t count = write(fd, buffer, UnsignedCast(bufferSize));
    assert(count >= -1 && count <= bufferSize);
    return static_cast<int32_t>(count);
}
Exemple #14
0
extern "C" int32_t Read(int32_t fd, void* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr || bufferSize == 0);
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ssize_t count = read(fd, buffer, UnsignedCast(bufferSize));
    assert(count >= -1 && count <= bufferSize);
    return static_cast<int32_t>(count);
}
Exemple #15
0
extern "C" int32_t SystemNative_ReadStdinUnbuffered(void* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr || bufferSize == 0);
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ssize_t count;
    while (CheckInterrupted(count = read(STDIN_FILENO, buffer, UnsignedCast(bufferSize))));
    return static_cast<int32_t>(count);
}
Exemple #16
0
extern "C" int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize)
{
    assert(buffer != nullptr || bufferSize == 0);
    assert(bufferSize >= 0);

    if (bufferSize < 0)
    {
        errno = ERANGE;
        return -1;
    }

    ssize_t count;
    while (CheckInterrupted(count = write(ToFileDescriptor(fd), buffer, UnsignedCast(bufferSize))));

    assert(count >= -1 && count <= bufferSize);
    return static_cast<int32_t>(count);
}
Exemple #17
0
extern "C" int32_t CryptoNative_HmacFinal(HMAC_CTX* ctx, uint8_t* md, int32_t* len)
{
    assert(ctx != nullptr);
    assert(len != nullptr);
    assert(md != nullptr || *len == 0);
    assert(*len >= 0);

    if (len == nullptr || *len < 0)
    {
        return 0;
    }

    unsigned int unsignedLen = UnsignedCast(*len);
    int ret = HMAC_Final(ctx, md, &unsignedLen);
    *len = SignedCast(unsignedLen);
    return ret;
}
Exemple #18
0
extern "C" int32_t GetPwUidR(uint32_t uid, Passwd* pwd, char* buf, int32_t buflen)
{
    assert(pwd != nullptr);
    assert(buf != nullptr);
    assert(buflen >= 0);

    if (buflen < 0)
        return EINVAL;

    struct passwd nativePwd;
    struct passwd* result;
    int error = getpwuid_r(uid, &nativePwd, buf, UnsignedCast(buflen), &result);

    // positive error number returned -> failure other than entry-not-found
    if (error != 0)
    {
        assert(error > 0);
        *pwd = {}; // managed out param must be initialized
        return error;
    }

    // 0 returned with null result -> entry-not-found
    if (result == nullptr)
    {
        *pwd = {}; // managed out param must be initialized
        return -1; // shim convention for entry-not-found
    }

    // 0 returned with non-null result (guaranteed to be set to pwd arg) -> success
    assert(result == &nativePwd);
    pwd->Name = nativePwd.pw_name;
    pwd->Password = nativePwd.pw_passwd;
    pwd->UserId = nativePwd.pw_uid;
    pwd->GroupId = nativePwd.pw_gid;
    pwd->UserInfo = nativePwd.pw_gecos;
    pwd->HomeDirectory = nativePwd.pw_dir;
    pwd->Shell = nativePwd.pw_shell;
    return 0;
}
Exemple #19
0
extern "C" int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd)
{
    int inFd = ToFileDescriptor(sourceFd);
    int outFd = ToFileDescriptor(destinationFd);

#if HAVE_FCOPYFILE
    // If fcopyfile is available (OS X), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    // Copy data and metadata.
    return fcopyfile(inFd, outFd, nullptr, COPYFILE_ALL) == 0 ? 0 : -1;
#else
    // Get the stats on the source file.
    int ret;
    struct stat_ sourceStat;
    bool copied = false;
#if HAVE_SENDFILE
    // If sendfile is available (Linux), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    while (CheckInterrupted(ret = fstat_(inFd, &sourceStat)));
    if (ret != 0)
    {
        return -1;
    }


    // We use `auto' here to adapt the type of `size' depending on the running platform.
    // On 32-bit, if you use 64-bit offsets, the last argument of `sendfile' will be a
    // `size_t' a 32-bit integer while the `st_size' field of the stat structure will be off64_t.
    // So `size' will have to be `uint64_t'. In all other cases, it will be `size_t'.
    auto size = UnsignedCast(sourceStat.st_size);

    // Note that per man page for large files, you have to iterate until the
    // whole file is copied (Linux has a limit of 0x7ffff000 bytes copied).
    while (size > 0)
    {
        ssize_t sent = sendfile(outFd, inFd, nullptr, (size >= SSIZE_MAX ? SSIZE_MAX : static_cast<size_t>(size)));
        if (sent < 0)
        {
            if (errno != EINVAL && errno != ENOSYS)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else
        {
            assert(UnsignedCast(sent) <= size);
            size -= UnsignedCast(sent);
        }
    }
    if (size == 0)
    {
        copied = true;
    }
    // sendfile couldn't be used; fall back to a manual copy below. This could happen
    // if we're on an old kernel, for example, where sendfile could only be used
    // with sockets and not regular files.
#endif // HAVE_SENDFILE

    // Manually read all data from the source and write it to the destination.
    if (!copied && CopyFile_ReadWrite(inFd, outFd) != 0)
    {
        return -1;
    }

    // Now that the data from the file has been copied, copy over metadata
    // from the source file.  First copy the file times.
    while (CheckInterrupted(ret = fstat_(inFd, &sourceStat)));
    if (ret == 0)
    {
        struct timeval origTimes[2];
        origTimes[0].tv_sec = sourceStat.st_atime;
        origTimes[0].tv_usec = 0;
        origTimes[1].tv_sec = sourceStat.st_mtime;
        origTimes[1].tv_usec = 0;
        while (CheckInterrupted(ret = futimes(outFd, origTimes)));
    }
    if (ret != 0)
    {
        return -1;
    }

    // Then copy permissions.
    while (CheckInterrupted(ret = fchmod(outFd, sourceStat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))));
    if (ret != 0)
    {
        return -1;
    }

    return 0;
#endif // HAVE_FCOPYFILE
}
Exemple #20
0
extern "C" int32_t
CryptoNative_RsaVerify(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigbuf, int32_t siglen, RSA* rsa)
{
    return RSA_verify(type, m, UnsignedCast(mlen), sigbuf, UnsignedCast(siglen), rsa);
}