• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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