a21d6b74192fb2b4a1045303bdf66f7c9ec50c82
[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 #ifdef _WIN32
246
247 TCHAR *GetFileOwnerWin(const TCHAR *file)
248 {
249 return _tcsdup(_T(""));
250 }
251
252 #endif // _WIN32
253
254 static bool FillMessageFolderContent(const TCHAR *filePath, const TCHAR *fileName, NXCPMessage *msg, UINT32 varId)
255 {
256 if (_taccess(filePath, 4) != 0)
257 return false;
258
259 NX_STAT_STRUCT st;
260 if (CALL_STAT(filePath, &st) == 0)
261 {
262 msg->setField(varId++, fileName);
263 msg->setField(varId++, (QWORD)st.st_size);
264 msg->setField(varId++, (QWORD)st.st_mtime);
265 UINT32 type = 0;
266 TCHAR accessRights[11];
267 #ifndef _WIN32
268 if(S_ISLNK(st.st_mode))
269 {
270 accessRights[0] = _T('l');
271 type |= SYMLINC;
272 NX_STAT_STRUCT symlincSt;
273 if (CALL_STAT_FOLLOW_SYMLINK(filePath, &symlincSt) == 0)
274 {
275 type |= S_ISDIR(symlincSt.st_mode) ? DIRECTORY : 0;
276 }
277 }
278
279 if(S_ISCHR(st.st_mode)) accessRights[0] = _T('c');
280 if(S_ISBLK(st.st_mode)) accessRights[0] = _T('b');
281 if(S_ISFIFO(st.st_mode)) accessRights[0] = _T('p');
282 if(S_ISSOCK(st.st_mode)) accessRights[0] = _T('s');
283 #endif
284 if(S_ISREG(st.st_mode))
285 {
286 type |= REGULAR_FILE;
287 accessRights[0] = _T('-');
288 }
289 if(S_ISDIR(st.st_mode))
290 {
291 type |= DIRECTORY;
292 accessRights[0] = _T('d');
293 }
294
295 msg->setField(varId++, type);
296 TCHAR fullName[MAX_PATH];
297 _tcscpy(fullName, filePath);
298 msg->setField(varId++, fullName);
299
300 #ifndef _WIN32
301 struct passwd *pw = getpwuid(st.st_uid);
302 struct group *gr = getgrgid(st.st_gid);
303 #ifdef UNICODE
304 msg->setFieldFromMBString(varId++, pw->pw_name);
305 msg->setFieldFromMBString(varId++, gr->gr_name);
306 #else
307 msg->setField(varId++, pw->pw_name);
308 msg->setField(varId++, gr->gr_name);
309 #endif
310 accessRights[1] = (S_IRUSR & st.st_mode) > 0 ? _T('r') : _T('-');
311 accessRights[2] = (S_IWUSR & st.st_mode) > 0 ? _T('w') : _T('-');
312 accessRights[3] = (S_IXUSR & st.st_mode) > 0 ? _T('x') : _T('-');
313 accessRights[4] = (S_IRGRP & st.st_mode) > 0 ? _T('r') : _T('-');
314 accessRights[5] = (S_IWGRP & st.st_mode) > 0 ? _T('w') : _T('-');
315 accessRights[6] = (S_IXGRP & st.st_mode) > 0 ? _T('x') : _T('-');
316 accessRights[7] = (S_IROTH & st.st_mode) > 0 ? _T('r') : _T('-');
317 accessRights[8] = (S_IWOTH & st.st_mode) > 0 ? _T('w') : _T('-');
318 accessRights[9] = (S_IXOTH & st.st_mode) > 0 ? _T('x') : _T('-');
319 accessRights[10] = 0;
320 msg->setField(varId++, accessRights);
321 #else
322 TCHAR *owner = GetFileOwnerWin(filePath);
323 msg->setField(varId++, owner);
324 safe_free(owner);
325 msg->setField(varId++, _T(""));
326 msg->setField(varId++, _T(""));
327 #endif // _WIN32
328 return true;
329 }
330 else
331 {
332 AgentWriteDebugLog(3, _T("FILEMGR: GetFolderContent: cannot get folder %s"), filePath);
333 return false;
334 }
335 }
336
337 /**
338 * Puts in response list of containing files
339 */
340 static void GetFolderContent(TCHAR *folder, NXCPMessage *response, bool rootFolder, bool allowMultipart, AbstractCommSession *session)
341 {
342 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" (root=%s, multipart=%s)"),
343 folder, rootFolder ? _T("true") : _T("false"), allowMultipart ? _T("true") : _T("false"));
344
345 NXCPMessage *msg;
346 if (allowMultipart)
347 {
348 msg = new NXCPMessage();
349 msg->setCode(CMD_REQUEST_COMPLETED);
350 msg->setId(response->getId());
351 msg->setField(VID_ALLOW_MULTIPART, (INT16)1);
352 }
353 else
354 {
355 msg = response;
356 }
357
358 UINT32 count = 0;
359 UINT32 fieldId = VID_INSTANCE_LIST_BASE;
360
361 if (!_tcscmp(folder, FS_PATH_SEPARATOR) && rootFolder)
362 {
363 response->setField(VID_RCC, ERR_SUCCESS);
364
365 for(int i = 0; i < g_rootFileManagerFolders->size(); i++)
366 {
367 if (FillMessageFolderContent(g_rootFileManagerFolders->get(i)->getFolder(), g_rootFileManagerFolders->get(i)->getFolder(), msg, fieldId))
368 {
369 count++;
370 fieldId += 10;
371 }
372 }
373 msg->setField(VID_INSTANCE_COUNT, count);
374 if (allowMultipart)
375 {
376 msg->setEndOfSequence();
377 msg->setField(VID_INSTANCE_COUNT, count);
378 session->sendMessage(msg);
379 delete msg;
380 }
381 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" completed"), folder);
382 return;
383 }
384
385 _TDIR *dir = _topendir(folder);
386 if (dir != NULL)
387 {
388 response->setField(VID_RCC, ERR_SUCCESS);
389
390 struct _tdirent *d;
391 while((d = _treaddir(dir)) != NULL)
392 {
393 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
394 continue;
395
396 TCHAR fullName[MAX_PATH];
397 _tcscpy(fullName, folder);
398 _tcscat(fullName, FS_PATH_SEPARATOR);
399 _tcscat(fullName, d->d_name);
400
401 if (FillMessageFolderContent(fullName, d->d_name, msg, fieldId))
402 {
403 count++;
404 fieldId += 10;
405 }
406 if (allowMultipart && (count == 64))
407 {
408 msg->setField(VID_INSTANCE_COUNT, count);
409 session->sendMessage(msg);
410 msg->deleteAllFields();
411 msg->setField(VID_ALLOW_MULTIPART, (INT16)1);
412 count = 0;
413 fieldId = VID_INSTANCE_LIST_BASE;
414 }
415 }
416 msg->setField(VID_INSTANCE_COUNT, count);
417 _tclosedir(dir);
418
419 if (allowMultipart)
420 {
421 msg->setEndOfSequence();
422 msg->setField(VID_INSTANCE_COUNT, count);
423 session->sendMessage(msg);
424 }
425 }
426 else
427 {
428 response->setField(VID_RCC, ERR_IO_FAILURE);
429 }
430
431 if (allowMultipart)
432 delete msg;
433
434 nxlog_debug(5, _T("FILEMGR: GetFolderContent: reading \"%s\" completed"), folder);
435 }
436
437 /**
438 * Delete file/folder
439 */
440 static BOOL Delete(const TCHAR *name)
441 {
442 NX_STAT_STRUCT st;
443
444 if (CALL_STAT(name, &st) != 0)
445 {
446 return FALSE;
447 }
448
449 bool result = true;
450
451 if (S_ISDIR(st.st_mode))
452 {
453 // get element list and for each element run Delete
454 _TDIR *dir = _topendir(name);
455 if (dir != NULL)
456 {
457 struct _tdirent *d;
458 while((d = _treaddir(dir)) != NULL)
459 {
460 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
461 {
462 continue;
463 }
464 TCHAR newName[MAX_PATH];
465 _tcscpy(newName, name);
466 _tcscat(newName, FS_PATH_SEPARATOR);
467 _tcscat(newName, d->d_name);
468 result = result && Delete(newName);
469 }
470 _tclosedir(dir);
471 }
472 //remove directory
473 #ifdef _WIN32
474 return RemoveDirectory(name);
475 #else
476 return _trmdir(name) == 0;
477 #endif
478 }
479 #ifdef _WIN32
480 return DeleteFile(name);
481 #else
482 return _tremove(name) == 0;
483 #endif
484 }
485
486 /**
487 * Rename file/folder
488 */
489 static BOOL Rename(TCHAR* oldName, TCHAR * newName)
490 {
491 if (_trename(oldName, newName) == 0)
492 {
493 return TRUE;
494 }
495 else
496 {
497 return FALSE;
498 }
499 }
500
501 #ifndef _WIN32
502
503 /**
504 * Copy file/folder
505 */
506 static BOOL CopyFile(NX_STAT_STRUCT *st, const TCHAR *oldName, const TCHAR *newName)
507 {
508 int oldFile = _topen(oldName, O_RDONLY | O_BINARY);
509 if (oldFile == -1)
510 return FALSE;
511
512 int newFile = _topen(newName, O_CREAT | O_BINARY | O_WRONLY, st->st_mode); // should be copied with the same acess rights
513 if (newFile == -1)
514 {
515 close(oldFile);
516 return FALSE;
517 }
518
519 int size = 16384, in, out;
520 BYTE *bytes = (BYTE *)malloc(size);
521
522 while((in = read(oldFile, bytes, size)) > 0)
523 {
524 out = write(newFile, bytes, (ssize_t)in);
525 if (out != in)
526 {
527 close(oldFile);
528 close(newFile);
529 free(bytes);
530 return FALSE;
531 }
532 }
533
534 close(oldFile);
535 close(newFile);
536 free(bytes);
537 return TRUE;
538 }
539
540 #endif
541
542 /**
543 * Move file/folder
544 */
545 static BOOL MoveFile(TCHAR* oldName, TCHAR* newName)
546 {
547 #ifdef _WIN32
548 return MoveFileEx(oldName, newName, MOVEFILE_COPY_ALLOWED);
549 #else
550 if (Rename(oldName, newName))
551 {
552 return TRUE;
553 }
554
555 NX_STAT_STRUCT st;
556
557 if (CALL_STAT(oldName, &st) != 0)
558 {
559 return FALSE;
560 }
561
562 if (S_ISDIR(st.st_mode))
563 {
564 _tmkdir(newName, st.st_mode);
565 _TDIR *dir = _topendir(oldName);
566 if (dir != NULL)
567 {
568 struct _tdirent *d;
569 while((d = _treaddir(dir)) != NULL)
570 {
571 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
572 {
573 continue;
574 }
575 TCHAR nextNewName[MAX_PATH];
576 _tcscpy(nextNewName, newName);
577 _tcscat(nextNewName, _T("/"));
578 _tcscat(nextNewName, d->d_name);
579
580 TCHAR nextOldaName[MAX_PATH];
581 _tcscpy(nextOldaName, oldName);
582 _tcscat(nextOldaName, _T("/"));
583 _tcscat(nextOldaName, d->d_name);
584
585 MoveFile(nextOldaName, nextNewName);
586 }
587 _tclosedir(dir);
588 }
589 _trmdir(oldName);
590 }
591 else
592 {
593 if (!CopyFile(&st, oldName, newName))
594 return FALSE;
595 }
596 return TRUE;
597 #endif /* _WIN32 */
598 }
599
600 /**
601 * Send file
602 */
603 THREAD_RESULT THREAD_CALL SendFile(void *dataStruct)
604 {
605 MessageData *data = (MessageData *)dataStruct;
606
607 AgentWriteDebugLog(5, _T("CommSession::getLocalFile(): request for file \"%s\", follow = %s, compress = %s"),
608 data->fileName, data->follow ? _T("true") : _T("false"), data->allowCompression ? _T("true") : _T("false"));
609 bool success = AgentSendFileToServer(data->session, data->id, data->fileName, (int)data->offset, data->allowCompression);
610 if (data->follow && success)
611 {
612 g_monitorFileList.add(data->fileNameCode);
613 FollowData *flData = new FollowData(data->fileName, data->fileNameCode, 0, data->session->getServerAddress());
614 ThreadCreateEx(SendFileUpdatesOverNXCP, 0, flData);
615 }
616 free(data->fileName);
617 free(data->fileNameCode);
618 delete data;
619 return THREAD_OK;
620 }
621
622 /**
623 * Get folder information
624 */
625 static void GetFolderInfo(const TCHAR *folder, UINT64 *fileCount, UINT64 *folderSize)
626 {
627 _TDIR *dir = _topendir(folder);
628 if (dir != NULL)
629 {
630 NX_STAT_STRUCT st;
631 struct _tdirent *d;
632 while((d = _treaddir(dir)) != NULL)
633 {
634 if (sizeof(folder) >= MAX_PATH)
635 return;
636
637 if (!_tcscmp(d->d_name, _T(".")) || !_tcscmp(d->d_name, _T("..")))
638 {
639 continue;
640 }
641
642 TCHAR fullName[MAX_PATH];
643 _tcscpy(fullName, folder);
644 _tcscat(fullName, FS_PATH_SEPARATOR);
645 _tcscat(fullName, d->d_name);
646
647 if (CALL_STAT(fullName, &st) == 0)
648 {
649 if (S_ISDIR(st.st_mode))
650 {
651 GetFolderInfo(fullName, fileCount, folderSize);
652 }
653 else
654 {
655 *folderSize += st.st_size;
656 (*fileCount)++;
657 }
658 }
659 }
660 _tclosedir(dir);
661 }
662 }
663
664 /**
665 * Process commands like get files in folder, delete file/folder, copy file/folder, move file/folder
666 */
667 static BOOL ProcessCommands(UINT32 command, NXCPMessage *request, NXCPMessage *response, AbstractCommSession *session)
668 {
669 switch(command)
670 {
671 case CMD_GET_FOLDER_SIZE:
672 {
673 TCHAR directory[MAX_PATH];
674 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
675 response->setId(request->getId());
676 if (directory[0] == 0)
677 {
678 response->setField(VID_RCC, ERR_IO_FAILURE);
679 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_SIZE): File name should be set."));
680 return TRUE;
681 }
682 ConvertPathToHost(directory);
683
684 if (CheckFullPath(directory, false) && session->isMasterServer())
685 {
686 UINT64 fileCount = 0, fileSize = 0;
687 GetFolderInfo(directory, &fileCount, &fileSize);
688 response->setField(VID_RCC, ERR_SUCCESS);
689 response->setField(VID_FOLDER_SIZE, fileSize);
690 response->setField(VID_FILE_COUNT, fileCount);
691 }
692 else
693 {
694 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_SIZE): Access denied"));
695 response->setField(VID_RCC, ERR_ACCESS_DENIED);
696 }
697
698 return TRUE;
699 }
700 case CMD_GET_FOLDER_CONTENT:
701 {
702 TCHAR directory[MAX_PATH];
703 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
704 response->setId(request->getId());
705 if (directory[0] == 0)
706 {
707 response->setField(VID_RCC, ERR_IO_FAILURE);
708 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_CONTENT): File name should be set."));
709 return TRUE;
710 }
711 ConvertPathToHost(directory);
712
713 bool rootFolder = request->getFieldAsUInt16(VID_ROOT) ? 1 : 0;
714 if (CheckFullPath(directory, rootFolder) && session->isMasterServer())
715 {
716 GetFolderContent(directory, response, rootFolder, request->getFieldAsBoolean(VID_ALLOW_MULTIPART), session);
717 }
718 else
719 {
720 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FOLDER_CONTENT): Access denied"));
721 response->setField(VID_RCC, ERR_ACCESS_DENIED);
722 }
723 return TRUE;
724 }
725 case CMD_FILEMGR_DELETE_FILE:
726 {
727 TCHAR file[MAX_PATH];
728 request->getFieldAsString(VID_FILE_NAME, file, MAX_PATH);
729 response->setId(request->getId());
730 if(file[0] == 0)
731 {
732 response->setField(VID_RCC, ERR_IO_FAILURE);
733 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_DELETE_FILE): File name should be set."));
734 return TRUE;
735 }
736 ConvertPathToHost(file);
737
738 if (CheckFullPath(file, false, true) && session->isMasterServer())
739 {
740 if (Delete(file))
741 {
742 response->setField(VID_RCC, ERR_SUCCESS);
743 }
744 else
745 {
746 response->setField(VID_RCC, ERR_IO_FAILURE);
747 }
748 }
749 else
750 {
751 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_DELETE_FILE): Access denied"));
752 response->setField(VID_RCC, ERR_ACCESS_DENIED);
753 }
754 return TRUE;
755 }
756 case CMD_FILEMGR_RENAME_FILE:
757 {
758 TCHAR oldName[MAX_PATH];
759 request->getFieldAsString(VID_FILE_NAME, oldName, MAX_PATH);
760 TCHAR newName[MAX_PATH];
761 request->getFieldAsString(VID_NEW_FILE_NAME, newName, MAX_PATH);
762 response->setId(request->getId());
763 if (oldName[0] == 0 && newName[0] == 0)
764 {
765 response->setField(VID_RCC, ERR_IO_FAILURE);
766 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_RENAME_FILE): File names should be set."));
767 return TRUE;
768 }
769 ConvertPathToHost(oldName);
770 ConvertPathToHost(newName);
771
772 if (CheckFullPath(oldName, false, true) && CheckFullPath(newName, false) && session->isMasterServer())
773 {
774 if (Rename(oldName, newName))
775 {
776 response->setField(VID_RCC, ERR_SUCCESS);
777 }
778 else
779 {
780 response->setField(VID_RCC, ERR_IO_FAILURE);
781 }
782 }
783 else
784 {
785 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_RENAME_FILE): Access denied"));
786 response->setField(VID_RCC, ERR_ACCESS_DENIED);
787 }
788 return TRUE;
789 }
790 case CMD_FILEMGR_MOVE_FILE:
791 {
792 TCHAR oldName[MAX_PATH];
793 request->getFieldAsString(VID_FILE_NAME, oldName, MAX_PATH);
794 TCHAR newName[MAX_PATH];
795 request->getFieldAsString(VID_NEW_FILE_NAME, newName, MAX_PATH);
796 response->setId(request->getId());
797 if ((oldName[0] == 0) && (newName[0] == 0))
798 {
799 response->setField(VID_RCC, ERR_IO_FAILURE);
800 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_MOVE_FILE): File names should be set."));
801 return TRUE;
802 }
803 ConvertPathToHost(oldName);
804 ConvertPathToHost(newName);
805
806 if (CheckFullPath(oldName, false, true) && CheckFullPath(newName, false) && session->isMasterServer())
807 {
808 if(MoveFile(oldName, newName))
809 {
810 response->setField(VID_RCC, ERR_SUCCESS);
811 }
812 else
813 {
814 response->setField(VID_RCC, ERR_IO_FAILURE);
815 }
816 }
817 else
818 {
819 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_MOVE_FILE): Access denied"));
820 response->setField(VID_RCC, ERR_ACCESS_DENIED);
821 }
822 return TRUE;
823 }
824 case CMD_FILEMGR_UPLOAD:
825 {
826 TCHAR name[MAX_PATH];
827 request->getFieldAsString(VID_FILE_NAME, name, MAX_PATH);
828 response->setId(request->getId());
829 if (name[0] == 0)
830 {
831 response->setField(VID_RCC, ERR_IO_FAILURE);
832 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_UPLOAD): File name should be set."));
833 return TRUE;
834 }
835 ConvertPathToHost(name);
836
837 if (CheckFullPath(name, false, true) && session->isMasterServer())
838 {
839 response->setField(VID_RCC, session->openFile(name, request->getId(), request->getFieldAsTime(VID_MODIFICATION_TIME)));
840 }
841 else
842 {
843 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_UPLOAD): Access denied"));
844 response->setField(VID_RCC, ERR_ACCESS_DENIED);
845 }
846 return TRUE;
847 }
848 case CMD_GET_FILE_DETAILS:
849 {
850 TCHAR fileName[MAX_PATH];
851 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
852 ExpandFileName(fileName, fileName, MAX_PATH, session->isMasterServer());
853 response->setId(request->getId());
854
855 if (session->isMasterServer() && CheckFullPath(fileName, false))
856 {
857 NX_STAT_STRUCT fs;
858
859 //prepare file name
860 if (CALL_STAT(fileName, &fs) == 0)
861 {
862 response->setField(VID_FILE_SIZE, (UINT64)fs.st_size);
863 response->setField(VID_MODIFICATION_TIME, (UINT64)fs.st_mtime);
864 response->setField(VID_RCC, ERR_SUCCESS);
865 }
866 else
867 {
868 response->setField(VID_RCC, ERR_FILE_STAT_FAILED);
869 }
870 }
871 else
872 {
873 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_GET_FILE_DETAILS): Access denied"));
874 response->setField(VID_RCC, ERR_ACCESS_DENIED);
875 }
876 return TRUE;
877 }
878 case CMD_GET_AGENT_FILE:
879 {
880 response->setId(request->getId());
881 TCHAR fileName[MAX_PATH];
882 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
883 ExpandFileName(fileName, fileName, MAX_PATH, session->isMasterServer());
884
885 if (CheckFullPath(fileName, false))
886 {
887 TCHAR *fileNameCode = (TCHAR*)malloc(MAX_PATH * sizeof(TCHAR));
888 request->getFieldAsString(VID_NAME, fileNameCode, MAX_PATH);
889
890 MessageData *data = new MessageData();
891 data->fileName = _tcsdup(fileName);
892 data->fileNameCode = fileNameCode;
893 data->follow = request->getFieldAsBoolean(VID_FILE_FOLLOW);
894 data->allowCompression = request->getFieldAsBoolean(VID_ENABLE_COMPRESSION);
895 data->id = request->getId();
896 data->offset = request->getFieldAsUInt32(VID_FILE_OFFSET);
897 data->session = session;
898
899 ThreadCreateEx(SendFile, 0, data);
900
901 response->setField(VID_RCC, ERR_SUCCESS);
902 }
903 else
904 {
905 response->setField(VID_RCC, ERR_ACCESS_DENIED);
906 }
907 return TRUE;
908 }
909 case CMD_CANCEL_FILE_MONITORING:
910 {
911 response->setId(request->getId());
912 TCHAR fileName[MAX_PATH];
913 request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
914 if (g_monitorFileList.remove(fileName))
915 {
916 response->setField(VID_RCC, ERR_SUCCESS);
917 }
918 else
919 {
920 response->setField(VID_RCC, ERR_BAD_ARGUMENTS);
921 }
922 return TRUE;
923 }
924 case CMD_FILEMGR_CREATE_FOLDER:
925 {
926 TCHAR directory[MAX_PATH];
927 request->getFieldAsString(VID_FILE_NAME, directory, MAX_PATH);
928 response->setId(request->getId());
929 if (directory[0] == 0)
930 {
931 response->setField(VID_RCC, ERR_IO_FAILURE);
932 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): File name should be set."));
933 return TRUE;
934 }
935 ConvertPathToHost(directory);
936
937 if (CheckFullPath(directory, false, true) && session->isMasterServer())
938 {
939 if (CreateFolder(directory))
940 {
941 response->setField(VID_RCC, ERR_SUCCESS);
942 }
943 else
944 {
945 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): Could not create directory"));
946 response->setField(VID_RCC, ERR_IO_FAILURE);
947 }
948 }
949 else
950 {
951 AgentWriteDebugLog(6, _T("FILEMGR: ProcessCommands(CMD_FILEMGR_CREATE_FOLDER): Access denied"));
952 response->setField(VID_RCC, ERR_ACCESS_DENIED);
953 }
954 return TRUE;
955 }
956 default:
957 return FALSE;
958 }
959 }
960
961 /**
962 * Subagent information
963 */
964 static NETXMS_SUBAGENT_INFO m_info =
965 {
966 NETXMS_SUBAGENT_INFO_MAGIC,
967 _T("FILEMGR"), NETXMS_BUILD_TAG,
968 SubagentInit, SubagentShutdown, ProcessCommands,
969 0, NULL, // parameters
970 0, NULL, // lists
971 0, NULL, // tables
972 0, NULL, // actions
973 0, NULL // push parameters
974 };
975
976 /**
977 * Entry point for NetXMS agent
978 */
979 DECLARE_SUBAGENT_ENTRY_POINT(FILEMGR)
980 {
981 *ppInfo = &m_info;
982 return TRUE;
983 }
984
985 #ifdef _WIN32
986
987 /**
988 * DLL entry point
989 */
990 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
991 {
992 if (dwReason == DLL_PROCESS_ATTACH)
993 DisableThreadLibraryCalls(hInstance);
994 return TRUE;
995 }
996
997 #endif