LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rfbtightserver.c
Go to the documentation of this file.
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"
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 
39 
40 rfbTightClientPtr
41 rfbGetTightClientData(rfbClientPtr cl)
42 {
43  rfbTightClientPtr rtcp = (rfbTightClientPtr)
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
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 */
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
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
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
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
181 rfbSendAuthCaps(rfbClientPtr cl)
182 {
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 */
217  } else {
218 #ifdef USE_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
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. */
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
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. */
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);
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)) {
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;
322  SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
325 #ifdef LIBVNCSERVER_HAVE_LIBZ
328 #else
329  n_enc_caps -= 2;
330 #endif
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,
346  rfbWriteExact(cl, (char *)&smsg_list[0],
348  rfbWriteExact(cl, (char *)&cmsg_list[0],
350  rfbWriteExact(cl, (char *)&enc_list[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
364 rfbTightExtensionInit(rfbClientPtr cl, void* data)
365 {
366 
368 
369  return TRUE;
370 }
371 
372 static rfbBool
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
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 
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 
417 
418  return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest);
419 
420  case rfbFileUploadFailed:
421 
422  return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest);
423 
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
449 rfbTightExtensionClientClose(rfbClientPtr cl, void* data) {
450 
451  if(data != NULL)
452  free(data);
453 
454 }
455 
456 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
465 rfbTightProcessArg(int argc, char *argv[]) {
466 
467  rfbLog("tightvnc-filetransfer/rfbTightProcessArg\n");
468 
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) {
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
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,
521  NULL,
522  NULL,
527  NULL
528 };
529 
530 static rfbSecurityHandler tightVncSecurityHandler = {
533  NULL
534 };
535 
537  rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
538  rfbRegisterSecurityHandler(&tightVncSecurityHandler);
539 }
540 
541 void
543  rfbUnregisterProtocolExtension(&tightVncFileTransferExtension);
544  rfbUnregisterSecurityHandler(&tightVncSecurityHandler);
545 }
546