You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/libvncserver/tightvnc-filetransfer/rfbtightserver.c

550 lines
15 KiB

/*
* 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"
#include "filetransfermsg.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)
{
rfbTightClientPtr rtcp = (rfbTightClientPtr)
rfbGetExtensionClientData(cl,
&tightVncFileTransferExtension);
if(rtcp == NULL) {
rfbLog("Extension client data is null, closing the connection !\n");
rfbCloseClient(cl);
}
return rtcp;
}
/*
* Send the authentication challenge.
*/
static void
rfbVncAuthSendChallenge(rfbClientPtr cl)
{
rfbLog("tightvnc-filetransfer/rfbVncAuthSendChallenge\n");
/* 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);
}
/*
* LibVNCServer has a bug WRT Tight SecurityType and RFB 3.8
* It should send auth result even for rfbAuthNone.
* See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=517422
* For testing set USE_SECTYPE_TIGHT_FOR_RFB_3_8 when compiling
* or set it here.
*/
#define SECTYPE_TIGHT_FOR_RFB_3_8 \
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) { \
uint32_t authResult; \
rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); \
authResult = Swap32IfLE(rfbVncAuthOK); \
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { \
rfbLogPerror("rfbAuthProcessClientMessage: write"); \
rfbCloseClient(cl); \
return; \
} \
}
/*
Enabled by runge on 2010/01/02
*/
#define USE_SECTYPE_TIGHT_FOR_RFB_3_8
/*
* Read client's preferred authentication type (protocol 3.7t).
*/
void
rfbProcessClientAuthType(rfbClientPtr cl)
{
uint32_t auth_type;
int n, i;
rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
rfbLog("tightvnc-filetransfer/rfbProcessClientAuthType\n");
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. */
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
SECTYPE_TIGHT_FOR_RFB_3_8
#endif
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(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(rfbClientPtr cl)
{
rfbAuthenticationCapsMsg caps;
rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
int count = 0;
rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
rfbLog("tightvnc-filetransfer/rfbSendAuthCaps\n");
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 {
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
SECTYPE_TIGHT_FOR_RFB_3_8
#endif
/* Dispatch client input to rfbProcessClientInitMessage. */
cl->state = RFB_INITIALISATION;
}
}
/*
* Send the list of our tunneling capabilities (protocol 3.7t).
*/
static void
rfbSendTunnelingCaps(rfbClientPtr cl)
{
rfbTunnelingCapsMsg caps;
uint32_t nTypes = 0; /* we don't support tunneling yet */
rfbLog("tightvnc-filetransfer/rfbSendTunnelingCaps\n");
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(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, n_enc_caps = N_ENC_CAPS;
/* 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;
rfbLog("tightvnc-filetransfer/rfbSendInteractionCaps\n");
/* 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);
#ifdef LIBVNCSERVER_HAVE_LIBZ
SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
#else
n_enc_caps -= 2;
#endif
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(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("tightvnc-filetransfer: %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(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) {
CloseUndoneFileUpload(cl, data);
CloseUndoneFileDownload(cl, data);
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[]) {
rfbLog("tightvnc-filetransfer/rfbTightProcessArg\n");
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));
rfbLog("tightvnc-filetransfer/rfbHandleSecTypeTight\n");
if(rtcp == NULL) {
/* Error condition close socket */
rfbLog("Memory error has occurred 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,
NULL,
NULL,
rfbTightExtensionMsgHandler,
rfbTightExtensionClientClose,
rfbTightUsage,
rfbTightProcessArg,
NULL
};
static rfbSecurityHandler tightVncSecurityHandler = {
rfbSecTypeTight,
rfbHandleSecTypeTight,
NULL
};
void rfbRegisterTightVNCFileTransferExtension() {
rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
rfbRegisterSecurityHandler(&tightVncSecurityHandler);
}
void
rfbUnregisterTightVNCFileTransferExtension() {
rfbUnregisterProtocolExtension(&tightVncFileTransferExtension);
rfbUnregisterSecurityHandler(&tightVncSecurityHandler);
}