diff --git a/winpr/libwinpr/credentials/credentials.c b/winpr/libwinpr/credentials/credentials.c index f7e4810a0..d1c28cb27 100644 --- a/winpr/libwinpr/credentials/credentials.c +++ b/winpr/libwinpr/credentials/credentials.c @@ -34,7 +34,7 @@ #ifndef _WIN32 -static BYTE wchar_decode(WCHAR c) +static BYTE char_decode(char c) { if (c >= 'A' && c <= 'Z') return (BYTE)(c - 'A'); @@ -49,26 +49,26 @@ static BYTE wchar_decode(WCHAR c) return 64; } -static BOOL cred_decode(const WCHAR* cred, size_t len, BYTE* buf) +static BOOL cred_decode(const char* cred, size_t len, BYTE* buf) { size_t i = 0; - const WCHAR* p = cred; + const char* p = cred; while (len >= 4) { - BYTE c0 = wchar_decode(p[0]); + BYTE c0 = char_decode(p[0]); if (c0 > 63) return FALSE; - BYTE c1 = wchar_decode(p[1]); + BYTE c1 = char_decode(p[1]); if (c1 > 63) return FALSE; - BYTE c2 = wchar_decode(p[2]); + BYTE c2 = char_decode(p[2]); if (c2 > 63) return FALSE; - BYTE c3 = wchar_decode(p[3]); + BYTE c3 = char_decode(p[3]); if (c3 > 63) return FALSE; @@ -82,15 +82,15 @@ static BOOL cred_decode(const WCHAR* cred, size_t len, BYTE* buf) if (len == 3) { - BYTE c0 = wchar_decode(p[0]); + BYTE c0 = char_decode(p[0]); if (c0 > 63) return FALSE; - BYTE c1 = wchar_decode(p[1]); + BYTE c1 = char_decode(p[1]); if (c1 > 63) return FALSE; - BYTE c2 = wchar_decode(p[2]); + BYTE c2 = char_decode(p[2]); if (c2 > 63) return FALSE; @@ -99,11 +99,11 @@ static BOOL cred_decode(const WCHAR* cred, size_t len, BYTE* buf) } else if (len == 2) { - BYTE c0 = wchar_decode(p[0]); + BYTE c0 = char_decode(p[0]); if (c0 > 63) return FALSE; - BYTE c1 = wchar_decode(p[1]); + BYTE c1 = char_decode(p[1]); if (c1 > 63) return FALSE; @@ -117,54 +117,72 @@ static BOOL cred_decode(const WCHAR* cred, size_t len, BYTE* buf) return TRUE; } -static size_t cred_encode(const BYTE* bin, size_t len, WCHAR* cred) +static size_t cred_encode(const BYTE* bin, size_t len, char* cred, size_t credlen) { - static const WCHAR encodingChars[] = { - /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */ - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - /* abcdefghijklmnopqrstuvwxyz */ - 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, - /* 0123456789 */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - /* #- */ - 0x23, 0x2d - }; + static const char encodingChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "#-"; size_t n = 0; - - while (len > 0) + size_t offset = 0; + while (offset < len) { - cred[n++] = encodingChars[bin[0] & 0x3f]; - BYTE x = (bin[0] & 0xc0) >> 6; - if (len == 1) + if (n >= credlen) + break; + + cred[n++] = encodingChars[bin[offset] & 0x3f]; + BYTE x = (bin[offset] & 0xc0) >> 6; + offset++; + + if (offset >= len) { cred[n++] = encodingChars[x]; break; } - cred[n++] = encodingChars[((bin[1] & 0xf) << 2) | x]; - x = (bin[1] & 0xf0) >> 4; - if (len == 2) + if (n >= credlen) + break; + cred[n++] = encodingChars[((bin[offset] & 0xf) << 2) | x]; + x = (bin[offset] & 0xf0) >> 4; + offset++; + + if (offset >= len) { cred[n++] = encodingChars[x]; break; } - cred[n++] = encodingChars[((bin[2] & 0x3) << 4) | x]; - cred[n++] = encodingChars[(bin[2] & 0xfc) >> 2]; - bin += 3; - len -= 3; + if (n >= credlen) + break; + cred[n++] = encodingChars[((bin[offset] & 0x3) << 4) | x]; + + if (n >= credlen) + break; + cred[n++] = encodingChars[(bin[offset] & 0xfc) >> 2]; + offset++; } return n; } -BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID cred, LPWSTR* MarshaledCredential) +BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID Credential, + LPWSTR* MarshaledCredential) { - CERT_CREDENTIAL_INFO* cert = cred; - WCHAR* p = NULL; + char* b = NULL; + if (!CredMarshalCredentialA(CredType, Credential, &b) || !b) + return FALSE; - if (!cred || (CredType == CertCredential && cert->cbSize < sizeof(*cert))) + *MarshaledCredential = ConvertUtf8ToWCharAlloc(b, NULL); + free(b); + return (*MarshaledCredential != NULL); +} + +BOOL CredMarshalCredentialA(CRED_MARSHAL_TYPE CredType, PVOID Credential, + LPSTR* MarshaledCredential) +{ + CERT_CREDENTIAL_INFO* cert = Credential; + + if (!cert || ((CredType == CertCredential) && (cert->cbSize < sizeof(CERT_CREDENTIAL_INFO))) || + !MarshaledCredential) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -174,96 +192,86 @@ BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID cred, LPWSTR* Mars { case CertCredential: { - size_t size = (sizeof(cert->rgbHashOfCert) + 2) * 4 / 3; - if (!(p = malloc((size + 4) * sizeof(WCHAR)))) - return FALSE; - p[0] = '@'; - p[1] = '@'; - p[2] = (WCHAR)('A' + CredType); - size_t len = cred_encode(cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), p + 3); - p[len + 3] = 0; - break; + char buffer[3ULL + (sizeof(cert->rgbHashOfCert) * 4 / 3) + + 1ULL /* rounding error */] = { 0 }; + + const char c = WINPR_ASSERTING_INT_CAST(char, 'A' + CredType); + (void)_snprintf(buffer, sizeof(buffer), "@@%c", c); + size_t len = cred_encode(cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), &buffer[3], + sizeof(buffer) - 3); + *MarshaledCredential = strndup(buffer, len + 3); + return TRUE; } default: WLog_ERR(TAG, "unhandled type 0x%x", CredType); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - - *MarshaledCredential = p; - return TRUE; -} - -BOOL CredMarshalCredentialA(CRED_MARSHAL_TYPE CredType, PVOID Credential, - LPSTR* MarshaledCredential) -{ - WCHAR* b = NULL; - if (!CredMarshalCredentialW(CredType, Credential, &b) || !b) - return FALSE; - - *MarshaledCredential = ConvertWCharNToUtf8Alloc(b, _wcslen(b), NULL); - free(b); - return (*MarshaledCredential != NULL); } BOOL CredUnmarshalCredentialW(LPCWSTR cred, PCRED_MARSHAL_TYPE pcredType, PVOID* out) { - if (!cred || !pcredType || !out || cred[0] != '@' || cred[1] != '@') + char* str = NULL; + if (cred) + str = ConvertWCharToUtf8Alloc(cred, NULL); + const BOOL rc = CredUnmarshalCredentialA(str, pcredType, out); + free(str); + return rc; +} + +BOOL CredUnmarshalCredentialA(LPCSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential) +{ + if (!cred) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - BYTE b = wchar_decode(cred[2]); - if (!b || b > BinaryBlobForSystem) + const size_t len = strlen(cred); + if ((len < 3) || !CredType || !Credential || (cred[0] != '@') || (cred[1] != '@')) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - *pcredType = (CRED_MARSHAL_TYPE)b; + BYTE b = char_decode(cred[2]); + if (!b || (b > BinaryBlobForSystem)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - size_t len = _wcslen(cred + 3); - switch (*pcredType) + *CredType = (CRED_MARSHAL_TYPE)b; + + switch (*CredType) { case CertCredential: { - BYTE hash[CERT_HASH_LENGTH]; + BYTE hash[CERT_HASH_LENGTH] = { 0 }; - if (len != 27 || !cred_decode(cred + 3, len, hash)) + if ((len != 30) || !cred_decode(&cred[3], len - 3, hash)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - CERT_CREDENTIAL_INFO* cert = malloc(sizeof(*cert)); + CERT_CREDENTIAL_INFO* cert = calloc(1, sizeof(CERT_CREDENTIAL_INFO)); if (!cert) return FALSE; + cert->cbSize = sizeof(CERT_CREDENTIAL_INFO); memcpy(cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert)); - cert->cbSize = sizeof(*cert); - *out = cert; + *Credential = cert; break; } default: - WLog_ERR(TAG, "unhandled credType 0x%x", *pcredType); + WLog_ERR(TAG, "unhandled credType 0x%x", *CredType); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } return TRUE; } -BOOL CredUnmarshalCredentialA(LPCSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential) -{ - WCHAR* b = ConvertUtf8NToWCharAlloc(cred, strlen(cred), NULL); - if (!b) - return FALSE; - - BOOL ret = CredUnmarshalCredentialW(b, CredType, Credential); - free(b); - return ret; -} - BOOL CredIsMarshaledCredentialW(LPCWSTR MarshaledCredential) { CRED_MARSHAL_TYPE t = BinaryBlobForSystem; diff --git a/winpr/libwinpr/credentials/test/TestMarshalUnmarshal.c b/winpr/libwinpr/credentials/test/TestMarshalUnmarshal.c index 1d0c1056c..aa3ba5ae4 100644 --- a/winpr/libwinpr/credentials/test/TestMarshalUnmarshal.c +++ b/winpr/libwinpr/credentials/test/TestMarshalUnmarshal.c @@ -25,29 +25,32 @@ typedef struct BYTE source[CERT_HASH_LENGTH]; } TestItem; -static TestItem testValues[] = { { "@@BQ9eNR0KWVU-CT8sPCp8z37POZHJ", - { 0x50, 0xef, 0x35, 0x11, 0xad, 0x58, 0x15, 0xf5, 0x0b, 0x13, - 0xcf, 0x3e, 0x42, 0xca, 0xcf, 0xf7, 0xfe, 0x38, 0xd9, 0x91 } }, - { "@@BKay-HwJsFZzclXAWZ#nO6Eluc7P", - { 0x8a, 0x26, 0xff, 0x07, 0x9c, 0xb0, 0x45, 0x36, 0x73, 0xe5, - 0x05, 0x58, 0x99, 0x7f, 0x3a, 0x3a, 0x51, 0xba, 0xdc, 0xfe } +static const TestItem testValues[] = { + { "@@BQ9eNR0KWVU-CT8sPCp8z37POZHJ", + { 0x50, 0xef, 0x35, 0x11, 0xad, 0x58, 0x15, 0xf5, 0x0b, 0x13, + 0xcf, 0x3e, 0x42, 0xca, 0xcf, 0xf7, 0xfe, 0x38, 0xd9, 0x91 } }, + { "@@BKay-HwJsFZzclXAWZ#nO6Eluc7P", + { 0x8a, 0x26, 0xff, 0x07, 0x9c, 0xb0, 0x45, 0x36, 0x73, 0xe5, + 0x05, 0x58, 0x99, 0x7f, 0x3a, 0x3a, 0x51, 0xba, 0xdc, 0xfe } - } }; + } +}; -static int TestUnmarshal(int argc, char** argv) +static int TestUnmarshal(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char** argv) { - for (int i = 0; i < ARRAYSIZE(testValues); i++) + for (size_t i = 0; i < ARRAYSIZE(testValues); i++) { CRED_MARSHAL_TYPE t = BinaryBlobForSystem; CERT_CREDENTIAL_INFO* certInfo = NULL; + const TestItem* const val = &testValues[i]; - if (!CredUnmarshalCredentialA(testValues[i].marshalled, &t, (void**)&certInfo) || - !certInfo || t != CertCredential) + if (!CredUnmarshalCredentialA(val->marshalled, &t, (void**)&certInfo) || !certInfo || + (t != CertCredential)) return -1; - BOOL ok = memcmp(testValues[i].source, certInfo->rgbHashOfCert, - sizeof(certInfo->rgbHashOfCert)) == 0; + const BOOL ok = + memcmp(val->source, certInfo->rgbHashOfCert, sizeof(certInfo->rgbHashOfCert)) == 0; free(certInfo); @@ -57,20 +60,21 @@ static int TestUnmarshal(int argc, char** argv) return 0; } -static int TestMarshal(int argc, char** argv) +static int TestMarshal(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char** argv) { - for (int i = 0; i < ARRAYSIZE(testValues); i++) + for (size_t i = 0; i < ARRAYSIZE(testValues); i++) { - CRED_MARSHAL_TYPE t = BinaryBlobForSystem; CERT_CREDENTIAL_INFO certInfo = { sizeof(certInfo), { 0 } }; - memcpy(certInfo.rgbHashOfCert, testValues[i].source, sizeof(certInfo.rgbHashOfCert)); + const TestItem* const val = &testValues[i]; + + memcpy(certInfo.rgbHashOfCert, val->source, sizeof(certInfo.rgbHashOfCert)); LPSTR out = NULL; if (!CredMarshalCredentialA(CertCredential, &certInfo, &out) || !out) return -1; - BOOL ok = (strcmp(testValues[i].marshalled, out) == 0); + BOOL ok = (strcmp(val->marshalled, out) == 0); free(out); diff --git a/winpr/libwinpr/crt/unicode_builtin.c b/winpr/libwinpr/crt/unicode_builtin.c index 394122fdc..3526d84c5 100644 --- a/winpr/libwinpr/crt/unicode_builtin.c +++ b/winpr/libwinpr/crt/unicode_builtin.c @@ -124,6 +124,26 @@ static const uint32_t offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2 */ static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +/* We always need UTF-16LE, even on big endian systems! */ +static WCHAR setWcharFrom(WCHAR w) +{ +#if defined(__BIG_ENDIAN__) + union + { + WCHAR w; + char c[2]; + } cnv; + + cnv.w = w; + const char c = cnv.c[0]; + cnv.c[0] = cnv.c[1]; + cnv.c[1] = c; + return cnv.w; +#else + return w; +#endif +} + /* --------------------------------------------------------------------- */ /* The interface converts a whole buffer to avoid function-call overhead. @@ -155,7 +175,7 @@ static ConversionResult winpr_ConvertUTF16toUTF8_Internal(const uint16_t** sourc const uint16_t* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; + ch = setWcharFrom(*source++); /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) @@ -163,7 +183,7 @@ static ConversionResult winpr_ConvertUTF16toUTF8_Internal(const uint16_t** sourc /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { - uint32_t ch2 = *source; + uint32_t ch2 = setWcharFrom(*source); /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) @@ -472,7 +492,7 @@ static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** source else { if (!computeLength) - *target++ = UNI_REPLACEMENT_CHAR; + *target++ = setWcharFrom(UNI_REPLACEMENT_CHAR); else target++; } @@ -480,7 +500,7 @@ static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** source else { if (!computeLength) - *target++ = (uint16_t)ch; /* normal case */ + *target++ = setWcharFrom((WCHAR)ch); /* normal case */ else target++; } @@ -496,7 +516,7 @@ static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** source else { if (!computeLength) - *target++ = UNI_REPLACEMENT_CHAR; + *target++ = setWcharFrom(UNI_REPLACEMENT_CHAR); else target++; } @@ -515,8 +535,8 @@ static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** source if (!computeLength) { - *target++ = (uint16_t)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (uint16_t)((ch & halfMask) + UNI_SUR_LOW_START); + *target++ = setWcharFrom((WCHAR)((ch >> halfShift) + UNI_SUR_HIGH_START)); + *target++ = setWcharFrom((WCHAR)((ch & halfMask) + UNI_SUR_LOW_START)); } else {