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 (at) 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 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 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 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 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 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 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 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 364 rfbTightExtensionInit(rfbClientPtr cl, void* data) 365 { 366 367 rfbSendInteractionCaps(cl); 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 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 449 rfbTightExtensionClientClose(rfbClientPtr cl, void* data) { 450 451 if(data != NULL) 452 free(data); 453 454 } 455 456 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 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 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 536 void rfbRegisterTightVNCFileTransferExtension() { 537 rfbRegisterProtocolExtension(&tightVncFileTransferExtension); 538 rfbRegisterSecurityHandler(&tightVncSecurityHandler); 539 } 540 541 void 542 rfbUnregisterTightVNCFileTransferExtension() { 543 rfbUnregisterProtocolExtension(&tightVncFileTransferExtension); 544 rfbUnregisterSecurityHandler(&tightVncSecurityHandler); 545 } 546 547