GUACAMOLE-221: Merge rely on FreeRDP error code if no RDP disconnect reason is available.

This commit is contained in:
Virtually Nick 2020-11-02 22:16:43 -05:00 committed by GitHub
commit 1e856d4e2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 122 additions and 17 deletions

View File

@ -18,14 +18,119 @@
*/ */
#include "error.h" #include "error.h"
#include "rdp.h"
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <winpr/wtypes.h>
void guac_rdp_client_abort(guac_client* client) { /**
* Translates the error code returned by freerdp_get_last_error() for the given
* RDP instance into a Guacamole status code and human-readable message. If no
* error was reported, a successful error code and message will be assigned.
*
* @param rdp_inst
* The FreeRDP client instance handling the RDP connection that failed.
*
* @param status
* Pointer to the variable that should receive the guac_protocol_status
* value equivalent to the error returned by freerdp_get_last_error().
*
* @param message
* Pointer to the variable that should receive a static human-readable
* message generally describing the error returned by
* freerdp_get_last_error().
*/
static void guac_rdp_translate_last_error(freerdp* rdp_inst,
guac_protocol_status* status, const char** message) {
UINT32 last_error = freerdp_get_last_error(rdp_inst->context);
switch (last_error) {
/* Normal disconnect */
case FREERDP_ERROR_NONE:
case FREERDP_ERROR_SUCCESS:
*status = GUAC_PROTOCOL_STATUS_SUCCESS;
*message = "Disconnected.";
break;
/* Account expired */
case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
case FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED:
case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
case FREERDP_ERROR_SERVER_FRESH_CREDENTIALS_REQUIRED:
*status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
*message = "Credentials expired.";
break;
/* Security negotiation failed */
case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
*status = GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED;
*message = "Security negotiation failed (wrong security type?)";
break;
/* Access denied */
case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
case FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED:
case FREERDP_ERROR_INSUFFICIENT_PRIVILEGES:
case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
*status = GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED;
*message = "Access denied by server (account locked/disabled?)";
break;
/* General, unspecified authentication failure */
case FREERDP_ERROR_AUTHENTICATION_FAILED:
case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
*status = GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED;
*message = "Authentication failure (invalid credentials?)";
break;
/* SSL/TLS connection failed */
case FREERDP_ERROR_TLS_CONNECT_FAILED:
*status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
*message = "SSL/TLS connection failed (untrusted/self-signed certificate?)";
break;
/* DNS lookup failed */
case FREERDP_ERROR_DNS_ERROR:
case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
*status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
*message = "DNS lookup failed (incorrect hostname?)";
break;
case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
*status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
*message = "Server refused connection (wrong security type?)";
break;
/* Connection failed */
case FREERDP_ERROR_CONNECT_CANCELLED:
case FREERDP_ERROR_CONNECT_FAILED:
case FREERDP_ERROR_CONNECT_KDC_UNREACHABLE:
case FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR:
*status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
*message = "Connection failed (server unreachable?)";
break;
/* All other errors */
default:
*status = GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR;
*message = "Upstream error.";
}
}
void guac_rdp_client_abort(guac_client* client, freerdp* rdp_inst) {
/* /*
* NOTE: The RDP status codes translated here are documented within * NOTE: The RDP status codes translated here are documented within
@ -35,9 +140,6 @@ void guac_rdp_client_abort(guac_client* client) {
* https://msdn.microsoft.com/en-us/library/cc240544.aspx * https://msdn.microsoft.com/en-us/library/cc240544.aspx
*/ */
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
freerdp* rdp_inst = rdp_client->rdp_inst;
guac_protocol_status status; guac_protocol_status status;
const char* message; const char* message;
@ -47,10 +149,9 @@ void guac_rdp_client_abort(guac_client* client) {
/* Translate reason code into Guacamole protocol status */ /* Translate reason code into Guacamole protocol status */
switch (error_info) { switch (error_info) {
/* Normal disconnect */ /* Possibly-normal disconnect, depending on freerdp_get_last_error() */
case 0x0: /* ERRINFO_SUCCESS */ case 0x0: /* ERRINFO_SUCCESS */
status = GUAC_PROTOCOL_STATUS_SUCCESS; guac_rdp_translate_last_error(rdp_inst, &status, &message);
message = "Disconnected.";
break; break;
/* Forced disconnect (possibly by admin) */ /* Forced disconnect (possibly by admin) */
@ -129,8 +230,8 @@ void guac_rdp_client_abort(guac_client* client) {
} }
/* Log human-readable description of disconnect at info level */ /* Log human-readable description of disconnect at info level */
guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection: %s", guac_client_log(client, GUAC_LOG_INFO, "RDP server closed/refused "
message); "connection: %s", message);
/* Log internal disconnect reason code at debug level */ /* Log internal disconnect reason code at debug level */
if (error_info) if (error_info)

View File

@ -20,17 +20,22 @@
#ifndef GUAC_RDP_ERROR_H #ifndef GUAC_RDP_ERROR_H
#define GUAC_RDP_ERROR_H #define GUAC_RDP_ERROR_H
#include <freerdp/freerdp.h>
#include <guacamole/client.h> #include <guacamole/client.h>
/** /**
* Stops the current connection due to the RDP server disconnecting. If the RDP * Stops the current connection due to the RDP server disconnecting or the
* server provided a reason for disconnecting, that reason will be logged, and * connection attempt failing. If the RDP server or FreeRDP provided a reason
* an appropriate error code will be sent to the Guacamole client. * for for the failure/disconnect, that reason will be logged, and an
* appropriate error code will be sent to the Guacamole client.
* *
* @param client * @param client
* The Guacamole client to disconnect. * The Guacamole client to disconnect.
*
* @param rdp_inst
* The FreeRDP client instance handling the RDP connection that failed.
*/ */
void guac_rdp_client_abort(guac_client* client); void guac_rdp_client_abort(guac_client* client, freerdp* rdp_inst);
#endif #endif

View File

@ -461,8 +461,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
/* Connect to RDP server */ /* Connect to RDP server */
if (!freerdp_connect(rdp_inst)) { if (!freerdp_connect(rdp_inst)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND, guac_rdp_client_abort(client, rdp_inst);
"Error connecting to RDP server");
goto fail; goto fail;
} }
@ -542,7 +541,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
/* Close connection cleanly if server is disconnecting */ /* Close connection cleanly if server is disconnecting */
if (connection_closing) if (connection_closing)
guac_rdp_client_abort(client); guac_rdp_client_abort(client, rdp_inst);
/* If a low-level connection error occurred, fail */ /* If a low-level connection error occurred, fail */
else if (wait_result < 0) else if (wait_result < 0)