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 (at) 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 #include <dirent.h> 31 #include <utime.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 37 #include <rfb/rfb.h> 38 #include "rfbtightproto.h" 39 #include "filelistinfo.h" 40 #include "filetransfermsg.h" 41 #include "handlefiletransferrequest.h" 42 43 #define SZ_RFBBLOCKSIZE 8192 44 45 46 void 47 FreeFileTransferMsg(FileTransferMsg ftm) 48 { 49 50 if(ftm.data != NULL) { 51 free(ftm.data); 52 ftm.data = NULL; 53 } 54 55 ftm.length = 0; 56 57 } 58 59 60 /****************************************************************************** 61 * Methods to handle file list request. 62 ******************************************************************************/ 63 64 int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag); 65 FileTransferMsg CreateFileListErrMsg(char flags); 66 FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags); 67 68 69 /* 70 * This is the method called by HandleFileListRequest to get the file list 71 */ 72 73 FileTransferMsg 74 GetFileListResponseMsg(char* path, char flags) 75 { 76 FileTransferMsg fileListMsg; 77 FileListInfo fileListInfo; 78 int status = -1; 79 80 memset(&fileListMsg, 0, sizeof(FileTransferMsg)); 81 memset(&fileListInfo, 0, sizeof(FileListInfo)); 82 83 84 /* fileListInfo can have null data if the folder is Empty 85 or if some error condition has occured. 86 The return value is 'failure' only if some error condition has occured. 87 */ 88 status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10)); 89 90 if(status == FAILURE) { 91 fileListMsg = CreateFileListErrMsg(flags); 92 } 93 else { 94 /* DisplayFileList(fileListInfo); For Debugging */ 95 96 fileListMsg = CreateFileListMsg(fileListInfo, flags); 97 FreeFileListInfo(fileListInfo); 98 } 99 100 return fileListMsg; 101 } 102 103 #ifndef __GNUC__ 104 #define __FUNCTION__ "unknown" 105 #endif 106 107 int 108 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag) 109 { 110 DIR* pDir = NULL; 111 struct dirent* pDirent = NULL; 112 113 if((path == NULL) || (strlen(path) == 0)) { 114 /* In this case we will send the list of entries in ftp root*/ 115 sprintf(path, "%s%s", GetFtpRoot(), "/"); 116 } 117 118 if((pDir = opendir(path)) == NULL) { 119 rfbLog("File [%s]: Method [%s]: not able to open the dir\n", 120 __FILE__, __FUNCTION__); 121 return FAILURE; 122 } 123 124 while((pDirent = readdir(pDir))) { 125 if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) { 126 struct stat stat_buf; 127 /* 128 int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2); 129 */ 130 char fullpath[PATH_MAX]; 131 132 memset(fullpath, 0, PATH_MAX); 133 134 strcpy(fullpath, path); 135 if(path[strlen(path)-1] != '/') 136 strcat(fullpath, "/"); 137 strcat(fullpath, pDirent->d_name); 138 139 if(stat(fullpath, &stat_buf) < 0) { 140 rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n", 141 __FILE__, __FUNCTION__, fullpath); 142 continue; 143 } 144 145 if(S_ISDIR(stat_buf.st_mode)) { 146 if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) { 147 rfbLog("File [%s]: Method [%s]: Add directory %s in the" 148 " list failed\n", __FILE__, __FUNCTION__, fullpath); 149 continue; 150 } 151 } 152 else { 153 if(flag) { 154 if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, 155 stat_buf.st_size, 156 stat_buf.st_mtime) == 0) { 157 rfbLog("File [%s]: Method [%s]: Add file %s in the " 158 "list failed\n", __FILE__, __FUNCTION__, fullpath); 159 continue; 160 } 161 } 162 } 163 } 164 } 165 if(closedir(pDir) < 0) { 166 rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n", 167 __FILE__, __FUNCTION__); 168 } 169 170 return SUCCESS; 171 } 172 173 174 FileTransferMsg 175 CreateFileListErrMsg(char flags) 176 { 177 FileTransferMsg fileListMsg; 178 rfbFileListDataMsg* pFLD = NULL; 179 char* data = NULL; 180 unsigned int length = 0; 181 182 memset(&fileListMsg, 0, sizeof(FileTransferMsg)); 183 184 data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char)); 185 if(data == NULL) { 186 return fileListMsg; 187 } 188 length = sizeof(rfbFileListDataMsg) * sizeof(char); 189 pFLD = (rfbFileListDataMsg*) data; 190 191 pFLD->type = rfbFileListData; 192 pFLD->numFiles = Swap16IfLE(0); 193 pFLD->dataSize = Swap16IfLE(0); 194 pFLD->compressedSize = Swap16IfLE(0); 195 pFLD->flags = flags | 0x80; 196 197 fileListMsg.data = data; 198 fileListMsg.length = length; 199 200 return fileListMsg; 201 } 202 203 204 FileTransferMsg 205 CreateFileListMsg(FileListInfo fileListInfo, char flags) 206 { 207 FileTransferMsg fileListMsg; 208 rfbFileListDataMsg* pFLD = NULL; 209 char *data = NULL, *pFileNames = NULL; 210 unsigned int length = 0, dsSize = 0, i = 0; 211 FileListItemSizePtr pFileListItemSize = NULL; 212 213 memset(&fileListMsg, 0, sizeof(FileTransferMsg)); 214 dsSize = fileListInfo.numEntries * 8; 215 length = sz_rfbFileListDataMsg + dsSize + 216 GetSumOfFileNamesLength(fileListInfo) + 217 fileListInfo.numEntries; 218 219 data = (char*) calloc(length, sizeof(char)); 220 if(data == NULL) { 221 return fileListMsg; 222 } 223 pFLD = (rfbFileListDataMsg*) data; 224 pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg]; 225 pFileNames = &data[sz_rfbFileListDataMsg + dsSize]; 226 227 pFLD->type = rfbFileListData; 228 pFLD->flags = flags & 0xF0; 229 pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries); 230 pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) + 231 fileListInfo.numEntries); 232 pFLD->compressedSize = pFLD->dataSize; 233 234 for(i =0; i <fileListInfo.numEntries; i++) { 235 pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i)); 236 pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i)); 237 strcpy(pFileNames, GetFileNameAt(fileListInfo, i)); 238 239 if(i+1 < fileListInfo.numEntries) 240 pFileNames += strlen(pFileNames) + 1; 241 } 242 243 fileListMsg.data = data; 244 fileListMsg.length = length; 245 246 return fileListMsg; 247 } 248 249 250 /****************************************************************************** 251 * Methods to handle File Download Request. 252 ******************************************************************************/ 253 254 FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen); 255 FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime); 256 FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile); 257 258 FileTransferMsg 259 GetFileDownLoadErrMsg() 260 { 261 FileTransferMsg fileDownloadErrMsg; 262 263 char reason[] = "An internal error on the server caused download failure"; 264 int reasonLen = strlen(reason); 265 266 memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg)); 267 268 fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen); 269 270 return fileDownloadErrMsg; 271 } 272 273 274 FileTransferMsg 275 GetFileDownloadReadDataErrMsg() 276 { 277 char reason[] = "Cannot open file, perhaps it is absent or is a directory"; 278 int reasonLen = strlen(reason); 279 280 return CreateFileDownloadErrMsg(reason, reasonLen); 281 282 } 283 284 285 FileTransferMsg 286 GetFileDownloadLengthErrResponseMsg() 287 { 288 char reason [] = "Path length exceeds PATH_MAX (4096) bytes"; 289 int reasonLen = strlen(reason); 290 291 return CreateFileDownloadErrMsg(reason, reasonLen); 292 } 293 294 295 FileTransferMsg 296 GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp) 297 { 298 /* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */ 299 int numOfBytesRead = 0; 300 char pBuf[SZ_RFBBLOCKSIZE]; 301 char* path = rtcp->rcft.rcfd.fName; 302 303 memset(pBuf, 0, SZ_RFBBLOCKSIZE); 304 305 if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) { 306 if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) { 307 rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n", 308 __FILE__, __FUNCTION__); 309 return GetFileDownloadReadDataErrMsg(); 310 } 311 rtcp->rcft.rcfd.downloadInProgress = TRUE; 312 } 313 if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) { 314 if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) { 315 close(rtcp->rcft.rcfd.downloadFD); 316 rtcp->rcft.rcfd.downloadFD = -1; 317 rtcp->rcft.rcfd.downloadInProgress = FALSE; 318 if(numOfBytesRead == 0) { 319 return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime); 320 } 321 return GetFileDownloadReadDataErrMsg(); 322 } 323 return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf); 324 } 325 return GetFileDownLoadErrMsg(); 326 } 327 328 329 FileTransferMsg 330 ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp) 331 { 332 FileTransferMsg fileDownloadMsg; 333 struct stat stat_buf; 334 int sz_rfbFileSize = 0; 335 char* path = rtcp->rcft.rcfd.fName; 336 337 memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg)); 338 339 if( (path == NULL) || (strlen(path) == 0) || 340 (stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) { 341 342 char reason[] = "Cannot open file, perhaps it is absent or is not a regular file"; 343 int reasonLen = strlen(reason); 344 345 rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n", 346 __FILE__, __FUNCTION__, path); 347 348 fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen); 349 } 350 else { 351 rtcp->rcft.rcfd.mTime = stat_buf.st_mtime; 352 sz_rfbFileSize = stat_buf.st_size; 353 if(sz_rfbFileSize <= 0) { 354 fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime); 355 } 356 357 } 358 return fileDownloadMsg; 359 } 360 361 362 FileTransferMsg 363 CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen) 364 { 365 FileTransferMsg fileDownloadErrMsg; 366 int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1; 367 rfbFileDownloadFailedMsg *pFDF = NULL; 368 char *pFollow = NULL; 369 370 char *pData = (char*) calloc(length, sizeof(char)); 371 memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg)); 372 if(pData == NULL) { 373 rfbLog("File [%s]: Method [%s]: pData is NULL\n", 374 __FILE__, __FUNCTION__); 375 return fileDownloadErrMsg; 376 } 377 378 pFDF = (rfbFileDownloadFailedMsg *) pData; 379 pFollow = &pData[sz_rfbFileDownloadFailedMsg]; 380 381 pFDF->type = rfbFileDownloadFailed; 382 pFDF->reasonLen = Swap16IfLE(reasonLen); 383 memcpy(pFollow, reason, reasonLen); 384 385 fileDownloadErrMsg.data = pData; 386 fileDownloadErrMsg.length = length; 387 388 return fileDownloadErrMsg; 389 } 390 391 392 FileTransferMsg 393 CreateFileDownloadZeroSizeDataMsg(unsigned long mTime) 394 { 395 FileTransferMsg fileDownloadZeroSizeDataMsg; 396 int length = sz_rfbFileDownloadDataMsg + sizeof(unsigned long); 397 rfbFileDownloadDataMsg *pFDD = NULL; 398 char *pFollow = NULL; 399 400 char *pData = (char*) calloc(length, sizeof(char)); 401 memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg)); 402 if(pData == NULL) { 403 rfbLog("File [%s]: Method [%s]: pData is NULL\n", 404 __FILE__, __FUNCTION__); 405 return fileDownloadZeroSizeDataMsg; 406 } 407 408 pFDD = (rfbFileDownloadDataMsg *) pData; 409 pFollow = &pData[sz_rfbFileDownloadDataMsg]; 410 411 pFDD->type = rfbFileDownloadData; 412 pFDD->compressLevel = 0; 413 pFDD->compressedSize = Swap16IfLE(0); 414 pFDD->realSize = Swap16IfLE(0); 415 416 memcpy(pFollow, &mTime, sizeof(unsigned long)); 417 418 fileDownloadZeroSizeDataMsg.data = pData; 419 fileDownloadZeroSizeDataMsg.length = length; 420 421 return fileDownloadZeroSizeDataMsg; 422 423 } 424 425 426 FileTransferMsg 427 CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile) 428 { 429 FileTransferMsg fileDownloadBlockSizeDataMsg; 430 int length = sz_rfbFileDownloadDataMsg + sizeFile; 431 rfbFileDownloadDataMsg *pFDD = NULL; 432 char *pFollow = NULL; 433 434 char *pData = (char*) calloc(length, sizeof(char)); 435 memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg)); 436 if(NULL == pData) { 437 rfbLog("File [%s]: Method [%s]: pData is NULL\n", 438 __FILE__, __FUNCTION__); 439 return fileDownloadBlockSizeDataMsg; 440 } 441 442 pFDD = (rfbFileDownloadDataMsg *) pData; 443 pFollow = &pData[sz_rfbFileDownloadDataMsg]; 444 445 pFDD->type = rfbFileDownloadData; 446 pFDD->compressLevel = 0; 447 pFDD->compressedSize = Swap16IfLE(sizeFile); 448 pFDD->realSize = Swap16IfLE(sizeFile); 449 450 memcpy(pFollow, pFile, sizeFile); 451 452 fileDownloadBlockSizeDataMsg.data = pData; 453 fileDownloadBlockSizeDataMsg.length = length; 454 455 return fileDownloadBlockSizeDataMsg; 456 457 } 458 459 460 /****************************************************************************** 461 * Methods to handle file upload request 462 ******************************************************************************/ 463 464 FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen); 465 466 FileTransferMsg 467 GetFileUploadLengthErrResponseMsg() 468 { 469 char reason [] = "Path length exceeds PATH_MAX (4096) bytes"; 470 int reasonLen = strlen(reason); 471 472 return CreateFileUploadErrMsg(reason, reasonLen); 473 } 474 475 476 FileTransferMsg 477 ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp) 478 { 479 FileTransferMsg fileUploadErrMsg; 480 481 memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg)); 482 if( (rtcp->rcft.rcfu.fName == NULL) || 483 (strlen(rtcp->rcft.rcfu.fName) == 0) || 484 ((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName, 485 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) { 486 487 char reason[] = "Could not create file"; 488 int reasonLen = strlen(reason); 489 fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen); 490 } 491 else 492 rtcp->rcft.rcfu.uploadInProgress = TRUE; 493 494 return fileUploadErrMsg; 495 } 496 497 498 FileTransferMsg 499 GetFileUploadCompressedLevelErrMsg() 500 { 501 char reason[] = "Server does not support data compression on upload"; 502 int reasonLen = strlen(reason); 503 504 return CreateFileUploadErrMsg(reason, reasonLen); 505 } 506 507 508 FileTransferMsg 509 ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf) 510 { 511 FileTransferMsg ftm; 512 unsigned long numOfBytesWritten = 0; 513 514 memset(&ftm, 0, sizeof(FileTransferMsg)); 515 516 numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize); 517 518 if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) { 519 char reason[] = "Error writing file data"; 520 int reasonLen = strlen(reason); 521 ftm = CreateFileUploadErrMsg(reason, reasonLen); 522 CloseUndoneFileTransfer(cl, rtcp); 523 } 524 return ftm; 525 } 526 527 528 void 529 FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp) 530 { 531 /* Here we are settimg the modification and access time of the file */ 532 /* Windows code stes mod/access/creation time of the file */ 533 struct utimbuf utb; 534 535 utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime; 536 if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) { 537 rfbLog("File [%s]: Method [%s]: Setting the modification/access" 538 " time for the file <%s> failed\n", __FILE__, 539 __FUNCTION__, rtcp->rcft.rcfu.fName); 540 } 541 542 if(rtcp->rcft.rcfu.uploadFD != -1) { 543 close(rtcp->rcft.rcfu.uploadFD); 544 rtcp->rcft.rcfu.uploadFD = -1; 545 rtcp->rcft.rcfu.uploadInProgress = FALSE; 546 } 547 } 548 549 550 FileTransferMsg 551 CreateFileUploadErrMsg(char* reason, unsigned int reasonLen) 552 { 553 FileTransferMsg fileUploadErrMsg; 554 int length = sz_rfbFileUploadCancelMsg + reasonLen; 555 rfbFileUploadCancelMsg *pFDF = NULL; 556 char *pFollow = NULL; 557 558 char *pData = (char*) calloc(length, sizeof(char)); 559 memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg)); 560 if(pData == NULL) { 561 rfbLog("File [%s]: Method [%s]: pData is NULL\n", 562 __FILE__, __FUNCTION__); 563 return fileUploadErrMsg; 564 } 565 566 pFDF = (rfbFileUploadCancelMsg *) pData; 567 pFollow = &pData[sz_rfbFileUploadCancelMsg]; 568 569 pFDF->type = rfbFileUploadCancel; 570 pFDF->reasonLen = Swap16IfLE(reasonLen); 571 memcpy(pFollow, reason, reasonLen); 572 573 fileUploadErrMsg.data = pData; 574 fileUploadErrMsg.length = length; 575 576 return fileUploadErrMsg; 577 } 578 579 580 /****************************************************************************** 581 * Method to cancel File Transfer operation. 582 ******************************************************************************/ 583 584 void 585 CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp) 586 { 587 /* TODO :: File Upload case is not handled currently */ 588 /* TODO :: In case of concurrency we need to use Critical Section */ 589 590 if(cl == NULL) 591 return; 592 593 594 if(rtcp->rcft.rcfu.uploadInProgress == TRUE) { 595 rtcp->rcft.rcfu.uploadInProgress = FALSE; 596 597 if(rtcp->rcft.rcfu.uploadFD != -1) { 598 close(rtcp->rcft.rcfu.uploadFD); 599 rtcp->rcft.rcfu.uploadFD = -1; 600 } 601 602 if(unlink(rtcp->rcft.rcfu.fName) == -1) { 603 rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n", 604 __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName); 605 } 606 607 memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX); 608 } 609 610 if(rtcp->rcft.rcfd.downloadInProgress == TRUE) { 611 rtcp->rcft.rcfd.downloadInProgress = FALSE; 612 613 if(rtcp->rcft.rcfd.downloadFD != -1) { 614 close(rtcp->rcft.rcfd.downloadFD); 615 rtcp->rcft.rcfd.downloadFD = -1; 616 } 617 memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX); 618 } 619 } 620 621 622 /****************************************************************************** 623 * Method to handle create directory request. 624 ******************************************************************************/ 625 626 void 627 CreateDirectory(char* dirName) 628 { 629 if(dirName == NULL) return; 630 631 if(mkdir(dirName, 0700) == -1) { 632 rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n", 633 __FILE__, __FUNCTION__, dirName); 634 } 635 } 636 637