1 /*
2 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20 /*
21 * vncviewer.c - the Xt-based VNC viewer.
22 */
23
24 #ifdef WIN32
25 #undef SOCKET
26 #include <winsock2.h>
27 #endif
28
29 #ifdef _MSC_VER
30 #define strdup _strdup /* Prevent POSIX deprecation warnings */
31 #endif
32
33 #ifdef __STRICT_ANSI__
34 #define _BSD_SOURCE
35 #define _POSIX_SOURCE
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <rfb/rfbclient.h>
42 #include "tls.h"
43
Dummy(rfbClient * client)44 static void Dummy(rfbClient* client) {
45 }
DummyPoint(rfbClient * client,int x,int y)46 static rfbBool DummyPoint(rfbClient* client, int x, int y) {
47 return TRUE;
48 }
DummyRect(rfbClient * client,int x,int y,int w,int h)49 static void DummyRect(rfbClient* client, int x, int y, int w, int h) {
50 }
51
52 #ifdef WIN32
NoPassword(rfbClient * client)53 static char* NoPassword(rfbClient* client) {
54 return strdup("");
55 }
56 #define close closesocket
57 #else
58 #include <stdio.h>
59 #include <termios.h>
60 #endif
61
ReadPassword(rfbClient * client)62 static char* ReadPassword(rfbClient* client) {
63 #ifdef WIN32
64 /* FIXME */
65 rfbClientErr("ReadPassword on Windows NOT IMPLEMENTED\n");
66 return NoPassword(client);
67 #else
68 int i;
69 char* p=malloc(9);
70 struct termios save,noecho;
71 p[0]=0;
72 if(tcgetattr(fileno(stdin),&save)!=0) return p;
73 noecho=save; noecho.c_lflag &= ~ECHO;
74 if(tcsetattr(fileno(stdin),TCSAFLUSH,&noecho)!=0) return p;
75 fprintf(stderr,"Password: ");
76 i=0;
77 while(1) {
78 int c=fgetc(stdin);
79 if(c=='\n')
80 break;
81 if(i<8) {
82 p[i]=c;
83 i++;
84 p[i]=0;
85 }
86 }
87 tcsetattr(fileno(stdin),TCSAFLUSH,&save);
88 return p;
89 #endif
90 }
MallocFrameBuffer(rfbClient * client)91 static rfbBool MallocFrameBuffer(rfbClient* client) {
92 uint64_t allocSize;
93
94 if(client->frameBuffer)
95 free(client->frameBuffer);
96
97 /* SECURITY: promote 'width' into uint64_t so that the multiplication does not overflow
98 'width' and 'height' are 16-bit integers per RFB protocol design
99 SIZE_MAX is the maximum value that can fit into size_t
100 */
101 allocSize = (uint64_t)client->width * client->height * client->format.bitsPerPixel/8;
102
103 if (allocSize >= SIZE_MAX) {
104 rfbClientErr("CRITICAL: cannot allocate frameBuffer, requested size is too large\n");
105 return FALSE;
106 }
107
108 client->frameBuffer=malloc( (size_t)allocSize );
109
110 if (client->frameBuffer == NULL)
111 rfbClientErr("CRITICAL: frameBuffer allocation failed, requested size too large or not enough memory?\n");
112
113 return client->frameBuffer?TRUE:FALSE;
114 }
115
initAppData(AppData * data)116 static void initAppData(AppData* data) {
117 data->shareDesktop=TRUE;
118 data->viewOnly=FALSE;
119 #ifdef LIBVNCSERVER_CONFIG_LIBVA
120 data->encodingsString="h264 tight zrle ultra copyrect hextile zlib corre rre raw";
121 #else
122 data->encodingsString="tight zrle ultra copyrect hextile zlib corre rre raw";
123 #endif
124 data->useBGR233=FALSE;
125 data->nColours=0;
126 data->forceOwnCmap=FALSE;
127 data->forceTrueColour=FALSE;
128 data->requestedDepth=0;
129 data->compressLevel=3;
130 data->qualityLevel=5;
131 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
132 data->enableJPEG=TRUE;
133 #else
134 data->enableJPEG=FALSE;
135 #endif
136 data->useRemoteCursor=FALSE;
137 }
138
rfbGetClient(int bitsPerSample,int samplesPerPixel,int bytesPerPixel)139 rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
140 int bytesPerPixel) {
141 rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1);
142 if(!client) {
143 rfbClientErr("Couldn't allocate client structure!\n");
144 return NULL;
145 }
146 initAppData(&client->appData);
147 client->endianTest = 1;
148 client->programName="";
149 client->serverHost=strdup("");
150 client->serverPort=5900;
151
152 client->destHost = NULL;
153 client->destPort = 5900;
154
155 client->CurrentKeyboardLedState = 0;
156 client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint;
157
158 /* default: use complete frame buffer */
159 client->updateRect.x = -1;
160
161 client->frameBuffer = NULL;
162 client->outputWindow = 0;
163
164 client->format.bitsPerPixel = bytesPerPixel*8;
165 client->format.depth = bitsPerSample*samplesPerPixel;
166 client->appData.requestedDepth=client->format.depth;
167 client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
168 client->format.trueColour = TRUE;
169
170 if (client->format.bitsPerPixel == 8) {
171 client->format.redMax = 7;
172 client->format.greenMax = 7;
173 client->format.blueMax = 3;
174 client->format.redShift = 0;
175 client->format.greenShift = 3;
176 client->format.blueShift = 6;
177 } else {
178 client->format.redMax = (1 << bitsPerSample) - 1;
179 client->format.greenMax = (1 << bitsPerSample) - 1;
180 client->format.blueMax = (1 << bitsPerSample) - 1;
181 if(!client->format.bigEndian) {
182 client->format.redShift = 0;
183 client->format.greenShift = bitsPerSample;
184 client->format.blueShift = bitsPerSample * 2;
185 } else {
186 if(client->format.bitsPerPixel==8*3) {
187 client->format.redShift = bitsPerSample*2;
188 client->format.greenShift = bitsPerSample*1;
189 client->format.blueShift = 0;
190 } else {
191 client->format.redShift = bitsPerSample*3;
192 client->format.greenShift = bitsPerSample*2;
193 client->format.blueShift = bitsPerSample;
194 }
195 }
196 }
197
198 client->bufoutptr=client->buf;
199 client->buffered=0;
200
201 #ifdef LIBVNCSERVER_HAVE_LIBZ
202 client->raw_buffer_size = -1;
203 client->decompStreamInited = FALSE;
204
205 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
206 memset(client->zlibStreamActive,0,sizeof(rfbBool)*4);
207 client->jpegSrcManager = NULL;
208 #endif
209 #endif
210
211 client->HandleCursorPos = DummyPoint;
212 client->SoftCursorLockArea = DummyRect;
213 client->SoftCursorUnlockScreen = Dummy;
214 client->GotFrameBufferUpdate = DummyRect;
215 client->FinishedFrameBufferUpdate = NULL;
216 client->GetPassword = ReadPassword;
217 client->MallocFrameBuffer = MallocFrameBuffer;
218 client->Bell = Dummy;
219 client->CurrentKeyboardLedState = 0;
220 client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint;
221 client->QoS_DSCP = 0;
222
223 client->authScheme = 0;
224 client->subAuthScheme = 0;
225 client->GetCredential = NULL;
226 client->tlsSession = NULL;
227 client->sock = -1;
228 client->listenSock = -1;
229 client->listenAddress = NULL;
230 client->listen6Sock = -1;
231 client->listen6Address = NULL;
232 client->clientAuthSchemes = NULL;
233 return client;
234 }
235
rfbInitConnection(rfbClient * client)236 static rfbBool rfbInitConnection(rfbClient* client)
237 {
238 /* Unless we accepted an incoming connection, make a TCP connection to the
239 given VNC server */
240
241 if (!client->listenSpecified) {
242 if (!client->serverHost)
243 return FALSE;
244 if (client->destHost) {
245 if (!ConnectToRFBRepeater(client,client->serverHost,client->serverPort,client->destHost,client->destPort))
246 return FALSE;
247 } else {
248 if (!ConnectToRFBServer(client,client->serverHost,client->serverPort))
249 return FALSE;
250 }
251 }
252
253 /* Initialise the VNC connection, including reading the password */
254
255 if (!InitialiseRFBConnection(client))
256 return FALSE;
257
258 client->width=client->si.framebufferWidth;
259 client->height=client->si.framebufferHeight;
260 if (!client->MallocFrameBuffer(client))
261 return FALSE;
262
263 if (!SetFormatAndEncodings(client))
264 return FALSE;
265
266 if (client->updateRect.x < 0) {
267 client->updateRect.x = client->updateRect.y = 0;
268 client->updateRect.w = client->width;
269 client->updateRect.h = client->height;
270 }
271
272 if (client->appData.scaleSetting>1)
273 {
274 if (!SendScaleSetting(client, client->appData.scaleSetting))
275 return FALSE;
276 if (!SendFramebufferUpdateRequest(client,
277 client->updateRect.x / client->appData.scaleSetting,
278 client->updateRect.y / client->appData.scaleSetting,
279 client->updateRect.w / client->appData.scaleSetting,
280 client->updateRect.h / client->appData.scaleSetting,
281 FALSE))
282 return FALSE;
283 }
284 else
285 {
286 if (!SendFramebufferUpdateRequest(client,
287 client->updateRect.x, client->updateRect.y,
288 client->updateRect.w, client->updateRect.h,
289 FALSE))
290 return FALSE;
291 }
292
293 return TRUE;
294 }
295
rfbInitClient(rfbClient * client,int * argc,char ** argv)296 rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) {
297 int i,j;
298
299 if(argv && argc && *argc) {
300 if(client->programName==0)
301 client->programName=argv[0];
302
303 for (i = 1; i < *argc; i++) {
304 j = i;
305 if (strcmp(argv[i], "-listen") == 0) {
306 listenForIncomingConnections(client);
307 break;
308 } else if (strcmp(argv[i], "-listennofork") == 0) {
309 listenForIncomingConnectionsNoFork(client, -1);
310 break;
311 } else if (strcmp(argv[i], "-play") == 0) {
312 client->serverPort = -1;
313 j++;
314 } else if (i+1<*argc && strcmp(argv[i], "-encodings") == 0) {
315 client->appData.encodingsString = argv[i+1];
316 j+=2;
317 } else if (i+1<*argc && strcmp(argv[i], "-compress") == 0) {
318 client->appData.compressLevel = atoi(argv[i+1]);
319 j+=2;
320 } else if (i+1<*argc && strcmp(argv[i], "-quality") == 0) {
321 client->appData.qualityLevel = atoi(argv[i+1]);
322 j+=2;
323 } else if (i+1<*argc && strcmp(argv[i], "-scale") == 0) {
324 client->appData.scaleSetting = atoi(argv[i+1]);
325 j+=2;
326 } else if (i+1<*argc && strcmp(argv[i], "-qosdscp") == 0) {
327 client->QoS_DSCP = atoi(argv[i+1]);
328 j+=2;
329 } else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) {
330 char* colon=strchr(argv[i+1],':');
331
332 if(client->destHost)
333 free(client->destHost);
334 client->destPort = 5900;
335
336 client->destHost = strdup(argv[i+1]);
337 if(colon) {
338 client->destHost[(int)(colon-argv[i+1])] = '\0';
339 client->destPort = atoi(colon+1);
340 }
341 j+=2;
342 } else {
343 char* colon=strchr(argv[i],':');
344
345 if(client->serverHost)
346 free(client->serverHost);
347
348 if(colon) {
349 client->serverHost = strdup(argv[i]);
350 client->serverHost[(int)(colon-argv[i])] = '\0';
351 client->serverPort = atoi(colon+1);
352 } else {
353 client->serverHost = strdup(argv[i]);
354 }
355 if(client->serverPort >= 0 && client->serverPort < 5900)
356 client->serverPort += 5900;
357 }
358 /* purge arguments */
359 if (j>i) {
360 *argc-=j-i;
361 memmove(argv+i,argv+j,(*argc-i)*sizeof(char*));
362 i--;
363 }
364 }
365 }
366
367 if(!rfbInitConnection(client)) {
368 rfbClientCleanup(client);
369 return FALSE;
370 }
371
372 return TRUE;
373 }
374
rfbClientCleanup(rfbClient * client)375 void rfbClientCleanup(rfbClient* client) {
376 #ifdef LIBVNCSERVER_HAVE_LIBZ
377 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
378 int i;
379
380 for ( i = 0; i < 4; i++ ) {
381 if (client->zlibStreamActive[i] == TRUE ) {
382 if (inflateEnd (&client->zlibStream[i]) != Z_OK &&
383 client->zlibStream[i].msg != NULL)
384 rfbClientLog("inflateEnd: %s\n", client->zlibStream[i].msg);
385 }
386 }
387
388 if ( client->decompStreamInited == TRUE ) {
389 if (inflateEnd (&client->decompStream) != Z_OK &&
390 client->decompStream.msg != NULL)
391 rfbClientLog("inflateEnd: %s\n", client->decompStream.msg );
392 }
393
394 if (client->jpegSrcManager)
395 free(client->jpegSrcManager);
396 #endif
397 #endif
398
399 FreeTLS(client);
400
401 while (client->clientData) {
402 rfbClientData* next = client->clientData->next;
403 free(client->clientData);
404 client->clientData = next;
405 }
406
407 if (client->sock >= 0)
408 close(client->sock);
409 if (client->listenSock >= 0)
410 close(client->listenSock);
411 free(client->desktopName);
412 free(client->serverHost);
413 if (client->destHost)
414 free(client->destHost);
415 if (client->clientAuthSchemes)
416 free(client->clientAuthSchemes);
417 free(client);
418 }
419