1 /*
2 * Copyright (c) 2005 Novell, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program 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 program; if not, contact Novell, Inc.
16 *
17 * To contact Novell about this file by physical or electronic mail,
18 * you may find current contact information at www.novell.com
19 *
20 * Author : Rohit Kumar
21 * Email ID : rokumar@novell.com
22 * Date : 25th August 2005
23 */
24
25
26 #include <rfb/rfb.h>
27 #include "rfbtightproto.h"
28 #include "handlefiletransferrequest.h"
29
30 /*
31 * Get my data!
32 *
33 * This gets the extension specific data from the client structure. If
34 * the data is not found, the client connection is closed, a complaint
35 * is logged, and NULL is returned.
36 */
37
38 extern rfbProtocolExtension tightVncFileTransferExtension;
39
40 rfbTightClientPtr
rfbGetTightClientData(rfbClientPtr cl)41 rfbGetTightClientData(rfbClientPtr cl)
42 {
43 rfbTightClientPtr rtcp = (rfbTightClientPtr)
44 rfbGetExtensionClientData(cl,
45 &tightVncFileTransferExtension);
46 if(rtcp == NULL) {
47 rfbLog("Extension client data is null, closing the connection !\n");
48 rfbCloseClient(cl);
49 }
50
51 return rtcp;
52 }
53
54 /*
55 * Send the authentication challenge.
56 */
57
58 static void
rfbVncAuthSendChallenge(rfbClientPtr cl)59 rfbVncAuthSendChallenge(rfbClientPtr cl)
60 {
61
62 rfbLog("tightvnc-filetransfer/rfbVncAuthSendChallenge\n");
63 /* 4 byte header is alreay sent. Which is rfbSecTypeVncAuth (same as rfbVncAuth). Just send the challenge. */
64 rfbRandomBytes(cl->authChallenge);
65 if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
66 rfbLogPerror("rfbAuthNewClient: write");
67 rfbCloseClient(cl);
68 return;
69 }
70
71 /* Dispatch client input to rfbVncAuthProcessResponse. */
72 /* This methos is defined in auth.c file */
73 rfbAuthProcessClientMessage(cl);
74
75 }
76
77 /*
78 * LibVNCServer has a bug WRT Tight SecurityType and RFB 3.8
79 * It should send auth result even for rfbAuthNone.
80 * See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=517422
81 * For testing set USE_SECTYPE_TIGHT_FOR_RFB_3_8 when compiling
82 * or set it here.
83 */
84 #define SECTYPE_TIGHT_FOR_RFB_3_8 \
85 if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) { \
86 uint32_t authResult; \
87 rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); \
88 authResult = Swap32IfLE(rfbVncAuthOK); \
89 if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { \
90 rfbLogPerror("rfbAuthProcessClientMessage: write"); \
91 rfbCloseClient(cl); \
92 return; \
93 } \
94 }
95
96 /*
97 Enabled by runge on 2010/01/02
98 */
99 #define USE_SECTYPE_TIGHT_FOR_RFB_3_8
100
101 /*
102 * Read client's preferred authentication type (protocol 3.7t).
103 */
104
105 void
rfbProcessClientAuthType(rfbClientPtr cl)106 rfbProcessClientAuthType(rfbClientPtr cl)
107 {
108 uint32_t auth_type;
109 int n, i;
110 rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
111
112 rfbLog("tightvnc-filetransfer/rfbProcessClientAuthType\n");
113
114 if(rtcp == NULL)
115 return;
116
117 /* Read authentication type selected by the client. */
118 n = rfbReadExact(cl, (char *)&auth_type, sizeof(auth_type));
119 if (n <= 0) {
120 if (n == 0)
121 rfbLog("rfbProcessClientAuthType: client gone\n");
122 else
123 rfbLogPerror("rfbProcessClientAuthType: read");
124 rfbCloseClient(cl);
125 return;
126 }
127 auth_type = Swap32IfLE(auth_type);
128
129 /* Make sure it was present in the list sent by the server. */
130 for (i = 0; i < rtcp->nAuthCaps; i++) {
131 if (auth_type == rtcp->authCaps[i])
132 break;
133 }
134 if (i >= rtcp->nAuthCaps) {
135 rfbLog("rfbProcessClientAuthType: "
136 "wrong authentication type requested\n");
137 rfbCloseClient(cl);
138 return;
139 }
140
141 switch (auth_type) {
142 case rfbAuthNone:
143 /* Dispatch client input to rfbProcessClientInitMessage. */
144 #ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
145 SECTYPE_TIGHT_FOR_RFB_3_8
146 #endif
147 cl->state = RFB_INITIALISATION;
148 break;
149 case rfbAuthVNC:
150 rfbVncAuthSendChallenge(cl);
151 break;
152 default:
153 rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
154 rfbCloseClient(cl);
155 }
156 }
157
158
159 /*
160 * Read tunneling type requested by the client (protocol 3.7t).
161 * NOTE: Currently, we don't support tunneling, and this function
162 * can never be called.
163 */
164
165 void
rfbProcessClientTunnelingType(rfbClientPtr cl)166 rfbProcessClientTunnelingType(rfbClientPtr cl)
167 {
168 /* If we were called, then something's really wrong. */
169 rfbLog("rfbProcessClientTunnelingType: not implemented\n");
170 rfbCloseClient(cl);
171 return;
172 }
173
174
175 /*
176 * Send the list of our authentication capabilities to the client
177 * (protocol 3.7t).
178 */
179
180 static void
rfbSendAuthCaps(rfbClientPtr cl)181 rfbSendAuthCaps(rfbClientPtr cl)
182 {
183 rfbAuthenticationCapsMsg caps;
184 rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
185 int count = 0;
186 rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
187
188 rfbLog("tightvnc-filetransfer/rfbSendAuthCaps\n");
189
190 if(rtcp == NULL)
191 return;
192
193 if (cl->screen->authPasswdData && !cl->reverseConnection) {
194 /* chk if this condition is valid or not. */
195 SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
196 rtcp->authCaps[count++] = rfbAuthVNC;
197 }
198
199 rtcp->nAuthCaps = count;
200 caps.nAuthTypes = Swap32IfLE((uint32_t)count);
201 if (rfbWriteExact(cl, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
202 rfbLogPerror("rfbSendAuthCaps: write");
203 rfbCloseClient(cl);
204 return;
205 }
206
207 if (count) {
208 if (rfbWriteExact(cl, (char *)&caplist[0],
209 count * sz_rfbCapabilityInfo) < 0) {
210 rfbLogPerror("rfbSendAuthCaps: write");
211 rfbCloseClient(cl);
212 return;
213 }
214 /* Dispatch client input to rfbProcessClientAuthType. */
215 /* Call the function for authentication from here */
216 rfbProcessClientAuthType(cl);
217 } else {
218 #ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
219 SECTYPE_TIGHT_FOR_RFB_3_8
220 #endif
221 /* Dispatch client input to rfbProcessClientInitMessage. */
222 cl->state = RFB_INITIALISATION;
223 }
224 }
225
226
227 /*
228 * Send the list of our tunneling capabilities (protocol 3.7t).
229 */
230
231 static void
rfbSendTunnelingCaps(rfbClientPtr cl)232 rfbSendTunnelingCaps(rfbClientPtr cl)
233 {
234 rfbTunnelingCapsMsg caps;
235 uint32_t nTypes = 0; /* we don't support tunneling yet */
236
237 rfbLog("tightvnc-filetransfer/rfbSendTunnelingCaps\n");
238
239 caps.nTunnelTypes = Swap32IfLE(nTypes);
240 if (rfbWriteExact(cl, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
241 rfbLogPerror("rfbSendTunnelingCaps: write");
242 rfbCloseClient(cl);
243 return;
244 }
245
246 if (nTypes) {
247 /* Dispatch client input to rfbProcessClientTunnelingType(). */
248 /* The flow should not reach here as tunneling is not implemented. */
249 rfbProcessClientTunnelingType(cl);
250 } else {
251 rfbSendAuthCaps(cl);
252 }
253 }
254
255
256
257 /*
258 * rfbSendInteractionCaps is called after sending the server
259 * initialisation message, only if TightVNC protocol extensions were
260 * enabled (protocol 3.7t). In this function, we send the lists of
261 * supported protocol messages and encodings.
262 */
263
264 /* Update these constants on changing capability lists below! */
265 /* Values updated for FTP */
266 #define N_SMSG_CAPS 4
267 #define N_CMSG_CAPS 6
268 #define N_ENC_CAPS 12
269
270 void
rfbSendInteractionCaps(rfbClientPtr cl)271 rfbSendInteractionCaps(rfbClientPtr cl)
272 {
273 rfbInteractionCapsMsg intr_caps;
274 rfbCapabilityInfo smsg_list[N_SMSG_CAPS];
275 rfbCapabilityInfo cmsg_list[N_CMSG_CAPS];
276 rfbCapabilityInfo enc_list[N_ENC_CAPS];
277 int i, n_enc_caps = N_ENC_CAPS;
278
279 /* Fill in the header structure sent prior to capability lists. */
280 intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
281 intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
282 intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
283 intr_caps.pad = 0;
284
285 rfbLog("tightvnc-filetransfer/rfbSendInteractionCaps\n");
286
287 /* Supported server->client message types. */
288 /* For file transfer support: */
289 i = 0;
290 if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
291 SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor);
292 SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor);
293 SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor);
294 SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor);
295 if (i != N_SMSG_CAPS) {
296 rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
297 rfbCloseClient(cl);
298 return;
299 }
300 }
301
302 /* Supported client->server message types. */
303 /* For file transfer support: */
304 i = 0;
305 if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
306 SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor);
307 SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor);
308 SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor);
309 SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor);
310 SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor);
311 SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor);
312 if (i != N_CMSG_CAPS) {
313 rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
314 rfbCloseClient(cl);
315 return;
316 }
317 }
318
319 /* Encoding types. */
320 i = 0;
321 SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor);
322 SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
323 SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor);
324 SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor);
325 #ifdef LIBVNCSERVER_HAVE_LIBZ
326 SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
327 SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
328 #else
329 n_enc_caps -= 2;
330 #endif
331 SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor);
332 SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor);
333 SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor);
334 SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor);
335 SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor);
336 SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor);
337 if (i != n_enc_caps) {
338 rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
339 rfbCloseClient(cl);
340 return;
341 }
342
343 /* Send header and capability lists */
344 if (rfbWriteExact(cl, (char *)&intr_caps,
345 sz_rfbInteractionCapsMsg) < 0 ||
346 rfbWriteExact(cl, (char *)&smsg_list[0],
347 sz_rfbCapabilityInfo * N_SMSG_CAPS) < 0 ||
348 rfbWriteExact(cl, (char *)&cmsg_list[0],
349 sz_rfbCapabilityInfo * N_CMSG_CAPS) < 0 ||
350 rfbWriteExact(cl, (char *)&enc_list[0],
351 sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
352 rfbLogPerror("rfbSendInteractionCaps: write");
353 rfbCloseClient(cl);
354 return;
355 }
356
357 /* Dispatch client input to rfbProcessClientNormalMessage(). */
358 cl->state = RFB_NORMAL;
359 }
360
361
362
363 rfbBool
rfbTightExtensionInit(rfbClientPtr cl,void * data)364 rfbTightExtensionInit(rfbClientPtr cl, void* data)
365 {
366
367 rfbSendInteractionCaps(cl);
368
369 return TRUE;
370 }
371
372 static rfbBool
handleMessage(rfbClientPtr cl,const char * messageName,void (* handler)(rfbClientPtr cl,rfbTightClientPtr data))373 handleMessage(rfbClientPtr cl,
374 const char* messageName,
375 void (*handler)(rfbClientPtr cl, rfbTightClientPtr data))
376 {
377 rfbTightClientPtr data;
378
379 rfbLog("tightvnc-filetransfer: %s message received\n", messageName);
380
381 if((IsFileTransferEnabled() == FALSE) || ( cl->viewOnly == TRUE)) {
382 rfbCloseClient(cl);
383 return FALSE;
384 }
385
386 data = rfbGetTightClientData(cl);
387 if(data == NULL)
388 return FALSE;
389
390 handler(cl, data);
391 return TRUE;
392 }
393
394 rfbBool
rfbTightExtensionMsgHandler(struct _rfbClientRec * cl,void * data,const rfbClientToServerMsg * msg)395 rfbTightExtensionMsgHandler(struct _rfbClientRec* cl, void* data,
396 const rfbClientToServerMsg* msg)
397 {
398 switch (msg->type) {
399
400 case rfbFileListRequest:
401
402 return handleMessage(cl, "rfbFileListRequest", HandleFileListRequest);
403
404 case rfbFileDownloadRequest:
405
406 return handleMessage(cl, "rfbFileDownloadRequest", HandleFileDownloadRequest);
407
408 case rfbFileUploadRequest:
409
410 return handleMessage(cl, "rfbFileUploadRequest", HandleFileUploadRequest);
411
412 case rfbFileUploadData:
413
414 return handleMessage(cl, "rfbFileUploadDataRequest", HandleFileUploadDataRequest);
415
416 case rfbFileDownloadCancel:
417
418 return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest);
419
420 case rfbFileUploadFailed:
421
422 return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest);
423
424 case rfbFileCreateDirRequest:
425
426 return handleMessage(cl, "rfbFileCreateDirRequest", HandleFileCreateDirRequest);
427
428 default:
429
430 rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
431 msg->type);
432
433 /*
434
435 We shouldn't close the connection here for unhandled msg,
436 it should be left to libvncserver.
437 rfbLog(" ... closing connection\n");
438 rfbCloseClient(cl);
439
440 */
441
442 return FALSE;
443
444 }
445 }
446
447
448 void
rfbTightExtensionClientClose(rfbClientPtr cl,void * data)449 rfbTightExtensionClientClose(rfbClientPtr cl, void* data) {
450
451 if(data != NULL)
452 free(data);
453
454 }
455
456 void
rfbTightUsage(void)457 rfbTightUsage(void) {
458 fprintf(stderr, "\nlibvncserver-tight-extension options:\n");
459 fprintf(stderr, "-disablefiletransfer disable file transfer\n");
460 fprintf(stderr, "-ftproot string set ftp root\n");
461 fprintf(stderr,"\n");
462 }
463
464 int
rfbTightProcessArg(int argc,char * argv[])465 rfbTightProcessArg(int argc, char *argv[]) {
466
467 rfbLog("tightvnc-filetransfer/rfbTightProcessArg\n");
468
469 InitFileTransfer();
470
471 if(argc<1)
472 return 0;
473
474 if (strcmp(argv[0], "-ftproot") == 0) { /* -ftproot string */
475 if (2 > argc) {
476 return 0;
477 }
478 rfbLog("ftproot is set to <%s>\n", argv[1]);
479 if(SetFtpRoot(argv[1]) == FALSE) {
480 rfbLog("ERROR:: Path specified for ftproot in invalid\n");
481 return 0;
482 }
483 return 2;
484 } else if (strcmp(argv[0], "-disablefiletransfer") == 0) {
485 EnableFileTransfer(FALSE);
486 return 1;
487 }
488 return 0;
489 }
490
491 /*
492 * This method should be registered to libvncserver to handle rfbSecTypeTight security type.
493 */
494 void
rfbHandleSecTypeTight(rfbClientPtr cl)495 rfbHandleSecTypeTight(rfbClientPtr cl) {
496
497 rfbTightClientPtr rtcp = (rfbTightClientPtr) malloc(sizeof(rfbTightClientRec));
498
499 rfbLog("tightvnc-filetransfer/rfbHandleSecTypeTight\n");
500
501 if(rtcp == NULL) {
502 /* Error condition close socket */
503 rfbLog("Memory error has occured while handling "
504 "Tight security type... closing connection.\n");
505 rfbCloseClient(cl);
506 return;
507 }
508
509 memset(rtcp, 0, sizeof(rfbTightClientRec));
510 rtcp->rcft.rcfd.downloadFD = -1;
511 rtcp->rcft.rcfu.uploadFD = -1;
512 rfbEnableExtension(cl, &tightVncFileTransferExtension, rtcp);
513
514 rfbSendTunnelingCaps(cl);
515
516 }
517
518 rfbProtocolExtension tightVncFileTransferExtension = {
519 NULL,
520 rfbTightExtensionInit,
521 NULL,
522 NULL,
523 rfbTightExtensionMsgHandler,
524 rfbTightExtensionClientClose,
525 rfbTightUsage,
526 rfbTightProcessArg,
527 NULL
528 };
529
530 static rfbSecurityHandler tightVncSecurityHandler = {
531 rfbSecTypeTight,
532 rfbHandleSecTypeTight,
533 NULL
534 };
535
rfbRegisterTightVNCFileTransferExtension()536 void rfbRegisterTightVNCFileTransferExtension() {
537 rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
538 rfbRegisterSecurityHandler(&tightVncSecurityHandler);
539 }
540
541 void
rfbUnregisterTightVNCFileTransferExtension()542 rfbUnregisterTightVNCFileTransferExtension() {
543 rfbUnregisterProtocolExtension(&tightVncFileTransferExtension);
544 rfbUnregisterSecurityHandler(&tightVncSecurityHandler);
545 }
546
547