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