Make sure clipboard uses \n line endings
This is required by the protocol so we should make sure it is
enforced. We are tolerant of clients that violate this though and
convert incoming clipboard data.
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index 2b5b9fb..a928eb1 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -157,10 +157,10 @@
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, strlen(filtered.buf));
}
void CMsgReader::readFence()
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
index d357c97..fed0bd2 100644
--- a/common/rfb/CMsgWriter.cxx
+++ b/common/rfb/CMsgWriter.cxx
@@ -181,6 +181,9 @@
void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len)
{
+ if (memchr(str, '\r', len) != NULL)
+ throw Exception("Invalid carriage return in clipboard data");
+
startMsg(msgTypeClientCutText);
os->pad(3);
os->writeU32(len);
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
index 200350c..0c0e8b2 100644
--- a/common/rfb/SMsgReader.cxx
+++ b/common/rfb/SMsgReader.cxx
@@ -212,10 +212,10 @@
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->clientCutText(ca.buf, len);
+ CharArray filtered(convertLF(ca.buf, len));
+ handler->clientCutText(filtered.buf, strlen(filtered.buf));
}
void SMsgReader::readQEMUMessage()
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 6a2c2ba..f0748ff 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -80,6 +80,9 @@
void SMsgWriter::writeServerCutText(const char* str, int len)
{
+ if (memchr(str, '\r', len) != NULL)
+ throw Exception("Invalid carriage return in clipboard data");
+
startMsg(msgTypeServerCutText);
os->pad(3);
os->writeU32(len);
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index c95c14f..7820aef 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -342,6 +342,8 @@
void VNCServerST::serverCutText(const char* str, int len)
{
+ if (memchr(str, '\r', len) != NULL)
+ throw Exception("Invalid carriage return in clipboard data");
std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++;
diff --git a/common/rfb/util.cxx b/common/rfb/util.cxx
index f52213b..f43a945 100644
--- a/common/rfb/util.cxx
+++ b/common/rfb/util.cxx
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-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
@@ -107,6 +108,61 @@
dest[src ? destlen-1 : 0] = 0;
}
+ char* convertLF(const char* src, size_t bytes)
+ {
+ char* buffer;
+ size_t sz;
+
+ char* out;
+ const char* in;
+ size_t in_len;
+
+ // Always include space for a NULL
+ sz = 1;
+
+ // Compute output size
+ in = src;
+ in_len = bytes;
+ while ((*in != '\0') && (in_len > 0)) {
+ if (*in != '\r') {
+ sz++;
+ in++;
+ in_len--;
+ continue;
+ }
+
+ if ((in_len == 0) || (*(in+1) != '\n'))
+ sz++;
+
+ in++;
+ in_len--;
+ }
+
+ // Alloc
+ buffer = new char[sz];
+ memset(buffer, 0, sz);
+
+ // And convert
+ out = buffer;
+ in = src;
+ in_len = bytes;
+ while ((*in != '\0') && (in_len > 0)) {
+ if (*in != '\r') {
+ *out++ = *in++;
+ in_len--;
+ continue;
+ }
+
+ if ((in_len == 0) || (*(in+1) != '\n'))
+ *out++ = '\n';
+
+ in++;
+ in_len--;
+ }
+
+ return buffer;
+ }
+
unsigned msBetween(const struct timeval *first,
const struct timeval *second)
{
diff --git a/common/rfb/util.h b/common/rfb/util.h
index 9e59bd3..de09669 100644
--- a/common/rfb/util.h
+++ b/common/rfb/util.h
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-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
@@ -83,6 +84,9 @@
// Copies src to dest, up to specified length-1, and guarantees termination
void strCopy(char* dest, const char* src, int destlen);
+ // Makes sure line endings are in a certain format
+
+ char* convertLF(const char* src, size_t bytes = (size_t)-1);
// HELPER functions for timeout handling
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
index 160177b..d9c456e 100644
--- a/unix/xserver/hw/vnc/RFBGlue.cc
+++ b/unix/xserver/hw/vnc/RFBGlue.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-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
@@ -210,3 +210,17 @@
}
return 0;
}
+
+char* vncConvertLF(const char* src, size_t bytes)
+{
+ try {
+ return convertLF(src, bytes);
+ } catch (...) {
+ return NULL;
+ }
+}
+
+void vncStrFree(char* str)
+{
+ strFree(str);
+}
diff --git a/unix/xserver/hw/vnc/RFBGlue.h b/unix/xserver/hw/vnc/RFBGlue.h
index a63afd0..8e70c68 100644
--- a/unix/xserver/hw/vnc/RFBGlue.h
+++ b/unix/xserver/hw/vnc/RFBGlue.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-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
@@ -49,6 +49,9 @@
int vncGetSocketPort(int fd);
int vncIsTCPPortUsed(int port);
+char* vncConvertLF(const char* src, size_t bytes);
+void vncStrFree(char* str);
+
#ifdef __cplusplus
}
#endif
diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
index 4f3538d..5ddcaf0 100644
--- a/unix/xserver/hw/vnc/vncSelection.c
+++ b/unix/xserver/hw/vnc/vncSelection.c
@@ -1,4 +1,4 @@
-/* Copyright 2016 Pierre Ossman for Cendio AB
+/* Copyright 2016-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
@@ -415,13 +415,22 @@
else if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
vncSelectionRequest(selection, xaUTF8_STRING);
} else if (target == xaSTRING) {
+ char* filtered;
+
if (prop->format != 8)
return;
if (prop->type != xaSTRING)
return;
- vncServerCutText(prop->data, prop->size);
+ filtered = vncConvertLF(prop->data, prop->size);
+ if (filtered == NULL)
+ return;
+
+ vncServerCutText(filtered, strlen(filtered));
+
+ vncStrFree(filtered);
} else if (target == xaUTF8_STRING) {
+ char *filtered;
unsigned char* buffer;
unsigned char* out;
size_t len;
@@ -470,9 +479,14 @@
}
}
- vncServerCutText((const char*)buffer, len);
-
+ filtered = vncConvertLF(buffer, len);
free(buffer);
+ if (filtered == NULL)
+ return;
+
+ vncServerCutText(filtered, strlen(filtered));
+
+ vncStrFree(filtered);
}
}
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 5df5c79..15a3ec4 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2014 Pierre Ossman for Cendio AB
+ * Copyright 2011-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
@@ -549,7 +549,7 @@
int Viewport::handle(int event)
{
- char *buffer;
+ char *buffer, *filtered;
int ret;
int buttonMask, wheelMask;
DownMap::const_iterator iter;
@@ -564,22 +564,26 @@
ret = fl_utf8toa(Fl::event_text(), Fl::event_length(), buffer,
Fl::event_length() + 1);
assert(ret < (Fl::event_length() + 1));
+ filtered = convertLF(buffer, ret);
+ delete [] buffer;
if (!hasFocus()) {
- pendingClientCutText = buffer;
+ pendingClientCutText = new char[strlen(filtered) + 1];
+ strcpy((char*)pendingClientCutText, filtered);
+ strFree(filtered);
return 1;
}
- vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(buffer));
+ vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(filtered));
try {
- cc->writer()->writeClientCutText(buffer, ret);
+ cc->writer()->writeClientCutText(filtered, strlen(filtered));
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
- delete [] buffer;
+ strFree(filtered);
return 1;
diff --git a/win/rfb_win32/Clipboard.cxx b/win/rfb_win32/Clipboard.cxx
index 0e29062..fca6c1d 100644
--- a/win/rfb_win32/Clipboard.cxx
+++ b/win/rfb_win32/Clipboard.cxx
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2012-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
@@ -35,18 +36,6 @@
//
char*
-dos2unix(const char* text) {
- int len = strlen(text)+1;
- char* unix = new char[strlen(text)+1];
- int i, j=0;
- for (i=0; i<len; i++) {
- if (text[i] != '\x0d')
- unix[j++] = text[i];
- }
- return unix;
-}
-
-char*
unix2dos(const char* text) {
int len = strlen(text)+1;
char* dos = new char[strlen(text)*2+1];
@@ -126,8 +115,7 @@
if (!clipdata) {
notifier->notifyClipboardChanged(0, 0);
} else {
- CharArray unix_text;
- unix_text.buf = dos2unix(clipdata);
+ CharArray unix_text(convertLF(clipdata, strlen(clipdata)));
removeNonISOLatin1Chars(unix_text.buf);
notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
}