Home | History | Annotate | Download | only in tightvnc-filetransfer
      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