Coverage Report

Created: 2026-08-13 06:17

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