This monster commit contains support for TightVNC's file transfer protocol.

Thank you very much, Rohit!
pull/1/head
dscho 19 years ago
parent 93be927b1c
commit 0a909fde7a

@ -19,6 +19,9 @@ original proof-of-concept. It really deserves to replace the old version,
as it is a state-of-the-art, fast and usable program by now! However, he
maintains it and improves it still in amazing ways!
The file transfer protocol from TightVNC was implemented by Rohit Kumar.
This includes an implementation of RFB protocol version 3.7t.
Occasional important patches were sent by (in order I found the names in my
archives and please don't beat me, if I forgot you, but just send me an
email!): Akira Hatakeyama, Karl J. Runge, Justin "Zippy" Dearing,

@ -1,3 +1,9 @@
2005-09-28 Rohit Kumar <rokumar@novell.com>
* examples/filetransfer.c, rfb/rfb.h, configure.ac,
libvncserver/{auth,cargs,main,rfbserver,sockets}.c,
libvncserver/tightvnc-extension/*:
Implement TightVNC's file transfer protocol.
2005-09-27 Rohit Kumar <rokumar@novell.com>
* libvncserver/{cargs,sockets,main,rfbserver}.c,
rfb/rfb.h: Provide a generic means to extend the RFB

@ -17,6 +17,14 @@ AC_PATH_PROG([AR], [ar], [/usr/bin/ar],
[$PATH:/usr/ccs/bin])
# Options
AH_TEMPLATE(WITH_TIGHTVNC_FILETRANSFER, [Disable TightVNCFileTransfer protocol])
AC_ARG_WITH(tightvnc-filetransfer,
[ --without-filetransfer disable TightVNC file transfer protocol],
, [ with_tightvnc_filetransfer=yes ])
if test "x$with_tightvnc_filetransfer" == "xyes"; then
AC_DEFINE(WITH_TIGHTVNC_FILETRANSFER)
fi
AM_CONDITIONAL(WITH_TIGHTVNC_FILETRANSFER, test "$with_tightvnc_filetransfer" == "yes")
AH_TEMPLATE(BACKCHANNEL, [Enable BackChannel communication])
AC_ARG_WITH(backchannel,
[ --without-backchannel disable backchannel method],

@ -13,4 +13,5 @@ simple15
colourmaptest
regiontest
mac
filetransfer

@ -6,9 +6,14 @@ MAC=mac
mac_LDFLAGS=-framework ApplicationServices -framework Carbon -framework IOKit
endif
if WITH_TIGHTVNC_FILETRANSFER
FILETRANSFER=filetransfer
endif
noinst_HEADERS=radon.h
noinst_PROGRAMS=example pnmshow regiontest pnmshow24 fontsel \
vncev storepasswd colourmaptest simple simple15 $(MAC)
vncev storepasswd colourmaptest simple simple15 $(MAC) \
$(FILETRANSFER)

@ -0,0 +1,11 @@
#include <rfb/rfb.h>
int main(int argc,char** argv)
{
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,8,3,4);
server->frameBuffer=(char*)malloc(400*300*4);
rfbRegisterTightVNCFileTransferExtension();
rfbInitServer(server);
rfbRunEventLoop(server,-1,FALSE);
return(0);
}

@ -1,5 +1,5 @@
.deps
Makefile
Makefile.in
client_test
libvncclient.a

@ -1,4 +1,5 @@
.deps
Makefile
Makefile.in
libvncserver.a

@ -1,4 +1,16 @@
DEFINES=-g -Wall
AM_CFLAGS=-g -Wall
#if WITH_TIGHTVNC_FILETRANSFER
TIGHTVNCFILETRANSFERHDRS=tightvnc-filetransfer/filelistinfo.h \
tightvnc-filetransfer/filetransfermsg.h \
tightvnc-filetransfer/handlefiletransferrequest.h \
tightvnc-filetransfer/rfbtightproto.h
TIGHTVNCFILETRANSFERSRCS = tightvnc-filetransfer/rfbtightserver.c \
tightvnc-filetransfer/handlefiletransferrequest.c \
tightvnc-filetransfer/filetransfermsg.c \
tightvnc-filetransfer/filelistinfo.c
#endif
includedir=$(prefix)/include/rfb
#include_HEADERS=rfb.h rfbconfig.h rfbint.h rfbproto.h keysym.h rfbregion.h
@ -7,7 +19,8 @@ include_HEADERS=../rfb/rfb.h ../rfb/rfbconfig.h ../rfb/rfbint.h \
../rfb/rfbproto.h ../rfb/keysym.h ../rfb/rfbregion.h ../rfb/rfbclient.h
noinst_HEADERS=d3des.h ../rfb/default8x16.h zrleoutstream.h \
zrlepalettehelper.h zrletypes.h private.h
zrlepalettehelper.h zrletypes.h private.h \
$(TIGHTVNCFILETRANSFERHDRS)
EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \
tableinitcmtemplate.c tabletrans24template.c \
@ -24,7 +37,7 @@ LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c \
stats.c corre.c hextile.c rre.c translate.c cutpaste.c \
httpd.c cursor.c font.c \
draw.c selbox.c d3des.c vncauth.c cargs.c \
$(ZLIBSRCS) $(JPEGSRCS)
$(ZLIBSRCS) $(JPEGSRCS) $(TIGHTVNCFILETRANSFERSRCS)
libvncserver_a_SOURCES=$(LIB_SRCS)

@ -207,7 +207,7 @@ rfbAuthNewClient(rfbClientPtr cl)
void
rfbProcessClientSecurityType(rfbClientPtr cl)
{
int n, i;
int n;
uint8_t chosenType;
rfbSecurityHandler* handler;

@ -151,7 +151,7 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[])
for(extension=rfbGetExtensionIterator();handled==0 && extension;
extension=extension->next)
if(extension->processArgument)
handled = extension->processArgument(argv + i);
handled = extension->processArgument(*argc - i, argv + i);
rfbReleaseExtensionIterator();
if(handled==0) {

@ -84,6 +84,46 @@ void rfbReleaseExtensionIterator()
UNLOCK(extMutex);
}
rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
void* data)
{
rfbExtensionData* extData;
/* make sure extension is not yet enabled. */
for(extData = cl->extensions; extData; extData = extData->next)
if(extData->extension == extension)
return FALSE;
extData = calloc(sizeof(rfbExtensionData),1);
extData->extension = extension;
extData->data = data;
extData->next = cl->extensions;
cl->extensions = extData;
return TRUE;
}
rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
{
rfbExtensionData* extData;
rfbExtensionData* prevData = NULL;
for(extData = cl->extensions; extData; extData = extData->next) {
if(extData->extension == extension) {
if(extData->data)
free(extData->data);
if(prevData == NULL)
cl->extensions = extData->next;
else
prevData->next = extData->next;
return TRUE;
}
prevData = extData;
}
return FALSE;
}
/*
* Logging
*/

@ -229,6 +229,7 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
rfbClientPtr cl,cl_;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
rfbProtocolExtension* extension;
cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
@ -361,6 +362,16 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
}
}
for(extension = rfbGetExtensionIterator(); extension;
extension=extension->next) {
void* data = NULL;
/* if the extension does not have a newClient method, it wants
* to be initialized later. */
if(extension->newClient && extension->newClient(cl, &data))
rfbEnableExtension(cl, extension, data);
}
rfbReleaseExtensionIterator();
switch (cl->screen->newClientHook(cl)) {
case RFB_CLIENT_ON_HOLD:
cl->onHold = TRUE;
@ -606,7 +617,7 @@ rfbProcessClientInitMessage(rfbClientPtr cl)
int len, n;
rfbClientIteratorPtr iterator;
rfbClientPtr otherCl;
rfbProtocolExtension* extension;
rfbExtensionData* extension;
if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
if (n == 0)
@ -636,18 +647,14 @@ rfbProcessClientInitMessage(rfbClientPtr cl)
return;
}
for(extension=rfbGetExtensionIterator();extension;extension=extension->next)
if(extension->init) {
void* data;
if(extension->init(cl, &data)) {
rfbExtensionData* extensionData=calloc(sizeof(rfbExtensionData),1);
extensionData->extension=extension;
extensionData->data=data;
extensionData->next=cl->extensions;
cl->extensions=extensionData;
for(extension = cl->extensions; extension;) {
rfbExtensionData* next = extension->next;
if(extension->extension->init &&
!extension->extension->init(cl, extension->data))
/* extension requested that it be removed */
rfbDisableExtension(cl, extension->extension);
extension = next;
}
}
rfbReleaseExtensionIterator();
cl->state = RFB_NORMAL;
@ -1068,7 +1075,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
for(extension=cl->extensions; extension; extension=extension->next)
if(extension->extension->handleMessage &&
extension->extension->handleMessage(cl, extension->data, msg))
extension->extension->handleMessage(cl, extension->data, &msg))
return;
if(cl->screen->processCustomClientMessage(cl,msg.type)) {

@ -466,6 +466,14 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
}
}
}
#undef DEBUG_READ_EXACT
#ifdef DEBUG_READ_EXACT
rfbLog("ReadExact %d bytes\n",len);
for(n=0;n<len;n++)
fprintf(stderr,"%02x ",(unsigned char)buf[n]);
fprintf(stderr,"\n");
#endif
return 1;
}

