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