diff options
| author | dscho <dscho> | 2005-09-28 16:51:50 +0000 | 
|---|---|---|
| committer | dscho <dscho> | 2005-09-28 16:51:50 +0000 | 
| commit | 0a909fde7a283fb22c22bbdbc16bcf4c0fe391ec (patch) | |
| tree | 9de5c473941fc3c2525a7cbc67fc416cee11efc0 /libvncserver/tightvnc-filetransfer/rfbtightserver.c | |
| parent | 93be927b1c1c74bc4da6f6d5978ba8e6e52f3cc2 (diff) | |
| download | libtdevnc-0a909fde.tar.gz libtdevnc-0a909fde.zip | |
This monster commit contains support for TightVNC's file transfer protocol.
Thank you very much, Rohit!
Diffstat (limited to 'libvncserver/tightvnc-filetransfer/rfbtightserver.c')
| -rw-r--r-- | libvncserver/tightvnc-filetransfer/rfbtightserver.c | 506 | 
1 files changed, 506 insertions, 0 deletions
| diff --git a/libvncserver/tightvnc-filetransfer/rfbtightserver.c b/libvncserver/tightvnc-filetransfer/rfbtightserver.c new file mode 100644 index 0000000..825fce0 --- /dev/null +++ b/libvncserver/tightvnc-filetransfer/rfbtightserver.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2005 Novell, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com  + * + * Author		: Rohit Kumar + * Email ID	: rokumar@novell.com + * Date		: 25th August 2005 + */ + + +#include <rfb/rfb.h> +#include "rfbtightproto.h" +#include "handlefiletransferrequest.h" + +/* + * Get my data! + * + * This gets the extension specific data from the client structure. If + * the data is not found, the client connection is closed, a complaint + * is logged, and NULL is returned. + */ + +extern rfbProtocolExtension tightVncFileTransferExtension; + +rfbTightClientPtr rfbGetTightClientData(rfbClientPtr cl) +{ +    rfbExtensionData* data = cl->extensions; + +    while(data && data->extension != &tightVncFileTransferExtension) +	data = data->next; + +    if(data == NULL) { +	rfbLog("TightVNC enabled, but client data missing?!\n"); +	rfbCloseClient(cl); +	return NULL; +    } + +    return (rfbTightClientPtr)data->data; +} + +/* + * Send the authentication challenge. + */ + +static void +rfbVncAuthSendChallenge(cl) +    rfbClientPtr cl; +{ +	 +    // 4 byte header is alreay sent. Which is rfbSecTypeVncAuth (same as rfbVncAuth). Just send the challenge. +    rfbRandomBytes(cl->authChallenge); +    if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) { +        rfbLogPerror("rfbAuthNewClient: write"); +        rfbCloseClient(cl); +        return; +    } +     +    /* Dispatch client input to rfbVncAuthProcessResponse. */ +   /* This methos is defined in auth.c file */ +    rfbAuthProcessClientMessage(cl); + +} + +/* + * Read client's preferred authentication type (protocol 3.7t). + */ + +void +rfbProcessClientAuthType(cl) +    rfbClientPtr cl; +{ +    uint32_t auth_type; +    int n, i; +    rfbTightClientPtr rtcp = rfbGetTightClientData(cl); + +    if(rtcp == NULL) +	return; + +    /* Read authentication type selected by the client. */ +    n = rfbReadExact(cl, (char *)&auth_type, sizeof(auth_type)); +    if (n <= 0) { +	if (n == 0) +	    rfbLog("rfbProcessClientAuthType: client gone\n"); +	else +	    rfbLogPerror("rfbProcessClientAuthType: read"); +	rfbCloseClient(cl); +	return; +    } +    auth_type = Swap32IfLE(auth_type); + +    /* Make sure it was present in the list sent by the server. */ +    for (i = 0; i < rtcp->nAuthCaps; i++) { +	if (auth_type == rtcp->authCaps[i]) +	    break; +    } +    if (i >= rtcp->nAuthCaps) { +	rfbLog("rfbProcessClientAuthType: " +	       "wrong authentication type requested\n"); +	rfbCloseClient(cl); +	return; +    } + +    switch (auth_type) { +    case rfbAuthNone: +	/* Dispatch client input to rfbProcessClientInitMessage. */ +	cl->state = RFB_INITIALISATION; +	break; +    case rfbAuthVNC: +	rfbVncAuthSendChallenge(cl); +	break; +    default: +	rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n"); +	rfbCloseClient(cl); +    } +} + + +/* + * Read tunneling type requested by the client (protocol 3.7t). + * NOTE: Currently, we don't support tunneling, and this function + *       can never be called. + */ + +void +rfbProcessClientTunnelingType(cl) +    rfbClientPtr cl; +{ +    /* If we were called, then something's really wrong. */ +    rfbLog("rfbProcessClientTunnelingType: not implemented\n"); +    rfbCloseClient(cl); +    return; +} + + +/* + * Send the list of our authentication capabilities to the client + * (protocol 3.7t). + */ + +static void +rfbSendAuthCaps(cl) +    rfbClientPtr cl; +{ +    rfbBool authRequired; +    rfbAuthenticationCapsMsg caps; +    rfbCapabilityInfo caplist[MAX_AUTH_CAPS]; +    int count = 0; +    rfbTightClientPtr rtcp = rfbGetTightClientData(cl); + +    if(rtcp == NULL) +	return; + +    if (cl->screen->authPasswdData && !cl->reverseConnection) { +	// chk if this condition is valid or not. +	    SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor); +	    rtcp->authCaps[count++] = rfbAuthVNC; +    } + +    rtcp->nAuthCaps = count; +    caps.nAuthTypes = Swap32IfLE((uint32_t)count); +    if (rfbWriteExact(cl, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) { +	rfbLogPerror("rfbSendAuthCaps: write"); +	rfbCloseClient(cl); +	return; +    } + +    if (count) { +	if (rfbWriteExact(cl, (char *)&caplist[0], +		       count * sz_rfbCapabilityInfo) < 0) { +	    rfbLogPerror("rfbSendAuthCaps: write"); +	    rfbCloseClient(cl); +	    return; +	} +	/* Dispatch client input to rfbProcessClientAuthType. */ +	/* Call the function for authentication from here */ +	rfbProcessClientAuthType(cl); +    } else { +	/* Dispatch client input to rfbProcessClientInitMessage. */ +	cl->state = RFB_INITIALISATION; +    } +} + + + + + +/* + * Send the list of our tunneling capabilities (protocol 3.7t). + */ + +static void +rfbSendTunnelingCaps(cl) +    rfbClientPtr cl; +{ +    rfbTunnelingCapsMsg caps; +    uint32_t nTypes = 0;		/* we don't support tunneling yet */ + +    caps.nTunnelTypes = Swap32IfLE(nTypes); +    if (rfbWriteExact(cl, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) { +	rfbLogPerror("rfbSendTunnelingCaps: write"); +	rfbCloseClient(cl); +	return; +    } + +    if (nTypes) { +	/* Dispatch client input to rfbProcessClientTunnelingType(). */ +	/* The flow should not reach here as tunneling is not implemented. */ +	rfbProcessClientTunnelingType(cl); +    } else { +	rfbSendAuthCaps(cl); +    } +} + + + +/* + * rfbSendInteractionCaps is called after sending the server + * initialisation message, only if TightVNC protocol extensions were + * enabled (protocol 3.7t). In this function, we send the lists of + * supported protocol messages and encodings. + */ + +/* Update these constants on changing capability lists below! */ +/* Values updated for FTP */  +#define N_SMSG_CAPS  4 +#define N_CMSG_CAPS  6 +#define N_ENC_CAPS  12 + +void +rfbSendInteractionCaps(cl) +    rfbClientPtr cl; +{ +    rfbInteractionCapsMsg intr_caps; +    rfbCapabilityInfo smsg_list[N_SMSG_CAPS]; +    rfbCapabilityInfo cmsg_list[N_CMSG_CAPS]; +    rfbCapabilityInfo enc_list[N_ENC_CAPS]; +    int i; + +    /* Fill in the header structure sent prior to capability lists. */ +    intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS); +    intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS); +    intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS); +    intr_caps.pad = 0; + +    /* Supported server->client message types. */ +    /* For file transfer support: */ +    i = 0; +	if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) { +	    SetCapInfo(&smsg_list[i++], rfbFileListData,           rfbTightVncVendor); +	    SetCapInfo(&smsg_list[i++], rfbFileDownloadData,       rfbTightVncVendor); +	    SetCapInfo(&smsg_list[i++], rfbFileUploadCancel,       rfbTightVncVendor); +	    SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed,     rfbTightVncVendor); +	    if (i != N_SMSG_CAPS) { +			rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n"); +			rfbCloseClient(cl); +			return; +	    } +	} + +    /* Supported client->server message types. */ +    /* For file transfer support: */ +    i = 0; +	if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) { +	    SetCapInfo(&cmsg_list[i++], rfbFileListRequest,        rfbTightVncVendor); +	    SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest,    rfbTightVncVendor); +	    SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest,      rfbTightVncVendor); +	    SetCapInfo(&cmsg_list[i++], rfbFileUploadData,         rfbTightVncVendor); +	    SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel,     rfbTightVncVendor); +	    SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed,       rfbTightVncVendor); +	    if (i != N_CMSG_CAPS) { +			rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n"); +			rfbCloseClient(cl); +			return; +	    }		 +	} +	 +    /* Encoding types. */ +    i = 0; +    SetCapInfo(&enc_list[i++],  rfbEncodingCopyRect,       rfbStandardVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingRRE,            rfbStandardVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingCoRRE,          rfbStandardVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingHextile,        rfbStandardVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingZlib,           rfbTridiaVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingTight,          rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingCompressLevel0, rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingQualityLevel0,  rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingXCursor,        rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingRichCursor,     rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingPointerPos,     rfbTightVncVendor); +    SetCapInfo(&enc_list[i++],  rfbEncodingLastRect,       rfbTightVncVendor); +    if (i != N_ENC_CAPS) { +	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n"); +	rfbCloseClient(cl); +	return; +    } + +    /* Send header and capability lists */ +    if (rfbWriteExact(cl, (char *)&intr_caps, +		   sz_rfbInteractionCapsMsg) < 0 || +	rfbWriteExact(cl, (char *)&smsg_list[0], +		   sz_rfbCapabilityInfo * N_SMSG_CAPS) < 0 ||  +	rfbWriteExact(cl, (char *)&cmsg_list[0], +		   sz_rfbCapabilityInfo * N_CMSG_CAPS) < 0  || +	rfbWriteExact(cl, (char *)&enc_list[0], +		   sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) { +	rfbLogPerror("rfbSendInteractionCaps: write"); +	rfbCloseClient(cl);	 +	return; +    } + +    /* Dispatch client input to rfbProcessClientNormalMessage(). */ +    cl->state = RFB_NORMAL; +} + + + +rfbBool +rfbTightExtensionInit(cl, data) +rfbClientPtr cl; +void** data; +{ + +   rfbSendInteractionCaps(cl); + +    return TRUE; +} + +static rfbBool +handleMessage(rfbClientPtr cl, +	const char* messageName, +	void (*handler)(rfbClientPtr cl, rfbTightClientPtr data)) +{ +	rfbTightClientPtr data; + +	rfbLog("%s message received\n", messageName); + +	if((IsFileTransferEnabled() == FALSE) || ( cl->viewOnly == TRUE)) { +		rfbCloseClient(cl); +		return FALSE;	 +	} + +	data = rfbGetTightClientData(cl); +	if(data == NULL) +		return FALSE; + +	handler(cl, data); +	return TRUE; +} + +rfbBool +rfbTightExtensionMsgHandler(cl, data, msg) +struct _rfbClientRec* cl; +void* data; +const rfbClientToServerMsg* msg; +{ +    switch (msg->type) { +		 +	case rfbFileListRequest: + +	return handleMessage(cl, "rfbFileListRequest", HandleFileListRequest); + +	case rfbFileDownloadRequest: + +	return handleMessage(cl, "rfbFileDownloadRequest", HandleFileDownloadRequest); + +	case rfbFileUploadRequest:	 +	 +	return handleMessage(cl, "rfbFileUploadRequest", HandleFileUploadRequest); + +	case rfbFileUploadData: + +	return handleMessage(cl, "rfbFileUploadDataRequest", HandleFileUploadDataRequest); + +	case rfbFileDownloadCancel: + +	return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest); + +	case rfbFileUploadFailed: + +	return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest); + +	case rfbFileCreateDirRequest: + +	return handleMessage(cl, "rfbFileCreateDirRequest", HandleFileCreateDirRequest); +	 +    default: + +	rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n", +		msg->type); + +	/* + +	// We shouldn't close the connection here for unhandled msg, it should be left to libvncserver. +	rfbLog(" ... closing connection\n"); +	rfbCloseClient(cl); + +	*/ +	 +	return FALSE; + +    } +} + + +void +rfbTightExtensionClientClose(rfbClientPtr cl, void* data) { + +	if(data != NULL) +		free(data); + +} + +void +rfbTightUsage(void) { +    fprintf(stderr, "\nlibvncserver-tight-extension options:\n"); +    fprintf(stderr, "-disablefiletransfer   disable file transfer\n"); +    fprintf(stderr, "-ftproot string        set ftp root\n"); +    fprintf(stderr,"\n"); +} + +int +rfbTightProcessArg(int argc, char *argv[]) { + +    InitFileTransfer(); + +    if(argc<1) +	return 0; + +    if (strcmp(argv[0], "-ftproot") == 0) { /* -ftproot string */ +	if (2 > argc) { +	    return 0; +	} +	rfbLog("ftproot is set to <%s>\n", argv[1]); +	if(SetFtpRoot(argv[1]) == FALSE) { +	    rfbLog("ERROR:: Path specified for ftproot in invalid\n"); +	    return 0; +	} +	return 2; +    } else if (strcmp(argv[0], "-disablefiletransfer") == 0) { +	EnableFileTransfer(FALSE); +	return 1; +    } +    return 0; +} + +/* +  * This method should be registered to libvncserver to handle rfbSecTypeTight  security type. +  */ +void +rfbHandleSecTypeTight(rfbClientPtr cl) { + +    rfbTightClientPtr rtcp = (rfbTightClientPtr) malloc(sizeof(rfbTightClientRec)); + +    if(rtcp == NULL) { +        // Error condition close socket +        rfbLog("Memory error has occured while handling Tight security type... closing connection.\n"); +	 rfbCloseClient(cl); +	 return; +    } + +    memset(rtcp, 0, sizeof(rfbTightClientRec)); +    rtcp->rcft.rcfd.downloadFD = -1; +    rtcp->rcft.rcfu.uploadFD = -1; +    rfbEnableExtension(cl, &tightVncFileTransferExtension, rtcp); + +    rfbSendTunnelingCaps(cl); + +} + +rfbProtocolExtension tightVncFileTransferExtension = { +	NULL, +	rfbTightExtensionInit, +	rfbTightExtensionMsgHandler, +	rfbTightExtensionClientClose, +	rfbTightUsage, +	rfbTightProcessArg, +	NULL +}; + +static rfbSecurityHandler tightVncSecurityHandler = { +	rfbSecTypeTight, +	rfbHandleSecTypeTight, +	NULL +}; + +void rfbRegisterTightVNCFileTransferExtension() { +	rfbRegisterProtocolExtension(&tightVncFileTransferExtension); +	rfbRegisterSecurityHandler(&tightVncSecurityHandler); +} + + | 
