Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
17fd2dcbfa
@ -552,9 +552,25 @@ void* WTSVirtualChannelOpenEx(
|
|||||||
|
|
||||||
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
|
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
|
||||||
{
|
{
|
||||||
|
for (i = 0; i < client->settings->ChannelCount; i++)
|
||||||
|
{
|
||||||
|
if (client->settings->ChannelDefArray[i].joined &&
|
||||||
|
strncmp(client->settings->ChannelDefArray[i].Name, "drdynvc", 7) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i >= client->settings->ChannelCount)
|
||||||
|
{
|
||||||
|
DEBUG_DVC("Dynamic virtual channel not registered.");
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY)
|
if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY)
|
||||||
{
|
{
|
||||||
DEBUG_DVC("Dynamic virtual channel not ready.");
|
DEBUG_DVC("Dynamic virtual channel not ready.");
|
||||||
|
SetLastError(ERROR_NOT_READY);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +602,10 @@ void* WTSVirtualChannelOpenEx(
|
|||||||
len = strlen(pVirtualName);
|
len = strlen(pVirtualName);
|
||||||
|
|
||||||
if (len > 8)
|
if (len > 8)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < client->settings->ChannelCount; i++)
|
for (i = 0; i < client->settings->ChannelCount; i++)
|
||||||
{
|
{
|
||||||
@ -598,7 +617,10 @@ void* WTSVirtualChannelOpenEx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i >= client->settings->ChannelCount)
|
if (i >= client->settings->ChannelCount)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
channel = (rdpPeerChannel*) client->settings->ChannelDefArray[i].handle;
|
channel = (rdpPeerChannel*) client->settings->ChannelDefArray[i].handle;
|
||||||
|
|
||||||
|
@ -258,6 +258,8 @@ int android_freerdp_run(freerdp* instance)
|
|||||||
void* wfds[32];
|
void* wfds[32];
|
||||||
fd_set rfds_set;
|
fd_set rfds_set;
|
||||||
fd_set wfds_set;
|
fd_set wfds_set;
|
||||||
|
int select_status;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
memset(rfds, 0, sizeof(rfds));
|
memset(rfds, 0, sizeof(rfds));
|
||||||
memset(wfds, 0, sizeof(wfds));
|
memset(wfds, 0, sizeof(wfds));
|
||||||
@ -269,7 +271,7 @@ int android_freerdp_run(freerdp* instance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
((androidContext*)instance->context)->is_connected = TRUE;
|
((androidContext*)instance->context)->is_connected = TRUE;
|
||||||
while (1)
|
while (!freerdp_shall_disconnect(instance))
|
||||||
{
|
{
|
||||||
rcount = 0;
|
rcount = 0;
|
||||||
wcount = 0;
|
wcount = 0;
|
||||||
@ -307,7 +309,14 @@ int android_freerdp_run(freerdp* instance)
|
|||||||
if (max_fds == 0)
|
if (max_fds == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout);
|
||||||
|
|
||||||
|
if (select_status == 0)
|
||||||
|
continue;
|
||||||
|
else if (select_status == -1)
|
||||||
{
|
{
|
||||||
/* these are not really errors */
|
/* these are not really errors */
|
||||||
if (!((errno == EAGAIN) ||
|
if (!((errno == EAGAIN) ||
|
||||||
@ -495,9 +504,6 @@ JNIEXPORT void JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls,
|
|||||||
settings->ConsoleSession = (console == JNI_TRUE) ? TRUE : FALSE;
|
settings->ConsoleSession = (console == JNI_TRUE) ? TRUE : FALSE;
|
||||||
|
|
||||||
settings->SoftwareGdi = TRUE;
|
settings->SoftwareGdi = TRUE;
|
||||||
|
|
||||||
/* enable NSCodec */
|
|
||||||
settings->NSCodec = TRUE;
|
|
||||||
settings->BitmapCacheV3Enabled = TRUE;
|
settings->BitmapCacheV3Enabled = TRUE;
|
||||||
|
|
||||||
switch ((int) security)
|
switch ((int) security)
|
||||||
@ -561,6 +567,11 @@ JNIEXPORT void JNICALL jni_freerdp_set_performance_flags(
|
|||||||
settings->LargePointerFlag = TRUE;
|
settings->LargePointerFlag = TRUE;
|
||||||
settings->FrameMarkerCommandEnabled = TRUE;
|
settings->FrameMarkerCommandEnabled = TRUE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* enable NSCodec if we don't use remotefx */
|
||||||
|
settings->NSCodec = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* store performance settings */
|
/* store performance settings */
|
||||||
if (disableWallpaper == JNI_TRUE)
|
if (disableWallpaper == JNI_TRUE)
|
||||||
|
7
client/Android/aFreeRDP/res/values-es/strings.xml
Normal file
7
client/Android/aFreeRDP/res/values-es/strings.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_title">aFreeRDP</string>
|
||||||
|
<!-- Search strings -->
|
||||||
|
<string name="search_label">aFreeRDP</string>
|
||||||
|
<string name="search_settings_description">Remote Computers</string>
|
||||||
|
</resources>
|
7
client/Android/aFreeRDP/res/values-nl/strings.xml
Normal file
7
client/Android/aFreeRDP/res/values-nl/strings.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_title">aFreeRDP</string>
|
||||||
|
<!-- Search strings -->
|
||||||
|
<string name="search_label">aFreeRDP</string>
|
||||||
|
<string name="search_settings_description">Remote Computers</string>
|
||||||
|
</resources>
|
@ -195,12 +195,13 @@ void xf_kbd_focus_in(xfInfo* xfi)
|
|||||||
Window wdummy;
|
Window wdummy;
|
||||||
UINT32 state = 0;
|
UINT32 state = 0;
|
||||||
|
|
||||||
input = xfi->instance->input;
|
if (xfi->display && xfi->window)
|
||||||
|
{
|
||||||
syncFlags = xf_kbd_get_toggle_keys_state(xfi);
|
input = xfi->instance->input;
|
||||||
XQueryPointer(xfi->display, xfi->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
|
syncFlags = xf_kbd_get_toggle_keys_state(xfi);
|
||||||
|
XQueryPointer(xfi->display, xfi->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
|
||||||
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
|
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL xf_kbd_handle_special_keys(xfInfo* xfi, KeySym keysym)
|
BOOL xf_kbd_handle_special_keys(xfInfo* xfi, KeySym keysym)
|
||||||
|
@ -126,6 +126,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
|||||||
{ "glyph-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "glyph cache" },
|
{ "glyph-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "glyph cache" },
|
||||||
{ "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "<rfx|nsc|jpeg>", NULL, NULL, -1, NULL, "bitmap codec cache" },
|
{ "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "<rfx|nsc|jpeg>", NULL, NULL, -1, NULL, "bitmap codec cache" },
|
||||||
{ "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "fast-path input/output" },
|
{ "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "fast-path input/output" },
|
||||||
|
{ "max-fast-path-size", COMMAND_LINE_VALUE_OPTIONAL, "<size>", NULL, NULL, -1, NULL, "maximum fast-path update size" },
|
||||||
{ "async-input", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous input" },
|
{ "async-input", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous input" },
|
||||||
{ "async-update", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous update" },
|
{ "async-update", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous update" },
|
||||||
{ "async-transport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous transport (unstable)" },
|
{ "async-transport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "asynchronous transport (unstable)" },
|
||||||
@ -1554,6 +1555,10 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
|
|||||||
settings->FastPathInput = arg->Value ? TRUE : FALSE;
|
settings->FastPathInput = arg->Value ? TRUE : FALSE;
|
||||||
settings->FastPathOutput = arg->Value ? TRUE : FALSE;
|
settings->FastPathOutput = arg->Value ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
CommandLineSwitchCase(arg, "max-fast-path-size")
|
||||||
|
{
|
||||||
|
settings->MultifragMaxRequestSize = atoi(arg->Value);
|
||||||
|
}
|
||||||
CommandLineSwitchCase(arg, "async-input")
|
CommandLineSwitchCase(arg, "async-input")
|
||||||
{
|
{
|
||||||
settings->AsyncInput = arg->Value ? TRUE : FALSE;
|
settings->AsyncInput = arg->Value ? TRUE : FALSE;
|
||||||
|
@ -138,11 +138,13 @@ ios_run_freerdp(freerdp * instance)
|
|||||||
void* wfds[32];
|
void* wfds[32];
|
||||||
fd_set rfds_set;
|
fd_set rfds_set;
|
||||||
fd_set wfds_set;
|
fd_set wfds_set;
|
||||||
|
struct timeval timeout;
|
||||||
|
int select_status;
|
||||||
|
|
||||||
memset(rfds, 0, sizeof(rfds));
|
memset(rfds, 0, sizeof(rfds));
|
||||||
memset(wfds, 0, sizeof(wfds));
|
memset(wfds, 0, sizeof(wfds));
|
||||||
|
|
||||||
while (1)
|
while (!freerdp_shall_disconnect(instance))
|
||||||
{
|
{
|
||||||
rcount = wcount = 0;
|
rcount = wcount = 0;
|
||||||
|
|
||||||
@ -179,11 +181,19 @@ ios_run_freerdp(freerdp * instance)
|
|||||||
|
|
||||||
FD_SET(fds, &rfds_set);
|
FD_SET(fds, &rfds_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_fds == 0)
|
if (max_fds == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout);
|
||||||
|
|
||||||
|
// timeout?
|
||||||
|
if (select_status == 0)
|
||||||
|
continue;
|
||||||
|
else if (select_status == -1)
|
||||||
{
|
{
|
||||||
/* these are not really errors */
|
/* these are not really errors */
|
||||||
if (!((errno == EAGAIN) ||
|
if (!((errno == EAGAIN) ||
|
||||||
@ -191,7 +201,7 @@ ios_run_freerdp(freerdp * instance)
|
|||||||
(errno == EINPROGRESS) ||
|
(errno == EINPROGRESS) ||
|
||||||
(errno == EINTR))) /* signal occurred */
|
(errno == EINTR))) /* signal occurred */
|
||||||
{
|
{
|
||||||
NSLog(@"%s: max_sck is zero.", __func__);
|
NSLog(@"%s: select failed!", __func__);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,7 @@
|
|||||||
|
|
||||||
if (CCKeyDerivationPBKDF != NULL)
|
if (CCKeyDerivationPBKDF != NULL)
|
||||||
{
|
{
|
||||||
int rounds = CCCalibratePBKDF(kCCPBKDF2, strlen(plaintext_password_data), TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, TSXEncryptorPBKDF2KeySize, 100);
|
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data)-1, (const uint8_t*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, TSXEncryptorPBKDF2Rounds, derived_key, TSXEncryptorPBKDF2KeySize);
|
||||||
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data)-1, (const uint8_t*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, rounds, derived_key, TSXEncryptorPBKDF2KeySize);
|
|
||||||
//NSLog(@"CCKeyDerivationPBKDF ret = %d; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
|
//NSLog(@"CCKeyDerivationPBKDF ret = %d; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -101,9 +101,12 @@ NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect"
|
|||||||
settings->FrameMarkerCommandEnabled = TRUE;
|
settings->FrameMarkerCommandEnabled = TRUE;
|
||||||
settings->FrameAcknowledge = 10;
|
settings->FrameAcknowledge = 10;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// enable NSCodec
|
{
|
||||||
settings->NSCodec = TRUE;
|
// enable NSCodec if remotefx is not used
|
||||||
|
settings->NSCodec = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
settings->BitmapCacheV3Enabled = TRUE;
|
settings->BitmapCacheV3Enabled = TRUE;
|
||||||
|
|
||||||
// Performance flags
|
// Performance flags
|
||||||
|
@ -54,10 +54,9 @@
|
|||||||
|
|
||||||
FREERDP_API BOOL ber_read_length(wStream* s, int* length);
|
FREERDP_API BOOL ber_read_length(wStream* s, int* length);
|
||||||
FREERDP_API int ber_write_length(wStream* s, int length);
|
FREERDP_API int ber_write_length(wStream* s, int length);
|
||||||
FREERDP_API int _ber_skip_length(int length);
|
FREERDP_API int _ber_sizeof_length(int length);
|
||||||
FREERDP_API int ber_get_content_length(int length);
|
|
||||||
FREERDP_API BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc);
|
FREERDP_API BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc);
|
||||||
FREERDP_API void ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc);
|
FREERDP_API int ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc);
|
||||||
FREERDP_API BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length);
|
FREERDP_API BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length);
|
||||||
FREERDP_API void ber_write_application_tag(wStream* s, BYTE tag, int length);
|
FREERDP_API void ber_write_application_tag(wStream* s, BYTE tag, int length);
|
||||||
FREERDP_API BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length);
|
FREERDP_API BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length);
|
||||||
@ -65,21 +64,21 @@ FREERDP_API BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count);
|
|||||||
FREERDP_API void ber_write_enumerated(wStream* s, BYTE enumerated, BYTE count);
|
FREERDP_API void ber_write_enumerated(wStream* s, BYTE enumerated, BYTE count);
|
||||||
FREERDP_API BOOL ber_read_contextual_tag(wStream* s, BYTE tag, int* length, BOOL pc);
|
FREERDP_API BOOL ber_read_contextual_tag(wStream* s, BYTE tag, int* length, BOOL pc);
|
||||||
FREERDP_API int ber_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc);
|
FREERDP_API int ber_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc);
|
||||||
FREERDP_API int ber_skip_contextual_tag(int length);
|
FREERDP_API int ber_sizeof_contextual_tag(int length);
|
||||||
FREERDP_API BOOL ber_read_sequence_tag(wStream* s, int* length);
|
FREERDP_API BOOL ber_read_sequence_tag(wStream* s, int* length);
|
||||||
FREERDP_API int ber_write_sequence_tag(wStream* s, int length);
|
FREERDP_API int ber_write_sequence_tag(wStream* s, int length);
|
||||||
FREERDP_API int ber_skip_sequence(int length);
|
FREERDP_API int ber_sizeof_sequence(int length);
|
||||||
FREERDP_API int ber_skip_sequence_tag(int length);
|
FREERDP_API int ber_sizeof_sequence_tag(int length);
|
||||||
FREERDP_API BOOL ber_read_bit_string(wStream* s, int* length, BYTE* padding);
|
FREERDP_API BOOL ber_read_bit_string(wStream* s, int* length, BYTE* padding);
|
||||||
FREERDP_API void ber_write_octet_string(wStream* s, const BYTE* oct_str, int length);
|
FREERDP_API int ber_write_octet_string(wStream* s, const BYTE* oct_str, int length);
|
||||||
FREERDP_API BOOL ber_read_octet_string_tag(wStream* s, int* length);
|
FREERDP_API BOOL ber_read_octet_string_tag(wStream* s, int* length);
|
||||||
FREERDP_API int ber_write_octet_string_tag(wStream* s, int length);
|
FREERDP_API int ber_write_octet_string_tag(wStream* s, int length);
|
||||||
FREERDP_API int ber_skip_octet_string(int length);
|
FREERDP_API int ber_sizeof_octet_string(int length);
|
||||||
FREERDP_API BOOL ber_read_BOOL(wStream* s, BOOL* value);
|
FREERDP_API BOOL ber_read_BOOL(wStream* s, BOOL* value);
|
||||||
FREERDP_API void ber_write_BOOL(wStream* s, BOOL value);
|
FREERDP_API void ber_write_BOOL(wStream* s, BOOL value);
|
||||||
FREERDP_API BOOL ber_read_integer(wStream* s, UINT32* value);
|
FREERDP_API BOOL ber_read_integer(wStream* s, UINT32* value);
|
||||||
FREERDP_API int ber_write_integer(wStream* s, UINT32 value);
|
FREERDP_API int ber_write_integer(wStream* s, UINT32 value);
|
||||||
FREERDP_API BOOL ber_read_integer_length(wStream* s, int* length);
|
FREERDP_API BOOL ber_read_integer_length(wStream* s, int* length);
|
||||||
FREERDP_API int ber_skip_integer(UINT32 value);
|
FREERDP_API int ber_sizeof_integer(UINT32 value);
|
||||||
|
|
||||||
#endif /* FREERDP_CRYPTO_BER_H */
|
#endif /* FREERDP_CRYPTO_BER_H */
|
||||||
|
@ -62,7 +62,7 @@ FREERDP_API int tls_wait_read(rdpTls* tls);
|
|||||||
FREERDP_API int tls_wait_write(rdpTls* tls);
|
FREERDP_API int tls_wait_write(rdpTls* tls);
|
||||||
|
|
||||||
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname);
|
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname);
|
||||||
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint);
|
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file);
|
||||||
FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count);
|
FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count);
|
||||||
|
|
||||||
FREERDP_API BOOL tls_print_error(char* func, SSL* connection, int value);
|
FREERDP_API BOOL tls_print_error(char* func, SSL* connection, int value);
|
||||||
|
@ -90,7 +90,15 @@ struct _audin_server_context
|
|||||||
psAudinServerReceiveSamples ReceiveSamples;
|
psAudinServerReceiveSamples ReceiveSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
FREERDP_API audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm);
|
FREERDP_API audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm);
|
||||||
FREERDP_API void audin_server_context_free(audin_server_context* context);
|
FREERDP_API void audin_server_context_free(audin_server_context* context);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_AUDIN_SERVER_H */
|
#endif /* FREERDP_CHANNEL_AUDIN_SERVER_H */
|
||||||
|
@ -91,7 +91,15 @@ struct _rdpsnd_server_context
|
|||||||
psRdpsndServerActivated Activated;
|
psRdpsndServerActivated Activated;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
FREERDP_API rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm);
|
FREERDP_API rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm);
|
||||||
FREERDP_API void rdpsnd_server_context_free(rdpsnd_server_context* context);
|
FREERDP_API void rdpsnd_server_context_free(rdpsnd_server_context* context);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPSND_SERVER_H */
|
#endif /* FREERDP_CHANNEL_RDPSND_SERVER_H */
|
||||||
|
@ -1177,7 +1177,7 @@ struct rdp_settings
|
|||||||
/* NSCodec */
|
/* NSCodec */
|
||||||
ALIGN64 BOOL NSCodec; /* 3712 */
|
ALIGN64 BOOL NSCodec; /* 3712 */
|
||||||
ALIGN64 UINT32 NSCodecId; /* 3713 */
|
ALIGN64 UINT32 NSCodecId; /* 3713 */
|
||||||
ALIGN64 BOOL FrameAcknowledge; /* 3714 */
|
ALIGN64 UINT32 FrameAcknowledge; /* 3714 */
|
||||||
UINT64 padding3776[3776 - 3715]; /* 3715 */
|
UINT64 padding3776[3776 - 3715]; /* 3715 */
|
||||||
|
|
||||||
/* JPEG */
|
/* JPEG */
|
||||||
|
@ -2196,6 +2196,8 @@ BOOL rdp_read_multifragment_update_capability_set(wStream* s, UINT16 length, rdp
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, multifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
|
Stream_Read_UINT32(s, multifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
|
||||||
|
if (settings->RemoteFxCodec && settings->MultifragMaxRequestSize < multifragMaxRequestSize)
|
||||||
|
settings->MultifragMaxRequestSize = multifragMaxRequestSize;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
#include "rpc_client.h"
|
#include "rpc_client.h"
|
||||||
|
|
||||||
|
#include "../rdp.h"
|
||||||
|
|
||||||
wStream* rpc_client_fragment_pool_take(rdpRpc* rpc)
|
wStream* rpc_client_fragment_pool_take(rdpRpc* rpc)
|
||||||
{
|
{
|
||||||
wStream* fragment = NULL;
|
wStream* fragment = NULL;
|
||||||
@ -156,6 +158,15 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc)
|
|||||||
if (StubLength == 4)
|
if (StubLength == 4)
|
||||||
{
|
{
|
||||||
//fprintf(stderr, "Ignoring TsProxySendToServer Response\n");
|
//fprintf(stderr, "Ignoring TsProxySendToServer Response\n");
|
||||||
|
printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id);
|
||||||
|
|
||||||
|
/* received a disconnect request from the server? */
|
||||||
|
if (header->common.call_id == rpc->PipeCallId && header->common.pfc_flags & PFC_LAST_FRAG)
|
||||||
|
{
|
||||||
|
((freerdp*)rpc->settings->instance)->context->rdp->disconnect = TRUE;
|
||||||
|
((freerdp*)rpc->settings->instance)->context->rdp->transport->tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
rpc_client_fragment_pool_return(rpc, fragment);
|
rpc_client_fragment_pool_return(rpc, fragment);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1371,8 +1371,14 @@ BOOL tsg_disconnect(rdpTsg* tsg)
|
|||||||
|
|
||||||
tsg->rpc->client->SynchronousReceive = TRUE;
|
tsg->rpc->client->SynchronousReceive = TRUE;
|
||||||
|
|
||||||
if (!TsProxyCloseChannel(tsg, NULL))
|
/* if we are already in state pending (i.e. if a server initiated disconnect was issued)
|
||||||
return FALSE;
|
we have to skip TsProxyCloseChannel - see Figure 13 in section 3.2.3
|
||||||
|
*/
|
||||||
|
if (tsg->state != TSG_STATE_TUNNEL_CLOSE_PENDING)
|
||||||
|
{
|
||||||
|
if (!TsProxyCloseChannel(tsg, NULL))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!TsProxyMakeTunnelCall(tsg, &tsg->TunnelContext, TSG_TUNNEL_CANCEL_ASYNC_MSG_REQUEST, NULL, NULL))
|
if (!TsProxyMakeTunnelCall(tsg, &tsg->TunnelContext, TSG_TUNNEL_CANCEL_ASYNC_MSG_REQUEST, NULL, NULL))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -240,6 +240,8 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings)
|
|||||||
Stream_Seek_UINT32(s); /* CodePage */
|
Stream_Seek_UINT32(s); /* CodePage */
|
||||||
Stream_Read_UINT32(s, flags); /* flags */
|
Stream_Read_UINT32(s, flags); /* flags */
|
||||||
|
|
||||||
|
settings->AudioCapture = ((flags & RNS_INFO_AUDIOCAPTURE) ? TRUE : FALSE);
|
||||||
|
settings->AudioPlayback = ((flags & INFO_NOAUDIOPLAYBACK) ? FALSE : TRUE);
|
||||||
settings->AutoLogonEnabled = ((flags & INFO_AUTOLOGON) ? TRUE : FALSE);
|
settings->AutoLogonEnabled = ((flags & INFO_AUTOLOGON) ? TRUE : FALSE);
|
||||||
settings->RemoteApplicationMode = ((flags & INFO_RAIL) ? TRUE : FALSE);
|
settings->RemoteApplicationMode = ((flags & INFO_RAIL) ? TRUE : FALSE);
|
||||||
settings->RemoteConsoleAudio = ((flags & INFO_REMOTECONSOLEAUDIO) ? TRUE : FALSE);
|
settings->RemoteConsoleAudio = ((flags & INFO_REMOTECONSOLEAUDIO) ? TRUE : FALSE);
|
||||||
|
@ -101,6 +101,9 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp);
|
|||||||
SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
|
SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
|
||||||
SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
|
SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
|
||||||
|
|
||||||
|
#define ber_sizeof_sequence_octet_string(length) ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)) + ber_sizeof_octet_string(length)
|
||||||
|
#define ber_write_sequence_octet_string(stream, context, value, length) ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE) + ber_write_octet_string(stream, value, length)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize NTLMSSP authentication module (client).
|
* Initialize NTLMSSP authentication module (client).
|
||||||
* @param credssp
|
* @param credssp
|
||||||
@ -112,7 +115,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
|
|||||||
int length;
|
int length;
|
||||||
freerdp* instance;
|
freerdp* instance;
|
||||||
rdpSettings* settings;
|
rdpSettings* settings;
|
||||||
|
|
||||||
settings = credssp->settings;
|
settings = credssp->settings;
|
||||||
instance = (freerdp*) settings->instance;
|
instance = (freerdp*) settings->instance;
|
||||||
|
|
||||||
@ -238,7 +241,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
|||||||
ZeroMemory(&output_buffer, sizeof(SecBuffer));
|
ZeroMemory(&output_buffer, sizeof(SecBuffer));
|
||||||
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* from tspkg.dll: 0x00000132
|
* from tspkg.dll: 0x00000132
|
||||||
* ISC_REQ_MUTUAL_AUTH
|
* ISC_REQ_MUTUAL_AUTH
|
||||||
* ISC_REQ_CONFIDENTIALITY
|
* ISC_REQ_CONFIDENTIALITY
|
||||||
@ -456,7 +459,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
|||||||
ZeroMemory(&output_buffer_desc, sizeof(SecBufferDesc));
|
ZeroMemory(&output_buffer_desc, sizeof(SecBufferDesc));
|
||||||
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* from tspkg.dll: 0x00000112
|
* from tspkg.dll: 0x00000112
|
||||||
* ASC_REQ_MUTUAL_AUTH
|
* ASC_REQ_MUTUAL_AUTH
|
||||||
* ASC_REQ_CONFIDENTIALITY
|
* ASC_REQ_CONFIDENTIALITY
|
||||||
@ -783,24 +786,24 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
|
|||||||
return SEC_E_OK;
|
return SEC_E_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_ts_password_creds(rdpCredssp* credssp)
|
int credssp_sizeof_ts_password_creds(rdpCredssp* credssp)
|
||||||
{
|
{
|
||||||
int length;
|
int length;
|
||||||
int ts_password_creds_length = 0;
|
int ts_password_creds_length = 0;
|
||||||
|
|
||||||
length = ber_skip_octet_string(credssp->identity.DomainLength * 2);
|
length = ber_sizeof_octet_string(credssp->identity.DomainLength * 2);
|
||||||
length += ber_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
ts_password_creds_length += length;
|
ts_password_creds_length += length;
|
||||||
|
|
||||||
length = ber_skip_octet_string(credssp->identity.UserLength * 2);
|
length = ber_sizeof_octet_string(credssp->identity.UserLength * 2);
|
||||||
length += ber_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
ts_password_creds_length += length;
|
ts_password_creds_length += length;
|
||||||
|
|
||||||
length = ber_skip_octet_string(credssp->identity.PasswordLength * 2);
|
length = ber_sizeof_octet_string(credssp->identity.PasswordLength * 2);
|
||||||
length += ber_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
ts_password_creds_length += length;
|
ts_password_creds_length += length;
|
||||||
|
|
||||||
length = ber_skip_sequence(ts_password_creds_length);
|
length = ber_sizeof_sequence(ts_password_creds_length);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -842,47 +845,41 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s)
|
|||||||
credssp->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
credssp->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void credssp_write_ts_password_creds(rdpCredssp* credssp, wStream* s)
|
int credssp_write_ts_password_creds(rdpCredssp* credssp, wStream* s)
|
||||||
{
|
{
|
||||||
int length;
|
int size = 0;
|
||||||
|
int innerSize = credssp_sizeof_ts_password_creds(credssp);
|
||||||
|
|
||||||
length = credssp_skip_ts_password_creds(credssp);
|
if (innerSize > Stream_GetRemainingLength(s))
|
||||||
|
{
|
||||||
|
printf("\033[91m[ ERROR ] Not enough space allocated for ts_password_creds\033[0m");
|
||||||
|
}
|
||||||
|
|
||||||
/* TSPasswordCreds (SEQUENCE) */
|
/* TSPasswordCreds (SEQUENCE) */
|
||||||
length = ber_get_content_length(length);
|
|
||||||
ber_write_sequence_tag(s, length);
|
size += ber_write_sequence_tag(s, innerSize);
|
||||||
|
|
||||||
/* [0] domainName (OCTET STRING) */
|
/* [0] domainName (OCTET STRING) */
|
||||||
ber_write_contextual_tag(s, 0, credssp->identity.DomainLength * 2 + 2, TRUE);
|
size += ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2);
|
||||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2);
|
|
||||||
|
|
||||||
/* [1] userName (OCTET STRING) */
|
/* [1] userName (OCTET STRING) */
|
||||||
ber_write_contextual_tag(s, 1, credssp->identity.UserLength * 2 + 2, TRUE);
|
size += ber_write_sequence_octet_string(s, 1, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2);
|
||||||
ber_write_octet_string(s, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2);
|
|
||||||
|
|
||||||
/* [2] password (OCTET STRING) */
|
/* [2] password (OCTET STRING) */
|
||||||
ber_write_contextual_tag(s, 2, credssp->identity.PasswordLength * 2 + 2, TRUE);
|
size += ber_write_sequence_octet_string(s, 2, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2);
|
||||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2);
|
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_ts_credentials(rdpCredssp* credssp)
|
int credssp_sizeof_ts_credentials(rdpCredssp* credssp)
|
||||||
{
|
{
|
||||||
int length;
|
int size = 0;
|
||||||
int ts_password_creds_length;
|
|
||||||
int ts_credentials_length = 0;
|
|
||||||
|
|
||||||
length = ber_skip_integer(0);
|
size += ber_sizeof_integer(1);
|
||||||
length += ber_skip_contextual_tag(length);
|
size += ber_sizeof_contextual_tag(ber_sizeof_integer(1));
|
||||||
ts_credentials_length += length;
|
size += ber_sizeof_sequence_octet_string(ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp)));
|
||||||
|
|
||||||
ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
|
return size;
|
||||||
length = ber_skip_octet_string(ts_password_creds_length);
|
|
||||||
length += ber_skip_contextual_tag(length);
|
|
||||||
ts_credentials_length += length;
|
|
||||||
|
|
||||||
length = ber_skip_sequence(ts_credentials_length);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
|
void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
|
||||||
@ -909,28 +906,28 @@ void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
|
|||||||
Stream_Free(s, FALSE);
|
Stream_Free(s, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void credssp_write_ts_credentials(rdpCredssp* credssp, wStream* s)
|
int credssp_write_ts_credentials(rdpCredssp* credssp, wStream* s)
|
||||||
{
|
{
|
||||||
int length;
|
int size = 0;
|
||||||
int ts_password_creds_length;
|
int innerSize = credssp_sizeof_ts_credentials(credssp);
|
||||||
|
int passwordSize;
|
||||||
length = credssp_skip_ts_credentials(credssp);
|
|
||||||
ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
|
|
||||||
|
|
||||||
/* TSCredentials (SEQUENCE) */
|
/* TSCredentials (SEQUENCE) */
|
||||||
length = ber_get_content_length(length);
|
size += ber_write_sequence_tag(s, innerSize);
|
||||||
length -= ber_write_sequence_tag(s, length);
|
|
||||||
|
|
||||||
/* [0] credType (INTEGER) */
|
/* [0] credType (INTEGER) */
|
||||||
length -= ber_write_contextual_tag(s, 0, 3, TRUE);
|
size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE);
|
||||||
length -= ber_write_integer(s, 1);
|
size += ber_write_integer(s, 1);
|
||||||
|
|
||||||
/* [1] credentials (OCTET STRING) */
|
/* [1] credentials (OCTET STRING) */
|
||||||
length -= 1;
|
|
||||||
length -= ber_write_contextual_tag(s, 1, length, TRUE);
|
|
||||||
length -= ber_write_octet_string_tag(s, ts_password_creds_length);
|
|
||||||
|
|
||||||
credssp_write_ts_password_creds(credssp, s);
|
passwordSize = ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp));
|
||||||
|
|
||||||
|
size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE);
|
||||||
|
size += ber_write_octet_string_tag(s, passwordSize);
|
||||||
|
size += credssp_write_ts_password_creds(credssp, s);
|
||||||
|
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -943,7 +940,7 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp)
|
|||||||
wStream* s;
|
wStream* s;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
length = credssp_skip_ts_credentials(credssp);
|
length = ber_sizeof_sequence(credssp_sizeof_ts_credentials(credssp));
|
||||||
sspi_SecBufferAlloc(&credssp->ts_credentials, length);
|
sspi_SecBufferAlloc(&credssp->ts_credentials, length);
|
||||||
|
|
||||||
s = Stream_New(credssp->ts_credentials.pvBuffer, length);
|
s = Stream_New(credssp->ts_credentials.pvBuffer, length);
|
||||||
@ -1029,41 +1026,40 @@ SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
|
|||||||
return SEC_E_OK;
|
return SEC_E_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_nego_token(int length)
|
int credssp_sizeof_nego_token(int length)
|
||||||
{
|
{
|
||||||
length = der_skip_octet_string(length);
|
length = ber_sizeof_octet_string(length);
|
||||||
length += der_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_nego_tokens(int length)
|
int credssp_sizeof_nego_tokens(int length)
|
||||||
{
|
{
|
||||||
length = credssp_skip_nego_token(length);
|
length = credssp_sizeof_nego_token(length);
|
||||||
length += der_skip_sequence_tag(length);
|
length += ber_sizeof_sequence_tag(length);
|
||||||
length += der_skip_sequence_tag(length);
|
length += ber_sizeof_sequence_tag(length);
|
||||||
length += der_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_pub_key_auth(int length)
|
int credssp_sizeof_pub_key_auth(int length)
|
||||||
{
|
{
|
||||||
length = ber_skip_octet_string(length);
|
length = ber_sizeof_octet_string(length);
|
||||||
length += ber_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_auth_info(int length)
|
int credssp_sizeof_auth_info(int length)
|
||||||
{
|
{
|
||||||
length = ber_skip_octet_string(length);
|
length = ber_sizeof_octet_string(length);
|
||||||
length += ber_skip_contextual_tag(length);
|
length += ber_sizeof_contextual_tag(length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int credssp_skip_ts_request(int length)
|
int credssp_sizeof_ts_request(int length)
|
||||||
{
|
{
|
||||||
length += ber_skip_integer(2);
|
length += ber_sizeof_integer(2);
|
||||||
length += ber_skip_contextual_tag(3);
|
length += ber_sizeof_contextual_tag(3);
|
||||||
length += der_skip_sequence_tag(length);
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,18 +1077,18 @@ void credssp_send(rdpCredssp* credssp)
|
|||||||
int pub_key_auth_length;
|
int pub_key_auth_length;
|
||||||
int auth_info_length;
|
int auth_info_length;
|
||||||
|
|
||||||
nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_skip_nego_tokens(credssp->negoToken.cbBuffer) : 0;
|
nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_sizeof_nego_tokens(credssp->negoToken.cbBuffer) : 0;
|
||||||
pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_skip_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
|
pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_sizeof_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
|
||||||
auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_skip_auth_info(credssp->authInfo.cbBuffer) : 0;
|
auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_sizeof_auth_info(credssp->authInfo.cbBuffer) : 0;
|
||||||
|
|
||||||
length = nego_tokens_length + pub_key_auth_length + auth_info_length;
|
length = nego_tokens_length + pub_key_auth_length + auth_info_length;
|
||||||
ts_request_length = credssp_skip_ts_request(length);
|
|
||||||
|
|
||||||
s = Stream_New(NULL, ts_request_length);
|
ts_request_length = credssp_sizeof_ts_request(length);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length));
|
||||||
|
|
||||||
/* TSRequest */
|
/* TSRequest */
|
||||||
length = der_get_content_length(ts_request_length);
|
ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */
|
||||||
der_write_sequence_tag(s, length); /* SEQUENCE */
|
|
||||||
|
|
||||||
/* [0] version */
|
/* [0] version */
|
||||||
ber_write_contextual_tag(s, 0, 3, TRUE);
|
ber_write_contextual_tag(s, 0, 3, TRUE);
|
||||||
@ -1102,27 +1098,25 @@ void credssp_send(rdpCredssp* credssp)
|
|||||||
if (nego_tokens_length > 0)
|
if (nego_tokens_length > 0)
|
||||||
{
|
{
|
||||||
length = nego_tokens_length;
|
length = nego_tokens_length;
|
||||||
length -= der_write_contextual_tag(s, 1, der_get_content_length(length), TRUE); /* NegoData */
|
|
||||||
length -= der_write_sequence_tag(s, der_get_content_length(length)); /* SEQUENCE OF NegoDataItem */
|
length -= ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */
|
||||||
length -= der_write_sequence_tag(s, der_get_content_length(length)); /* NegoDataItem */
|
length -= ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
|
||||||
length -= der_write_contextual_tag(s, 0, der_get_content_length(length), TRUE); /* [0] negoToken */
|
length -= ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */
|
||||||
der_write_octet_string(s, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
|
length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* [2] authInfo (OCTET STRING) */
|
/* [2] authInfo (OCTET STRING) */
|
||||||
if (auth_info_length > 0)
|
if (auth_info_length > 0)
|
||||||
{
|
{
|
||||||
length = auth_info_length;
|
length = auth_info_length;
|
||||||
length -= ber_write_contextual_tag(s, 2, ber_get_content_length(length), TRUE);
|
length -= ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
|
||||||
ber_write_octet_string(s, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* [3] pubKeyAuth (OCTET STRING) */
|
/* [3] pubKeyAuth (OCTET STRING) */
|
||||||
if (pub_key_auth_length > 0)
|
if (pub_key_auth_length > 0)
|
||||||
{
|
{
|
||||||
length = pub_key_auth_length;
|
length = pub_key_auth_length;
|
||||||
length -= ber_write_contextual_tag(s, 3, ber_get_content_length(length), TRUE);
|
length -= ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
|
||||||
ber_write_octet_string(s, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transport_write(credssp->transport, s);
|
transport_write(credssp->transport, s);
|
||||||
|
@ -120,6 +120,9 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, UINT16 port)
|
|||||||
UINT32 option_value;
|
UINT32 option_value;
|
||||||
socklen_t option_len;
|
socklen_t option_len;
|
||||||
|
|
||||||
|
if (hostname == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (hostname[0] == '/')
|
if (hostname[0] == '/')
|
||||||
{
|
{
|
||||||
tcp->sockfd = freerdp_uds_connect(hostname);
|
tcp->sockfd = freerdp_uds_connect(hostname);
|
||||||
|
@ -30,7 +30,7 @@ BOOL ber_read_length(wStream* s, int* length)
|
|||||||
{
|
{
|
||||||
BYTE byte;
|
BYTE byte;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ BOOL ber_read_length(wStream* s, int* length)
|
|||||||
{
|
{
|
||||||
byte &= ~(0x80);
|
byte &= ~(0x80);
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < byte)
|
if (Stream_GetRemainingLength(s) < byte)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (byte == 1)
|
if (byte == 1)
|
||||||
@ -63,33 +63,29 @@ BOOL ber_read_length(wStream* s, int* length)
|
|||||||
|
|
||||||
int ber_write_length(wStream* s, int length)
|
int ber_write_length(wStream* s, int length)
|
||||||
{
|
{
|
||||||
if (length > 0x7F)
|
if (length > 0xFF)
|
||||||
{
|
{
|
||||||
Stream_Write_UINT8(s, 0x82);
|
Stream_Write_UINT8(s, 0x80 ^ 2);
|
||||||
Stream_Write_UINT16_BE(s, length);
|
Stream_Write_UINT16_BE(s, length);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
else
|
if (length > 0x7F)
|
||||||
{
|
{
|
||||||
|
Stream_Write_UINT8(s, 0x80 ^ 1);
|
||||||
Stream_Write_UINT8(s, length);
|
Stream_Write_UINT8(s, length);
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
Stream_Write_UINT8(s, length);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _ber_skip_length(int length)
|
int _ber_sizeof_length(int length)
|
||||||
{
|
{
|
||||||
if (length > 0x80)
|
if (length > 0xFF)
|
||||||
return 3;
|
return 3;
|
||||||
else
|
if (length > 0x7F)
|
||||||
return 1;
|
return 2;
|
||||||
}
|
return 1;
|
||||||
|
|
||||||
int ber_get_content_length(int length)
|
|
||||||
{
|
|
||||||
if (length > 0x81)
|
|
||||||
return length - 4;
|
|
||||||
else
|
|
||||||
return length - 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,7 +99,7 @@ BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
|||||||
{
|
{
|
||||||
BYTE byte;
|
BYTE byte;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -120,9 +116,10 @@ BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
|||||||
* @param pc primitive (FALSE) or constructed (TRUE)
|
* @param pc primitive (FALSE) or constructed (TRUE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
int ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||||
{
|
{
|
||||||
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,14 +135,14 @@ BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length)
|
|||||||
|
|
||||||
if (tag > 30)
|
if (tag > 30)
|
||||||
{
|
{
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK))
|
if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -156,7 +153,7 @@ BOOL ber_read_application_tag(wStream* s, BYTE tag, int* length)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -195,7 +192,7 @@ BOOL ber_read_contextual_tag(wStream* s, BYTE tag, int* length, BOOL pc)
|
|||||||
{
|
{
|
||||||
BYTE byte;
|
BYTE byte;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -211,19 +208,19 @@ BOOL ber_read_contextual_tag(wStream* s, BYTE tag, int* length, BOOL pc)
|
|||||||
int ber_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc)
|
int ber_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc)
|
||||||
{
|
{
|
||||||
Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
||||||
return ber_write_length(s, length) + 1;
|
return 1 + ber_write_length(s, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ber_skip_contextual_tag(int length)
|
int ber_sizeof_contextual_tag(int length)
|
||||||
{
|
{
|
||||||
return _ber_skip_length(length) + 1;
|
return 1 + _ber_sizeof_length(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ber_read_sequence_tag(wStream* s, int* length)
|
BOOL ber_read_sequence_tag(wStream* s, int* length)
|
||||||
{
|
{
|
||||||
BYTE byte;
|
BYTE byte;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, byte);
|
Stream_Read_UINT8(s, byte);
|
||||||
|
|
||||||
@ -242,24 +239,24 @@ BOOL ber_read_sequence_tag(wStream* s, int* length)
|
|||||||
int ber_write_sequence_tag(wStream* s, int length)
|
int ber_write_sequence_tag(wStream* s, int length)
|
||||||
{
|
{
|
||||||
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
|
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
|
||||||
return ber_write_length(s, length) + 1;
|
return 1 + ber_write_length(s, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ber_skip_sequence(int length)
|
int ber_sizeof_sequence(int length)
|
||||||
{
|
{
|
||||||
return 1 + _ber_skip_length(length) + length;
|
return 1 + _ber_sizeof_length(length) + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ber_skip_sequence_tag(int length)
|
int ber_sizeof_sequence_tag(int length)
|
||||||
{
|
{
|
||||||
return 1 + _ber_skip_length(length);
|
return 1 + _ber_sizeof_length(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
|
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
|
||||||
{
|
{
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
if(!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) ||
|
if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) ||
|
||||||
!ber_read_length(s, &length))
|
!ber_read_length(s, &length))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -284,11 +281,11 @@ void ber_write_enumerated(wStream* s, BYTE enumerated, BYTE count)
|
|||||||
|
|
||||||
BOOL ber_read_bit_string(wStream* s, int* length, BYTE* padding)
|
BOOL ber_read_bit_string(wStream* s, int* length, BYTE* padding)
|
||||||
{
|
{
|
||||||
if(!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) ||
|
if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) ||
|
||||||
!ber_read_length(s, length))
|
!ber_read_length(s, length))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if(Stream_GetRemainingLength(s) < 1)
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
Stream_Read_UINT8(s, *padding);
|
Stream_Read_UINT8(s, *padding);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -301,11 +298,14 @@ BOOL ber_read_bit_string(wStream* s, int* length, BYTE* padding)
|
|||||||
* @param length string length
|
* @param length string length
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ber_write_octet_string(wStream* s, const BYTE* oct_str, int length)
|
int ber_write_octet_string(wStream* s, const BYTE* oct_str, int length)
|
||||||
{
|
{
|
||||||
ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
int size = 0;
|
||||||
ber_write_length(s, length);
|
size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
||||||
|
size += ber_write_length(s, length);
|
||||||
Stream_Write(s, oct_str, length);
|
Stream_Write(s, oct_str, length);
|
||||||
|
size += length;
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ber_read_octet_string_tag(wStream* s, int* length)
|
BOOL ber_read_octet_string_tag(wStream* s, int* length)
|
||||||
@ -319,12 +319,12 @@ int ber_write_octet_string_tag(wStream* s, int length)
|
|||||||
{
|
{
|
||||||
ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
||||||
ber_write_length(s, length);
|
ber_write_length(s, length);
|
||||||
return 1 + _ber_skip_length(length);
|
return 1 + _ber_sizeof_length(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ber_skip_octet_string(int length)
|
int ber_sizeof_octet_string(int length)
|
||||||
{
|
{
|
||||||
return 1 + _ber_skip_length(length) + length;
|
return 1 + _ber_sizeof_length(length) + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -421,48 +421,52 @@ int ber_write_integer(wStream* s, UINT32 value)
|
|||||||
{
|
{
|
||||||
ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
|
ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
|
||||||
|
|
||||||
if (value <= 0xFF)
|
if (value < 0x80)
|
||||||
{
|
{
|
||||||
ber_write_length(s, 1);
|
ber_write_length(s, 1);
|
||||||
Stream_Write_UINT8(s, value);
|
Stream_Write_UINT8(s, value);
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
else if (value < 0xFF80)
|
else if (value < 0x8000)
|
||||||
{
|
{
|
||||||
ber_write_length(s, 2);
|
ber_write_length(s, 2);
|
||||||
Stream_Write_UINT16_BE(s, value);
|
Stream_Write_UINT16_BE(s, value);
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
else if (value < 0xFF8000)
|
else if (value < 0x800000)
|
||||||
{
|
{
|
||||||
ber_write_length(s, 3);
|
ber_write_length(s, 3);
|
||||||
Stream_Write_UINT8(s, (value >> 16));
|
Stream_Write_UINT8(s, (value >> 16));
|
||||||
Stream_Write_UINT16_BE(s, (value & 0xFFFF));
|
Stream_Write_UINT16_BE(s, (value & 0xFFFF));
|
||||||
return 4;
|
return 5;
|
||||||
}
|
}
|
||||||
else if (value <= 0xFFFFFFFF)
|
else if (value < 0x80000000)
|
||||||
{
|
{
|
||||||
ber_write_length(s, 4);
|
ber_write_length(s, 4);
|
||||||
Stream_Write_UINT32_BE(s, value);
|
Stream_Write_UINT32_BE(s, value);
|
||||||
return 5;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ber_skip_integer(UINT32 value)
|
int ber_sizeof_integer(UINT32 value)
|
||||||
{
|
{
|
||||||
if (value <= 0xFF)
|
if (value < 0x80)
|
||||||
{
|
{
|
||||||
return _ber_skip_length(1) + 2;
|
return 3;
|
||||||
}
|
}
|
||||||
else if (value <= 0xFFFF)
|
else if (value < 0x8000)
|
||||||
{
|
{
|
||||||
return _ber_skip_length(2) + 3;
|
return 4;
|
||||||
}
|
}
|
||||||
else if (value <= 0xFFFFFFFF)
|
else if (value < 0x800000)
|
||||||
{
|
{
|
||||||
return _ber_skip_length(4) + 5;
|
return 5;
|
||||||
|
}
|
||||||
|
else if (value < 0x80000000)
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -603,7 +603,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
|||||||
else if (match == -1)
|
else if (match == -1)
|
||||||
{
|
{
|
||||||
/* entry was found in known_hosts file, but fingerprint does not match. ask user to use it */
|
/* entry was found in known_hosts file, but fingerprint does not match. ask user to use it */
|
||||||
tls_print_certificate_error(hostname, fingerprint);
|
tls_print_certificate_error(hostname, fingerprint, tls->certificate_store->file);
|
||||||
|
|
||||||
if (instance->VerifyChangedCertificate)
|
if (instance->VerifyChangedCertificate)
|
||||||
accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, "");
|
accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, "");
|
||||||
@ -644,7 +644,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
|||||||
return verification_status;
|
return verification_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tls_print_certificate_error(char* hostname, char* fingerprint)
|
void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "The host key for %s has changed\n", hostname);
|
fprintf(stderr, "The host key for %s has changed\n", hostname);
|
||||||
fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
||||||
@ -655,7 +655,7 @@ void tls_print_certificate_error(char* hostname, char* fingerprint)
|
|||||||
fprintf(stderr, "It is also possible that a host key has just been changed.\n");
|
fprintf(stderr, "It is also possible that a host key has just been changed.\n");
|
||||||
fprintf(stderr, "The fingerprint for the host key sent by the remote host is\n%s\n", fingerprint);
|
fprintf(stderr, "The fingerprint for the host key sent by the remote host is\n%s\n", fingerprint);
|
||||||
fprintf(stderr, "Please contact your system administrator.\n");
|
fprintf(stderr, "Please contact your system administrator.\n");
|
||||||
fprintf(stderr, "Add correct host key in ~/.freerdp/known_hosts to get rid of this message.\n");
|
fprintf(stderr, "Add correct host key in %s to get rid of this message.\n", hosts_file);
|
||||||
fprintf(stderr, "Host key for %s has changed and you have requested strict checking.\n", hostname);
|
fprintf(stderr, "Host key for %s has changed and you have requested strict checking.\n", hostname);
|
||||||
fprintf(stderr, "Host key verification failed.\n");
|
fprintf(stderr, "Host key verification failed.\n");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user