]> source.dussan.org Git - tigervnc.git/commitdiff
Make sure clipboard uses \n line endings
authorPierre Ossman <ossman@cendio.se>
Thu, 2 May 2019 10:32:03 +0000 (12:32 +0200)
committerPierre Ossman <ossman@cendio.se>
Mon, 1 Jul 2019 08:38:35 +0000 (10:38 +0200)
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.

12 files changed:
common/rfb/CMsgReader.cxx
common/rfb/CMsgWriter.cxx
common/rfb/SMsgReader.cxx
common/rfb/SMsgWriter.cxx
common/rfb/VNCServerST.cxx
common/rfb/util.cxx
common/rfb/util.h
unix/xserver/hw/vnc/RFBGlue.cc
unix/xserver/hw/vnc/RFBGlue.h
unix/xserver/hw/vnc/vncSelection.c
vncviewer/Viewport.cxx
win/rfb_win32/Clipboard.cxx

index 2b5b9fbf8ea144d8378b4e888bb44f032242bff6..a928eb1587ad29c06cf8dcd10b735ef072f5590c 100644 (file)
@@ -157,10 +157,10 @@ void CMsgReader::readServerCutText()
     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()
index d357c9761fd78aca4264c7d3084a285d0b82139e..fed0bd27724c0e18588b6176e173ceafeb7418f1 100644 (file)
@@ -181,6 +181,9 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
 
 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);
index 200350c146be0837c73cda7427984572c2a253ca..0c0e8b264df167542be23d08a492ebbc2c6a3d5f 100644 (file)
@@ -212,10 +212,10 @@ void SMsgReader::readClientCutText()
     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()
index 6a2c2ba0bcf23cf70f921b7a395d7fb20cd856d6..f0748ff233025c4c0e64a8483efbd25eb7f80d57 100644 (file)
@@ -80,6 +80,9 @@ void SMsgWriter::writeBell()
 
 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);
index c95c14f068c4c0ab498403ebca7c304c8772c08a..7820aef573f4e82726e4ecc8145de977d8bc9b4d 100644 (file)
@@ -342,6 +342,8 @@ void VNCServerST::bell()
 
 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++;
index f52213b32063fbb001d47f410079ec3e42bbf8e8..f43a9453916e0380a8701510c735b62d46dbe4c2 100644 (file)
@@ -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 @@ namespace rfb {
     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)
   {
index 9e59bd378f7048b2e5dd041a36e44a660d104ac4..de096692cf12c55a32092b6f376182efe9315bbe 100644 (file)
@@ -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 @@ namespace rfb {
   // 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
 
index 160177bd0d4a16075c6d26c2d4ca4d812467666a..d9c456e859bff67c1a3ba296663a0cc43593aa18 100644 (file)
@@ -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 @@ int vncIsTCPPortUsed(int port)
   }
   return 0;
 }
+
+char* vncConvertLF(const char* src, size_t bytes)
+{
+  try {
+    return convertLF(src, bytes);
+  } catch (...) {
+    return NULL;
+  }
+}
+
+void vncStrFree(char* str)
+{
+  strFree(str);
+}
index a63afd07e52f4be37da7f948bc5139ec732130f2..8e70c680985a1e5c1b4a5914c70ff1f252f84a7f 100644 (file)
@@ -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 @@ void vncListParams(int width, int nameWidth);
 int vncGetSocketPort(int fd);
 int vncIsTCPPortUsed(int port);
 
+char* vncConvertLF(const char* src, size_t bytes);
+void vncStrFree(char* str);
+
 #ifdef __cplusplus
 }
 #endif
index 4f3538d4d9e0dd75fab2721e2a520f765518d3ba..5ddcaf009b55ac5cc991dd12beaed3ec4e040a9a 100644 (file)
@@ -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 @@ static void vncHandleSelection(Atom selection, Atom target,
     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 @@ static void vncHandleSelection(Atom selection, Atom target,
       }
     }
 
-    vncServerCutText((const char*)buffer, len);
-
+    filtered = vncConvertLF(buffer, len);
     free(buffer);
+    if (filtered == NULL)
+      return;
+
+    vncServerCutText(filtered, strlen(filtered));
+
+    vncStrFree(filtered);
   }
 }
 
index 5df5c796c9f548171e72a7515a1f776896960e05..15a3ec422b55126bb36abd239294063e8a6a91ce 100644 (file)
@@ -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 @@ void Viewport::resize(int x, int y, int w, int h)
 
 int Viewport::handle(int event)
 {
-  char *buffer;
+  char *buffer, *filtered;
   int ret;
   int buttonMask, wheelMask;
   DownMap::const_iterator iter;
@@ -564,22 +564,26 @@ int Viewport::handle(int event)
     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;
 
index 0e2906236515a44b417bc44ace7d8052b20370cc..fca6c1df2a6cfef0f423927b0593dacf78463dc1 100644 (file)
@@ -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
@@ -34,18 +35,6 @@ static LogWriter vlog("Clipboard");
 // -=- CR/LF handlers
 //
 
-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;
@@ -126,8 +115,7 @@ Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
               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));
               }