cscg24-guacamole

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

download.c (7810B)


      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 "common/json.h"
     21#include "download.h"
     22#include "fs.h"
     23#include "ls.h"
     24#include "rdp.h"
     25
     26#include <guacamole/client.h>
     27#include <guacamole/mem.h>
     28#include <guacamole/object.h>
     29#include <guacamole/protocol.h>
     30#include <guacamole/socket.h>
     31#include <guacamole/stream.h>
     32#include <guacamole/string.h>
     33#include <guacamole/user.h>
     34#include <winpr/file.h>
     35#include <winpr/nt.h>
     36#include <winpr/shell.h>
     37
     38#include <stdlib.h>
     39
     40int guac_rdp_download_ack_handler(guac_user* user, guac_stream* stream,
     41        char* message, guac_protocol_status status) {
     42
     43    guac_client* client = user->client;
     44    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     45    guac_rdp_download_status* download_status = (guac_rdp_download_status*) stream->data;
     46
     47    /* Get filesystem, return error if no filesystem */
     48    guac_rdp_fs* fs = rdp_client->filesystem;
     49    if (fs == NULL) {
     50        guac_protocol_send_ack(user->socket, stream, "FAIL (NO FS)",
     51                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
     52        guac_socket_flush(user->socket);
     53        return 0;
     54    }
     55
     56    /* If successful, read data */
     57    if (status == GUAC_PROTOCOL_STATUS_SUCCESS) {
     58
     59        /* Attempt read into buffer */
     60        char buffer[4096];
     61        int bytes_read = guac_rdp_fs_read(fs,
     62                download_status->file_id,
     63                download_status->offset, buffer, sizeof(buffer));
     64
     65        /* If bytes read, send as blob */
     66        if (bytes_read > 0) {
     67            download_status->offset += bytes_read;
     68            guac_protocol_send_blob(user->socket, stream,
     69                    buffer, bytes_read);
     70        }
     71
     72        /* If EOF, send end */
     73        else if (bytes_read == 0) {
     74            guac_protocol_send_end(user->socket, stream);
     75            guac_user_free_stream(user, stream);
     76            guac_mem_free(download_status);
     77        }
     78
     79        /* Otherwise, fail stream */
     80        else {
     81            guac_user_log(user, GUAC_LOG_ERROR,
     82                    "Error reading file for download");
     83            guac_protocol_send_end(user->socket, stream);
     84            guac_user_free_stream(user, stream);
     85            guac_mem_free(download_status);
     86        }
     87
     88        guac_socket_flush(user->socket);
     89
     90    }
     91
     92    /* Otherwise, return stream to user */
     93    else
     94        guac_user_free_stream(user, stream);
     95
     96    return 0;
     97
     98}
     99
    100int guac_rdp_download_get_handler(guac_user* user, guac_object* object,
    101        char* name) {
    102
    103    guac_client* client = user->client;
    104    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
    105
    106    /* Get filesystem, ignore request if no filesystem */
    107    guac_rdp_fs* fs = rdp_client->filesystem;
    108    if (fs == NULL)
    109        return 0;
    110
    111    /* Attempt to open file for reading */
    112    int file_id = guac_rdp_fs_open(fs, name, GENERIC_READ, 0, FILE_OPEN, 0);
    113    if (file_id < 0) {
    114        guac_user_log(user, GUAC_LOG_INFO, "Unable to read file \"%s\"",
    115                name);
    116        return 0;
    117    }
    118
    119    /* Get opened file */
    120    guac_rdp_fs_file* file = guac_rdp_fs_get_file(fs, file_id);
    121    if (file == NULL) {
    122        guac_client_log(fs->client, GUAC_LOG_DEBUG,
    123                "%s: Successful open produced bad file_id: %i",
    124                __func__, file_id);
    125        return 0;
    126    }
    127
    128    /* If directory, send contents of directory */
    129    if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) {
    130
    131        /* Create stream data */
    132        guac_rdp_ls_status* ls_status = guac_mem_alloc(sizeof(guac_rdp_ls_status));
    133        ls_status->fs = fs;
    134        ls_status->file_id = file_id;
    135        guac_strlcpy(ls_status->directory_name, name,
    136                sizeof(ls_status->directory_name));
    137
    138        /* Allocate stream for body */
    139        guac_stream* stream = guac_user_alloc_stream(user);
    140        stream->ack_handler = guac_rdp_ls_ack_handler;
    141        stream->data = ls_status;
    142
    143        /* Init JSON object state */
    144        guac_common_json_begin_object(user, stream,
    145                &ls_status->json_state);
    146
    147        /* Associate new stream with get request */
    148        guac_protocol_send_body(user->socket, object, stream,
    149                GUAC_USER_STREAM_INDEX_MIMETYPE, name);
    150
    151    }
    152
    153    /* Otherwise, send file contents if downloads are allowed */
    154    else if (!fs->disable_download) {
    155
    156        /* Create stream data */
    157        guac_rdp_download_status* download_status = guac_mem_alloc(sizeof(guac_rdp_download_status));
    158        download_status->file_id = file_id;
    159        download_status->offset = 0;
    160
    161        /* Allocate stream for body */
    162        guac_stream* stream = guac_user_alloc_stream(user);
    163        stream->data = download_status;
    164        stream->ack_handler = guac_rdp_download_ack_handler;
    165
    166        /* Associate new stream with get request */
    167        guac_protocol_send_body(user->socket, object, stream,
    168                "application/octet-stream", name);
    169
    170    }
    171
    172    else
    173        guac_client_log(client, GUAC_LOG_INFO, "Unable to download file "
    174                "\"%s\", file downloads have been disabled.", name);
    175
    176    guac_socket_flush(user->socket);
    177    return 0;
    178}
    179
    180void* guac_rdp_download_to_user(guac_user* user, void* data) {
    181
    182    /* Do not bother attempting the download if the user has left */
    183    if (user == NULL)
    184        return NULL;
    185
    186    guac_client* client = user->client;
    187    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
    188    guac_rdp_fs* filesystem = rdp_client->filesystem;
    189
    190    /* Ignore download if filesystem has been unloaded */
    191    if (filesystem == NULL)
    192        return NULL;
    193
    194    /* Ignore download if downloads have been disabled */
    195    if (filesystem->disable_download) {
    196        guac_client_log(client, GUAC_LOG_WARNING, "A download attempt has "
    197                "been blocked due to downloads being disabled, however it "
    198                "should have been blocked at a higher level. This is likely "
    199                "a bug.");
    200        return NULL;
    201    }
    202
    203    /* Attempt to open requested file */
    204    char* path = (char*) data;
    205    int file_id = guac_rdp_fs_open(filesystem, path,
    206            FILE_READ_DATA, 0, FILE_OPEN, 0);
    207
    208    /* If file opened successfully, start stream */
    209    if (file_id >= 0) {
    210
    211        /* Associate stream with transfer status */
    212        guac_stream* stream = guac_user_alloc_stream(user);
    213        guac_rdp_download_status* download_status = guac_mem_alloc(sizeof(guac_rdp_download_status));
    214        stream->data = download_status;
    215        stream->ack_handler = guac_rdp_download_ack_handler;
    216        download_status->file_id = file_id;
    217        download_status->offset = 0;
    218
    219        guac_user_log(user, GUAC_LOG_DEBUG, "%s: Initiating download "
    220                "of \"%s\"", __func__, path);
    221
    222        /* Begin stream */
    223        guac_protocol_send_file(user->socket, stream,
    224                "application/octet-stream", guac_rdp_fs_basename(path));
    225        guac_socket_flush(user->socket);
    226
    227        /* Download started successfully */
    228        return stream;
    229
    230    }
    231
    232    /* Download failed */
    233    guac_user_log(user, GUAC_LOG_ERROR, "Unable to download \"%s\"", path);
    234    return NULL;
    235
    236}
    237