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