Fixed size checks for locale detection.

Reported by George Zaytsev from Positive Technologies
This commit is contained in:
akallabeth 2021-12-22 08:53:25 +01:00 committed by akallabeth
parent d0986489dd
commit 7c9117cf86

View File

@ -33,6 +33,7 @@
#include <string.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/environment.h>
#include "liblocale.h"
@ -653,86 +654,98 @@ static const LOCALE_KEYBOARD_LAYOUTS LOCALE_KEYBOARD_LAYOUTS_TABLE[] = {
{ XHOSA, { 0x00000409, 0x00000409, 0x0, 0x0, 0x0 } },
};
static BOOL freerdp_get_system_language_and_country_codes(char* language, char* country)
static BOOL freerdp_get_system_language_and_country_codes(char* language, size_t languageLen,
char* country, size_t countryLen)
{
WINPR_ASSERT(language);
WINPR_ASSERT(languageLen > 0);
WINPR_ASSERT(country);
WINPR_ASSERT(countryLen);
#if defined(__APPLE__)
CFIndex strSize;
CFStringRef langRef, countryRef;
CFLocaleRef localeRef = CFLocaleCopyCurrent();
if (!localeRef)
return FALSE;
langRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleLanguageCode);
countryRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleCountryCode);
if (!langRef || !countryRef)
{
CFRelease(localeRef);
return FALSE;
}
CFIndex strSize;
CFStringRef langRef, countryRef;
CFLocaleRef localeRef = CFLocaleCopyCurrent();
if (!localeRef)
return FALSE;
if (!CFStringGetCString(langRef, language, LOCALE_LANGUAGE_LEN, kCFStringEncodingUTF8) ||
!CFStringGetCString(countryRef, country, LOCALE_COUNTRY_LEN, kCFStringEncodingUTF8))
{
CFRelease(localeRef);
return FALSE;
}
langRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleLanguageCode);
countryRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleCountryCode);
if (!langRef || !countryRef)
{
CFRelease(localeRef);
return FALSE;
}
CFRelease(localeRef);
return TRUE;
if (!CFStringGetCString(langRef, language, languageLen, kCFStringEncodingUTF8) ||
!CFStringGetCString(countryRef, country, countryLen, kCFStringEncodingUTF8))
{
CFRelease(localeRef);
return FALSE;
}
CFRelease(localeRef);
return TRUE;
}
#else
int dot;
DWORD nSize;
int underscore;
char* env_lang = NULL;
LPCSTR lang = "LANG";
/* LANG = <language>_<country>.<encoding> */
nSize = GetEnvironmentVariableA(lang, NULL, 0);
if (!nSize)
return FALSE; /* LANG environment variable was not set */
env_lang = (char*)malloc(nSize);
if (!env_lang)
return FALSE;
if (GetEnvironmentVariableA(lang, env_lang, nSize) !=
nSize - 1) /* Get locale from environment variable LANG */
{
int dot;
DWORD nSize;
int underscore;
char* env_lang = NULL;
LPCSTR lang = "LANG";
/* LANG = <language>_<country>.<encoding> */
nSize = GetEnvironmentVariableA(lang, NULL, 0);
if (!nSize)
return FALSE; /* LANG environment variable was not set */
env_lang = (char*)malloc(nSize);
if (!env_lang)
return FALSE;
if (GetEnvironmentVariableA(lang, env_lang, nSize) !=
nSize - 1) /* Get locale from environment variable LANG */
{
free(env_lang);
return FALSE;
}
underscore = strcspn(env_lang, "_");
if (underscore > 3)
{
free(env_lang);
return FALSE; /* The language name should not be more than 3 letters long */
}
else
{
/* Get language code */
size_t len = MIN(languageLen - 1, underscore);
strncpy(language, env_lang, len);
language[len] = '\0';
}
dot = strcspn(env_lang, ".");
/* Get country code */
if (dot > underscore)
{
size_t len = MIN(countryLen - 1, dot - underscore - 1);
strncpy(country, &env_lang[underscore + 1], len);
country[len] = '\0';
}
else
{
free(env_lang);
return FALSE; /* Invalid locale */
}
free(env_lang);
return FALSE;
return TRUE;
}
underscore = strcspn(env_lang, "_");
if (underscore > 3)
{
free(env_lang);
return FALSE; /* The language name should not be more than 3 letters long */
}
else
{
/* Get language code */
strncpy(language, env_lang, underscore);
language[underscore] = '\0';
}
dot = strcspn(env_lang, ".");
/* Get country code */
if (dot > underscore)
{
strncpy(country, &env_lang[underscore + 1], dot - underscore - 1);
country[dot - underscore - 1] = '\0';
}
else
{
free(env_lang);
return FALSE; /* Invalid locale */
}
free(env_lang);
return TRUE;
#endif
}
@ -742,14 +755,17 @@ static const SYSTEM_LOCALE* freerdp_detect_system_locale(void)
char language[LOCALE_LANGUAGE_LEN] = { 0 };
char country[LOCALE_COUNTRY_LEN] = { 0 };
const SYSTEM_LOCALE* locale = NULL;
freerdp_get_system_language_and_country_codes(language, country);
freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country,
ARRAYSIZE(country));
for (i = 0; i < ARRAYSIZE(SYSTEM_LOCALE_TABLE); i++)
{
if ((strcmp(language, SYSTEM_LOCALE_TABLE[i].language) == 0) &&
(strcmp(country, SYSTEM_LOCALE_TABLE[i].country) == 0))
const SYSTEM_LOCALE* current = &SYSTEM_LOCALE_TABLE[i];
if ((strcmp(language, current->language) == 0) && (strcmp(country, current->country) == 0))
{
locale = (const SYSTEM_LOCALE*)&SYSTEM_LOCALE_TABLE[i];
locale = current;
break;
}
}
@ -774,8 +790,10 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId)
for (index = 0; index < ARRAYSIZE(LOCALE_NAME_TABLE); index++)
{
if (localeId == LOCALE_NAME_TABLE[index].localeId)
return LOCALE_NAME_TABLE[index].name;
const LOCALE_NAME* const current = &LOCALE_NAME_TABLE[index];
if (localeId == current->localeId)
return current->name;
}
return NULL;
@ -787,7 +805,9 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
char language[LOCALE_LANGUAGE_LEN] = { 0 };
char country[LOCALE_COUNTRY_LEN] = { 0 };
const SYSTEM_LOCALE* locale;
freerdp_get_system_language_and_country_codes(language, country);
freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country,
ARRAYSIZE(country));
if ((strcmp(language, "C") == 0) || (strcmp(language, "POSIX") == 0))
{
@ -804,22 +824,24 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
for (i = 0; i < ARRAYSIZE(LOCALE_KEYBOARD_LAYOUTS_TABLE); i++)
{
if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].locale == locale->code)
const LOCALE_KEYBOARD_LAYOUTS* const current = &LOCALE_KEYBOARD_LAYOUTS_TABLE[i];
if (current->locale == locale->code)
{
/* Locale found in list of default keyboard layouts */
for (j = 0; j < 5; j++)
{
if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == ENGLISH_UNITED_STATES)
if (current->keyboardLayouts[j] == ENGLISH_UNITED_STATES)
{
continue; /* Skip, try to get a more localized keyboard layout */
}
else if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == 0)
else if (current->keyboardLayouts[j] == 0)
{
break; /* No more keyboard layouts */
}
else
{
*keyboardLayoutId = LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j];
*keyboardLayoutId = current->keyboardLayouts[j];
return 0;
}
}