diff options
Diffstat (limited to 'common/rfb/CMsgReader.cxx')
-rw-r--r-- | common/rfb/CMsgReader.cxx | 118 |
1 files changed, 112 insertions, 6 deletions
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index 2b5b9fbf..a9e12d70 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2017 Pierre Ossman for Cendio AB + * Copyright 2009-2019 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +20,11 @@ #include <assert.h> #include <stdio.h> -#include <rfb/msgTypes.h> #include <rdr/InStream.h> +#include <rdr/ZlibInStream.h> + +#include <rfb/msgTypes.h> +#include <rfb/clipboardTypes.h> #include <rfb/Exception.h> #include <rfb/LogWriter.h> #include <rfb/util.h> @@ -30,6 +33,8 @@ static rfb::LogWriter vlog("CMsgReader"); +static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024); + using namespace rfb; CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_) @@ -152,15 +157,116 @@ void CMsgReader::readServerCutText() { is->skip(3); rdr::U32 len = is->readU32(); - if (len > 256*1024) { + + if (len & 0x80000000) { + rdr::S32 slen = len; + slen = -slen; + readExtendedClipboard(slen); + return; + } + + if (len > (size_t)maxCutText) { is->skip(len); vlog.error("cut text too long (%d bytes) - ignoring",len); return; } - CharArray ca(len+1); - ca.buf[len] = 0; + CharArray ca(len); is->readBytes(ca.buf, len); - handler->serverCutText(ca.buf, len); + CharArray filtered(convertLF(ca.buf, len)); + handler->serverCutText(filtered.buf); +} + +void CMsgReader::readExtendedClipboard(rdr::S32 len) +{ + rdr::U32 flags; + rdr::U32 action; + + if (len < 4) + throw Exception("Invalid extended clipboard message"); + if (len > maxCutText) { + vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len); + is->skip(len); + return; + } + + flags = is->readU32(); + action = flags & clipboardActionMask; + + if (action & clipboardCaps) { + int i; + size_t num; + rdr::U32 lengths[16]; + + num = 0; + for (i = 0;i < 16;i++) { + if (flags & (1 << i)) + num++; + } + + if (len < (rdr::S32)(4 + 4*num)) + throw Exception("Invalid extended clipboard message"); + + num = 0; + for (i = 0;i < 16;i++) { + if (flags & (1 << i)) + lengths[num++] = is->readU32(); + } + + handler->handleClipboardCaps(flags, lengths); + } else if (action == clipboardProvide) { + rdr::ZlibInStream zis; + + int i; + size_t num; + size_t lengths[16]; + rdr::U8* buffers[16]; + + zis.setUnderlying(is, len - 4); + + num = 0; + for (i = 0;i < 16;i++) { + if (!(flags & 1 << i)) + continue; + + lengths[num] = zis.readU32(); + if (lengths[num] > (size_t)maxCutText) { + vlog.error("Extended clipboard data too long (%d bytes) - ignoring", + (unsigned)lengths[num]); + zis.skip(lengths[num]); + flags &= ~(1 << i); + continue; + } + + buffers[num] = new rdr::U8[lengths[num]]; + zis.readBytes(buffers[num], lengths[num]); + num++; + } + + zis.removeUnderlying(); + + handler->handleClipboardProvide(flags, lengths, buffers); + + num = 0; + for (i = 0;i < 16;i++) { + if (!(flags & 1 << i)) + continue; + delete [] buffers[num++]; + } + } else { + switch (action) { + case clipboardRequest: + handler->handleClipboardRequest(flags); + break; + case clipboardPeek: + handler->handleClipboardPeek(flags); + break; + case clipboardNotify: + handler->handleClipboardNotify(flags); + break; + default: + throw Exception("Invalid extended clipboard action"); + } + } } void CMsgReader::readFence() |