Coverage Report

Created: 2026-01-16 06:49

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