@ -0,0 +1,15 @@
DEFINES=-g -Wall
includedir=$(prefix)/include/rfb
noinst_HEADERS=filelistinfo.h filetransfermsg.h \
handlefiletransferrequest.h rfbtightproto.h
LIB_SRCS = rfbtightserver.c handlefiletransferrequest.c filetransfermsg.c \
filelistinfo.c
tightvnc_filetransfer_a_SOURCES=$(LIB_SRCS)
lib_LIBRARIES=tightvnc-filetransfer.a

@ -0,0 +1,130 @@
/*
* 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 : 14th July 2005
*/
#include <stdio.h>
#include "rfb/rfb.h"
#include "filelistinfo.h"
/* This method is used for debugging purpose */
void
DisplayFileList(FileListInfo fli)
{
int i = 0;
if((fli.pEntries == NULL) || (fli.numEntries == 0)) return;
rfbLog("DISPLAYING FILE NAMES IN THE LIST ...START\n\n");
rfbLog("Numer of entries:: %d\n", fli.numEntries);
for(i = 0; i < fli.numEntries; i++)
rfbLog("file[%d]\t<%s>\n", i, fli.pEntries[i].name);
rfbLog("DISPLAYING FILE NAMES IN THE LIST ...END\n\n");
}
int
AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name,
unsigned int size, unsigned int data)
{
FileListItemInfoPtr fileListItemInfoPtr = (FileListItemInfoPtr)
calloc((fileListInfoPtr->numEntries + 1),
sizeof(FileListItemInfo));
if(fileListItemInfoPtr == NULL) {
rfbLog("File [%s]: Method [%s]: fileListItemInfoPtr is NULL\n",
__FILE__, __FUNCTION__);
return FAILURE;
}
if(fileListInfoPtr->numEntries != 0) {
memcpy(fileListItemInfoPtr, fileListInfoPtr->pEntries,
fileListInfoPtr->numEntries * sizeof(FileListItemInfo));
}
strcpy(fileListItemInfoPtr[fileListInfoPtr->numEntries].name, name);
fileListItemInfoPtr[fileListInfoPtr->numEntries].size = size;
fileListItemInfoPtr[fileListInfoPtr->numEntries].data = data;
if(fileListInfoPtr->pEntries != NULL) {
free(fileListInfoPtr->pEntries);
fileListInfoPtr->pEntries = NULL;
}
fileListInfoPtr->pEntries = fileListItemInfoPtr;
fileListItemInfoPtr = NULL;
fileListInfoPtr->numEntries++;
return SUCCESS;
}
char*
GetFileNameAt(FileListInfo fileListInfo, int number)
{
char* name = NULL;
if(number >= 0 && number < fileListInfo.numEntries)
name = fileListInfo.pEntries[number].name;
return name;
}
unsigned int
GetFileSizeAt(FileListInfo fileListInfo, int number)
{
unsigned int size = 0;
if(number >= 0 && number < fileListInfo.numEntries)
size = fileListInfo.pEntries[number].size;
return size;
}
unsigned int
GetFileDataAt(FileListInfo fileListInfo, int number)
{
unsigned int data = 0;
if(number >= 0 && number < fileListInfo.numEntries)
data = fileListInfo.pEntries[number].data;
return data;
}
unsigned int
GetSumOfFileNamesLength(FileListInfo fileListInfo)
{
int i = 0, sumLen = 0;
for(i = 0; i < fileListInfo.numEntries; i++)
sumLen += strlen(fileListInfo.pEntries[i].name);
return sumLen;
}
void
FreeFileListInfo(FileListInfo fileListInfo)
{
if(fileListInfo.pEntries != NULL) {
free(fileListInfo.pEntries);
fileListInfo.pEntries = NULL;
}
fileListInfo.numEntries = 0;
}

@ -0,0 +1,61 @@
/*
* 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 : 14th July 2005
*/
#ifndef FILE_LIST_INFO_H
#define FILE_LIST_INFO_H
#include <limits.h>
#define SUCCESS 1
#define FAILURE 0
typedef struct _FileListItemInfo {
char name[NAME_MAX];
unsigned int size;
unsigned int data;
} FileListItemInfo, *FileListItemInfoPtr;
typedef struct _FileListItemSize {
unsigned int size;
unsigned int data;
} FileListItemSize, *FileListItemSizePtr;
typedef struct _FileListInfo {
FileListItemInfoPtr pEntries;
int numEntries;
} FileListInfo, *FileListInfoPtr;
int AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name, unsigned int size, unsigned int data);
char* GetFileNameAt(FileListInfo fileListInfo, int number);
unsigned int GetFileSizeAt(FileListInfo fileListInfo, int number);
unsigned int GetFileDataAt(FileListInfo fileListInfo, int number);
unsigned int GetSumOfFileNamesLength(FileListInfo fileListInfo);
void FreeFileListInfo(FileListInfo fileListInfo);
void DisplayFileList(FileListInfo fli);
#endif

