• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * rfbserver.c - deal with server-side of the RFB protocol.
3  */
4 
5 /*
6  *  Copyright (C) 2011-2012 D. R. Commander
7  *  Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
8  *  Copyright (C) 2002 RealVNC Ltd.
9  *  OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
10  *  Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
11  *  All Rights Reserved.
12  *
13  *  This is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  This software is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with this software; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
26  *  USA.
27  */
28 
29 #ifdef __STRICT_ANSI__
30 #define _BSD_SOURCE
31 #define _POSIX_SOURCE
32 #define _XOPEN_SOURCE 600
33 #endif
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <rfb/rfb.h>
38 #include <rfb/rfbregion.h>
39 #include "private.h"
40 
41 #ifdef LIBVNCSERVER_HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
44 
45 #ifdef WIN32
46 #include <winsock2.h>
47 #include <ws2tcpip.h>
48 #include <io.h>
49 #define write(sock,buf,len) send(sock,buf,len,0)
50 #else
51 #ifdef LIBVNCSERVER_HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #include <pwd.h>
55 #ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
56 #include <sys/socket.h>
57 #endif
58 #ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
59 #include <netinet/in.h>
60 #include <netinet/tcp.h>
61 #include <netdb.h>
62 #include <arpa/inet.h>
63 #endif
64 #endif
65 
66 #ifdef DEBUGPROTO
67 #undef DEBUGPROTO
68 #define DEBUGPROTO(x) x
69 #else
70 #define DEBUGPROTO(x)
71 #endif
72 #include <stdarg.h>
73 #include <scale.h>
74 /* stst() */
75 #include <sys/types.h>
76 #include <sys/stat.h>
77 #include <unistd.h>
78 
79 #ifndef WIN32
80 /* readdir() */
81 #include <dirent.h>
82 #endif
83 
84 /* errno */
85 #include <errno.h>
86 /* strftime() */
87 #include <time.h>
88 
89 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
90 #include "rfbssl.h"
91 #endif
92 
93 #ifdef _MSC_VER
94 #define snprintf _snprintf /* Missing in MSVC */
95 /* Prevent POSIX deprecation warnings */
96 #define close _close
97 #define strdup _strdup
98 #endif
99 
100 #ifdef WIN32
101 #ifdef __MINGW32__
102 #define mkdir(path, perms) mkdir(path) /* Omit the perms argument to match POSIX signature */
103 #else /* MSVC and other windows compilers */
104 #define mkdir(path, perms) _mkdir(path) /* Omit the perms argument to match POSIX signature */
105 #endif /* __MINGW32__ else... */
106 #define S_ISDIR(m)	(((m) & S_IFDIR) == S_IFDIR)
107 #include <direct.h>
108 #endif
109 
110 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
111 /*
112  * Map of quality levels to provide compatibility with TightVNC/TigerVNC
113  * clients.  This emulates the behavior of the TigerVNC Server.
114  */
115 
116 static const int tight2turbo_qual[10] = {
117    15, 29, 41, 42, 62, 77, 79, 86, 92, 100
118 };
119 
120 static const int tight2turbo_subsamp[10] = {
121    1, 1, 1, 2, 2, 2, 0, 0, 0, 0
122 };
123 #endif
124 
125 static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
126 static void rfbProcessClientNormalMessage(rfbClientPtr cl);
127 static void rfbProcessClientInitMessage(rfbClientPtr cl);
128 
129 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
rfbIncrClientRef(rfbClientPtr cl)130 void rfbIncrClientRef(rfbClientPtr cl)
131 {
132   LOCK(cl->refCountMutex);
133   cl->refCount++;
134   UNLOCK(cl->refCountMutex);
135 }
136 
rfbDecrClientRef(rfbClientPtr cl)137 void rfbDecrClientRef(rfbClientPtr cl)
138 {
139   LOCK(cl->refCountMutex);
140   cl->refCount--;
141   if(cl->refCount<=0) /* just to be sure also < 0 */
142     TSIGNAL(cl->deleteCond);
143   UNLOCK(cl->refCountMutex);
144 }
145 #else
rfbIncrClientRef(rfbClientPtr cl)146 void rfbIncrClientRef(rfbClientPtr cl) {}
rfbDecrClientRef(rfbClientPtr cl)147 void rfbDecrClientRef(rfbClientPtr cl) {}
148 #endif
149 
150 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
151 static MUTEX(rfbClientListMutex);
152 #endif
153 
154 struct rfbClientIterator {
155   rfbClientPtr next;
156   rfbScreenInfoPtr screen;
157   rfbBool closedToo;
158 };
159 
160 void
rfbClientListInit(rfbScreenInfoPtr rfbScreen)161 rfbClientListInit(rfbScreenInfoPtr rfbScreen)
162 {
163     if(sizeof(rfbBool)!=1) {
164         /* a sanity check */
165         fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",(int)sizeof(rfbBool));
166 	/* we cannot continue, because rfbBool is supposed to be char everywhere */
167 	exit(1);
168     }
169     rfbScreen->clientHead = NULL;
170     INIT_MUTEX(rfbClientListMutex);
171 }
172 
173 rfbClientIteratorPtr
rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)174 rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
175 {
176   rfbClientIteratorPtr i =
177     (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
178   i->next = NULL;
179   i->screen = rfbScreen;
180   i->closedToo = FALSE;
181   return i;
182 }
183 
184 rfbClientIteratorPtr
rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)185 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)
186 {
187   rfbClientIteratorPtr i =
188     (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
189   i->next = NULL;
190   i->screen = rfbScreen;
191   i->closedToo = TRUE;
192   return i;
193 }
194 
195 rfbClientPtr
rfbClientIteratorHead(rfbClientIteratorPtr i)196 rfbClientIteratorHead(rfbClientIteratorPtr i)
197 {
198 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
199   if(i->next != 0) {
200     rfbDecrClientRef(i->next);
201     rfbIncrClientRef(i->screen->clientHead);
202   }
203 #endif
204   LOCK(rfbClientListMutex);
205   i->next = i->screen->clientHead;
206   UNLOCK(rfbClientListMutex);
207   return i->next;
208 }
209 
210 rfbClientPtr
rfbClientIteratorNext(rfbClientIteratorPtr i)211 rfbClientIteratorNext(rfbClientIteratorPtr i)
212 {
213   if(i->next == 0) {
214     LOCK(rfbClientListMutex);
215     i->next = i->screen->clientHead;
216     UNLOCK(rfbClientListMutex);
217   } else {
218     IF_PTHREADS(rfbClientPtr cl = i->next);
219     i->next = i->next->next;
220     IF_PTHREADS(rfbDecrClientRef(cl));
221   }
222 
223 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
224     if(!i->closedToo)
225       while(i->next && i->next->sock<0)
226         i->next = i->next->next;
227     if(i->next)
228       rfbIncrClientRef(i->next);
229 #endif
230 
231     return i->next;
232 }
233 
234 void
rfbReleaseClientIterator(rfbClientIteratorPtr iterator)235 rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
236 {
237   IF_PTHREADS(if(iterator->next) rfbDecrClientRef(iterator->next));
238   free(iterator);
239 }
240 
241 
242 /*
243  * rfbNewClientConnection is called from sockets.c when a new connection
244  * comes in.
245  */
246 
247 void
rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,int sock)248 rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,
249                        int sock)
250 {
251     rfbNewClient(rfbScreen,sock);
252 }
253 
254 
255 /*
256  * rfbReverseConnection is called to make an outward
257  * connection to a "listening" RFB client.
258  */
259 
260 rfbClientPtr
rfbReverseConnection(rfbScreenInfoPtr rfbScreen,char * host,int port)261 rfbReverseConnection(rfbScreenInfoPtr rfbScreen,
262                      char *host,
263                      int port)
264 {
265     int sock;
266     rfbClientPtr cl;
267 
268     if ((sock = rfbConnect(rfbScreen, host, port)) < 0)
269         return (rfbClientPtr)NULL;
270 
271     cl = rfbNewClient(rfbScreen, sock);
272 
273     if (cl) {
274         cl->reverseConnection = TRUE;
275     }
276 
277     return cl;
278 }
279 
280 
281 void
rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen,int major_,int minor_)282 rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_)
283 {
284     /* Permit the server to set the version to report */
285     /* TODO: sanity checking */
286     if ((major_==3) && (minor_ > 2 && minor_ < 9))
287     {
288       rfbScreen->protocolMajorVersion = major_;
289       rfbScreen->protocolMinorVersion = minor_;
290     }
291     else
292         rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_);
293 }
294 
295 /*
296  * rfbNewClient is called when a new connection has been made by whatever
297  * means.
298  */
299 
300 static rfbClientPtr
rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,int sock,rfbBool isUDP)301 rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
302                      int sock,
303                      rfbBool isUDP)
304 {
305     rfbProtocolVersionMsg pv;
306     rfbClientIteratorPtr iterator;
307     rfbClientPtr cl,cl_;
308 #ifdef LIBVNCSERVER_IPv6
309     struct sockaddr_storage addr;
310 #else
311     struct sockaddr_in addr;
312 #endif
313     socklen_t addrlen = sizeof(addr);
314     rfbProtocolExtension* extension;
315 
316     cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
317 
318     cl->screen = rfbScreen;
319     cl->sock = sock;
320     cl->viewOnly = FALSE;
321     /* setup pseudo scaling */
322     cl->scaledScreen = rfbScreen;
323     cl->scaledScreen->scaledScreenRefCount++;
324 
325     rfbResetStats(cl);
326 
327     cl->clientData = NULL;
328     cl->clientGoneHook = rfbDoNothingWithClient;
329 
330     if(isUDP) {
331       rfbLog(" accepted UDP client\n");
332 	} else {
333 #ifdef LIBVNCSERVER_IPv6
334 		char host[1024];
335 #endif
336       int one=1;
337 
338       getpeername(sock, (struct sockaddr *)&addr, &addrlen);
339 #ifdef LIBVNCSERVER_IPv6
340       if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
341 	rfbLogPerror("rfbNewClient: error in getnameinfo");
342 	cl->host = strdup("");
343       }
344       else
345 	cl->host = strdup(host);
346 #else
347       cl->host = strdup(inet_ntoa(addr.sin_addr));
348 #endif
349 
350       rfbLog("  other clients:\n");
351       iterator = rfbGetClientIterator(rfbScreen);
352       while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) {
353         rfbLog("     %s\n",cl_->host);
354       }
355       rfbReleaseClientIterator(iterator);
356 
357       if(!rfbSetNonBlocking(sock)) {
358 	close(sock);
359 	return NULL;
360       }
361 
362       if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
363 		     (char *)&one, sizeof(one)) < 0) {
364 	rfbLogPerror("setsockopt failed");
365 	close(sock);
366 	return NULL;
367       }
368 
369       FD_SET(sock,&(rfbScreen->allFds));
370 		rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
371 
372       INIT_MUTEX(cl->outputMutex);
373       INIT_MUTEX(cl->refCountMutex);
374       INIT_MUTEX(cl->sendMutex);
375       INIT_COND(cl->deleteCond);
376 
377       cl->state = RFB_PROTOCOL_VERSION;
378 
379       cl->reverseConnection = FALSE;
380       cl->readyForSetColourMapEntries = FALSE;
381       cl->useCopyRect = FALSE;
382       cl->preferredEncoding = -1;
383       cl->correMaxWidth = 48;
384       cl->correMaxHeight = 48;
385 #ifdef LIBVNCSERVER_HAVE_LIBZ
386       cl->zrleData = NULL;
387 #endif
388 
389       cl->copyRegion = sraRgnCreate();
390       cl->copyDX = 0;
391       cl->copyDY = 0;
392 
393       cl->modifiedRegion =
394 	sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height);
395 
396       INIT_MUTEX(cl->updateMutex);
397       INIT_COND(cl->updateCond);
398 
399       cl->requestedRegion = sraRgnCreate();
400 
401       cl->format = cl->screen->serverFormat;
402       cl->translateFn = rfbTranslateNone;
403       cl->translateLookupTable = NULL;
404 
405       LOCK(rfbClientListMutex);
406 
407       IF_PTHREADS(cl->refCount = 0);
408       cl->next = rfbScreen->clientHead;
409       cl->prev = NULL;
410       if (rfbScreen->clientHead)
411         rfbScreen->clientHead->prev = cl;
412 
413       rfbScreen->clientHead = cl;
414       UNLOCK(rfbClientListMutex);
415 
416 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
417       cl->tightQualityLevel = -1;
418 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
419       cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
420       cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP;
421       {
422 	int i;
423 	for (i = 0; i < 4; i++)
424           cl->zsActive[i] = FALSE;
425       }
426 #endif
427 #endif
428 
429       cl->fileTransfer.fd = -1;
430 
431       cl->enableCursorShapeUpdates = FALSE;
432       cl->enableCursorPosUpdates = FALSE;
433       cl->useRichCursorEncoding = FALSE;
434       cl->enableLastRectEncoding = FALSE;
435       cl->enableKeyboardLedState = FALSE;
436       cl->enableSupportedMessages = FALSE;
437       cl->enableSupportedEncodings = FALSE;
438       cl->enableServerIdentity = FALSE;
439       cl->lastKeyboardLedState = -1;
440       cl->cursorX = rfbScreen->cursorX;
441       cl->cursorY = rfbScreen->cursorY;
442       cl->useNewFBSize = FALSE;
443 
444 #ifdef LIBVNCSERVER_HAVE_LIBZ
445       cl->compStreamInited = FALSE;
446       cl->compStream.total_in = 0;
447       cl->compStream.total_out = 0;
448       cl->compStream.zalloc = Z_NULL;
449       cl->compStream.zfree = Z_NULL;
450       cl->compStream.opaque = Z_NULL;
451 
452       cl->zlibCompressLevel = 5;
453 #endif
454 
455       cl->progressiveSliceY = 0;
456 
457       cl->extensions = NULL;
458 
459       cl->lastPtrX = -1;
460 
461 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
462       /*
463        * Wait a few ms for the client to send one of:
464        * - Flash policy request
465        * - WebSockets connection (TLS/SSL or plain)
466        */
467       if (!webSocketsCheck(cl)) {
468         /* Error reporting handled in webSocketsHandshake */
469         rfbCloseClient(cl);
470         rfbClientConnectionGone(cl);
471         return NULL;
472       }
473 #endif
474 
475       sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion,
476               rfbScreen->protocolMinorVersion);
477 
478       if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
479         rfbLogPerror("rfbNewClient: write");
480         rfbCloseClient(cl);
481 	rfbClientConnectionGone(cl);
482         return NULL;
483       }
484     }
485 
486     for(extension = rfbGetExtensionIterator(); extension;
487 	    extension=extension->next) {
488 	void* data = NULL;
489 	/* if the extension does not have a newClient method, it wants
490 	 * to be initialized later. */
491 	if(extension->newClient && extension->newClient(cl, &data))
492 		rfbEnableExtension(cl, extension, data);
493     }
494     rfbReleaseExtensionIterator();
495 
496     switch (cl->screen->newClientHook(cl)) {
497     case RFB_CLIENT_ON_HOLD:
498 	    cl->onHold = TRUE;
499 	    break;
500     case RFB_CLIENT_ACCEPT:
501 	    cl->onHold = FALSE;
502 	    break;
503     case RFB_CLIENT_REFUSE:
504 	    rfbCloseClient(cl);
505 	    rfbClientConnectionGone(cl);
506 	    cl = NULL;
507 	    break;
508     }
509     return cl;
510 }
511 
512 rfbClientPtr
rfbNewClient(rfbScreenInfoPtr rfbScreen,int sock)513 rfbNewClient(rfbScreenInfoPtr rfbScreen,
514              int sock)
515 {
516   return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE));
517 }
518 
519 rfbClientPtr
rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)520 rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)
521 {
522   return((rfbScreen->udpClient=
523 	  rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE)));
524 }
525 
526 /*
527  * rfbClientConnectionGone is called from sockets.c just after a connection
528  * has gone away.
529  */
530 
531 void
rfbClientConnectionGone(rfbClientPtr cl)532 rfbClientConnectionGone(rfbClientPtr cl)
533 {
534 #if defined(LIBVNCSERVER_HAVE_LIBZ) && defined(LIBVNCSERVER_HAVE_LIBJPEG)
535     int i;
536 #endif
537 
538     LOCK(rfbClientListMutex);
539 
540     if (cl->prev)
541         cl->prev->next = cl->next;
542     else
543         cl->screen->clientHead = cl->next;
544     if (cl->next)
545         cl->next->prev = cl->prev;
546 
547     UNLOCK(rfbClientListMutex);
548 
549 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
550     if(cl->screen->backgroundLoop != FALSE) {
551       int i;
552       do {
553 	LOCK(cl->refCountMutex);
554 	i=cl->refCount;
555 	if(i>0)
556 	  WAIT(cl->deleteCond,cl->refCountMutex);
557 	UNLOCK(cl->refCountMutex);
558       } while(i>0);
559     }
560 #endif
561 
562     if(cl->sock>=0)
563 	close(cl->sock);
564 
565     if (cl->scaledScreen!=NULL)
566         cl->scaledScreen->scaledScreenRefCount--;
567 
568 #ifdef LIBVNCSERVER_HAVE_LIBZ
569     rfbFreeZrleData(cl);
570 #endif
571 
572     rfbFreeUltraData(cl);
573 
574     /* free buffers holding pixel data before and after encoding */
575     free(cl->beforeEncBuf);
576     free(cl->afterEncBuf);
577 
578     if(cl->sock>=0)
579        FD_CLR(cl->sock,&(cl->screen->allFds));
580 
581     cl->clientGoneHook(cl);
582 
583     rfbLog("Client %s gone\n",cl->host);
584     free(cl->host);
585 
586 #ifdef LIBVNCSERVER_HAVE_LIBZ
587     /* Release the compression state structures if any. */
588     if ( cl->compStreamInited ) {
589 	deflateEnd( &(cl->compStream) );
590     }
591 
592 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
593     for (i = 0; i < 4; i++) {
594 	if (cl->zsActive[i])
595 	    deflateEnd(&cl->zsStruct[i]);
596     }
597 #endif
598 #endif
599 
600     if (cl->screen->pointerClient == cl)
601         cl->screen->pointerClient = NULL;
602 
603     sraRgnDestroy(cl->modifiedRegion);
604     sraRgnDestroy(cl->requestedRegion);
605     sraRgnDestroy(cl->copyRegion);
606 
607     if (cl->translateLookupTable) free(cl->translateLookupTable);
608 
609     TINI_COND(cl->updateCond);
610     TINI_MUTEX(cl->updateMutex);
611 
612     /* make sure outputMutex is unlocked before destroying */
613     LOCK(cl->outputMutex);
614     UNLOCK(cl->outputMutex);
615     TINI_MUTEX(cl->outputMutex);
616 
617     LOCK(cl->sendMutex);
618     UNLOCK(cl->sendMutex);
619     TINI_MUTEX(cl->sendMutex);
620 
621     rfbPrintStats(cl);
622     rfbResetStats(cl);
623 
624     free(cl);
625 }
626 
627 
628 /*
629  * rfbProcessClientMessage is called when there is data to read from a client.
630  */
631 
632 void
rfbProcessClientMessage(rfbClientPtr cl)633 rfbProcessClientMessage(rfbClientPtr cl)
634 {
635     switch (cl->state) {
636     case RFB_PROTOCOL_VERSION:
637         rfbProcessClientProtocolVersion(cl);
638         return;
639     case RFB_SECURITY_TYPE:
640         rfbProcessClientSecurityType(cl);
641         return;
642     case RFB_AUTHENTICATION:
643         rfbAuthProcessClientMessage(cl);
644         return;
645     case RFB_INITIALISATION:
646     case RFB_INITIALISATION_SHARED:
647         rfbProcessClientInitMessage(cl);
648         return;
649     default:
650         rfbProcessClientNormalMessage(cl);
651         return;
652     }
653 }
654 
655 
656 /*
657  * rfbProcessClientProtocolVersion is called when the client sends its
658  * protocol version.
659  */
660 
661 static void
rfbProcessClientProtocolVersion(rfbClientPtr cl)662 rfbProcessClientProtocolVersion(rfbClientPtr cl)
663 {
664     rfbProtocolVersionMsg pv;
665     int n, major_, minor_;
666 
667     if ((n = rfbReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) {
668         if (n == 0)
669             rfbLog("rfbProcessClientProtocolVersion: client gone\n");
670         else
671             rfbLogPerror("rfbProcessClientProtocolVersion: read");
672         rfbCloseClient(cl);
673         return;
674     }
675 
676     pv[sz_rfbProtocolVersionMsg] = 0;
677     if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) {
678 	rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client: %s\n", pv);
679 	rfbCloseClient(cl);
680 	return;
681     }
682     rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
683 
684     if (major_ != rfbProtocolMajorVersion) {
685         rfbErr("RFB protocol version mismatch - server %d.%d, client %d.%d",
686                 cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion,
687                 major_,minor_);
688         rfbCloseClient(cl);
689         return;
690     }
691 
692     /* Check for the minor version use either of the two standard version of RFB */
693     /*
694      * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions
695      * 3.4, 3.6, 3.14, 3.16
696      * It's a bad method, but it is what they use to enable features...
697      * maintaining RFB version compatibility across multiple servers is a pain
698      * Should use something like ServerIdentity encoding
699      */
700     cl->protocolMajorVersion = major_;
701     cl->protocolMinorVersion = minor_;
702 
703     rfbLog("Protocol version sent %d.%d, using %d.%d\n",
704               major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
705 
706     rfbAuthNewClient(cl);
707 }
708 
709 
710 void
rfbClientSendString(rfbClientPtr cl,const char * reason)711 rfbClientSendString(rfbClientPtr cl, const char *reason)
712 {
713     char *buf;
714     int len = strlen(reason);
715 
716     rfbLog("rfbClientSendString(\"%s\")\n", reason);
717 
718     buf = (char *)malloc(4 + len);
719     ((uint32_t *)buf)[0] = Swap32IfLE(len);
720     memcpy(buf + 4, reason, len);
721 
722     if (rfbWriteExact(cl, buf, 4 + len) < 0)
723         rfbLogPerror("rfbClientSendString: write");
724     free(buf);
725 
726     rfbCloseClient(cl);
727 }
728 
729 /*
730  * rfbClientConnFailed is called when a client connection has failed either
731  * because it talks the wrong protocol or it has failed authentication.
732  */
733 
734 void
rfbClientConnFailed(rfbClientPtr cl,const char * reason)735 rfbClientConnFailed(rfbClientPtr cl,
736                     const char *reason)
737 {
738     char *buf;
739     int len = strlen(reason);
740 
741     rfbLog("rfbClientConnFailed(\"%s\")\n", reason);
742 
743     buf = (char *)malloc(8 + len);
744     ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed);
745     ((uint32_t *)buf)[1] = Swap32IfLE(len);
746     memcpy(buf + 8, reason, len);
747 
748     if (rfbWriteExact(cl, buf, 8 + len) < 0)
749         rfbLogPerror("rfbClientConnFailed: write");
750     free(buf);
751 
752     rfbCloseClient(cl);
753 }
754 
755 
756 /*
757  * rfbProcessClientInitMessage is called when the client sends its
758  * initialisation message.
759  */
760 
761 static void
rfbProcessClientInitMessage(rfbClientPtr cl)762 rfbProcessClientInitMessage(rfbClientPtr cl)
763 {
764     rfbClientInitMsg ci;
765     union {
766         char buf[256];
767         rfbServerInitMsg si;
768     } u;
769     int len, n;
770     rfbClientIteratorPtr iterator;
771     rfbClientPtr otherCl;
772     rfbExtensionData* extension;
773 
774     if (cl->state == RFB_INITIALISATION_SHARED) {
775         /* In this case behave as though an implicit ClientInit message has
776          * already been received with a shared-flag of true. */
777         ci.shared = 1;
778         /* Avoid the possibility of exposing the RFB_INITIALISATION_SHARED
779          * state to calling software. */
780         cl->state = RFB_INITIALISATION;
781     } else {
782         if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
783             if (n == 0)
784                 rfbLog("rfbProcessClientInitMessage: client gone\n");
785             else
786                 rfbLogPerror("rfbProcessClientInitMessage: read");
787             rfbCloseClient(cl);
788             return;
789         }
790     }
791 
792     memset(u.buf,0,sizeof(u.buf));
793 
794     u.si.framebufferWidth = Swap16IfLE(cl->screen->width);
795     u.si.framebufferHeight = Swap16IfLE(cl->screen->height);
796     u.si.format = cl->screen->serverFormat;
797     u.si.format.redMax = Swap16IfLE(u.si.format.redMax);
798     u.si.format.greenMax = Swap16IfLE(u.si.format.greenMax);
799     u.si.format.blueMax = Swap16IfLE(u.si.format.blueMax);
800 
801     strncpy(u.buf + sz_rfbServerInitMsg, cl->screen->desktopName, 127);
802     len = strlen(u.buf + sz_rfbServerInitMsg);
803     u.si.nameLength = Swap32IfLE(len);
804 
805     if (rfbWriteExact(cl, u.buf, sz_rfbServerInitMsg + len) < 0) {
806         rfbLogPerror("rfbProcessClientInitMessage: write");
807         rfbCloseClient(cl);
808         return;
809     }
810 
811     for(extension = cl->extensions; extension;) {
812 	rfbExtensionData* next = extension->next;
813 	if(extension->extension->init &&
814 		!extension->extension->init(cl, extension->data))
815 	    /* extension requested that it be removed */
816 	    rfbDisableExtension(cl, extension->extension);
817 	extension = next;
818     }
819 
820     cl->state = RFB_NORMAL;
821 
822     if (!cl->reverseConnection &&
823                         (cl->screen->neverShared || (!cl->screen->alwaysShared && !ci.shared))) {
824 
825         if (cl->screen->dontDisconnect) {
826             iterator = rfbGetClientIterator(cl->screen);
827             while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
828                 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
829                     rfbLog("-dontdisconnect: Not shared & existing client\n");
830                     rfbLog("  refusing new client %s\n", cl->host);
831                     rfbCloseClient(cl);
832                     rfbReleaseClientIterator(iterator);
833                     return;
834                 }
835             }
836             rfbReleaseClientIterator(iterator);
837         } else {
838             iterator = rfbGetClientIterator(cl->screen);
839             while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
840                 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
841                     rfbLog("Not shared - closing connection to client %s\n",
842                            otherCl->host);
843                     rfbCloseClient(otherCl);
844                 }
845             }
846             rfbReleaseClientIterator(iterator);
847         }
848     }
849 }
850 
851 /* The values come in based on the scaled screen, we need to convert them to
852  * values based on the man screen's coordinate system
853  */
rectSwapIfLEAndClip(uint16_t * x,uint16_t * y,uint16_t * w,uint16_t * h,rfbClientPtr cl)854 static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h,
855 		rfbClientPtr cl)
856 {
857 	int x1=Swap16IfLE(*x);
858 	int y1=Swap16IfLE(*y);
859 	int w1=Swap16IfLE(*w);
860 	int h1=Swap16IfLE(*h);
861 
862 	rfbScaledCorrection(cl->scaledScreen, cl->screen, &x1, &y1, &w1, &h1, "rectSwapIfLEAndClip");
863 	*x = x1;
864 	*y = y1;
865 	*w = w1;
866 	*h = h1;
867 
868 	if(*w>cl->screen->width-*x)
869 		*w=cl->screen->width-*x;
870 	/* possible underflow */
871 	if(*w>cl->screen->width-*x)
872 		return FALSE;
873 	if(*h>cl->screen->height-*y)
874 		*h=cl->screen->height-*y;
875 	if(*h>cl->screen->height-*y)
876 		return FALSE;
877 
878 	return TRUE;
879 }
880 
881 /*
882  * Send keyboard state (PointerPos pseudo-encoding).
883  */
884 
885 rfbBool
rfbSendKeyboardLedState(rfbClientPtr cl)886 rfbSendKeyboardLedState(rfbClientPtr cl)
887 {
888     rfbFramebufferUpdateRectHeader rect;
889 
890     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
891         if (!rfbSendUpdateBuf(cl))
892             return FALSE;
893     }
894 
895     rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState);
896     rect.r.x = Swap16IfLE(cl->lastKeyboardLedState);
897     rect.r.y = 0;
898     rect.r.w = 0;
899     rect.r.h = 0;
900 
901     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
902         sz_rfbFramebufferUpdateRectHeader);
903     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
904 
905     rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
906 
907     if (!rfbSendUpdateBuf(cl))
908         return FALSE;
909 
910     return TRUE;
911 }
912 
913 
914 #define rfbSetBit(buffer, position)  (buffer[(position & 255) / 8] |= (1 << (position % 8)))
915 
916 /*
917  * Send rfbEncodingSupportedMessages.
918  */
919 
920 rfbBool
rfbSendSupportedMessages(rfbClientPtr cl)921 rfbSendSupportedMessages(rfbClientPtr cl)
922 {
923     rfbFramebufferUpdateRectHeader rect;
924     rfbSupportedMessages msgs;
925 
926     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
927                   + sz_rfbSupportedMessages > UPDATE_BUF_SIZE) {
928         if (!rfbSendUpdateBuf(cl))
929             return FALSE;
930     }
931 
932     rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
933     rect.r.x = 0;
934     rect.r.y = 0;
935     rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
936     rect.r.h = 0;
937 
938     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
939         sz_rfbFramebufferUpdateRectHeader);
940     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
941 
942     memset((char *)&msgs, 0, sz_rfbSupportedMessages);
943     rfbSetBit(msgs.client2server, rfbSetPixelFormat);
944     rfbSetBit(msgs.client2server, rfbFixColourMapEntries);
945     rfbSetBit(msgs.client2server, rfbSetEncodings);
946     rfbSetBit(msgs.client2server, rfbFramebufferUpdateRequest);
947     rfbSetBit(msgs.client2server, rfbKeyEvent);
948     rfbSetBit(msgs.client2server, rfbPointerEvent);
949     rfbSetBit(msgs.client2server, rfbClientCutText);
950     rfbSetBit(msgs.client2server, rfbFileTransfer);
951     rfbSetBit(msgs.client2server, rfbSetScale);
952     /*rfbSetBit(msgs.client2server, rfbSetServerInput);  */
953     /*rfbSetBit(msgs.client2server, rfbSetSW);           */
954     /*rfbSetBit(msgs.client2server, rfbTextChat);        */
955     rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
956     rfbSetBit(msgs.client2server, rfbXvp);
957 
958     rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
959     rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
960     rfbSetBit(msgs.server2client, rfbBell);
961     rfbSetBit(msgs.server2client, rfbServerCutText);
962     rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
963     rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
964     rfbSetBit(msgs.server2client, rfbXvp);
965 
966     memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
967     cl->ublen += sz_rfbSupportedMessages;
968 
969     rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
970         sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
971         sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
972     if (!rfbSendUpdateBuf(cl))
973         return FALSE;
974 
975     return TRUE;
976 }
977 
978 
979 
980 /*
981  * Send rfbEncodingSupportedEncodings.
982  */
983 
984 rfbBool
rfbSendSupportedEncodings(rfbClientPtr cl)985 rfbSendSupportedEncodings(rfbClientPtr cl)
986 {
987     rfbFramebufferUpdateRectHeader rect;
988     static uint32_t supported[] = {
989         rfbEncodingRaw,
990 	rfbEncodingCopyRect,
991 	rfbEncodingRRE,
992 	rfbEncodingCoRRE,
993 	rfbEncodingHextile,
994 #ifdef LIBVNCSERVER_HAVE_LIBZ
995 	rfbEncodingZlib,
996 	rfbEncodingZRLE,
997 	rfbEncodingZYWRLE,
998 #endif
999 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
1000 	rfbEncodingTight,
1001 #endif
1002 #ifdef LIBVNCSERVER_HAVE_LIBPNG
1003 	rfbEncodingTightPng,
1004 #endif
1005 	rfbEncodingUltra,
1006 	rfbEncodingUltraZip,
1007 	rfbEncodingXCursor,
1008 	rfbEncodingRichCursor,
1009 	rfbEncodingPointerPos,
1010 	rfbEncodingLastRect,
1011 	rfbEncodingNewFBSize,
1012 	rfbEncodingKeyboardLedState,
1013 	rfbEncodingSupportedMessages,
1014 	rfbEncodingSupportedEncodings,
1015 	rfbEncodingServerIdentity,
1016     };
1017     uint32_t nEncodings = sizeof(supported) / sizeof(supported[0]), i;
1018 
1019     /* think rfbSetEncodingsMsg */
1020 
1021     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1022                   + (nEncodings * sizeof(uint32_t)) > UPDATE_BUF_SIZE) {
1023         if (!rfbSendUpdateBuf(cl))
1024             return FALSE;
1025     }
1026 
1027     rect.encoding = Swap32IfLE(rfbEncodingSupportedEncodings);
1028     rect.r.x = 0;
1029     rect.r.y = 0;
1030     rect.r.w = Swap16IfLE(nEncodings * sizeof(uint32_t));
1031     rect.r.h = Swap16IfLE(nEncodings);
1032 
1033     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1034         sz_rfbFramebufferUpdateRectHeader);
1035     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1036 
1037     for (i = 0; i < nEncodings; i++) {
1038         uint32_t encoding = Swap32IfLE(supported[i]);
1039 	memcpy(&cl->updateBuf[cl->ublen], (char *)&encoding, sizeof(encoding));
1040 	cl->ublen += sizeof(encoding);
1041     }
1042 
1043     rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
1044         sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
1045         sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
1046 
1047     if (!rfbSendUpdateBuf(cl))
1048         return FALSE;
1049 
1050     return TRUE;
1051 }
1052 
1053 
1054 void
rfbSetServerVersionIdentity(rfbScreenInfoPtr screen,char * fmt,...)1055 rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...)
1056 {
1057     char buffer[256];
1058     va_list ap;
1059 
1060     va_start(ap, fmt);
1061     vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
1062     va_end(ap);
1063 
1064     if (screen->versionString!=NULL) free(screen->versionString);
1065     screen->versionString = strdup(buffer);
1066 }
1067 
1068 /*
1069  * Send rfbEncodingServerIdentity.
1070  */
1071 
1072 rfbBool
rfbSendServerIdentity(rfbClientPtr cl)1073 rfbSendServerIdentity(rfbClientPtr cl)
1074 {
1075     rfbFramebufferUpdateRectHeader rect;
1076     char buffer[512];
1077 
1078     /* tack on our library version */
1079     snprintf(buffer,sizeof(buffer)-1, "%s (%s)",
1080         (cl->screen->versionString==NULL ? "unknown" : cl->screen->versionString),
1081         LIBVNCSERVER_PACKAGE_STRING);
1082 
1083     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1084                   + (strlen(buffer)+1) > UPDATE_BUF_SIZE) {
1085         if (!rfbSendUpdateBuf(cl))
1086             return FALSE;
1087     }
1088 
1089     rect.encoding = Swap32IfLE(rfbEncodingServerIdentity);
1090     rect.r.x = 0;
1091     rect.r.y = 0;
1092     rect.r.w = Swap16IfLE(strlen(buffer)+1);
1093     rect.r.h = 0;
1094 
1095     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1096         sz_rfbFramebufferUpdateRectHeader);
1097     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1098 
1099     memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
1100     cl->ublen += strlen(buffer)+1;
1101 
1102     rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
1103         sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
1104         sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
1105 
1106 
1107     if (!rfbSendUpdateBuf(cl))
1108         return FALSE;
1109 
1110     return TRUE;
1111 }
1112 
1113 /*
1114  * Send an xvp server message
1115  */
1116 
1117 rfbBool
rfbSendXvp(rfbClientPtr cl,uint8_t version,uint8_t code)1118 rfbSendXvp(rfbClientPtr cl, uint8_t version, uint8_t code)
1119 {
1120     rfbXvpMsg xvp;
1121 
1122     xvp.type = rfbXvp;
1123     xvp.pad = 0;
1124     xvp.version = version;
1125     xvp.code = code;
1126 
1127     LOCK(cl->sendMutex);
1128     if (rfbWriteExact(cl, (char *)&xvp, sz_rfbXvpMsg) < 0) {
1129       rfbLogPerror("rfbSendXvp: write");
1130       rfbCloseClient(cl);
1131     }
1132     UNLOCK(cl->sendMutex);
1133 
1134     rfbStatRecordMessageSent(cl, rfbXvp, sz_rfbXvpMsg, sz_rfbXvpMsg);
1135 
1136     return TRUE;
1137 }
1138 
1139 
rfbSendTextChatMessage(rfbClientPtr cl,uint32_t length,char * buffer)1140 rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer)
1141 {
1142     rfbTextChatMsg tc;
1143     int bytesToSend=0;
1144 
1145     memset((char *)&tc, 0, sizeof(tc));
1146     tc.type = rfbTextChat;
1147     tc.length = Swap32IfLE(length);
1148 
1149     switch(length) {
1150     case rfbTextChatOpen:
1151     case rfbTextChatClose:
1152     case rfbTextChatFinished:
1153         bytesToSend=0;
1154         break;
1155     default:
1156         bytesToSend=length;
1157         if (bytesToSend>rfbTextMaxSize)
1158             bytesToSend=rfbTextMaxSize;
1159     }
1160 
1161     if (cl->ublen + sz_rfbTextChatMsg + bytesToSend > UPDATE_BUF_SIZE) {
1162         if (!rfbSendUpdateBuf(cl))
1163             return FALSE;
1164     }
1165 
1166     memcpy(&cl->updateBuf[cl->ublen], (char *)&tc, sz_rfbTextChatMsg);
1167     cl->ublen += sz_rfbTextChatMsg;
1168     if (bytesToSend>0) {
1169         memcpy(&cl->updateBuf[cl->ublen], buffer, bytesToSend);
1170         cl->ublen += bytesToSend;
1171     }
1172     rfbStatRecordMessageSent(cl, rfbTextChat, sz_rfbTextChatMsg+bytesToSend, sz_rfbTextChatMsg+bytesToSend);
1173 
1174     if (!rfbSendUpdateBuf(cl))
1175         return FALSE;
1176 
1177     return TRUE;
1178 }
1179 
1180 #define FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN(msg, cl, ret) \
1181 	if ((cl->screen->getFileTransferPermission != NULL \
1182 	    && cl->screen->getFileTransferPermission(cl) != TRUE) \
1183 	    || cl->screen->permitFileTransfer != TRUE) { \
1184 		rfbLog("%sUltra File Transfer is disabled, dropping client: %s\n", msg, cl->host); \
1185 		rfbCloseClient(cl); \
1186 		return ret; \
1187 	}
1188 
1189 int DB = 1;
1190 
rfbSendFileTransferMessage(rfbClientPtr cl,uint8_t contentType,uint8_t contentParam,uint32_t size,uint32_t length,const char * buffer)1191 rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, const char *buffer)
1192 {
1193     rfbFileTransferMsg ft;
1194     ft.type = rfbFileTransfer;
1195     ft.contentType = contentType;
1196     ft.contentParam = contentParam;
1197     ft.pad          = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */
1198     ft.size         = Swap32IfLE(size);
1199     ft.length       = Swap32IfLE(length);
1200 
1201     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1202     /*
1203     rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
1204     */
1205     LOCK(cl->sendMutex);
1206     if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
1207         rfbLogPerror("rfbSendFileTransferMessage: write");
1208         rfbCloseClient(cl);
1209         UNLOCK(cl->sendMutex);
1210         return FALSE;
1211     }
1212 
1213     if (length>0)
1214     {
1215         if (rfbWriteExact(cl, buffer, length) < 0) {
1216             rfbLogPerror("rfbSendFileTransferMessage: write");
1217             rfbCloseClient(cl);
1218             UNLOCK(cl->sendMutex);
1219             return FALSE;
1220         }
1221     }
1222     UNLOCK(cl->sendMutex);
1223 
1224     rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
1225 
1226     return TRUE;
1227 }
1228 
1229 
1230 /*
1231  * UltraVNC uses Windows Structures
1232  */
1233 #define MAX_PATH 260
1234 
1235 typedef struct {
1236     uint32_t dwLowDateTime;
1237     uint32_t dwHighDateTime;
1238 } RFB_FILETIME;
1239 
1240 typedef struct {
1241     uint32_t dwFileAttributes;
1242     RFB_FILETIME ftCreationTime;
1243     RFB_FILETIME ftLastAccessTime;
1244     RFB_FILETIME ftLastWriteTime;
1245     uint32_t nFileSizeHigh;
1246     uint32_t nFileSizeLow;
1247     uint32_t dwReserved0;
1248     uint32_t dwReserved1;
1249     uint8_t  cFileName[ MAX_PATH ];
1250     uint8_t  cAlternateFileName[ 14 ];
1251 } RFB_FIND_DATA;
1252 
1253 #define RFB_FILE_ATTRIBUTE_READONLY   0x1
1254 #define RFB_FILE_ATTRIBUTE_HIDDEN     0x2
1255 #define RFB_FILE_ATTRIBUTE_SYSTEM     0x4
1256 #define RFB_FILE_ATTRIBUTE_DIRECTORY  0x10
1257 #define RFB_FILE_ATTRIBUTE_ARCHIVE    0x20
1258 #define RFB_FILE_ATTRIBUTE_NORMAL     0x80
1259 #define RFB_FILE_ATTRIBUTE_TEMPORARY  0x100
1260 #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
1261 
rfbFilenameTranslate2UNIX(rfbClientPtr cl,char * path,char * unixPath,size_t unixPathMaxLen)1262 rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, /* in */ char *path, /* out */ char *unixPath, size_t unixPathMaxLen)
1263 {
1264     int x;
1265     char *home=NULL;
1266 
1267     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1268 
1269     /*
1270      * Do not use strncpy() - truncating the file name would probably have undesirable side effects
1271      * Instead check if destination buffer is big enough
1272      */
1273     if (strlen(path) >= unixPathMaxLen)
1274       return FALSE;
1275 
1276     /* C: */
1277     if (path[0]=='C' && path[1]==':')
1278       strcpy(unixPath, &path[2]);
1279     else
1280     {
1281       home = getenv("HOME");
1282       if (home!=NULL)
1283       {
1284         /* Re-check buffer size */
1285         if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen)
1286           return FALSE;
1287 
1288         strcpy(unixPath, home);
1289         strcat(unixPath,"/");
1290         strcat(unixPath, path);
1291       }
1292       else
1293         strcpy(unixPath, path);
1294     }
1295     for (x=0;x<strlen(unixPath);x++)
1296       if (unixPath[x]=='\\') unixPath[x]='/';
1297     return TRUE;
1298 }
1299 
rfbFilenameTranslate2DOS(rfbClientPtr cl,char * unixPath,char * path)1300 rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path)
1301 {
1302     int x;
1303 
1304     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1305 
1306     sprintf(path,"C:%s", unixPath);
1307     for (x=2;x<strlen(path);x++)
1308         if (path[x]=='/') path[x]='\\';
1309     return TRUE;
1310 }
1311 
rfbSendDirContent(rfbClientPtr cl,int length,char * buffer)1312 rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
1313 {
1314     char retfilename[MAX_PATH];
1315     char path[MAX_PATH];
1316     struct stat statbuf;
1317     RFB_FIND_DATA win32filename;
1318     int nOptLen = 0, retval=0;
1319 #ifdef WIN32
1320     WIN32_FIND_DATAA winFindData;
1321     HANDLE findHandle;
1322     int pathLen, basePathLength;
1323     char *basePath;
1324 #else
1325     DIR *dirp=NULL;
1326     struct dirent *direntp=NULL;
1327 #endif
1328 
1329     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1330 
1331     /* Client thinks we are Winblows */
1332     if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path)))
1333         return FALSE;
1334 
1335     if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
1336 
1337 #ifdef WIN32
1338     // Create a search string, like C:\folder\*
1339 
1340     pathLen = strlen(path);
1341     basePath = malloc(pathLen + 3);
1342     memcpy(basePath, path, pathLen);
1343     basePathLength = pathLen;
1344     basePath[basePathLength] = '\\';
1345     basePath[basePathLength + 1] = '*';
1346     basePath[basePathLength + 2] = '\0';
1347 
1348     // Start a search
1349     memset(&winFindData, 0, sizeof(winFindData));
1350     findHandle = FindFirstFileA(path, &winFindData);
1351     free(basePath);
1352 
1353     if (findHandle == INVALID_HANDLE_VALUE)
1354 #else
1355     dirp=opendir(path);
1356     if (dirp==NULL)
1357 #endif
1358         return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL);
1359 
1360     /* send back the path name (necessary for links) */
1361     if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE;
1362 
1363 #ifdef WIN32
1364     while (findHandle != INVALID_HANDLE_VALUE)
1365 #else
1366     for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp))
1367 #endif
1368     {
1369         /* get stats */
1370 #ifdef WIN32
1371     snprintf(retfilename,sizeof(retfilename),"%s/%s", path, winFindData.cFileName);
1372 #else
1373     snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name);
1374 #endif
1375         retval = stat(retfilename, &statbuf);
1376 
1377         if (retval==0)
1378         {
1379             memset((char *)&win32filename, 0, sizeof(win32filename));
1380 #ifdef WIN32
1381             win32filename.dwFileAttributes = winFindData.dwFileAttributes;
1382             win32filename.ftCreationTime.dwLowDateTime = winFindData.ftCreationTime.dwLowDateTime;
1383             win32filename.ftCreationTime.dwHighDateTime = winFindData.ftCreationTime.dwHighDateTime;
1384             win32filename.ftLastAccessTime.dwLowDateTime = winFindData.ftLastAccessTime.dwLowDateTime;
1385             win32filename.ftLastAccessTime.dwHighDateTime = winFindData.ftLastAccessTime.dwHighDateTime;
1386             win32filename.ftLastWriteTime.dwLowDateTime = winFindData.ftLastWriteTime.dwLowDateTime;
1387             win32filename.ftLastWriteTime.dwHighDateTime = winFindData.ftLastWriteTime.dwHighDateTime;
1388             win32filename.nFileSizeLow = winFindData.nFileSizeLow;
1389             win32filename.nFileSizeHigh = winFindData.nFileSizeHigh;
1390             win32filename.dwReserved0 = winFindData.dwReserved0;
1391             win32filename.dwReserved1 = winFindData.dwReserved1;
1392             strcpy((char *)win32filename.cFileName, winFindData.cFileName);
1393             strcpy((char *)win32filename.cAlternateFileName, winFindData.cAlternateFileName);
1394 #else
1395             win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_NORMAL);
1396             if (S_ISDIR(statbuf.st_mode))
1397                 win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_DIRECTORY);
1398             win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime);   /* Intel Order */
1399             win32filename.ftCreationTime.dwHighDateTime = 0;
1400             win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */
1401             win32filename.ftLastAccessTime.dwHighDateTime = 0;
1402             win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime);  /* Intel Order */
1403             win32filename.ftLastWriteTime.dwHighDateTime = 0;
1404             win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */
1405             win32filename.nFileSizeHigh = 0;
1406             win32filename.dwReserved0 = 0;
1407             win32filename.dwReserved1 = 0;
1408 
1409             /* If this had the full path, we would need to translate to DOS format ("C:\") */
1410             /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */
1411             strcpy((char *)win32filename.cFileName, direntp->d_name);
1412 #endif
1413 
1414             /* Do not show hidden files (but show how to move up the tree) */
1415             if ((strcmp((char *)win32filename.cFileName, "..")==0) || (win32filename.cFileName[0]!='.'))
1416             {
1417                 nOptLen = sizeof(RFB_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName);
1418                 /*
1419                 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName);
1420                 */
1421                 if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE)
1422                 {
1423 #ifdef WIN32
1424                     FindClose(findHandle);
1425 #else
1426                     closedir(dirp);
1427 #endif
1428                     return FALSE;
1429                 }
1430             }
1431         }
1432 
1433 #ifdef WIN32
1434         if (FindNextFileA(findHandle, &winFindData) == 0)
1435         {
1436             FindClose(findHandle);
1437             findHandle = INVALID_HANDLE_VALUE;
1438         }
1439 #endif
1440     }
1441 #ifdef WIN32
1442     if (findHandle != INVALID_HANDLE_VALUE)
1443     {
1444         FindClose(findHandle);
1445     }
1446 #else
1447     closedir(dirp);
1448 #endif
1449     /* End of the transfer */
1450     return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL);
1451 }
1452 
1453 
rfbProcessFileTransferReadBuffer(rfbClientPtr cl,uint32_t length)1454 char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length)
1455 {
1456     char *buffer=NULL;
1457     int   n=0;
1458 
1459     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL);
1460     /*
1461     rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length);
1462     */
1463     if (length>0) {
1464         buffer=malloc(length+1);
1465         if (buffer!=NULL) {
1466             if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) {
1467                 if (n != 0)
1468                     rfbLogPerror("rfbProcessFileTransferReadBuffer: read");
1469                 rfbCloseClient(cl);
1470                 /* NOTE: don't forget to free(buffer) if you return early! */
1471                 if (buffer!=NULL) free(buffer);
1472                 return NULL;
1473             }
1474             /* Null Terminate */
1475             buffer[length]=0;
1476         }
1477     }
1478     return buffer;
1479 }
1480 
1481 
rfbSendFileTransferChunk(rfbClientPtr cl)1482 rfbBool rfbSendFileTransferChunk(rfbClientPtr cl)
1483 {
1484     /* Allocate buffer for compression */
1485     unsigned char readBuf[sz_rfbBlockSize];
1486     int bytesRead=0;
1487     int retval=0;
1488     fd_set wfds;
1489     struct timeval tv;
1490     int n;
1491 #ifdef LIBVNCSERVER_HAVE_LIBZ
1492     unsigned char compBuf[sz_rfbBlockSize + 1024];
1493     unsigned long nMaxCompSize = sizeof(compBuf);
1494     int nRetC = 0;
1495 #endif
1496 
1497     /*
1498      * Don't close the client if we get into this one because
1499      * it is called from many places to service file transfers.
1500      * Note that permitFileTransfer is checked first.
1501      */
1502     if (cl->screen->permitFileTransfer != TRUE ||
1503        (cl->screen->getFileTransferPermission != NULL
1504         && cl->screen->getFileTransferPermission(cl) != TRUE)) {
1505 		return TRUE;
1506     }
1507 
1508     /* If not sending, or no file open...   Return as if we sent something! */
1509     if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
1510     {
1511 	FD_ZERO(&wfds);
1512         FD_SET(cl->sock, &wfds);
1513 
1514         /* return immediately */
1515 	tv.tv_sec = 0;
1516 	tv.tv_usec = 0;
1517 	n = select(cl->sock + 1, NULL, &wfds, NULL, &tv);
1518 
1519 	if (n<0) {
1520 #ifdef WIN32
1521 	    errno=WSAGetLastError();
1522 #endif
1523             rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno));
1524 	}
1525         /* We have space on the transmit queue */
1526 	if (n > 0)
1527 	{
1528             bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize);
1529             switch (bytesRead) {
1530             case 0:
1531                 /*
1532                 rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n");
1533                 */
1534                 retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL);
1535                 close(cl->fileTransfer.fd);
1536                 cl->fileTransfer.fd = -1;
1537                 cl->fileTransfer.sending   = 0;
1538                 cl->fileTransfer.receiving = 0;
1539                 return retval;
1540             case -1:
1541                 /* TODO : send an error msg to the client... */
1542 #ifdef WIN32
1543 	        errno=WSAGetLastError();
1544 #endif
1545                 rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno));
1546                 retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL);
1547                 close(cl->fileTransfer.fd);
1548                 cl->fileTransfer.fd = -1;
1549                 cl->fileTransfer.sending   = 0;
1550                 cl->fileTransfer.receiving = 0;
1551                 return retval;
1552             default:
1553                 /*
1554                 rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead);
1555                 */
1556                 if (!cl->fileTransfer.compressionEnabled)
1557                     return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1558                 else
1559                 {
1560 #ifdef LIBVNCSERVER_HAVE_LIBZ
1561                     nRetC = compress(compBuf, &nMaxCompSize, readBuf, bytesRead);
1562                     /*
1563                     rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead);
1564                     */
1565 
1566                     if ((nRetC==0) && (nMaxCompSize<bytesRead))
1567                         return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf);
1568                     else
1569                         return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1570 #else
1571                     /* We do not support compression of the data stream */
1572                     return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1573 #endif
1574                 }
1575             }
1576         }
1577     }
1578     return TRUE;
1579 }
1580 
rfbProcessFileTransfer(rfbClientPtr cl,uint8_t contentType,uint8_t contentParam,uint32_t size,uint32_t length)1581 rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length)
1582 {
1583     char *buffer=NULL, *p=NULL;
1584     int retval=0;
1585     char filename1[MAX_PATH];
1586     char filename2[MAX_PATH];
1587     char szFileTime[MAX_PATH];
1588     struct stat statbuf;
1589     uint32_t sizeHtmp=0;
1590     int n=0;
1591     char timespec[64];
1592 #ifdef LIBVNCSERVER_HAVE_LIBZ
1593     unsigned char compBuff[sz_rfbBlockSize];
1594     unsigned long nRawBytes = sz_rfbBlockSize;
1595     int nRet = 0;
1596 #endif
1597 
1598     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1599 
1600     /*
1601     rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length);
1602     */
1603 
1604     switch (contentType) {
1605     case rfbDirContentRequest:
1606         switch (contentParam) {
1607         case rfbRDrivesList: /* Client requests the List of Local Drives */
1608             /*
1609             rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n");
1610             */
1611             /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL>
1612              *
1613              * We replace the "\" char following the drive letter and ":"
1614              * with a char corresponding to the type of drive
1615              * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>"
1616              *  Isn't it ugly ?
1617              * DRIVE_FIXED = 'l'     (local?)
1618              * DRIVE_REMOVABLE = 'f' (floppy?)
1619              * DRIVE_CDROM = 'c'
1620              * DRIVE_REMOTE = 'n'
1621              */
1622 
1623             /* in unix, there are no 'drives'  (We could list mount points though)
1624              * We fake the root as a "C:" for the Winblows users
1625              */
1626             filename2[0]='C';
1627             filename2[1]=':';
1628             filename2[2]='l';
1629             filename2[3]=0;
1630             filename2[4]=0;
1631             retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2);
1632             if (buffer!=NULL) free(buffer);
1633             return retval;
1634             break;
1635         case rfbRDirContent: /* Client requests the content of a directory */
1636             /*
1637             rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n");
1638             */
1639             if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1640             retval = rfbSendDirContent(cl, length, buffer);
1641             if (buffer!=NULL) free(buffer);
1642             return retval;
1643         }
1644         break;
1645 
1646     case rfbDirPacket:
1647         rfbLog("rfbProcessFileTransfer() rfbDirPacket\n");
1648         break;
1649     case rfbFileAcceptHeader:
1650         rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n");
1651         break;
1652     case rfbCommandReturn:
1653         rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n");
1654         break;
1655     case rfbFileChecksums:
1656         /* Destination file already exists - the viewer sends the checksums */
1657         rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n");
1658         break;
1659     case rfbFileTransferAccess:
1660         rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n");
1661         break;
1662 
1663     /*
1664      * sending from the server to the viewer
1665      */
1666 
1667     case rfbFileTransferRequest:
1668         /*
1669         rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n");
1670         */
1671         /* add some space to the end of the buffer as we will be adding a timespec to it */
1672         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1673         /* The client requests a File */
1674         if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1675             goto fail;
1676         cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
1677 
1678         /*
1679         */
1680         if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), cl->fileTransfer.fd);
1681 
1682         if (cl->fileTransfer.fd!=-1) {
1683             if (fstat(cl->fileTransfer.fd, &statbuf)!=0) {
1684                 close(cl->fileTransfer.fd);
1685                 cl->fileTransfer.fd=-1;
1686             }
1687             else
1688             {
1689               /* Add the File Time Stamp to the filename */
1690               strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime));
1691               buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */
1692               if (buffer==NULL) {
1693                   rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2);
1694                   return FALSE;
1695               }
1696               strcat(buffer,",");
1697               strcat(buffer, timespec);
1698               length = strlen(buffer);
1699               if (DB) rfbLog("rfbProcessFileTransfer() buffer is now: \"%s\"\n", buffer);
1700             }
1701         }
1702 
1703         /* The viewer supports compression if size==1 */
1704         cl->fileTransfer.compressionEnabled = (size==1);
1705 
1706         /*
1707         rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":""));
1708         */
1709 
1710         /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1711         retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer);
1712 
1713         if (cl->fileTransfer.fd==-1)
1714         {
1715             if (buffer!=NULL) free(buffer);
1716             return retval;
1717         }
1718         /* setup filetransfer stuff */
1719         cl->fileTransfer.fileSize = statbuf.st_size;
1720         cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize;
1721         cl->fileTransfer.receiving = 0;
1722         cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */
1723 
1724         /* TODO: finish 64-bit file size support */
1725         sizeHtmp = 0;
1726         LOCK(cl->sendMutex);
1727         if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
1728           rfbLogPerror("rfbProcessFileTransfer: write");
1729           rfbCloseClient(cl);
1730           UNLOCK(cl->sendMutex);
1731           if (buffer!=NULL) free(buffer);
1732           return FALSE;
1733         }
1734         UNLOCK(cl->sendMutex);
1735         break;
1736 
1737     case rfbFileHeader:
1738         /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */
1739         if (size==-1) {
1740             rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n");
1741             close(cl->fileTransfer.fd);
1742             cl->fileTransfer.fd=-1;
1743             return TRUE;
1744         }
1745 
1746         /*
1747         rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size);
1748         */
1749 
1750         /* Starts the transfer! */
1751         cl->fileTransfer.sending=1;
1752         return rfbSendFileTransferChunk(cl);
1753         break;
1754 
1755 
1756     /*
1757      * sending from the viewer to the server
1758      */
1759 
1760     case rfbFileTransferOffer:
1761         /* client is sending a file to us */
1762         /* buffer contains full path name (plus FileTime) */
1763         /* size contains size of the file */
1764         /*
1765         rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n");
1766         */
1767         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1768 
1769         /* Parse the FileTime */
1770         p = strrchr(buffer, ',');
1771         if (p!=NULL) {
1772             *p = '\0';
1773             strncpy(szFileTime, p+1, sizeof(szFileTime));
1774             szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */
1775         } else
1776             szFileTime[0]=0;
1777 
1778 
1779 
1780         /* Need to read in sizeHtmp */
1781         if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
1782             if (n != 0)
1783                 rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp");
1784             rfbCloseClient(cl);
1785             /* NOTE: don't forget to free(buffer) if you return early! */
1786             if (buffer!=NULL) free(buffer);
1787             return FALSE;
1788         }
1789         sizeHtmp = Swap32IfLE(sizeHtmp);
1790 
1791         if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1792             goto fail;
1793 
1794         /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
1795         /* TODO: Delta Transfer */
1796 
1797         cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744);
1798         if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer(\"%s\"->\"%s\") %s %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), (cl->fileTransfer.fd==-1?strerror(errno):""), cl->fileTransfer.fd);
1799         /*
1800         */
1801 
1802         /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1803         retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer);
1804         if (cl->fileTransfer.fd==-1) {
1805             free(buffer);
1806             return retval;
1807         }
1808 
1809         /* setup filetransfer stuff */
1810         cl->fileTransfer.fileSize = size;
1811         cl->fileTransfer.numPackets = size / sz_rfbBlockSize;
1812         cl->fileTransfer.receiving = 1;
1813         cl->fileTransfer.sending = 0;
1814         break;
1815 
1816     case rfbFilePacket:
1817         /*
1818         rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n");
1819         */
1820         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1821         if (cl->fileTransfer.fd!=-1) {
1822             /* buffer contains the contents of the file */
1823             if (size==0)
1824                 retval=write(cl->fileTransfer.fd, buffer, length);
1825             else
1826             {
1827 #ifdef LIBVNCSERVER_HAVE_LIBZ
1828                 /* compressed packet */
1829                 nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length);
1830 		if(nRet == Z_OK)
1831 		  retval=write(cl->fileTransfer.fd, (char*)compBuff, nRawBytes);
1832 		else
1833 		  retval = -1;
1834 #else
1835                 /* Write the file out as received... */
1836                 retval=write(cl->fileTransfer.fd, buffer, length);
1837 #endif
1838             }
1839             if (retval==-1)
1840             {
1841                 close(cl->fileTransfer.fd);
1842                 cl->fileTransfer.fd=-1;
1843                 cl->fileTransfer.sending   = 0;
1844                 cl->fileTransfer.receiving = 0;
1845             }
1846         }
1847         break;
1848 
1849     case rfbEndOfFile:
1850         if (DB) rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n");
1851         /*
1852         */
1853         if (cl->fileTransfer.fd!=-1)
1854             close(cl->fileTransfer.fd);
1855         cl->fileTransfer.fd=-1;
1856         cl->fileTransfer.sending   = 0;
1857         cl->fileTransfer.receiving = 0;
1858         break;
1859 
1860     case rfbAbortFileTransfer:
1861         if (DB) rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n");
1862         /*
1863         */
1864         if (cl->fileTransfer.fd!=-1)
1865         {
1866             close(cl->fileTransfer.fd);
1867             cl->fileTransfer.fd=-1;
1868             cl->fileTransfer.sending   = 0;
1869             cl->fileTransfer.receiving = 0;
1870         }
1871         else
1872         {
1873             /* We use this message for FileTransfer rights (<=RC18 versions)
1874              * The client asks for FileTransfer permission
1875              */
1876             if (contentParam == 0)
1877             {
1878                 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED! (Client Version <=RC18)\n");
1879                 /* Old method for FileTransfer handshake perimssion (<=RC18) (Deny it)*/
1880                 return rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, -1, 0, "");
1881             }
1882             /* New method is allowed */
1883             if (cl->screen->getFileTransferPermission!=NULL)
1884             {
1885                 if (cl->screen->getFileTransferPermission(cl)==TRUE)
1886                 {
1887                     rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1888                     return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1889                 }
1890                 else
1891                 {
1892                     rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED!\n");
1893                     return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* Deny */
1894                 }
1895             }
1896             else
1897             {
1898                 if (cl->screen->permitFileTransfer)
1899                 {
1900                     rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1901                     return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1902                 }
1903                 else
1904                 {
1905                     rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED by default!\n");
1906                     return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* DEFAULT: DENY (for security) */
1907                 }
1908 
1909             }
1910         }
1911         break;
1912 
1913 
1914     case rfbCommand:
1915         /*
1916         rfbLog("rfbProcessFileTransfer() rfbCommand:\n");
1917         */
1918         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1919         switch (contentParam) {
1920         case rfbCDirCreate:  /* Client requests the creation of a directory */
1921             if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1922                 goto fail;
1923             retval = mkdir(filename1, 0755);
1924             if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
1925             /*
1926             */
1927             retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbADirCreate, retval, length, buffer);
1928             if (buffer!=NULL) free(buffer);
1929             return retval;
1930         case rfbCFileDelete: /* Client requests the deletion of a file */
1931             if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1932                 goto fail;
1933             if (stat(filename1,&statbuf)==0)
1934             {
1935                 if (S_ISDIR(statbuf.st_mode))
1936                     retval = rmdir(filename1);
1937                 else
1938                     retval = unlink(filename1);
1939             }
1940             else retval=-1;
1941             retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileDelete, retval, length, buffer);
1942             if (buffer!=NULL) free(buffer);
1943             return retval;
1944         case rfbCFileRename: /* Client requests the Renaming of a file/directory */
1945             p = strrchr(buffer, '*');
1946             if (p != NULL)
1947             {
1948                 /* Split into 2 filenames ('*' is a seperator) */
1949                 *p = '\0';
1950                 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1951                     goto fail;
1952                 if (!rfbFilenameTranslate2UNIX(cl, p+1,    filename2, sizeof(filename2)))
1953                     goto fail;
1954                 retval = rename(filename1,filename2);
1955                 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
1956                 /*
1957                 */
1958                 /* Restore the buffer so the reply is good */
1959                 *p = '*';
1960                 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileRename, retval, length, buffer);
1961                 if (buffer!=NULL) free(buffer);
1962                 return retval;
1963             }
1964             break;
1965         }
1966 
1967         break;
1968     }
1969 
1970     /* NOTE: don't forget to free(buffer) if you return early! */
1971     if (buffer!=NULL) free(buffer);
1972     return TRUE;
1973 
1974 fail:
1975     if (buffer!=NULL) free(buffer);
1976     return FALSE;
1977 }
1978 
1979 /*
1980  * rfbProcessClientNormalMessage is called when the client has sent a normal
1981  * protocol message.
1982  */
1983 
1984 static void
rfbProcessClientNormalMessage(rfbClientPtr cl)1985 rfbProcessClientNormalMessage(rfbClientPtr cl)
1986 {
1987     int n=0;
1988     rfbClientToServerMsg msg;
1989     char *str;
1990     int i;
1991     uint32_t enc=0;
1992     uint32_t lastPreferredEncoding = -1;
1993     char encBuf[64];
1994     char encBuf2[64];
1995 
1996 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
1997     if (cl->wsctx && webSocketCheckDisconnect(cl))
1998       return;
1999 #endif
2000 
2001     if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) {
2002         if (n != 0)
2003             rfbLogPerror("rfbProcessClientNormalMessage: read");
2004         rfbCloseClient(cl);
2005         return;
2006     }
2007 
2008     switch (msg.type) {
2009 
2010     case rfbSetPixelFormat:
2011 
2012         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2013                            sz_rfbSetPixelFormatMsg - 1)) <= 0) {
2014             if (n != 0)
2015                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2016             rfbCloseClient(cl);
2017             return;
2018         }
2019 
2020         cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
2021         cl->format.depth = msg.spf.format.depth;
2022         cl->format.bigEndian = (msg.spf.format.bigEndian ? TRUE : FALSE);
2023         cl->format.trueColour = (msg.spf.format.trueColour ? TRUE : FALSE);
2024         cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
2025         cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
2026         cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
2027         cl->format.redShift = msg.spf.format.redShift;
2028         cl->format.greenShift = msg.spf.format.greenShift;
2029         cl->format.blueShift = msg.spf.format.blueShift;
2030 
2031 	cl->readyForSetColourMapEntries = TRUE;
2032         cl->screen->setTranslateFunction(cl);
2033 
2034         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
2035 
2036         return;
2037 
2038 
2039     case rfbFixColourMapEntries:
2040         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2041                            sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
2042             if (n != 0)
2043                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2044             rfbCloseClient(cl);
2045             return;
2046         }
2047         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
2048         rfbLog("rfbProcessClientNormalMessage: %s",
2049                 "FixColourMapEntries unsupported\n");
2050         rfbCloseClient(cl);
2051         return;
2052 
2053 
2054     /* NOTE: Some clients send us a set of encodings (ie: PointerPos) designed to enable/disable features...
2055      * We may want to look into this...
2056      * Example:
2057      *     case rfbEncodingXCursor:
2058      *         cl->enableCursorShapeUpdates = TRUE;
2059      *
2060      * Currently: cl->enableCursorShapeUpdates can *never* be turned off...
2061      */
2062     case rfbSetEncodings:
2063     {
2064 
2065         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2066                            sz_rfbSetEncodingsMsg - 1)) <= 0) {
2067             if (n != 0)
2068                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2069             rfbCloseClient(cl);
2070             return;
2071         }
2072 
2073         msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
2074 
2075         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4),sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4));
2076 
2077         /*
2078          * UltraVNC Client has the ability to adapt to changing network environments
2079          * So, let's give it a change to tell us what it wants now!
2080          */
2081         if (cl->preferredEncoding!=-1)
2082             lastPreferredEncoding = cl->preferredEncoding;
2083 
2084         /* Reset all flags to defaults (allows us to switch between PointerPos and Server Drawn Cursors) */
2085         cl->preferredEncoding=-1;
2086         cl->useCopyRect              = FALSE;
2087         cl->useNewFBSize             = FALSE;
2088         cl->cursorWasChanged         = FALSE;
2089         cl->useRichCursorEncoding    = FALSE;
2090         cl->enableCursorPosUpdates   = FALSE;
2091         cl->enableCursorShapeUpdates = FALSE;
2092         cl->enableCursorShapeUpdates = FALSE;
2093         cl->enableLastRectEncoding   = FALSE;
2094         cl->enableKeyboardLedState   = FALSE;
2095         cl->enableSupportedMessages  = FALSE;
2096         cl->enableSupportedEncodings = FALSE;
2097         cl->enableServerIdentity     = FALSE;
2098 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
2099         cl->tightQualityLevel        = -1;
2100 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2101         cl->tightCompressLevel       = TIGHT_DEFAULT_COMPRESSION;
2102         cl->turboSubsampLevel        = TURBO_DEFAULT_SUBSAMP;
2103         cl->turboQualityLevel        = -1;
2104 #endif
2105 #endif
2106 
2107 
2108         for (i = 0; i < msg.se.nEncodings; i++) {
2109             if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) {
2110                 if (n != 0)
2111                     rfbLogPerror("rfbProcessClientNormalMessage: read");
2112                 rfbCloseClient(cl);
2113                 return;
2114             }
2115             enc = Swap32IfLE(enc);
2116 
2117             switch (enc) {
2118 
2119             case rfbEncodingCopyRect:
2120 		cl->useCopyRect = TRUE;
2121                 break;
2122             case rfbEncodingRaw:
2123             case rfbEncodingRRE:
2124             case rfbEncodingCoRRE:
2125             case rfbEncodingHextile:
2126             case rfbEncodingUltra:
2127 #ifdef LIBVNCSERVER_HAVE_LIBZ
2128 	    case rfbEncodingZlib:
2129             case rfbEncodingZRLE:
2130             case rfbEncodingZYWRLE:
2131 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2132 	    case rfbEncodingTight:
2133 #endif
2134 #endif
2135 #ifdef LIBVNCSERVER_HAVE_LIBPNG
2136 	    case rfbEncodingTightPng:
2137 #endif
2138             /* The first supported encoding is the 'preferred' encoding */
2139                 if (cl->preferredEncoding == -1)
2140                     cl->preferredEncoding = enc;
2141 
2142 
2143                 break;
2144 	    case rfbEncodingXCursor:
2145 		if(!cl->screen->dontConvertRichCursorToXCursor) {
2146 		    rfbLog("Enabling X-style cursor updates for client %s\n",
2147 			   cl->host);
2148 		    /* if cursor was drawn, hide the cursor */
2149 		    if(!cl->enableCursorShapeUpdates)
2150 		        rfbRedrawAfterHideCursor(cl,NULL);
2151 
2152 		    cl->enableCursorShapeUpdates = TRUE;
2153 		    cl->cursorWasChanged = TRUE;
2154 		}
2155 		break;
2156 	    case rfbEncodingRichCursor:
2157 	        rfbLog("Enabling full-color cursor updates for client %s\n",
2158 		       cl->host);
2159 		/* if cursor was drawn, hide the cursor */
2160 		if(!cl->enableCursorShapeUpdates)
2161 		    rfbRedrawAfterHideCursor(cl,NULL);
2162 
2163 	        cl->enableCursorShapeUpdates = TRUE;
2164 	        cl->useRichCursorEncoding = TRUE;
2165 	        cl->cursorWasChanged = TRUE;
2166 	        break;
2167 	    case rfbEncodingPointerPos:
2168 		if (!cl->enableCursorPosUpdates) {
2169 		    rfbLog("Enabling cursor position updates for client %s\n",
2170 			   cl->host);
2171 		    cl->enableCursorPosUpdates = TRUE;
2172 		    cl->cursorWasMoved = TRUE;
2173 		}
2174 	        break;
2175 	    case rfbEncodingLastRect:
2176 		if (!cl->enableLastRectEncoding) {
2177 		    rfbLog("Enabling LastRect protocol extension for client "
2178 			   "%s\n", cl->host);
2179 		    cl->enableLastRectEncoding = TRUE;
2180 		}
2181 		break;
2182 	    case rfbEncodingNewFBSize:
2183 		if (!cl->useNewFBSize) {
2184 		    rfbLog("Enabling NewFBSize protocol extension for client "
2185 			   "%s\n", cl->host);
2186 		    cl->useNewFBSize = TRUE;
2187 		}
2188 		break;
2189             case rfbEncodingKeyboardLedState:
2190                 if (!cl->enableKeyboardLedState) {
2191                   rfbLog("Enabling KeyboardLedState protocol extension for client "
2192                           "%s\n", cl->host);
2193                   cl->enableKeyboardLedState = TRUE;
2194                 }
2195                 break;
2196             case rfbEncodingSupportedMessages:
2197                 if (!cl->enableSupportedMessages) {
2198                   rfbLog("Enabling SupportedMessages protocol extension for client "
2199                           "%s\n", cl->host);
2200                   cl->enableSupportedMessages = TRUE;
2201                 }
2202                 break;
2203             case rfbEncodingSupportedEncodings:
2204                 if (!cl->enableSupportedEncodings) {
2205                   rfbLog("Enabling SupportedEncodings protocol extension for client "
2206                           "%s\n", cl->host);
2207                   cl->enableSupportedEncodings = TRUE;
2208                 }
2209                 break;
2210             case rfbEncodingServerIdentity:
2211                 if (!cl->enableServerIdentity) {
2212                   rfbLog("Enabling ServerIdentity protocol extension for client "
2213                           "%s\n", cl->host);
2214                   cl->enableServerIdentity = TRUE;
2215                 }
2216                 break;
2217 	    case rfbEncodingXvp:
2218 	        rfbLog("Enabling Xvp protocol extension for client "
2219 		        "%s\n", cl->host);
2220 		if (!rfbSendXvp(cl, 1, rfbXvp_Init)) {
2221 		  rfbCloseClient(cl);
2222 		  return;
2223 		}
2224                 break;
2225             default:
2226 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
2227 		if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
2228 		     enc <= (uint32_t)rfbEncodingCompressLevel9 ) {
2229 		    cl->zlibCompressLevel = enc & 0x0F;
2230 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2231 		    cl->tightCompressLevel = enc & 0x0F;
2232 		    rfbLog("Using compression level %d for client %s\n",
2233 			   cl->tightCompressLevel, cl->host);
2234 #endif
2235 		} else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
2236 			    enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
2237 		    cl->tightQualityLevel = enc & 0x0F;
2238 		    rfbLog("Using image quality level %d for client %s\n",
2239 			   cl->tightQualityLevel, cl->host);
2240 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2241 		    cl->turboQualityLevel = tight2turbo_qual[enc & 0x0F];
2242 		    cl->turboSubsampLevel = tight2turbo_subsamp[enc & 0x0F];
2243 		    rfbLog("Using JPEG subsampling %d, Q%d for client %s\n",
2244 			   cl->turboSubsampLevel, cl->turboQualityLevel, cl->host);
2245 		} else if ( enc >= (uint32_t)rfbEncodingFineQualityLevel0 + 1 &&
2246 			    enc <= (uint32_t)rfbEncodingFineQualityLevel100 ) {
2247 		    cl->turboQualityLevel = enc & 0xFF;
2248 		    rfbLog("Using fine quality level %d for client %s\n",
2249 			   cl->turboQualityLevel, cl->host);
2250 		} else if ( enc >= (uint32_t)rfbEncodingSubsamp1X &&
2251 			    enc <= (uint32_t)rfbEncodingSubsampGray ) {
2252 		    cl->turboSubsampLevel = enc & 0xFF;
2253 		    rfbLog("Using subsampling level %d for client %s\n",
2254 			   cl->turboSubsampLevel, cl->host);
2255 #endif
2256 		} else
2257 #endif
2258 		{
2259 			rfbExtensionData* e;
2260 			for(e = cl->extensions; e;) {
2261 				rfbExtensionData* next = e->next;
2262 				if(e->extension->enablePseudoEncoding &&
2263 					e->extension->enablePseudoEncoding(cl,
2264 						&e->data, (int)enc))
2265 					/* ext handles this encoding */
2266 					break;
2267 				e = next;
2268 			}
2269 			if(e == NULL) {
2270 				rfbBool handled = FALSE;
2271 				/* if the pseudo encoding is not handled by the
2272 				   enabled extensions, search through all
2273 				   extensions. */
2274 				rfbProtocolExtension* e;
2275 
2276 				for(e = rfbGetExtensionIterator(); e;) {
2277 					int* encs = e->pseudoEncodings;
2278 					while(encs && *encs!=0) {
2279 						if(*encs==(int)enc) {
2280 							void* data = NULL;
2281 							if(!e->enablePseudoEncoding(cl, &data, (int)enc)) {
2282 								rfbLog("Installed extension pretends to handle pseudo encoding 0x%x, but does not!\n",(int)enc);
2283 							} else {
2284 								rfbEnableExtension(cl, e, data);
2285 								handled = TRUE;
2286 								e = NULL;
2287 								break;
2288 							}
2289 						}
2290 						encs++;
2291 					}
2292 
2293 					if(e)
2294 						e = e->next;
2295 				}
2296 				rfbReleaseExtensionIterator();
2297 
2298 				if(!handled)
2299 					rfbLog("rfbProcessClientNormalMessage: "
2300 					    "ignoring unsupported encoding type %s\n",
2301 					    encodingName(enc,encBuf,sizeof(encBuf)));
2302 			}
2303 		}
2304             }
2305         }
2306 
2307 
2308 
2309         if (cl->preferredEncoding == -1) {
2310             if (lastPreferredEncoding==-1) {
2311                 cl->preferredEncoding = rfbEncodingRaw;
2312                 rfbLog("Defaulting to %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2313             }
2314             else {
2315                 cl->preferredEncoding = lastPreferredEncoding;
2316                 rfbLog("Sticking with %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2317             }
2318         }
2319         else
2320         {
2321           if (lastPreferredEncoding==-1) {
2322               rfbLog("Using %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2323           } else {
2324               rfbLog("Switching from %s to %s Encoding for client %s\n",
2325                   encodingName(lastPreferredEncoding,encBuf2,sizeof(encBuf2)),
2326                   encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)), cl->host);
2327           }
2328         }
2329 
2330 	if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
2331 	  rfbLog("Disabling cursor position updates for client %s\n",
2332 		 cl->host);
2333 	  cl->enableCursorPosUpdates = FALSE;
2334 	}
2335 
2336         return;
2337     }
2338 
2339 
2340     case rfbFramebufferUpdateRequest:
2341     {
2342         sraRegionPtr tmpRegion;
2343 
2344         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2345                            sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
2346             if (n != 0)
2347                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2348             rfbCloseClient(cl);
2349             return;
2350         }
2351 
2352         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg);
2353 
2354         /* The values come in based on the scaled screen, we need to convert them to
2355          * values based on the main screen's coordinate system
2356          */
2357 	if(!rectSwapIfLEAndClip(&msg.fur.x,&msg.fur.y,&msg.fur.w,&msg.fur.h,cl))
2358 	{
2359 	        rfbLog("Warning, ignoring rfbFramebufferUpdateRequest: %dXx%dY-%dWx%dH\n",msg.fur.x, msg.fur.y, msg.fur.w, msg.fur.h);
2360 		return;
2361         }
2362 
2363 
2364 	tmpRegion =
2365 	  sraRgnCreateRect(msg.fur.x,
2366 			   msg.fur.y,
2367 			   msg.fur.x+msg.fur.w,
2368 			   msg.fur.y+msg.fur.h);
2369 
2370         LOCK(cl->updateMutex);
2371 	sraRgnOr(cl->requestedRegion,tmpRegion);
2372 
2373 	if (!cl->readyForSetColourMapEntries) {
2374 	    /* client hasn't sent a SetPixelFormat so is using server's */
2375 	    cl->readyForSetColourMapEntries = TRUE;
2376 	    if (!cl->format.trueColour) {
2377 		if (!rfbSetClientColourMap(cl, 0, 0)) {
2378 		    sraRgnDestroy(tmpRegion);
2379 		    TSIGNAL(cl->updateCond);
2380 		    UNLOCK(cl->updateMutex);
2381 		    return;
2382 		}
2383 	    }
2384 	}
2385 
2386        if (!msg.fur.incremental) {
2387 	    sraRgnOr(cl->modifiedRegion,tmpRegion);
2388 	    sraRgnSubtract(cl->copyRegion,tmpRegion);
2389        }
2390        TSIGNAL(cl->updateCond);
2391        UNLOCK(cl->updateMutex);
2392 
2393        sraRgnDestroy(tmpRegion);
2394 
2395        return;
2396     }
2397 
2398     case rfbKeyEvent:
2399 
2400 	if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2401 			   sz_rfbKeyEventMsg - 1)) <= 0) {
2402 	    if (n != 0)
2403 		rfbLogPerror("rfbProcessClientNormalMessage: read");
2404 	    rfbCloseClient(cl);
2405 	    return;
2406 	}
2407 
2408 	rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);
2409 
2410 	if(!cl->viewOnly) {
2411 	    cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
2412 	}
2413 
2414         return;
2415 
2416 
2417     case rfbPointerEvent:
2418 
2419 	if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2420 			   sz_rfbPointerEventMsg - 1)) <= 0) {
2421 	    if (n != 0)
2422 		rfbLogPerror("rfbProcessClientNormalMessage: read");
2423 	    rfbCloseClient(cl);
2424 	    return;
2425 	}
2426 
2427 	rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg);
2428 
2429 	if (cl->screen->pointerClient && cl->screen->pointerClient != cl)
2430 	    return;
2431 
2432 	if (msg.pe.buttonMask == 0)
2433 	    cl->screen->pointerClient = NULL;
2434 	else
2435 	    cl->screen->pointerClient = cl;
2436 
2437 	if(!cl->viewOnly) {
2438 	    if (msg.pe.buttonMask != cl->lastPtrButtons ||
2439 		    cl->screen->deferPtrUpdateTime == 0) {
2440 		cl->screen->ptrAddEvent(msg.pe.buttonMask,
2441 			ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x)),
2442 			ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y)),
2443 			cl);
2444 		cl->lastPtrButtons = msg.pe.buttonMask;
2445 	    } else {
2446 		cl->lastPtrX = ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x));
2447 		cl->lastPtrY = ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y));
2448 		cl->lastPtrButtons = msg.pe.buttonMask;
2449 	    }
2450       }
2451       return;
2452 
2453 
2454     case rfbFileTransfer:
2455         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2456                               sz_rfbFileTransferMsg - 1)) <= 0) {
2457             if (n != 0)
2458                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2459             rfbCloseClient(cl);
2460             return;
2461         }
2462         msg.ft.size         = Swap32IfLE(msg.ft.size);
2463         msg.ft.length       = Swap32IfLE(msg.ft.length);
2464         /* record statistics in rfbProcessFileTransfer as length is filled with garbage when it is not valid */
2465         rfbProcessFileTransfer(cl, msg.ft.contentType, msg.ft.contentParam, msg.ft.size, msg.ft.length);
2466         return;
2467 
2468     case rfbSetSW:
2469         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2470                               sz_rfbSetSWMsg - 1)) <= 0) {
2471             if (n != 0)
2472                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2473             rfbCloseClient(cl);
2474             return;
2475         }
2476         msg.sw.x = Swap16IfLE(msg.sw.x);
2477         msg.sw.y = Swap16IfLE(msg.sw.y);
2478         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetSWMsg, sz_rfbSetSWMsg);
2479         /* msg.sw.status is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2480 
2481         rfbLog("Received a rfbSetSingleWindow(%d x, %d y)\n", msg.sw.x, msg.sw.y);
2482         if (cl->screen->setSingleWindow!=NULL)
2483             cl->screen->setSingleWindow(cl, msg.sw.x, msg.sw.y);
2484         return;
2485 
2486     case rfbSetServerInput:
2487         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2488                               sz_rfbSetServerInputMsg - 1)) <= 0) {
2489             if (n != 0)
2490                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2491             rfbCloseClient(cl);
2492             return;
2493         }
2494         rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetServerInputMsg, sz_rfbSetServerInputMsg);
2495 
2496         /* msg.sim.pad is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2497         /* msg.sim.pad = Swap16IfLE(msg.sim.pad); */
2498 
2499         rfbLog("Received a rfbSetServerInput(%d status)\n", msg.sim.status);
2500         if (cl->screen->setServerInput!=NULL)
2501             cl->screen->setServerInput(cl, msg.sim.status);
2502         return;
2503 
2504     case rfbTextChat:
2505         if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2506                               sz_rfbTextChatMsg - 1)) <= 0) {
2507             if (n != 0)
2508                 rfbLogPerror("rfbProcessClientNormalMessage: read");
2509             rfbCloseClient(cl);
2510             return;
2511         }
2512 
2513         msg.tc.pad2   = Swap16IfLE(msg.tc.pad2);
2514         msg.tc.length = Swap32IfLE(msg.tc.length);
2515 
2516         switch (msg.tc.length) {
2517         case rfbTextChatOpen:
2518         case rfbTextChatClose:
2519         case rfbTextChatFinished:
2520             /* commands do not have text following */
2521             /* Why couldn't they have used the pad byte??? */
2522             str=NULL;
2523             rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg, sz_rfbTextChatMsg);
2524             break;
2525         default:
2526             if ((msg.tc.length>0) && (msg.tc.length<rfbTextMaxSize))
2527             {
2528                 str = (char *)malloc(msg.tc.length);
2529                 if (str==NULL)
2530                 {
2531                     rfbLog("Unable to malloc %d bytes for a TextChat Message\n", msg.tc.length);
2532                     rfbCloseClient(cl);
2533                     return;
2534                 }
2535                 if ((n = rfbReadExact(cl, str, msg.tc.length)) <= 0) {
2536                     if (n != 0)
2537                         rfbLogPerror("rfbProcessClientNormalMessage: read");
2538                     free(str);
2539                     rfbCloseClient(cl);
2540                     return;
2541                 }
2542                 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg+msg.tc.length, sz_rfbTextChatMsg+msg.tc.length);
2543             }
2544             else
2545             {
2546                 /* This should never happen */
2547                 rfbLog("client sent us a Text Message that is too big %d>%d\n", msg.tc.length, rfbTextMaxSize);
2548                 rfbCloseClient(cl);
2549                 return;
2550             }
2551         }
2552 
2553         /* Note: length can be commands: rfbTextChatOpen, rfbTextChatClose, and rfbTextChatFinished
2554          * at which point, the str is NULL (as it is not sent)
2555          */
2556         if (cl->screen->setTextChat!=NULL)
2557             cl->screen->setTextChat(cl, msg.tc.length, str);
2558 
2559         free(str);
2560         return;
2561 
2562 
2563     case rfbClientCutText:
2564 
2565 	if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2566 			   sz_rfbClientCutTextMsg - 1)) <= 0) {
2567 	    if (n != 0)
2568 		rfbLogPerror("rfbProcessClientNormalMessage: read");
2569 	    rfbCloseClient(cl);
2570 	    return;
2571 	}
2572 
2573 	msg.cct.length = Swap32IfLE(msg.cct.length);
2574 
2575 	str = (char *)malloc(msg.cct.length);
2576 	if (str == NULL) {
2577 		rfbLogPerror("rfbProcessClientNormalMessage: not enough memory");
2578 		rfbCloseClient(cl);
2579 		return;
2580 	}
2581 
2582 	if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) {
2583 	    if (n != 0)
2584 	        rfbLogPerror("rfbProcessClientNormalMessage: read");
2585 	    free(str);
2586 	    rfbCloseClient(cl);
2587 	    return;
2588 	}
2589 	rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length);
2590 	if(!cl->viewOnly) {
2591 	    cl->screen->setXCutText(str, msg.cct.length, cl);
2592 	}
2593 	free(str);
2594 
2595         return;
2596 
2597     case rfbPalmVNCSetScaleFactor:
2598       cl->PalmVNC = TRUE;
2599       if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2600           sz_rfbSetScaleMsg - 1)) <= 0) {
2601           if (n != 0)
2602             rfbLogPerror("rfbProcessClientNormalMessage: read");
2603           rfbCloseClient(cl);
2604           return;
2605       }
2606 
2607       if (msg.ssc.scale == 0) {
2608           rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
2609           rfbCloseClient(cl);
2610           return;
2611       }
2612 
2613       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2614       rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2615       rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2616 
2617       rfbSendNewScaleSize(cl);
2618       return;
2619 
2620     case rfbSetScale:
2621 
2622       if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2623           sz_rfbSetScaleMsg - 1)) <= 0) {
2624           if (n != 0)
2625             rfbLogPerror("rfbProcessClientNormalMessage: read");
2626           rfbCloseClient(cl);
2627           return;
2628       }
2629 
2630       if (msg.ssc.scale == 0) {
2631           rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
2632           rfbCloseClient(cl);
2633           return;
2634       }
2635 
2636       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2637       rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2638       rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2639 
2640       rfbSendNewScaleSize(cl);
2641       return;
2642 
2643     case rfbXvp:
2644 
2645       if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2646           sz_rfbXvpMsg - 1)) <= 0) {
2647           if (n != 0)
2648             rfbLogPerror("rfbProcessClientNormalMessage: read");
2649           rfbCloseClient(cl);
2650           return;
2651       }
2652       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbXvpMsg, sz_rfbXvpMsg);
2653 
2654       /* only version when is defined, so echo back a fail */
2655       if(msg.xvp.version != 1) {
2656 	rfbSendXvp(cl, msg.xvp.version, rfbXvp_Fail);
2657       }
2658       else {
2659 	/* if the hook exists and fails, send a fail msg */
2660 	if(cl->screen->xvpHook && !cl->screen->xvpHook(cl, msg.xvp.version, msg.xvp.code))
2661 	  rfbSendXvp(cl, 1, rfbXvp_Fail);
2662       }
2663       return;
2664 
2665     default:
2666 	{
2667 	    rfbExtensionData *e,*next;
2668 
2669 	    for(e=cl->extensions; e;) {
2670 		next = e->next;
2671 		if(e->extension->handleMessage &&
2672 			e->extension->handleMessage(cl, e->data, &msg))
2673                 {
2674                     rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */
2675 		    return;
2676                 }
2677 		e = next;
2678 	    }
2679 
2680 	    rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
2681 		    msg.type);
2682 	    rfbLog(" ... closing connection\n");
2683 	    rfbCloseClient(cl);
2684 	    return;
2685 	}
2686     }
2687 }
2688 
2689 
2690 
2691 /*
2692  * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
2693  * the RFB client.
2694  * givenUpdateRegion is not changed.
2695  */
2696 
2697 rfbBool
rfbSendFramebufferUpdate(rfbClientPtr cl,sraRegionPtr givenUpdateRegion)2698 rfbSendFramebufferUpdate(rfbClientPtr cl,
2699                          sraRegionPtr givenUpdateRegion)
2700 {
2701     sraRectangleIterator* i=NULL;
2702     sraRect rect;
2703     int nUpdateRegionRects;
2704     rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf;
2705     sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
2706     int dx, dy;
2707     rfbBool sendCursorShape = FALSE;
2708     rfbBool sendCursorPos = FALSE;
2709     rfbBool sendKeyboardLedState = FALSE;
2710     rfbBool sendSupportedMessages = FALSE;
2711     rfbBool sendSupportedEncodings = FALSE;
2712     rfbBool sendServerIdentity = FALSE;
2713     rfbBool result = TRUE;
2714 
2715 
2716     if(cl->screen->displayHook)
2717       cl->screen->displayHook(cl);
2718 
2719     /*
2720      * If framebuffer size was changed and the client supports NewFBSize
2721      * encoding, just send NewFBSize marker and return.
2722      */
2723 
2724     if (cl->useNewFBSize && cl->newFBSizePending) {
2725       LOCK(cl->updateMutex);
2726       cl->newFBSizePending = FALSE;
2727       UNLOCK(cl->updateMutex);
2728       fu->type = rfbFramebufferUpdate;
2729       fu->nRects = Swap16IfLE(1);
2730       cl->ublen = sz_rfbFramebufferUpdateMsg;
2731       if (!rfbSendNewFBSize(cl, cl->scaledScreen->width, cl->scaledScreen->height)) {
2732 	if(cl->screen->displayFinishedHook)
2733 	  cl->screen->displayFinishedHook(cl, FALSE);
2734         return FALSE;
2735       }
2736       result = rfbSendUpdateBuf(cl);
2737       if(cl->screen->displayFinishedHook)
2738 	cl->screen->displayFinishedHook(cl, result);
2739       return result;
2740     }
2741 
2742     /*
2743      * If this client understands cursor shape updates, cursor should be
2744      * removed from the framebuffer. Otherwise, make sure it's put up.
2745      */
2746 
2747     if (cl->enableCursorShapeUpdates) {
2748       if (cl->cursorWasChanged && cl->readyForSetColourMapEntries)
2749 	  sendCursorShape = TRUE;
2750     }
2751 
2752     /*
2753      * Do we plan to send cursor position update?
2754      */
2755 
2756     if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
2757       sendCursorPos = TRUE;
2758 
2759     /*
2760      * Do we plan to send a keyboard state update?
2761      */
2762     if ((cl->enableKeyboardLedState) &&
2763 	(cl->screen->getKeyboardLedStateHook!=NULL))
2764     {
2765         int x;
2766         x=cl->screen->getKeyboardLedStateHook(cl->screen);
2767         if (x!=cl->lastKeyboardLedState)
2768         {
2769             sendKeyboardLedState = TRUE;
2770             cl->lastKeyboardLedState=x;
2771         }
2772     }
2773 
2774     /*
2775      * Do we plan to send a rfbEncodingSupportedMessages?
2776      */
2777     if (cl->enableSupportedMessages)
2778     {
2779         sendSupportedMessages = TRUE;
2780         /* We only send this message ONCE <per setEncodings message received>
2781          * (We disable it here)
2782          */
2783         cl->enableSupportedMessages = FALSE;
2784     }
2785     /*
2786      * Do we plan to send a rfbEncodingSupportedEncodings?
2787      */
2788     if (cl->enableSupportedEncodings)
2789     {
2790         sendSupportedEncodings = TRUE;
2791         /* We only send this message ONCE <per setEncodings message received>
2792          * (We disable it here)
2793          */
2794         cl->enableSupportedEncodings = FALSE;
2795     }
2796     /*
2797      * Do we plan to send a rfbEncodingServerIdentity?
2798      */
2799     if (cl->enableServerIdentity)
2800     {
2801         sendServerIdentity = TRUE;
2802         /* We only send this message ONCE <per setEncodings message received>
2803          * (We disable it here)
2804          */
2805         cl->enableServerIdentity = FALSE;
2806     }
2807 
2808     LOCK(cl->updateMutex);
2809 
2810     /*
2811      * The modifiedRegion may overlap the destination copyRegion.  We remove
2812      * any overlapping bits from the copyRegion (since they'd only be
2813      * overwritten anyway).
2814      */
2815 
2816     sraRgnSubtract(cl->copyRegion,cl->modifiedRegion);
2817 
2818     /*
2819      * The client is interested in the region requestedRegion.  The region
2820      * which should be updated now is the intersection of requestedRegion
2821      * and the union of modifiedRegion and copyRegion.  If it's empty then
2822      * no update is needed.
2823      */
2824 
2825     updateRegion = sraRgnCreateRgn(givenUpdateRegion);
2826     if(cl->screen->progressiveSliceHeight>0) {
2827 	    int height=cl->screen->progressiveSliceHeight,
2828 	    	y=cl->progressiveSliceY;
2829 	    sraRegionPtr bbox=sraRgnBBox(updateRegion);
2830 	    sraRect rect;
2831 	    if(sraRgnPopRect(bbox,&rect,0)) {
2832 		sraRegionPtr slice;
2833 		if(y<rect.y1 || y>=rect.y2)
2834 		    y=rect.y1;
2835 	    	slice=sraRgnCreateRect(0,y,cl->screen->width,y+height);
2836 		sraRgnAnd(updateRegion,slice);
2837 		sraRgnDestroy(slice);
2838 	    }
2839 	    sraRgnDestroy(bbox);
2840 	    y+=height;
2841 	    if(y>=cl->screen->height)
2842 		    y=0;
2843 	    cl->progressiveSliceY=y;
2844     }
2845 
2846     sraRgnOr(updateRegion,cl->copyRegion);
2847     if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
2848        sraRgnEmpty(updateRegion) &&
2849        (cl->enableCursorShapeUpdates ||
2850 	(cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) &&
2851        !sendCursorShape && !sendCursorPos && !sendKeyboardLedState &&
2852        !sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) {
2853       sraRgnDestroy(updateRegion);
2854       UNLOCK(cl->updateMutex);
2855       if(cl->screen->displayFinishedHook)
2856 	cl->screen->displayFinishedHook(cl, TRUE);
2857       return TRUE;
2858     }
2859 
2860     /*
2861      * We assume that the client doesn't have any pixel data outside the
2862      * requestedRegion.  In other words, both the source and destination of a
2863      * copy must lie within requestedRegion.  So the region we can send as a
2864      * copy is the intersection of the copyRegion with both the requestedRegion
2865      * and the requestedRegion translated by the amount of the copy.  We set
2866      * updateCopyRegion to this.
2867      */
2868 
2869     updateCopyRegion = sraRgnCreateRgn(cl->copyRegion);
2870     sraRgnAnd(updateCopyRegion,cl->requestedRegion);
2871     tmpRegion = sraRgnCreateRgn(cl->requestedRegion);
2872     sraRgnOffset(tmpRegion,cl->copyDX,cl->copyDY);
2873     sraRgnAnd(updateCopyRegion,tmpRegion);
2874     sraRgnDestroy(tmpRegion);
2875     dx = cl->copyDX;
2876     dy = cl->copyDY;
2877 
2878     /*
2879      * Next we remove updateCopyRegion from updateRegion so that updateRegion
2880      * is the part of this update which is sent as ordinary pixel data (i.e not
2881      * a copy).
2882      */
2883 
2884     sraRgnSubtract(updateRegion,updateCopyRegion);
2885 
2886     /*
2887      * Finally we leave modifiedRegion to be the remainder (if any) of parts of
2888      * the screen which are modified but outside the requestedRegion.  We also
2889      * empty both the requestedRegion and the copyRegion - note that we never
2890      * carry over a copyRegion for a future update.
2891      */
2892 
2893      sraRgnOr(cl->modifiedRegion,cl->copyRegion);
2894      sraRgnSubtract(cl->modifiedRegion,updateRegion);
2895      sraRgnSubtract(cl->modifiedRegion,updateCopyRegion);
2896 
2897      sraRgnMakeEmpty(cl->requestedRegion);
2898      sraRgnMakeEmpty(cl->copyRegion);
2899      cl->copyDX = 0;
2900      cl->copyDY = 0;
2901 
2902      UNLOCK(cl->updateMutex);
2903 
2904     if (!cl->enableCursorShapeUpdates) {
2905       if(cl->cursorX != cl->screen->cursorX || cl->cursorY != cl->screen->cursorY) {
2906 	rfbRedrawAfterHideCursor(cl,updateRegion);
2907 	LOCK(cl->screen->cursorMutex);
2908 	cl->cursorX = cl->screen->cursorX;
2909 	cl->cursorY = cl->screen->cursorY;
2910 	UNLOCK(cl->screen->cursorMutex);
2911 	rfbRedrawAfterHideCursor(cl,updateRegion);
2912       }
2913       rfbShowCursor(cl);
2914     }
2915 
2916     /*
2917      * Now send the update.
2918      */
2919 
2920     rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0);
2921     if (cl->preferredEncoding == rfbEncodingCoRRE) {
2922         nUpdateRegionRects = 0;
2923 
2924         for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2925             int x = rect.x1;
2926             int y = rect.y1;
2927             int w = rect.x2 - x;
2928             int h = rect.y2 - y;
2929 	    int rectsPerRow, rows;
2930             /* We need to count the number of rects in the scaled screen */
2931             if (cl->screen!=cl->scaledScreen)
2932                 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2933 	    rectsPerRow = (w-1)/cl->correMaxWidth+1;
2934 	    rows = (h-1)/cl->correMaxHeight+1;
2935 	    nUpdateRegionRects += rectsPerRow*rows;
2936         }
2937 	sraRgnReleaseIterator(i); i=NULL;
2938     } else if (cl->preferredEncoding == rfbEncodingUltra) {
2939         nUpdateRegionRects = 0;
2940 
2941         for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2942             int x = rect.x1;
2943             int y = rect.y1;
2944             int w = rect.x2 - x;
2945             int h = rect.y2 - y;
2946             /* We need to count the number of rects in the scaled screen */
2947             if (cl->screen!=cl->scaledScreen)
2948                 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2949             nUpdateRegionRects += (((h-1) / (ULTRA_MAX_SIZE( w ) / w)) + 1);
2950           }
2951         sraRgnReleaseIterator(i); i=NULL;
2952 #ifdef LIBVNCSERVER_HAVE_LIBZ
2953     } else if (cl->preferredEncoding == rfbEncodingZlib) {
2954 	nUpdateRegionRects = 0;
2955 
2956         for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2957             int x = rect.x1;
2958             int y = rect.y1;
2959             int w = rect.x2 - x;
2960             int h = rect.y2 - y;
2961             /* We need to count the number of rects in the scaled screen */
2962             if (cl->screen!=cl->scaledScreen)
2963                 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2964 	    nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
2965 	}
2966 	sraRgnReleaseIterator(i); i=NULL;
2967 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2968     } else if (cl->preferredEncoding == rfbEncodingTight) {
2969 	nUpdateRegionRects = 0;
2970 
2971         for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2972             int x = rect.x1;
2973             int y = rect.y1;
2974             int w = rect.x2 - x;
2975             int h = rect.y2 - y;
2976             int n;
2977             /* We need to count the number of rects in the scaled screen */
2978             if (cl->screen!=cl->scaledScreen)
2979                 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2980 	    n = rfbNumCodedRectsTight(cl, x, y, w, h);
2981 	    if (n == 0) {
2982 		nUpdateRegionRects = 0xFFFF;
2983 		break;
2984 	    }
2985 	    nUpdateRegionRects += n;
2986 	}
2987 	sraRgnReleaseIterator(i); i=NULL;
2988 #endif
2989 #endif
2990 #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && defined(LIBVNCSERVER_HAVE_LIBPNG)
2991     } else if (cl->preferredEncoding == rfbEncodingTightPng) {
2992 	nUpdateRegionRects = 0;
2993 
2994         for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2995             int x = rect.x1;
2996             int y = rect.y1;
2997             int w = rect.x2 - x;
2998             int h = rect.y2 - y;
2999             int n;
3000             /* We need to count the number of rects in the scaled screen */
3001             if (cl->screen!=cl->scaledScreen)
3002                 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
3003 	    n = rfbNumCodedRectsTight(cl, x, y, w, h);
3004 	    if (n == 0) {
3005 		nUpdateRegionRects = 0xFFFF;
3006 		break;
3007 	    }
3008 	    nUpdateRegionRects += n;
3009 	}
3010 	sraRgnReleaseIterator(i); i=NULL;
3011 #endif
3012     } else {
3013         nUpdateRegionRects = sraRgnCountRects(updateRegion);
3014     }
3015 
3016     fu->type = rfbFramebufferUpdate;
3017     if (nUpdateRegionRects != 0xFFFF) {
3018 	if(cl->screen->maxRectsPerUpdate>0
3019 	   /* CoRRE splits the screen into smaller squares */
3020 	   && cl->preferredEncoding != rfbEncodingCoRRE
3021 	   /* Ultra encoding splits rectangles up into smaller chunks */
3022            && cl->preferredEncoding != rfbEncodingUltra
3023 #ifdef LIBVNCSERVER_HAVE_LIBZ
3024 	   /* Zlib encoding splits rectangles up into smaller chunks */
3025 	   && cl->preferredEncoding != rfbEncodingZlib
3026 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
3027 	   /* Tight encoding counts the rectangles differently */
3028 	   && cl->preferredEncoding != rfbEncodingTight
3029 #endif
3030 #endif
3031 #ifdef LIBVNCSERVER_HAVE_LIBPNG
3032 	   /* Tight encoding counts the rectangles differently */
3033 	   && cl->preferredEncoding != rfbEncodingTightPng
3034 #endif
3035 	   && nUpdateRegionRects>cl->screen->maxRectsPerUpdate) {
3036 	    sraRegion* newUpdateRegion = sraRgnBBox(updateRegion);
3037 	    sraRgnDestroy(updateRegion);
3038 	    updateRegion = newUpdateRegion;
3039 	    nUpdateRegionRects = sraRgnCountRects(updateRegion);
3040 	}
3041 	fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) +
3042 					   nUpdateRegionRects +
3043 					   !!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState +
3044 					   !!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity));
3045     } else {
3046 	fu->nRects = 0xFFFF;
3047     }
3048     cl->ublen = sz_rfbFramebufferUpdateMsg;
3049 
3050    if (sendCursorShape) {
3051 	cl->cursorWasChanged = FALSE;
3052 	if (!rfbSendCursorShape(cl))
3053 	    goto updateFailed;
3054     }
3055 
3056    if (sendCursorPos) {
3057 	cl->cursorWasMoved = FALSE;
3058 	if (!rfbSendCursorPos(cl))
3059 	        goto updateFailed;
3060    }
3061 
3062    if (sendKeyboardLedState) {
3063        if (!rfbSendKeyboardLedState(cl))
3064            goto updateFailed;
3065    }
3066 
3067    if (sendSupportedMessages) {
3068        if (!rfbSendSupportedMessages(cl))
3069            goto updateFailed;
3070    }
3071    if (sendSupportedEncodings) {
3072        if (!rfbSendSupportedEncodings(cl))
3073            goto updateFailed;
3074    }
3075    if (sendServerIdentity) {
3076        if (!rfbSendServerIdentity(cl))
3077            goto updateFailed;
3078    }
3079 
3080     if (!sraRgnEmpty(updateCopyRegion)) {
3081 	if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy))
3082 	        goto updateFailed;
3083     }
3084 
3085     for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
3086         int x = rect.x1;
3087         int y = rect.y1;
3088         int w = rect.x2 - x;
3089         int h = rect.y2 - y;
3090 
3091         /* We need to count the number of rects in the scaled screen */
3092         if (cl->screen!=cl->scaledScreen)
3093             rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
3094 
3095         switch (cl->preferredEncoding) {
3096 	case -1:
3097         case rfbEncodingRaw:
3098             if (!rfbSendRectEncodingRaw(cl, x, y, w, h))
3099 	        goto updateFailed;
3100             break;
3101         case rfbEncodingRRE:
3102             if (!rfbSendRectEncodingRRE(cl, x, y, w, h))
3103 	        goto updateFailed;
3104             break;
3105         case rfbEncodingCoRRE:
3106             if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h))
3107 	        goto updateFailed;
3108 	    break;
3109         case rfbEncodingHextile:
3110             if (!rfbSendRectEncodingHextile(cl, x, y, w, h))
3111 	        goto updateFailed;
3112             break;
3113         case rfbEncodingUltra:
3114             if (!rfbSendRectEncodingUltra(cl, x, y, w, h))
3115                 goto updateFailed;
3116             break;
3117 #ifdef LIBVNCSERVER_HAVE_LIBZ
3118 	case rfbEncodingZlib:
3119 	    if (!rfbSendRectEncodingZlib(cl, x, y, w, h))
3120 	        goto updateFailed;
3121 	    break;
3122        case rfbEncodingZRLE:
3123        case rfbEncodingZYWRLE:
3124            if (!rfbSendRectEncodingZRLE(cl, x, y, w, h))
3125 	       goto updateFailed;
3126            break;
3127 #endif
3128 #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && (defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG))
3129 	case rfbEncodingTight:
3130 	    if (!rfbSendRectEncodingTight(cl, x, y, w, h))
3131 	        goto updateFailed;
3132 	    break;
3133 #ifdef LIBVNCSERVER_HAVE_LIBPNG
3134 	case rfbEncodingTightPng:
3135 	    if (!rfbSendRectEncodingTightPng(cl, x, y, w, h))
3136 	        goto updateFailed;
3137 	    break;
3138 #endif
3139 #endif
3140         }
3141     }
3142     if (i) {
3143         sraRgnReleaseIterator(i);
3144         i = NULL;
3145     }
3146 
3147     if ( nUpdateRegionRects == 0xFFFF &&
3148 	 !rfbSendLastRectMarker(cl) )
3149 	    goto updateFailed;
3150 
3151     if (!rfbSendUpdateBuf(cl)) {
3152 updateFailed:
3153 	result = FALSE;
3154     }
3155 
3156     if (!cl->enableCursorShapeUpdates) {
3157       rfbHideCursor(cl);
3158     }
3159 
3160     if(i)
3161         sraRgnReleaseIterator(i);
3162     sraRgnDestroy(updateRegion);
3163     sraRgnDestroy(updateCopyRegion);
3164 
3165     if(cl->screen->displayFinishedHook)
3166       cl->screen->displayFinishedHook(cl, result);
3167     return result;
3168 }
3169 
3170 
3171 /*
3172  * Send the copy region as a string of CopyRect encoded rectangles.
3173  * The only slightly tricky thing is that we should send the messages in
3174  * the correct order so that an earlier CopyRect will not corrupt the source
3175  * of a later one.
3176  */
3177 
3178 rfbBool
rfbSendCopyRegion(rfbClientPtr cl,sraRegionPtr reg,int dx,int dy)3179 rfbSendCopyRegion(rfbClientPtr cl,
3180                   sraRegionPtr reg,
3181                   int dx,
3182                   int dy)
3183 {
3184     int x, y, w, h;
3185     rfbFramebufferUpdateRectHeader rect;
3186     rfbCopyRect cr;
3187     sraRectangleIterator* i;
3188     sraRect rect1;
3189 
3190     /* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */
3191     i = sraRgnGetReverseIterator(reg,dx>0,dy>0);
3192 
3193     /* correct for the scale of the screen */
3194     dx = ScaleX(cl->screen, cl->scaledScreen, dx);
3195     dy = ScaleX(cl->screen, cl->scaledScreen, dy);
3196 
3197     while(sraRgnIteratorNext(i,&rect1)) {
3198       x = rect1.x1;
3199       y = rect1.y1;
3200       w = rect1.x2 - x;
3201       h = rect1.y2 - y;
3202 
3203       /* correct for scaling (if necessary) */
3204       rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "copyrect");
3205 
3206       rect.r.x = Swap16IfLE(x);
3207       rect.r.y = Swap16IfLE(y);
3208       rect.r.w = Swap16IfLE(w);
3209       rect.r.h = Swap16IfLE(h);
3210       rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
3211 
3212       memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3213 	     sz_rfbFramebufferUpdateRectHeader);
3214       cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3215 
3216       cr.srcX = Swap16IfLE(x - dx);
3217       cr.srcY = Swap16IfLE(y - dy);
3218 
3219       memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
3220       cl->ublen += sz_rfbCopyRect;
3221 
3222       rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
3223           w * h  * (cl->scaledScreen->bitsPerPixel / 8));
3224     }
3225     sraRgnReleaseIterator(i);
3226 
3227     return TRUE;
3228 }
3229 
3230 /*
3231  * Send a given rectangle in raw encoding (rfbEncodingRaw).
3232  */
3233 
3234 rfbBool
rfbSendRectEncodingRaw(rfbClientPtr cl,int x,int y,int w,int h)3235 rfbSendRectEncodingRaw(rfbClientPtr cl,
3236                        int x,
3237                        int y,
3238                        int w,
3239                        int h)
3240 {
3241     rfbFramebufferUpdateRectHeader rect;
3242     int nlines;
3243     int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
3244     char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
3245                    + (x * (cl->scaledScreen->bitsPerPixel / 8)));
3246 
3247     /* Flush the buffer to guarantee correct alignment for translateFn(). */
3248     if (cl->ublen > 0) {
3249         if (!rfbSendUpdateBuf(cl))
3250             return FALSE;
3251     }
3252 
3253     rect.r.x = Swap16IfLE(x);
3254     rect.r.y = Swap16IfLE(y);
3255     rect.r.w = Swap16IfLE(w);
3256     rect.r.h = Swap16IfLE(h);
3257     rect.encoding = Swap32IfLE(rfbEncodingRaw);
3258 
3259     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
3260     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3261 
3262 
3263     rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
3264         sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
3265 
3266     nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
3267 
3268     while (TRUE) {
3269         if (nlines > h)
3270             nlines = h;
3271 
3272         (*cl->translateFn)(cl->translateLookupTable,
3273 			   &(cl->screen->serverFormat),
3274                            &cl->format, fbptr, &cl->updateBuf[cl->ublen],
3275                            cl->scaledScreen->paddedWidthInBytes, w, nlines);
3276 
3277         cl->ublen += nlines * bytesPerLine;
3278         h -= nlines;
3279 
3280         if (h == 0)     /* rect fitted in buffer, do next one */
3281             return TRUE;
3282 
3283         /* buffer full - flush partial rect and do another nlines */
3284 
3285         if (!rfbSendUpdateBuf(cl))
3286             return FALSE;
3287 
3288         fbptr += (cl->scaledScreen->paddedWidthInBytes * nlines);
3289 
3290         nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
3291         if (nlines == 0) {
3292             rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d "
3293                    "bytes per line\n", bytesPerLine);
3294             rfbCloseClient(cl);
3295             return FALSE;
3296         }
3297     }
3298 }
3299 
3300 
3301 
3302 /*
3303  * Send an empty rectangle with encoding field set to value of
3304  * rfbEncodingLastRect to notify client that this is the last
3305  * rectangle in framebuffer update ("LastRect" extension of RFB
3306  * protocol).
3307  */
3308 
3309 rfbBool
rfbSendLastRectMarker(rfbClientPtr cl)3310 rfbSendLastRectMarker(rfbClientPtr cl)
3311 {
3312     rfbFramebufferUpdateRectHeader rect;
3313 
3314     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3315 	if (!rfbSendUpdateBuf(cl))
3316 	    return FALSE;
3317     }
3318 
3319     rect.encoding = Swap32IfLE(rfbEncodingLastRect);
3320     rect.r.x = 0;
3321     rect.r.y = 0;
3322     rect.r.w = 0;
3323     rect.r.h = 0;
3324 
3325     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
3326     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3327 
3328 
3329     rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3330 
3331     return TRUE;
3332 }
3333 
3334 
3335 /*
3336  * Send NewFBSize pseudo-rectangle. This tells the client to change
3337  * its framebuffer size.
3338  */
3339 
3340 rfbBool
rfbSendNewFBSize(rfbClientPtr cl,int w,int h)3341 rfbSendNewFBSize(rfbClientPtr cl,
3342                  int w,
3343                  int h)
3344 {
3345     rfbFramebufferUpdateRectHeader rect;
3346 
3347     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3348 	if (!rfbSendUpdateBuf(cl))
3349 	    return FALSE;
3350     }
3351 
3352     if (cl->PalmVNC==TRUE)
3353         rfbLog("Sending rfbEncodingNewFBSize in response to a PalmVNC style framebuffer resize (%dx%d)\n", w, h);
3354     else
3355         rfbLog("Sending rfbEncodingNewFBSize for resize to (%dx%d)\n", w, h);
3356 
3357     rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
3358     rect.r.x = 0;
3359     rect.r.y = 0;
3360     rect.r.w = Swap16IfLE(w);
3361     rect.r.h = Swap16IfLE(h);
3362 
3363     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3364            sz_rfbFramebufferUpdateRectHeader);
3365     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3366 
3367     rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3368 
3369     return TRUE;
3370 }
3371 
3372 
3373 /*
3374  * Send the contents of cl->updateBuf.  Returns 1 if successful, -1 if
3375  * not (errno should be set).
3376  */
3377 
3378 rfbBool
rfbSendUpdateBuf(rfbClientPtr cl)3379 rfbSendUpdateBuf(rfbClientPtr cl)
3380 {
3381     if(cl->sock<0)
3382       return FALSE;
3383 
3384     if (rfbWriteExact(cl, cl->updateBuf, cl->ublen) < 0) {
3385         rfbLogPerror("rfbSendUpdateBuf: write");
3386         rfbCloseClient(cl);
3387         return FALSE;
3388     }
3389 
3390     cl->ublen = 0;
3391     return TRUE;
3392 }
3393 
3394 /*
3395  * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
3396  * client, using values from the currently installed colormap.
3397  */
3398 
3399 rfbBool
rfbSendSetColourMapEntries(rfbClientPtr cl,int firstColour,int nColours)3400 rfbSendSetColourMapEntries(rfbClientPtr cl,
3401                            int firstColour,
3402                            int nColours)
3403 {
3404     char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
3405     char *wbuf = buf;
3406     rfbSetColourMapEntriesMsg *scme;
3407     uint16_t *rgb;
3408     rfbColourMap* cm = &cl->screen->colourMap;
3409     int i, len;
3410 
3411     if (nColours > 256) {
3412 	/* some rare hardware has, e.g., 4096 colors cells: PseudoColor:12 */
3413     	wbuf = (char *) malloc(sz_rfbSetColourMapEntriesMsg + nColours * 3 * 2);
3414     }
3415 
3416     scme = (rfbSetColourMapEntriesMsg *)wbuf;
3417     rgb = (uint16_t *)(&wbuf[sz_rfbSetColourMapEntriesMsg]);
3418 
3419     scme->type = rfbSetColourMapEntries;
3420 
3421     scme->firstColour = Swap16IfLE(firstColour);
3422     scme->nColours = Swap16IfLE(nColours);
3423 
3424     len = sz_rfbSetColourMapEntriesMsg;
3425 
3426     for (i = 0; i < nColours; i++) {
3427       if(i<(int)cm->count) {
3428 	if(cm->is16) {
3429 	  rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
3430 	  rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
3431 	  rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
3432 	} else {
3433 	  rgb[i*3] = Swap16IfLE((unsigned short)cm->data.bytes[i*3]);
3434 	  rgb[i*3+1] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+1]);
3435 	  rgb[i*3+2] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+2]);
3436 	}
3437       }
3438     }
3439 
3440     len += nColours * 3 * 2;
3441 
3442     LOCK(cl->sendMutex);
3443     if (rfbWriteExact(cl, wbuf, len) < 0) {
3444 	rfbLogPerror("rfbSendSetColourMapEntries: write");
3445 	rfbCloseClient(cl);
3446         if (wbuf != buf) free(wbuf);
3447         UNLOCK(cl->sendMutex);
3448 	return FALSE;
3449     }
3450     UNLOCK(cl->sendMutex);
3451 
3452     rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
3453     if (wbuf != buf) free(wbuf);
3454     return TRUE;
3455 }
3456 
3457 /*
3458  * rfbSendBell sends a Bell message to all the clients.
3459  */
3460 
3461 void
rfbSendBell(rfbScreenInfoPtr rfbScreen)3462 rfbSendBell(rfbScreenInfoPtr rfbScreen)
3463 {
3464     rfbClientIteratorPtr i;
3465     rfbClientPtr cl;
3466     rfbBellMsg b;
3467 
3468     i = rfbGetClientIterator(rfbScreen);
3469     while((cl=rfbClientIteratorNext(i))) {
3470 	b.type = rfbBell;
3471         LOCK(cl->sendMutex);
3472 	if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
3473 	    rfbLogPerror("rfbSendBell: write");
3474 	    rfbCloseClient(cl);
3475 	}
3476         UNLOCK(cl->sendMutex);
3477     }
3478     rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
3479     rfbReleaseClientIterator(i);
3480 }
3481 
3482 
3483 /*
3484  * rfbSendServerCutText sends a ServerCutText message to all the clients.
3485  */
3486 
3487 void
rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char * str,int len)3488 rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
3489 {
3490     rfbClientPtr cl;
3491     rfbServerCutTextMsg sct;
3492     rfbClientIteratorPtr iterator;
3493 
3494     iterator = rfbGetClientIterator(rfbScreen);
3495     while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
3496         sct.type = rfbServerCutText;
3497         sct.length = Swap32IfLE(len);
3498         LOCK(cl->sendMutex);
3499         if (rfbWriteExact(cl, (char *)&sct,
3500                        sz_rfbServerCutTextMsg) < 0) {
3501             rfbLogPerror("rfbSendServerCutText: write");
3502             rfbCloseClient(cl);
3503             UNLOCK(cl->sendMutex);
3504             continue;
3505         }
3506         if (rfbWriteExact(cl, str, len) < 0) {
3507             rfbLogPerror("rfbSendServerCutText: write");
3508             rfbCloseClient(cl);
3509         }
3510         UNLOCK(cl->sendMutex);
3511         rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
3512     }
3513     rfbReleaseClientIterator(iterator);
3514 }
3515 
3516 /*****************************************************************************
3517  *
3518  * UDP can be used for keyboard and pointer events when the underlying
3519  * network is highly reliable.  This is really here to support ORL's
3520  * videotile, whose TCP implementation doesn't like sending lots of small
3521  * packets (such as 100s of pen readings per second!).
3522  */
3523 
3524 static unsigned char ptrAcceleration = 50;
3525 
3526 void
rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,int sock)3527 rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,
3528                     int sock)
3529 {
3530   if (write(sock, (char*) &ptrAcceleration, 1) < 0) {
3531 	rfbLogPerror("rfbNewUDPConnection: write");
3532     }
3533 }
3534 
3535 /*
3536  * Because UDP is a message based service, we can't read the first byte and
3537  * then the rest of the packet separately like we do with TCP.  We will always
3538  * get a whole packet delivered in one go, so we ask read() for the maximum
3539  * number of bytes we can possibly get.
3540  */
3541 
3542 void
rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)3543 rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
3544 {
3545     int n;
3546     rfbClientPtr cl=rfbScreen->udpClient;
3547     rfbClientToServerMsg msg;
3548 
3549     if((!cl) || cl->onHold)
3550       return;
3551 
3552     if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
3553 	if (n < 0) {
3554 	    rfbLogPerror("rfbProcessUDPInput: read");
3555 	}
3556 	rfbDisconnectUDPSock(rfbScreen);
3557 	return;
3558     }
3559 
3560     switch (msg.type) {
3561 
3562     case rfbKeyEvent:
3563 	if (n != sz_rfbKeyEventMsg) {
3564 	    rfbErr("rfbProcessUDPInput: key event incorrect length\n");
3565 	    rfbDisconnectUDPSock(rfbScreen);
3566 	    return;
3567 	}
3568 	cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
3569 	break;
3570 
3571     case rfbPointerEvent:
3572 	if (n != sz_rfbPointerEventMsg) {
3573 	    rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
3574 	    rfbDisconnectUDPSock(rfbScreen);
3575 	    return;
3576 	}
3577 	cl->screen->ptrAddEvent(msg.pe.buttonMask,
3578 		    Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
3579 	break;
3580 
3581     default:
3582 	rfbErr("rfbProcessUDPInput: unknown message type %d\n",
3583 	       msg.type);
3584 	rfbDisconnectUDPSock(rfbScreen);
3585     }
3586 }
3587 
3588 
3589