557731c50589efe5a47a1b6290ba9248ef782c23
[public/netxms.git] / src / server / core / session.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2015 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 ** File: session.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <netxms_mt.h>
25 #include <nxtools.h>
26 #include <nxstat.h>
27
28 #ifdef _WIN32
29 #include <psapi.h>
30 #define write _write
31 #define close _close
32 #else
33 #include <dirent.h>
34 #endif
35
36 #ifdef WITH_ZMQ
37 #include "zeromq.h"
38 #endif
39
40 #ifndef min
41 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #endif
43
44 // WARNING! this hack works only for d2i_X509(); be carefull when adding new code
45 #ifdef OPENSSL_CONST
46 # undef OPENSSL_CONST
47 #endif
48 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
49 # define OPENSSL_CONST const
50 #else
51 # define OPENSSL_CONST
52 #endif
53
54 /**
55 * Constants
56 */
57 #define TRAP_CREATE 1
58 #define TRAP_UPDATE 2
59 #define TRAP_DELETE 3
60
61 #define MAX_MSG_SIZE 4194304
62
63 /**
64 * Externals
65 */
66 extern Queue g_nodePollerQueue;
67 extern Queue g_dataCollectionQueue;
68 extern Queue g_dciCacheLoaderQueue;
69
70 void UnregisterClientSession(int id);
71 void ResetDiscoveryPoller();
72 NXCPMessage *ForwardMessageToReportingServer(NXCPMessage *request, ClientSession *session);
73 void RemovePendingFileTransferRequests(ClientSession *session);
74
75 /**
76 * Node poller start data
77 */
78 typedef struct
79 {
80 ClientSession *pSession;
81 Node *pNode;
82 int iPollType;
83 UINT32 dwRqId;
84 } POLLER_START_DATA;
85
86 /**
87 * Additional processing thread start data
88 */
89 typedef struct
90 {
91 ClientSession *pSession;
92 NXCPMessage *pMsg;
93 } PROCTHREAD_START_DATA;
94
95 /**
96 *
97 */
98 typedef struct
99 {
100 uuid_t *guid;
101 bool removed;
102 } LIBRARY_IMAGE_UPDATE_INFO;
103
104 /**
105 * Callback to delete agent connections for loading files in distructor
106 */
107 static void DeleteCallback(NetObj* obj, void *data)
108 {
109 delete (AgentConnection *)obj;
110 }
111
112 /**
113 * Callback for sending image library update notifications
114 */
115 static void ImageLibraryUpdateCallback(ClientSession *pSession, void *pArg)
116 {
117 pSession->onLibraryImageChange((uuid_t *)pArg, false);
118 }
119
120 /**
121 * Callback for sending image library delete notifications
122 */
123 static void ImageLibraryDeleteCallback(ClientSession *pSession, void *pArg)
124 {
125 pSession->onLibraryImageChange((uuid_t *)pArg, true);
126 }
127
128 /**
129 * Additional message processing thread starters
130 */
131 #define CALL_IN_NEW_THREAD(func, msg) \
132 { \
133 PROCTHREAD_START_DATA *pData = (PROCTHREAD_START_DATA *)malloc(sizeof(PROCTHREAD_START_DATA)); \
134 pData->pSession = this; \
135 pData->pMsg = msg; \
136 msg = NULL; /* prevent deletion by main processing thread*/ \
137 m_dwRefCount++; \
138 ThreadPoolExecute(g_mainThreadPool, ThreadStarter_##func, pData); \
139 }
140
141 #define DEFINE_THREAD_STARTER(func) \
142 void ClientSession::ThreadStarter_##func(void *pArg) \
143 { \
144 ((PROCTHREAD_START_DATA *)pArg)->pSession->debugPrintf(6, _T("Method ") _T(#func) _T(" called on background thread")); \
145 ((PROCTHREAD_START_DATA *)pArg)->pSession->func(((PROCTHREAD_START_DATA *)pArg)->pMsg); \
146 ((PROCTHREAD_START_DATA *)pArg)->pSession->m_dwRefCount--; \
147 delete ((PROCTHREAD_START_DATA *)pArg)->pMsg; \
148 free(pArg); \
149 }
150
151 DEFINE_THREAD_STARTER(cancelFileMonitoring)
152 DEFINE_THREAD_STARTER(clearDCIData)
153 DEFINE_THREAD_STARTER(createObject)
154 DEFINE_THREAD_STARTER(executeAction)
155 DEFINE_THREAD_STARTER(executeScript)
156 DEFINE_THREAD_STARTER(fileManagerControl)
157 DEFINE_THREAD_STARTER(findIpAddress)
158 DEFINE_THREAD_STARTER(findMacAddress)
159 DEFINE_THREAD_STARTER(findNodeConnection)
160 DEFINE_THREAD_STARTER(forceDCIPoll)
161 DEFINE_THREAD_STARTER(forwardToReportingServer)
162 DEFINE_THREAD_STARTER(getAgentFile)
163 DEFINE_THREAD_STARTER(getAlarmEvents)
164 DEFINE_THREAD_STARTER(getCollectedData)
165 DEFINE_THREAD_STARTER(getLocationHistory)
166 DEFINE_THREAD_STARTER(getNetworkPath)
167 DEFINE_THREAD_STARTER(getRoutingTable)
168 DEFINE_THREAD_STARTER(getServerFile)
169 DEFINE_THREAD_STARTER(getServerLogQueryData)
170 DEFINE_THREAD_STARTER(getSwitchForwardingDatabase)
171 DEFINE_THREAD_STARTER(getTableCollectedData)
172 DEFINE_THREAD_STARTER(importConfiguration)
173 DEFINE_THREAD_STARTER(openHelpdeskIssue)
174 DEFINE_THREAD_STARTER(processConsoleCommand)
175 DEFINE_THREAD_STARTER(queryAgentTable)
176 DEFINE_THREAD_STARTER(queryL2Topology)
177 DEFINE_THREAD_STARTER(queryParameter)
178 DEFINE_THREAD_STARTER(queryServerLog)
179 DEFINE_THREAD_STARTER(sendEventLog)
180 DEFINE_THREAD_STARTER(sendMib)
181 DEFINE_THREAD_STARTER(sendSyslog)
182 DEFINE_THREAD_STARTER(uploadUserFileToAgent)
183
184 /**
185 * Client communication read thread starter
186 */
187 THREAD_RESULT THREAD_CALL ClientSession::readThreadStarter(void *pArg)
188 {
189 ((ClientSession *)pArg)->readThread();
190
191 // When ClientSession::ReadThread exits, all other session
192 // threads are already stopped, so we can safely destroy
193 // session object
194 UnregisterClientSession(((ClientSession *)pArg)->getId());
195 delete (ClientSession *)pArg;
196 return THREAD_OK;
197 }
198
199 /**
200 * Client communication write thread starter
201 */
202 THREAD_RESULT THREAD_CALL ClientSession::writeThreadStarter(void *pArg)
203 {
204 ((ClientSession *)pArg)->writeThread();
205 return THREAD_OK;
206 }
207
208 /**
209 * Received message processing thread starter
210 */
211 THREAD_RESULT THREAD_CALL ClientSession::processingThreadStarter(void *pArg)
212 {
213 ((ClientSession *)pArg)->processingThread();
214 return THREAD_OK;
215 }
216
217 /**
218 * Information update processing thread starter
219 */
220 THREAD_RESULT THREAD_CALL ClientSession::updateThreadStarter(void *pArg)
221 {
222 ((ClientSession *)pArg)->updateThread();
223 return THREAD_OK;
224 }
225
226 /**
227 * Client session class constructor
228 */
229 ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr)
230 {
231 m_pSendQueue = new Queue;
232 m_pMessageQueue = new Queue;
233 m_pUpdateQueue = new Queue;
234 m_hSocket = hSocket;
235 m_id = -1;
236 m_state = SESSION_STATE_INIT;
237 m_pCtx = NULL;
238 m_hWriteThread = INVALID_THREAD_HANDLE;
239 m_hProcessingThread = INVALID_THREAD_HANDLE;
240 m_hUpdateThread = INVALID_THREAD_HANDLE;
241 m_mutexSocketWrite = MutexCreate();
242 m_mutexSendEvents = MutexCreate();
243 m_mutexSendSyslog = MutexCreate();
244 m_mutexSendTrapLog = MutexCreate();
245 m_mutexSendObjects = MutexCreate();
246 m_mutexSendAlarms = MutexCreate();
247 m_mutexSendActions = MutexCreate();
248 m_mutexSendAuditLog = MutexCreate();
249 m_mutexSendSituations = MutexCreate();
250 m_mutexPollerInit = MutexCreate();
251 m_dwFlags = 0;
252 m_clientType = CLIENT_TYPE_DESKTOP;
253 m_clientAddr = (struct sockaddr *)nx_memdup(addr, (addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
254 if (addr->sa_family == AF_INET)
255 IpToStr(ntohl(((struct sockaddr_in *)m_clientAddr)->sin_addr.s_addr), m_workstation);
256 #ifdef WITH_IPV6
257 else
258 Ip6ToStr(((struct sockaddr_in6 *)m_clientAddr)->sin6_addr.s6_addr, m_workstation);
259 #endif
260 m_webServerAddress[0] = 0;
261 m_loginName[0] = 0;
262 _tcscpy(m_sessionName, _T("<not logged in>"));
263 _tcscpy(m_clientInfo, _T("n/a"));
264 m_dwUserId = INVALID_INDEX;
265 m_dwOpenDCIListSize = 0;
266 m_pOpenDCIList = NULL;
267 m_ppEPPRuleList = NULL;
268 m_hCurrFile = -1;
269 m_dwFileRqId = 0;
270 m_dwRefCount = 0;
271 m_dwEncryptionRqId = 0;
272 m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
273 m_dwActiveChannels = 0;
274 m_console = NULL;
275 m_loginTime = time(NULL);
276 m_musicTypeList.add(_T("wav"));
277 _tcscpy(m_language, _T("en"));
278 }
279
280 /**
281 * Destructor
282 */
283 ClientSession::~ClientSession()
284 {
285 if (m_hSocket != -1)
286 closesocket(m_hSocket);
287 delete m_pSendQueue;
288 delete m_pMessageQueue;
289 delete m_pUpdateQueue;
290 safe_free(m_clientAddr);
291 MutexDestroy(m_mutexSocketWrite);
292 MutexDestroy(m_mutexSendEvents);
293 MutexDestroy(m_mutexSendSyslog);
294 MutexDestroy(m_mutexSendTrapLog);
295 MutexDestroy(m_mutexSendObjects);
296 MutexDestroy(m_mutexSendAlarms);
297 MutexDestroy(m_mutexSendActions);
298 MutexDestroy(m_mutexSendAuditLog);
299 MutexDestroy(m_mutexSendSituations);
300 MutexDestroy(m_mutexPollerInit);
301 safe_free(m_pOpenDCIList);
302 if (m_ppEPPRuleList != NULL)
303 {
304 UINT32 i;
305
306 if (m_dwFlags & CSF_EPP_UPLOAD) // Aborted in the middle of EPP transfer
307 for(i = 0; i < m_dwRecordsUploaded; i++)
308 delete m_ppEPPRuleList[i];
309 free(m_ppEPPRuleList);
310 }
311 if (m_pCtx != NULL)
312 m_pCtx->decRefCount();
313 if (m_condEncryptionSetup != INVALID_CONDITION_HANDLE)
314 ConditionDestroy(m_condEncryptionSetup);
315
316 if (m_console != NULL)
317 {
318 delete m_console->pMsg;
319 free(m_console);
320 }
321 m_musicTypeList.clear();
322 if (m_agentConn.size() > 0)
323 {
324 m_agentConn.forEach(&DeleteCallback, NULL);
325 }
326 }
327
328 /**
329 * Start all threads
330 */
331 void ClientSession::run()
332 {
333 m_hWriteThread = ThreadCreateEx(writeThreadStarter, 0, this);
334 m_hProcessingThread = ThreadCreateEx(processingThreadStarter, 0, this);
335 m_hUpdateThread = ThreadCreateEx(updateThreadStarter, 0, this);
336 ThreadCreate(readThreadStarter, 0, this);
337 }
338
339 /**
340 * Print debug information
341 */
342 void ClientSession::debugPrintf(int level, const TCHAR *format, ...)
343 {
344 if (level <= (int)g_debugLevel)
345 {
346 va_list args;
347 TCHAR buffer[8192];
348
349 va_start(args, format);
350 _vsntprintf(buffer, 8192, format, args);
351 va_end(args);
352 DbgPrintf(level, _T("[CLSN-%d] %s"), m_id, buffer);
353 }
354 }
355
356 /**
357 * Read thread
358 */
359 void ClientSession::readThread()
360 {
361 TCHAR szBuffer[256];
362 UINT32 i;
363 NetObj *object;
364
365 SocketMessageReceiver receiver(m_hSocket, 4096, MAX_MSG_SIZE);
366 while(true)
367 {
368 MessageReceiverResult result;
369 NXCPMessage *msg = receiver.readMessage(900000, &result);
370
371 // Check for decryption error
372 if (result == MSGRECV_DECRYPTION_FAILURE)
373 {
374 debugPrintf(4, _T("readThread: Unable to decrypt received message"));
375 continue;
376 }
377
378 // Receive error
379 if (msg == NULL)
380 {
381 debugPrintf(5, _T("readThread: message receiving error (%s)"), AbstractMessageReceiver::resultToText(result));
382 break;
383 }
384
385 if (g_debugLevel >= 8)
386 {
387 String msgDump = NXCPMessage::dump(receiver.getRawMessageBuffer(), NXCP_VERSION);
388 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
389 }
390
391 // Special handling for raw messages
392 if (msg->isBinary())
393 {
394 debugPrintf(6, _T("Received raw message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
395
396 if ((msg->getCode() == CMD_FILE_DATA) ||
397 (msg->getCode() == CMD_ABORT_FILE_TRANSFER))
398 {
399 if ((m_hCurrFile != -1) && (m_dwFileRqId == msg->getId()))
400 {
401 if (msg->getCode() == CMD_FILE_DATA)
402 {
403 if (write(m_hCurrFile, msg->getBinaryData(), (int)msg->getBinaryDataSize()) == (int)msg->getBinaryDataSize())
404 {
405 if (msg->isEndOfFile())
406 {
407 debugPrintf(6, _T("Got end of file marker"));
408 NXCPMessage response;
409
410 close(m_hCurrFile);
411 m_hCurrFile = -1;
412
413 response.setCode(CMD_REQUEST_COMPLETED);
414 response.setId(msg->getId());
415 response.setField(VID_RCC, RCC_SUCCESS);
416 sendMessage(&response);
417
418 onFileUpload(TRUE);
419 }
420 }
421 else
422 {
423 debugPrintf(6, _T("I/O error"));
424 // I/O error
425 NXCPMessage response;
426
427 close(m_hCurrFile);
428 m_hCurrFile = -1;
429
430 response.setCode(CMD_REQUEST_COMPLETED);
431 response.setId(msg->getId());
432 response.setField(VID_RCC, RCC_IO_ERROR);
433 sendMessage(&response);
434
435 onFileUpload(FALSE);
436 }
437 }
438 else
439 {
440 // Abort current file transfer because of client's problem
441 close(m_hCurrFile);
442 m_hCurrFile = -1;
443
444 onFileUpload(FALSE);
445 }
446 }
447 else
448 {
449 AgentConnection *conn = (AgentConnection *)m_agentConn.get(msg->getId());
450 if (conn != NULL)
451 {
452 if (msg->getCode() == CMD_FILE_DATA)
453 {
454 if (conn->sendMessage(msg)) //send raw message
455 {
456 if (msg->isEndOfFile())
457 {
458 debugPrintf(6, _T("Got end of file marker"));
459 //get response with specific ID if ok< then send ok, else send error
460 m_agentConn.remove(msg->getId());
461 delete conn;
462
463 NXCPMessage response;
464 response.setCode(CMD_REQUEST_COMPLETED);
465 response.setId(msg->getId());
466 response.setField(VID_RCC, RCC_SUCCESS);
467 sendMessage(&response);
468 }
469 }
470 else
471 {
472 debugPrintf(6, _T("Error while sending to agent"));
473 // I/O error
474 m_agentConn.remove(msg->getId());
475 delete conn;
476
477 NXCPMessage response;
478 response.setCode(CMD_REQUEST_COMPLETED);
479 response.setId(msg->getId());
480 response.setField(VID_RCC, RCC_IO_ERROR); //set result that came from agent
481 sendMessage(&response);
482 }
483 }
484 else
485 {
486 // Resend abort message
487 conn->sendMessage(msg);
488 m_agentConn.remove(msg->getId());
489 delete conn;
490 }
491 }
492 else
493 {
494 debugPrintf(4, _T("Out of state message (ID: %d)"), msg->getId());
495 }
496 }
497 }
498 delete msg;
499 }
500 else
501 {
502 if ((msg->getCode() == CMD_SESSION_KEY) && (msg->getId() == m_dwEncryptionRqId))
503 {
504 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
505 m_dwEncryptionResult = SetupEncryptionContext(msg, &m_pCtx, NULL, g_pServerKey, NXCP_VERSION);
506 receiver.setEncryptionContext(m_pCtx);
507 ConditionSet(m_condEncryptionSetup);
508 m_dwEncryptionRqId = 0;
509 delete msg;
510 }
511 else if (msg->getCode() == CMD_KEEPALIVE)
512 {
513 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
514 respondToKeepalive(msg->getId());
515 delete msg;
516 }
517 else
518 {
519 m_pMessageQueue->put(msg);
520 }
521 }
522 }
523
524 // Mark as terminated (sendMessage calls will not work after that point)
525 m_dwFlags |= CSF_TERMINATED;
526
527 // Finish update thread first
528 m_pUpdateQueue->put(INVALID_POINTER_VALUE);
529 ThreadJoin(m_hUpdateThread);
530
531 // Notify other threads to exit
532 NXCP_MESSAGE *rawMsg;
533 while((rawMsg = (NXCP_MESSAGE *)m_pSendQueue->get()) != NULL)
534 free(rawMsg);
535 m_pSendQueue->put(INVALID_POINTER_VALUE);
536
537 NXCPMessage *msg;
538 while((msg = (NXCPMessage *)m_pMessageQueue->get()) != NULL)
539 delete msg;
540 m_pMessageQueue->put(INVALID_POINTER_VALUE);
541
542 // Wait for other threads to finish
543 ThreadJoin(m_hWriteThread);
544 ThreadJoin(m_hProcessingThread);
545
546 // Abort current file upload operation, if any
547 if (m_hCurrFile != -1)
548 {
549 close(m_hCurrFile);
550 m_hCurrFile = -1;
551 onFileUpload(FALSE);
552 }
553
554 // remove all pending file transfers from reporting server
555 RemovePendingFileTransferRequests(this);
556
557 // Remove all locks created by this session
558 RemoveAllSessionLocks(m_id);
559 for(i = 0; i < m_dwOpenDCIListSize; i++)
560 {
561 object = FindObjectById(m_pOpenDCIList[i]);
562 if (object != NULL)
563 if ((object->getObjectClass() == OBJECT_NODE) ||
564 (object->getObjectClass() == OBJECT_CLUSTER) ||
565 (object->getObjectClass() == OBJECT_TEMPLATE))
566 ((Template *)object)->unlockDCIList(m_id);
567 }
568
569 // Waiting while reference count becomes 0
570 if (m_dwRefCount > 0)
571 {
572 debugPrintf(3, _T("Waiting for pending requests..."));
573 do
574 {
575 ThreadSleep(1);
576 } while(m_dwRefCount > 0);
577 }
578
579 if (m_dwFlags & CSF_AUTHENTICATED)
580 {
581 CALL_ALL_MODULES(pfClientSessionClose, (this));
582 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("User logged out (client: %s)"), m_clientInfo);
583 }
584 debugPrintf(3, _T("Session closed"));
585 }
586
587 /**
588 * Network write thread
589 */
590 void ClientSession::writeThread()
591 {
592 while(true)
593 {
594 NXCP_MESSAGE *rawMsg = (NXCP_MESSAGE *)m_pSendQueue->getOrBlock();
595 if (rawMsg == INVALID_POINTER_VALUE) // Session termination indicator
596 break;
597
598 sendRawMessage(rawMsg);
599 free(rawMsg);
600 }
601 }
602
603 /**
604 * Update processing thread
605 */
606 void ClientSession::updateThread()
607 {
608 UPDATE_INFO *pUpdate;
609 NXCPMessage msg;
610
611 while(1)
612 {
613 pUpdate = (UPDATE_INFO *)m_pUpdateQueue->getOrBlock();
614 if (pUpdate == INVALID_POINTER_VALUE) // Session termination indicator
615 break;
616
617 switch(pUpdate->dwCategory)
618 {
619 case INFO_CAT_EVENT:
620 MutexLock(m_mutexSendEvents);
621 sendMessage((NXCPMessage *)pUpdate->pData);
622 MutexUnlock(m_mutexSendEvents);
623 delete (NXCPMessage *)pUpdate->pData;
624 break;
625 case INFO_CAT_SYSLOG_MSG:
626 MutexLock(m_mutexSendSyslog);
627 msg.setCode(CMD_SYSLOG_RECORDS);
628 CreateMessageFromSyslogMsg(&msg, (NX_SYSLOG_RECORD *)pUpdate->pData);
629 sendMessage(&msg);
630 MutexUnlock(m_mutexSendSyslog);
631 free(pUpdate->pData);
632 break;
633 case INFO_CAT_SNMP_TRAP:
634 MutexLock(m_mutexSendTrapLog);
635 sendMessage((NXCPMessage *)pUpdate->pData);
636 MutexUnlock(m_mutexSendTrapLog);
637 delete (NXCPMessage *)pUpdate->pData;
638 break;
639 case INFO_CAT_AUDIT_RECORD:
640 MutexLock(m_mutexSendAuditLog);
641 sendMessage((NXCPMessage *)pUpdate->pData);
642 MutexUnlock(m_mutexSendAuditLog);
643 delete (NXCPMessage *)pUpdate->pData;
644 break;
645 case INFO_CAT_OBJECT_CHANGE:
646 MutexLock(m_mutexSendObjects);
647 msg.setCode(CMD_OBJECT_UPDATE);
648 if (!((NetObj *)pUpdate->pData)->isDeleted())
649 {
650 ((NetObj *)pUpdate->pData)->fillMessage(&msg);
651 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
652 ((NetObj *)pUpdate->pData)->commentsToMessage(&msg);
653 }
654 else
655 {
656 msg.setField(VID_OBJECT_ID, ((NetObj *)pUpdate->pData)->getId());
657 msg.setField(VID_IS_DELETED, (WORD)1);
658 }
659 sendMessage(&msg);
660 MutexUnlock(m_mutexSendObjects);
661 msg.deleteAllFields();
662 ((NetObj *)pUpdate->pData)->decRefCount();
663 break;
664 case INFO_CAT_ALARM:
665 MutexLock(m_mutexSendAlarms);
666 msg.setCode(CMD_ALARM_UPDATE);
667 msg.setField(VID_NOTIFICATION_CODE, pUpdate->dwCode);
668 FillAlarmInfoMessage(&msg, (NXC_ALARM *)pUpdate->pData);
669 sendMessage(&msg);
670 MutexUnlock(m_mutexSendAlarms);
671 msg.deleteAllFields();
672 free(pUpdate->pData);
673 break;
674 case INFO_CAT_ACTION:
675 MutexLock(m_mutexSendActions);
676 msg.setCode(CMD_ACTION_DB_UPDATE);
677 msg.setField(VID_NOTIFICATION_CODE, pUpdate->dwCode);
678 msg.setField(VID_ACTION_ID, ((NXC_ACTION *)pUpdate->pData)->dwId);
679 if (pUpdate->dwCode != NX_NOTIFY_ACTION_DELETED)
680 FillActionInfoMessage(&msg, (NXC_ACTION *)pUpdate->pData);
681 sendMessage(&msg);
682 MutexUnlock(m_mutexSendActions);
683 msg.deleteAllFields();
684 free(pUpdate->pData);
685 break;
686 case INFO_CAT_SITUATION:
687 MutexLock(m_mutexSendSituations);
688 sendMessage((NXCPMessage *)pUpdate->pData);
689 MutexUnlock(m_mutexSendSituations);
690 delete (NXCPMessage *)pUpdate->pData;
691 break;
692 case INFO_CAT_LIBRARY_IMAGE:
693 {
694 LIBRARY_IMAGE_UPDATE_INFO *info = (LIBRARY_IMAGE_UPDATE_INFO *)pUpdate->pData;
695 msg.setCode(CMD_IMAGE_LIBRARY_UPDATE);
696 msg.setField(VID_GUID, (BYTE *)info->guid, UUID_LENGTH);
697 if (info->removed)
698 {
699 msg.setField(VID_FLAGS, (UINT32)1);
700 }
701 else
702 {
703 msg.setField(VID_FLAGS, (UINT32)0);
704 }
705 sendMessage(&msg);
706 msg.deleteAllFields();
707 free(info->guid);
708 free(info);
709 }
710 break;
711 default:
712 break;
713 }
714
715 free(pUpdate);
716 }
717 }
718
719 /**
720 * Message processing thread
721 */
722 void ClientSession::processingThread()
723 {
724 NXCPMessage *pMsg;
725 TCHAR szBuffer[128];
726 UINT32 i;
727 int status;
728
729 while(1)
730 {
731 pMsg = (NXCPMessage *)m_pMessageQueue->getOrBlock();
732 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
733 break;
734
735 m_wCurrentCmd = pMsg->getCode();
736 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(m_wCurrentCmd, szBuffer));
737 if (!(m_dwFlags & CSF_AUTHENTICATED) &&
738 (m_wCurrentCmd != CMD_LOGIN) &&
739 (m_wCurrentCmd != CMD_GET_SERVER_INFO) &&
740 (m_wCurrentCmd != CMD_REQUEST_ENCRYPTION) &&
741 (m_wCurrentCmd != CMD_GET_MY_CONFIG) &&
742 (m_wCurrentCmd != CMD_REGISTER_AGENT))
743 {
744 delete pMsg;
745 continue;
746 }
747
748 m_state = SESSION_STATE_PROCESSING;
749 switch(m_wCurrentCmd)
750 {
751 case CMD_LOGIN:
752 login(pMsg);
753 break;
754 case CMD_GET_SERVER_INFO:
755 sendServerInfo(pMsg->getId());
756 break;
757 case CMD_GET_MY_CONFIG:
758 sendConfigForAgent(pMsg);
759 break;
760 case CMD_GET_OBJECTS:
761 sendAllObjects(pMsg);
762 break;
763 case CMD_GET_SELECTED_OBJECTS:
764 sendSelectedObjects(pMsg);
765 break;
766 case CMD_GET_EVENTS:
767 CALL_IN_NEW_THREAD(sendEventLog, pMsg);
768 break;
769 case CMD_GET_CONFIG_VARLIST:
770 getConfigurationVariables(pMsg->getId());
771 break;
772 case CMD_GET_PUBLIC_CONFIG_VAR:
773 getPublicConfigurationVariable(pMsg);
774 break;
775 case CMD_SET_CONFIG_VARIABLE:
776 setConfigurationVariable(pMsg);
777 break;
778 case CMD_DELETE_CONFIG_VARIABLE:
779 deleteConfigurationVariable(pMsg);
780 break;
781 case CMD_CONFIG_GET_CLOB:
782 getConfigCLOB(pMsg);
783 break;
784 case CMD_CONFIG_SET_CLOB:
785 setConfigCLOB(pMsg);
786 break;
787 case CMD_LOAD_EVENT_DB:
788 sendEventDB(pMsg->getId());
789 break;
790 case CMD_SET_EVENT_INFO:
791 modifyEventTemplate(pMsg);
792 break;
793 case CMD_DELETE_EVENT_TEMPLATE:
794 deleteEventTemplate(pMsg);
795 break;
796 case CMD_GENERATE_EVENT_CODE:
797 generateEventCode(pMsg->getId());
798 break;
799 case CMD_MODIFY_OBJECT:
800 modifyObject(pMsg);
801 break;
802 case CMD_SET_OBJECT_MGMT_STATUS:
803 changeObjectMgmtStatus(pMsg);
804 break;
805 case CMD_ENTER_MAINT_MODE:
806 enterMaintenanceMode(pMsg);
807 break;
808 case CMD_LEAVE_MAINT_MODE:
809 leaveMaintenanceMode(pMsg);
810 break;
811 case CMD_LOAD_USER_DB:
812 sendUserDB(pMsg->getId());
813 break;
814 case CMD_CREATE_USER:
815 createUser(pMsg);
816 break;
817 case CMD_UPDATE_USER:
818 updateUser(pMsg);
819 break;
820 case CMD_DETACH_LDAP_USER:
821 detachLdapUser(pMsg);
822 break;
823 case CMD_DELETE_USER:
824 deleteUser(pMsg);
825 break;
826 case CMD_LOCK_USER_DB:
827 lockUserDB(pMsg->getId(), TRUE);
828 break;
829 case CMD_UNLOCK_USER_DB:
830 lockUserDB(pMsg->getId(), FALSE);
831 break;
832 case CMD_SET_PASSWORD:
833 setPassword(pMsg);
834 break;
835 case CMD_VALIDATE_PASSWORD:
836 validatePassword(pMsg);
837 break;
838 case CMD_GET_NODE_DCI_LIST:
839 openNodeDCIList(pMsg);
840 break;
841 case CMD_UNLOCK_NODE_DCI_LIST:
842 closeNodeDCIList(pMsg);
843 break;
844 case CMD_CREATE_NEW_DCI:
845 case CMD_MODIFY_NODE_DCI:
846 case CMD_DELETE_NODE_DCI:
847 modifyNodeDCI(pMsg);
848 break;
849 case CMD_SET_DCI_STATUS:
850 changeDCIStatus(pMsg);
851 break;
852 case CMD_COPY_DCI:
853 copyDCI(pMsg);
854 break;
855 case CMD_APPLY_TEMPLATE:
856 applyTemplate(pMsg);
857 break;
858 case CMD_GET_DCI_DATA:
859 CALL_IN_NEW_THREAD(getCollectedData, pMsg);
860 break;
861 case CMD_GET_TABLE_DCI_DATA:
862 CALL_IN_NEW_THREAD(getTableCollectedData, pMsg);
863 break;
864 case CMD_CLEAR_DCI_DATA:
865 CALL_IN_NEW_THREAD(clearDCIData, pMsg);
866 break;
867 case CMD_FORCE_DCI_POLL:
868 CALL_IN_NEW_THREAD(forceDCIPoll, pMsg);
869 break;
870 case CMD_OPEN_EPP:
871 openEPP(pMsg);
872 break;
873 case CMD_CLOSE_EPP:
874 closeEPP(pMsg->getId());
875 break;
876 case CMD_SAVE_EPP:
877 saveEPP(pMsg);
878 break;
879 case CMD_EPP_RECORD:
880 processEPPRecord(pMsg);
881 break;
882 case CMD_GET_MIB_TIMESTAMP:
883 sendMIBTimestamp(pMsg->getId());
884 break;
885 case CMD_GET_MIB:
886 CALL_IN_NEW_THREAD(sendMib, pMsg);
887 break;
888 case CMD_CREATE_OBJECT:
889 CALL_IN_NEW_THREAD(createObject, pMsg);
890 break;
891 case CMD_BIND_OBJECT:
892 changeObjectBinding(pMsg, TRUE);
893 break;
894 case CMD_UNBIND_OBJECT:
895 changeObjectBinding(pMsg, FALSE);
896 break;
897 case CMD_ADD_CLUSTER_NODE:
898 addClusterNode(pMsg);
899 break;
900 case CMD_GET_ALL_ALARMS:
901 sendAllAlarms(pMsg->getId());
902 break;
903 case CMD_GET_ALARM_COMMENTS:
904 getAlarmComments(pMsg);
905 break;
906 case CMD_SET_ALARM_STATUS_FLOW:
907 updateAlarmStatusFlow(pMsg);
908 break;
909 case CMD_UPDATE_ALARM_COMMENT:
910 updateAlarmComment(pMsg);
911 break;
912 case CMD_DELETE_ALARM_COMMENT:
913 deleteAlarmComment(pMsg);
914 break;
915 case CMD_GET_ALARM:
916 getAlarm(pMsg);
917 break;
918 case CMD_GET_ALARM_EVENTS:
919 CALL_IN_NEW_THREAD(getAlarmEvents, pMsg);
920 break;
921 case CMD_ACK_ALARM:
922 acknowledgeAlarm(pMsg);
923 break;
924 case CMD_RESOLVE_ALARM:
925 resolveAlarm(pMsg, false);
926 break;
927 case CMD_TERMINATE_ALARM:
928 resolveAlarm(pMsg, true);
929 break;
930 case CMD_DELETE_ALARM:
931 deleteAlarm(pMsg);
932 break;
933 case CMD_OPEN_HELPDESK_ISSUE:
934 CALL_IN_NEW_THREAD(openHelpdeskIssue, pMsg);
935 break;
936 case CMD_GET_HELPDESK_URL:
937 getHelpdeskUrl(pMsg);
938 break;
939 case CMD_UNLINK_HELPDESK_ISSUE:
940 unlinkHelpdeskIssue(pMsg);
941 break;
942 case CMD_CREATE_ACTION:
943 createAction(pMsg);
944 break;
945 case CMD_MODIFY_ACTION:
946 updateAction(pMsg);
947 break;
948 case CMD_DELETE_ACTION:
949 deleteAction(pMsg);
950 break;
951 case CMD_LOAD_ACTIONS:
952 sendAllActions(pMsg->getId());
953 break;
954 case CMD_DELETE_OBJECT:
955 deleteObject(pMsg);
956 break;
957 case CMD_POLL_NODE:
958 forcedNodePoll(pMsg);
959 break;
960 case CMD_TRAP:
961 onTrap(pMsg);
962 break;
963 case CMD_WAKEUP_NODE:
964 onWakeUpNode(pMsg);
965 break;
966 case CMD_CREATE_TRAP:
967 editTrap(TRAP_CREATE, pMsg);
968 break;
969 case CMD_MODIFY_TRAP:
970 editTrap(TRAP_UPDATE, pMsg);
971 break;
972 case CMD_DELETE_TRAP:
973 editTrap(TRAP_DELETE, pMsg);
974 break;
975 case CMD_LOAD_TRAP_CFG:
976 sendAllTraps(pMsg->getId());
977 break;
978 case CMD_GET_TRAP_CFG_RO:
979 sendAllTraps2(pMsg->getId());
980 break;
981 case CMD_QUERY_PARAMETER:
982 CALL_IN_NEW_THREAD(queryParameter, pMsg);
983 break;
984 case CMD_QUERY_TABLE:
985 CALL_IN_NEW_THREAD(queryAgentTable, pMsg);
986 break;
987 case CMD_LOCK_PACKAGE_DB:
988 LockPackageDB(pMsg->getId(), TRUE);
989 break;
990 case CMD_UNLOCK_PACKAGE_DB:
991 LockPackageDB(pMsg->getId(), FALSE);
992 break;
993 case CMD_GET_PACKAGE_LIST:
994 SendAllPackages(pMsg->getId());
995 break;
996 case CMD_INSTALL_PACKAGE:
997 InstallPackage(pMsg);
998 break;
999 case CMD_REMOVE_PACKAGE:
1000 RemovePackage(pMsg);
1001 break;
1002 case CMD_GET_PARAMETER_LIST:
1003 getParametersList(pMsg);
1004 break;
1005 case CMD_DEPLOY_PACKAGE:
1006 DeployPackage(pMsg);
1007 break;
1008 case CMD_GET_LAST_VALUES:
1009 getLastValues(pMsg);
1010 break;
1011 case CMD_GET_DCI_VALUES:
1012 getLastValuesByDciId(pMsg);
1013 break;
1014 case CMD_GET_TABLE_LAST_VALUES:
1015 getTableLastValues(pMsg);
1016 break;
1017 case CMD_GET_THRESHOLD_SUMMARY:
1018 getThresholdSummary(pMsg);
1019 break;
1020 case CMD_GET_USER_VARIABLE:
1021 getUserVariable(pMsg);
1022 break;
1023 case CMD_SET_USER_VARIABLE:
1024 setUserVariable(pMsg);
1025 break;
1026 case CMD_DELETE_USER_VARIABLE:
1027 deleteUserVariable(pMsg);
1028 break;
1029 case CMD_ENUM_USER_VARIABLES:
1030 enumUserVariables(pMsg);
1031 break;
1032 case CMD_COPY_USER_VARIABLE:
1033 copyUserVariable(pMsg);
1034 break;
1035 case CMD_CHANGE_ZONE:
1036 changeObjectZone(pMsg);
1037 break;
1038 case CMD_REQUEST_ENCRYPTION:
1039 setupEncryption(pMsg);
1040 break;
1041 case CMD_GET_AGENT_CONFIG:
1042 getAgentConfig(pMsg);
1043 break;
1044 case CMD_UPDATE_AGENT_CONFIG:
1045 updateAgentConfig(pMsg);
1046 break;
1047 case CMD_EXECUTE_ACTION:
1048 CALL_IN_NEW_THREAD(executeAction, pMsg);
1049 break;
1050 case CMD_GET_OBJECT_TOOLS:
1051 getObjectTools(pMsg->getId());
1052 break;
1053 case CMD_EXEC_TABLE_TOOL:
1054 execTableTool(pMsg);
1055 break;
1056 case CMD_GET_OBJECT_TOOL_DETAILS:
1057 getObjectToolDetails(pMsg);
1058 break;
1059 case CMD_UPDATE_OBJECT_TOOL:
1060 updateObjectTool(pMsg);
1061 break;
1062 case CMD_DELETE_OBJECT_TOOL:
1063 deleteObjectTool(pMsg);
1064 break;
1065 case CMD_CHANGE_OBJECT_TOOL_STATUS:
1066 changeObjectToolStatus(pMsg);
1067 break;
1068 case CMD_GENERATE_OBJECT_TOOL_ID:
1069 generateObjectToolId(pMsg->getId());
1070 break;
1071 case CMD_CHANGE_SUBSCRIPTION:
1072 changeSubscription(pMsg);
1073 break;
1074 case CMD_GET_SYSLOG:
1075 CALL_IN_NEW_THREAD(sendSyslog, pMsg);
1076 break;
1077 case CMD_GET_SERVER_STATS:
1078 sendServerStats(pMsg->getId());
1079 break;
1080 case CMD_GET_SCRIPT_LIST:
1081 sendScriptList(pMsg->getId());
1082 break;
1083 case CMD_GET_SCRIPT:
1084 sendScript(pMsg);
1085 break;
1086 case CMD_UPDATE_SCRIPT:
1087 updateScript(pMsg);
1088 break;
1089 case CMD_RENAME_SCRIPT:
1090 renameScript(pMsg);
1091 break;
1092 case CMD_DELETE_SCRIPT:
1093 deleteScript(pMsg);
1094 break;
1095 case CMD_GET_SESSION_LIST:
1096 SendSessionList(pMsg->getId());
1097 break;
1098 case CMD_KILL_SESSION:
1099 KillSession(pMsg);
1100 break;
1101 case CMD_GET_TRAP_LOG:
1102 SendTrapLog(pMsg);
1103 break;
1104 case CMD_START_SNMP_WALK:
1105 StartSnmpWalk(pMsg);
1106 break;
1107 case CMD_RESOLVE_DCI_NAMES:
1108 resolveDCINames(pMsg);
1109 break;
1110 case CMD_GET_DCI_INFO:
1111 SendDCIInfo(pMsg);
1112 break;
1113 case CMD_GET_DCI_THRESHOLDS:
1114 sendDCIThresholds(pMsg);
1115 break;
1116 case CMD_GET_DCI_EVENTS_LIST:
1117 getDCIEventList(pMsg);
1118 break;
1119 case CMD_GET_DCI_SCRIPT_LIST:
1120 getDCIScriptList(pMsg);
1121 break;
1122 case CMD_GET_PERFTAB_DCI_LIST:
1123 sendPerfTabDCIList(pMsg);
1124 break;
1125 case CMD_PUSH_DCI_DATA:
1126 pushDCIData(pMsg);
1127 break;
1128 case CMD_GET_AGENT_CFG_LIST:
1129 sendAgentCfgList(pMsg->getId());
1130 break;
1131 case CMD_OPEN_AGENT_CONFIG:
1132 OpenAgentConfig(pMsg);
1133 break;
1134 case CMD_SAVE_AGENT_CONFIG:
1135 SaveAgentConfig(pMsg);
1136 break;
1137 case CMD_DELETE_AGENT_CONFIG:
1138 DeleteAgentConfig(pMsg);
1139 break;
1140 case CMD_SWAP_AGENT_CONFIGS:
1141 SwapAgentConfigs(pMsg);
1142 break;
1143 case CMD_GET_OBJECT_COMMENTS:
1144 SendObjectComments(pMsg);
1145 break;
1146 case CMD_UPDATE_OBJECT_COMMENTS:
1147 updateObjectComments(pMsg);
1148 break;
1149 case CMD_GET_ADDR_LIST:
1150 getAddrList(pMsg);
1151 break;
1152 case CMD_SET_ADDR_LIST:
1153 setAddrList(pMsg);
1154 break;
1155 case CMD_RESET_COMPONENT:
1156 resetComponent(pMsg);
1157 break;
1158 case CMD_EXPORT_CONFIGURATION:
1159 exportConfiguration(pMsg);
1160 break;
1161 case CMD_IMPORT_CONFIGURATION:
1162 CALL_IN_NEW_THREAD(importConfiguration, pMsg);
1163 break;
1164 case CMD_GET_GRAPH_LIST:
1165 sendGraphList(pMsg);
1166 break;
1167 case CMD_SAVE_GRAPH:
1168 saveGraph(pMsg);
1169 break;
1170 case CMD_DELETE_GRAPH:
1171 deleteGraph(pMsg);
1172 break;
1173 case CMD_ADD_CA_CERTIFICATE:
1174 AddCACertificate(pMsg);
1175 break;
1176 case CMD_DELETE_CERTIFICATE:
1177 DeleteCertificate(pMsg);
1178 break;
1179 case CMD_UPDATE_CERT_COMMENTS:
1180 UpdateCertificateComments(pMsg);
1181 break;
1182 case CMD_GET_CERT_LIST:
1183 getCertificateList(pMsg->getId());
1184 break;
1185 case CMD_QUERY_L2_TOPOLOGY:
1186 CALL_IN_NEW_THREAD(queryL2Topology, pMsg);
1187 break;
1188 case CMD_SEND_SMS:
1189 sendSMS(pMsg);
1190 break;
1191 case CMD_GET_COMMUNITY_LIST:
1192 SendCommunityList(pMsg->getId());
1193 break;
1194 case CMD_UPDATE_COMMUNITY_LIST:
1195 UpdateCommunityList(pMsg);
1196 break;
1197 case CMD_GET_USM_CREDENTIALS:
1198 sendUsmCredentials(pMsg->getId());
1199 break;
1200 case CMD_UPDATE_USM_CREDENTIALS:
1201 updateUsmCredentials(pMsg);
1202 break;
1203 case CMD_GET_SITUATION_LIST:
1204 getSituationList(pMsg->getId());
1205 break;
1206 case CMD_CREATE_SITUATION:
1207 createSituation(pMsg);
1208 break;
1209 case CMD_UPDATE_SITUATION:
1210 updateSituation(pMsg);
1211 break;
1212 case CMD_DELETE_SITUATION:
1213 deleteSituation(pMsg);
1214 break;
1215 case CMD_DEL_SITUATION_INSTANCE:
1216 deleteSituationInstance(pMsg);
1217 break;
1218 case CMD_REGISTER_AGENT:
1219 registerAgent(pMsg);
1220 break;
1221 case CMD_GET_SERVER_FILE:
1222 CALL_IN_NEW_THREAD(getServerFile, pMsg);
1223 break;
1224 case CMD_GET_AGENT_FILE:
1225 CALL_IN_NEW_THREAD(getAgentFile, pMsg);
1226 break;
1227 case CMD_CANCEL_FILE_MONITORING:
1228 CALL_IN_NEW_THREAD(cancelFileMonitoring, pMsg);
1229 break;
1230 case CMD_TEST_DCI_TRANSFORMATION:
1231 testDCITransformation(pMsg);
1232 break;
1233 case CMD_EXECUTE_SCRIPT:
1234 CALL_IN_NEW_THREAD(executeScript, pMsg);
1235 break;
1236 case CMD_GET_JOB_LIST:
1237 sendJobList(pMsg->getId());
1238 break;
1239 case CMD_CANCEL_JOB:
1240 cancelJob(pMsg);
1241 break;
1242 case CMD_HOLD_JOB:
1243 holdJob(pMsg);
1244 break;
1245 case CMD_UNHOLD_JOB:
1246 unholdJob(pMsg);
1247 break;
1248 case CMD_DEPLOY_AGENT_POLICY:
1249 deployAgentPolicy(pMsg, false);
1250 break;
1251 case CMD_UNINSTALL_AGENT_POLICY:
1252 deployAgentPolicy(pMsg, true);
1253 break;
1254 case CMD_GET_CURRENT_USER_ATTR:
1255 getUserCustomAttribute(pMsg);
1256 break;
1257 case CMD_SET_CURRENT_USER_ATTR:
1258 setUserCustomAttribute(pMsg);
1259 break;
1260 case CMD_OPEN_SERVER_LOG:
1261 openServerLog(pMsg);
1262 break;
1263 case CMD_CLOSE_SERVER_LOG:
1264 closeServerLog(pMsg);
1265 break;
1266 case CMD_QUERY_LOG:
1267 CALL_IN_NEW_THREAD(queryServerLog, pMsg);
1268 break;
1269 case CMD_GET_LOG_DATA:
1270 CALL_IN_NEW_THREAD(getServerLogQueryData, pMsg);
1271 break;
1272 case CMD_FIND_NODE_CONNECTION:
1273 CALL_IN_NEW_THREAD(findNodeConnection, pMsg);
1274 break;
1275 case CMD_FIND_MAC_LOCATION:
1276 CALL_IN_NEW_THREAD(findMacAddress, pMsg);
1277 break;
1278 case CMD_FIND_IP_LOCATION:
1279 CALL_IN_NEW_THREAD(findIpAddress, pMsg);
1280 break;
1281 case CMD_GET_IMAGE:
1282 sendLibraryImage(pMsg);
1283 break;
1284 case CMD_CREATE_IMAGE:
1285 updateLibraryImage(pMsg);
1286 break;
1287 case CMD_DELETE_IMAGE:
1288 deleteLibraryImage(pMsg);
1289 break;
1290 case CMD_MODIFY_IMAGE:
1291 updateLibraryImage(pMsg);
1292 break;
1293 case CMD_LIST_IMAGES:
1294 listLibraryImages(pMsg);
1295 break;
1296 case CMD_EXECUTE_SERVER_COMMAND:
1297 executeServerCommand(pMsg);
1298 break;
1299 case CMD_LIST_SERVER_FILES:
1300 listServerFileStore(pMsg);
1301 break;
1302 case CMD_UPLOAD_FILE_TO_AGENT:
1303 uploadFileToAgent(pMsg);
1304 break;
1305 case CMD_UPLOAD_FILE:
1306 receiveFile(pMsg);
1307 break;
1308 case CMD_DELETE_FILE:
1309 deleteFile(pMsg);
1310 break;
1311 case CMD_OPEN_CONSOLE:
1312 openConsole(pMsg->getId());
1313 break;
1314 case CMD_CLOSE_CONSOLE:
1315 closeConsole(pMsg->getId());
1316 break;
1317 case CMD_ADM_REQUEST:
1318 CALL_IN_NEW_THREAD(processConsoleCommand, pMsg);
1319 break;
1320 case CMD_GET_VLANS:
1321 getVlans(pMsg);
1322 break;
1323 case CMD_GET_NETWORK_PATH:
1324 CALL_IN_NEW_THREAD(getNetworkPath, pMsg);
1325 break;
1326 case CMD_GET_NODE_COMPONENTS:
1327 getNodeComponents(pMsg);
1328 break;
1329 case CMD_GET_NODE_SOFTWARE:
1330 getNodeSoftware(pMsg);
1331 break;
1332 case CMD_GET_WINPERF_OBJECTS:
1333 getWinPerfObjects(pMsg);
1334 break;
1335 case CMD_LIST_MAPPING_TABLES:
1336 listMappingTables(pMsg);
1337 break;
1338 case CMD_GET_MAPPING_TABLE:
1339 getMappingTable(pMsg);
1340 break;
1341 case CMD_UPDATE_MAPPING_TABLE:
1342 updateMappingTable(pMsg);
1343 break;
1344 case CMD_DELETE_MAPPING_TABLE:
1345 deleteMappingTable(pMsg);
1346 break;
1347 case CMD_GET_WIRELESS_STATIONS:
1348 getWirelessStations(pMsg);
1349 break;
1350 case CMD_GET_SUMMARY_TABLES:
1351 getSummaryTables(pMsg->getId());
1352 break;
1353 case CMD_GET_SUMMARY_TABLE_DETAILS:
1354 getSummaryTableDetails(pMsg);
1355 break;
1356 case CMD_MODIFY_SUMMARY_TABLE:
1357 modifySummaryTable(pMsg);
1358 break;
1359 case CMD_DELETE_SUMMARY_TABLE:
1360 deleteSummaryTable(pMsg);
1361 break;
1362 case CMD_QUERY_SUMMARY_TABLE:
1363 querySummaryTable(pMsg);
1364 break;
1365 case CMD_QUERY_ADHOC_SUMMARY_TABLE:
1366 queryAdHocSummaryTable(pMsg);
1367 break;
1368 case CMD_GET_SUBNET_ADDRESS_MAP:
1369 getSubnetAddressMap(pMsg);
1370 break;
1371 case CMD_GET_EFFECTIVE_RIGHTS:
1372 getEffectiveRights(pMsg);
1373 break;
1374 case CMD_GET_FOLDER_CONTENT:
1375 case CMD_FILEMGR_DELETE_FILE:
1376 case CMD_FILEMGR_RENAME_FILE:
1377 case CMD_FILEMGR_MOVE_FILE:
1378 case CMD_FILEMGR_CREATE_FOLDER:
1379 CALL_IN_NEW_THREAD(fileManagerControl, pMsg);
1380 break;
1381 case CMD_FILEMGR_UPLOAD:
1382 CALL_IN_NEW_THREAD(uploadUserFileToAgent, pMsg);
1383 break;
1384 case CMD_GET_SWITCH_FDB:
1385 CALL_IN_NEW_THREAD(getSwitchForwardingDatabase, pMsg);
1386 break;
1387 case CMD_GET_ROUTING_TABLE:
1388 CALL_IN_NEW_THREAD(getRoutingTable, pMsg);
1389 break;
1390 case CMD_GET_LOC_HISTORY:
1391 CALL_IN_NEW_THREAD(getLocationHistory, pMsg);
1392 break;
1393 case CMD_TAKE_SCREENSHOT:
1394 getScreenshot(pMsg);
1395 break;
1396 case CMD_COMPILE_SCRIPT:
1397 compileScript(pMsg);
1398 break;
1399 case CMD_CLEAN_AGENT_DCI_CONF:
1400 cleanAgentDciConfiguration(pMsg);
1401 break;
1402 case CMD_RESYNC_AGENT_DCI_CONF:
1403 resyncAgentDciConfiguration(pMsg);
1404 break;
1405 case CMD_LIST_SCHEDULE_CALLBACKS:
1406 getSchedulerTaskHandlers(pMsg);
1407 break;
1408 case CMD_LIST_SCHEDULES:
1409 getScheduledTasks(pMsg);
1410 break;
1411 case CMD_ADD_SCHEDULE:
1412 addScheduledTask(pMsg);
1413 break;
1414 case CMD_UPDATE_SCHEDULE:
1415 updateScheduledTask(pMsg);
1416 break;
1417 case CMD_REMOVE_SCHEDULE:
1418 removeScheduledTask(pMsg);
1419 #ifdef WITH_ZMQ
1420 case CMD_ZMQ_SUBSCRIBE_EVENT:
1421 zmqManageSubscription(pMsg, zmq::EVENT, true);
1422 break;
1423 case CMD_ZMQ_UNSUBSCRIBE_EVENT:
1424 zmqManageSubscription(pMsg, zmq::EVENT, false);
1425 break;
1426 case CMD_ZMQ_SUBSCRIBE_DATA:
1427 zmqManageSubscription(pMsg, zmq::DATA, true);
1428 break;
1429 case CMD_ZMQ_UNSUBSCRIBE_DATA:
1430 zmqManageSubscription(pMsg, zmq::DATA, false);
1431 break;
1432 case CMD_ZMQ_LIST_EVENT_SUBSCRIPTIONS:
1433 zmqListSubscriptions(pMsg, zmq::EVENT);
1434 break;
1435 case CMD_ZMQ_LIST_DATA_SUBSCRIPTIONS:
1436 zmqListSubscriptions(pMsg, zmq::DATA);
1437 break;
1438 #endif
1439 default:
1440 if ((m_wCurrentCmd >> 8) == 0x11)
1441 {
1442 // Reporting Server range (0x1100 - 0x11FF)
1443 CALL_IN_NEW_THREAD(forwardToReportingServer, pMsg);
1444 break;
1445 }
1446
1447 // Pass message to loaded modules
1448 for(i = 0; i < g_dwNumModules; i++)
1449 {
1450 if (g_pModuleList[i].pfClientCommandHandler != NULL)
1451 {
1452 status = g_pModuleList[i].pfClientCommandHandler(m_wCurrentCmd, pMsg, this);
1453 if (status != NXMOD_COMMAND_IGNORED)
1454 {
1455 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
1456 {
1457 pMsg = NULL; // Prevent deletion
1458 m_dwRefCount++;
1459 }
1460 break; // Message was processed by the module
1461 }
1462 }
1463 }
1464 if (i == g_dwNumModules)
1465 {
1466 NXCPMessage response;
1467
1468 response.setId(pMsg->getId());
1469 response.setCode(CMD_REQUEST_COMPLETED);
1470 response.setField(VID_RCC, RCC_NOT_IMPLEMENTED);
1471 sendMessage(&response);
1472 }
1473 break;
1474 }
1475 delete pMsg;
1476 m_state = (m_dwFlags & CSF_AUTHENTICATED) ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
1477 }
1478 }
1479
1480 /**
1481 * Respond to client's keepalive message
1482 */
1483 void ClientSession::respondToKeepalive(UINT32 dwRqId)
1484 {
1485 NXCPMessage msg;
1486
1487 msg.setCode(CMD_REQUEST_COMPLETED);
1488 msg.setId(dwRqId);
1489 msg.setField(VID_RCC, RCC_SUCCESS);
1490 sendMessage(&msg);
1491 }
1492
1493 /**
1494 * Process received file
1495 */
1496 void ClientSession::onFileUpload(BOOL bSuccess)
1497 {
1498 // Do processing specific to command initiated file upload
1499 switch(m_dwUploadCommand)
1500 {
1501 case CMD_INSTALL_PACKAGE:
1502 if (!bSuccess)
1503 {
1504 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1505 TCHAR szQuery[256];
1506 _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_dwUploadData);
1507 DBQuery(hdb, szQuery);
1508 DBConnectionPoolReleaseConnection(hdb);
1509 }
1510 break;
1511 case CMD_MODIFY_IMAGE:
1512 EnumerateClientSessions(ImageLibraryUpdateCallback, (void *)&m_uploadImageGuid);
1513 break;
1514 default:
1515 break;
1516 }
1517
1518 // Remove received file in case of failure
1519 if (!bSuccess)
1520 _tunlink(m_szCurrFileName);
1521 }
1522
1523 /**
1524 * Send message to client
1525 */
1526 bool ClientSession::sendMessage(NXCPMessage *msg)
1527 {
1528 if (isTerminated())
1529 return false;
1530
1531 if (msg->getCode() != CMD_ADM_MESSAGE)
1532 {
1533 TCHAR buffer[128];
1534 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(msg->getCode(), buffer));
1535 }
1536
1537 NXCP_MESSAGE *rawMsg = msg->createMessage();
1538 if ((g_debugLevel >= 8) && (msg->getCode() != CMD_ADM_MESSAGE))
1539 {
1540 String msgDump = NXCPMessage::dump(rawMsg, NXCP_VERSION);
1541 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
1542 }
1543
1544 bool result;
1545 if (m_pCtx != NULL)
1546 {
1547 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(rawMsg);
1548 if (enMsg != NULL)
1549 {
1550 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
1551 free(enMsg);
1552 }
1553 else
1554 {
1555 result = false;
1556 }
1557 }
1558 else
1559 {
1560 result = (SendEx(m_hSocket, (const char *)rawMsg, ntohl(rawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
1561 }
1562 free(rawMsg);
1563
1564 if (!result)
1565 {
1566 closesocket(m_hSocket);
1567 m_hSocket = -1;
1568 }
1569 return result;
1570 }
1571
1572 /**
1573 * Send raw message to client
1574 */
1575 void ClientSession::sendRawMessage(NXCP_MESSAGE *msg)
1576 {
1577 if (isTerminated())
1578 return;
1579
1580 UINT16 code = htons(msg->code);
1581 if (code != CMD_ADM_MESSAGE)
1582 {
1583 TCHAR buffer[128];
1584 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(ntohs(msg->code), buffer));
1585 }
1586
1587 if ((g_debugLevel >= 8) && (code != CMD_ADM_MESSAGE))
1588 {
1589 String msgDump = NXCPMessage::dump(msg, NXCP_VERSION);
1590 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
1591 }
1592
1593 bool result;
1594 if (m_pCtx != NULL)
1595 {
1596 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(msg);
1597 if (enMsg != NULL)
1598 {
1599 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
1600 free(enMsg);
1601 }
1602 else
1603 {
1604 result = false;
1605 }
1606 }
1607 else
1608 {
1609 result = (SendEx(m_hSocket, (const char *)msg, ntohl(msg->size), 0, m_mutexSocketWrite) == (int)ntohl(msg->size));
1610 }
1611
1612 if (!result)
1613 {
1614 closesocket(m_hSocket);
1615 m_hSocket = -1;
1616 }
1617 }
1618
1619 /**
1620 * Send file to client
1621 */
1622 BOOL ClientSession::sendFile(const TCHAR *file, UINT32 dwRqId, long ofset)
1623 {
1624 return !isTerminated() ? SendFileOverNXCP(m_hSocket, dwRqId, file, m_pCtx, ofset, NULL, NULL, m_mutexSocketWrite) : FALSE;
1625 }
1626
1627 /**
1628 * Send server information to client
1629 */
1630 void ClientSession::sendServerInfo(UINT32 dwRqId)
1631 {
1632 static UINT32 protocolVersions[] = {
1633 CLIENT_PROTOCOL_VERSION_BASE,
1634 CLIENT_PROTOCOL_VERSION_ALARMS,
1635 CLIENT_PROTOCOL_VERSION_PUSH,
1636 CLIENT_PROTOCOL_VERSION_TRAP,
1637 CLIENT_PROTOCOL_VERSION_MOBILE,
1638 CLIENT_PROTOCOL_VERSION_FULL
1639 };
1640 NXCPMessage msg;
1641 TCHAR szBuffer[MAX_CONFIG_VALUE];
1642 String strURL;
1643
1644 // Prepare response message
1645 msg.setCode(CMD_REQUEST_COMPLETED);
1646 msg.setId(dwRqId);
1647
1648 // Generate challenge for certificate authentication
1649 #ifdef _WITH_ENCRYPTION
1650 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
1651 #else
1652 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
1653 #endif
1654
1655 // Fill message with server info
1656 msg.setField(VID_RCC, RCC_SUCCESS);
1657 msg.setField(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
1658 msg.setField(VID_SERVER_ID, g_serverId);
1659 msg.setField(VID_SUPPORTED_ENCRYPTION, (UINT32)0);
1660 msg.setField(VID_PROTOCOL_VERSION, (UINT32)CLIENT_PROTOCOL_VERSION_BASE);
1661 msg.setFieldFromInt32Array(VID_PROTOCOL_VERSION_EX, sizeof(protocolVersions) / sizeof(UINT32), protocolVersions);
1662 msg.setField(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
1663 msg.setField(VID_TIMESTAMP, (UINT32)time(NULL));
1664
1665 #if defined(_WIN32)
1666 TIME_ZONE_INFORMATION tz;
1667 WCHAR wst[4], wdt[8], *curr;
1668 int i;
1669
1670 DWORD tzType = GetTimeZoneInformation(&tz);
1671
1672 // Create 3 letter abbreviation for standard name
1673 for(i = 0, curr = tz.StandardName; (*curr != 0) && (i < 3); curr++)
1674 if (iswupper(*curr))
1675 wst[i++] = *curr;
1676 while(i < 3)
1677 wst[i++] = L'X';
1678 wst[i] = 0;
1679
1680 // Create abbreviation for DST name
1681 for(i = 0, curr = tz.DaylightName; (*curr != 0) && (i < 7); curr++)
1682 if (iswupper(*curr))
1683 wdt[i++] = *curr;
1684 while(i < 3)
1685 wdt[i++] = L'X';
1686 wdt[i] = 0;
1687
1688 LONG effectiveBias;
1689 switch(tzType)
1690 {
1691 case TIME_ZONE_ID_STANDARD:
1692 effectiveBias = tz.Bias + tz.StandardBias;
1693 break;
1694 case TIME_ZONE_ID_DAYLIGHT:
1695 effectiveBias = tz.Bias + tz.DaylightBias;
1696 break;
1697 case TIME_ZONE_ID_UNKNOWN:
1698 effectiveBias = tz.Bias;
1699 break;
1700 default: // error
1701 effectiveBias = 0;
1702 debugPrintf(4, _T("GetTimeZoneInformation() call failed"));
1703 break;
1704 }
1705
1706 #ifdef UNICODE
1707 swprintf(szBuffer, 1024, L"%s%c%02d%s", wst, (effectiveBias > 0) ? '-' : '+',
1708 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1709 #else
1710 sprintf(szBuffer, "%S%c%02d%S", wst, (effectiveBias > 0) ? '-' : '+',
1711 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1712 #endif
1713
1714 #elif HAVE_TM_GMTOFF /* not Windows but have tm_gmtoff */
1715
1716 time_t t = time(NULL);
1717 int gmtOffset;
1718 #if HAVE_LOCALTIME_R
1719 struct tm tmbuff;
1720 struct tm *loc = localtime_r(&t, &tmbuff);
1721 #else
1722 struct tm *loc = localtime(&t);
1723 #endif
1724 gmtOffset = loc->tm_gmtoff / 3600;
1725 #ifdef UNICODE
1726 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1727 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1728 #else
1729 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1730 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1731 #endif
1732
1733 #else /* not Windows and no tm_gmtoff */
1734
1735 time_t t = time(NULL);
1736 #if HAVE_GMTIME_R
1737 struct tm tmbuff;
1738 struct tm *gmt = gmtime_r(&t, &tmbuff);
1739 #else
1740 struct tm *gmt = gmtime(&t);
1741 #endif
1742 gmt->tm_isdst = -1;
1743 int gmtOffset = (int)((t - mktime(gmt)) / 3600);
1744 #ifdef UNICODE
1745 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1746 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1747 #else
1748 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1749 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1750 #endif
1751
1752 #endif
1753
1754 msg.setField(VID_TIMEZONE, szBuffer);
1755 debugPrintf(2, _T("Server time zone: %s"), szBuffer);
1756
1757 ConfigReadStr(_T("TileServerURL"), szBuffer, MAX_CONFIG_VALUE, _T("http://tile.openstreetmap.org/"));
1758 msg.setField(VID_TILE_SERVER_URL, szBuffer);
1759
1760 ConfigReadStr(_T("DefaultConsoleDateFormat"), szBuffer, MAX_CONFIG_VALUE, _T("dd.MM.yyyy"));
1761 msg.setField(VID_DATE_FORMAT, szBuffer);
1762
1763 ConfigReadStr(_T("DefaultConsoleTimeFormat"), szBuffer, MAX_CONFIG_VALUE, _T("HH:mm:ss"));
1764 msg.setField(VID_TIME_FORMAT, szBuffer);
1765
1766 ConfigReadStr(_T("DefaultConsoleShortTimeFormat"), szBuffer, MAX_CONFIG_VALUE, _T("HH:mm"));
1767 msg.setField(VID_SHORT_TIME_FORMAT, szBuffer);
1768
1769 // Send response
1770 sendMessage(&msg);
1771 }
1772
1773 /**
1774 * Authenticate client
1775 */
1776 void ClientSession::login(NXCPMessage *pRequest)
1777 {
1778 NXCPMessage msg;
1779 TCHAR szLogin[MAX_USER_NAME], szPassword[1024];
1780 int nAuthType;
1781 bool changePasswd = false, intruderLockout = false;
1782 UINT32 dwResult;
1783 #ifdef _WITH_ENCRYPTION
1784 X509 *pCert;
1785 #endif
1786
1787 // Prepare response message
1788 msg.setCode(CMD_LOGIN_RESP);
1789 msg.setId(pRequest->getId());
1790
1791 // Get client info string
1792 if (pRequest->isFieldExist(VID_CLIENT_INFO))
1793 {
1794 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
1795
1796 pRequest->getFieldAsString(VID_CLIENT_INFO, szClientInfo, 32);
1797 pRequest->getFieldAsString(VID_OS_INFO, szOSInfo, 32);
1798 pRequest->getFieldAsString(VID_LIBNXCL_VERSION, szLibVersion, 16);
1799 _sntprintf(m_clientInfo, 96, _T("%s (%s; libnxcl %s)"), szClientInfo, szOSInfo, szLibVersion);
1800 }
1801
1802 m_clientType = pRequest->getFieldAsUInt16(VID_CLIENT_TYPE);
1803 if ((m_clientType < 0) || (m_clientType > CLIENT_TYPE_APPLICATION))
1804 m_clientType = CLIENT_TYPE_DESKTOP;
1805
1806 if (m_clientType == CLIENT_TYPE_WEB)
1807 {
1808 _tcscpy(m_webServerAddress, m_workstation);
1809 if (pRequest->isFieldExist(VID_CLIENT_ADDRESS))
1810 {
1811 pRequest->getFieldAsString(VID_CLIENT_ADDRESS, m_workstation, 256);
1812 debugPrintf(5, _T("Real web client address is %s"), m_workstation);
1813 }
1814 }
1815
1816 if (pRequest->isFieldExist(VID_LANGUAGE))
1817 {
1818 pRequest->getFieldAsString(VID_LANGUAGE, m_language, 8);
1819 }
1820
1821 if (!(m_dwFlags & CSF_AUTHENTICATED))
1822 {
1823 pRequest->getFieldAsString(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
1824 nAuthType = (int)pRequest->getFieldAsUInt16(VID_AUTH_TYPE);
1825 debugPrintf(6, _T("authentication type %d"), nAuthType);
1826 switch(nAuthType)
1827 {
1828 case NETXMS_AUTH_TYPE_PASSWORD:
1829 #ifdef UNICODE
1830 pRequest->getFieldAsString(VID_PASSWORD, szPassword, 256);
1831 #else
1832 pRequest->getFieldAsUtf8String(VID_PASSWORD, szPassword, 1024);
1833 #endif
1834 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
1835 &m_dwSystemAccess, &changePasswd, &intruderLockout, false);
1836 break;
1837 case NETXMS_AUTH_TYPE_CERTIFICATE:
1838 #ifdef _WITH_ENCRYPTION
1839 pCert = CertificateFromLoginMessage(pRequest);
1840 if (pCert != NULL)
1841 {
1842 BYTE signature[256];
1843 UINT32 dwSigLen;
1844
1845 dwSigLen = pRequest->getFieldAsBinary(VID_SIGNATURE, signature, 256);
1846 dwResult = AuthenticateUser(szLogin, (TCHAR *)signature, dwSigLen, pCert,
1847 m_challenge, &m_dwUserId, &m_dwSystemAccess,
1848 &changePasswd, &intruderLockout, false);
1849 X509_free(pCert);
1850 }
1851 else
1852 {
1853 dwResult = RCC_BAD_CERTIFICATE;
1854 }
1855 #else
1856 dwResult = RCC_NOT_IMPLEMENTED;
1857 #endif
1858 break;
1859 case NETXMS_AUTH_TYPE_SSO_TICKET:
1860 char ticket[1024];
1861 pRequest->getFieldAsMBString(VID_PASSWORD, ticket, 1024);
1862 if (CASAuthenticate(ticket, szLogin))
1863 {
1864 debugPrintf(5, _T("SSO ticket %hs is valid, login name %s"), ticket, szLogin);
1865 dwResult = AuthenticateUser(szLogin, NULL, 0, NULL, NULL, &m_dwUserId,
1866 &m_dwSystemAccess, &changePasswd, &intruderLockout, true);
1867 }
1868 else
1869 {
1870 debugPrintf(5, _T("SSO ticket %hs is invalid"), ticket);
1871 dwResult = RCC_ACCESS_DENIED;
1872 }
1873 break;
1874 default:
1875 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
1876 break;
1877 }
1878
1879 // Additional validation by loaded modules
1880 if (dwResult == RCC_SUCCESS)
1881 {
1882 for(UINT32 i = 0; i < g_dwNumModules; i++)
1883 {
1884 if (g_pModuleList[i].pfAdditionalLoginCheck != NULL)
1885 {
1886 dwResult = g_pModuleList[i].pfAdditionalLoginCheck(m_dwUserId, pRequest);
1887 if (dwResult != RCC_SUCCESS)
1888 {
1889 debugPrintf(4, _T("Login blocked by module %s (rcc=%d)"), g_pModuleList[i].szName, dwResult);
1890 break;
1891 }
1892 }
1893 }
1894 }
1895
1896 if (dwResult == RCC_SUCCESS)
1897 {
1898 m_dwFlags |= CSF_AUTHENTICATED;
1899 nx_strncpy(m_loginName, szLogin, MAX_USER_NAME);
1900 _sntprintf(m_sessionName, MAX_SESSION_NAME, _T("%s@%s"), szLogin, m_workstation);
1901 m_loginTime = time(NULL);
1902 msg.setField(VID_RCC, RCC_SUCCESS);
1903 msg.setField(VID_USER_SYS_RIGHTS, m_dwSystemAccess);
1904 msg.setField(VID_USER_ID, m_dwUserId);
1905 msg.setField(VID_SESSION_ID, (UINT32)m_id);
1906 msg.setField(VID_CHANGE_PASSWD_FLAG, (WORD)changePasswd);
1907 msg.setField(VID_DBCONN_STATUS, (UINT16)((g_flags & AF_DB_CONNECTION_LOST) ? 0 : 1));
1908 msg.setField(VID_ZONING_ENABLED, (UINT16)((g_flags & AF_ENABLE_ZONING) ? 1 : 0));
1909 msg.setField(VID_POLLING_INTERVAL, (INT32)DCObject::m_defaultPollingInterval);
1910 msg.setField(VID_RETENTION_TIME, (INT32)DCObject::m_defaultRetentionTime);
1911 msg.setField(VID_ALARM_STATUS_FLOW_STATE, (UINT16)ConfigReadInt(_T("StrictAlarmStatusFlow"), 0));
1912 msg.setField(VID_TIMED_ALARM_ACK_ENABLED, (UINT16)ConfigReadInt(_T("EnableTimedAlarmAck"), 0));
1913 msg.setField(VID_VIEW_REFRESH_INTERVAL, (UINT16)ConfigReadInt(_T("MinViewRefreshInterval"), 200));
1914 msg.setField(VID_HELPDESK_LINK_ACTIVE, (UINT16)((g_flags & AF_HELPDESK_LINK_ACTIVE) ? 1 : 0));
1915 msg.setField(VID_ALARM_LIST_DISP_LIMIT, ConfigReadULong(_T("AlarmListDisplayLimit"), 4096));
1916 msg.setField(VID_SERVERCMD_TIMEOUT, ConfigReadULong(_T("ServerCommandOutputTimeout"), 60));
1917 debugPrintf(3, _T("User %s authenticated (language=%s clientInfo=\"%s\")"), m_sessionName, m_language, m_clientInfo);
1918 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0,
1919 _T("User \"%s\" logged in (language: %s; client info: %s)"), szLogin, m_language, m_clientInfo);
1920 }
1921 else
1922 {
1923 msg.setField(VID_RCC, dwResult);
1924 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, m_id, 0,
1925 _T("User \"%s\" login failed with error code %d (client info: %s)"),
1926 szLogin, dwResult, m_clientInfo);
1927 if (intruderLockout)
1928 {
1929 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, m_id, 0,
1930 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
1931 }
1932 }
1933 }
1934 else
1935 {
1936 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1937 }
1938
1939 // Send response
1940 sendMessage(&msg);
1941 }
1942
1943 /**
1944 * Send event configuration to client
1945 */
1946 void ClientSession::sendEventDB(UINT32 dwRqId)
1947 {
1948 NXCPMessage msg;
1949 TCHAR szBuffer[4096];
1950
1951 // Prepare response message
1952 msg.setCode(CMD_REQUEST_COMPLETED);
1953 msg.setId(dwRqId);
1954
1955 if (checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EPP))
1956 {
1957 if (!(g_flags & AF_DB_CONNECTION_LOST))
1958 {
1959 msg.setField(VID_RCC, RCC_SUCCESS);
1960 sendMessage(&msg);
1961 msg.deleteAllFields();
1962
1963 // Prepare data message
1964 msg.setCode(CMD_EVENT_DB_RECORD);
1965 msg.setId(dwRqId);
1966
1967 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1968 DB_UNBUFFERED_RESULT hResult = DBSelectUnbuffered(hdb, _T("SELECT event_code,event_name,severity,flags,message,description FROM event_cfg"));
1969 if (hResult != NULL)
1970 {
1971 while(DBFetch(hResult))
1972 {
1973 msg.setField(VID_EVENT_CODE, DBGetFieldULong(hResult, 0));
1974 msg.setField(VID_NAME, DBGetField(hResult, 1, szBuffer, 1024));
1975 msg.setField(VID_SEVERITY, DBGetFieldULong(hResult, 2));
1976 msg.setField(VID_FLAGS, DBGetFieldULong(hResult, 3));
1977
1978 DBGetField(hResult, 4, szBuffer, 4096);
1979 msg.setField(VID_MESSAGE, szBuffer);
1980
1981 DBGetField(hResult, 5, szBuffer, 4096);
1982 msg.setField(VID_DESCRIPTION, szBuffer);
1983
1984 sendMessage(&msg);
1985 msg.deleteAllFields();
1986 }
1987 DBFreeResult(hResult);
1988 }
1989 DBConnectionPoolReleaseConnection(hdb);
1990
1991 // End-of-list indicator
1992 msg.setField(VID_EVENT_CODE, (UINT32)0);
1993 msg.setEndOfSequence();
1994 }
1995 else
1996 {
1997 msg.setField(VID_RCC, RCC_DB_CONNECTION_LOST);
1998 }
1999 }
2000 else
2001 {
2002 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2003 }
2004 sendMessage(&msg);
2005 }
2006
2007 /**
2008 * Callback for sending event configuration change notifications
2009 */
2010 static void SendEventDBChangeNotification(ClientSession *session, void *arg)
2011 {
2012 if (session->isAuthenticated() &&
2013 (session->checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) ||
2014 session->checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) ||
2015 session->checkSysAccessRights(SYSTEM_ACCESS_EPP)))
2016 session->postMessage((NXCPMessage *)arg);
2017 }
2018
2019 /**
2020 * Update event template
2021 */
2022 void ClientSession::modifyEventTemplate(NXCPMessage *pRequest)
2023 {
2024 NXCPMessage msg;
2025
2026 // Prepare reply message
2027 msg.setCode(CMD_REQUEST_COMPLETED);
2028 msg.setId(pRequest->getId());
2029
2030 // Check access rights
2031 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
2032 {
2033 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2034
2035 // Check if event with specific code exists
2036 UINT32 dwEventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
2037 bool bEventExist = IsDatabaseRecordExist(hdb, _T("event_cfg"), _T("event_code"), dwEventCode);
2038
2039 // Check that we are not trying to create event below 100000
2040 if (bEventExist || (dwEventCode >= FIRST_USER_EVENT_ID))
2041 {
2042 // Prepare and execute SQL query
2043 TCHAR name[MAX_EVENT_NAME];
2044 pRequest->getFieldAsString(VID_NAME, name, MAX_EVENT_NAME);
2045 if (IsValidObjectName(name, TRUE))
2046 {
2047 DB_STATEMENT hStmt;
2048 if (bEventExist)
2049 {
2050 hStmt = DBPrepare(hdb, _T("UPDATE event_cfg SET event_name=?,severity=?,flags=?,message=?,description=? WHERE event_code=?"));
2051 }
2052 else
2053 {
2054 hStmt = DBPrepare(hdb, _T("INSERT INTO event_cfg (event_name,severity,flags,message,description,event_code) VALUES (?,?,?,?,?,?)"));
2055 }
2056
2057 if (hStmt != NULL)
2058 {
2059 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
2060 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, pRequest->getFieldAsInt32(VID_SEVERITY));
2061 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, pRequest->getFieldAsInt32(VID_FLAGS));
2062 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, pRequest->getFieldAsString(VID_MESSAGE), DB_BIND_DYNAMIC, MAX_EVENT_MSG_LENGTH - 1);
2063 DBBind(hStmt, 5, DB_SQLTYPE_TEXT, pRequest->getFieldAsString(VID_DESCRIPTION), DB_BIND_DYNAMIC);
2064 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, dwEventCode);
2065
2066 if (DBExecute(hStmt))
2067 {
2068 msg.setField(VID_RCC, RCC_SUCCESS);
2069 ReloadEvents();
2070
2071 NXCPMessage nmsg(pRequest);
2072 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2073 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_CHANGED);
2074 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2075 }
2076 else
2077 {
2078 msg.setField(VID_RCC, RCC_DB_FAILURE);
2079 }
2080 DBFreeStatement(hStmt);
2081 }
2082 else
2083 {
2084 msg.setField(VID_RCC, RCC_DB_FAILURE);
2085 }
2086 }
2087 else
2088 {
2089 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
2090 }
2091 }
2092 else
2093 {
2094 msg.setField(VID_RCC, RCC_INVALID_EVENT_CODE);
2095 }
2096 DBConnectionPoolReleaseConnection(hdb);
2097 }
2098 else
2099 {
2100 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2101 }
2102
2103 // Send response
2104 sendMessage(&msg);
2105 }
2106
2107 /**
2108 * Delete event template
2109 */
2110 void ClientSession::deleteEventTemplate(NXCPMessage *pRequest)
2111 {
2112 NXCPMessage msg;
2113 UINT32 dwEventCode;
2114
2115 // Prepare reply message
2116 msg.setCode(CMD_REQUEST_COMPLETED);
2117 msg.setId(pRequest->getId());
2118
2119 dwEventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
2120
2121 // Check access rights
2122 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
2123 {
2124 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2125 TCHAR szQuery[256];
2126 _sntprintf(szQuery, 256, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
2127 if (DBQuery(hdb, szQuery))
2128 {
2129 DeleteEventTemplateFromList(dwEventCode);
2130
2131 NXCPMessage nmsg;
2132 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2133 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_DELETED);
2134 nmsg.setField(VID_EVENT_CODE, dwEventCode);
2135 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2136
2137 msg.setField(VID_RCC, RCC_SUCCESS);
2138
2139 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Event template %d deleted"), dwEventCode);
2140 }
2141 else
2142 {
2143 msg.setField(VID_RCC, RCC_DB_FAILURE);
2144 }
2145 DBConnectionPoolReleaseConnection(hdb);
2146 }
2147 else
2148 {
2149 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2150 }
2151
2152 // Send response
2153 sendMessage(&msg);
2154 }
2155
2156 /**
2157 * Generate event code for new event template
2158 */
2159 void ClientSession::generateEventCode(UINT32 dwRqId)
2160 {
2161 NXCPMessage msg;
2162
2163 // Prepare reply message
2164 msg.setCode(CMD_REQUEST_COMPLETED);
2165 msg.setId(dwRqId);
2166
2167 // Check access rights
2168 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
2169 {
2170 msg.setField(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
2171 }
2172 else
2173 {
2174 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2175 }
2176
2177 // Send response
2178 sendMessage(&msg);
2179 }
2180
2181 /**
2182 * Send all objects to client
2183 */
2184 void ClientSession::sendAllObjects(NXCPMessage *pRequest)
2185 {
2186 NXCPMessage msg;
2187
2188 // Send confirmation message
2189 msg.setCode(CMD_REQUEST_COMPLETED);
2190 msg.setId(pRequest->getId());
2191 msg.setField(VID_RCC, RCC_SUCCESS);
2192 sendMessage(&msg);
2193 msg.deleteAllFields();
2194
2195 // Change "sync comments" flag
2196 if (pRequest->getFieldAsUInt16(VID_SYNC_COMMENTS))
2197 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2198 else
2199 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2200
2201 // Get client's last known time stamp
2202 UINT32 dwTimeStamp = pRequest->getFieldAsUInt32(VID_TIMESTAMP);
2203
2204 // Prepare message
2205 msg.setCode(CMD_OBJECT);
2206
2207 // Send objects, one per message
2208 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects(true);
2209 MutexLock(m_mutexSendObjects);
2210 for(int i = 0; i < objects->size(); i++)
2211 {
2212 NetObj *object = objects->get(i);
2213 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2214 (object->getTimeStamp() >= dwTimeStamp) &&
2215 !object->isHidden() && !object->isSystem())
2216 {
2217 object->fillMessage(&msg);
2218 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2219 object->commentsToMessage(&msg);
2220 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2221 {
2222 // mask passwords
2223 msg.setField(VID_SHARED_SECRET, _T("********"));
2224 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2225 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
2226 }
2227 sendMessage(&msg);
2228 msg.deleteAllFields();
2229 }
2230 object->decRefCount();
2231 }
2232 delete objects;
2233
2234 // Send end of list notification
2235 msg.setCode(CMD_OBJECT_LIST_END);
2236 sendMessage(&msg);
2237
2238 MutexUnlock(m_mutexSendObjects);
2239 }
2240
2241 /**
2242 * Send selected objects to client
2243 */
2244 void ClientSession::sendSelectedObjects(NXCPMessage *pRequest)
2245 {
2246 NXCPMessage msg;
2247
2248 // Send confirmation message
2249 msg.setCode(CMD_REQUEST_COMPLETED);
2250 msg.setId(pRequest->getId());
2251 msg.setField(VID_RCC, RCC_SUCCESS);
2252 sendMessage(&msg);
2253 msg.deleteAllFields();
2254
2255 // Change "sync comments" flag
2256 if (pRequest->getFieldAsBoolean(VID_SYNC_COMMENTS))
2257 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2258 else
2259 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2260
2261 UINT32 dwTimeStamp = pRequest->getFieldAsUInt32(VID_TIMESTAMP);
2262 UINT32 numObjects = pRequest->getFieldAsUInt32(VID_NUM_OBJECTS);
2263 UINT32 *objects = (UINT32 *)malloc(sizeof(UINT32) * numObjects);
2264 pRequest->getFieldAsInt32Array(VID_OBJECT_LIST, numObjects, objects);
2265 UINT32 options = pRequest->getFieldAsUInt16(VID_FLAGS);
2266
2267 MutexLock(m_mutexSendObjects);
2268
2269 // Prepare message
2270 msg.setCode((options & OBJECT_SYNC_SEND_UPDATES) ? CMD_OBJECT_UPDATE : CMD_OBJECT);
2271
2272 // Send objects, one per message
2273 for(UINT32 i = 0; i < numObjects; i++)
2274 {
2275 NetObj *object = FindObjectById(objects[i]);
2276 if ((object != NULL) &&
2277 object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2278 (object->getTimeStamp() >= dwTimeStamp) &&
2279 !object->isHidden() && !object->isSystem())
2280 {
2281 object->fillMessage(&msg);
2282 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2283 object->commentsToMessage(&msg);
2284 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2285 {
2286 // mask passwords
2287 msg.setField(VID_SHARED_SECRET, _T("********"));
2288 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2289 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
2290 }
2291 sendMessage(&msg);
2292 msg.deleteAllFields();
2293 }
2294 }
2295
2296 MutexUnlock(m_mutexSendObjects);
2297 safe_free(objects);
2298
2299 if (options & OBJECT_SYNC_DUAL_CONFIRM)
2300 {
2301 msg.setCode(CMD_REQUEST_COMPLETED);
2302 msg.setField(VID_RCC, RCC_SUCCESS);
2303 sendMessage(&msg);
2304 }
2305 }
2306
2307 /**
2308 * Send event log records to client
2309 */
2310 void ClientSession::sendEventLog(NXCPMessage *pRequest)
2311 {
2312 NXCPMessage msg;
2313 DB_RESULT hTempResult;
2314 UINT32 dwRqId, dwMaxRecords, dwNumRows, dwId;
2315 TCHAR szQuery[1024], szBuffer[1024];
2316 WORD wRecOrder;
2317
2318 dwRqId = pRequest->getId();
2319 dwMaxRecords = pRequest->getFieldAsUInt32(VID_MAX_RECORDS);
2320 wRecOrder = ((g_dbSyntax == DB_SYNTAX_MSSQL) || (g_dbSyntax == DB_SYNTAX_ORACLE)) ? RECORD_ORDER_REVERSED : RECORD_ORDER_NORMAL;
2321
2322 // Prepare confirmation message
2323 msg.setCode(CMD_REQUEST_COMPLETED);
2324 msg.setId(dwRqId);
2325
2326 MutexLock(m_mutexSendEvents);
2327 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2328
2329 // Retrieve events from database
2330 switch(g_dbSyntax)
2331 {
2332 case DB_SYNTAX_MYSQL:
2333 case DB_SYNTAX_PGSQL:
2334 case DB_SYNTAX_SQLITE:
2335 dwNumRows = 0;
2336 hTempResult = DBSelect(hdb, _T("SELECT count(*) FROM event_log"));
2337 if (hTempResult != NULL)
2338 {
2339 if (DBGetNumRows(hTempResult) > 0)
2340 {
2341 dwNumRows = DBGetFieldULong(hTempResult, 0, 0);
2342 }
2343 DBFreeResult(hTempResult);
2344 }
2345 _sntprintf(szQuery, 1024,
2346 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2347 _T("event_severity,event_message,user_tag FROM event_log ")
2348 _T("ORDER BY event_id LIMIT %u OFFSET %u"),
2349 dwMaxRecords, dwNumRows - min(dwNumRows, dwMaxRecords));
2350 break;
2351 case DB_SYNTAX_MSSQL:
2352 _sntprintf(szQuery, 1024,
2353 _T("SELECT TOP %u event_id,event_code,event_timestamp,event_source,")
2354 _T("event_severity,event_message,user_tag FROM event_log ")
2355 _T("ORDER BY event_id DESC"), dwMaxRecords);
2356 break;
2357 case DB_SYNTAX_ORACLE:
2358 _sntprintf(szQuery, 1024,
2359 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2360 _T("event_severity,event_message,user_tag FROM event_log ")
2361 _T("WHERE ROWNUM <= %u ORDER BY event_id DESC"), dwMaxRecords);
2362 break;
2363 case DB_SYNTAX_DB2:
2364 _sntprintf(szQuery, 1024,
2365 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2366 _T("event_severity,event_message,user_tag FROM event_log ")
2367 _T("ORDER BY event_id DESC FETCH FIRST %u ROWS ONLY"), dwMaxRecords);
2368 break;
2369 default:
2370 szQuery[0] = 0;
2371 break;
2372 }
2373 DB_UNBUFFERED_RESULT hResult = DBSelectUnbuffered(hdb, szQuery);
2374 if (hResult != NULL)
2375 {
2376 msg.setField(VID_RCC, RCC_SUCCESS);
2377 sendMessage(&msg);
2378 msg.deleteAllFields();
2379 msg.setCode(CMD_EVENTLOG_RECORDS);
2380
2381 for(dwId = VID_EVENTLOG_MSG_BASE, dwNumRows = 0; DBFetch(hResult); dwNumRows++)
2382 {
2383 if (dwNumRows == 10)
2384 {
2385 msg.setField(VID_NUM_RECORDS, dwNumRows);
2386 msg.setField(VID_RECORDS_ORDER, wRecOrder);
2387 sendMessage(&msg);
2388 msg.deleteAllFields();
2389 dwNumRows = 0;
2390 dwId = VID_EVENTLOG_MSG_BASE;
2391 }
2392 msg.setField(dwId++, DBGetFieldUInt64(hResult, 0));
2393 msg.setField(dwId++, DBGetFieldULong(hResult, 1));
2394 msg.setField(dwId++, DBGetFieldULong(hResult, 2));
2395 msg.setField(dwId++, DBGetFieldULong(hResult, 3));
2396 msg.setField(dwId++, (WORD)DBGetFieldLong(hResult, 4));
2397 DBGetField(hResult, 5, szBuffer, 1024);
2398 msg.setField(dwId++, szBuffer);
2399 DBGetField(hResult, 6, szBuffer, 1024);
2400 msg.setField(dwId++, szBuffer);
2401 msg.setField(dwId++, (UINT32)0); // Do not send parameters
2402 }
2403 DBFreeResult(hResult);
2404
2405 // Send remaining records with End-Of-Sequence notification
2406 msg.setField(VID_NUM_RECORDS, dwNumRows);
2407 msg.setField(VID_RECORDS_ORDER, wRecOrder);
2408 msg.setEndOfSequence();
2409 sendMessage(&msg);
2410 }
2411 else
2412 {
2413 msg.setField(VID_RCC, RCC_DB_FAILURE);
2414 sendMessage(&msg);
2415 }
2416
2417 DBConnectionPoolReleaseConnection(hdb);
2418 MutexUnlock(m_mutexSendEvents);
2419 }
2420
2421 /**
2422 * Send all configuration variables to client
2423 */
2424 void ClientSession::getConfigurationVariables(UINT32 dwRqId)
2425 {
2426 UINT32 i, dwId, dwNumRecords;
2427 NXCPMessage msg;
2428 TCHAR szBuffer[MAX_CONFIG_VALUE];
2429
2430 // Prepare message
2431 msg.setCode(CMD_REQUEST_COMPLETED);
2432 msg.setId(dwRqId);
2433
2434 // Check user rights
2435 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2436 {
2437 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2438
2439 // Retrieve configuration variables from database
2440 DB_RESULT hResult = DBSelect(hdb, _T("SELECT var_name,var_value,need_server_restart FROM config WHERE is_visible=1"));
2441 if (hResult != NULL)
2442 {
2443 // Send events, one per message
2444 dwNumRecords = DBGetNumRows(hResult);
2445 msg.setField(VID_NUM_VARIABLES, dwNumRecords);
2446 for(i = 0, dwId = VID_VARLIST_BASE; i < dwNumRecords; i++)
2447 {
2448 msg.setField(dwId++, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2449 DBGetField(hResult, i, 1, szBuffer, MAX_CONFIG_VALUE);
2450 DecodeSQLString(szBuffer);
2451 msg.setField(dwId++, szBuffer);
2452 msg.setField(dwId++, (WORD)DBGetFieldLong(hResult, i, 2));
2453 }
2454 DBFreeResult(hResult);
2455 }
2456 DBConnectionPoolReleaseConnection(hdb);
2457 msg.setField(VID_RCC, RCC_SUCCESS);
2458 }
2459 else
2460 {
2461 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2462 }
2463
2464 // Send response
2465 sendMessage(&msg);
2466 }
2467
2468 /**
2469 * Get public configuration variable by name
2470 */
2471 void ClientSession::getPublicConfigurationVariable(NXCPMessage *request)
2472 {
2473 NXCPMessage msg;
2474 msg.setCode(CMD_REQUEST_COMPLETED);
2475 msg.setId(request->getId());
2476
2477 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2478
2479 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config WHERE var_name=? AND is_public='Y'"));
2480 if (hStmt != NULL)
2481 {
2482 TCHAR name[64];
2483 request->getFieldAsString(VID_NAME, name, 64);
2484 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
2485
2486 DB_RESULT hResult = DBSelectPrepared(hStmt);
2487 if (hResult != NULL)
2488 {
2489 if (DBGetNumRows(hResult) > 0)
2490 {
2491 TCHAR value[MAX_CONFIG_VALUE];
2492 msg.setField(VID_VALUE, DBGetField(hResult, 0, 0, value, MAX_CONFIG_VALUE));
2493 msg.setField(VID_RCC, RCC_SUCCESS);
2494 }
2495 else
2496 {
2497 msg.setField(VID_RCC, RCC_UNKNOWN_CONFIG_VARIABLE);
2498 }
2499 DBFreeResult(hResult);
2500 }
2501 else
2502 {
2503 msg.setField(VID_RCC, RCC_DB_FAILURE);
2504 }
2505 DBFreeStatement(hStmt);
2506 }
2507 else
2508 {
2509 msg.setField(VID_RCC, RCC_DB_FAILURE);
2510 }
2511
2512 sendMessage(&msg);
2513 }
2514
2515 /**
2516 * Set configuration variable's value
2517 */
2518 void ClientSession::setConfigurationVariable(NXCPMessage *pRequest)
2519 {
2520 NXCPMessage msg;
2521 TCHAR szName[MAX_OBJECT_NAME], szValue[MAX_CONFIG_VALUE];
2522
2523 // Prepare response message
2524 msg.setCode(CMD_REQUEST_COMPLETED);
2525 msg.setId(pRequest->getId());
2526
2527 // Check user rights
2528 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2529 {
2530 pRequest->getFieldAsString(VID_NAME, szName, MAX_OBJECT_NAME);
2531 pRequest->getFieldAsString(VID_VALUE, szValue, MAX_CONFIG_VALUE);
2532 if (ConfigWriteStr(szName, szValue, true))
2533 {
2534 msg.setField(VID_RCC, RCC_SUCCESS);
2535 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
2536 _T("Server configuration variable \"%s\" set to \"%s\""), szName, szValue);
2537 }
2538 else
2539 {
2540 msg.setField(VID_RCC, RCC_DB_FAILURE);
2541 }
2542 }
2543 else
2544 {
2545 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2546 }
2547
2548 // Send response
2549 sendMessage(&msg);
2550 }
2551
2552 /**
2553 * Delete configuration variable
2554 */
2555 void ClientSession::deleteConfigurationVariable(NXCPMessage *pRequest)
2556 {
2557 NXCPMessage msg;
2558
2559 // Prepare response message
2560 msg.setCode(CMD_REQUEST_COMPLETED);
2561 msg.setId(pRequest->getId());
2562
2563 // Check user rights
2564 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2565 {
2566 TCHAR name[MAX_OBJECT_NAME];
2567 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2568 if (ConfigDelete(name))
2569 {
2570 msg.setField(VID_RCC, RCC_SUCCESS);
2571 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Server configuration variable \"%s\" deleted"), name);
2572 }
2573 else
2574 {
2575 msg.setField(VID_RCC, RCC_DB_FAILURE);
2576 }
2577 }
2578 else
2579 {
2580 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2581 }
2582
2583 // Send response
2584 sendMessage(&msg);
2585 }
2586
2587 /**
2588 * Set configuration clob
2589 */
2590 void ClientSession::setConfigCLOB(NXCPMessage *pRequest)
2591 {
2592 NXCPMessage msg;
2593 TCHAR name[MAX_OBJECT_NAME], *value;
2594
2595 msg.setId(pRequest->getId());
2596 msg.setCode(CMD_REQUEST_COMPLETED);
2597
2598 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2599 {
2600 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2601 value = pRequest->getFieldAsString(VID_VALUE);
2602 if (value != NULL)
2603 {
2604 if (ConfigWriteCLOB(name, value, TRUE))
2605 {
2606 msg.setField(VID_RCC, RCC_SUCCESS);
2607 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
2608 _T("Server configuration variable \"%s\" set to \"%s\""), name, value);
2609 free(value);
2610 }
2611 else
2612 {
2613 msg.setField(VID_RCC, RCC_DB_FAILURE);
2614 }
2615 }
2616 else
2617 {
2618 msg.setField(VID_RCC, RCC_INVALID_REQUEST);
2619 }
2620 }
2621 else
2622 {
2623 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2624 }
2625
2626 sendMessage(&msg);
2627 }
2628
2629 /**
2630 * Get value of configuration clob
2631 */
2632 void ClientSession::getConfigCLOB(NXCPMessage *pRequest)
2633 {
2634 NXCPMessage msg;
2635 TCHAR name[MAX_OBJECT_NAME], *value;
2636
2637 msg.setId(pRequest->getId());
2638 msg.setCode(CMD_REQUEST_COMPLETED);
2639
2640 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2641 {
2642 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2643 value = ConfigReadCLOB(name, NULL);
2644 if (value != NULL)
2645 {
2646 msg.setField(VID_VALUE, value);
2647 msg.setField(VID_RCC, RCC_SUCCESS);
2648 free(value);
2649 }
2650 else
2651 {
2652 msg.setField(VID_RCC, RCC_UNKNOWN_VARIABLE);
2653 }
2654 }
2655 else
2656 {
2657 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2658 }
2659
2660 sendMessage(&msg);
2661 }
2662
2663 /**
2664 * Close session
2665 */
2666 void ClientSession::kill()
2667 {
2668 notify(NX_NOTIFY_SESSION_KILLED);
2669
2670 // We shutdown socket connection, which will cause
2671 // read thread to stop, and other threads will follow
2672 shutdown(m_hSocket, 2);
2673 }
2674
2675 /**
2676 * Handler for new events
2677 */
2678 void ClientSession::onNewEvent(Event *pEvent)
2679 {
2680 UPDATE_INFO *pUpdate;
2681 NXCPMessage *msg;
2682 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_EVENTS) && (m_dwSystemAccess & SYSTEM_ACCESS_VIEW_EVENT_LOG))
2683 {
2684 NetObj *object = FindObjectById(pEvent->getSourceId());
2685 //If can't find object - just send to all events, if object found send to thous who have rights
2686 if (object == NULL || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2687 {
2688 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2689 pUpdate->dwCategory = INFO_CAT_EVENT;
2690 msg = new NXCPMessage;
2691 msg->setCode(CMD_EVENTLOG_RECORDS);
2692 pEvent->prepareMessage(msg);
2693 pUpdate->pData = msg;
2694 m_pUpdateQueue->put(pUpdate);
2695 }
2696 }
2697 }
2698
2699 /**
2700 * Handler for object changes
2701 */
2702 void ClientSession::onObjectChange(NetObj *object)
2703 {
2704 UPDATE_INFO *pUpdate;
2705
2706 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_OBJECTS))
2707 if (object->isDeleted() || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2708 {
2709 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2710 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
2711 pUpdate->pData = object;
2712 object->incRefCount();
2713 m_pUpdateQueue->put(pUpdate);
2714 }
2715 }
2716
2717 /**
2718 * Send notification message to server
2719 */
2720 void ClientSession::notify(UINT32 dwCode, UINT32 dwData)
2721 {
2722 NXCPMessage msg;
2723
2724 msg.setCode(CMD_NOTIFY);
2725 msg.setField(VID_NOTIFICATION_CODE, dwCode);
2726 msg.setField(VID_NOTIFICATION_DATA, dwData);
2727 sendMessage(&msg);
2728 }
2729
2730 static void SetNodesConflictString(NXCPMessage *msg, UINT32 zoneId, InetAddress ipAddr)
2731 {
2732 if(ipAddr.isValid())
2733 {
2734 TCHAR value[512];
2735
2736 Node *sameNode = FindNodeByIP(zoneId, ipAddr);
2737 Subnet *sameSubnet = FindSubnetByIP(zoneId, ipAddr);
2738 if(sameNode != NULL)
2739 {
2740 _sntprintf(value, 512, _T("%s"), sameNode->getName());
2741 }
2742 else if (sameSubnet != NULL)
2743 {
2744 _sntprintf(value, 512, _T("%s"), sameSubnet->getName());
2745 }
2746 else
2747 {
2748 _tcscpy(value, _T(""));
2749 }
2750 msg->setField(VID_VALUE, value);
2751 }
2752 }
2753
2754 /**
2755 * Modify object
2756 */
2757 void ClientSession::modifyObject(NXCPMessage *pRequest)
2758 {
2759 UINT32 dwObjectId, dwResult = RCC_SUCCESS;
2760 NetObj *object;
2761 NXCPMessage msg;
2762
2763 // Prepare reply message
2764 msg.setCode(CMD_REQUEST_COMPLETED);
2765 msg.setId(pRequest->getId());
2766
2767 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
2768 object = FindObjectById(dwObjectId);
2769 if (object != NULL)
2770 {
2771 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2772 {
2773 // If user attempts to change object's ACL, check
2774 // if he has OBJECT_ACCESS_ACL permission
2775 if (pRequest->isFieldExist(VID_ACL_SIZE))
2776 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
2777 dwResult = RCC_ACCESS_DENIED;
2778
2779 // If user attempts to rename object, check object's name
2780 if (pRequest->isFieldExist(VID_OBJECT_NAME))
2781 {
2782 TCHAR name[256];
2783 pRequest->getFieldAsString(VID_OBJECT_NAME, name, 256);
2784 if (!IsValidObjectName(name, TRUE))
2785 dwResult = RCC_INVALID_OBJECT_NAME;
2786 }
2787
2788 // If allowed, change object and set completion code
2789 if (dwResult == RCC_SUCCESS)
2790 {
2791 dwResult = object->modifyFromMessage(pRequest);
2792 if (dwResult == RCC_SUCCESS)
2793 {
2794 object->postModify();
2795 }
2796 else if (dwResult == RCC_ALREADY_EXIST)
2797 {
2798 //Add information about conflicting nodes
2799 InetAddress ipAddr;
2800
2801 if (pRequest->isFieldExist(VID_IP_ADDRESS))
2802 {
2803 ipAddr = pRequest->getFieldAsInetAddress(VID_IP_ADDRESS);
2804 } else if (pRequest->isFieldExist(VID_PRIMARY_NAME))
2805 {
2806 TCHAR primaryName[MAX_DNS_NAME];
2807 pRequest->getFieldAsString(VID_PRIMARY_NAME, primaryName, MAX_DNS_NAME);
2808 ipAddr = InetAddress::resolveHostName(primaryName);
2809 }
2810 SetNodesConflictString(&msg, ((Node*)object)->getZoneId(), ipAddr);
2811 }
2812 }
2813 msg.setField(VID_RCC, dwResult);
2814
2815 if (dwResult == RCC_SUCCESS)
2816 {
2817 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, dwObjectId,
2818 _T("Object %s modified from client"), object->getName());
2819 }
2820 else
2821 {
2822 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
2823 _T("Failed to modify object from client - error %d"), dwResult);
2824 }
2825 }
2826 else
2827 {
2828 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2829 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
2830 _T("Failed to modify object from client - access denied"), dwResult);
2831 }
2832 }
2833 else
2834 {
2835 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
2836 }
2837
2838 // Send response
2839 sendMessage(&msg);
2840 }
2841
2842 /**
2843 * Send users database to client
2844 */
2845 void ClientSession::sendUserDB(UINT32 dwRqId)
2846 {
2847 NXCPMessage msg;
2848 UserDatabaseObject **users;
2849 int i, userCount;
2850
2851 // Prepare response message
2852 msg.setCode(CMD_REQUEST_COMPLETED);
2853 msg.setId(dwRqId);
2854 msg.setField(VID_RCC, RCC_SUCCESS);
2855 sendMessage(&msg);
2856 msg.deleteAllFields();
2857
2858 // Send user database
2859 users = OpenUserDatabase(&userCount);
2860 for(i = 0; i < userCount; i++)
2861 {
2862 msg.setCode((users[i]->getId() & GROUP_FLAG) ? CMD_GROUP_DATA : CMD_USER_DATA);
2863 users[i]->fillMessage(&msg);
2864 sendMessage(&msg);
2865 msg.deleteAllFields();
2866 }
2867 CloseUserDatabase();
2868
2869 // Send end-of-database notification
2870 msg.setCode(CMD_USER_DB_EOF);
2871 sendMessage(&msg);
2872 }
2873
2874 /**
2875 * Create new user
2876 */
2877 void ClientSession::createUser(NXCPMessage *pRequest)
2878 {
2879 NXCPMessage msg;
2880
2881 // Prepare response message
2882 msg.setCode(CMD_REQUEST_COMPLETED);
2883 msg.setId(pRequest->getId());
2884
2885 // Check user rights
2886 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2887 {
2888 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2889 }
2890 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2891 {
2892 // User database have to be locked before any
2893 // changes to user database can be made
2894 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2895 }
2896 else
2897 {
2898 UINT32 dwResult, dwUserId;
2899 BOOL bIsGroup;
2900 TCHAR szUserName[MAX_USER_NAME];
2901
2902 pRequest->getFieldAsString(VID_USER_NAME, szUserName, MAX_USER_NAME);
2903 if (IsValidObjectName(szUserName))
2904 {
2905 bIsGroup = pRequest->getFieldAsUInt16(VID_IS_GROUP);
2906 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
2907 msg.setField(VID_RCC, dwResult);
2908 if (dwResult == RCC_SUCCESS)
2909 {
2910 msg.setField(VID_USER_ID, dwUserId); // Send id of new user to client
2911 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, dwUserId, _T("%s %s created"), bIsGroup ? _T("Group") : _T("User"), szUserName);
2912 }
2913 }
2914 else
2915 {
2916 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
2917 }
2918 }
2919
2920 // Send response
2921 sendMessage(&msg);
2922 }
2923
2924 /**
2925 * Update existing user's data
2926 */
2927 void ClientSession::updateUser(NXCPMessage *pRequest)
2928 {
2929 NXCPMessage msg;
2930
2931 // Prepare response message
2932 msg.setCode(CMD_REQUEST_COMPLETED);
2933 msg.setId(pRequest->getId());
2934
2935 // Check user rights
2936 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2937 {
2938 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2939 }
2940 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2941 {
2942 // User database have to be locked before any
2943 // changes to user database can be made
2944 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2945 }
2946 else
2947 {
2948 UINT32 result = ModifyUserDatabaseObject(pRequest);
2949 if (result == RCC_SUCCESS)
2950 {
2951 TCHAR name[MAX_DB_STRING];
2952 UINT32 id = pRequest->getFieldAsUInt32(VID_USER_ID);
2953 ResolveUserId(id, name, MAX_DB_STRING);
2954 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, id,
2955 _T("%s %s modified"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2956 }
2957 msg.setField(VID_RCC, result);
2958 }
2959
2960 // Send response
2961 sendMessage(&msg);
2962 }
2963
2964 /**
2965 * Delete user
2966 */
2967 void ClientSession::detachLdapUser(NXCPMessage *pRequest)
2968 {
2969 NXCPMessage msg;
2970
2971 // Prepare response message
2972 msg.setCode(CMD_REQUEST_COMPLETED);
2973 msg.setId(pRequest->getId());
2974 UINT32 id = pRequest->getFieldAsUInt32(VID_USER_ID);
2975
2976 // Check user rights
2977 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2978 {
2979 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2980 }
2981 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2982 {
2983 // User database have to be locked before any
2984 // changes to user database can be made
2985 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2986 }
2987 else
2988 {
2989 UINT32 result = DetachLdapUser(id);
2990 if (result == RCC_SUCCESS)
2991 {
2992 TCHAR name[MAX_DB_STRING];
2993 ResolveUserId(id, name, MAX_DB_STRING);
2994 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, id,
2995 _T("%s %s modified"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2996 }
2997 msg.setField(VID_RCC, result);
2998 }
2999
3000 // Send response
3001 sendMessage(&msg);
3002 }
3003
3004 /**
3005 * Delete user
3006 */
3007 void ClientSession::deleteUser(NXCPMessage *pRequest)
3008 {
3009 NXCPMessage msg;
3010 UINT32 dwUserId;
3011
3012 // Prepare response message
3013 msg.setCode(CMD_REQUEST_COMPLETED);
3014 msg.setId(pRequest->getId());
3015
3016 // Check user rights
3017 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
3018 {
3019 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3020 }
3021 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
3022 {
3023 // User database have to be locked before any
3024 // changes to user database can be made
3025 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3026 }
3027 else
3028 {
3029 // Get Id of user to be deleted
3030 dwUserId = pRequest->getFieldAsUInt32(VID_USER_ID);
3031
3032 if ((dwUserId != 0) && (dwUserId != GROUP_EVERYONE))
3033 {
3034 if (!IsLoggedIn(dwUserId))
3035 {
3036 TCHAR name[MAX_DB_STRING];
3037 ResolveUserId(dwUserId, name, MAX_DB_STRING);
3038 UINT32 rcc = DeleteUserDatabaseObject(dwUserId);
3039 msg.setField(VID_RCC, rcc);
3040 if(rcc == RCC_SUCCESS)
3041 {
3042 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, dwUserId,
3043 _T("%s %s [%d] deleted"), (dwUserId & GROUP_FLAG) ? _T("Group") : _T("User"), name, dwUserId);
3044 }
3045 }
3046 else
3047 {
3048 // logger in users cannot be deleted
3049 msg.setField(VID_RCC, RCC_USER_LOGGED_IN);
3050 }
3051 }
3052 else
3053 {
3054 // System administrator account and everyone group cannot be deleted
3055 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3056 }
3057 }
3058
3059 // Send response
3060 sendMessage(&msg);
3061 }
3062
3063 /**
3064 * Lock/unlock user database
3065 */
3066 void ClientSession::lockUserDB(UINT32 dwRqId, BOOL bLock)
3067 {
3068 NXCPMessage msg;
3069 TCHAR szBuffer[256];
3070
3071 // Prepare response message
3072 msg.setCode(CMD_REQUEST_COMPLETED);
3073 msg.setId(dwRqId);
3074
3075 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
3076 {
3077 if (bLock)
3078 {
3079 if (!LockComponent(CID_USER_DB, m_id, m_sessionName, NULL, szBuffer))
3080 {
3081 msg.setField(VID_RCC, RCC_COMPONENT_LOCKED);
3082 msg.setField(VID_LOCKED_BY, szBuffer);
3083 }
3084 else
3085 {
3086 m_dwFlags |= CSF_USER_DB_LOCKED;
3087 msg.setField(VID_RCC, RCC_SUCCESS);
3088 }
3089 }
3090 else
3091 {
3092 if (m_dwFlags & CSF_USER_DB_LOCKED)
3093 {
3094 UnlockComponent(CID_USER_DB);
3095 m_dwFlags &= ~CSF_USER_DB_LOCKED;
3096 }
3097 msg.setField(VID_RCC, RCC_SUCCESS);
3098 }
3099 }
3100 else
3101 {
3102 // Current user has no rights for user account management
3103 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3104 }
3105
3106 // Send response
3107 sendMessage(&msg);
3108 }
3109
3110 /**
3111 * Notify client on user database update
3112 */
3113 void ClientSession::onUserDBUpdate(int code, UINT32 id, UserDatabaseObject *object)
3114 {
3115 NXCPMessage msg;
3116
3117 if (isAuthenticated())
3118 {
3119 msg.setCode(CMD_USER_DB_UPDATE);
3120 msg.setId(0);
3121 msg.setField(VID_UPDATE_TYPE, (WORD)code);
3122
3123 switch(code)
3124 {
3125 case USER_DB_CREATE:
3126 case USER_DB_MODIFY:
3127 object->fillMessage(&msg);
3128 break;
3129 default:
3130 msg.setField(VID_USER_ID, id);
3131 break;
3132 }
3133
3134 sendMessage(&msg);
3135 }
3136 }
3137
3138 /**
3139 * Change management status for the object
3140 */
3141 void ClientSession::changeObjectMgmtStatus(NXCPMessage *pRequest)
3142 {
3143 NXCPMessage msg;
3144 UINT32 dwObjectId;
3145 NetObj *object;
3146
3147 // Prepare response message
3148 msg.setCode(CMD_REQUEST_COMPLETED);
3149 msg.setId(pRequest->getId());
3150
3151 // Get object id and check access rights
3152 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
3153 object = FindObjectById(dwObjectId);
3154 if (object != NULL)
3155 {
3156 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3157 {
3158 if ((object->getObjectClass() != OBJECT_TEMPLATE) &&
3159 (object->getObjectClass() != OBJECT_TEMPLATEGROUP) &&
3160 (object->getObjectClass() != OBJECT_TEMPLATEROOT))
3161 {
3162 BOOL bIsManaged = (BOOL)pRequest->getFieldAsUInt16(VID_MGMT_STATUS);
3163 object->setMgmtStatus(bIsManaged);
3164 msg.setField(VID_RCC, RCC_SUCCESS);
3165 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, object->getId(),
3166 _T("Object %s set to %s state"), object->getName(), bIsManaged ? _T("managed") : _T("unmanaged"));
3167 }
3168 else
3169 {
3170 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3171 }
3172 }
3173 else
3174 {
3175 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3176 }
3177 }
3178 else
3179 {
3180 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3181 }
3182
3183 // Send response
3184 sendMessage(&msg);
3185 }
3186
3187 /**
3188 * Enter maintenance mode for object
3189 */
3190 void ClientSession::enterMaintenanceMode(NXCPMessage *request)
3191 {
3192 NXCPMessage msg;
3193 msg.setCode(CMD_REQUEST_COMPLETED);
3194 msg.setId(request->getId());
3195
3196 // Get object id and check access rights
3197 NetObj *object = FindObjectById(request->getFieldAsUInt32(VID_OBJECT_ID));
3198 if (object != NULL)
3199 {
3200 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3201 {
3202 if ((object->getObjectClass() == OBJECT_CONTAINER) ||
3203 (object->getObjectClass() == OBJECT_CLUSTER) ||
3204 (object->getObjectClass() == OBJECT_NODE) ||
3205 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3206 (object->getObjectClass() == OBJECT_ACCESSPOINT) ||
3207 (object->getObjectClass() == OBJECT_ZONE) ||
3208 (object->getObjectClass() == OBJECT_SUBNET) ||
3209 (object->getObjectClass() == OBJECT_NETWORK) ||
3210 (object->getObjectClass() == OBJECT_SERVICEROOT))
3211 {
3212 object->enterMaintenanceMode();
3213 msg.setField(VID_RCC, RCC_SUCCESS);
3214 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, object->getId(),
3215 _T("Requested maintenance mode enter for object %s [%d]"), object->getName(), object->getId());
3216 }
3217 else
3218 {
3219 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3220 }
3221 }
3222 else
3223 {
3224 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3225 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, object->getId(),
3226 _T("Access denied on maintenance mode enter request for object %s [%d]"), object->getName(), object->getId());
3227 }
3228 }
3229 else
3230 {
3231 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3232 }
3233
3234 sendMessage(&msg);
3235 }
3236
3237 /**
3238 * Leave maintenance mode for object
3239 */
3240 void ClientSession::leaveMaintenanceMode(NXCPMessage *request)
3241 {
3242 NXCPMessage msg;
3243 msg.setCode(CMD_REQUEST_COMPLETED);
3244 msg.setId(request->getId());
3245
3246 // Get object id and check access rights
3247 NetObj *object = FindObjectById(request->getFieldAsUInt32(VID_OBJECT_ID));
3248 if (object != NULL)
3249 {
3250 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3251 {
3252 if ((object->getObjectClass() == OBJECT_CONTAINER) ||
3253 (object->getObjectClass() == OBJECT_CLUSTER) ||
3254 (object->getObjectClass() == OBJECT_NODE) ||
3255 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3256 (object->getObjectClass() == OBJECT_ACCESSPOINT) ||
3257 (object->getObjectClass() == OBJECT_ZONE) ||
3258 (object->getObjectClass() == OBJECT_SUBNET) ||
3259 (object->getObjectClass() == OBJECT_NETWORK) ||
3260 (object->getObjectClass() == OBJECT_SERVICEROOT))
3261 {
3262 object->leaveMaintenanceMode();
3263 msg.setField(VID_RCC, RCC_SUCCESS);
3264 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, object->getId(),
3265 _T("Requested maintenance mode exit for object %s [%d]"), object->getName(), object->getId());
3266 }
3267 else
3268 {
3269 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3270 }
3271 }
3272 else
3273 {
3274 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3275 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, object->getId(),
3276 _T("Access denied on maintenance mode exit request for object %s [%d]"), object->getName(), object->getId());
3277 }
3278 }
3279 else
3280 {
3281 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3282 }
3283
3284 sendMessage(&msg);
3285 }
3286
3287 /**
3288 * Validate password for currently logged in user
3289 */
3290 void ClientSession::validatePassword(NXCPMessage *request)
3291 {
3292 NXCPMessage msg;
3293 msg.setCode(CMD_REQUEST_COMPLETED);
3294 msg.setId(request->getId());
3295
3296 #ifdef UNICODE
3297 TCHAR password[256];
3298 request->getFieldAsString(VID_PASSWORD, password, 256);
3299 #else
3300 char password[256];
3301 request->getFieldAsUtf8String(VID_PASSWORD, password, 256);
3302 #endif
3303
3304 bool isValid = false;
3305 msg.setField(VID_RCC, ValidateUserPassword(m_dwUserId, m_loginName, password, &isValid));
3306 msg.setField(VID_PASSWORD_IS_VALID, (INT16)(isValid ? 1 : 0));
3307
3308 sendMessage(&msg);
3309 }
3310
3311 /**
3312 * Set user's password
3313 */
3314 void ClientSession::setPassword(NXCPMessage *request)
3315 {
3316 NXCPMessage msg;
3317 UINT32 dwUserId;
3318
3319 // Prepare response message
3320 msg.setCode(CMD_REQUEST_COMPLETED);
3321 msg.setId(request->getId());
3322
3323 dwUserId = request->getFieldAsUInt32(VID_USER_ID);
3324
3325 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
3326 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
3327 (dwUserId == m_dwUserId)) // User can change password for itself
3328 {
3329 UINT32 dwResult;
3330 TCHAR newPassword[1024], oldPassword[1024];
3331
3332 #ifdef UNICODE
3333 request->getFieldAsString(VID_PASSWORD, newPassword, 256);
3334 if (request->isFieldExist(VID_OLD_PASSWORD))
3335 request->getFieldAsString(VID_OLD_PASSWORD, oldPassword, 256);
3336 #else
3337 request->getFieldAsUtf8String(VID_PASSWORD, newPassword, 1024);
3338 if (request->isFieldExist(VID_OLD_PASSWORD))
3339 request->getFieldAsUtf8String(VID_OLD_PASSWORD, oldPassword, 1024);
3340 #endif
3341 else
3342 oldPassword[0] = 0;
3343 dwResult = SetUserPassword(dwUserId, newPassword, oldPassword, dwUserId == m_dwUserId);
3344 msg.setField(VID_RCC, dwResult);
3345
3346 if (dwResult == RCC_SUCCESS)
3347 {
3348 TCHAR userName[MAX_DB_STRING];
3349 ResolveUserId(dwUserId, userName, MAX_DB_STRING);
3350 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Changed password for user %s"), userName);
3351 }
3352 }
3353 else
3354 {
3355 // Current user has no rights to change password for specific user
3356 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3357 }
3358
3359 // Send response
3360 sendMessage(&msg);
3361 }
3362
3363 /**
3364 * Send node's DCIs to client and lock data collection settings
3365 */
3366 void ClientSession::openNodeDCIList(NXCPMessage *request)
3367 {
3368 NXCPMessage msg;
3369 UINT32 dwObjectId;
3370 NetObj *object;
3371 BOOL bSuccess = FALSE;
3372 TCHAR szLockInfo[MAX_SESSION_NAME];
3373
3374 // Prepare response message
3375 msg.setCode(CMD_REQUEST_COMPLETED);
3376 msg.setId(request->getId());
3377
3378 // Get node id and check object class and access rights
3379 dwObjectId = request->getFieldAsUInt32(VID_OBJECT_ID);
3380 object = FindObjectById(dwObjectId);
3381 if (object != NULL)
3382 {
3383 if ((object->getObjectClass() == OBJECT_NODE) ||
3384 (object->getObjectClass() == OBJECT_CLUSTER) ||
3385 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3386 (object->getObjectClass() == OBJECT_TEMPLATE))
3387 {
3388 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3389 {
3390 // Try to lock DCI list
3391 if (((Template *)object)->lockDCIList(m_id, m_sessionName, szLockInfo))
3392 {
3393 bSuccess = TRUE;
3394 msg.setField(VID_RCC, RCC_SUCCESS);
3395
3396 // modify list of open nodes DCI lists
3397 m_pOpenDCIList = (UINT32 *)realloc(m_pOpenDCIList, sizeof(UINT32) * (m_dwOpenDCIListSize + 1));
3398 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
3399 m_dwOpenDCIListSize++;
3400 }
3401 else
3402 {
3403 msg.setField(VID_RCC, RCC_COMPONENT_LOCKED);
3404 msg.setField(VID_LOCKED_BY, szLockInfo);
3405 }
3406 }
3407 else
3408 {
3409 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3410 }
3411 }
3412 else
3413 {
3414 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3415 }
3416 }
3417 else
3418 {
3419 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3420 }
3421
3422 // Send response
3423 sendMessage(&msg);
3424
3425 // If DCI list was successfully locked, send it to client
3426 if (bSuccess)
3427 ((Template *)object)->sendItemsToClient(this, request->getId());
3428 }
3429
3430 /**
3431 * Unlock node's data collection settings
3432 */
3433 void ClientSession::closeNodeDCIList(NXCPMessage *request)
3434 {
3435 NXCPMessage msg;
3436 UINT32 dwObjectId;
3437 NetObj *object;
3438
3439 // Prepare response message
3440 msg.setCode(CMD_REQUEST_COMPLETED);
3441 msg.setId(request->getId());
3442
3443 // Get node id and check object class and access rights
3444 dwObjectId = request->getFieldAsUInt32(VID_OBJECT_ID);
3445 object = FindObjectById(dwObjectId);
3446 if (object != NULL)
3447 {
3448 if ((object->getObjectClass() == OBJECT_NODE) ||
3449 (object->getObjectClass() == OBJECT_CLUSTER) ||
3450 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3451 (object->getObjectClass() == OBJECT_TEMPLATE))
3452 {
3453 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3454 {
3455 BOOL bSuccess;
3456
3457 // Try to unlock DCI list
3458 bSuccess = ((Template *)object)->unlockDCIList(m_id);
3459 msg.setField(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
3460
3461 // modify list of open nodes DCI lists
3462 if (bSuccess)
3463 {
3464 UINT32 i;
3465
3466 for(i = 0; i < m_dwOpenDCIListSize; i++)
3467 if (m_pOpenDCIList[i] == dwObjectId)
3468 {
3469 m_dwOpenDCIListSize--;
3470 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1], sizeof(UINT32) * (m_dwOpenDCIListSize - i));
3471 break;
3472 }
3473 }
3474 }
3475 else
3476 {
3477 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3478 }
3479 }
3480 else
3481 {
3482 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3483 }
3484 }
3485 else
3486 {
3487 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3488 }
3489
3490 // Send response
3491 sendMessage(&msg);
3492 }
3493
3494 /**
3495 * Create, modify, or delete data collection item for node
3496 */
3497 void ClientSession::modifyNodeDCI(NXCPMessage *request)
3498 {
3499 NXCPMessage msg;
3500 UINT32 dwObjectId;
3501 NetObj *object;
3502
3503 // Prepare response message
3504 msg.setCode(CMD_REQUEST_COMPLETED);
3505 msg.setId(request->getId());
3506
3507 // Get node id and check object class and access rights
3508 dwObjectId = request->getFieldAsUInt32(VID_OBJECT_ID);
3509 object = FindObjectById(dwObjectId);
3510 if (object != NULL)
3511 {
3512 if ((object->getObjectClass() == OBJECT_NODE) ||
3513 (object->getObjectClass() == OBJECT_CLUSTER) ||
3514 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3515 (object->getObjectClass() == OBJECT_TEMPLATE))
3516 {
3517 if (((Template *)object)->isLockedBySession(m_id))
3518 {
3519 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3520 {
3521 UINT32 i, dwItemId, dwNumMaps, *pdwMapId, *pdwMapIndex;
3522 DCObject *dcObject;
3523 BOOL bSuccess = FALSE;
3524
3525 int dcObjectType = (int)request->getFieldAsUInt16(VID_DCOBJECT_TYPE);
3526 switch(request->getCode())
3527 {
3528 case CMD_CREATE_NEW_DCI:
3529 // Create dummy DCI
3530 switch(dcObjectType)
3531 {
3532 case DCO_TYPE_ITEM:
3533 dcObject = new DCItem(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL, DCI_DT_INT,
3534 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3535 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3536 break;
3537 case DCO_TYPE_TABLE:
3538 dcObject = new DCTable(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL,
3539 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3540 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3541 break;
3542 default:
3543 dcObject = NULL;
3544 break;
3545 }
3546 if (dcObject != NULL)
3547 {
3548 dcObject->setStatus(ITEM_STATUS_DISABLED, false);
3549 if ((bSuccess = ((Template *)object)->addDCObject(dcObject)))
3550 {
3551 msg.setField(VID_RCC, RCC_SUCCESS);
3552 // Return new item id to client
3553 msg.setField(VID_DCI_ID, dcObject->getId());
3554 }
3555 else // Unable to add item to node
3556 {
3557 delete dcObject;
3558 msg.setField(VID_RCC, RCC_DUPLICATE_DCI);
3559 }
3560 }
3561 else
3562 {
3563 msg.setField(VID_RCC, RCC_INVALID_ARGUMENT);
3564 }
3565 break;
3566 case CMD_MODIFY_NODE_DCI:
3567 dwItemId = request->getFieldAsUInt32(VID_DCI_ID);
3568 bSuccess = ((Template *)object)->updateDCObject(dwItemId, request, &dwNumMaps, &pdwMapIndex, &pdwMapId);
3569 if (bSuccess)
3570 {
3571 msg.setField(VID_RCC, RCC_SUCCESS);
3572
3573 // Send index to id mapping for newly created thresholds to client
3574 if (dcObjectType == DCO_TYPE_ITEM)
3575 {
3576 msg.setField(VID_DCI_NUM_MAPS, dwNumMaps);
3577 for(i = 0; i < dwNumMaps; i++)
3578 {
3579 pdwMapId[i] = htonl(pdwMapId[i]);
3580 pdwMapIndex[i] = htonl(pdwMapIndex[i]);
3581 }
3582 msg.setField(VID_DCI_MAP_IDS, (BYTE *)pdwMapId, sizeof(UINT32) * dwNumMaps);
3583 msg.setField(VID_DCI_MAP_INDEXES, (BYTE *)pdwMapIndex, sizeof(UINT32) * dwNumMaps);
3584 safe_free(pdwMapId);
3585 safe_free(pdwMapIndex);
3586 }
3587 }
3588 else
3589 {
3590 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3591 }
3592 break;
3593 case CMD_DELETE_NODE_DCI:
3594 dwItemId = request->getFieldAsUInt32(VID_DCI_ID);
3595 bSuccess = ((Template *)object)->deleteDCObject(dwItemId, true);
3596 msg.setField(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_INVALID_DCI_ID);
3597 break;
3598 }
3599 if (bSuccess)
3600 ((Template *)object)->setDCIModificationFlag();
3601 }
3602 else // User doesn't have MODIFY rights on object
3603 {
3604 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3605 }
3606 }
3607 else // Nodes DCI list not locked by this session
3608 {
3609 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3610 }
3611 }
3612 else // Object is not a node
3613 {
3614 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3615 }
3616 }
3617 else // No object with given ID
3618 {
3619 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3620 }
3621
3622 // Send response
3623 sendMessage(&msg);
3624 }
3625
3626 /**
3627 * Change status for one or more DCIs
3628 */
3629 void ClientSession::changeDCIStatus(NXCPMessage *request)
3630 {
3631 NXCPMessage msg;
3632 NetObj *object;
3633
3634 // Prepare response message
3635 msg.setCode(CMD_REQUEST_COMPLETED);
3636 msg.setId(request->getId());
3637
3638 // Get node id and check object class and access rights
3639 object = FindObjectById(request->getFieldAsUInt32(VID_OBJECT_ID));
3640 if (object != NULL)
3641 {
3642 if ((object->getObjectClass() == OBJECT_NODE) ||
3643 (object->getObjectClass() == OBJECT_CLUSTER) ||
3644 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3645 (object->getObjectClass() == OBJECT_TEMPLATE))
3646 {
3647 if (((Template *)object)->isLockedBySession(m_id))
3648 {
3649 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3650 {
3651 UINT32 dwNumItems, *pdwItemList;
3652 int iStatus;
3653
3654 iStatus = request->getFieldAsUInt16(VID_DCI_STATUS);
3655 dwNumItems = request->getFieldAsUInt32(VID_NUM_ITEMS);
3656 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * dwNumItems);
3657 request->getFieldAsInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3658 if (((Template *)object)->setItemStatus(dwNumItems, pdwItemList, iStatus))
3659 msg.setField(VID_RCC, RCC_SUCCESS);
3660 else
3661 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3662 free(pdwItemList);
3663 }
3664 else // User doesn't have MODIFY rights on object
3665 {
3666 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3667 }
3668 }
3669 else // Nodes DCI list not locked by this session
3670 {
3671 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3672 }
3673 }
3674 else // Object is not a node
3675 {
3676 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3677 }
3678 }
3679 else // No object with given ID
3680 {
3681 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3682 }
3683
3684 // Send response
3685 sendMessage(&msg);
3686 }
3687
3688 /**
3689 * Clear all collected data for DCI
3690 */
3691 void ClientSession::clearDCIData(NXCPMessage *request)
3692 {
3693 NXCPMessage msg;
3694 NetObj *object;
3695 UINT32 dwItemId;
3696
3697 // Prepare response message
3698 msg.setCode(CMD_REQUEST_COMPLETED);
3699 msg.setId(request->getId());
3700
3701 // Get node id and check object class and access rights
3702 object = FindObjectById(request->getFieldAsUInt32(VID_OBJECT_ID));
3703 if (object != NULL)
3704 {
3705 if ((object->getObjectClass() == OBJECT_NODE) || (object->getObjectClass() == OBJECT_MOBILEDEVICE) || (object->getObjectClass() == OBJECT_CLUSTER))
3706 {