@ -0,0 +1,632 @@
/*
* 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 : 14th July 2005
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <utime.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <rfb/rfb.h>
#include "rfbtightproto.h"
#include "filelistinfo.h"
#include "filetransfermsg.h"
#include "handlefiletransferrequest.h"
#define SZ_RFBBLOCKSIZE 8192
void
FreeFileTransferMsg(FileTransferMsg ftm)
{
if(ftm.data != NULL) {
free(ftm.data);
ftm.data = NULL;
}
ftm.length = 0;
}
/******************************************************************************
* Methods to handle file list request.
******************************************************************************/
int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
FileTransferMsg CreateFileListErrMsg(char flags);
FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
/*
* This is the method called by HandleFileListRequest to get the file list
*/
FileTransferMsg
GetFileListResponseMsg(char* path, char flags)
{
FileTransferMsg fileListMsg;
FileListInfo fileListInfo;
int status = -1;
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
memset(&fileListInfo, 0, sizeof(FileListInfo));
/* fileListInfo can have null data if the folder is Empty
or if some error condition has occured.
The return value is 'failure' only if some error condition has occured.
*/
status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
if(status == FAILURE) {
fileListMsg = CreateFileListErrMsg(flags);
}
else {
/* DisplayFileList(fileListInfo); For Debugging */
fileListMsg = CreateFileListMsg(fileListInfo, flags);
FreeFileListInfo(fileListInfo);
}
return fileListMsg;
}
int
CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
{
DIR* pDir = NULL;
struct dirent* pDirent = NULL;
if((path == NULL) || (strlen(path) == 0)) {
/* In this case we will send the list of entries in ftp root*/
sprintf(path, "%s%s", GetFtpRoot(), "/");
}
if((pDir = opendir(path)) == NULL) {
rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
__FILE__, __FUNCTION__);
return FAILURE;
}
while((pDirent = readdir(pDir))) {
if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
struct stat stat_buf;
/*
int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
*/
char fullpath[PATH_MAX];
memset(fullpath, 0, PATH_MAX);
strcpy(fullpath, path);
if(path[strlen(path)-1] != '/')
strcat(fullpath, "/");
strcat(fullpath, pDirent->d_name);
if(stat(fullpath, &stat_buf) < 0) {
rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
__FILE__, __FUNCTION__, fullpath);
continue;
}
if(S_ISDIR(stat_buf.st_mode)) {
if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
rfbLog("File [%s]: Method [%s]: Add directory %s in the"
" list failed\n", __FILE__, __FUNCTION__, fullpath);
continue;
}
}
else {
if(flag) {
if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
stat_buf.st_size,
stat_buf.st_mtime) == 0) {
rfbLog("File [%s]: Method [%s]: Add file %s in the "
"list failed\n", __FILE__, __FUNCTION__, fullpath);
continue;
}
}
}
}
}
if(closedir(pDir) < 0) {
rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
__FILE__, __FUNCTION__);
}
return SUCCESS;
}
FileTransferMsg
CreateFileListErrMsg(char flags)
{
FileTransferMsg fileListMsg;
rfbFileListDataMsg* pFLD = NULL;
char* data = NULL;
unsigned int length = 0;
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
if(data == NULL) {
return fileListMsg;
}
length = sizeof(rfbFileListDataMsg) * sizeof(char);
pFLD = (rfbFileListDataMsg*) data;
pFLD->type = rfbFileListData;
pFLD->numFiles = Swap16IfLE(0);
pFLD->dataSize = Swap16IfLE(0);
pFLD->compressedSize = Swap16IfLE(0);
pFLD->flags = flags | 0x80;
fileListMsg.data = data;
fileListMsg.length = length;
return fileListMsg;
}
FileTransferMsg
CreateFileListMsg(FileListInfo fileListInfo, char flags)
{
FileTransferMsg fileListMsg;
rfbFileListDataMsg* pFLD = NULL;
char *data = NULL, *pFileNames = NULL;
unsigned int length = 0, dsSize = 0, i = 0;
FileListItemSizePtr pFileListItemSize = NULL;
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
dsSize = fileListInfo.numEntries * 8;
length = sz_rfbFileListDataMsg + dsSize +
GetSumOfFileNamesLength(fileListInfo) +
fileListInfo.numEntries;
data = (char*) calloc(length, sizeof(char));
if(data == NULL) {
return fileListMsg;
}
pFLD = (rfbFileListDataMsg*) data;
pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
pFLD->type = rfbFileListData;
pFLD->flags = flags & 0xF0;
pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries);
pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
fileListInfo.numEntries);
pFLD->compressedSize = pFLD->dataSize;
for(i =0; i <fileListInfo.numEntries; i++) {
pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
if(i+1 < fileListInfo.numEntries)
pFileNames += strlen(pFileNames) + 1;
}
fileListMsg.data = data;
fileListMsg.length = length;
return fileListMsg;
}
/******************************************************************************
* Methods to handle File Download Request.
******************************************************************************/
FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
FileTransferMsg
GetFileDownLoadErrMsg()
{
FileTransferMsg fileDownloadErrMsg;
char reason[] = "An internal error on the server caused download failure";
int reasonLen = strlen(reason);
memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
return fileDownloadErrMsg;
}
FileTransferMsg
GetFileDownloadReadDataErrMsg()
{
char reason[] = "Cannot open file, perhaps it is absent or is a directory";
int reasonLen = strlen(reason);
return CreateFileDownloadErrMsg(reason, reasonLen);
}
FileTransferMsg
GetFileDownloadLengthErrResponseMsg()
{
char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
int reasonLen = strlen(reason);
return CreateFileDownloadErrMsg(reason, reasonLen);
}
FileTransferMsg
GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
//const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE;
int numOfBytesRead = 0;
char pBuf[SZ_RFBBLOCKSIZE];
char* path = rtcp->rcft.rcfd.fName;
memset(pBuf, 0, SZ_RFBBLOCKSIZE);
if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
__FILE__, __FUNCTION__);
return GetFileDownloadReadDataErrMsg();
}
rtcp->rcft.rcfd.downloadInProgress = TRUE;
}
if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
close(rtcp->rcft.rcfd.downloadFD);
rtcp->rcft.rcfd.downloadFD = -1;
rtcp->rcft.rcfd.downloadInProgress = FALSE;
if(numOfBytesRead == 0) {
return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
}
return GetFileDownloadReadDataErrMsg();
}
return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
}
}
FileTransferMsg
ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
FileTransferMsg fileDownloadMsg;
struct stat stat_buf;
int sz_rfbFileSize = 0;
char* path = rtcp->rcft.rcfd.fName;
memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
if( (path == NULL) || (strlen(path) == 0) ||
(stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
int reasonLen = strlen(reason);
rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
__FILE__, __FUNCTION__, path);
fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
}
else {
rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
sz_rfbFileSize = stat_buf.st_size;
if(sz_rfbFileSize <= 0) {
fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
}
}
return fileDownloadMsg;
}
FileTransferMsg
CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
{
FileTransferMsg fileDownloadErrMsg;
int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
rfbFileDownloadFailedMsg *pFDF = NULL;
char *pFollow = NULL;
char *pData = (char*) calloc(length, sizeof(char));
memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
if(pData == NULL) {
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
__FILE__, __FUNCTION__);
return fileDownloadErrMsg;
}
pFDF = (rfbFileDownloadFailedMsg *) pData;
pFollow = &pData[sz_rfbFileDownloadFailedMsg];
pFDF->type = rfbFileDownloadFailed;
pFDF->reasonLen = Swap16IfLE(reasonLen);
memcpy(pFollow, reason, reasonLen);
fileDownloadErrMsg.data = pData;
fileDownloadErrMsg.length = length;
return fileDownloadErrMsg;
}
FileTransferMsg
CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
{
FileTransferMsg fileDownloadZeroSizeDataMsg;
int length = sz_rfbFileDownloadDataMsg + sizeof(int);
rfbFileDownloadDataMsg *pFDD = NULL;
char *pFollow = NULL;
char *pData = (char*) calloc(length, sizeof(char));
memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
if(pData == NULL) {
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
__FILE__, __FUNCTION__);
return fileDownloadZeroSizeDataMsg;
}
pFDD = (rfbFileDownloadDataMsg *) pData;
pFollow = &pData[sz_rfbFileDownloadDataMsg];
pFDD->type = rfbFileDownloadData;
pFDD->compressLevel = 0;
pFDD->compressedSize = Swap16IfLE(0);
pFDD->realSize = Swap16IfLE(0);
memcpy(pFollow, &mTime, sizeof(unsigned long));
fileDownloadZeroSizeDataMsg.data = pData;
fileDownloadZeroSizeDataMsg.length = length;
return fileDownloadZeroSizeDataMsg;
}
FileTransferMsg
CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
{
FileTransferMsg fileDownloadBlockSizeDataMsg;
int length = sz_rfbFileDownloadDataMsg + sizeFile;
rfbFileDownloadDataMsg *pFDD = NULL;
char *pFollow = NULL;
char *pData = (char*) calloc(length, sizeof(char));
memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
if(NULL == pData) {
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
__FILE__, __FUNCTION__);
return fileDownloadBlockSizeDataMsg;
}
pFDD = (rfbFileDownloadDataMsg *) pData;
pFollow = &pData[sz_rfbFileDownloadDataMsg];
pFDD->type = rfbFileDownloadData;
pFDD->compressLevel = 0;
pFDD->compressedSize = Swap16IfLE(sizeFile);
pFDD->realSize = Swap16IfLE(sizeFile);
memcpy(pFollow, pFile, sizeFile);
fileDownloadBlockSizeDataMsg.data = pData;
fileDownloadBlockSizeDataMsg.length = length;
return fileDownloadBlockSizeDataMsg;
}
/******************************************************************************
* Methods to handle file upload request
******************************************************************************/
FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
FileTransferMsg
GetFileUploadLengthErrResponseMsg()
{
char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
int reasonLen = strlen(reason);
return CreateFileUploadErrMsg(reason, reasonLen);
}
FileTransferMsg
ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
FileTransferMsg fileUploadErrMsg;
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
if( (rtcp->rcft.rcfu.fName == NULL) ||
(strlen(rtcp->rcft.rcfu.fName) == 0) ||
((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
char reason[] = "Could not create file";
int reasonLen = strlen(reason);
fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
}
else
rtcp->rcft.rcfu.uploadInProgress = TRUE;
return fileUploadErrMsg;
}
FileTransferMsg
GetFileUploadCompressedLevelErrMsg()
{
char reason[] = "Server does not support data compression on upload";
int reasonLen = strlen(reason);
return CreateFileUploadErrMsg(reason, reasonLen);
}
FileTransferMsg
ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
{
FileTransferMsg ftm;
unsigned long numOfBytesWritten = 0;
memset(&ftm, 0, sizeof(FileTransferMsg));
numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
char reason[] = "Error writing file data";
int reasonLen = strlen(reason);
ftm = CreateFileUploadErrMsg(reason, reasonLen);
CloseUndoneFileTransfer(cl, rtcp);
}
return ftm;
}
void
FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
/* Here we are settimg the modification and access time of the file */
/* Windows code stes mod/access/creation time of the file */
struct utimbuf utb;
utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
rfbLog("File [%s]: Method [%s]: Setting the modification/access"
" time for the file <%s> failed\n", __FILE__,
__FUNCTION__, rtcp->rcft.rcfu.fName);
}
if(rtcp->rcft.rcfu.uploadFD != -1) {
close(rtcp->rcft.rcfu.uploadFD);
rtcp->rcft.rcfu.uploadFD = -1;
rtcp->rcft.rcfu.uploadInProgress = FALSE;
}
}
FileTransferMsg
CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
{
FileTransferMsg fileUploadErrMsg;
int length = sz_rfbFileUploadCancelMsg + reasonLen;
rfbFileUploadCancelMsg *pFDF = NULL;
char *pFollow = NULL;
char *pData = (char*) calloc(length, sizeof(char));
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
if(pData == NULL) {
rfbLog("File [%s]: Method [%s]: pData is NULL\n",
__FILE__, __FUNCTION__);
return fileUploadErrMsg;
}
pFDF = (rfbFileUploadCancelMsg *) pData;
pFollow = &pData[sz_rfbFileUploadCancelMsg];
pFDF->type = rfbFileUploadCancel;
pFDF->reasonLen = Swap16IfLE(reasonLen);
memcpy(pFollow, reason, reasonLen);
fileUploadErrMsg.data = pData;
fileUploadErrMsg.length = length;
return fileUploadErrMsg;
}
/******************************************************************************
* Method to cancel File Transfer operation.
******************************************************************************/
void
CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
/* TODO :: File Upload case is not handled currently */
/* TODO :: In case of concurrency we need to use Critical Section */
if(cl == NULL)
return;
if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
rtcp->rcft.rcfu.uploadInProgress = FALSE;
if(rtcp->rcft.rcfu.uploadFD != -1) {
close(rtcp->rcft.rcfu.uploadFD);
rtcp->rcft.rcfu.uploadFD = -1;
}
if(unlink(rtcp->rcft.rcfu.fName) == -1) {
rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
__FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
}
memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
}
if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
rtcp->rcft.rcfd.downloadInProgress = FALSE;
if(rtcp->rcft.rcfd.downloadFD != -1) {
close(rtcp->rcft.rcfd.downloadFD);
rtcp->rcft.rcfd.downloadFD = -1;
}
memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
}
}
/******************************************************************************
* Method to handle create directory request.
******************************************************************************/
void
CreateDirectory(char* dirName)
{
if(dirName == NULL) return;
if(mkdir(dirName, 0700) == -1) {
rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
__FILE__, __FUNCTION__, dirName);
}
}

@ -0,0 +1,54 @@
/*
* 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 : 14th July 2005
*/
#ifndef FILE_TRANSFER_MSG_H
#define FILE_TRANSFER_MSG_H
typedef struct _FileTransferMsg {
char* data;
unsigned int length;
} FileTransferMsg;
FileTransferMsg GetFileListResponseMsg(char* path, char flag);
FileTransferMsg GetFileDownloadResponseMsg(char* path);
FileTransferMsg GetFileDownloadLengthErrResponseMsg();
FileTransferMsg GetFileDownLoadErrMsg();
FileTransferMsg GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr data);
FileTransferMsg ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr data);
FileTransferMsg GetFileUploadLengthErrResponseMsg();
FileTransferMsg GetFileUploadCompressedLevelErrMsg();
FileTransferMsg ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr data);
FileTransferMsg ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr data, char* pBuf);
void CreateDirectory(char* dirName);
void FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr data);
void CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr data);
void FreeFileTransferMsg(FileTransferMsg ftm);
#endif

@ -0,0 +1,988 @@
/*
* 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 : 14th July 2005
*/
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <rfb/rfb.h>
#include "rfbtightproto.h"
#include "filetransfermsg.h"
#include "handlefiletransferrequest.h"
pthread_mutex_t fileDownloadMutex = PTHREAD_MUTEX_INITIALIZER;
rfbBool fileTransferEnabled = TRUE;
rfbBool fileTransferInitted = FALSE;
char ftproot[PATH_MAX];
/******************************************************************************
* File Transfer Init methods. These methods are called for initializating
* File Transfer and setting ftproot.
******************************************************************************/
void InitFileTransfer();
int SetFtpRoot(char* path);
char* GetHomeDir(uid_t uid);
void FreeHomeDir(char *homedir);
/*
* InitFileTransfer method is called before parsing the command-line options
* for Xvnc. This sets the ftproot to the Home dir of the user running the Xvnc
* server. In case of error ftproot is set to '\0' char.
*/
void
InitFileTransfer()
{
char* userHome = NULL;
uid_t uid = geteuid();
if(fileTransferInitted)
return;
memset(ftproot, 0, sizeof(ftproot));
userHome = GetHomeDir(uid);
if((userHome != NULL) && (strlen(userHome) != 0)) {
SetFtpRoot(userHome);
FreeHomeDir(userHome);
}
fileTransferEnabled = TRUE;
fileTransferInitted = TRUE;
}
/*
* This method is called from InitFileTransfer method and
* if the command line option for ftproot is provided.
*/
int
SetFtpRoot(char* path)
{
struct stat stat_buf;
DIR* dir = NULL;
if((path == NULL) || (strlen(path) == 0) || (strlen(path) > (PATH_MAX - 1))) {
rfbLog("File [%s]: Method [%s]: parameter passed is improper, ftproot"
" not changed\n", __FILE__, __FUNCTION__);
return FALSE;
}
if(stat(path, &stat_buf) < 0) {
rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
__FILE__, __FUNCTION__, path);
return FALSE;
}
if(S_ISDIR(stat_buf.st_mode) == 0) {
rfbLog("File [%s]: Method [%s]: path specified is not a directory\n",
__FILE__, __FUNCTION__);
return FALSE;
}
if((dir = opendir(path)) == NULL) {
rfbLog("File [%s]: Method [%s]: Not able to open the directory\n",
__FILE__, __FUNCTION__);
return FALSE;
}
else {
closedir(dir);
dir = NULL;
}
memset(ftproot, 0, PATH_MAX);
if(path[strlen(path)-1] == '/') {
memcpy(ftproot, path, strlen(path)-1);
}
else
memcpy(ftproot, path, strlen(path));
return TRUE;
}
/*
* Get the home directory for the user name
* param: username - name of the user for whom the home directory is required.
* returns: returns the home directory for the user, or null in case the entry
* is not found or any error. The returned string must be freed by calling the
* freehomedir function.
*/
char*
GetHomeDir(uid_t uid)
{
struct passwd *pwEnt = NULL;
char *homedir = NULL;
pwEnt = getpwuid (uid);
if (pwEnt == NULL)
return NULL;
if(pwEnt->pw_dir != NULL) {
homedir = strdup (pwEnt->pw_dir);
}
return homedir;
}
/*
* Free the home directory allocated by a previous call to retrieve the home
* directory. param: homedir - the string returned by a previous call to
* retrieve home directory for a user.
*/
void
FreeHomeDir(char *homedir)
{
free (homedir);
}
/******************************************************************************
* General methods.
******************************************************************************/
/*
* When the console sends the File Transfer Request, it sends the file path with
* ftproot as "/". So on Agent, to get the absolute file path we need to prepend
* the ftproot to it.
*/
char*
ConvertPath(char* path)
{
char p[PATH_MAX];
memset(p, 0, PATH_MAX);
if( (path == NULL) ||
(strlen(path) == 0) ||
(strlen(path)+strlen(ftproot) > PATH_MAX - 1) ) {
rfbLog("File [%s]: Method [%s]: cannot create path for file transfer\n",
__FILE__, __FUNCTION__);
return NULL;
}
memcpy(p, path, strlen(path));
memset(path, 0, PATH_MAX);
sprintf(path, "%s%s", ftproot, p);
return path;
}
void
EnableFileTransfer(rfbBool enable)
{
fileTransferEnabled = enable;
}
rfbBool
IsFileTransferEnabled()
{
return fileTransferEnabled;
}
char*
GetFtpRoot()
{
return ftproot;
}
/******************************************************************************
* Methods to Handle File List Request.
******************************************************************************/
/*
* HandleFileListRequest method is called when the server receives
* FileListRequest. In case of success a file list is sent to the client.
* For File List Request there is no failure reason sent.So here in case of any
* "unexpected" error no information will be sent. As these conditions should
* never come. Lets hope it never arrives :)
* In case of dir open failure an empty list will be sent, just the header of
* the message filled up. So on console you will get an Empty listing.
*/
void
HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data)
{
rfbClientToServerTightMsg msg;
int n = 0;
char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
FileTransferMsg fileListMsg;
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
memset(path, 0, PATH_MAX);
memset(&fileListMsg, 0, sizeof(FileTransferMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileListRequestMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Socket error while reading dir name"
" length\n", __FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.flr.dirNameSize = Swap16IfLE(msg.flr.dirNameSize);
if ((msg.flr.dirNameSize == 0) ||
(msg.flr.dirNameSize > (PATH_MAX - 1))) {
rfbLog("File [%s]: Method [%s]: Unexpected error:: path length is "
"greater that PATH_MAX\n", __FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, path, msg.flr.dirNameSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Socket error while reading dir name\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
if(ConvertPath(path) == NULL) {
/* The execution should never reach here */
rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL",
__FILE__, __FUNCTION__);
return;
}
fileListMsg = GetFileListResponseMsg(path, (char) (msg.flr.flags));
if((fileListMsg.data == NULL) || (fileListMsg.length == 0)) {
rfbLog("File [%s]: Method [%s]: Unexpected error:: Data to be sent is "
"of Zero length\n", __FILE__, __FUNCTION__);
return;
}
rfbWriteExact(cl, fileListMsg.data, fileListMsg.length);
FreeFileTransferMsg(fileListMsg);
}
/******************************************************************************
* Methods to Handle File Download Request.
******************************************************************************/
void HandleFileDownloadLengthError(rfbClientPtr cl, short fNameSize);
void SendFileDownloadLengthErrMsg(rfbClientPtr cl);
void HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr data);
#ifdef TODO
void HandleFileDownloadRequest(rfbClientPtr cl);
void SendFileDownloadErrMsg(rfbClientPtr cl);
void* RunFileDownloadThread(void* client);
#endif
/*
* HandleFileDownloadRequest method is called when the server receives
* rfbFileDownload request message.
*/
void
HandleFileDownloadRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
rfbClientToServerTightMsg msg;
memset(path, 0, sizeof(path));
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error:: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileDownloadRequestMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading dir name length\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fdr.fNameSize = Swap16IfLE(msg.fdr.fNameSize);
msg.fdr.position = Swap16IfLE(msg.fdr.position);
if ((msg.fdr.fNameSize == 0) ||
(msg.fdr.fNameSize > (PATH_MAX - 1))) {
rfbLog("File [%s]: Method [%s]: Error: path length is greater than"
" PATH_MAX\n", __FILE__, __FUNCTION__);
HandleFileDownloadLengthError(cl, msg.fdr.fNameSize);
return;
}
if((n = rfbReadExact(cl, rtcp->rcft.rcfd.fName, msg.fdr.fNameSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading dir name length\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
rtcp->rcft.rcfd.fName[msg.fdr.fNameSize] = '\0';
if(ConvertPath(rtcp->rcft.rcfd.fName) == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL",
__FILE__, __FUNCTION__);
/* This condition can come only if the file path is greater than
PATH_MAX. So sending file path length error msg back to client.
*/
SendFileDownloadLengthErrMsg(cl);
return;
}
HandleFileDownload(cl, rtcp);
}
void
HandleFileDownloadLengthError(rfbClientPtr cl, short fNameSize)
{
char *path = NULL;
int n = 0;
if((path = (char*) calloc(fNameSize, sizeof(char))) == NULL) {
rfbLog("File [%s]: Method [%s]: Fatal Error: Alloc failed\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, path, fNameSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading dir name\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
if(path != NULL) {
free(path);
path = NULL;
}
return;
}
if(path != NULL) {
free(path);
path = NULL;
}
SendFileDownloadLengthErrMsg(cl);
}
void
SendFileDownloadLengthErrMsg(rfbClientPtr cl)
{
FileTransferMsg fileDownloadErrMsg;
memset(&fileDownloadErrMsg, 0 , sizeof(FileTransferMsg));
fileDownloadErrMsg = GetFileDownloadLengthErrResponseMsg();
if((fileDownloadErrMsg.data == NULL) || (fileDownloadErrMsg.length == 0)) {
rfbLog("File [%s]: Method [%s]: Unexpected error: fileDownloadErrMsg "
"is null\n", __FILE__, __FUNCTION__);
return;
}
rfbWriteExact(cl, fileDownloadErrMsg.data, fileDownloadErrMsg.length);
FreeFileTransferMsg(fileDownloadErrMsg);
}
extern rfbTightClientPtr rfbGetTightClientData(rfbClientPtr cl);
void*
RunFileDownloadThread(void* client)
{
rfbClientPtr cl = (rfbClientPtr) client;
rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
FileTransferMsg fileDownloadMsg;
if(rtcp == NULL)
return NULL;
memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
do {
pthread_mutex_lock(&fileDownloadMutex);
fileDownloadMsg = GetFileDownloadResponseMsgInBlocks(cl, rtcp);
pthread_mutex_unlock(&fileDownloadMutex);
if((fileDownloadMsg.data != NULL) && (fileDownloadMsg.length != 0)) {
if(rfbWriteExact(cl, fileDownloadMsg.data, fileDownloadMsg.length) < 0) {
rfbLog("File [%s]: Method [%s]: Error while writing to socket \n"
, __FILE__, __FUNCTION__);
if(cl != NULL) {
rfbCloseClient(cl);
CloseUndoneFileTransfer(cl, rtcp);
}
FreeFileTransferMsg(fileDownloadMsg);
return NULL;
}
FreeFileTransferMsg(fileDownloadMsg);
}
} while(rtcp->rcft.rcfd.downloadInProgress == TRUE);
return NULL;
}
void
HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
pthread_t fileDownloadThread;
FileTransferMsg fileDownloadMsg;
memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
fileDownloadMsg = ChkFileDownloadErr(cl, rtcp);
if((fileDownloadMsg.data != NULL) && (fileDownloadMsg.length != 0)) {
rfbWriteExact(cl, fileDownloadMsg.data, fileDownloadMsg.length);
FreeFileTransferMsg(fileDownloadMsg);
return;
}
rtcp->rcft.rcfd.downloadInProgress = FALSE;
rtcp->rcft.rcfd.downloadFD = -1;
if(pthread_create(&fileDownloadThread, NULL, RunFileDownloadThread, (void*)
cl) != 0) {
FileTransferMsg ftm = GetFileDownLoadErrMsg();
rfbLog("File [%s]: Method [%s]: Download thread creation failed\n",
__FILE__, __FUNCTION__);
if((ftm.data != NULL) && (ftm.length != 0)) {
rfbWriteExact(cl, ftm.data, ftm.length);
FreeFileTransferMsg(ftm);
return;
}
}
}
/******************************************************************************
* Methods to Handle File Download Cancel Request.
******************************************************************************/
void
HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char *reason = NULL;
rfbClientToServerTightMsg msg;
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileDownloadCancelMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading "
"FileDownloadCancelMsg\n", __FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fdc.reasonLen = Swap16IfLE(msg.fdc.reasonLen);
if(msg.fdc.reasonLen == 0) {
rfbLog("File [%s]: Method [%s]: reason length received is Zero\n",
__FILE__, __FUNCTION__);
return;
}
reason = (char*) calloc(msg.fdc.reasonLen + 1, sizeof(char));
if(reason == NULL) {
rfbLog("File [%s]: Method [%s]: Fatal Error: Memory alloc failed\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, reason, msg.fdc.reasonLen)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading "
"FileDownloadCancelMsg\n", __FILE__, __FUNCTION__);
rfbCloseClient(cl);
}
rfbLog("File [%s]: Method [%s]: File Download Cancel Request received:"
" reason <%s>\n", __FILE__, __FUNCTION__, reason);
pthread_mutex_lock(&fileDownloadMutex);
CloseUndoneFileTransfer(cl, rtcp);
pthread_mutex_unlock(&fileDownloadMutex);
if(reason != NULL) {
free(reason);
reason = NULL;
}
}
/******************************************************************************
* Methods to Handle File upload request
******************************************************************************/
#ifdef TODO
void HandleFileUploadRequest(rfbClientPtr cl);
#endif
void HandleFileUpload(rfbClientPtr cl, rfbTightClientPtr data);
void HandleFileUploadLengthError(rfbClientPtr cl, short fNameSize);
void SendFileUploadLengthErrMsg(rfbClientPtr cl);
void
HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
rfbClientToServerTightMsg msg;
memset(path, 0, PATH_MAX);
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadRequestMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fupr.fNameSize = Swap16IfLE(msg.fupr.fNameSize);
msg.fupr.position = Swap16IfLE(msg.fupr.position);
if ((msg.fupr.fNameSize == 0) ||
(msg.fupr.fNameSize > (PATH_MAX - 1))) {
rfbLog("File [%s]: Method [%s]: error: path length is greater than PATH_MAX\n",
__FILE__, __FUNCTION__);
HandleFileUploadLengthError(cl, msg.fupr.fNameSize);
return;
}
if((n = rfbReadExact(cl, rtcp->rcft.rcfu.fName, msg.fupr.fNameSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n"
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
rtcp->rcft.rcfu.fName[msg.fupr.fNameSize] = '\0';
if(ConvertPath(rtcp->rcft.rcfu.fName) == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL\n",
__FILE__, __FUNCTION__);
/* This may come if the path length exceeds PATH_MAX.
So sending path length error to client
*/
SendFileUploadLengthErrMsg(cl);
return;
}
HandleFileUpload(cl, rtcp);
}
void
HandleFileUploadLengthError(rfbClientPtr cl, short fNameSize)
{
char *path = NULL;
int n = 0;
if((path = (char*) calloc(fNameSize, sizeof(char))) == NULL) {
rfbLog("File [%s]: Method [%s]: Fatal Error: Alloc failed\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, path, fNameSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading dir name\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
if(path != NULL) {
free(path);
path = NULL;
}
return;
}
rfbLog("File [%s]: Method [%s]: File Upload Length Error occured"
"file path requested is <%s>\n", __FILE__, __FUNCTION__, path);
if(path != NULL) {
free(path);
path = NULL;
}
SendFileUploadLengthErrMsg(cl);
}
void
SendFileUploadLengthErrMsg(rfbClientPtr cl)
{
FileTransferMsg fileUploadErrMsg;
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
fileUploadErrMsg = GetFileUploadLengthErrResponseMsg();
if((fileUploadErrMsg.data == NULL) || (fileUploadErrMsg.length == 0)) {
rfbLog("File [%s]: Method [%s]: Unexpected error: fileUploadErrMsg is null\n",
__FILE__, __FUNCTION__);
return;
}
rfbWriteExact(cl, fileUploadErrMsg.data, fileUploadErrMsg.length);
FreeFileTransferMsg(fileUploadErrMsg);
}
void
HandleFileUpload(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
FileTransferMsg fileUploadErrMsg;
memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
rtcp->rcft.rcfu.uploadInProgress = FALSE;
rtcp->rcft.rcfu.uploadFD = -1;
fileUploadErrMsg = ChkFileUploadErr(cl, rtcp);
if((fileUploadErrMsg.data != NULL) && (fileUploadErrMsg.length != 0)) {
rfbWriteExact(cl, fileUploadErrMsg.data, fileUploadErrMsg.length);
FreeFileTransferMsg(fileUploadErrMsg);
}
}
/******************************************************************************
* Methods to Handle File Upload Data Request
*****************************************************************************/
void HandleFileUploadWrite(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf);
void
HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char* pBuf = NULL;
rfbClientToServerTightMsg msg;
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadDataMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fud.realSize = Swap16IfLE(msg.fud.realSize);
msg.fud.compressedSize = Swap16IfLE(msg.fud.compressedSize);
if((msg.fud.realSize == 0) && (msg.fud.compressedSize == 0)) {
if((n = rfbReadExact(cl, (char*)&(rtcp->rcft.rcfu.mTime), sizeof(unsigned
long))) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
FileUpdateComplete(cl, rtcp);
return;
}
pBuf = (char*) calloc(msg.fud.compressedSize, sizeof(char));
if(pBuf == NULL) {
rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, pBuf, msg.fud.compressedSize)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
if(pBuf != NULL) {
free(pBuf);
pBuf = NULL;
}
return;
}
if(msg.fud.compressedLevel != 0) {
FileTransferMsg ftm;
memset(&ftm, 0, sizeof(FileTransferMsg));
ftm = GetFileUploadCompressedLevelErrMsg();
if((ftm.data != NULL) && (ftm.length != 0)) {
rfbWriteExact(cl, ftm.data, ftm.length);
FreeFileTransferMsg(ftm);
}
CloseUndoneFileTransfer(cl, rtcp);
if(pBuf != NULL) {
free(pBuf);
pBuf = NULL;
}
return;
}
rtcp->rcft.rcfu.fSize = msg.fud.compressedSize;
HandleFileUploadWrite(cl, rtcp, pBuf);
if(pBuf != NULL) {
free(pBuf);
pBuf = NULL;
}
}
void
HandleFileUploadWrite(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
{
FileTransferMsg ftm;
memset(&ftm, 0, sizeof(FileTransferMsg));
ftm = ChkFileUploadWriteErr(cl, rtcp, pBuf);
if((ftm.data != NULL) && (ftm.length != 0)) {
rfbWriteExact(cl, ftm.data, ftm.length);
FreeFileTransferMsg(ftm);
}
}
/******************************************************************************
* Methods to Handle File Upload Failed Request.
******************************************************************************/
void
HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char* reason = NULL;
rfbClientToServerTightMsg msg;
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadFailedMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fuf.reasonLen = Swap16IfLE(msg.fuf.reasonLen);
if(msg.fuf.reasonLen == 0) {
rfbLog("File [%s]: Method [%s]: reason length received is Zero\n",
__FILE__, __FUNCTION__);
return;
}
reason = (char*) calloc(msg.fuf.reasonLen + 1, sizeof(char));
if(reason == NULL) {
rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, reason, msg.fuf.reasonLen)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
if(reason != NULL) {
free(reason);
reason = NULL;
}
return;
}
rfbLog("File [%s]: Method [%s]: File Upload Failed Request received:"
" reason <%s>\n", __FILE__, __FUNCTION__, reason);
CloseUndoneFileTransfer(cl, rtcp);
if(reason != NULL) {
free(reason);
reason = NULL;
}
}
/******************************************************************************
* Methods to Handle File Create Request.
******************************************************************************/
void
HandleFileCreateDirRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
{
int n = 0;
char dirName[PATH_MAX];
rfbClientToServerTightMsg msg;
memset(dirName, 0, PATH_MAX);
memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
if(cl == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
__FILE__, __FUNCTION__);
return;
}
if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileCreateDirRequestMsg-1)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileCreateDirRequestMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
msg.fcdr.dNameLen = Swap16IfLE(msg.fcdr.dNameLen);
/* TODO :: chk if the dNameLen is greater than PATH_MAX */
if((n = rfbReadExact(cl, dirName, msg.fcdr.dNameLen)) <= 0) {
if (n < 0)
rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
__FILE__, __FUNCTION__);
rfbCloseClient(cl);
return;
}
if(ConvertPath(dirName) == NULL) {
rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL\n",
__FILE__, __FUNCTION__);
return;
}
CreateDirectory(dirName);
}

@ -0,0 +1,47 @@
/*
* 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 : 14th July 2005
*/
#ifndef HANDLE_FILE_TRANSFER_REQUEST_H
#define HANDLE_FILE_TRANSFER_REQUEST_H
#include <rfb/rfb.h>
void InitFileTransfer();
int SetFtpRoot(char* path);
void EnableFileTransfer(rfbBool enable);
rfbBool IsFileTransferEnabled();
char* GetFtpRoot();
void HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileDownloadRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientRec* data);
void HandleFileCreateDirRequest(rfbClientPtr cl, rfbTightClientRec* data);
#endif

@ -0,0 +1,450 @@
/*
* 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
*/
#ifndef RFBTIGHTPROTO_H
#define RFBTIGHTPROTO_H
#include <rfb/rfb.h>
#include <limits.h>
#define rfbSecTypeTight 16
void rfbTightUsage(void);
int rfbTightProcessArgs(int argc, char *argv[]);
/*-----------------------------------------------------------------------------
* Negotiation of Tunneling Capabilities (protocol version 3.7t)
*
* If the chosen security type is rfbSecTypeTight, the server sends a list of
* supported tunneling methods ("tunneling" refers to any additional layer of
* data transformation, such as encryption or external compression.)
*
* nTunnelTypes specifies the number of following rfbCapabilityInfo structures
* that list all supported tunneling methods in the order of preference.
*
* NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
* used, and the client should not send a response requesting a tunneling
* method.
*/
typedef struct _rfbTunnelingCapsMsg {
uint32_t nTunnelTypes;
/* followed by nTunnelTypes * rfbCapabilityInfo structures */
} rfbTunnelingCapsMsg;
#define sz_rfbTunnelingCapsMsg 4
/*-----------------------------------------------------------------------------
* Tunneling Method Request (protocol version 3.7t)
*
* If the list of tunneling capabilities sent by the server was not empty, the
* client should reply with a 32-bit code specifying a particular tunneling
* method. The following code should be used for no tunneling.
*/
#define rfbNoTunneling 0
#define sig_rfbNoTunneling "NOTUNNEL"
/*-----------------------------------------------------------------------------
* Negotiation of Authentication Capabilities (protocol version 3.7t)
*
* After setting up tunneling, the server sends a list of supported
* authentication schemes.
*
* nAuthTypes specifies the number of following rfbCapabilityInfo structures
* that list all supported authentication schemes in the order of preference.
*
* NOTE: If nAuthTypes is 0, that tells the client that no authentication is
* necessary, and the client should not send a response requesting an
* authentication scheme.
*/
typedef struct _rfbAuthenticationCapsMsg {
uint32_t nAuthTypes;
/* followed by nAuthTypes * rfbCapabilityInfo structures */
} rfbAuthenticationCapsMsg;
#define sz_rfbAuthenticationCapsMsg 4
/*-----------------------------------------------------------------------------
* Authentication Scheme Request (protocol version 3.7t)
*
* If the list of authentication capabilities sent by the server was not empty,
* the client should reply with a 32-bit code specifying a particular
* authentication scheme. The following codes are supported.
*/
#define rfbAuthNone 1
#define rfbAuthVNC 2
#define rfbAuthUnixLogin 129
#define rfbAuthExternal 130
#define sig_rfbAuthNone "NOAUTH__"
#define sig_rfbAuthVNC "VNCAUTH_"
#define sig_rfbAuthUnixLogin "ULGNAUTH"
#define sig_rfbAuthExternal "XTRNAUTH"
/*-----------------------------------------------------------------------------
* Structure used to describe protocol options such as tunneling methods,
* authentication schemes and message types (protocol version 3.7t).
*/
typedef struct _rfbCapabilityInfo {
uint32_t code; /* numeric identifier */
uint8_t vendorSignature[4]; /* vendor identification */
uint8_t nameSignature[8]; /* abbreviated option name */
} rfbCapabilityInfo;
#define sz_rfbCapabilityInfoVendor 4
#define sz_rfbCapabilityInfoName 8
#define sz_rfbCapabilityInfo 16
/*
* Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
*/
#define rfbStandardVendor "STDV"
#define rfbTridiaVncVendor "TRDV"
#define rfbTightVncVendor "TGHT"
/* It's a good idea to keep these values a bit greater than required. */
#define MAX_TIGHT_ENCODINGS 10
#define MAX_TUNNELING_CAPS 16
#define MAX_AUTH_CAPS 16
typedef struct _rfbClientFileDownload {
char fName[PATH_MAX];
int downloadInProgress;
unsigned long mTime;
int downloadFD;
} rfbClientFileDownload ;
typedef struct _rfbClientFileUpload {
char fName[PATH_MAX];
int uploadInProgress;
unsigned long mTime;
unsigned long fSize;
int uploadFD;
} rfbClientFileUpload ;
typedef struct _rfbClientFileTransfer {
rfbClientFileDownload rcfd;
rfbClientFileUpload rcfu;
} rfbClientFileTransfer;
typedef struct _rfbTightClientRec {
/* Lists of capability codes sent to clients. We remember these
lists to restrict clients from choosing those tunneling and
authentication types that were not advertised. */
int nAuthCaps;
uint32_t authCaps[MAX_AUTH_CAPS];
/* This is not useful while we don't support tunneling:
int nTunnelingCaps;
uint32_t tunnelingCaps[MAX_TUNNELING_CAPS]; */
rfbClientFileTransfer rcft;
} rfbTightClientRec, *rfbTightClientPtr;
/*
* Macro to fill in an rfbCapabilityInfo structure (protocol 3.7t).
* Normally, using macros is no good, but this macro saves us from
* writing constants twice -- it constructs signature names from codes.
* Note that "code_sym" argument should be a single symbol, not an expression.
*/
#define SetCapInfo(cap_ptr, code_sym, vendor) \
{ \
rfbCapabilityInfo *pcap; \
pcap = (cap_ptr); \
pcap->code = Swap32IfLE(code_sym); \
memcpy(pcap->vendorSignature, (vendor), \
sz_rfbCapabilityInfoVendor); \
memcpy(pcap->nameSignature, sig_##code_sym, \
sz_rfbCapabilityInfoName); \
}
void rfbHandleSecTypeTight(rfbClientPtr cl);
/*-----------------------------------------------------------------------------
* Server Interaction Capabilities Message (protocol version 3.7t)
*
* In the protocol version 3.7t, the server informs the client what message
* types it supports in addition to ones defined in the protocol version 3.7.
* Also, the server sends the list of all supported encodings (note that it's
* not necessary to advertise the "raw" encoding sinse it MUST be supported in
* RFB 3.x protocols).
*
* This data immediately follows the server initialisation message.
*/
typedef struct _rfbInteractionCapsMsg {
uint16_t nServerMessageTypes;
uint16_t nClientMessageTypes;
uint16_t nEncodingTypes;
uint16_t pad; /* reserved, must be 0 */
/* followed by nServerMessageTypes * rfbCapabilityInfo structures */
/* followed by nClientMessageTypes * rfbCapabilityInfo structures */
} rfbInteractionCapsMsg;
#define sz_rfbInteractionCapsMsg 8
#define rfbFileListData 130
#define rfbFileDownloadData 131
#define rfbFileUploadCancel 132
#define rfbFileDownloadFailed 133
/* signatures for non-standard messages */
#define sig_rfbFileListData "FTS_LSDT"
#define sig_rfbFileDownloadData "FTS_DNDT"
#define sig_rfbFileUploadCancel "FTS_UPCN"
#define sig_rfbFileDownloadFailed "FTS_DNFL"
#define rfbFileListRequest 130
#define rfbFileDownloadRequest 131
#define rfbFileUploadRequest 132
#define rfbFileUploadData 133
#define rfbFileDownloadCancel 134
#define rfbFileUploadFailed 135
#define rfbFileCreateDirRequest 136
/* signatures for non-standard messages */
#define sig_rfbFileListRequest "FTC_LSRQ"
#define sig_rfbFileDownloadRequest "FTC_DNRQ"
#define sig_rfbFileUploadRequest "FTC_UPRQ"
#define sig_rfbFileUploadData "FTC_UPDT"
#define sig_rfbFileDownloadCancel "FTC_DNCN"
#define sig_rfbFileUploadFailed "FTC_UPFL"
#define sig_rfbFileCreateDirRequest "FTC_FCDR"
/* signatures for basic encoding types */
#define sig_rfbEncodingRaw "RAW_____"
#define sig_rfbEncodingCopyRect "COPYRECT"
#define sig_rfbEncodingRRE "RRE_____"
#define sig_rfbEncodingCoRRE "CORRE___"
#define sig_rfbEncodingHextile "HEXTILE_"
#define sig_rfbEncodingZlib "ZLIB____"
#define sig_rfbEncodingTight "TIGHT___"
#define sig_rfbEncodingZlibHex "ZLIBHEX_"
/* signatures for "fake" encoding types */
#define sig_rfbEncodingCompressLevel0 "COMPRLVL"
#define sig_rfbEncodingXCursor "X11CURSR"
#define sig_rfbEncodingRichCursor "RCHCURSR"
#define sig_rfbEncodingPointerPos "POINTPOS"
#define sig_rfbEncodingLastRect "LASTRECT"
#define sig_rfbEncodingNewFBSize "NEWFBSIZ"
#define sig_rfbEncodingQualityLevel0 "JPEGQLVL"
/*-----------------------------------------------------------------------------
* FileListRequest
*/
typedef struct _rfbFileListRequestMsg {
uint8_t type;
uint8_t flags;
uint16_t dirNameSize;
/* Followed by char Dirname[dirNameSize] */
} rfbFileListRequestMsg;
#define sz_rfbFileListRequestMsg 4
/*-----------------------------------------------------------------------------
* FileDownloadRequest
*/
typedef struct _rfbFileDownloadRequestMsg {
uint8_t type;
uint8_t compressedLevel;
uint16_t fNameSize;
uint32_t position;
/* Followed by char Filename[fNameSize] */
} rfbFileDownloadRequestMsg;
#define sz_rfbFileDownloadRequestMsg 8
/*-----------------------------------------------------------------------------
* FileUploadRequest
*/
typedef struct _rfbFileUploadRequestMsg {
uint8_t type;
uint8_t compressedLevel;
uint16_t fNameSize;
uint32_t position;
/* Followed by char Filename[fNameSize] */
} rfbFileUploadRequestMsg;
#define sz_rfbFileUploadRequestMsg 8
/*-----------------------------------------------------------------------------
* FileUploadData
*/
typedef struct _rfbFileUploadDataMsg {
uint8_t type;
uint8_t compressedLevel;
uint16_t realSize;
uint16_t compressedSize;
/* Followed by File[compressedSize],
but if (realSize = compressedSize = 0) followed by uint32_t modTime */
} rfbFileUploadDataMsg;
#define sz_rfbFileUploadDataMsg 6
/*-----------------------------------------------------------------------------
* FileDownloadCancel
*/
typedef struct _rfbFileDownloadCancelMsg {
uint8_t type;
uint8_t unused;
uint16_t reasonLen;
/* Followed by reason[reasonLen] */
} rfbFileDownloadCancelMsg;
#define sz_rfbFileDownloadCancelMsg 4
/*-----------------------------------------------------------------------------
* FileUploadFailed
*/
typedef struct _rfbFileUploadFailedMsg {
uint8_t type;
uint8_t unused;
uint16_t reasonLen;
/* Followed by reason[reasonLen] */
} rfbFileUploadFailedMsg;
#define sz_rfbFileUploadFailedMsg 4
/*-----------------------------------------------------------------------------
* FileCreateDirRequest
*/
typedef struct _rfbFileCreateDirRequestMsg {
uint8_t type;
uint8_t unused;
uint16_t dNameLen;
/* Followed by dName[dNameLen] */
} rfbFileCreateDirRequestMsg;
#define sz_rfbFileCreateDirRequestMsg 4
/*-----------------------------------------------------------------------------
* Union of all client->server messages.
*/
typedef union _rfbClientToServerTightMsg {
rfbFileListRequestMsg flr;
rfbFileDownloadRequestMsg fdr;
rfbFileUploadRequestMsg fupr;
rfbFileUploadDataMsg fud;
rfbFileDownloadCancelMsg fdc;
rfbFileUploadFailedMsg fuf;
rfbFileCreateDirRequestMsg fcdr;
} rfbClientToServerTightMsg;
/*-----------------------------------------------------------------------------
* FileListData
*/
typedef struct _rfbFileListDataMsg {
uint8_t type;
uint8_t flags;
uint16_t numFiles;
uint16_t dataSize;
uint16_t compressedSize;
/* Followed by SizeData[numFiles] */
/* Followed by Filenames[compressedSize] */
} rfbFileListDataMsg;
#define sz_rfbFileListDataMsg 8
/*-----------------------------------------------------------------------------
* FileDownloadData
*/
typedef struct _rfbFileDownloadDataMsg {
uint8_t type;
uint8_t compressLevel;
uint16_t realSize;
uint16_t compressedSize;
/* Followed by File[copressedSize],
but if (realSize = compressedSize = 0) followed by uint32_t modTime */
} rfbFileDownloadDataMsg;
#define sz_rfbFileDownloadDataMsg 6
/*-----------------------------------------------------------------------------
* FileUploadCancel
*/
typedef struct _rfbFileUploadCancelMsg {
uint8_t type;
uint8_t unused;
uint16_t reasonLen;
/* Followed by reason[reasonLen] */
} rfbFileUploadCancelMsg;
#define sz_rfbFileUploadCancelMsg 4
/*-----------------------------------------------------------------------------
* FileDownloadFailed
*/
typedef struct _rfbFileDownloadFailedMsg {
uint8_t type;
uint8_t unused;
uint16_t reasonLen;
/* Followed by reason[reasonLen] */
} rfbFileDownloadFailedMsg;
#define sz_rfbFileDownloadFailedMsg 4
#endif

@ -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);
}

@ -159,16 +159,20 @@ typedef struct _rfbSecurity {
*/
typedef struct _rfbProtocolExtension {
/* returns TRUE if extension should be activated */
rfbBool (*init)(struct _rfbClientRec* client, void** data);
/* returns FALSE if extension should be deactivated for client.
if newClient == NULL, it is always deactivated. */
rfbBool (*newClient)(struct _rfbClientRec* client, void** data);
/* returns FALSE if extension should be deactivated for client.
if init == NULL, it stays activated. */
rfbBool (*init)(struct _rfbClientRec* client, void* data);
/* returns TRUE if message was handled */
rfbBool (*handleMessage)(struct _rfbClientRec* client,
void* data,
rfbClientToServerMsg message);
const rfbClientToServerMsg* message);
void (*close)(struct _rfbClientRec* client, void* data);
void (*usage)(void);
/* processArguments returns the number of handled arguments */
int (*processArgument)(char *argv[]);
int (*processArgument)(int argc, char *argv[]);
struct _rfbProtocolExtension* next;
} rfbProtocolExtension;
@ -623,6 +627,7 @@ extern void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen);
/* auth.c */
extern void rfbAuthNewClient(rfbClientPtr cl);
extern void rfbProcessClientSecurityType(rfbClientPtr cl);
extern void rfbAuthProcessClientMessage(rfbClientPtr cl);
extern void rfbRegisterSecurityHandler(rfbSecurityHandler* handler);
@ -788,7 +793,9 @@ enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl);
void rfbRegisterProtocolExtension(rfbProtocolExtension* extension);
struct _rfbProtocolExtension* rfbGetExtensionIterator();
void rfbReleaseExtensionIterator();
rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension);
rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
void* data);
rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension);
/* to check against plain passwords */
rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len);
@ -821,6 +828,9 @@ extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, rfbBool runI
extern rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec);
extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo);
/* TightVNC file transfer extension */
void rfbRegisterTightVNCFileTransferExtension();
#endif
#if(defined __cplusplus)

Loading…
Cancel
Save