Commit message: tightvnc-filetransfer: fix heap use-after-free

One can only guess what the intended semantics were here, but as every
other rfbCloseClient() call in this file is followed by an immediate
return, let's assume this was forgotton in this case.

Anyway, don't forget to clean up to not leak memory.

Closes #241
CVE: CVE-2018-6307
CWE: CWE-416
Vulnerability description: LibVNC before commit ca2a5ac02fbbadd0a21fabba779c1ea69173d10b contains heap use-after-free vulnerability in server code of file transfer extension that can result remote code execution.

Project: libvncserver

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

Project: libvncserver

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

}

Project: libvncserver

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

Project: libvncserver

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

Project: libvncserver

GetFtpRoot()
{
	return ftproot;
}

Project: libvncserver

SetFtpRoot(char* path)
{
	struct stat stat_buf;
	DIR* dir = NULL;

	rfbLog("tightvnc-filetransfer/SetFtpRoot\n");
	
	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;
}

Project: libvncserver

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

Project: libvncserver

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

}

Project: libvncserver

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 occurred"
			"file path requested is <%s>\n", __FILE__, __FUNCTION__, path);

    if(path != NULL) {
		free(path);
		path = NULL;
	}

    SendFileUploadLengthErrMsg(cl);
}

Project: libvncserver

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

}

Project: libvncserver

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

Project: libvncserver

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

Project: libvncserver

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

Project: libvncserver

IsFileTransferEnabled()
{
	return fileTransferEnabled;
}

Project: libvncserver

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

Project: libvncserver

EnableFileTransfer(rfbBool enable)
{
	fileTransferEnabled = enable;
}

Project: libvncserver

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

Project: libvncserver

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

Project: libvncserver

InitFileTransfer()
{
	char* userHome = NULL;
	uid_t uid = geteuid();

	if(fileTransferInitted)
		return;

	rfbLog("tightvnc-filetransfer/InitFileTransfer\n");
	
	memset(ftproot, 0, sizeof(ftproot));
	
	userHome = GetHomeDir(uid);

	if((userHome != NULL) && (strlen(userHome) != 0)) {
		SetFtpRoot(userHome);
		FreeHomeDir(userHome);
	}
	
	fileTransferEnabled = TRUE;
	fileTransferInitted = TRUE;
}

Project: libvncserver

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

Project: libvncserver

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);
	    free(reason);
	    return;
	}

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

}

Project: libvncserver

FreeHomeDir(char *homedir)
{
    free (homedir);
}

Project: libvncserver

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