Fixed download file canceling
[public/netxms.git] / src / agent / subagents / filemgr / filemgr.cpp
1 /*
2 ** File management subagent
3 ** Copyright (C) 2014-2017 Raden Solutions
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 **/
20
21 #include "filemgr.h"
22
23 #ifndef _WIN32
24 #include <pwd.h>
25 #include <grp.h>
26 #endif
27
28 /*
29 * Create new RootFolder
30 */
31 RootFolder::RootFolder(const TCHAR *folder)
32 {
33 m_folder = _tcsdup(folder);
34 m_readOnly = false;
35
36 TCHAR *ptr = _tcschr(m_folder, _T(';'));
37 if (ptr == NULL)
38 return;
39
40 *ptr = 0;
41 if (_tcscmp(ptr+1, _T("ro")) == 0)
42 m_readOnly = true;
43 }
44
45 /**
46 * Root folders
47 */
48 static ObjectArray<RootFolder> *g_rootFileManagerFolders;
49 static HashMap<UINT32, VolatileCounter> *g_downloadFileStopMarkers;
50
51 /**
52 * Monitored file list
53 */
54 MonitoredFileList g_monitorFileList;
55
56
57 #ifdef _WIN32
58
59 /**
60 * Convert path from UNIX to local format
61 */
62 static void ConvertPathToHost(TCHAR *path)
63 {
64 for(int i = 0; path[i] != 0; i++)
65 if (path[i] == _T('/'))
66 path[i] = _T('\\');
67 }
68
69 #else
70
71 #define ConvertPathToHost(x)
72
73 #endif
74
75 #ifdef _WIN32
76
77 /**
78 * Convert path from local to UNIX format
79 */
80 static void ConvertPathToNetwork(TCHAR *path)
81 {
82 for(int i = 0; path[i] != 0; i++)
83 if (path[i] == _T('\\'))
84 path[i] = _T('/');
85 }
86
87 #else
88
89 #define ConvertPathToNetwork(x)
90
91 #endif
92
93 /**
94 * Subagent initialization
95 */
96 static BOOL SubagentInit(Config *config)
97 {
98 g_rootFileManagerFolders = new ObjectArray<RootFolder>(16, 16, true);
99 g_downloadFileStopMarkers = new HashMap<UINT32, VolatileCounter>();
100 ConfigEntry *root = config->getEntry(_T("/filemgr/RootFolder"));
101 if (root != NULL)
102 {
103 for(int i = 0; i < root->getValueCount(); i++)
104 {
105 RootFolder *folder = new RootFolder(root->getValue(i));
106 g_rootFileManagerFolders->add(folder);
107 AgentWriteDebugLog(5, _T("FILEMGR: added root folder \"%s\""), folder->getFolder());
108 }
109 }
110 AgentWriteDebugLog(2, _T("FILEMGR: subagent initialized"));
111 return TRUE;
112 }
113
114 /**
115 * Called by master agent at unload
116 */
117 static void SubagentShutdown()
118 {
119 delete g_rootFileManagerFolders;
120 delete g_downloadFileStopMarkers;
121 }
122
123 #ifndef _WIN32
124
125 /**
126 * Converts path to absolute removing "//", "../", "./" ...
127 */
128 static TCHAR *GetRealPath(TCHAR *path)
129 {
130 if(path == NULL || path[0] == 0)
131 return NULL;
132 TCHAR *result = (TCHAR*)malloc(sizeof(TCHAR)*MAX_PATH);
133 _tcscpy(result,path);
134 TCHAR *current = result;
135
136 // just remove all dots before path
137 if (!_tcsncmp(current, _T("../"), 3))
138 memmove(current, current + 3, (_tcslen(current+3) + 1) * sizeof(TCHAR));
139
140 if (!_tcsncmp(current, _T("./"), 2))
141 memmove(current, current + 2, (_tcslen(current+2) + 1) * sizeof(TCHAR));
142
143 while(*current != 0)
144 {
145 if (current[0] == '/')
146 {
147 switch(current[1])
148 {
149 case '/':
150 memmove(current, current + 1, _tcslen(current) * sizeof(TCHAR));
151 break;
152 case '.':
153 if (current[2] != 0)
154 {
155 if (current[2] == '.' && (current[3] == 0 || current[3] == '/'))
156 {
157 if (current == result)
158 {
159 memmove(current, current + 3, (_tcslen(current + 3) + 1) * sizeof(TCHAR));
160 }
161 else
162 {
163 TCHAR *tmp = current;
164 do
165 {
166 tmp--;
167 if (tmp[0] == '/')
168 {
169 break;
170 }
171 } while(result != tmp);
172 memmove(tmp, current + 3, (_tcslen(current+3) + 1) * sizeof(TCHAR));
173 }
174 }
175 else
176 {
177 // dot + something, skip both
178 current += 2;
179 }
180 }
181 else
182 {
183 // "/." at the end
184 *current = 0;
185 }
186 break;
187 default:
188 current++;
189 break;
190 }
191 }
192 else
193 {
194 current++;
195 }
196 }
197 return result;
198 }
199
200 #endif
201
202 /**
203 * Takes folder/file path - make it absolute (result will be written back to the folder variable)
204 * and check that this folder/file is under allowed root path.
205 * If second parameter is set to true - then request is for getting content and "/" path should be acepted
206 * and afterwards treatet as: "give list of all allowd folders".
207 */
208 static bool CheckFullPath(TCHAR *folder, bool withHomeDir, bool isModify = false)
209 {
210 AgentWriteDebugLog(3, _T("FILEMGR: CheckFullPath: input is %s"), folder);
211 if (withHomeDir && !_tcscmp(folder, FS_PATH_SEPARATOR))
212 {
213 return true;
214 }
215
216 #ifdef _WIN32
217 TCHAR *fullPathT = _tfullpath(NULL, folder, MAX_PATH);
218 #else
219 TCHAR *fullPathT = GetRealPath(folder);
220 #endif
221 AgentWriteDebugLog(3, _T("FILEMGR: CheckFullPath: Full path %s"), fullPathT);
222 if (fullPathT != NULL)
223 {
224 _tcscpy(folder, fullPathT);
225 free(fullPathT);
226 }
227 else
228 {
229 return false;
230 }
231 for(int i = 0; i < g_rootFileManagerFolders->size(); i++)
232 {
233 if (!_tcsncmp(g_rootFileManagerFolders->get(i)->getFolder(), folder, _tcslen(g_rootFileManagerFolders->get(i)->getFolder())))
234 {
235 if (isModify && g_rootFileManagerFolders->get(i)->isReadOnly())
236 return false;
237 else
238 return true;
239 }
240 }
241
242 return false;
243 }
244
245 #define REGULAR_FILE 1
246 #define DIRECTORY 2
247 #define SYMLINC 4
248
249 /**
250 * Returns if file already exist
251 */
252 int CheckFileType(const TCHAR *fileName)
253 {
254 NX_STAT_STRUCT st;
255 if (CALL_STAT(fileName, &st) == 0)
256 {
257 if(S_ISDIR(st.st_mode))
258 {
259 return DIRECTORY;
260 }
261 else
262 return REGULAR_FILE;
263 }
264 return -1;
265 }
266
267 bool VerifyFileOperation(const TCHAR *fileName, bool allowOverwirite, NXCPMessage *response)
268 {
269 int fileType = CheckFileType(fileName);
270 if(fileType > 0 && !allowOverwirite)
271 {
272 response->setField(VID_RCC, fileType == DIRECTORY ? ERR_FOLDER_ALREADY_EXISTS : ERR_FILE_ALREADY_EXISTS);
273 return false;
274 }
275 else
276 return true;
277 }
278
279 #ifdef _WIN32
280
281 TCHAR *GetFileOwnerWin(const TCHAR *file)
282 {
283 return _tcsdup(_T(""));
284 }
285
286 #endif // _WIN32
287
288 static bool FillMessageFolderContent(const TCHAR *filePath, const TCHAR *fileName, NXCPMessage *msg, UINT32 varId)
289 {
290 if (_taccess(filePath, 4) != 0)
291 return false;
292
293 NX_STAT_STRUCT st;
294 if (CALL_STAT(filePath, &st) == 0)
295 {
296 msg->setField(varId++, fileName);
297 msg->setField(varId++, (QWORD)st.st_size);
298 msg->setField(varId++, (QWORD)st.st_mtime);
299 UINT32 type = 0;
300 TCHAR accessRights[11];
301 #ifndef _WIN32
302 if(S_ISLNK(st.st_mode))
303 {
304 accessRights[0] = _T('l');
305 type |= SYMLINC;
306 NX_STAT_STRUCT symlincSt;
307 if (CALL_STAT_FOLLOW_SYMLINK(filePath, &symlincSt) == 0)
308 {
309 type |= S_ISDIR(symlincSt.st_mode) ? DIRECTORY : 0;
310 }
311 }
312
313 if(S_ISCHR(st.st_mode)) accessRights[0] = _T('c');
314 if(S_ISBLK(st.st_mode)) accessRights[0] = _T('b');
315 if(S_ISFIFO(st.st_mode)) accessRights[0] = _T('p');
316 if(S_ISSOCK(st.st_mode)) accessRights[0] = _T('s');
317 #endif
318 if(S_ISREG(st.st_mode))
319 {
320 type |= REGULAR_FILE;
321 accessRights[0] = _T('-');
322 }
323 if(S_ISDIR(st.st_mode))
324 {
325 type |= DIRECTORY;
326 accessRights[0] = _T('d');
327 }
328
329 msg->setField(varId++, type);
330 TCHAR fullName[MAX_PATH];
331 _tcscpy(fullName, filePath);
332 msg->setField(varId++, fullName);
333
334 #ifndef _WIN32
335 struct passwd *pw = getpwuid(st.st_uid);
336 struct group *gr = getgrgid(st.st_gid);
337 #ifdef UNICODE
338 msg->setFieldFromMBString(varId++, pw->pw_name);
339 msg->setFieldFromMBString(varId++, gr->gr_name);
340 #else
341 msg->setField(varId++, pw->pw_name);
342 msg->setField(varId++, gr->gr_name);
343 #endif
344 accessRights[1] = (S_IRUSR & st.st_mode) > 0 ? _T('r') : _T('-');
345 accessRights[2] = (S_IWUSR & st.st_mode) > 0 ? _T('w') : _T('-');
346 accessRights[3] = (S_IXUSR & st.st_mode) > 0 ? _T('x') : _T('-');
347 accessRights[4] = (S_IRGRP & st.st_mode) > 0 ? _T('r') : _T('-');
348 accessRights[5] = (S_IWGRP & st.st_mode) > 0 ? _T('w') : _T('-');
349 accessRights[6] = (S_IXGRP & st.st_mode) > 0 ? _T('x') : _T('-');
350 accessRights[7] = (S_IROTH & st.st_mode) > 0 ? _T('r') : _T('-');
351 accessRights[8] = (S_IWOTH & st.st_mode) > 0 ? _T('w') : _T('-');
352 accessRights[9] = (S_IXOTH & st.st_mode) > 0 ? _T('x') : _T('-');
353 accessRights[10] = 0;
354 msg->setField(varId++, accessRights);
355 #else
356 TCHAR *owner = GetFileOwnerWin(filePath);
357 msg->setField(varId++, owner);
358 safe_free(owner);
359 msg->setField(varId++, _T(""));
360 msg->setField(varId++, _T(""));
361 #endif // _WIN32
362 return true;
363 }
364 else
365 {
366 AgentWriteDebugLog(3, _T("FILEMGR: GetFolderContent: cannot get folder %s"), filePath);
367 return false;
368 }
369 }
370
371 /**
372 * Puts in response list of containing files
373 */
374 static void GetFolderContent(TCHAR *folder, NXCPMessage *response, bool rootFolder, bool allowMultipart, AbstractCommSession *session)
375 {
376 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" (root=%s, multipart=%s)"),
377 folder, rootFolder ? _T("true") : _T("false"), allowMultipart ? _T("true") : _T("false"));
378
379 NXCPMessage *msg;
380 if (allowMultipart)
381 {
382 msg = new NXCPMessage();
383 msg->setCode(CMD_REQUEST_COMPLETED);
384 msg->setId(response->getId());
385 msg->setField(VID_ALLOW_MULTIPART, (INT16)1);
386 }
387 else
388 {
389 msg = response;
390 }
391
392 UINT32 count = 0;
393 UINT32 fieldId = VID_INSTANCE_LIST_BASE;
394
395 if (!_tcscmp(folder, FS_PATH_SEPARATOR) && rootFolder)
396 {
397 response->setField(VID_RCC, ERR_SUCCESS);
398
399 for(int i = 0; i < g_rootFileManagerFolders->size(); i++)
400 {
401 if (FillMessageFolderContent(g_rootFileManagerFolders->get(i)->getFolder(), g_rootFileManagerFolders->get(i)->getFolder(), msg, fieldId))
402 {
403 count++;
404 fieldId += 10;
405 }
406 }
407 msg->setField(VID_INSTANCE_COUNT, count);
408 if (allowMultipart)
409 {
410 msg->setEndOfSequence();
411 msg->setField(VID_INSTANCE_COUNT, count);
412 session->sendMessage(msg);
413 delete msg;
414 }
415 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" completed"), folder);
416 return;
417 }
418
419 _TDIR *dir = _topendir(folder);
420 if (dir != NULL)
421 {
422 response->setField(VID_RCC, ERR_SUCCESS);
423
424 struct _tdirent *d;
425 while((d = _treaddir(dir)) != NULL)
426 {
427 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
428 continue;
429
430 TCHAR fullName[MAX_PATH];
431 _tcscpy(fullName, folder);
432 _tcscat(fullName, FS_PATH_SEPARATOR);
433 _tcscat(fullName, d->d_name);
434
435 if (FillMessageFolderContent(fullName, d->d_name, msg, fieldId))
436 {
437 count++;
438 fieldId += 10;
439 }
440 if (allowMultipart && (count == 64))
441 {
442 msg->setField(VID_INSTANCE_COUNT, count);
443 session->sendMessage(msg);
444 msg->deleteAllFields();
445 msg->setField(VID_ALLOW_MULTIPART, (INT16)1);
446 count = 0;
447 fieldId = VID_INSTANCE_LIST_BASE;
448 }
449 }
450 msg->setField(VID_INSTANCE_COUNT, count);
451 _tclosedir(dir);
452
453 if (allowMultipart)
454 {
455 msg->setEndOfSequence();
456 msg->setField(VID_INSTANCE_COUNT, count);
457 session->sendMessage(msg);
458 }
459 }
460 else
461 {
462 response->setField(VID_RCC, ERR_IO_FAILURE);
463 }
464
465 if (allowMultipart)
466 delete msg;
467
468 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" completed"), folder);
469 }
470
471 /**
472 * Delete file/folder
473 */
474 static BOOL Delete(const TCHAR *name)
475 {
476 NX_STAT_STRUCT st;
477
478 if (CALL_STAT(name, &st) != 0)
479 {
480 return FALSE;
481 }
482
483 bool result = true;
484
485 if (S_ISDIR(st.st_mode))
486 {
487 // get element list and for each element run Delete
488 _TDIR *dir = _topendir(name);
489 if (dir != NULL)
490 {
491 struct _tdirent *d;
492 while((d = _treaddir(dir)) != NULL)
493 {
494 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
495 {
496 continue;
497 }
498 TCHAR newName[MAX_PATH];
499 _tcscpy(newName, name);
500 _tcscat(newName, FS_PATH_SEPARATOR);
501 _tcscat(newName, d->d_name);
502 result = result && Delete(newName);
503 }
504 _tclosedir(dir);
505 }
506 //remove directory
507 #ifdef _WIN32
508 return RemoveDirectory(name);
509 #else
510 return _trmdir(name) == 0;
511 #endif
512 }
513 #ifdef _WIN32
514 return DeleteFile(name);
515 #else
516 return _tremove(name) == 0;
517 #endif
518 }
519
520 /**
521 * Rename file/folder
522 */
523 static BOOL Rename(TCHAR* oldName, TCHAR * newName)
524 {
525 if (_trename(oldName, newName) == 0)
526 {
527 return TRUE;
528 }
529 else
530 {
531 return FALSE;
532 }
533 }
534
535 #ifndef _WIN32
536
537 /**
538 * Copy file/folder
539 */
540 static BOOL CopyFile(NX_STAT_STRUCT *st, const TCHAR *oldName, const TCHAR *newName)
541 {
542 int oldFile = _topen(oldName, O_RDONLY | O_BINARY);
543 if (oldFile == -1)
544 return FALSE;
545
546 int newFile = _topen(newName, O_CREAT | O_BINARY | O_WRONLY, st->st_mode); // should be copied with the same acess rights
547 if (newFile == -1)
548 {
549 close(oldFile);
550 return FALSE;
551 }
552
553 int size = 16384, in, out;
554 BYTE *bytes = (BYTE *)malloc(size);
555
556 while((in = read(oldFile, bytes, size)) > 0)
557 {
558 out = write(newFile, bytes, (ssize_t)in);
559 if (out != in)
560 {
561 close(oldFile);
562 close(newFile);
563 free(bytes);
564 return FALSE;
565 }
566 }
567
568 close(oldFile);
569 close(newFile);
570 free(bytes);
571 return TRUE;
572 }
573
574 #endif
575
576 /**
577 * Move file/folder
578 */
579 static BOOL MoveFile(TCHAR* oldName, TCHAR* newName)
580 {
581 #ifdef _WIN32
582 return MoveFileEx(oldName, newName, MOVEFILE_COPY_ALLOWED);
583 #else
584 if (Rename(oldName, newName))
585 {
586 return TRUE;
587 }
588
589 NX_STAT_STRUCT st;
590
591 if (CALL_STAT(oldName, &st) != 0)
592 {
593 return FALSE;
594 }
595
596 if (S_ISDIR(st.st_mode))
597 {
598 _tmkdir(newName, st.st_mode);
599 _TDIR *dir = _topendir(oldName);
600 if (dir != NULL)
601 {
602 struct _tdirent *d;
603 while((d = _treaddir(dir)) != NULL)
604 {
605 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
606 {
607 continue;
608 }
609 TCHAR nextNewName[MAX_PATH];
610 _tcscpy(nextNewName, newName);
611 _tcscat(nextNewName, _T("/"));
612 _tcscat(nextNewName, d->d_name);
613
614 TCHAR nextOldaName[MAX_PATH];
615 _tcscpy(nextOldaName, oldName);
616 _tcscat(nextOldaName, _T("/"));
617 _tcscat(nextOldaName, d->d_name);
618
619 MoveFile(nextOldaName, nextNewName);
620 }
621 _tclosedir(dir);
622 }
623 _trmdir(oldName);
624 }
625 else
626 {
627 if (!CopyFile(&st, oldName, newName))
628 return FALSE;
629 }
630 return TRUE;
631 #endif /* _WIN32 */
632 }
633
634 /**
635 * Send file
636 */
637 THREAD_RESULT THREAD_CALL SendFile(void *dataStruct)
638 {
639 MessageData *data = (MessageData *)dataStruct;
640
641 AgentWriteDebugLog(5, _T("CommSession::getLocalFile(): request for file \"%s\", follow = %s, compress = %s"),
642 data->fileName, data->follow ? _T("true") : _T("false"), data->allowCompression ? _T("true") : _T("false"));
643 bool success = AgentSendFileToServer(data->session, data->id, data->fileName, (int)data->offset, data->allowCompression, g_downloadFileStopMarkers->get(data->id));
644 if (data->follow && success)
645 {
646 g_monitorFileList.add(data->fileNameCode);
647 FollowData *flData = new FollowData(data->fileName, data->fileNameCode, 0, data->session->getServerAddress());
648 ThreadCreateEx(SendFileUpdatesOverNXCP, 0, flData);
649 }
650 free(data->fileName);
651 free(data->fileNameCode);
652 g_downloadFileStopMarkers->remove(data->id);
653 delete data;
654 return THREAD_OK;
655 }
656
657 /**
658 * Get folder information
659 */
660 static void GetFolderInfo(const TCHAR *folder, UINT64 *fileCount, UINT64 *folderSize)
661 {
662 _TDIR *dir = _topendir(folder);
663 if (dir != NULL)
664 {
665 NX_STAT_STRUCT st;
666 struct _tdirent *d;
667 while((d = _treaddir(dir)) != NULL)
668 {
669 if (sizeof(folder) >= MAX_PATH)
670 return;
671
672 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
673 {
674 continue;
675 }
676
677 TCHAR fullName[MAX_PATH];
678 _tcscpy(fullName, folder);
679 _tcscat(fullName, FS_PATH_SEPARATOR);
680 _tcscat(fullName, d->d_name);
681
682 if (CALL_STAT(fullName, &st) == 0)
683 {
684 if (S_ISDIR(st.st_mode))
685 {
686 GetFolderInfo(fullName, fileCount, folderSize);
687 }
688 else
689 {
690 *folderSize += st.st_size;
691 (*fileCount)++;
692 }
693 }
694 }
695 _tclosedir(dir);
696 }
697 }
698
699 /**
700 * Process commands like get files in folder, delete file/folder, copy file/folder, move file/folder
701 */
702 static BOOL ProcessCommands(UINT32 command, NXCPMessage *request, NXCPMessage *response, AbstractCommSession *session)
703 {
704 switch(command)
705 {
706 case CMD_GET_FOLDER_SIZE:
707 {
708 TCHAR directory[MAX_PATH];
709 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
710 response->setId(request->getId());
711 if (directory[0] == 0)
712 {
713 response->setField(VID_RCC, ERR_IO_FAILURE);
714 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_SIZE): File name should be set."));
715 return TRUE;
716 }
717 ConvertPathToHost(directory);
718
719 if (CheckFullPath(directory, false) && session->isMasterServer())
720 {
721 UINT64 fileCount = 0, fileSize = 0;
722 GetFolderInfo(directory, &fileCount, &fileSize);
723 response->setField(VID_RCC, ERR_SUCCESS);
724 response->setField(VID_FOLDER_SIZE, fileSize);
725 response->setField(VID_FILE_COUNT, fileCount);
726 }
727 else
728 {
729 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_SIZE): Access denied"));
730 response->setField(VID_RCC, ERR_ACCESS_DENIED);
731 }
732
733 return TRUE;
734 }
735 case CMD_GET_FOLDER_CONTENT:
736 {
737 TCHAR directory[MAX_PATH];
738 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
739 response->setId(request->getId());
740 if (directory[0] == 0)
741 {
742 response->setField(VID_RCC, ERR_IO_FAILURE);
743 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_CONTENT): File name should be set."));
744 return TRUE;
745 }
746 ConvertPathToHost(directory);
747
748 bool rootFolder = request->getFieldAsUInt16(VID_ROOT) ? 1 : 0;
749 if (CheckFullPath(directory, rootFolder) && session->isMasterServer())
750 {
751 GetFolderContent(directory, response, rootFolder, request->getFieldAsBoolean(VID_ALLOW_MULTIPART), session);
752 }
753 else
754 {
755 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_CONTENT): Access denied"));
756 response->setField(VID_RCC, ERR_ACCESS_DENIED);
757 }
758 return TRUE;
759 }
760 case CMD_FILEMGR_DELETE_FILE:
761 {
762 TCHAR file[MAX_PATH];
763 request->getFieldAsString(VID_FILE_NAME, file, MAX_PATH);
764 response->setId(request->getId());
765 if(file[0] == 0)
766 {
767 response->setField(VID_RCC, ERR_IO_FAILURE);
768 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_DELETE_FILE): File name should be set."));
769 return TRUE;
770 }
771 ConvertPathToHost(file);
772
773 if (CheckFullPath(file, false, true) && session->isMasterServer())
774 {
775 if (Delete(file))
776 {
777 response->setField(VID_RCC, ERR_SUCCESS);
778 }
779 else
780 {
781 response->setField(VID_RCC, ERR_IO_FAILURE);
782 }
783 }
784 else
785 {
786 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_DELETE_FILE): Access denied"));
787 response->setField(VID_RCC, ERR_ACCESS_DENIED);
788 }
789 return TRUE;
790 }
791 case CMD_FILEMGR_RENAME_FILE:
792 {
793 TCHAR oldName[MAX_PATH];
794 request->getFieldAsString(VID_FILE_NAME, oldName, MAX_PATH);
795 TCHAR newName[MAX_PATH];
796 request->getFieldAsString(VID_NEW_FILE_NAME, newName, MAX_PATH);
797 bool allowOverwirite = request->getFieldAsBoolean(VID_OVERVRITE);
798 response->setId(request->getId());
799 if (oldName[0] == 0 && newName[0] == 0)
800 {
801 response->setField(VID_RCC, ERR_IO_FAILURE);
802 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_RENAME_FILE): File names should be set."));
803 return TRUE;
804 }
805 ConvertPathToHost(oldName);
806 ConvertPathToHost(newName);
807
808 if (CheckFullPath(oldName, false, true) && CheckFullPath(newName, false) && session->isMasterServer())
809 {
810 if(VerifyFileOperation(newName, allowOverwirite, response))
811 {
812 if (Rename(oldName, newName))
813 {
814 response->setField(VID_RCC, ERR_SUCCESS);
815 }
816 else
817 {
818 response->setField(VID_RCC, ERR_IO_FAILURE);
819 }
820 }
821 }
822 else
823 {
824 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_RENAME_FILE): Access denied"));
825 response->setField(VID_RCC, ERR_ACCESS_DENIED);
826 }
827 return TRUE;
828 }
829 case CMD_FILEMGR_MOVE_FILE:
830 {
831 TCHAR oldName[MAX_PATH];
832 request->getFieldAsString(VID_FILE_NAME, oldName, MAX_PATH);
833 TCHAR newName[MAX_PATH];
834 request->getFieldAsString(VID_NEW_FILE_NAME, newName, MAX_PATH);
835 bool allowOverwirite = request->getFieldAsBoolean(VID_OVERVRITE);
836 response->setId(request->getId());
837 if ((oldName[0] == 0) && (newName[0] == 0))
838 {
839 response->setField(VID_RCC, ERR_IO_FAILURE);
840 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_MOVE_FILE): File names should be set."));
841 return TRUE;
842 }
843 ConvertPathToHost(oldName);
844 ConvertPathToHost(newName);
845
846 if (CheckFullPath(oldName, false, true) && CheckFullPath(newName, false) && session->isMasterServer())
847 {
848 if(VerifyFileOperation(newName, allowOverwirite, response))
849 {
850 if(MoveFile(oldName, newName))
851 {
852 response->setField(VID_RCC, ERR_SUCCESS);
853 }
854 else
855 {
856 response->setField(VID_RCC, ERR_IO_FAILURE);
857 }
858 }
859 }
860 else
861 {
862 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_MOVE_FILE): Access denied"));
863 response->setField(VID_RCC, ERR_ACCESS_DENIED);
864 }
865 return TRUE;
866 }
867 case CMD_FILEMGR_UPLOAD:
868 {
869 TCHAR name[MAX_PATH];
870 request->getFieldAsString(VID_FILE_NAME, name, MAX_PATH);
871 bool allowOverwirite = request->getFieldAsBoolean(VID_OVERVRITE);
872 response->setId(request->getId());
873 if (name[0] == 0)
874 {
875 response->setField(VID_RCC, ERR_IO_FAILURE);
876 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_UPLOAD): File name should be set."));
877 return TRUE;
878 }
879 ConvertPathToHost(name);
880
881 if (CheckFullPath(name, false, true) && session->isMasterServer())
882 {
883 if(VerifyFileOperation(name, allowOverwirite, response))
884 response->setField(VID_RCC, session->openFile(name, request->getId(), request->getFieldAsTime(VID_MODIFICATION_TIME)));
885 }
886 else
887 {
888 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_UPLOAD): Access denied"));
889 response->setField(VID_RCC, ERR_ACCESS_DENIED);
890 }
891 return TRUE;
892 }
893 case CMD_GET_FILE_DETAILS:
894 {
895 TCHAR fileName[MAX_PATH];
896 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
897 ExpandFileName(fileName, fileName, MAX_PATH, session->isMasterServer());
898 response->setId(request->getId());
899
900 if (session->isMasterServer() && CheckFullPath(fileName, false))
901 {
902 NX_STAT_STRUCT fs;
903
904 //prepare file name
905 if (CALL_STAT(fileName, &fs) == 0)
906 {
907 response->setField(VID_FILE_SIZE, (UINT64)fs.st_size);
908 response->setField(VID_MODIFICATION_TIME, (UINT64)fs.st_mtime);
909 response->setField(VID_RCC, ERR_SUCCESS);
910 }
911 else
912 {
913 response->setField(VID_RCC, ERR_FILE_STAT_FAILED);
914 }
915 }
916 else
917 {
918 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FILE_DETAILS): Access denied"));
919 response->setField(VID_RCC, ERR_ACCESS_DENIED);
920 }
921 return TRUE;
922 }
923 case CMD_GET_AGENT_FILE:
924 {
925 response->setId(request->getId());
926 TCHAR fileName[MAX_PATH];
927 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
928 ExpandFileName(fileName, fileName, MAX_PATH, session->isMasterServer());
929
930 if (CheckFullPath(fileName, false))
931 {
932 TCHAR *fileNameCode = (TCHAR*)malloc(MAX_PATH * sizeof(TCHAR));
933 request->getFieldAsString(VID_NAME, fileNameCode, MAX_PATH);
934
935 MessageData *data = new MessageData();
936 data->fileName = _tcsdup(fileName);
937 data->fileNameCode = fileNameCode;
938 data->follow = request->getFieldAsBoolean(VID_FILE_FOLLOW);
939 data->allowCompression = request->getFieldAsBoolean(VID_ENABLE_COMPRESSION);
940 data->id = request->getId();
941 data->offset = request->getFieldAsUInt32(VID_FILE_OFFSET);
942 data->session = session;
943 g_downloadFileStopMarkers->set(request->getId(), new VolatileCounter(0));
944
945 ThreadCreateEx(SendFile, 0, data);
946
947 response->setField(VID_RCC, ERR_SUCCESS);
948 }
949 else
950 {
951 response->setField(VID_RCC, ERR_ACCESS_DENIED);
952 }
953 return TRUE;
954 }
955 case CMD_CANCEL_FILE_DOWNLOAD:
956 {
957 VolatileCounter *counter = g_downloadFileStopMarkers->get(request->getFieldAsUInt32(VID_REQUEST_ID));
958 if(counter != NULL)
959 {
960 InterlockedIncrement(counter);
961 response->setField(VID_RCC, ERR_SUCCESS);
962 }
963 else
964 response->setField(VID_RCC, ERR_INTERNAL_ERROR);
965 return TRUE;
966 }
967 case CMD_CANCEL_FILE_MONITORING:
968 {
969 response->setId(request->getId());
970 TCHAR fileName[MAX_PATH];
971 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
972 if (g_monitorFileList.remove(fileName))
973 {
974 response->setField(VID_RCC, ERR_SUCCESS);
975 }
976 else
977 {
978 response->setField(VID_RCC, ERR_BAD_ARGUMENTS);
979 }
980 return TRUE;
981 }
982 case CMD_FILEMGR_CREATE_FOLDER:
983 {
984 TCHAR directory[MAX_PATH];
985 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
986 response->setId(request->getId());
987 if (directory[0] == 0)
988 {
989 response->setField(VID_RCC, ERR_IO_FAILURE);
990 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): File name should be set."));
991 return TRUE;
992 }
993 ConvertPathToHost(directory);
994
995 if (CheckFullPath(directory, false, true) && session->isMasterServer())
996 {
997 if(VerifyFileOperation(directory, false, response))
998 {
999 if (CreateFolder(directory))
1000 {
1001 response->setField(VID_RCC, ERR_SUCCESS);
1002 }
1003 else
1004 {
1005 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): Could not create directory"));
1006 response->setField(VID_RCC, ERR_IO_FAILURE);
1007 }
1008 }
1009 }
1010 else
1011 {
1012 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): Access denied"));
1013 response->setField(VID_RCC, ERR_ACCESS_DENIED);
1014 }
1015 return TRUE;
1016 }
1017 default:
1018 return FALSE;
1019 }
1020 }
1021
1022 /**
1023 * Subagent information
1024 */
1025 static NETXMS_SUBAGENT_INFO m_info =
1026 {
1027 NETXMS_SUBAGENT_INFO_MAGIC,
1028 _T("FILEMGR"), NETXMS_BUILD_TAG,
1029 SubagentInit, SubagentShutdown, ProcessCommands,
1030 0, NULL, // parameters
1031 0, NULL, // lists
1032 0, NULL, // tables
1033 0, NULL, // actions
1034 0, NULL // push parameters
1035 };
1036
1037 /**
1038 * Entry point for NetXMS agent
1039 */
1040 DECLARE_SUBAGENT_ENTRY_POINT(FILEMGR)
1041 {
1042 *ppInfo = &m_info;
1043 return TRUE;
1044 }
1045
1046 #ifdef _WIN32
1047
1048 /**
1049 * DLL entry point
1050 */
1051 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1052 {
1053 if (dwReason == DLL_PROCESS_ATTACH)
1054 DisableThreadLibraryCalls(hInstance);
1055 return TRUE;
1056 }
1057
1058 #endif