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