Fix CVE-2023-27533

Merge: curl/curl@538b1e79a6
This commit is contained in:
Kawe Mazidjatari 2023-06-13 16:49:15 +02:00
parent 1d570a82d8
commit 4090757035
3 changed files with 186 additions and 59 deletions

View File

@ -93,6 +93,73 @@ char Curl_raw_toupper(char in)
return in;
}
/* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because
its behavior is altered by the current locale. */
char Curl_raw_tolower(char in)
{
#if !defined(CURL_DOES_CONVERSIONS)
if(in >= 'A' && in <= 'Z')
return (char)('a' + in - 'A');
#else
switch(in) {
case 'A':
return 'a';
case 'B':
return 'b';
case 'C':
return 'c';
case 'D':
return 'd';
case 'E':
return 'e';
case 'F':
return 'f';
case 'G':
return 'g';
case 'H':
return 'h';
case 'I':
return 'i';
case 'J':
return 'j';
case 'K':
return 'k';
case 'L':
return 'l';
case 'M':
return 'm';
case 'N':
return 'n';
case 'O':
return 'o';
case 'P':
return 'p';
case 'Q':
return 'q';
case 'R':
return 'r';
case 'S':
return 's';
case 'T':
return 't';
case 'U':
return 'u';
case 'V':
return 'v';
case 'W':
return 'w';
case 'X':
return 'x';
case 'Y':
return 'y';
case 'Z':
return 'z';
}
#endif
return in;
}
/*
* Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
* to be locale independent and only compare strings we know are safe for
@ -164,6 +231,21 @@ void Curl_strntoupper(char *dest, const char *src, size_t n)
} while(*src++ && --n);
}
/* Copy a lower case version of the string from src to dest. The
* strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be
* NUL-terminated if that limit is reached.
*/
void Curl_strntolower(char *dest, const char *src, size_t n)
{
if(n < 1)
return;
do {
*dest++ = Curl_raw_tolower(*src);
} while(*src++ && --n);
}
/* Compare case-sensitive NUL-terminated strings, taking care of possible
* null pointers. Return true if arguments match.
*/

View File

@ -46,7 +46,9 @@ char Curl_raw_toupper(char in);
#define checkprefix(a,b) curl_strnequal(a,b,strlen(a))
void Curl_strntoupper(char *dest, const char *src, size_t n);
void Curl_strntolower(char *dest, const char *src, size_t n);
char Curl_raw_toupper(char in);
char Curl_raw_tolower(char in);
bool Curl_safecmp(char *a, char *b);

View File

@ -815,22 +815,33 @@ static void printsub(struct Curl_easy *data,
}
}
static bool str_is_nonascii(const char *str)
{
size_t len = strlen(str);
while(len--) {
if(*str & 0x80)
return TRUE;
str++;
}
return FALSE;
}
static CURLcode check_telnet_options(struct connectdata *conn)
{
struct curl_slist *head;
struct curl_slist *beg;
char option_keyword[128] = "";
char option_arg[256] = "";
struct Curl_easy *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
CURLcode result = CURLE_OK;
int binary_option;
/* Add the user name as an environment variable if it
was given on the command line */
if(conn->bits.user_passwd) {
snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
beg = curl_slist_append(tn->telnet_vars, option_arg);
char buffer[256];
if(str_is_nonascii(conn->user))
return CURLE_BAD_FUNCTION_ARGUMENT;
snprintf(buffer, sizeof(buffer), "USER,%s", conn->user);
beg = curl_slist_append(tn->telnet_vars, buffer);
if(!beg) {
curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL;
@ -840,68 +851,100 @@ static CURLcode check_telnet_options(struct connectdata *conn)
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
for(head = data->set.telnet_options; head; head=head->next) {
if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
option_keyword, option_arg) == 2) {
/* Terminal type */
if(strcasecompare(option_keyword, "TTYPE")) {
strncpy(tn->subopt_ttype, option_arg, 31);
tn->subopt_ttype[31] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
for(head = data->set.telnet_options; head && !result; head = head->next) {
size_t olen;
char *option = head->data;
char *arg;
char *sep = strchr(option, '=');
if(sep) {
olen = sep - option;
arg = ++sep;
if(str_is_nonascii(arg))
continue;
}
/* Display variable */
if(strcasecompare(option_keyword, "XDISPLOC")) {
strncpy(tn->subopt_xdisploc, option_arg, 127);
tn->subopt_xdisploc[127] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
continue;
}
/* Environment variable */
if(strcasecompare(option_keyword, "NEW_ENV")) {
beg = curl_slist_append(tn->telnet_vars, option_arg);
if(!beg) {
result = CURLE_OUT_OF_MEMORY;
break;
switch(olen) {
case 5:
/* Terminal type */
if(strncasecompare(option, "TTYPE", 5)) {
strncpy(tn->subopt_ttype, arg, 31);
tn->subopt_ttype[31] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
}
tn->telnet_vars = beg;
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
continue;
}
else
result = CURLE_UNKNOWN_OPTION;
break;
/* Window Size */
if(strcasecompare(option_keyword, "WS")) {
if(sscanf(option_arg, "%hu%*[xX]%hu",
&tn->subopt_wsx, &tn->subopt_wsy) == 2)
tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
else {
failf(data, "Syntax error in telnet option: %s", head->data);
result = CURLE_TELNET_OPTION_SYNTAX;
break;
case 8:
/* Display variable */
if(strncasecompare(option, "XDISPLOC", 8)) {
strncpy(tn->subopt_xdisploc, arg, 127);
tn->subopt_xdisploc[127] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
}
continue;
}
else
result = CURLE_UNKNOWN_OPTION;
break;
/* To take care or not of the 8th bit in data exchange */
if(strcasecompare(option_keyword, "BINARY")) {
binary_option=atoi(option_arg);
if(binary_option!=1) {
tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
case 7:
/* Environment variable */
if(strncasecompare(option, "NEW_ENV", 7)) {
beg = curl_slist_append(tn->telnet_vars, arg);
if(!beg) {
result = CURLE_OUT_OF_MEMORY;
break;
}
tn->telnet_vars = beg;
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
continue;
}
else
result = CURLE_UNKNOWN_OPTION;
break;
failf(data, "Unknown telnet option %s", head->data);
result = CURLE_UNKNOWN_TELNET_OPTION;
break;
case 2:
/* Window Size */
if(strncasecompare(option, "WS", 2)) {
char *p;
unsigned long x = strtoul(arg, &p, 10);
unsigned long y = 0;
if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
p++;
y = strtoul(p, NULL, 10);
if(y && (y <= 0xffff)) {
tn->subopt_wsx = (unsigned short)x;
tn->subopt_wsy = (unsigned short)y;
tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
}
}
if(!y) {
failf(data, "Syntax error in telnet option: %s", head->data);
result = CURLE_TELNET_OPTION_SYNTAX;
}
}
else
result = CURLE_UNKNOWN_OPTION;
break;
case 6:
/* To take care or not of the 8th bit in data exchange */
if(strncasecompare(option, "BINARY", 6)) {
int binary_option = atoi(arg);
if(binary_option != 1) {
tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
}
}
else
result = CURLE_UNKNOWN_OPTION;
break;
default:
failf(data, "Unknown telnet option %s", head->data);
result = CURLE_UNKNOWN_OPTION;
break;
}
}
else {
failf(data, "Syntax error in telnet option: %s", head->data);
result = CURLE_TELNET_OPTION_SYNTAX;
}
failf(data, "Syntax error in telnet option: %s", head->data);
result = CURLE_TELNET_OPTION_SYNTAX;
break;
}
if(result) {