void APP_CC scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus) { tui32 len; int tmp; SMARTCARD *sc; log_debug("entered"); /* sanity check */ if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { log_error("DeviceId/CompletionId do not match those in IRP"); return; } if (IoStatus != 0) { log_error("failed to establish context - device not usable"); /* LK_TODO delete irp and smartcard entry */ return; } sc = smartcards[irp->scard_index]; /* get OutputBufferLen */ xstream_rd_u32_le(s, len); /* LK_TODO */ g_hexdump(s->p, len); xstream_rd_u32_le(s, tmp); /* should be len 8, LE, V1 */ xstream_rd_u32_le(s, tmp); /* marshalling flag */ xstream_rd_u32_le(s, tmp); /* ?? */ xstream_rd_u32_le(s, tmp); /* ?? */ xstream_rd_u32_le(s, tmp); /* ?? */ xstream_rd_u32_le(s, tmp); /* ?? */ xstream_rd_u32_le(s, tmp); /* ?? */ xstream_rd_u32_le(s, len); /* len of context in bytes */ sc->Context_len = len; xstream_copyout(sc->Context, s, len); if (LOG_LEVEL == LOG_DEBUG) { log_debug("dumping context (%d bytes)", sc->Context_len); g_hexdump(sc->Context, sc->Context_len); } irp->callback = scard_handle_ListReaders_Return; scard_send_ListReaders(irp, 1); /* LK_TODO need to delete IRP */ log_debug("leaving"); }
void APP_CC scard_handle_ListReaders_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus) { tui32 len; log_debug("entered"); /* sanity check */ if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { log_error("DeviceId/CompletionId do not match those in IRP"); return; } if (IoStatus != 0) { log_error("failed to list readers - device not usable"); /* LK_TODO delete irp and smartcard entry */ return; } /* get OutputBufferLen */ xstream_rd_u32_le(s, len); /* LK_TODO */ log_debug("dumping %d bytes", len); g_hexdump(s->p, len); log_debug("leaving"); }
/** * @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; } } }
/** * @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; } }
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); }
void dev_redir_proc_device_iocompletion(struct stream *s) { FUSE_DATA *fuse_data = NULL; IRP *irp = NULL; tui32 DeviceId; tui32 CompletionId; tui32 IoStatus; tui32 Length; xstream_rd_u32_le(s, DeviceId); xstream_rd_u32_le(s, CompletionId); xstream_rd_u32_le(s, IoStatus); /* LK_TODO need to check for IoStatus */ log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId); if ((irp = devredir_irp_find(CompletionId)) == NULL) { log_error("IRP with completion ID %d not found", CompletionId); return; } /* if callback has been set, call it */ if (irp->callback) { (*irp->callback)(s, irp, DeviceId, CompletionId, IoStatus); goto done; } switch (irp->completion_type) { case CID_CREATE_DIR_REQ: log_debug("got CID_CREATE_DIR_REQ"); if (IoStatus != NT_STATUS_SUCCESS) { /* we were trying to create a request to enumerate a dir */ /* that does not exist; let FUSE know */ fuse_data = dev_redir_fuse_data_dequeue(irp); if (fuse_data) { xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, IoStatus); free(fuse_data); } devredir_irp_delete(irp); return; } xstream_rd_u32_le(s, irp->FileId); log_debug("got CID_CREATE_DIR_REQ IoStatus=0x%x FileId=%d", IoStatus, irp->FileId); dev_redir_send_drive_dir_request(irp, DeviceId, 1, irp->pathname); break; case CID_CREATE_OPEN_REQ: xstream_rd_u32_le(s, irp->FileId); log_debug("got CID_CREATE_OPEN_REQ IoStatus=0x%x FileId=%d", IoStatus, irp->FileId); fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_open_file(fuse_data->data_ptr, DeviceId, irp->FileId); if (irp->type == S_IFDIR) devredir_irp_delete(irp); break; case CID_READ: log_debug("got CID_READ"); xstream_rd_u32_le(s, Length); fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length); break; case CID_WRITE: log_debug("got CID_WRITE"); xstream_rd_u32_le(s, Length); fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length); break; case CID_CLOSE: log_debug("got CID_CLOSE"); log_debug("deleting irp with completion_id=%d comp_type=%d", irp->CompletionId, irp->completion_type); devredir_irp_delete(irp); break; case CID_FILE_CLOSE: log_debug("got CID_FILE_CLOSE"); fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_file_close(fuse_data->data_ptr); devredir_irp_delete(irp); break; case CID_DIRECTORY_CONTROL: log_debug("got CID_DIRECTORY_CONTROL"); dev_redir_proc_query_dir_response(irp, s, DeviceId, CompletionId, IoStatus); break; case CID_RMDIR_OR_FILE: log_debug("got CID_RMDIR_OR_FILE"); xstream_rd_u32_le(s, irp->FileId); devredir_proc_cid_rmdir_or_file(irp, IoStatus); return; break; case CID_RMDIR_OR_FILE_RESP: log_debug("got CID_RMDIR_OR_FILE_RESP"); devredir_proc_cid_rmdir_or_file_resp(irp, IoStatus); break; case CID_RENAME_FILE: log_debug("got CID_RENAME_FILE"); xstream_rd_u32_le(s, irp->FileId); devredir_proc_cid_rename_file(irp, IoStatus); return; break; case CID_RENAME_FILE_RESP: log_debug("got CID_RENAME_FILE_RESP"); devredir_proc_cid_rename_file_resp(irp, IoStatus); break; default: log_error("got unknown CompletionID: DeviceId=0x%x " "CompletionId=0x%x IoStatus=0x%x", DeviceId, CompletionId, IoStatus); break; } done: if (fuse_data) free(fuse_data); log_debug("exiting"); }
void devredir_proc_client_devlist_announce_req(struct stream *s) { int i; int j; tui32 device_count; tui32 device_type; tui32 device_data_len; char preferred_dos_name[9]; /* get number of devices being announced */ xstream_rd_u32_le(s, device_count); log_debug("num of devices announced: %d", device_count); for (i = 0; i < device_count; i++) { xstream_rd_u32_le(s, device_type); xstream_rd_u32_le(s, g_device_id); switch (device_type) { case RDPDR_DTYP_FILESYSTEM: /* get preferred DOS name */ for (j = 0; j < 8; j++) { preferred_dos_name[j] = *s->p++; } /* DOS names that are 8 chars long are not NULL terminated */ preferred_dos_name[8] = 0; /* get device data len */ xstream_rd_u32_le(s, device_data_len); if (device_data_len) { xstream_rd_string(g_full_name_for_filesystem, s, device_data_len); } log_debug("device_type=FILE_SYSTEM device_id=0x%x dosname=%s " "device_data_len=%d full_name=%s", g_device_id, preferred_dos_name, device_data_len, g_full_name_for_filesystem); devredir_send_server_device_announce_resp(g_device_id); /* create share directory in xrdp file system; */ /* think of this as the mount point for this share */ xfuse_create_share(g_device_id, preferred_dos_name); break; case RDPDR_DTYP_SMARTCARD: /* get preferred DOS name */ for (j = 0; j < 8; j++) { preferred_dos_name[j] = *s->p++; } /* DOS names that are 8 chars long are not NULL terminated */ preferred_dos_name[8] = 0; /* for smart cards, device data len always 0 */ log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s " "device_data_len=%d", g_device_id, preferred_dos_name, device_data_len); devredir_send_server_device_announce_resp(g_device_id); scard_device_announce(g_device_id); break; /* we don't yet support these devices */ case RDPDR_DTYP_SERIAL: case RDPDR_DTYP_PARALLEL: case RDPDR_DTYP_PRINT: log_debug("unsupported dev: 0x%x", device_type); break; } } }
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; }