cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

error.c (10920B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "error.h"
     21
     22#include <freerdp/freerdp.h>
     23#include <guacamole/client.h>
     24#include <guacamole/protocol.h>
     25#include <guacamole/socket.h>
     26#include <winpr/wtypes.h>
     27
     28/**
     29 * Translates the error code returned by freerdp_get_last_error() for the given
     30 * RDP instance into a Guacamole status code and human-readable message. If no
     31 * error was reported, a successful error code and message will be assigned.
     32 *
     33 * @param rdp_inst
     34 *     The FreeRDP client instance handling the RDP connection that failed.
     35 *
     36 * @param status
     37 *     Pointer to the variable that should receive the guac_protocol_status
     38 *     value equivalent to the error returned by freerdp_get_last_error().
     39 *
     40 * @param message
     41 *     Pointer to the variable that should receive a static human-readable
     42 *     message generally describing the error returned by
     43 *     freerdp_get_last_error().
     44 */
     45static void guac_rdp_translate_last_error(freerdp* rdp_inst,
     46        guac_protocol_status* status, const char** message) {
     47
     48    UINT32 last_error = freerdp_get_last_error(rdp_inst->context);
     49    switch (last_error) {
     50
     51        /*
     52         * Normal disconnect (no error at all)
     53         */
     54
     55        case FREERDP_ERROR_NONE:
     56        case FREERDP_ERROR_SUCCESS:
     57            *status = GUAC_PROTOCOL_STATUS_SUCCESS;
     58            *message = "Disconnected.";
     59            break;
     60
     61        /*
     62         * General credentials expired (password has expired, password must be
     63         * reset before it can be used for the first time, etc.)
     64         */
     65
     66#ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
     67        case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
     68#endif
     69
     70#ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
     71        case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
     72#endif
     73
     74        case FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED:
     75        case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
     76        case FREERDP_ERROR_SERVER_FRESH_CREDENTIALS_REQUIRED:
     77            *status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
     78            *message = "Credentials expired.";
     79            break;
     80
     81        /*
     82         * Security negotiation failed (the server is refusing the connection
     83         * because the security negotiation process failed)
     84         */
     85
     86        case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
     87            *status = GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED;
     88            *message = "Security negotiation failed (wrong security type?)";
     89            break;
     90
     91        /*
     92         * General access denied/revoked (regardless of any credentials
     93         * provided, the server is denying the requested access by this
     94         * account)
     95         */
     96
     97#ifdef FREERDP_ERROR_CONNECT_ACCESS_DENIED
     98        case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
     99#endif
    100
    101#ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
    102        case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
    103#endif
    104
    105#ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
    106        case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
    107#endif
    108
    109#ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
    110        case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
    111#endif
    112
    113#ifdef FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED
    114        case FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED:
    115#endif
    116
    117        case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
    118        case FREERDP_ERROR_INSUFFICIENT_PRIVILEGES:
    119        case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
    120        case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
    121            *status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
    122            *message = "Access denied by server (account locked/disabled?)";
    123            break;
    124
    125        /*
    126         * General authentication failure (no credentials provided or wrong
    127         * credentials provided)
    128         */
    129
    130#ifdef FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS
    131        case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
    132#endif
    133
    134#ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
    135        case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
    136#endif
    137
    138#ifdef FREERDP_ERROR_CONNECT_WRONG_PASSWORD
    139        case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
    140#endif
    141
    142        case FREERDP_ERROR_AUTHENTICATION_FAILED:
    143            *status = GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED;
    144            *message = "Authentication failure (invalid credentials?)";
    145            break;
    146
    147        /*
    148         * SSL/TLS connection failed (the server's certificate is not trusted)
    149         */
    150
    151        case FREERDP_ERROR_TLS_CONNECT_FAILED:
    152            *status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
    153            *message = "SSL/TLS connection failed (untrusted/self-signed certificate?)";
    154            break;
    155
    156        /*
    157         * DNS lookup failed (hostname resolution failed or invalid IP address)
    158         */
    159
    160        case FREERDP_ERROR_DNS_ERROR:
    161        case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
    162            *status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
    163            *message = "DNS lookup failed (incorrect hostname?)";
    164            break;
    165
    166        /*
    167         * Connection refused (the server is outright refusing to handle the
    168         * inbound connection, typically due to the client requesting a
    169         * security type that is not allowed)
    170         */
    171
    172        case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
    173            *status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
    174            *message = "Server refused connection (wrong security type?)";
    175            break;
    176
    177        /*
    178         * Connection failed (the network connection to the server did not
    179         * succeed)
    180         */
    181
    182        case FREERDP_ERROR_CONNECT_CANCELLED:
    183        case FREERDP_ERROR_CONNECT_FAILED:
    184        case FREERDP_ERROR_CONNECT_KDC_UNREACHABLE:
    185        case FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR:
    186            *status = GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND;
    187            *message = "Connection failed (server unreachable?)";
    188            break;
    189
    190        /*
    191         * All other (unknown) errors
    192         */
    193        default:
    194            *status = GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR;
    195            *message = "Upstream error.";
    196
    197    }
    198
    199}
    200
    201void guac_rdp_client_abort(guac_client* client, freerdp* rdp_inst) {
    202
    203    /*
    204     * NOTE: The RDP status codes translated here are documented within
    205     * [MS-RDPBCGR], section 2.2.5.1.1: "Set Error Info PDU Data", in the
    206     * description of the "errorInfo" field.
    207     *
    208     * https://msdn.microsoft.com/en-us/library/cc240544.aspx
    209     */
    210
    211    guac_protocol_status status;
    212    const char* message;
    213
    214    /* Read disconnect reason code from connection */
    215    int error_info = freerdp_error_info(rdp_inst);
    216
    217    /* Translate reason code into Guacamole protocol status */
    218    switch (error_info) {
    219
    220        /* Possibly-normal disconnect, depending on freerdp_get_last_error() */
    221        case 0x0: /* ERRINFO_SUCCESS */
    222            guac_rdp_translate_last_error(rdp_inst, &status, &message);
    223            break;
    224
    225        /* Forced disconnect (possibly by admin) */
    226        case 0x1: /* ERRINFO_RPC_INITIATED_DISCONNECT */
    227            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
    228            message = "Forcibly disconnected.";
    229            break;
    230
    231        /* The user was logged off (possibly by admin) */
    232        case 0x2: /* ERRINFO_RPC_INITIATED_LOGOFF */
    233            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
    234            message = "Logged off.";
    235            break;
    236
    237        /* The user was idle long enough that the RDP server disconnected */
    238        case 0x3: /* ERRINFO_IDLE_TIMEOUT */
    239            status = GUAC_PROTOCOL_STATUS_SESSION_TIMEOUT;
    240            message = "Idle session time limit exceeded.";
    241            break;
    242
    243        /* The user's session has been active for too long */
    244        case 0x4: /* ERRINFO_LOGON_TIMEOUT */
    245            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
    246            message = "Active session time limit exceeded.";
    247            break;
    248
    249        /* Another user logged on, disconnecting this user */
    250        case 0x5: /* ERRINFO_DISCONNECTED_BY_OTHER_CONNECTION */
    251            status = GUAC_PROTOCOL_STATUS_SESSION_CONFLICT;
    252            message = "Disconnected by other connection.";
    253            break;
    254
    255        /* The RDP server is refusing to service the connection */
    256        case 0x6: /* ERRINFO_OUT_OF_MEMORY */
    257        case 0x7: /* ERRINFO_SERVER_DENIED_CONNECTION */
    258            status = GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE;
    259            message = "Server refused connection.";
    260            break;
    261
    262        /* The user does not have permission to connect */
    263        case 0x9: /* ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES */
    264            status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
    265            message = "Insufficient privileges.";
    266            break;
    267
    268        /* The user's credentials have expired */
    269        case 0xA: /* ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED */
    270            status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
    271            message = "Credentials expired.";
    272            break;
    273
    274        /* The user manually disconnected using an administrative tool within
    275         * the session */
    276        case 0xB: /* ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER */
    277            status = GUAC_PROTOCOL_STATUS_SUCCESS;
    278            message = "Manually disconnected.";
    279            break;
    280
    281        /* The user manually logged off */
    282        case 0xC: /* ERRINFO_LOGOFF_BY_USER */
    283            status = GUAC_PROTOCOL_STATUS_SUCCESS;
    284            message = "Manually logged off.";
    285            break;
    286
    287        /* Unimplemented/unknown disconnect reason code */
    288        default:
    289            status = GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR;
    290            message = "Upstream error.";
    291
    292    }
    293
    294    /* Send error code if an error occurred */
    295    if (status != GUAC_PROTOCOL_STATUS_SUCCESS) {
    296        guac_protocol_send_error(client->socket, message, status);
    297        guac_socket_flush(client->socket);
    298    }
    299
    300    /* Log human-readable description of disconnect at info level */
    301    guac_client_log(client, GUAC_LOG_INFO, "RDP server closed/refused "
    302            "connection: %s", message);
    303
    304    /* Log internal disconnect reason code at debug level */
    305    if (error_info)
    306        guac_client_log(client, GUAC_LOG_DEBUG, "Disconnect reason "
    307                "code: 0x%X.", error_info);
    308
    309    /* Abort connection */
    310    guac_client_stop(client);
    311
    312}
    313