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