static BOOL TestStream_Seek(void) { BOOL rc = FALSE; wStream* s = Stream_New(NULL, 100); if (!s) goto out; if (s->pointer != s->buffer) goto out; Stream_Seek(s, 5); if (s->pointer != s->buffer + 5) goto out; Stream_Seek_UINT8(s); if (s->pointer != s->buffer + 6) goto out; Stream_Seek_UINT16(s); if (s->pointer != s->buffer + 8) goto out; Stream_Seek_UINT32(s); if (s->pointer != s->buffer + 12) goto out; Stream_Seek_UINT64(s); if (s->pointer != s->buffer + 20) goto out; rc = TRUE; out: Stream_Free(s, TRUE); return rc; }
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; mode_t m; UINT64 size; int status; char* fullpath; struct STAT st; struct timeval tv[2]; UINT64 LastWriteTime; UINT32 FileAttributes; UINT32 FileNameLength; m = 0; switch (FsInformationClass) { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ Stream_Seek_UINT64(input); /* CreationTime */ Stream_Seek_UINT64(input); /* LastAccessTime */ Stream_Read_UINT64(input, LastWriteTime); Stream_Seek_UINT64(input); /* ChangeTime */ Stream_Read_UINT32(input, FileAttributes); if (FSTAT(file->fd, &st) != 0) return FALSE; tv[0].tv_sec = st.st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); tv[1].tv_usec = 0; #ifndef WIN32 /* TODO on win32 */ #ifdef ANDROID utimes(file->fullpath, tv); #else futimes(file->fd, tv); #endif if (FileAttributes > 0) { m = st.st_mode; if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) m |= S_IWUSR; else m &= ~S_IWUSR; if (m != st.st_mode) fchmod(file->fd, m); } #endif break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ Stream_Read_UINT64(input, size); if (ftruncate(file->fd, size) != 0) return FALSE; break; case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ if (Length) Stream_Read_UINT8(input, file->delete_pending); else file->delete_pending = 1; if (file->delete_pending && file->is_dir) { /* mstsc causes this to FAIL if the directory is not empty, * and that's what the server is expecting. If we wait for * the close to flag a failure, cut and paste of a folder * will lose the folder's contents. */ int status; status = rmdir(file->fullpath); if (status == 0) { /* Put it back so the normal pending delete will work. */ mkdir(file->fullpath, 0755); } else { return FALSE; } } break; case FileRenameInformation: /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */ Stream_Seek_UINT8(input); /* ReplaceIfExists */ Stream_Seek_UINT8(input); /* RootDirectory */ Stream_Read_UINT32(input, FileNameLength); status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input), FileNameLength / 2, &s, 0, NULL, NULL); if (status < 1) s = (char*) calloc(1, 1); fullpath = drive_file_combine_fullpath(file->basepath, s); free(s); /* TODO rename does not work on win32 */ if (rename(file->fullpath, fullpath) == 0) { DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath); drive_file_set_fullpath(file, fullpath); } else { DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno); free(fullpath); return FALSE; } break; default: DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass); return FALSE; } return TRUE; }
static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { DWORD DesiredAccess; DWORD SharedAccess; DWORD CreateDisposition; UINT32 PathLength; if (Stream_GetRemainingLength(irp->input) < 32) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */ Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */ Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ if (Stream_GetRemainingLength(irp->input) < PathLength) return ERROR_INVALID_DATA; Stream_Seek(irp->input, PathLength); /* Path (variable) */ assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ #ifndef _WIN32 /* Windows 2012 server sends on a first call : * DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW * * then Windows 2012 sends : * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW * * assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); * assert(SharedAccess == 0); * assert(CreateDisposition == OPEN_EXISTING); * */ WLog_Print(serial->log, WLOG_DEBUG, "DesiredAccess: 0x%"PRIX32", SharedAccess: 0x%"PRIX32", CreateDisposition: 0x%"PRIX32"", DesiredAccess, SharedAccess, CreateDisposition); /* FIXME: As of today only the flags below are supported by CommCreateFileA: */ DesiredAccess = GENERIC_READ | GENERIC_WRITE; SharedAccess = 0; CreateDisposition = OPEN_EXISTING; #endif serial->hComm = CreateFile(serial->device.name, DesiredAccess, SharedAccess, NULL, /* SecurityAttributes */ CreateDisposition, 0, /* FlagsAndAttributes */ NULL); /* TemplateFile */ if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: 0x%08"PRIX32"", serial->device.name, GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; goto error_handle; } _comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId); _comm_set_permissive(serial->hComm, serial->permissive); /* NOTE: binary mode/raw mode required for the redirection. On * Linux, CommCreateFileA forces this setting. */ /* ZeroMemory(&dcb, sizeof(DCB)); */ /* dcb.DCBlength = sizeof(DCB); */ /* GetCommState(serial->hComm, &dcb); */ /* dcb.fBinary = TRUE; */ /* SetCommState(serial->hComm, &dcb); */ assert(irp->FileId == 0); irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ irp->IoStatus = STATUS_SUCCESS; WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %"PRIu32", FileId: %"PRIu32") created.", serial->device.name, irp->device->id, irp->FileId); error_handle: Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ return CHANNEL_RC_OK; }
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; mode_t m; UINT64 size; int status; char* fullpath; struct STAT st; #if defined(__linux__) && !defined(ANDROID) || defined(sun) struct timespec tv[2]; #else struct timeval tv[2]; #endif UINT64 LastWriteTime; UINT32 FileAttributes; UINT32 FileNameLength; m = 0; switch (FsInformationClass) { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ Stream_Seek_UINT64(input); /* CreationTime */ Stream_Seek_UINT64(input); /* LastAccessTime */ Stream_Read_UINT64(input, LastWriteTime); Stream_Seek_UINT64(input); /* ChangeTime */ Stream_Read_UINT32(input, FileAttributes); if (FSTAT(file->fd, &st) != 0) return FALSE; tv[0].tv_sec = st.st_atime; tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); #ifndef WIN32 /* TODO on win32 */ #ifdef ANDROID tv[0].tv_usec = 0; tv[1].tv_usec = 0; utimes(file->fullpath, tv); #elif defined (__linux__) || defined (sun) tv[0].tv_nsec = 0; tv[1].tv_nsec = 0; futimens(file->fd, tv); #else tv[0].tv_usec = 0; tv[1].tv_usec = 0; futimes(file->fd, tv); #endif if (FileAttributes > 0) { m = st.st_mode; if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) m |= S_IWUSR; else m &= ~S_IWUSR; if (m != st.st_mode) fchmod(file->fd, st.st_mode); } #endif break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ Stream_Read_UINT64(input, size); #ifndef _WIN32 if (ftruncate(file->fd, size) != 0) return FALSE; #endif break; case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ if (file->is_dir && !dir_empty(file->fullpath)) break; if (Length) Stream_Read_UINT8(input, file->delete_pending); else file->delete_pending = 1; break; case FileRenameInformation: /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */ Stream_Seek_UINT8(input); /* ReplaceIfExists */ Stream_Seek_UINT8(input); /* RootDirectory */ Stream_Read_UINT32(input, FileNameLength); status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input), FileNameLength / 2, &s, 0, NULL, NULL); if (status < 1) if (!(s = (char*) calloc(1, 1))) { WLog_ERR(TAG, "calloc failed!"); return FALSE; } fullpath = drive_file_combine_fullpath(file->basepath, s); if (!fullpath) { WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); free (s); return FALSE; } free(s); #ifdef _WIN32 if (file->fd) close(file->fd); #endif if (rename(file->fullpath, fullpath) == 0) { drive_file_set_fullpath(file, fullpath); #ifdef _WIN32 file->fd = OPEN(fullpath, O_RDWR | O_BINARY); #endif } else { free(fullpath); return FALSE; } break; default: return FALSE; } return TRUE; }
void guac_rdpdr_fs_process_create(guac_rdpdr_device* device, wStream* input_stream, int completion_id) { wStream* output_stream; int file_id; int desired_access, file_attributes; int create_disposition, create_options, path_length; char path[GUAC_RDP_FS_MAX_PATH]; /* Read "create" information */ Stream_Read_UINT32(input_stream, desired_access); Stream_Seek_UINT64(input_stream); /* allocation size */ Stream_Read_UINT32(input_stream, file_attributes); Stream_Seek_UINT32(input_stream); /* shared access */ Stream_Read_UINT32(input_stream, create_disposition); Stream_Read_UINT32(input_stream, create_options); Stream_Read_UINT32(input_stream, path_length); /* Convert path to UTF-8 */ guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1, path, sizeof(path)); /* Open file */ file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, path, desired_access, file_attributes, create_disposition, create_options); guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] " "desired_access=0x%x, file_attributes=0x%x, " "create_disposition=0x%x, create_options=0x%x, path=\"%s\"", __func__, file_id, desired_access, file_attributes, create_disposition, create_options, path); /* If an error occurred, notify server */ if (file_id < 0) { guac_client_log(device->rdpdr->client, GUAC_LOG_ERROR, "File open refused (%i): \"%s\"", file_id, path); output_stream = guac_rdpdr_new_io_completion(device, completion_id, guac_rdp_fs_get_status(file_id), 5); Stream_Write_UINT32(output_stream, 0); /* fileId */ Stream_Write_UINT8(output_stream, 0); /* information */ } /* Otherwise, open succeeded */ else { guac_rdp_fs_file* file; output_stream = guac_rdpdr_new_io_completion(device, completion_id, STATUS_SUCCESS, 5); Stream_Write_UINT32(output_stream, file_id); /* fileId */ Stream_Write_UINT8(output_stream, 0); /* information */ /* Create \Download if it doesn't exist */ file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); if (file != NULL && strcmp(file->absolute_path, "\\") == 0) { int download_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, "\\Download", ACCESS_GENERIC_READ, 0, DISP_FILE_OPEN_IF, FILE_DIRECTORY_FILE); if (download_id >= 0) guac_rdp_fs_close((guac_rdp_fs*) device->data, download_id); } } svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); }