From 1ffbd774e95cebb8d5da89a65b4cf092fea369f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 21 Jul 2016 17:53:20 -0400 Subject: [PATCH] freerdp: fix sending of TLS alert on NLA failure, add better handling of server-side NLA in shadow server --- include/freerdp/server/shadow.h | 1 + libfreerdp/core/connection.c | 4 +- libfreerdp/core/peer.c | 5 ++ libfreerdp/core/transport.c | 1 + libfreerdp/crypto/tls.c | 3 +- server/shadow/shadow.c | 10 ++- server/shadow/shadow_client.c | 72 ++++++++++++++++++--- server/shadow/shadow_server.c | 76 ++++++++++++++++++++++- winpr/libwinpr/sspi/Negotiate/negotiate.c | 2 +- 9 files changed, 156 insertions(+), 18 deletions(-) diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index 49bd0564a..60bb87d79 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -110,6 +110,7 @@ struct rdp_shadow_server HANDLE thread; HANDLE StopEvent; wArrayList* clients; + rdpSettings* settings; rdpShadowScreen* screen; rdpShadowSurface* surface; rdpShadowSurface* lobby; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index f66e1817b..3d6cd4ab9 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -1044,12 +1044,12 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) { if (settings->NlaSecurity && !settings->TlsSecurity) { - WLog_ERR(TAG, "server supports only NLA Security"); + WLog_WARN(TAG, "server supports only NLA Security"); nego->SelectedProtocol |= HYBRID_REQUIRED_BY_SERVER; } else { - WLog_ERR(TAG, "server supports only a SSL based Security (TLS or NLA)"); + WLog_WARN(TAG, "server supports only a SSL based Security (TLS or NLA)"); nego->SelectedProtocol |= SSL_REQUIRED_BY_SERVER; } } diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 8318c4d8d..6462d4678 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -476,6 +476,10 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) return -1; } + client->settings->NlaSecurity = (rdp->nego->SelectedProtocol & PROTOCOL_NLA) ? TRUE : FALSE; + client->settings->TlsSecurity = (rdp->nego->SelectedProtocol & PROTOCOL_TLS) ? TRUE : FALSE; + client->settings->RdpSecurity = (rdp->nego->SelectedProtocol & PROTOCOL_RDP) ? TRUE : FALSE; + if (rdp->nego->SelectedProtocol & PROTOCOL_NLA) { sspi_CopyAuthIdentity(&client->identity, rdp->nego->transport->nla->identity); @@ -686,6 +690,7 @@ BOOL freerdp_peer_context_new(freerdp_peer* client) context->peer = client; context->ServerMode = TRUE; + context->settings = client->settings; if (!(context->metrics = metrics_new(context))) goto fail_metrics; diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 147913f82..26563e779 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -363,6 +363,7 @@ BOOL transport_accept_nla(rdpTransport* transport) nla_free(transport->nla); transport->nla = NULL; tls_set_alert_code(transport->tls, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED); + tls_send_alert(transport->tls); return FALSE; } diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index e02577d6e..1dfc7c487 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -1011,10 +1011,10 @@ BOOL tls_send_alert(rdpTls* tls) if (tls->ssl->s3->wbuf.left == 0) tls->ssl->method->ssl_dispatch_alert(tls->ssl); } + return TRUE; } - BIO *findBufferedBio(BIO *front) { BIO *ret = front; @@ -1067,7 +1067,6 @@ int tls_set_alert_code(rdpTls* tls, int level, int description) { tls->alertLevel = level; tls->alertDescription = description; - return 0; } diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c index bc985192e..734f3a5ec 100644 --- a/server/shadow/shadow.c +++ b/server/shadow/shadow.c @@ -42,6 +42,7 @@ int main(int argc, char** argv) MSG msg; int status = 0; DWORD dwExitCode; + rdpSettings* settings; rdpShadowServer* server; shadow_subsystem_set_entry_builtin(NULL); @@ -54,6 +55,12 @@ int main(int argc, char** argv) goto fail_server_new; } + settings = server->settings; + + settings->NlaSecurity = FALSE; + settings->TlsSecurity = TRUE; + settings->RdpSecurity = TRUE; + #ifdef WITH_SHADOW_X11 server->authentication = TRUE; #else @@ -86,8 +93,7 @@ int main(int argc, char** argv) if (!GetExitCodeThread(server->thread, &dwExitCode)) status = -1; else - status = (int)dwExitCode; - + status = (int) dwExitCode; fail_server_start: shadow_server_uninit(server); diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 9c48579ff..1cc23c9b0 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -70,10 +70,6 @@ BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6; - settings->RdpSecurity = TRUE; - settings->TlsSecurity = TRUE; - settings->NlaSecurity = FALSE; - if (!(settings->CertificateFile = _strdup(server->CertificateFile))) goto fail_cert_file; if (!(settings->PrivateKeyFile = _strdup(server->PrivateKeyFile))) @@ -146,7 +142,7 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) WTSCloseServer((HANDLE) client->vcm); - /* Clear queued messages and free resource */ + /* Clear queued messages and free resource */ MessageQueue_Clear(client->MsgQueue); MessageQueue_Free(client->MsgQueue); @@ -250,17 +246,14 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) if (settings->Username && settings->Password) settings->AutoLogonEnabled = TRUE; - if (server->authentication) + if (server->authentication && !settings->NlaSecurity) { if (subsystem->Authenticate) { authStatus = subsystem->Authenticate(subsystem, client, settings->Username, settings->Domain, settings->Password); } - } - if (server->authentication) - { if (authStatus < 0) { WLog_ERR(TAG, "client authentication failure: %d", authStatus); @@ -385,6 +378,64 @@ BOOL shadow_client_activate(freerdp_peer* peer) return shadow_client_refresh_rect(client, 0, NULL); } +BOOL shadow_client_logon(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic) +{ + char* user = NULL; + char* domain = NULL; + char* password = NULL; + rdpSettings* settings = peer->settings; + + if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) + { + if (identity->User) + ConvertFromUnicode(CP_UTF8, 0, identity->User, identity->UserLength, &user, 0, NULL, NULL); + + if (identity->Domain) + ConvertFromUnicode(CP_UTF8, 0, identity->Domain, identity->DomainLength, &domain, 0, NULL, NULL); + + if (identity->Password) + ConvertFromUnicode(CP_UTF8, 0, identity->Password, identity->PasswordLength, &user, 0, NULL, NULL); + } + else + { + if (identity->User) + user = _strdup((char*) identity->User); + + if (identity->Domain) + domain = _strdup((char*) identity->Domain); + + if (identity->Password) + password = _strdup((char*) identity->Password); + } + + if (user) + { + free(settings->Username); + settings->Username = user; + user = NULL; + } + + if (domain) + { + free(settings->Domain); + settings->Domain = domain; + user = NULL; + } + + if (password) + { + free(settings->Password); + settings->Password = password; + password = NULL; + } + + free(user); + free(domain); + free(password); + + return TRUE; +} + BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) { /* @@ -993,6 +1044,7 @@ void* shadow_client_thread(rdpShadowClient* client) peer->Capabilities = shadow_client_capabilities; peer->PostConnect = shadow_client_post_connect; peer->Activate = shadow_client_activate; + peer->Logon = shadow_client_logon; shadow_input_register_callbacks(peer->input); @@ -1199,6 +1251,8 @@ BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer) peer->ContextNew = (psPeerContextNew) shadow_client_context_new; peer->ContextFree = (psPeerContextFree) shadow_client_context_free; + peer->settings = freerdp_settings_clone(server->settings); + if (!freerdp_peer_context_new(peer)) return FALSE; diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index 4e979a02a..7f6a6e2f8 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -50,6 +50,11 @@ static COMMAND_LINE_ARGUMENT_A shadow_args[] = { "auth", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Clients must authenticate" }, { "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" }, { "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" }, + { "sec", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "force specific protocol security" }, + { "sec-rdp", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "rdp protocol security" }, + { "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "tls protocol security" }, + { "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "nla protocol security" }, + { "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "nla extended protocol security" }, { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" }, { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -149,6 +154,7 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; + rdpSettings* settings = server->settings; if (argc < 2) return 1; @@ -253,6 +259,58 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a { server->authentication = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "sec") + { + if (strcmp("rdp", arg->Value) == 0) /* Standard RDP */ + { + settings->RdpSecurity = TRUE; + settings->TlsSecurity = FALSE; + settings->NlaSecurity = FALSE; + settings->ExtSecurity = FALSE; + settings->UseRdpSecurityLayer = TRUE; + } + else if (strcmp("tls", arg->Value) == 0) /* TLS */ + { + settings->RdpSecurity = FALSE; + settings->TlsSecurity = TRUE; + settings->NlaSecurity = FALSE; + settings->ExtSecurity = FALSE; + } + else if (strcmp("nla", arg->Value) == 0) /* NLA */ + { + settings->RdpSecurity = FALSE; + settings->TlsSecurity = FALSE; + settings->NlaSecurity = TRUE; + settings->ExtSecurity = FALSE; + } + else if (strcmp("ext", arg->Value) == 0) /* NLA Extended */ + { + settings->RdpSecurity = FALSE; + settings->TlsSecurity = FALSE; + settings->NlaSecurity = FALSE; + settings->ExtSecurity = TRUE; + } + else + { + WLog_ERR(TAG, "unknown protocol security: %s", arg->Value); + } + } + CommandLineSwitchCase(arg, "sec-rdp") + { + settings->RdpSecurity = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "sec-tls") + { + settings->TlsSecurity = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "sec-nla") + { + settings->NlaSecurity = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "sec-ext") + { + settings->ExtSecurity = arg->Value ? TRUE : FALSE; + } CommandLineSwitchDefault(arg) { @@ -708,6 +766,11 @@ rdpShadowServer* shadow_server_new() server->authentication = FALSE; + server->settings = freerdp_settings_new(FREERDP_SETTINGS_SERVER_MODE); + + if (!server) + return NULL; + return server; } @@ -716,8 +779,17 @@ void shadow_server_free(rdpShadowServer* server) if (!server) return; - free(server->ipcSocket); - server->ipcSocket = NULL; + if (server->ipcSocket) + { + free(server->ipcSocket); + server->ipcSocket = NULL; + } + + if (server->settings) + { + freerdp_settings_free(server->settings); + server->settings = NULL; + } free(server); } diff --git a/winpr/libwinpr/sspi/Negotiate/negotiate.c b/winpr/libwinpr/sspi/Negotiate/negotiate.c index 4af1cbca6..c6b7b8150 100644 --- a/winpr/libwinpr/sspi/Negotiate/negotiate.c +++ b/winpr/libwinpr/sspi/Negotiate/negotiate.c @@ -28,7 +28,7 @@ #include "../sspi.h" #include "../log.h" -#define TAG WINPR_TAG("negociate") +#define TAG WINPR_TAG("negotiate") extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA; extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW;