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