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