rdpdr.c (6196B)
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/rdpdr/rdpdr.h" 21#include "channels/rdpdr/rdpdr-fs.h" 22#include "channels/rdpdr/rdpdr-messages.h" 23#include "channels/rdpdr/rdpdr-printer.h" 24#include "rdp.h" 25#include "settings.h" 26 27#include <freerdp/channels/rdpdr.h> 28#include <freerdp/freerdp.h> 29#include <freerdp/settings.h> 30#include <guacamole/client.h> 31#include <guacamole/mem.h> 32#include <winpr/stream.h> 33 34#include <stdlib.h> 35 36void guac_rdpdr_process_receive(guac_rdp_common_svc* svc, 37 wStream* input_stream) { 38 39 int component; 40 int packet_id; 41 42 /* 43 * Check that device redirection stream contains at least 4 bytes 44 * (UINT16 + UINT16). 45 */ 46 if (Stream_GetRemainingLength(input_stream) < 4) { 47 guac_client_log(svc->client, GUAC_LOG_WARNING, "Device redirection " 48 "channel PDU header does not contain the expected number of " 49 "bytes. Device redirection may not function as expected."); 50 return; 51 } 52 53 /* Read header */ 54 Stream_Read_UINT16(input_stream, component); 55 Stream_Read_UINT16(input_stream, packet_id); 56 57 /* Core component */ 58 if (component == RDPDR_CTYP_CORE) { 59 60 /* Dispatch handlers based on packet ID */ 61 switch (packet_id) { 62 63 case PAKID_CORE_SERVER_ANNOUNCE: 64 guac_rdpdr_process_server_announce(svc, input_stream); 65 break; 66 67 case PAKID_CORE_CLIENTID_CONFIRM: 68 guac_rdpdr_process_clientid_confirm(svc, input_stream); 69 break; 70 71 case PAKID_CORE_DEVICE_REPLY: 72 guac_rdpdr_process_device_reply(svc, input_stream); 73 break; 74 75 case PAKID_CORE_DEVICE_IOREQUEST: 76 guac_rdpdr_process_device_iorequest(svc, input_stream); 77 break; 78 79 case PAKID_CORE_SERVER_CAPABILITY: 80 guac_rdpdr_process_server_capability(svc, input_stream); 81 break; 82 83 case PAKID_CORE_USER_LOGGEDON: 84 guac_rdpdr_process_user_loggedon(svc, input_stream); 85 break; 86 87 default: 88 guac_client_log(svc->client, GUAC_LOG_DEBUG, "Ignoring " 89 "RDPDR core packet with unexpected ID: 0x%04x", 90 packet_id); 91 92 } 93 94 } /* end if core */ 95 96 /* Printer component */ 97 else if (component == RDPDR_CTYP_PRN) { 98 99 /* Dispatch handlers based on packet ID */ 100 switch (packet_id) { 101 102 case PAKID_PRN_CACHE_DATA: 103 guac_rdpdr_process_prn_cache_data(svc, input_stream); 104 break; 105 106 case PAKID_PRN_USING_XPS: 107 guac_rdpdr_process_prn_using_xps(svc, input_stream); 108 break; 109 110 default: 111 guac_client_log(svc->client, GUAC_LOG_DEBUG, "Ignoring RDPDR " 112 "printer packet with unexpected ID: 0x%04x", 113 packet_id); 114 115 } 116 117 } /* end if printer */ 118 119 else 120 guac_client_log(svc->client, GUAC_LOG_DEBUG, "Ignoring packet for " 121 "unknown RDPDR component: 0x%04x", component); 122 123} 124 125wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device, 126 int completion_id, int status, int size) { 127 128 wStream* output_stream = Stream_New(NULL, 16+size); 129 130 /* Write header */ 131 Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); 132 Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICE_IOCOMPLETION); 133 134 /* Write content */ 135 Stream_Write_UINT32(output_stream, device->device_id); 136 Stream_Write_UINT32(output_stream, completion_id); 137 Stream_Write_UINT32(output_stream, status); 138 139 return output_stream; 140 141} 142 143void guac_rdpdr_process_connect(guac_rdp_common_svc* svc) { 144 145 /* Get data from client */ 146 guac_client* client = svc->client; 147 guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 148 149 guac_rdpdr* rdpdr = (guac_rdpdr*) guac_mem_zalloc(sizeof(guac_rdpdr)); 150 svc->data = rdpdr; 151 152 /* Register printer if enabled */ 153 if (rdp_client->settings->printing_enabled) 154 guac_rdpdr_register_printer(svc, rdp_client->settings->printer_name); 155 156 /* Register drive if enabled */ 157 if (rdp_client->settings->drive_enabled) 158 guac_rdpdr_register_fs(svc, rdp_client->settings->drive_name); 159 160} 161 162void guac_rdpdr_process_terminate(guac_rdp_common_svc* svc) { 163 164 guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data; 165 if (rdpdr == NULL) 166 return; 167 168 int i; 169 170 for (i=0; i<rdpdr->devices_registered; i++) { 171 guac_rdpdr_device* device = &(rdpdr->devices[i]); 172 guac_client_log(svc->client, GUAC_LOG_DEBUG, "Unloading device %i " 173 "(%s)", device->device_id, device->device_name); 174 device->free_handler(svc, device); 175 } 176 177 guac_mem_free(svc->data); /* rdpdr */ 178 179} 180 181 182void guac_rdpdr_load_plugin(rdpContext* context) { 183 184 guac_client* client = ((rdp_freerdp_context*) context)->client; 185 186 /* Load support for RDPDR */ 187 if (guac_rdp_common_svc_load_plugin(context, "rdpdr", 188 CHANNEL_OPTION_COMPRESS_RDP, guac_rdpdr_process_connect, 189 guac_rdpdr_process_receive, guac_rdpdr_process_terminate)) { 190 guac_client_log(client, GUAC_LOG_WARNING, "Support for the RDPDR " 191 "channel (device redirection) could not be loaded. Drive " 192 "redirection and printing will not work. Sound MAY not work."); 193 } 194 195} 196