void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus) { struct stream *s; int bytes; if (IoStatus != NT_STATUS_SUCCESS) { FUSE_DATA *fuse_data = dev_redir_fuse_data_dequeue(irp); if (fuse_data) { xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); free(fuse_data); } devredir_irp_delete(irp); return; } xstream_new(s, 1024); irp->completion_type = CID_RMDIR_OR_FILE_RESP; devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_SET_INFORMATION, 0); xstream_wr_u32_le(s, FileDispositionInformation); xstream_wr_u32_le(s, 0); /* length is zero */ xstream_seek(s, 24); /* padding */ /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return; }
int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, tui32 DeviceId, tui32 FileId, tui32 CompletionId, tui32 MajorFunction, tui32 MinorFunc, int pad_len) { struct stream *s; int bytes; xstream_new(s, 1024); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, CompletionId, MajorFunction, MinorFunc); if (pad_len) xstream_seek(s, pad_len); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); log_debug("sent close request; expect CID_FILE_CLOSE"); return 0; }
int APP_CC dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, const char *buf, int Length, tui64 Offset) { struct stream *s; IRP *irp; IRP *new_irp; int bytes; log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld", DeviceId, FileId, Length, Offset); xstream_new(s, 1024 + Length); if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) { log_error("no IRP found with FileId = %d", FileId); xfuse_devredir_cb_write_file(fusep, NULL, 0); xstream_free(s); return -1; } /* create a new IRP for this request */ if ((new_irp = devredir_irp_clone(irp)) == NULL) { /* system out of memory */ xfuse_devredir_cb_write_file(fusep, NULL, 0); xstream_free(s); return -1; } new_irp->FileId = 0; new_irp->completion_type = CID_WRITE; new_irp->CompletionId = g_completion_id++; devredir_fuse_data_enqueue(new_irp, fusep); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, new_irp->CompletionId, IRP_MJ_WRITE, 0); xstream_wr_u32_le(s, Length); xstream_wr_u64_le(s, Offset); xstream_seek(s, 20); /* padding */ /* now insert real data */ xstream_copyin(s, buf, Length); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
/** * @brief process client's response to our core_capability_req() msg * * @param s stream containing client's response *****************************************************************************/ void dev_redir_proc_client_core_cap_resp(struct stream *s) { int i; tui16 num_caps; tui16 cap_type; tui16 cap_len; tui32 cap_version; char* holdp; xstream_rd_u16_le(s, num_caps); xstream_seek(s, 2); /* padding */ for (i = 0; i < num_caps; i++) { holdp = s->p; xstream_rd_u16_le(s, cap_type); xstream_rd_u16_le(s, cap_len); xstream_rd_u32_le(s, cap_version); switch (cap_type) { case CAP_GENERAL_TYPE: log_debug("got CAP_GENERAL_TYPE"); break; case CAP_PRINTER_TYPE: log_debug("got CAP_PRINTER_TYPE"); g_is_printer_redir_supported = 1; break; case CAP_PORT_TYPE: log_debug("got CAP_PORT_TYPE"); g_is_port_redir_supported = 1; break; case CAP_DRIVE_TYPE: log_debug("got CAP_DRIVE_TYPE"); g_is_drive_redir_supported = 1; if (cap_version == 2) { g_drive_redir_version = 2; } break; case CAP_SMARTCARD_TYPE: log_debug("got CAP_SMARTCARD_TYPE"); g_is_smartcard_redir_supported = 1; scard_init(); break; } s->p = holdp + cap_len; } }
int APP_CC devredir_file_read(void *fusep, tui32 DeviceId, tui32 FileId, tui32 Length, tui64 Offset) { struct stream *s; IRP *irp; IRP *new_irp; int bytes; xstream_new(s, 1024); if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) { log_error("no IRP found with FileId = %d", FileId); xfuse_devredir_cb_read_file(fusep, NULL, 0); xstream_free(s); return -1; } /* create a new IRP for this request */ if ((new_irp = devredir_irp_clone(irp)) == NULL) { /* system out of memory */ xfuse_devredir_cb_read_file(fusep, NULL, 0); xstream_free(s); return -1; } new_irp->FileId = 0; new_irp->completion_type = CID_READ; new_irp->CompletionId = g_completion_id++; devredir_fuse_data_enqueue(new_irp, fusep); devredir_insert_DeviceIoRequest(s, DeviceId, FileId, new_irp->CompletionId, IRP_MJ_READ, 0); xstream_wr_u32_le(s, Length); xstream_wr_u64_le(s, Offset); xstream_seek(s, 20); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
static struct stream * APP_CC scard_make_new_ioctl(IRP *irp, tui32 ioctl) { /* * format of device control request * * DeviceIoRequest * u16 RDPDR_CTYP_CORE * u16 PAKID_CORE_DEVICE_IOREQUEST * u32 DeviceId * u32 FileId * u32 CompletionId * u32 MajorFunction * u32 MinorFunction * * u32 OutputBufferLength SHOULD be 2048 * u32 InputBufferLength * u32 IoControlCode * 20 bytes padding * xx bytes InputBuffer (variable) */ struct stream *s; xstream_new(s, 1024 * 3); if (s == NULL) { log_error("system out of memory"); return s; } devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_DEVICE_CONTROL, 0); xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ xstream_seek(s, 20); /* padding */ /* [MS-RPCE] 2.2.6.1 */ xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ xstream_wr_u32_le(s, 0xcccccccc); /* filler */ return s; }
/** * @brief process client's repsonse to our core_capability_req() msg * * @param s stream containing client's response *****************************************************************************/ void dev_redir_proc_client_core_cap_resp(struct stream *s) { int i; tui16 num_caps; tui16 cap_type; tui16 cap_len; tui32 cap_version; xstream_rd_u16_le(s, num_caps); xstream_seek(s, 2); /* padding */ for (i = 0; i < num_caps; i++) { xstream_rd_u16_le(s, cap_type); xstream_rd_u16_le(s, cap_len); xstream_rd_u32_le(s, cap_version); /* remove header length and version */ cap_len -= 8; switch (cap_type) { case CAP_GENERAL_TYPE: log_debug("got CAP_GENERAL_TYPE"); xstream_seek(s, cap_len); break; case CAP_PRINTER_TYPE: log_debug("got CAP_PRINTER_TYPE"); g_is_printer_redir_supported = 1; xstream_seek(s, cap_len); break; case CAP_PORT_TYPE: log_debug("got CAP_PORT_TYPE"); g_is_port_redir_supported = 1; xstream_seek(s, cap_len); break; case CAP_DRIVE_TYPE: log_debug("got CAP_DRIVE_TYPE"); g_is_drive_redir_supported = 1; if (cap_version == 2) g_drive_redir_version = 2; xstream_seek(s, cap_len); break; case CAP_SMARTCARD_TYPE: log_debug("got CAP_SMARTCARD_TYPE"); g_is_smartcard_redir_supported = 1; xstream_seek(s, cap_len); break; } } }
int dev_redir_send_drive_create_request(tui32 device_id, const char *path, tui32 DesiredAccess, tui32 CreateOptions, tui32 CreateDisposition, tui32 completion_id) { struct stream *s; int bytes; int len; log_debug("DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", DesiredAccess, CreateDisposition, CreateOptions); /* path in unicode needs this much space */ len = ((g_mbstowcs(NULL, path, 0) * sizeof(twchar)) / 2) + 2; xstream_new(s, 1024 + len); devredir_insert_DeviceIoRequest(s, device_id, 0, completion_id, IRP_MJ_CREATE, 0); xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */ xstream_wr_u32_le(s, 0); /* AllocationSize high unused */ xstream_wr_u32_le(s, 0); /* AllocationSize low unused */ xstream_wr_u32_le(s, 0); /* FileAttributes */ xstream_wr_u32_le(s, 3); /* SharedAccess LK_TODO */ xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */ xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */ xstream_wr_u32_le(s, len); /* PathLength */ devredir_cvt_to_unicode(s->p, path); /* path in unicode */ xstream_seek(s, len); /* send to client */ bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); return 0; }
void dev_redir_proc_query_dir_response(IRP *irp, struct stream *s_in, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus) { FUSE_DATA *fuse_data = NULL; XRDP_INODE *xinode = NULL; tui32 Length; tui32 NextEntryOffset; tui64 CreationTime; tui64 LastAccessTime; tui64 LastWriteTime; tui64 ChangeTime; tui64 EndOfFile; tui32 FileAttributes; tui32 FileNameLength; tui32 status; #ifdef USE_SHORT_NAMES_IN_DIR_LISTING tui32 EaSize; tui8 ShortNameLength; tui8 Reserved; #endif char filename[256]; int i = 0; xstream_rd_u32_le(s_in, Length); if ((IoStatus == NT_STATUS_UNSUCCESSFUL) || (IoStatus == STATUS_NO_MORE_FILES)) { status = (IoStatus == STATUS_NO_MORE_FILES) ? 0 : IoStatus; fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, status); irp->completion_type = CID_CLOSE; dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, PAKID_CORE_DEVICE_IOREQUEST, DeviceId, irp->FileId, irp->CompletionId, IRP_MJ_CLOSE, 0, 32); free(fuse_data); return; } /* TODO check status for errors */ /* process FILE_DIRECTORY_INFORMATION structures */ while (i < Length) { log_debug("processing FILE_DIRECTORY_INFORMATION structs"); xstream_rd_u32_le(s_in, NextEntryOffset); xstream_seek(s_in, 4); /* FileIndex */ xstream_rd_u64_le(s_in, CreationTime); xstream_rd_u64_le(s_in, LastAccessTime); xstream_rd_u64_le(s_in, LastWriteTime); xstream_rd_u64_le(s_in, ChangeTime); xstream_rd_u64_le(s_in, EndOfFile); xstream_seek(s_in, 8); /* AllocationSize */ xstream_rd_u32_le(s_in, FileAttributes); xstream_rd_u32_le(s_in, FileNameLength); #ifdef USE_SHORT_NAMES_IN_DIR_LISTING xstream_rd_u32_le(s_in, EaSize); xstream_rd_u8(s_in, ShortNameLength); xstream_rd_u8(s_in, Reserved); xstream_seek(s_in, 23); /* ShortName in Unicode */ #endif devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength); #ifdef USE_SHORT_NAMES_IN_DIR_LISTING i += 70 + 23 + FileNameLength; #else i += 64 + FileNameLength; #endif //log_debug("NextEntryOffset: 0x%x", NextEntryOffset); //log_debug("CreationTime: 0x%llx", CreationTime); //log_debug("LastAccessTime: 0x%llx", LastAccessTime); //log_debug("LastWriteTime: 0x%llx", LastWriteTime); //log_debug("ChangeTime: 0x%llx", ChangeTime); //log_debug("EndOfFile: %lld", EndOfFile); //log_debug("FileAttributes: 0x%x", FileAttributes); #ifdef USE_SHORT_NAMES_IN_DIR_LISTING //log_debug("ShortNameLength: %d", ShortNameLength); #endif //log_debug("FileNameLength: %d", FileNameLength); log_debug("FileName: %s", filename); if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) { log_error("system out of memory"); fuse_data = dev_redir_fuse_data_peek(irp); xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, NULL); return; } strcpy(xinode->name, filename); xinode->size = (size_t) EndOfFile; xinode->mode = WINDOWS_TO_LINUX_FILE_PERM(FileAttributes); xinode->atime = WINDOWS_TO_LINUX_TIME(LastAccessTime); xinode->mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime); xinode->ctime = WINDOWS_TO_LINUX_TIME(CreationTime); /* add this entry to xrdp file system */ fuse_data = dev_redir_fuse_data_peek(irp); xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, xinode); } dev_redir_send_drive_dir_request(irp, DeviceId, 0, NULL); }
int APP_CC dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { struct stream *ls; tui16 comp_type; tui16 pktID; tui16 minor_ver; int rv = 0; /* * handle packet fragmentation */ if ((chan_flags & 3) == 3) { /* all data contained in one packet */ ls = s; } else { /* is this is the first packet? */ if (chan_flags & 1) xstream_new(g_input_stream, total_length); xstream_copyin(g_input_stream, s->p, length); /* in last packet, chan_flags & 0x02 will be true */ if ((chan_flags & 2) == 0) return 0; g_input_stream->p = g_input_stream->data; ls = g_input_stream; } /* read header from incoming data */ xstream_rd_u16_le(ls, comp_type); xstream_rd_u16_le(ls, pktID); /* for now we only handle core type, not printers */ if (comp_type != RDPDR_CTYP_CORE) { log_error("invalid component type in response; expected 0x%x got 0x%x", RDPDR_CTYP_CORE, comp_type); rv = -1; goto done; } /* figure out what kind of response we have gotten */ switch (pktID) { case PAKID_CORE_CLIENTID_CONFIRM: xstream_seek(ls, 2); /* major version, we ignore it */ xstream_rd_u16_le(ls, minor_ver); xstream_rd_u32_le(ls, g_clientID); g_client_rdp_version = minor_ver; switch (minor_ver) { case RDP_CLIENT_50: break; case RDP_CLIENT_51: break; case RDP_CLIENT_52: break; case RDP_CLIENT_60_61: break; } // LK_TODO dev_redir_send_server_clientID_confirm(); break; case PAKID_CORE_CLIENT_NAME: /* client is telling us its computer name; do we even care? */ /* let client know loggin was successful */ dev_redir_send_server_user_logged_on(); usleep(1000 * 100); /* let client know our capabilites */ dev_redir_send_server_core_cap_req(); /* send confirm clientID */ dev_redir_send_server_clientID_confirm(); break; case PAKID_CORE_CLIENT_CAPABILITY: dev_redir_proc_client_core_cap_resp(ls); break; case PAKID_CORE_DEVICELIST_ANNOUNCE: devredir_proc_client_devlist_announce_req(ls); break; case PAKID_CORE_DEVICE_IOCOMPLETION: dev_redir_proc_device_iocompletion(ls); break; default: log_error("got unknown response 0x%x", pktID); break; } done: if (g_input_stream) { xstream_free(g_input_stream); g_input_stream = NULL; } return rv; }
static void APP_CC scard_send_ListReaders(IRP *irp, int wide) { /* see [MS-RDPESC] 2.2.2.4 */ SMARTCARD *sc; struct stream *s; int bytes; tui32 ioctl; if ((sc = smartcards[irp->scard_index]) == NULL) { log_error("smartcards[%d] is NULL", irp->scard_index); return; } ioctl = (wide > 0) ? SCARD_IOCTL_LIST_READERS_W : SCARD_IOCTL_LIST_READERS_A; if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) return; xstream_wr_u32_le(s, 72); /* number of bytes to follow */ xstream_seek(s, 0x1c); /* freerdp does not use this */ /* insert context */ xstream_wr_u32_le(s, sc->Context_len); xstream_copyin(s, sc->Context, sc->Context_len); xstream_wr_u32_le(s, 36); /* length of mszGroups */ xstream_wr_u16_le(s, 0x0053); xstream_wr_u16_le(s, 0x0043); xstream_wr_u16_le(s, 0x0061); xstream_wr_u16_le(s, 0x0072); xstream_wr_u16_le(s, 0x0064); xstream_wr_u16_le(s, 0x0024); xstream_wr_u16_le(s, 0x0041); xstream_wr_u16_le(s, 0x006c); xstream_wr_u16_le(s, 0x006c); xstream_wr_u16_le(s, 0x0052); xstream_wr_u16_le(s, 0x0065); xstream_wr_u16_le(s, 0x0061); xstream_wr_u16_le(s, 0x0064); xstream_wr_u16_le(s, 0x0065); xstream_wr_u16_le(s, 0x0072); xstream_wr_u16_le(s, 0x0073); xstream_wr_u32_le(s, 0x00); /* get stream len */ bytes = xstream_len(s); /* InputBufferLength is number of bytes AFTER 20 byte padding */ *(s->data + 28) = bytes - 56; /* send to client */ send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); /* scard_device_control: dumping 120 bytes of data 0000 00 08 00 00 58 00 00 00 2c 00 09 00 00 00 00 00 ....X...,....... 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... 0030 04 00 00 00 00 00 02 00 24 00 00 00 04 00 02 00 ........$....... 0040 00 00 00 00 ff ff ff ff 04 00 00 00 84 db 03 01 ................ 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. 0070 72 00 73 00 00 00 00 00 r.s..... scard_device_control: output_len=2048 input_len=88 ioctl_code=0x9002c */ /* scard_device_control: dumping 120 bytes of data 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. 0070 72 00 73 00 00 00 00 00 r.s..... scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 */ }