mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-17 09:51:02 +03:00
Compare commits
1 Commits
clipboard-
...
unauthoriz
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d652750b |
@@ -2443,6 +2443,9 @@ static FILEDESCRIPTORW *wf_cliprdr_get_file_descriptor(WCHAR *file_name, size_t
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to-do: use `fd->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI`.
|
||||||
|
// We keep `fd->dwFlags = FD_ATTRIBUTES | FD_WRITESTIME | FD_PROGRESSUI` for compatibility.
|
||||||
|
// fd->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
|
||||||
fd->dwFlags = FD_ATTRIBUTES | FD_WRITESTIME | FD_PROGRESSUI;
|
fd->dwFlags = FD_ATTRIBUTES | FD_WRITESTIME | FD_PROGRESSUI;
|
||||||
fd->dwFileAttributes = GetFileAttributesW(file_name);
|
fd->dwFileAttributes = GetFileAttributesW(file_name);
|
||||||
if (fd->dwFileAttributes == INVALID_FILE_ATTRIBUTES)
|
if (fd->dwFileAttributes == INVALID_FILE_ATTRIBUTES)
|
||||||
@@ -2455,34 +2458,7 @@ static FILEDESCRIPTORW *wf_cliprdr_get_file_descriptor(WCHAR *file_name, size_t
|
|||||||
fd->dwFlags &= ~FD_WRITESTIME;
|
fd->dwFlags &= ~FD_WRITESTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Announce the size in the file list. Without FD_FILESIZE the receiving side cannot
|
fd->nFileSizeLow = GetFileSize(hFile, &fd->nFileSizeHigh);
|
||||||
// trust the size fields, so CliprdrStream_New() asks for each file's size with its own
|
|
||||||
// FILECONTENTS_SIZE request and blocks on the reply. Those requests are made for every
|
|
||||||
// entry up front, while the shell is inside IDataObject::GetData(), so the cost grows
|
|
||||||
// with the number of files and not with their size.
|
|
||||||
//
|
|
||||||
// GetFileSize() reports failure as INVALID_FILE_SIZE, which cannot be told apart from a
|
|
||||||
// genuine 4GB-1 file without GetLastError(), and it fails outright on the directory
|
|
||||||
// handles FILE_FLAG_BACKUP_SEMANTICS lets us open above. A directory gets no size. A
|
|
||||||
// file whose size cannot be read is rejected rather than sent with the flag off: the
|
|
||||||
// Unix receiver reads the size fields whether or not the flag is set, for compatibility
|
|
||||||
// with older Windows senders, and would take the zero for an empty file.
|
|
||||||
if ((fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
||||||
{
|
|
||||||
LARGE_INTEGER file_size = {0};
|
|
||||||
|
|
||||||
if (!GetFileSizeEx(hFile, &file_size) || file_size.QuadPart < 0)
|
|
||||||
{
|
|
||||||
CloseHandle(hFile);
|
|
||||||
free(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd->nFileSizeLow = file_size.LowPart;
|
|
||||||
fd->nFileSizeHigh = (DWORD)file_size.HighPart;
|
|
||||||
fd->dwFlags |= FD_FILESIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((wcslen(file_name + pathLen) + 1) > sizeof(fd->cFileName) / sizeof(fd->cFileName[0]))
|
if ((wcslen(file_name + pathLen) + 1) > sizeof(fd->cFileName) / sizeof(fd->cFileName[0]))
|
||||||
{
|
{
|
||||||
// The file name is too long, which is not a normal case.
|
// The file name is too long, which is not a normal case.
|
||||||
@@ -3539,24 +3515,15 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
|
|||||||
{
|
{
|
||||||
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
|
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
|
||||||
{
|
{
|
||||||
FILEDESCRIPTORW *fd;
|
|
||||||
|
|
||||||
if (clipboard->nFiles <= fileContentsRequest->listIndex)
|
if (clipboard->nFiles <= fileContentsRequest->listIndex)
|
||||||
{
|
{
|
||||||
rc = ERROR_INTERNAL_ERROR;
|
rc = ERROR_INTERNAL_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
*((UINT32 *)&pData[0]) =
|
||||||
fd = clipboard->fileDescriptor[fileContentsRequest->listIndex];
|
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow;
|
||||||
// The size fields only mean anything when FD_FILESIZE says so. Answering with
|
*((UINT32 *)&pData[4]) =
|
||||||
// them regardless would describe an entry whose size could not be read as empty.
|
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeHigh;
|
||||||
if ((fd->dwFlags & FD_FILESIZE) == 0)
|
|
||||||
{
|
|
||||||
rc = ERROR_INTERNAL_ERROR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
*((UINT32 *)&pData[0]) = fd->nFileSizeLow;
|
|
||||||
*((UINT32 *)&pData[4]) = fd->nFileSizeHigh;
|
|
||||||
uSize = cbRequested;
|
uSize = cbRequested;
|
||||||
}
|
}
|
||||||
else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
|
else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
|
||||||
|
|||||||
@@ -221,6 +221,8 @@ pub async fn create_tcp_connection(
|
|||||||
let Some(unauthorized) = admit_unauthorized(id, addr.ip()) else {
|
let Some(unauthorized) = admit_unauthorized(id, addr.ip()) else {
|
||||||
bail!("too many unauthenticated connections from {}", addr.ip());
|
bail!("too many unauthenticated connections from {}", addr.ip());
|
||||||
};
|
};
|
||||||
|
// Before the handshake, so its read is bounded too; lifted again at authorization.
|
||||||
|
stream.set_max_packet_length(MAX_UNAUTHORIZED_MESSAGE);
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
handshake = identity_handshake(&mut stream, secure) => handshake?,
|
handshake = identity_handshake(&mut stream, secure) => handshake?,
|
||||||
_ = unauthorized.evicted() => {
|
_ = unauthorized.evicted() => {
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ const MAX_UNAUTHORIZED_CONNS: usize = 64;
|
|||||||
/// of addresses passes it, and the bound above is what holds. Meaningful only while the
|
/// of addresses passes it, and the bound above is what holds. Meaningful only while the
|
||||||
/// address is the controller's own, which punch and relay messages carry today.
|
/// address is the controller's own, which punch and relay messages carry today.
|
||||||
const MAX_UNAUTHORIZED_CONNS_PER_ADDR: usize = 16;
|
const MAX_UNAUTHORIZED_CONNS_PER_ADDR: usize = 16;
|
||||||
|
/// The largest message a connection may send before it authorizes. Until then a peer sends only
|
||||||
|
/// a public key, a login request, a test delay and a close reason, none of which carries an
|
||||||
|
/// unbounded field - the login request's avatar is a URL. Sized to the read buffer tungstenite
|
||||||
|
/// allocates per WebSocket connection regardless, so there the cap costs nothing beyond a floor
|
||||||
|
/// already paid; with MAX_UNAUTHORIZED_CONNS it holds them to 8 MiB in all, against the 1 GiB a
|
||||||
|
/// single one could make us hold before.
|
||||||
|
pub const MAX_UNAUTHORIZED_MESSAGE: usize = 128 * 1024;
|
||||||
|
|
||||||
/// A place among the unauthorized connections, taken before the identity handshake and given
|
/// A place among the unauthorized connections, taken before the identity handshake and given
|
||||||
/// back on drop: at authorization, or when the connection ends first. The count of live
|
/// back on drop: at authorization, or when the connection ends first. The count of live
|
||||||
@@ -1871,6 +1878,10 @@ impl Connection {
|
|||||||
if let Some(keep_alive) = self.prepare_terminal_login_for_authorization().await {
|
if let Some(keep_alive) = self.prepare_terminal_login_for_authorization().await {
|
||||||
return keep_alive;
|
return keep_alive;
|
||||||
}
|
}
|
||||||
|
// Lifted here rather than below with the rest of authorization: a multiplexed tunnel
|
||||||
|
// narrows it again for its own framing (`port_forward_mux::cap_packet_size`), so that
|
||||||
|
// call has to come after this one, not before.
|
||||||
|
self.stream.set_max_packet_length(usize::MAX);
|
||||||
if !self.connect_port_forward_if_needed().await {
|
if !self.connect_port_forward_if_needed().await {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user