1 /*
2  * Copyright (c) 2005 Novell, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact Novell, Inc.
16  *
17  * To contact Novell about this file by physical or electronic mail,
18  * you may find current contact information at www.novell.com
19  *
20  * Author		: Rohit Kumar
21  * Email ID	: rokumar@novell.com
22  * Date		: 14th July 2005
23  */
24 
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 
31 #ifdef WIN32
32 #include <io.h>
33 #include <direct.h>
34 #include <sys/utime.h>
35 #define mkdir(path, perms) _mkdir(path) /* Match POSIX signature */
36 #ifdef _MSC_VER
37 #define S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
38 #define S_ISDIR(m)	(((m) & S_IFDIR) == S_IFDIR)
39 #define S_IWUSR		S_IWRITE
40 #define S_IRUSR		S_IREAD
41 #define S_IWOTH		0x0000002
42 #define S_IROTH		0x0000004
43 #define S_IWGRP		0x0000010
44 #define S_IRGRP		0x0000020
45 /* Prevent POSIX deprecation warnings on MSVC */
46 #define creat _creat
47 #define open _open
48 #define read _read
49 #define write _write
50 #define close _close
51 #define unlink _unlink
52 #endif /* _MSC_VER */
53 #else
54 #include <dirent.h>
55 #include <utime.h>
56 #endif
57 
58 #include <errno.h>
59 #if LIBVNCSERVER_HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #include <sys/stat.h>
63 #include <sys/types.h>
64 
65 #include <rfb/rfb.h>
66 #include "rfbtightproto.h"
67 #include "filelistinfo.h"
68 #include "filetransfermsg.h"
69 #include "handlefiletransferrequest.h"
70 
71 #define SZ_RFBBLOCKSIZE 8192
72 
73 
74 void
FreeFileTransferMsg(FileTransferMsg ftm)75 FreeFileTransferMsg(FileTransferMsg ftm)
76 {
77 
78 	if(ftm.data != NULL) {
79 		free(ftm.data);
80 		ftm.data = NULL;
81 	}
82 
83 	ftm.length = 0;
84 
85 }
86 
87 
88 /******************************************************************************
89  * Methods to handle file list request.
90  ******************************************************************************/
91 
92 int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
93 FileTransferMsg CreateFileListErrMsg(char flags);
94 FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
95 
96 
97 /*
98  * This is the method called by HandleFileListRequest to get the file list
99  */
100 
101 FileTransferMsg
GetFileListResponseMsg(char * path,char flags)102 GetFileListResponseMsg(char* path, char flags)
103 {
104 	FileTransferMsg fileListMsg;
105 	FileListInfo fileListInfo;
106 	int status = -1;
107 
108 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
109 	memset(&fileListInfo, 0, sizeof(FileListInfo));
110 
111 
112 	 /* fileListInfo can have null data if the folder is Empty
113 	or if some error condition has occurred.
114 	The return value is 'failure' only if some error condition has occurred.
115 	 */
116 	status = CreateFileListInfo(&fileListInfo, path, !(flags  & 0x10));
117 
118 	if(status == FAILURE) {
119 		fileListMsg = CreateFileListErrMsg(flags);
120 	}
121 	else {
122 		/* DisplayFileList(fileListInfo); For Debugging  */
123 
124 		fileListMsg = CreateFileListMsg(fileListInfo, flags);
125 		FreeFileListInfo(fileListInfo);
126 	}
127 
128 	return fileListMsg;
129 }
130 
131 #if !defined(__GNUC__) && !defined(_MSC_VER)
132 #define __FUNCTION__ "unknown"
133 #endif
134 
135 #ifdef WIN32
136 
137 /* Most of the Windows version here is based on https://github.com/danielgindi/FileDir */
138 
139 #define FILETIME_TO_TIME_T(FILETIME) (((((__int64)FILETIME.dwLowDateTime) | (((__int64)FILETIME.dwHighDateTime) << 32)) - 116444736000000000L) / 10000000L)
140 
141 #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
142 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM))
143 #else
144 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) 0
145 #endif
146 
147 #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
148 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA))
149 #else
150 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) 0
151 #endif
152 
153 #define IS_REGULAR_FILE(dwFileAttributes) \
154 	( \
155 	!!(dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || \
156 	( \
157 	!(dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && \
158 	!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && \
159 	!(dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && \
160 	!IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) && \
161 	!IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) && \
162 	!(dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && \
163 	!(dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) \
164 	) \
165 	)
166 
167 #define IS_FOLDER(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
168 
169 int
CreateFileListInfo(FileListInfoPtr pFileListInfo,char * path,int flag)170 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
171 {
172 	int pathLen, basePathLength;
173 	char *basePath, *pChar;
174 	WIN32_FIND_DATAA winFindData;
175 	HANDLE findHandle;
176 
177 	if(path == NULL) {
178 		return FAILURE;
179 	}
180 
181 	if(strlen(path) == 0) {
182 		/* In this case we will send the list of entries in ftp root*/
183 		sprintf(path, "%s%s", GetFtpRoot(), "/");
184 	}
185 
186 	/* Create a search string, like C:\folder\* */
187 
188 	pathLen = strlen(path);
189 	basePath = malloc(pathLen + 3);
190 	memcpy(basePath, path, pathLen);
191 	basePathLength = pathLen;
192 	basePath[basePathLength] = '\\';
193 	basePath[basePathLength + 1] = '*';
194 	basePath[basePathLength + 2] = '\0';
195 
196 	/* Start a search */
197 	memset(&winFindData, 0, sizeof(winFindData));
198 	findHandle = FindFirstFileA(path, &winFindData);
199 
200 	basePath[basePathLength] = '\0'; /* Restore to a basePath + \ */
201 	/* Convert \ to / */
202 	for(pChar = basePath; *pChar; pChar++) {
203 		if (*pChar == '\\') {
204 			*pChar = '/';
205 		}
206 	}
207 
208 	/* While we can find a next file do...
209 	   But ignore \. and '.. entries, which are current folder and parent folder respectively */
210 	while(findHandle != INVALID_HANDLE_VALUE && winFindData.cFileName[0] == '.' &&
211 		(winFindData.cFileName[1] == '\0' ||
212 		(winFindData.cFileName[1] == '.' && winFindData.cFileName[2] == '\0'))) {
213 		char fullpath[PATH_MAX];
214 		fullpath[0] = 0;
215 
216 		strncpy_s(fullpath, PATH_MAX, basePath, basePathLength);
217 		strncpy_s(fullpath + basePathLength, PATH_MAX - basePathLength, winFindData.cFileName, (int)strlen(winFindData.cFileName));
218 
219 		if(IS_FOLDER(winFindData.dwFileAttributes)) {
220 			if (AddFileListItemInfo(pFileListInfo, winFindData.cFileName, -1, 0) == 0) {
221 				rfbLog("File [%s]: Method [%s]: Add directory %s in the"
222 					" list failed\n", __FILE__, __FUNCTION__, fullpath);
223 				continue;
224 			}
225 		}
226 		else if(IS_REGULAR_FILE(winFindData.dwFileAttributes)) {
227 			if(flag) {
228 				unsigned int fileSize = (winFindData.nFileSizeHigh * (MAXDWORD+1)) + winFindData.nFileSizeLow;
229 				if(AddFileListItemInfo(pFileListInfo, winFindData.cFileName, fileSize, FILETIME_TO_TIME_T(winFindData.ftLastWriteTime)) == 0) {
230 					rfbLog("File [%s]: Method [%s]: Add file %s in the "
231 						"list failed\n", __FILE__, __FUNCTION__, fullpath);
232 					continue;
233 				}
234 			}
235 		}
236 
237 		if(FindNextFileA(findHandle, &winFindData) == 0) {
238 			FindClose(findHandle);
239 			findHandle = INVALID_HANDLE_VALUE;
240 		}
241 	}
242 
243 	if(findHandle != INVALID_HANDLE_VALUE) {
244 		FindClose(findHandle);
245 	}
246 
247 	free(basePath);
248 
249 	return SUCCESS;
250 }
251 
252 #else /* WIN32 */
253 
254 int
CreateFileListInfo(FileListInfoPtr pFileListInfo,char * path,int flag)255 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
256 {
257 	DIR* pDir = NULL;
258 	struct dirent* pDirent = NULL;
259 
260 	if(path == NULL) {
261 		return FAILURE;
262 	}
263 
264 	if(strlen(path) == 0) {
265 		/* In this case we will send the list of entries in ftp root*/
266 		sprintf(path, "%s%s", GetFtpRoot(), "/");
267 	}
268 
269 	if((pDir = opendir(path)) == NULL) {
270 		rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
271 				__FILE__, __FUNCTION__);
272 		return FAILURE;
273 	}
274 
275 	while((pDirent = readdir(pDir))) {
276 		if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
277 			struct stat stat_buf;
278 			/*
279 			int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
280 			*/
281 			char fullpath[PATH_MAX];
282 
283 			memset(fullpath, 0, PATH_MAX);
284 
285 			strcpy(fullpath, path);
286 			if(path[strlen(path)-1] != '/')
287 				strcat(fullpath, "/");
288 			strcat(fullpath, pDirent->d_name);
289 
290 			if(stat(fullpath, &stat_buf) < 0) {
291 				rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
292 						__FILE__, __FUNCTION__, fullpath);
293 				continue;
294 			}
295 
296 			if(S_ISDIR(stat_buf.st_mode)) {
297 				if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
298 					rfbLog("File [%s]: Method [%s]: Add directory %s in the"
299 							" list failed\n", __FILE__, __FUNCTION__, fullpath);
300 					continue;
301 				}
302 			}
303 			else {
304 				if(flag) {
305 					if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
306 												stat_buf.st_size,
307 												stat_buf.st_mtime) == 0) {
308 						rfbLog("File [%s]: Method [%s]: Add file %s in the "
309 								"list failed\n", __FILE__, __FUNCTION__, fullpath);
310 						continue;
311 					}
312 				}
313 			}
314 		}
315 	}
316 	if(closedir(pDir) < 0) {
317 	    rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
318 	    	__FILE__, __FUNCTION__);
319 	}
320 
321 	return SUCCESS;
322 }
323 
324 #endif
325 
326 
327 FileTransferMsg
CreateFileListErrMsg(char flags)328 CreateFileListErrMsg(char flags)
329 {
330 	FileTransferMsg fileListMsg;
331 	rfbFileListDataMsg* pFLD = NULL;
332 	char* data = NULL;
333 	unsigned int length = 0;
334 
335 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
336 
337 	data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
338 	if(data == NULL) {
339 		return fileListMsg;
340 	}
341 	length = sizeof(rfbFileListDataMsg) * sizeof(char);
342 	pFLD = (rfbFileListDataMsg*) data;
343 
344 	pFLD->type = rfbFileListData;
345 	pFLD->numFiles = Swap16IfLE(0);
346 	pFLD->dataSize = Swap16IfLE(0);
347 	pFLD->compressedSize = Swap16IfLE(0);
348 	pFLD->flags = flags | 0x80;
349 
350 	fileListMsg.data = data;
351 	fileListMsg.length = length;
352 
353 	return fileListMsg;
354 }
355 
356 
357 FileTransferMsg
CreateFileListMsg(FileListInfo fileListInfo,char flags)358 CreateFileListMsg(FileListInfo fileListInfo, char flags)
359 {
360 	FileTransferMsg fileListMsg;
361 	rfbFileListDataMsg* pFLD = NULL;
362 	char *data = NULL, *pFileNames = NULL;
363 	unsigned int length = 0, dsSize = 0, i = 0;
364 	FileListItemSizePtr pFileListItemSize = NULL;
365 
366 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
367 	dsSize = fileListInfo.numEntries * 8;
368 	length = sz_rfbFileListDataMsg + dsSize +
369 			GetSumOfFileNamesLength(fileListInfo) +
370 			fileListInfo.numEntries;
371 
372 	data = (char*) calloc(length, sizeof(char));
373 	if(data == NULL) {
374 		return fileListMsg;
375 	}
376 	pFLD = (rfbFileListDataMsg*) data;
377 	pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
378 	pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
379 
380 	pFLD->type            = rfbFileListData;
381     pFLD->flags 		  = flags & 0xF0;
382     pFLD->numFiles 		  = Swap16IfLE(fileListInfo.numEntries);
383     pFLD->dataSize 		  = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
384     									fileListInfo.numEntries);
385     pFLD->compressedSize  = pFLD->dataSize;
386 
387 	for(i =0; i <fileListInfo.numEntries; i++) {
388 		pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
389 		pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
390 		strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
391 
392 		if(i+1 < fileListInfo.numEntries)
393 			pFileNames += strlen(pFileNames) + 1;
394 	}
395 
396 	fileListMsg.data 	= data;
397 	fileListMsg.length 	= length;
398 
399 	return fileListMsg;
400 }
401 
402 
403 /******************************************************************************
404  * Methods to handle File Download Request.
405  ******************************************************************************/
406 
407 FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
408 FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
409 FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
410 
411 FileTransferMsg
GetFileDownLoadErrMsg()412 GetFileDownLoadErrMsg()
413 {
414 	FileTransferMsg fileDownloadErrMsg;
415 
416 	char reason[] = "An internal error on the server caused download failure";
417 	int reasonLen = strlen(reason);
418 
419 	memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
420 
421 	fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
422 
423 	return fileDownloadErrMsg;
424 }
425 
426 
427 FileTransferMsg
GetFileDownloadReadDataErrMsg()428 GetFileDownloadReadDataErrMsg()
429 {
430 	char reason[] = "Cannot open file, perhaps it is absent or is a directory";
431 	int reasonLen = strlen(reason);
432 
433 	return CreateFileDownloadErrMsg(reason, reasonLen);
434 
435 }
436 
437 
438 FileTransferMsg
GetFileDownloadLengthErrResponseMsg()439 GetFileDownloadLengthErrResponseMsg()
440 {
441 	char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
442 	int reasonLen = strlen(reason);
443 
444 	return CreateFileDownloadErrMsg(reason, reasonLen);
445 }
446 
447 
448 FileTransferMsg
GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl,rfbTightClientPtr rtcp)449 GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
450 {
451 	/* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */
452     int numOfBytesRead = 0;
453 	char pBuf[SZ_RFBBLOCKSIZE];
454 	char* path = rtcp->rcft.rcfd.fName;
455 
456 	memset(pBuf, 0, SZ_RFBBLOCKSIZE);
457 
458 	if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
459 		if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
460 			rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
461 					__FILE__, __FUNCTION__);
462 			return GetFileDownloadReadDataErrMsg();
463 		}
464 		rtcp->rcft.rcfd.downloadInProgress = TRUE;
465 	}
466 	if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
467 		if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
468 			close(rtcp->rcft.rcfd.downloadFD);
469 			rtcp->rcft.rcfd.downloadFD = -1;
470 			rtcp->rcft.rcfd.downloadInProgress = FALSE;
471 			if(numOfBytesRead == 0) {
472 				return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
473 			}
474 			return GetFileDownloadReadDataErrMsg();
475 		}
476 	return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
477 	}
478 	return GetFileDownLoadErrMsg();
479 }
480 
481 
482 FileTransferMsg
ChkFileDownloadErr(rfbClientPtr cl,rfbTightClientPtr rtcp)483 ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
484 {
485     FileTransferMsg fileDownloadMsg;
486 	struct stat stat_buf;
487 	int sz_rfbFileSize = 0;
488 	char* path = rtcp->rcft.rcfd.fName;
489 
490 	memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
491 
492 	if( (path == NULL) || (strlen(path) == 0) ||
493 		(stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
494 
495 			char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
496 			int reasonLen = strlen(reason);
497 
498 			rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
499 					__FILE__, __FUNCTION__, path);
500 
501 			fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
502 	}
503 	else {
504 		rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
505 		sz_rfbFileSize = stat_buf.st_size;
506 		if(sz_rfbFileSize <= 0) {
507 			fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
508 		}
509 
510 	}
511 	return fileDownloadMsg;
512 }
513 
514 
515 FileTransferMsg
CreateFileDownloadErrMsg(char * reason,unsigned int reasonLen)516 CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
517 {
518 	FileTransferMsg fileDownloadErrMsg;
519 	int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
520 	rfbFileDownloadFailedMsg *pFDF = NULL;
521 	char *pFollow = NULL;
522 
523 	char *pData = (char*) calloc(length, sizeof(char));
524 	memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
525 	if(pData == NULL) {
526 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
527 				__FILE__, __FUNCTION__);
528 		return fileDownloadErrMsg;
529 	}
530 
531 	pFDF = (rfbFileDownloadFailedMsg *) pData;
532 	pFollow = &pData[sz_rfbFileDownloadFailedMsg];
533 
534 	pFDF->type = rfbFileDownloadFailed;
535 	pFDF->reasonLen = Swap16IfLE(reasonLen);
536 	memcpy(pFollow, reason, reasonLen);
537 
538 	fileDownloadErrMsg.data	= pData;
539 	fileDownloadErrMsg.length	= length;
540 
541 	return fileDownloadErrMsg;
542 }
543 
544 
545 FileTransferMsg
CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)546 CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
547 {
548 	FileTransferMsg fileDownloadZeroSizeDataMsg;
549 	int length = sz_rfbFileDownloadDataMsg + sizeof(unsigned long);
550 	rfbFileDownloadDataMsg *pFDD = NULL;
551 	char *pFollow = NULL;
552 
553 	char *pData = (char*) calloc(length, sizeof(char));
554 	memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
555 	if(pData == NULL) {
556 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
557 				__FILE__, __FUNCTION__);
558 		return fileDownloadZeroSizeDataMsg;
559 	}
560 
561 	pFDD = (rfbFileDownloadDataMsg *) pData;
562 	pFollow = &pData[sz_rfbFileDownloadDataMsg];
563 
564 	pFDD->type = rfbFileDownloadData;
565 	pFDD->compressLevel = 0;
566 	pFDD->compressedSize = Swap16IfLE(0);
567 	pFDD->realSize = Swap16IfLE(0);
568 
569 	memcpy(pFollow, &mTime, sizeof(unsigned long));
570 
571 	fileDownloadZeroSizeDataMsg.data	= pData;
572 	fileDownloadZeroSizeDataMsg.length	= length;
573 
574 	return fileDownloadZeroSizeDataMsg;
575 
576 }
577 
578 
579 FileTransferMsg
CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile,char * pFile)580 CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
581 {
582 	FileTransferMsg fileDownloadBlockSizeDataMsg;
583 	int length = sz_rfbFileDownloadDataMsg + sizeFile;
584 	rfbFileDownloadDataMsg *pFDD = NULL;
585 	char *pFollow = NULL;
586 
587 	char *pData = (char*) calloc(length, sizeof(char));
588 	memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
589 	if(NULL == pData) {
590 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
591 				__FILE__, __FUNCTION__);
592 		return fileDownloadBlockSizeDataMsg;
593 	}
594 
595 	pFDD = (rfbFileDownloadDataMsg *) pData;
596 	pFollow = &pData[sz_rfbFileDownloadDataMsg];
597 
598 	pFDD->type = rfbFileDownloadData;
599 	pFDD->compressLevel = 0;
600 	pFDD->compressedSize = Swap16IfLE(sizeFile);
601 	pFDD->realSize = Swap16IfLE(sizeFile);
602 
603 	memcpy(pFollow, pFile, sizeFile);
604 
605 	fileDownloadBlockSizeDataMsg.data	= pData;
606 	fileDownloadBlockSizeDataMsg.length	= length;
607 
608 	return fileDownloadBlockSizeDataMsg;
609 
610 }
611 
612 
613 /******************************************************************************
614  * Methods to handle file upload request
615  ******************************************************************************/
616 
617 FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
618 
619 FileTransferMsg
GetFileUploadLengthErrResponseMsg()620 GetFileUploadLengthErrResponseMsg()
621 {
622 	char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
623 	int reasonLen = strlen(reason);
624 
625 	return CreateFileUploadErrMsg(reason, reasonLen);
626 }
627 
628 
629 FileTransferMsg
ChkFileUploadErr(rfbClientPtr cl,rfbTightClientPtr rtcp)630 ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
631 {
632     FileTransferMsg fileUploadErrMsg;
633 
634 	memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
635 	if((strlen(rtcp->rcft.rcfu.fName) == 0) ||
636 		((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
637 		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
638 
639 			char reason[] = "Could not create file";
640 			int reasonLen = strlen(reason);
641 			fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
642 	}
643 	else
644 		rtcp->rcft.rcfu.uploadInProgress = TRUE;
645 
646 	return fileUploadErrMsg;
647 }
648 
649 
650 FileTransferMsg
GetFileUploadCompressedLevelErrMsg()651 GetFileUploadCompressedLevelErrMsg()
652 {
653 	char reason[] = "Server does not support data compression on upload";
654 	int reasonLen = strlen(reason);
655 
656 	return CreateFileUploadErrMsg(reason, reasonLen);
657 }
658 
659 
660 FileTransferMsg
ChkFileUploadWriteErr(rfbClientPtr cl,rfbTightClientPtr rtcp,char * pBuf)661 ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
662 {
663 	FileTransferMsg ftm;
664 	unsigned long numOfBytesWritten = 0;
665 
666 	memset(&ftm, 0, sizeof(FileTransferMsg));
667 
668 	numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
669 
670 	if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
671 		char reason[] = "Error writing file data";
672 		int reasonLen = strlen(reason);
673 		ftm = CreateFileUploadErrMsg(reason, reasonLen);
674 		CloseUndoneFileUpload(cl, rtcp);
675 	}
676 	return ftm;
677 }
678 
679 
680 void
FileUpdateComplete(rfbClientPtr cl,rfbTightClientPtr rtcp)681 FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
682 {
683 	/* Here we are settimg the modification and access time of the file */
684 	/* Windows code stes mod/access/creation time of the file */
685 	struct utimbuf utb;
686 
687 	utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
688 	if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
689 		rfbLog("File [%s]: Method [%s]: Setting the modification/access"
690 				" time for the file <%s> failed\n", __FILE__,
691 				__FUNCTION__, rtcp->rcft.rcfu.fName);
692 	}
693 
694 	if(rtcp->rcft.rcfu.uploadFD != -1) {
695 		close(rtcp->rcft.rcfu.uploadFD);
696 		rtcp->rcft.rcfu.uploadFD = -1;
697 		rtcp->rcft.rcfu.uploadInProgress = FALSE;
698 	}
699 }
700 
701 
702 FileTransferMsg
CreateFileUploadErrMsg(char * reason,unsigned int reasonLen)703 CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
704 {
705 	FileTransferMsg fileUploadErrMsg;
706 	int length = sz_rfbFileUploadCancelMsg + reasonLen;
707 	rfbFileUploadCancelMsg *pFDF = NULL;
708 	char *pFollow = NULL;
709 
710 	char *pData = (char*) calloc(length, sizeof(char));
711 	memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
712 	if(pData == NULL) {
713 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
714 				__FILE__, __FUNCTION__);
715 		return fileUploadErrMsg;
716 	}
717 
718 	pFDF = (rfbFileUploadCancelMsg *) pData;
719 	pFollow = &pData[sz_rfbFileUploadCancelMsg];
720 
721 	pFDF->type = rfbFileUploadCancel;
722 	pFDF->reasonLen = Swap16IfLE(reasonLen);
723 	memcpy(pFollow, reason, reasonLen);
724 
725 	fileUploadErrMsg.data		= pData;
726 	fileUploadErrMsg.length		= length;
727 
728 	return fileUploadErrMsg;
729 }
730 
731 
732 /******************************************************************************
733  * Method to cancel File Transfer operation.
734  ******************************************************************************/
735 
736 void
CloseUndoneFileUpload(rfbClientPtr cl,rfbTightClientPtr rtcp)737 CloseUndoneFileUpload(rfbClientPtr cl, rfbTightClientPtr rtcp)
738 {
739 	/* TODO :: File Upload case is not handled currently */
740 	/* TODO :: In case of concurrency we need to use Critical Section */
741 
742 	if(cl == NULL)
743 		return;
744 
745 
746 	if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
747 		rtcp->rcft.rcfu.uploadInProgress = FALSE;
748 
749 		if(rtcp->rcft.rcfu.uploadFD != -1) {
750 			close(rtcp->rcft.rcfu.uploadFD);
751 			rtcp->rcft.rcfu.uploadFD = -1;
752 		}
753 
754 		if(unlink(rtcp->rcft.rcfu.fName) == -1) {
755 			rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
756 					__FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
757 		}
758 
759 		memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
760 	}
761 }
762 
763 
764 void
CloseUndoneFileDownload(rfbClientPtr cl,rfbTightClientPtr rtcp)765 CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp)
766 {
767 	if(cl == NULL)
768 		return;
769 
770 	if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
771 		rtcp->rcft.rcfd.downloadInProgress = FALSE;
772 		/* the thread will return if downloadInProgress is FALSE */
773 		pthread_join(rtcp->rcft.rcfd.downloadThread, NULL);
774 
775 		if(rtcp->rcft.rcfd.downloadFD != -1) {
776 			close(rtcp->rcft.rcfd.downloadFD);
777 			rtcp->rcft.rcfd.downloadFD = -1;
778 		}
779 		memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
780 	}
781 }
782 
783 
784 /******************************************************************************
785  * Method to handle create directory request.
786  ******************************************************************************/
787 
788 #ifdef _MSC_VER
789 #undef CreateDirectory /* Prevent macro clashes under Windows */
790 #endif /* _MSC_VER */
791 
792 void
CreateDirectory(char * dirName)793 CreateDirectory(char* dirName)
794 {
795 	if(dirName == NULL) return;
796 
797 	if(mkdir(dirName, 0700) == -1) {
798 		rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
799 				__FILE__, __FUNCTION__, dirName);
800 	}
801 }
802