cscg24-guacamole

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

pipe-svc.c (7395B)


      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 "channels/common-svc.h"
     21#include "channels/pipe-svc.h"
     22#include "common/list.h"
     23#include "rdp.h"
     24
     25#include <freerdp/settings.h>
     26#include <guacamole/client.h>
     27#include <guacamole/mem.h>
     28#include <guacamole/protocol.h>
     29#include <guacamole/socket.h>
     30#include <guacamole/stream.h>
     31#include <guacamole/user.h>
     32#include <winpr/stream.h>
     33
     34#include <stdlib.h>
     35#include <string.h>
     36
     37void guac_rdp_pipe_svc_send_pipe(guac_socket* socket, guac_rdp_pipe_svc* pipe_svc) {
     38
     39    /* Send pipe instruction for the SVC's output stream */
     40    guac_protocol_send_pipe(socket, pipe_svc->output_pipe,
     41            "application/octet-stream", pipe_svc->svc->name);
     42
     43}
     44
     45
     46void guac_rdp_pipe_svc_send_pipes(
     47        guac_client* client, guac_socket* socket) {
     48
     49    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     50
     51    guac_common_list_lock(rdp_client->available_svc);
     52
     53    /* Send pipe for each allocated SVC's output stream */
     54    guac_common_list_element* current = rdp_client->available_svc->head;
     55    while (current != NULL) {
     56        guac_rdp_pipe_svc_send_pipe(socket, (guac_rdp_pipe_svc*) current->data);
     57        current = current->next;
     58    }
     59
     60    guac_common_list_unlock(rdp_client->available_svc);
     61}
     62
     63void guac_rdp_pipe_svc_add(guac_client* client, guac_rdp_pipe_svc* pipe_svc) {
     64
     65    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     66
     67    /* Add to list of available SVC */
     68    guac_common_list_lock(rdp_client->available_svc);
     69    guac_common_list_add(rdp_client->available_svc, pipe_svc);
     70    guac_common_list_unlock(rdp_client->available_svc);
     71
     72}
     73
     74guac_rdp_pipe_svc* guac_rdp_pipe_svc_get(guac_client* client, const char* name) {
     75
     76    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     77    guac_common_list_element* current;
     78    guac_rdp_pipe_svc* found = NULL;
     79
     80    /* For each available SVC */
     81    guac_common_list_lock(rdp_client->available_svc);
     82    current = rdp_client->available_svc->head;
     83    while (current != NULL) {
     84
     85        /* If name matches, found */
     86        guac_rdp_pipe_svc* current_svc = (guac_rdp_pipe_svc*) current->data;
     87        if (strcmp(current_svc->svc->name, name) == 0) {
     88            found = current_svc;
     89            break;
     90        }
     91
     92        current = current->next;
     93
     94    }
     95    guac_common_list_unlock(rdp_client->available_svc);
     96
     97    return found;
     98
     99}
    100
    101guac_rdp_pipe_svc* guac_rdp_pipe_svc_remove(guac_client* client, const char* name) {
    102
    103    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
    104    guac_common_list_element* current;
    105    guac_rdp_pipe_svc* found = NULL;
    106
    107    /* For each available SVC */
    108    guac_common_list_lock(rdp_client->available_svc);
    109    current = rdp_client->available_svc->head;
    110    while (current != NULL) {
    111
    112        /* If name matches, remove entry */
    113        guac_rdp_pipe_svc* current_svc = (guac_rdp_pipe_svc*) current->data;
    114        if (strcmp(current_svc->svc->name, name) == 0) {
    115            guac_common_list_remove(rdp_client->available_svc, current);
    116            found = current_svc;
    117            break;
    118        }
    119
    120        current = current->next;
    121
    122    }
    123    guac_common_list_unlock(rdp_client->available_svc);
    124
    125    /* Return removed entry, if any */
    126    return found;
    127
    128}
    129
    130int guac_rdp_pipe_svc_pipe_handler(guac_user* user, guac_stream* stream,
    131        char* mimetype, char* name) {
    132
    133    guac_rdp_pipe_svc* pipe_svc = guac_rdp_pipe_svc_get(user->client, name);
    134
    135    /* Fail if no such SVC */
    136    if (pipe_svc == NULL) {
    137        guac_user_log(user, GUAC_LOG_WARNING, "User requested non-existent "
    138                "pipe (no such SVC configured): \"%s\"", name);
    139        guac_protocol_send_ack(user->socket, stream, "FAIL (NO SUCH PIPE)",
    140                GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
    141        guac_socket_flush(user->socket);
    142        return 0;
    143    }
    144    else
    145        guac_user_log(user, GUAC_LOG_DEBUG, "Inbound half of channel \"%s\" "
    146                "connected.", name);
    147
    148    /* Init stream data */
    149    stream->data = pipe_svc;
    150    stream->blob_handler = guac_rdp_pipe_svc_blob_handler;
    151
    152    return 0;
    153
    154}
    155
    156int guac_rdp_pipe_svc_blob_handler(guac_user* user, guac_stream* stream,
    157        void* data, int length) {
    158
    159    guac_rdp_pipe_svc* pipe_svc = (guac_rdp_pipe_svc*) stream->data;
    160
    161    /* Write blob data to SVC directly */
    162    wStream* output_stream = Stream_New(NULL, length);
    163    Stream_Write(output_stream, data, length);
    164    guac_rdp_common_svc_write(pipe_svc->svc, output_stream);
    165
    166    guac_protocol_send_ack(user->socket, stream, "OK (DATA RECEIVED)",
    167            GUAC_PROTOCOL_STATUS_SUCCESS);
    168    guac_socket_flush(user->socket);
    169    return 0;
    170
    171}
    172
    173void guac_rdp_pipe_svc_process_connect(guac_rdp_common_svc* svc) {
    174
    175    /* Associate SVC with new Guacamole pipe */
    176    guac_rdp_pipe_svc* pipe_svc = guac_mem_alloc(sizeof(guac_rdp_pipe_svc));
    177    pipe_svc->svc = svc;
    178    pipe_svc->output_pipe = guac_client_alloc_stream(svc->client);
    179    svc->data = pipe_svc;
    180
    181    /* SVC may now receive data from client */
    182    guac_rdp_pipe_svc_add(svc->client, pipe_svc);
    183
    184    /* Notify of pipe's existence */
    185    guac_rdp_pipe_svc_send_pipe(svc->client->socket, pipe_svc);
    186
    187}
    188
    189void guac_rdp_pipe_svc_process_receive(guac_rdp_common_svc* svc,
    190        wStream* input_stream) {
    191
    192    guac_rdp_pipe_svc* pipe_svc = (guac_rdp_pipe_svc*) svc->data;
    193
    194    /* Fail if output not created */
    195    if (pipe_svc->output_pipe == NULL) {
    196        guac_client_log(svc->client, GUAC_LOG_WARNING, "%i bytes of data "
    197                "received from within the remote desktop session for SVC "
    198                "\"%s\" are being dropped because the outbound pipe stream "
    199                "for that SVC is not yet open. This should NOT happen.",
    200                Stream_Length(input_stream), svc->name);
    201        return;
    202    }
    203
    204    /* Send received data as blob */
    205    guac_protocol_send_blob(svc->client->socket, pipe_svc->output_pipe, Stream_Buffer(input_stream), Stream_Length(input_stream));
    206    guac_socket_flush(svc->client->socket);
    207
    208}
    209
    210void guac_rdp_pipe_svc_process_terminate(guac_rdp_common_svc* svc) {
    211
    212    guac_rdp_pipe_svc* pipe_svc = (guac_rdp_pipe_svc*) svc->data;
    213    if (pipe_svc == NULL)
    214        return;
    215
    216    /* Remove and free SVC */
    217    guac_rdp_pipe_svc_remove(svc->client, svc->name);
    218    guac_mem_free(pipe_svc);
    219
    220}
    221
    222void guac_rdp_pipe_svc_load_plugin(rdpContext* context, char* name) {
    223
    224    /* Attempt to load support for static channel */
    225    guac_rdp_common_svc_load_plugin(context, name, CHANNEL_OPTION_COMPRESS_RDP,
    226            guac_rdp_pipe_svc_process_connect,
    227            guac_rdp_pipe_svc_process_receive,
    228            guac_rdp_pipe_svc_process_terminate);
    229
    230}
    231