"alarm details" view mostly working; event history for active alarms preserved; minor...
[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_GET_ALARM_EVENTS:
867 getAlarmEvents(pMsg);
868 break;
869 case CMD_ACK_ALARM:
870 acknowledgeAlarm(pMsg);
871 break;
872 case CMD_RESOLVE_ALARM:
873 resolveAlarm(pMsg, false);
874 break;
875 case CMD_TERMINATE_ALARM:
876 resolveAlarm(pMsg, true);
877 break;
878 case CMD_DELETE_ALARM:
879 deleteAlarm(pMsg);
880 break;
881 case CMD_CREATE_ACTION:
882 createAction(pMsg);
883 break;
884 case CMD_MODIFY_ACTION:
885 updateAction(pMsg);
886 break;
887 case CMD_DELETE_ACTION:
888 deleteAction(pMsg);
889 break;
890 case CMD_LOAD_ACTIONS:
891 sendAllActions(pMsg->GetId());
892 break;
893 case CMD_GET_CONTAINER_CAT_LIST:
894 SendContainerCategories(pMsg->GetId());
895 break;
896 case CMD_DELETE_OBJECT:
897 deleteObject(pMsg);
898 break;
899 case CMD_POLL_NODE:
900 forcedNodePoll(pMsg);
901 break;
902 case CMD_TRAP:
903 onTrap(pMsg);
904 break;
905 case CMD_WAKEUP_NODE:
906 onWakeUpNode(pMsg);
907 break;
908 case CMD_CREATE_TRAP:
909 EditTrap(TRAP_CREATE, pMsg);
910 break;
911 case CMD_MODIFY_TRAP:
912 EditTrap(TRAP_UPDATE, pMsg);
913 break;
914 case CMD_DELETE_TRAP:
915 EditTrap(TRAP_DELETE, pMsg);
916 break;
917 case CMD_LOAD_TRAP_CFG:
918 SendAllTraps(pMsg->GetId());
919 break;
920 case CMD_GET_TRAP_CFG_RO:
921 SendAllTraps2(pMsg->GetId());
922 break;
923 case CMD_QUERY_PARAMETER:
924 CALL_IN_NEW_THREAD(queryParameter, pMsg);
925 break;
926 case CMD_LOCK_PACKAGE_DB:
927 LockPackageDB(pMsg->GetId(), TRUE);
928 break;
929 case CMD_UNLOCK_PACKAGE_DB:
930 LockPackageDB(pMsg->GetId(), FALSE);
931 break;
932 case CMD_GET_PACKAGE_LIST:
933 SendAllPackages(pMsg->GetId());
934 break;
935 case CMD_INSTALL_PACKAGE:
936 InstallPackage(pMsg);
937 break;
938 case CMD_REMOVE_PACKAGE:
939 RemovePackage(pMsg);
940 break;
941 case CMD_GET_PARAMETER_LIST:
942 SendParametersList(pMsg);
943 break;
944 case CMD_DEPLOY_PACKAGE:
945 DeployPackage(pMsg);
946 break;
947 case CMD_GET_LAST_VALUES:
948 getLastValues(pMsg);
949 break;
950 case CMD_GET_TABLE_LAST_VALUES:
951 getTableLastValues(pMsg);
952 break;
953 case CMD_GET_THRESHOLD_SUMMARY:
954 getThresholdSummary(pMsg);
955 break;
956 case CMD_GET_USER_VARIABLE:
957 GetUserVariable(pMsg);
958 break;
959 case CMD_SET_USER_VARIABLE:
960 SetUserVariable(pMsg);
961 break;
962 case CMD_DELETE_USER_VARIABLE:
963 DeleteUserVariable(pMsg);
964 break;
965 case CMD_ENUM_USER_VARIABLES:
966 EnumUserVariables(pMsg);
967 break;
968 case CMD_COPY_USER_VARIABLE:
969 CopyUserVariable(pMsg);
970 break;
971 case CMD_CHANGE_ZONE:
972 changeObjectZone(pMsg);
973 break;
974 case CMD_REQUEST_ENCRYPTION:
975 setupEncryption(pMsg);
976 break;
977 case CMD_GET_AGENT_CONFIG:
978 getAgentConfig(pMsg);
979 break;
980 case CMD_UPDATE_AGENT_CONFIG:
981 updateAgentConfig(pMsg);
982 break;
983 case CMD_EXECUTE_ACTION:
984 CALL_IN_NEW_THREAD(executeAction, pMsg);
985 break;
986 case CMD_GET_OBJECT_TOOLS:
987 sendObjectTools(pMsg->GetId());
988 break;
989 case CMD_EXEC_TABLE_TOOL:
990 execTableTool(pMsg);
991 break;
992 case CMD_GET_OBJECT_TOOL_DETAILS:
993 sendObjectToolDetails(pMsg);
994 break;
995 case CMD_UPDATE_OBJECT_TOOL:
996 updateObjectTool(pMsg);
997 break;
998 case CMD_DELETE_OBJECT_TOOL:
999 deleteObjectTool(pMsg);
1000 break;
1001 case CMD_GENERATE_OBJECT_TOOL_ID:
1002 generateObjectToolId(pMsg->GetId());
1003 break;
1004 case CMD_CHANGE_SUBSCRIPTION:
1005 changeSubscription(pMsg);
1006 break;
1007 case CMD_GET_SYSLOG:
1008 CALL_IN_NEW_THREAD(sendSyslog, pMsg);
1009 break;
1010 case CMD_GET_SERVER_STATS:
1011 sendServerStats(pMsg->GetId());
1012 break;
1013 case CMD_GET_SCRIPT_LIST:
1014 sendScriptList(pMsg->GetId());
1015 break;
1016 case CMD_GET_SCRIPT:
1017 sendScript(pMsg);
1018 break;
1019 case CMD_UPDATE_SCRIPT:
1020 updateScript(pMsg);
1021 break;
1022 case CMD_RENAME_SCRIPT:
1023 renameScript(pMsg);
1024 break;
1025 case CMD_DELETE_SCRIPT:
1026 deleteScript(pMsg);
1027 break;
1028 case CMD_GET_SESSION_LIST:
1029 SendSessionList(pMsg->GetId());
1030 break;
1031 case CMD_KILL_SESSION:
1032 KillSession(pMsg);
1033 break;
1034 case CMD_GET_TRAP_LOG:
1035 SendTrapLog(pMsg);
1036 break;
1037 case CMD_START_SNMP_WALK:
1038 StartSnmpWalk(pMsg);
1039 break;
1040 case CMD_RESOLVE_DCI_NAMES:
1041 ResolveDCINames(pMsg);
1042 break;
1043 case CMD_GET_DCI_INFO:
1044 SendDCIInfo(pMsg);
1045 break;
1046 case CMD_GET_DCI_THRESHOLDS:
1047 sendDCIThresholds(pMsg);
1048 break;
1049 case CMD_GET_DCI_EVENTS_LIST:
1050 sendDCIEventList(pMsg);
1051 break;
1052 case CMD_GET_PERFTAB_DCI_LIST:
1053 sendPerfTabDCIList(pMsg);
1054 break;
1055 case CMD_PUSH_DCI_DATA:
1056 pushDCIData(pMsg);
1057 break;
1058 case CMD_GET_AGENT_CFG_LIST:
1059 SendAgentCfgList(pMsg->GetId());
1060 break;
1061 case CMD_OPEN_AGENT_CONFIG:
1062 OpenAgentConfig(pMsg);
1063 break;
1064 case CMD_SAVE_AGENT_CONFIG:
1065 SaveAgentConfig(pMsg);
1066 break;
1067 case CMD_DELETE_AGENT_CONFIG:
1068 DeleteAgentConfig(pMsg);
1069 break;
1070 case CMD_SWAP_AGENT_CONFIGS:
1071 SwapAgentConfigs(pMsg);
1072 break;
1073 case CMD_GET_OBJECT_COMMENTS:
1074 SendObjectComments(pMsg);
1075 break;
1076 case CMD_UPDATE_OBJECT_COMMENTS:
1077 updateObjectComments(pMsg);
1078 break;
1079 case CMD_GET_ADDR_LIST:
1080 getAddrList(pMsg);
1081 break;
1082 case CMD_SET_ADDR_LIST:
1083 setAddrList(pMsg);
1084 break;
1085 case CMD_RESET_COMPONENT:
1086 resetComponent(pMsg);
1087 break;
1088 case CMD_EXPORT_CONFIGURATION:
1089 exportConfiguration(pMsg);
1090 break;
1091 case CMD_IMPORT_CONFIGURATION:
1092 importConfiguration(pMsg);
1093 break;
1094 case CMD_GET_GRAPH_LIST:
1095 SendGraphList(pMsg->GetId());
1096 break;
1097 case CMD_DEFINE_GRAPH:
1098 DefineGraph(pMsg);
1099 break;
1100 case CMD_DELETE_GRAPH:
1101 DeleteGraph(pMsg);
1102 break;
1103 case CMD_ADD_CA_CERTIFICATE:
1104 AddCACertificate(pMsg);
1105 break;
1106 case CMD_DELETE_CERTIFICATE:
1107 DeleteCertificate(pMsg);
1108 break;
1109 case CMD_UPDATE_CERT_COMMENTS:
1110 UpdateCertificateComments(pMsg);
1111 break;
1112 case CMD_GET_CERT_LIST:
1113 SendCertificateList(pMsg->GetId());
1114 break;
1115 case CMD_QUERY_L2_TOPOLOGY:
1116 CALL_IN_NEW_THREAD(queryL2Topology, pMsg);
1117 break;
1118 case CMD_SEND_SMS:
1119 sendSMS(pMsg);
1120 break;
1121 case CMD_GET_COMMUNITY_LIST:
1122 SendCommunityList(pMsg->GetId());
1123 break;
1124 case CMD_UPDATE_COMMUNITY_LIST:
1125 UpdateCommunityList(pMsg);
1126 break;
1127 case CMD_GET_USM_CREDENTIALS:
1128 sendUsmCredentials(pMsg->GetId());
1129 break;
1130 case CMD_UPDATE_USM_CREDENTIALS:
1131 updateUsmCredentials(pMsg);
1132 break;
1133 case CMD_GET_SITUATION_LIST:
1134 SendSituationList(pMsg->GetId());
1135 break;
1136 case CMD_CREATE_SITUATION:
1137 CreateSituation(pMsg);
1138 break;
1139 case CMD_UPDATE_SITUATION:
1140 UpdateSituation(pMsg);
1141 break;
1142 case CMD_DELETE_SITUATION:
1143 DeleteSituation(pMsg);
1144 break;
1145 case CMD_DEL_SITUATION_INSTANCE:
1146 DeleteSituationInstance(pMsg);
1147 break;
1148 case CMD_REGISTER_AGENT:
1149 registerAgent(pMsg);
1150 break;
1151 case CMD_GET_SERVER_FILE:
1152 CALL_IN_NEW_THREAD(getServerFile, pMsg);
1153 break;
1154 case CMD_GET_AGENT_FILE:
1155 CALL_IN_NEW_THREAD(getAgentFile, pMsg);
1156 break;
1157 case CMD_TEST_DCI_TRANSFORMATION:
1158 testDCITransformation(pMsg);
1159 break;
1160 case CMD_GET_JOB_LIST:
1161 sendJobList(pMsg->GetId());
1162 break;
1163 case CMD_CANCEL_JOB:
1164 cancelJob(pMsg);
1165 break;
1166 case CMD_HOLD_JOB:
1167 holdJob(pMsg);
1168 break;
1169 case CMD_UNHOLD_JOB:
1170 unholdJob(pMsg);
1171 break;
1172 case CMD_DEPLOY_AGENT_POLICY:
1173 deployAgentPolicy(pMsg, false);
1174 break;
1175 case CMD_UNINSTALL_AGENT_POLICY:
1176 deployAgentPolicy(pMsg, true);
1177 break;
1178 case CMD_GET_CURRENT_USER_ATTR:
1179 getUserCustomAttribute(pMsg);
1180 break;
1181 case CMD_SET_CURRENT_USER_ATTR:
1182 setUserCustomAttribute(pMsg);
1183 break;
1184 case CMD_OPEN_SERVER_LOG:
1185 openServerLog(pMsg);
1186 break;
1187 case CMD_CLOSE_SERVER_LOG:
1188 closeServerLog(pMsg);
1189 break;
1190 case CMD_QUERY_LOG:
1191 CALL_IN_NEW_THREAD(queryServerLog, pMsg);
1192 break;
1193 case CMD_GET_LOG_DATA:
1194 CALL_IN_NEW_THREAD(getServerLogQueryData, pMsg);
1195 break;
1196 case CMD_FIND_NODE_CONNECTION:
1197 CALL_IN_NEW_THREAD(findNodeConnection, pMsg);
1198 break;
1199 case CMD_FIND_MAC_LOCATION:
1200 CALL_IN_NEW_THREAD(findMacAddress, pMsg);
1201 break;
1202 case CMD_FIND_IP_LOCATION:
1203 CALL_IN_NEW_THREAD(findIpAddress, pMsg);
1204 break;
1205 case CMD_GET_IMAGE:
1206 sendLibraryImage(pMsg);
1207 break;
1208 case CMD_CREATE_IMAGE:
1209 updateLibraryImage(pMsg);
1210 break;
1211 case CMD_DELETE_IMAGE:
1212 deleteLibraryImage(pMsg);
1213 break;
1214 case CMD_MODIFY_IMAGE:
1215 updateLibraryImage(pMsg);
1216 break;
1217 case CMD_LIST_IMAGES:
1218 listLibraryImages(pMsg);
1219 break;
1220 case CMD_EXECUTE_SERVER_COMMAND:
1221 executeServerCommand(pMsg);
1222 break;
1223 case CMD_LIST_SERVER_FILES:
1224 listServerFileStore(pMsg);
1225 break;
1226 case CMD_UPLOAD_FILE_TO_AGENT:
1227 uploadFileToAgent(pMsg);
1228 break;
1229 case CMD_UPLOAD_FILE:
1230 receiveFile(pMsg);
1231 break;
1232 case CMD_DELETE_FILE:
1233 deleteFile(pMsg);
1234 break;
1235 case CMD_OPEN_CONSOLE:
1236 openConsole(pMsg->GetId());
1237 break;
1238 case CMD_CLOSE_CONSOLE:
1239 closeConsole(pMsg->GetId());
1240 break;
1241 case CMD_ADM_REQUEST:
1242 CALL_IN_NEW_THREAD(processConsoleCommand, pMsg);
1243 break;
1244 case CMD_GET_VLANS:
1245 getVlans(pMsg);
1246 break;
1247 case CMD_EXECUTE_REPORT:
1248 executeReport(pMsg);
1249 break;
1250 case CMD_GET_REPORT_RESULTS:
1251 CALL_IN_NEW_THREAD(getReportResults, pMsg);
1252 break;
1253 case CMD_DELETE_REPORT_RESULTS:
1254 CALL_IN_NEW_THREAD(deleteReportResults, pMsg);
1255 break;
1256 case CMD_RENDER_REPORT:
1257 CALL_IN_NEW_THREAD(renderReport, pMsg);
1258 break;
1259 case CMD_GET_NETWORK_PATH:
1260 CALL_IN_NEW_THREAD(getNetworkPath, pMsg);
1261 break;
1262 case CMD_GET_NODE_COMPONENTS:
1263 getNodeComponents(pMsg);
1264 break;
1265 default:
1266 // Pass message to loaded modules
1267 for(i = 0; i < g_dwNumModules; i++)
1268 {
1269 if (g_pModuleList[i].pfClientCommandHandler != NULL)
1270 {
1271 status = g_pModuleList[i].pfClientCommandHandler(m_wCurrentCmd, pMsg, this);
1272 if (status != NXMOD_COMMAND_IGNORED)
1273 {
1274 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
1275 {
1276 pMsg = NULL; // Prevent deletion
1277 m_dwRefCount++;
1278 }
1279 break; // Message was processed by the module
1280 }
1281 }
1282 }
1283 if (i == g_dwNumModules)
1284 {
1285 CSCPMessage response;
1286
1287 response.SetId(pMsg->GetId());
1288 response.SetCode(CMD_REQUEST_COMPLETED);
1289 response.SetVariable(VID_RCC, RCC_NOT_IMPLEMENTED);
1290 sendMessage(&response);
1291 }
1292 break;
1293 }
1294 delete pMsg;
1295 m_iState = (m_dwFlags & CSF_AUTHENTICATED) ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
1296 }
1297 }
1298
1299 /**
1300 * Respond to client's keepalive message
1301 */
1302 void ClientSession::respondToKeepalive(DWORD dwRqId)
1303 {
1304 CSCPMessage msg;
1305
1306 msg.SetCode(CMD_REQUEST_COMPLETED);
1307 msg.SetId(dwRqId);
1308 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1309 sendMessage(&msg);
1310 }
1311
1312 /**
1313 * Process received file
1314 */
1315 void ClientSession::onFileUpload(BOOL bSuccess)
1316 {
1317 // Do processing specific to command initiated file upload
1318 switch(m_dwUploadCommand)
1319 {
1320 case CMD_INSTALL_PACKAGE:
1321 if (!bSuccess)
1322 {
1323 TCHAR szQuery[256];
1324
1325 _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_dwUploadData);
1326 DBQuery(g_hCoreDB, szQuery);
1327 }
1328 break;
1329 default:
1330 break;
1331 }
1332
1333 // Remove received file in case of failure
1334 if (!bSuccess)
1335 _tunlink(m_szCurrFileName);
1336 }
1337
1338 /**
1339 * Send message to client
1340 */
1341 void ClientSession::sendMessage(CSCPMessage *msg)
1342 {
1343 TCHAR szBuffer[128];
1344 BOOL bResult;
1345
1346 if (msg->GetCode() != CMD_ADM_MESSAGE)
1347 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(msg->GetCode(), szBuffer));
1348
1349 CSCP_MESSAGE *pRawMsg = msg->CreateMessage();
1350 if (m_pCtx != NULL)
1351 {
1352 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
1353 if (pEnMsg != NULL)
1354 {
1355 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
1356 free(pEnMsg);
1357 }
1358 else
1359 {
1360 bResult = FALSE;
1361 }
1362 }
1363 else
1364 {
1365 bResult = (SendEx(m_hSocket, (const char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
1366 }
1367 free(pRawMsg);
1368
1369 if (!bResult)
1370 {
1371 closesocket(m_hSocket);
1372 m_hSocket = -1;
1373 }
1374 }
1375
1376 /**
1377 * Send raw message to client
1378 */
1379 void ClientSession::sendRawMessage(CSCP_MESSAGE *msg)
1380 {
1381 TCHAR szBuffer[128];
1382 BOOL bResult;
1383
1384 debugPrintf(6, _T("Sending raw message %s"), NXCPMessageCodeName(ntohs(msg->wCode), szBuffer));
1385 if (m_pCtx != NULL)
1386 {
1387 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(m_pCtx, msg);
1388 if (pEnMsg != NULL)
1389 {
1390 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
1391 free(pEnMsg);
1392 }
1393 else
1394 {
1395 bResult = FALSE;
1396 }
1397 }
1398 else
1399 {
1400 bResult = (SendEx(m_hSocket, (const char *)msg, ntohl(msg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(msg->dwSize));
1401 }
1402
1403 if (!bResult)
1404 {
1405 closesocket(m_hSocket);
1406 m_hSocket = -1;
1407 }
1408 }
1409
1410 /**
1411 * Send file to client
1412 */
1413 BOOL ClientSession::sendFile(const TCHAR *file, DWORD dwRqId)
1414 {
1415 return SendFileOverNXCP(m_hSocket, dwRqId, file, m_pCtx, 0, NULL, NULL, m_mutexSocketWrite);
1416 }
1417
1418 /**
1419 * Send server information to client
1420 */
1421 void ClientSession::sendServerInfo(DWORD dwRqId)
1422 {
1423 CSCPMessage msg;
1424 TCHAR szBuffer[1024];
1425 String strURL;
1426
1427 // Prepare response message
1428 msg.SetCode(CMD_REQUEST_COMPLETED);
1429 msg.SetId(dwRqId);
1430
1431 // Generate challenge for certificate authentication
1432 #ifdef _WITH_ENCRYPTION
1433 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
1434 #else
1435 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
1436 #endif
1437
1438 // Fill message with server info
1439 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1440 msg.SetVariable(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
1441 msg.SetVariable(VID_SERVER_ID, (BYTE *)&g_qwServerId, sizeof(QWORD));
1442 msg.SetVariable(VID_SUPPORTED_ENCRYPTION, (DWORD)0);
1443 msg.SetVariable(VID_PROTOCOL_VERSION, (DWORD)CLIENT_PROTOCOL_VERSION);
1444 msg.SetVariable(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
1445
1446 #if defined(_WIN32)
1447 TIME_ZONE_INFORMATION tz;
1448 WCHAR wst[4], wdt[8], *curr;
1449 int i;
1450
1451 GetTimeZoneInformation(&tz);
1452
1453 // Create 3 letter abbreviation for standard name
1454 for(i = 0, curr = tz.StandardName; (*curr != 0) && (i < 3); curr++)
1455 if (iswupper(*curr))
1456 wst[i++] = *curr;
1457 while(i < 3)
1458 wst[i++] = L'X';
1459 wst[i] = 0;
1460
1461 // Create abbreviation for DST name
1462 for(i = 0, curr = tz.DaylightName; (*curr != 0) && (i < 7); curr++)
1463 if (iswupper(*curr))
1464 wdt[i++] = *curr;
1465 while(i < 3)
1466 wdt[i++] = L'X';
1467 wdt[i] = 0;
1468
1469 #ifdef UNICODE
1470 swprintf(szBuffer, 1024, L"%s%c%02d%s", wst, (tz.Bias >= 0) ? '+' : '-',
1471 abs(tz.Bias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1472 #else
1473 sprintf(szBuffer, "%S%c%02d%S", wst, (tz.Bias >= 0) ? '+' : '-',
1474 abs(tz.Bias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1475 #endif
1476 #elif HAVE_DECL_TIMEZONE
1477 #ifdef UNICODE
1478 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (timezone >= 0) ? '+' : '-',
1479 abs(timezone) / 3600, (tzname[1] != NULL) ? tzname[1] : "");
1480 #else
1481 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (timezone >= 0) ? '+' : '-',
1482 abs(timezone) / 3600, (tzname[1] != NULL) ? tzname[1] : "");
1483 #endif
1484 #elif HAVE_TM_GMTOFF
1485 time_t t;
1486 struct tm *loc;
1487 int gmtOffset;
1488 #if HAVE_LOCALTIME_R
1489 struct tm tmbuff;
1490 #endif
1491
1492 t = time(NULL);
1493 #if HAVE_LOCALTIME_R
1494 loc = localtime_r(&t, &tmbuff);
1495 #else
1496 loc = localtime(&t);
1497 #endif
1498 gmtOffset = -loc->tm_gmtoff / 3600;
1499 if (loc->tm_isdst)
1500 gmtOffset++;
1501 #ifdef UNICODE
1502 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1503 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1504 #else
1505 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1506 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1507 #endif
1508 #else
1509 szBuffer[0] = 0;
1510 #endif
1511 msg.SetVariable(VID_TIMEZONE, szBuffer);
1512 debugPrintf(2, _T("Server time zone: %s"), szBuffer);
1513
1514 ConfigReadStr(_T("WindowsConsoleUpgradeURL"), szBuffer, 1024,
1515 _T("http://www.netxms.org/download/netxms-console-%version%.exe"));
1516 strURL = szBuffer;
1517 strURL.translate(_T("%version%"), NETXMS_VERSION_STRING);
1518 msg.SetVariable(VID_CONSOLE_UPGRADE_URL, (const TCHAR *)strURL);
1519
1520 ConfigReadStr(_T("TileServerURL"), szBuffer, 1024, _T("http://tile.openstreetmap.org/"));
1521 msg.SetVariable(VID_TILE_SERVER_URL, szBuffer);
1522
1523 ConfigReadStr(_T("DefaultConsoleDateFormat"), szBuffer, 1024, _T("dd.MM.yyyy"));
1524 msg.SetVariable(VID_DATE_FORMAT, szBuffer);
1525
1526 ConfigReadStr(_T("DefaultConsoleTimeFormat"), szBuffer, 1024, _T("HH:mm:ss"));
1527 msg.SetVariable(VID_TIME_FORMAT, szBuffer);
1528
1529 // Send response
1530 sendMessage(&msg);
1531 }
1532
1533 /**
1534 * Authenticate client
1535 */
1536 void ClientSession::login(CSCPMessage *pRequest)
1537 {
1538 CSCPMessage msg;
1539 TCHAR szLogin[MAX_USER_NAME], szPassword[1024];
1540 int nAuthType;
1541 bool changePasswd = false, intruderLockout = false;
1542 DWORD dwResult;
1543 #ifdef _WITH_ENCRYPTION
1544 X509 *pCert;
1545 #endif
1546
1547 // Prepare response message
1548 msg.SetCode(CMD_LOGIN_RESP);
1549 msg.SetId(pRequest->GetId());
1550
1551 // Get client info string
1552 if (pRequest->IsVariableExist(VID_CLIENT_INFO))
1553 {
1554 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
1555
1556 pRequest->GetVariableStr(VID_CLIENT_INFO, szClientInfo, 32);
1557 pRequest->GetVariableStr(VID_OS_INFO, szOSInfo, 32);
1558 pRequest->GetVariableStr(VID_LIBNXCL_VERSION, szLibVersion, 16);
1559 _sntprintf(m_szClientInfo, 96, _T("%s (%s; libnxcl %s)"),
1560 szClientInfo, szOSInfo, szLibVersion);
1561 }
1562
1563 m_clientType = pRequest->GetVariableShort(VID_CLIENT_TYPE);
1564 if ((m_clientType < 0) || (m_clientType > CLIENT_TYPE_APPLICATION))
1565 m_clientType = CLIENT_TYPE_DESKTOP;
1566
1567 if (!(m_dwFlags & CSF_AUTHENTICATED))
1568 {
1569 pRequest->GetVariableStr(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
1570 nAuthType = (int)pRequest->GetVariableShort(VID_AUTH_TYPE);
1571 switch(nAuthType)
1572 {
1573 case NETXMS_AUTH_TYPE_PASSWORD:
1574 #ifdef UNICODE
1575 pRequest->GetVariableStr(VID_PASSWORD, szPassword, 256);
1576 #else
1577 pRequest->GetVariableStrUTF8(VID_PASSWORD, szPassword, 1024);
1578 #endif
1579 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
1580 &m_dwSystemAccess, &changePasswd, &intruderLockout);
1581 break;
1582 case NETXMS_AUTH_TYPE_CERTIFICATE:
1583 #ifdef _WITH_ENCRYPTION
1584 pCert = CertificateFromLoginMessage(pRequest);
1585 if (pCert != NULL)
1586 {
1587 BYTE signature[256];
1588 DWORD dwSigLen;
1589
1590 dwSigLen = pRequest->GetVariableBinary(VID_SIGNATURE, signature, 256);
1591 dwResult = AuthenticateUser(szLogin, (TCHAR *)signature, dwSigLen, pCert,
1592 m_challenge, &m_dwUserId, &m_dwSystemAccess,
1593 &changePasswd, &intruderLockout);
1594 X509_free(pCert);
1595 }
1596 else
1597 {
1598 dwResult = RCC_BAD_CERTIFICATE;
1599 }
1600 #else
1601 dwResult = RCC_NOT_IMPLEMENTED;
1602 #endif
1603 break;
1604 default:
1605 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
1606 break;
1607 }
1608
1609 if (dwResult == RCC_SUCCESS)
1610 {
1611 m_dwFlags |= CSF_AUTHENTICATED;
1612 _sntprintf(m_szUserName, MAX_SESSION_NAME, _T("%s@%s"), szLogin, m_szWorkstation);
1613 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1614 msg.SetVariable(VID_USER_SYS_RIGHTS, m_dwSystemAccess);
1615 msg.SetVariable(VID_USER_ID, m_dwUserId);
1616 msg.SetVariable(VID_SESSION_ID, m_dwIndex);
1617 msg.SetVariable(VID_CHANGE_PASSWD_FLAG, (WORD)changePasswd);
1618 msg.SetVariable(VID_DBCONN_STATUS, (WORD)((g_dwFlags & AF_DB_CONNECTION_LOST) ? 0 : 1));
1619 msg.SetVariable(VID_ZONING_ENABLED, (WORD)((g_dwFlags & AF_ENABLE_ZONING) ? 1 : 0));
1620 debugPrintf(3, _T("User %s authenticated"), m_szUserName);
1621 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_szWorkstation, 0,
1622 _T("User \"%s\" logged in (client info: %s)"), szLogin, m_szClientInfo);
1623 }
1624 else
1625 {
1626 msg.SetVariable(VID_RCC, dwResult);
1627 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szWorkstation, 0,
1628 _T("User \"%s\" login failed with error code %d (client info: %s)"),
1629 szLogin, dwResult, m_szClientInfo);
1630 if (intruderLockout)
1631 {
1632 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szWorkstation, 0,
1633 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
1634 }
1635 }
1636 }
1637 else
1638 {
1639 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1640 }
1641
1642 // Send response
1643 sendMessage(&msg);
1644 }
1645
1646 /**
1647 * Send event configuration to client
1648 */
1649 void ClientSession::sendEventDB(DWORD dwRqId)
1650 {
1651 DB_ASYNC_RESULT hResult;
1652 CSCPMessage msg;
1653 TCHAR szBuffer[1024];
1654
1655 // Prepare response message
1656 msg.SetCode(CMD_REQUEST_COMPLETED);
1657 msg.SetId(dwRqId);
1658
1659 if (checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB | SYSTEM_ACCESS_EDIT_EVENT_DB | SYSTEM_ACCESS_EPP))
1660 {
1661 if (!(g_dwFlags & AF_DB_CONNECTION_LOST))
1662 {
1663 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1664 sendMessage(&msg);
1665 msg.DeleteAllVariables();
1666
1667 // Prepare data message
1668 msg.SetCode(CMD_EVENT_DB_RECORD);
1669 msg.SetId(dwRqId);
1670
1671 hResult = DBAsyncSelect(g_hCoreDB, _T("SELECT event_code,event_name,severity,flags,message,description FROM event_cfg"));
1672 if (hResult != NULL)
1673 {
1674 while(DBFetch(hResult))
1675 {
1676 msg.SetVariable(VID_EVENT_CODE, DBGetFieldAsyncULong(hResult, 0));
1677 msg.SetVariable(VID_NAME, DBGetFieldAsync(hResult, 1, szBuffer, 1024));
1678 msg.SetVariable(VID_SEVERITY, DBGetFieldAsyncULong(hResult, 2));
1679 msg.SetVariable(VID_FLAGS, DBGetFieldAsyncULong(hResult, 3));
1680
1681 DBGetFieldAsync(hResult, 4, szBuffer, 1024);
1682 DecodeSQLString(szBuffer);
1683 msg.SetVariable(VID_MESSAGE, szBuffer);
1684
1685 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
1686 DecodeSQLString(szBuffer);
1687 msg.SetVariable(VID_DESCRIPTION, szBuffer);
1688
1689 sendMessage(&msg);
1690 msg.DeleteAllVariables();
1691 }
1692 DBFreeAsyncResult(hResult);
1693 }
1694
1695 // End-of-list indicator
1696 msg.SetVariable(VID_EVENT_CODE, (DWORD)0);
1697 msg.SetEndOfSequence();
1698 }
1699 else
1700 {
1701 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
1702 }
1703 }
1704 else
1705 {
1706 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1707 }
1708 sendMessage(&msg);
1709 }
1710
1711
1712 //
1713 // Update event template
1714 //
1715
1716 static void SendEventDBChangeNotification(ClientSession *session, void *arg)
1717 {
1718 if (session->isAuthenticated() && session->checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB | SYSTEM_ACCESS_EDIT_EVENT_DB | SYSTEM_ACCESS_EPP))
1719 session->postMessage((CSCPMessage *)arg);
1720 }
1721
1722 void ClientSession::modifyEventTemplate(CSCPMessage *pRequest)
1723 {
1724 CSCPMessage msg;
1725
1726 // Prepare reply message
1727 msg.SetCode(CMD_REQUEST_COMPLETED);
1728 msg.SetId(pRequest->GetId());
1729
1730 // Check access rights
1731 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1732 {
1733 TCHAR szQuery[4096], szName[MAX_EVENT_NAME];
1734 DWORD dwEventCode;
1735 BOOL bEventExist = FALSE;
1736 DB_RESULT hResult;
1737
1738 // Check if event with specific code exists
1739 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
1740 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("SELECT event_code FROM event_cfg WHERE event_code=%d"), dwEventCode);
1741 hResult = DBSelect(g_hCoreDB, szQuery);
1742 if (hResult != NULL)
1743 {
1744 if (DBGetNumRows(hResult) > 0)
1745 bEventExist = TRUE;
1746 DBFreeResult(hResult);
1747 }
1748
1749 // Check that we are not trying to create event below 100000
1750 if (bEventExist || (dwEventCode >= FIRST_USER_EVENT_ID))
1751 {
1752 // Prepare and execute SQL query
1753 pRequest->GetVariableStr(VID_NAME, szName, MAX_EVENT_NAME);
1754 if (IsValidObjectName(szName))
1755 {
1756 TCHAR szMessage[MAX_DB_STRING], *pszDescription, *pszEscMsg, *pszEscDescr;
1757
1758 pRequest->GetVariableStr(VID_MESSAGE, szMessage, MAX_DB_STRING);
1759 pszEscMsg = EncodeSQLString(szMessage);
1760
1761 pszDescription = pRequest->GetVariableStr(VID_DESCRIPTION);
1762 pszEscDescr = EncodeSQLString(pszDescription);
1763 safe_free(pszDescription);
1764
1765 if (bEventExist)
1766 {
1767 _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"),
1768 szName, pRequest->GetVariableLong(VID_SEVERITY), pRequest->GetVariableLong(VID_FLAGS),
1769 pszEscMsg, pszEscDescr, dwEventCode);
1770 }
1771 else
1772 {
1773 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO event_cfg (event_code,event_name,severity,flags,")
1774 _T("message,description) VALUES (%d,'%s',%d,%d,'%s','%s')"),
1775 dwEventCode, szName, pRequest->GetVariableLong(VID_SEVERITY),
1776 pRequest->GetVariableLong(VID_FLAGS), pszEscMsg, pszEscDescr);
1777 }
1778
1779 free(pszEscMsg);
1780 free(pszEscDescr);
1781
1782 if (DBQuery(g_hCoreDB, szQuery))
1783 {
1784 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1785 ReloadEvents();
1786 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
1787
1788 CSCPMessage nmsg(pRequest);
1789 nmsg.SetCode(CMD_EVENT_DB_UPDATE);
1790 nmsg.SetVariable(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_CHANGED);
1791 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
1792 }
1793 else
1794 {
1795 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
1796 }
1797 }
1798 else
1799 {
1800 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
1801 }
1802 }
1803 else
1804 {
1805 msg.SetVariable(VID_RCC, RCC_INVALID_EVENT_CODE);
1806 }
1807 }
1808 else
1809 {
1810 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1811 }
1812
1813 // Send response
1814 sendMessage(&msg);
1815 }
1816
1817
1818 //
1819 // Delete event template
1820 //
1821
1822 void ClientSession::deleteEventTemplate(CSCPMessage *pRequest)
1823 {
1824 CSCPMessage msg;
1825 DWORD dwEventCode;
1826
1827 // Prepare reply message
1828 msg.SetCode(CMD_REQUEST_COMPLETED);
1829 msg.SetId(pRequest->GetId());
1830
1831 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
1832
1833 // Check access rights
1834 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
1835 {
1836 TCHAR szQuery[256];
1837
1838 _sntprintf(szQuery, 256, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
1839 if (DBQuery(g_hCoreDB, szQuery))
1840 {
1841 DeleteEventTemplateFromList(dwEventCode);
1842 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
1843
1844 CSCPMessage nmsg;
1845 nmsg.SetCode(CMD_EVENT_DB_UPDATE);
1846 nmsg.SetVariable(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_DELETED);
1847 nmsg.SetVariable(VID_EVENT_CODE, dwEventCode);
1848 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
1849
1850 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1851
1852 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
1853 _T("Event template %d deleted"), dwEventCode);
1854 }
1855 else
1856 {
1857 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
1858 }
1859 }
1860 else
1861 {
1862 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1863 }
1864
1865 // Send response
1866 sendMessage(&msg);
1867 }
1868
1869
1870 //
1871 // Generate event code for new event template
1872 //
1873
1874 void ClientSession::generateEventCode(DWORD dwRqId)
1875 {
1876 CSCPMessage msg;
1877
1878 // Prepare reply message
1879 msg.SetCode(CMD_REQUEST_COMPLETED);
1880 msg.SetId(dwRqId);
1881
1882 // Check access rights
1883 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1884 {
1885 msg.SetVariable(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
1886 }
1887 else
1888 {
1889 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1890 }
1891
1892 // Send response
1893 sendMessage(&msg);
1894 }
1895
1896
1897 //
1898 // Send all objects to client
1899 //
1900
1901 void ClientSession::sendAllObjects(CSCPMessage *pRequest)
1902 {
1903 DWORD dwTimeStamp;
1904 CSCPMessage msg;
1905
1906 // Send confirmation message
1907 msg.SetCode(CMD_REQUEST_COMPLETED);
1908 msg.SetId(pRequest->GetId());
1909 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1910 sendMessage(&msg);
1911 msg.DeleteAllVariables();
1912
1913 // Change "sync comments" flag
1914 if (pRequest->GetVariableShort(VID_SYNC_COMMENTS))
1915 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
1916 else
1917 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
1918
1919 // Get client's last known time stamp
1920 dwTimeStamp = pRequest->GetVariableLong(VID_TIMESTAMP);
1921
1922 // Prepare message
1923 msg.SetCode(CMD_OBJECT);
1924
1925 // Send objects, one per message
1926 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects();
1927 MutexLock(m_mutexSendObjects);
1928 for(int i = 0; i < objects->size(); i++)
1929 {
1930 NetObj *object = objects->get(i);
1931 if (object->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
1932 (object->TimeStamp() >= dwTimeStamp) &&
1933 !object->isHidden())
1934 {
1935 object->CreateMessage(&msg);
1936 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
1937 object->CommentsToMessage(&msg);
1938 sendMessage(&msg);
1939 msg.DeleteAllVariables();
1940 }
1941 }
1942 delete objects;
1943
1944 // Send end of list notification
1945 msg.SetCode(CMD_OBJECT_LIST_END);
1946 sendMessage(&msg);
1947
1948 MutexUnlock(m_mutexSendObjects);
1949 }
1950
1951
1952 //
1953 // Send selected objects to client
1954 //
1955
1956 void ClientSession::sendSelectedObjects(CSCPMessage *pRequest)
1957 {
1958 CSCPMessage msg;
1959
1960 // Send confirmation message
1961 msg.SetCode(CMD_REQUEST_COMPLETED);
1962 msg.SetId(pRequest->GetId());
1963 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1964 sendMessage(&msg);
1965 msg.DeleteAllVariables();
1966
1967 // Change "sync comments" flag
1968 if (pRequest->GetVariableShort(VID_SYNC_COMMENTS))
1969 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
1970 else
1971 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
1972
1973 DWORD dwTimeStamp = pRequest->GetVariableLong(VID_TIMESTAMP);
1974 DWORD numObjects = pRequest->GetVariableLong(VID_NUM_OBJECTS);
1975 DWORD *objects = (DWORD *)malloc(sizeof(DWORD) * numObjects);
1976 pRequest->GetVariableInt32Array(VID_OBJECT_LIST, numObjects, objects);
1977 DWORD options = pRequest->GetVariableShort(VID_FLAGS);
1978
1979 MutexLock(m_mutexSendObjects);
1980
1981 // Prepare message
1982 msg.SetCode((options & OBJECT_SYNC_SEND_UPDATES) ? CMD_OBJECT_UPDATE : CMD_OBJECT);
1983
1984 // Send objects, one per message
1985 for(DWORD i = 0; i < numObjects; i++)
1986 {
1987 NetObj *object = FindObjectById(objects[i]);
1988 if ((object != NULL) &&
1989 object->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
1990 (object->TimeStamp() >= dwTimeStamp) &&
1991 !object->isHidden())
1992 {
1993 object->CreateMessage(&msg);
1994 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
1995 object->CommentsToMessage(&msg);
1996 sendMessage(&msg);
1997 msg.DeleteAllVariables();
1998 }
1999 }
2000
2001 MutexUnlock(m_mutexSendObjects);
2002 safe_free(objects);
2003
2004 if (options & OBJECT_SYNC_DUAL_CONFIRM)
2005 {
2006 msg.SetCode(CMD_REQUEST_COMPLETED);
2007 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2008 sendMessage(&msg);
2009 }
2010 }
2011
2012 /**
2013 * Send event log records to client
2014 */
2015 void ClientSession::sendEventLog(CSCPMessage *pRequest)
2016 {
2017 CSCPMessage msg;
2018 DB_ASYNC_RESULT hResult = NULL;
2019 DB_RESULT hTempResult;
2020 DWORD dwRqId, dwMaxRecords, dwNumRows, dwId;
2021 TCHAR szQuery[1024], szBuffer[1024];
2022 WORD wRecOrder;
2023
2024 dwRqId = pRequest->GetId();
2025 dwMaxRecords = pRequest->GetVariableLong(VID_MAX_RECORDS);
2026 wRecOrder = ((g_nDBSyntax == DB_SYNTAX_MSSQL) || (g_nDBSyntax == DB_SYNTAX_ORACLE)) ? RECORD_ORDER_REVERSED : RECORD_ORDER_NORMAL;
2027
2028 // Prepare confirmation message
2029 msg.SetCode(CMD_REQUEST_COMPLETED);
2030 msg.SetId(dwRqId);
2031
2032 MutexLock(m_mutexSendEvents);
2033
2034 // Retrieve events from database
2035 switch(g_nDBSyntax)
2036 {
2037 case DB_SYNTAX_MYSQL:
2038 case DB_SYNTAX_PGSQL:
2039 case DB_SYNTAX_SQLITE:
2040 hTempResult = DBSelect(g_hCoreDB, _T("SELECT count(*) FROM event_log"));
2041 if (hTempResult != NULL)
2042 {
2043 if (DBGetNumRows(hTempResult) > 0)
2044 {
2045 dwNumRows = DBGetFieldULong(hTempResult, 0, 0);
2046 }
2047 else
2048 {
2049 dwNumRows = 0;
2050 }
2051 DBFreeResult(hTempResult);
2052 }
2053 _sntprintf(szQuery, 1024,
2054 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2055 _T("event_severity,event_message,user_tag FROM event_log ")
2056 _T("ORDER BY event_id LIMIT %u OFFSET %u"),
2057 dwMaxRecords, dwNumRows - min(dwNumRows, dwMaxRecords));
2058 break;
2059 case DB_SYNTAX_MSSQL:
2060 _sntprintf(szQuery, 1024,
2061 _T("SELECT TOP %u event_id,event_code,event_timestamp,event_source,")
2062 _T("event_severity,event_message,user_tag FROM event_log ")
2063 _T("ORDER BY event_id DESC"), dwMaxRecords);
2064 break;
2065 case DB_SYNTAX_ORACLE:
2066 _sntprintf(szQuery, 1024,
2067 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2068 _T("event_severity,event_message,user_tag FROM event_log ")
2069 _T("WHERE ROWNUM <= %u ORDER BY event_id DESC"), dwMaxRecords);
2070 break;
2071 default:
2072 szQuery[0] = 0;
2073 break;
2074 }
2075 hResult = DBAsyncSelect(g_hCoreDB, szQuery);
2076 if (hResult != NULL)
2077 {
2078 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2079 sendMessage(&msg);
2080 msg.DeleteAllVariables();
2081 msg.SetCode(CMD_EVENTLOG_RECORDS);
2082
2083 for(dwId = VID_EVENTLOG_MSG_BASE, dwNumRows = 0; DBFetch(hResult); dwNumRows++)
2084 {
2085 if (dwNumRows == 10)
2086 {
2087 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
2088 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
2089 sendMessage(&msg);
2090 msg.DeleteAllVariables();
2091 dwNumRows = 0;
2092 dwId = VID_EVENTLOG_MSG_BASE;
2093 }
2094 msg.SetVariable(dwId++, DBGetFieldAsyncUInt64(hResult, 0));
2095 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 1));
2096 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 2));
2097 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 3));
2098 msg.SetVariable(dwId++, (WORD)DBGetFieldAsyncLong(hResult, 4));
2099 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
2100 msg.SetVariable(dwId++, szBuffer);
2101 DBGetFieldAsync(hResult, 6, szBuffer, 1024);
2102 msg.SetVariable(dwId++, szBuffer);
2103 msg.SetVariable(dwId++, (DWORD)0); // Do not send parameters
2104 }
2105 DBFreeAsyncResult(hResult);
2106
2107 // Send remaining records with End-Of-Sequence notification
2108 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
2109 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
2110 msg.SetEndOfSequence();
2111 sendMessage(&msg);
2112 }
2113 else
2114 {
2115 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2116 sendMessage(&msg);
2117 }
2118
2119 MutexUnlock(m_mutexSendEvents);
2120 }
2121
2122 /**
2123 * Send all configuration variables to client
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 * Set configuration variable's value
2169 */
2170 void ClientSession::setConfigVariable(CSCPMessage *pRequest)
2171 {
2172 CSCPMessage msg;
2173 TCHAR szName[MAX_OBJECT_NAME], szValue[MAX_DB_STRING];
2174
2175 // Prepare response message
2176 msg.SetCode(CMD_REQUEST_COMPLETED);
2177 msg.SetId(pRequest->GetId());
2178
2179 // Check user rights
2180 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2181 {
2182 pRequest->GetVariableStr(VID_NAME, szName, MAX_OBJECT_NAME);
2183 pRequest->GetVariableStr(VID_VALUE, szValue, MAX_DB_STRING);
2184 if (ConfigWriteStr(szName, szValue, TRUE))
2185 {
2186 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2187 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
2188 _T("Server configuration variable \"%s\" set to \"%s\""), szName, szValue);
2189 }
2190 else
2191 {
2192 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2193 }
2194 }
2195 else
2196 {
2197 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2198 }
2199
2200 // Send response
2201 sendMessage(&msg);
2202 }
2203
2204 /**
2205 * Delete configuration variable
2206 */
2207 void ClientSession::deleteConfigVariable(CSCPMessage *pRequest)
2208 {
2209 CSCPMessage msg;
2210 TCHAR szName[MAX_OBJECT_NAME], szQuery[1024];
2211
2212 // Prepare response message
2213 msg.SetCode(CMD_REQUEST_COMPLETED);
2214 msg.SetId(pRequest->GetId());
2215
2216 // Check user rights
2217 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2218 {
2219 pRequest->GetVariableStr(VID_NAME, szName, MAX_OBJECT_NAME);
2220 _sntprintf(szQuery, 1024, _T("DELETE FROM config WHERE var_name='%s'"), szName);
2221 if (DBQuery(g_hCoreDB, szQuery))
2222 {
2223 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2224 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
2225 _T("Server configuration variable \"%s\" deleted"), szName);
2226 }
2227 else
2228 {
2229 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2230 }
2231 }
2232 else
2233 {
2234 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2235 }
2236
2237 // Send response
2238 sendMessage(&msg);
2239 }
2240
2241
2242 //
2243 // Set configuration clob
2244 //
2245
2246 void ClientSession::setConfigCLOB(CSCPMessage *pRequest)
2247 {
2248 CSCPMessage msg;
2249 TCHAR name[MAX_OBJECT_NAME], *value;
2250
2251 msg.SetId(pRequest->GetId());
2252 msg.SetCode(CMD_REQUEST_COMPLETED);
2253
2254 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2255 {
2256 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2257 value = pRequest->GetVariableStr(VID_VALUE);
2258 if (value != NULL)
2259 {
2260 if (ConfigWriteCLOB(name, value, TRUE))
2261 {
2262 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2263 free(value);
2264 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
2265 _T("Server configuration variable \"%s\" set to \"%s\""), name, value);
2266 }
2267 else
2268 {
2269 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2270 }
2271 }
2272 else
2273 {
2274 msg.SetVariable(VID_RCC, RCC_INVALID_REQUEST);
2275 }
2276 }
2277 else
2278 {
2279 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2280 }
2281
2282 sendMessage(&msg);
2283 }
2284
2285
2286 //
2287 // Get value of configuration clob
2288 //
2289
2290 void ClientSession::getConfigCLOB(CSCPMessage *pRequest)
2291 {
2292 CSCPMessage msg;
2293 TCHAR name[MAX_OBJECT_NAME], *value;
2294
2295 msg.SetId(pRequest->GetId());
2296 msg.SetCode(CMD_REQUEST_COMPLETED);
2297
2298 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2299 {
2300 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2301 value = ConfigReadCLOB(name, NULL);
2302 if (value != NULL)
2303 {
2304 msg.SetVariable(VID_VALUE, value);
2305 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2306 free(value);
2307 }
2308 else
2309 {
2310 msg.SetVariable(VID_RCC, RCC_UNKNOWN_VARIABLE);
2311 }
2312 }
2313 else
2314 {
2315 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2316 }
2317
2318 sendMessage(&msg);
2319 }
2320
2321
2322 //
2323 // Close session forcibly
2324 //
2325
2326 void ClientSession::kill()
2327 {
2328 // We shutdown socket connection, which will cause
2329 // read thread to stop, and other threads will follow
2330 shutdown(m_hSocket, 2);
2331 }
2332
2333
2334 //
2335 // Handler for new events
2336 //
2337
2338 void ClientSession::onNewEvent(Event *pEvent)
2339 {
2340 UPDATE_INFO *pUpdate;
2341 CSCPMessage *msg;
2342
2343 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_EVENTS))
2344 {
2345 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2346 pUpdate->dwCategory = INFO_CAT_EVENT;
2347 msg = new CSCPMessage;
2348 msg->SetCode(CMD_EVENTLOG_RECORDS);
2349 pEvent->prepareMessage(msg);
2350 pUpdate->pData = msg;
2351 m_pUpdateQueue->Put(pUpdate);
2352 }
2353 }
2354
2355
2356 //
2357 // Handler for object changes
2358 //
2359
2360 void ClientSession::onObjectChange(NetObj *pObject)
2361 {
2362 UPDATE_INFO *pUpdate;
2363
2364 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_OBJECTS))
2365 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2366 {
2367 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2368 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
2369 pUpdate->pData = pObject;
2370 pObject->IncRefCount();
2371 m_pUpdateQueue->Put(pUpdate);
2372 }
2373 }
2374
2375 /**
2376 * Send notification message to server
2377 */
2378 void ClientSession::notify(DWORD dwCode, DWORD dwData)
2379 {
2380 CSCPMessage msg;
2381
2382 msg.SetCode(CMD_NOTIFY);
2383 msg.SetVariable(VID_NOTIFICATION_CODE, dwCode);
2384 msg.SetVariable(VID_NOTIFICATION_DATA, dwData);
2385 sendMessage(&msg);
2386 }
2387
2388 /**
2389 * Modify object
2390 */
2391 void ClientSession::modifyObject(CSCPMessage *pRequest)
2392 {
2393 DWORD dwObjectId, dwResult = RCC_SUCCESS;
2394 NetObj *pObject;
2395 CSCPMessage msg;
2396
2397 // Prepare reply message
2398 msg.SetCode(CMD_REQUEST_COMPLETED);
2399 msg.SetId(pRequest->GetId());
2400
2401 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2402 pObject = FindObjectById(dwObjectId);
2403 if (pObject != NULL)
2404 {
2405 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2406 {
2407 // If user attempts to change object's ACL, check
2408 // if he has OBJECT_ACCESS_ACL permission
2409 if (pRequest->IsVariableExist(VID_ACL_SIZE))
2410 if (!pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
2411 dwResult = RCC_ACCESS_DENIED;
2412
2413 // If user attempts to rename object, check object's name
2414 if (pRequest->IsVariableExist(VID_OBJECT_NAME))
2415 {
2416 TCHAR name[256];
2417 pRequest->GetVariableStr(VID_OBJECT_NAME, name, 256);
2418 if (!IsValidObjectName(name, TRUE))
2419 dwResult = RCC_INVALID_OBJECT_NAME;
2420 }
2421
2422 // If allowed, change object and set completion code
2423 if (dwResult == RCC_SUCCESS)
2424 {
2425 dwResult = pObject->ModifyFromMessage(pRequest);
2426 if (dwResult == RCC_SUCCESS)
2427 {
2428 pObject->postModify();
2429 }
2430 }
2431 msg.SetVariable(VID_RCC, dwResult);
2432
2433 if (dwResult == RCC_SUCCESS)
2434 {
2435 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_szWorkstation, dwObjectId,
2436 _T("Object modified from client"));
2437 }
2438 else
2439 {
2440 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_szWorkstation, dwObjectId,
2441 _T("Failed to modify object from client - error %d"), dwResult);
2442 }
2443 }
2444 else
2445 {
2446 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2447 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_szWorkstation, dwObjectId,
2448 _T("Failed to modify object from client - access denied"), dwResult);
2449 }
2450 }
2451 else
2452 {
2453 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2454 }
2455
2456 // Send response
2457 sendMessage(&msg);
2458 }
2459
2460 /**
2461 * Send users database to client
2462 */
2463 void ClientSession::sendUserDB(DWORD dwRqId)
2464 {
2465 CSCPMessage msg;
2466 UserDatabaseObject **users;
2467 int i, userCount;
2468
2469 // Prepare response message
2470 msg.SetCode(CMD_REQUEST_COMPLETED);
2471 msg.SetId(dwRqId);
2472 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2473 sendMessage(&msg);
2474 msg.DeleteAllVariables();
2475
2476 // Send user database
2477 users = OpenUserDatabase(&userCount);
2478 for(i = 0; i < userCount; i++)
2479 {
2480 msg.SetCode((users[i]->getId() & GROUP_FLAG) ? CMD_GROUP_DATA : CMD_USER_DATA);
2481 users[i]->fillMessage(&msg);
2482 sendMessage(&msg);
2483 msg.DeleteAllVariables();
2484 }
2485 CloseUserDatabase();
2486
2487 // Send end-of-database notification
2488 msg.SetCode(CMD_USER_DB_EOF);
2489 sendMessage(&msg);
2490 }
2491
2492 /**
2493 * Create new user
2494 */
2495 void ClientSession::createUser(CSCPMessage *pRequest)
2496 {
2497 CSCPMessage msg;
2498
2499 // Prepare response message
2500 msg.SetCode(CMD_REQUEST_COMPLETED);
2501 msg.SetId(pRequest->GetId());
2502
2503 // Check user rights
2504 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2505 {
2506 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2507 }
2508 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2509 {
2510 // User database have to be locked before any
2511 // changes to user database can be made
2512 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2513 }
2514 else
2515 {
2516 DWORD dwResult, dwUserId;
2517 BOOL bIsGroup;
2518 TCHAR szUserName[MAX_USER_NAME];
2519
2520 pRequest->GetVariableStr(VID_USER_NAME, szUserName, MAX_USER_NAME);
2521 if (IsValidObjectName(szUserName))
2522 {
2523 bIsGroup = pRequest->GetVariableShort(VID_IS_GROUP);
2524 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
2525 msg.SetVariable(VID_RCC, dwResult);
2526 if (dwResult == RCC_SUCCESS)
2527 msg.SetVariable(VID_USER_ID, dwUserId); // Send id of new user to client
2528 }
2529 else
2530 {
2531 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
2532 }
2533 }
2534
2535 // Send response
2536 sendMessage(&msg);
2537 }
2538
2539 /**
2540 * Update existing user's data
2541 */
2542 void ClientSession::updateUser(CSCPMessage *pRequest)
2543 {
2544 CSCPMessage msg;
2545
2546 // Prepare response message
2547 msg.SetCode(CMD_REQUEST_COMPLETED);
2548 msg.SetId(pRequest->GetId());
2549
2550 // Check user rights
2551 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2552 {
2553 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2554 }
2555 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2556 {
2557 // User database have to be locked before any
2558 // changes to user database can be made
2559 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2560 }
2561 else
2562 {
2563 msg.SetVariable(VID_RCC, ModifyUserDatabaseObject(pRequest));
2564 }
2565
2566 // Send response
2567 sendMessage(&msg);
2568 }
2569
2570 /**
2571 * Delete user
2572 */
2573 void ClientSession::deleteUser(CSCPMessage *pRequest)
2574 {
2575 CSCPMessage msg;
2576 DWORD dwUserId;
2577
2578 // Prepare response message
2579 msg.SetCode(CMD_REQUEST_COMPLETED);
2580 msg.SetId(pRequest->GetId());
2581
2582 // Check user rights
2583 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2584 {
2585 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2586 }
2587 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2588 {
2589 // User database have to be locked before any
2590 // changes to user database can be made
2591 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2592 }
2593 else
2594 {
2595 // Get Id of user to be deleted
2596 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2597
2598 if ((dwUserId != 0) && (dwUserId != GROUP_EVERYONE))
2599 {
2600 DWORD dwResult;
2601
2602 dwResult = DeleteUserDatabaseObject(dwUserId);
2603 msg.SetVariable(VID_RCC, dwResult);
2604 }
2605 else
2606 {
2607 // System administrator account and _T("everyone") group cannot be deleted
2608 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2609 }
2610 }
2611
2612 // Send response
2613 sendMessage(&msg);
2614 }
2615
2616 /**
2617 * Lock/unlock user database
2618 */
2619 void ClientSession::lockUserDB(DWORD dwRqId, BOOL bLock)
2620 {
2621 CSCPMessage msg;
2622 TCHAR szBuffer[256];
2623
2624 // Prepare response message
2625 msg.SetCode(CMD_REQUEST_COMPLETED);
2626 msg.SetId(dwRqId);
2627
2628 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
2629 {
2630 if (bLock)
2631 {
2632 if (!LockComponent(CID_USER_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
2633 {
2634 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
2635 msg.SetVariable(VID_LOCKED_BY, szBuffer);
2636 }
2637 else
2638 {
2639 m_dwFlags |= CSF_USER_DB_LOCKED;
2640 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2641 }
2642 }
2643 else
2644 {
2645 if (m_dwFlags & CSF_USER_DB_LOCKED)
2646 {
2647 UnlockComponent(CID_USER_DB);
2648 m_dwFlags &= ~CSF_USER_DB_LOCKED;
2649 }
2650 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2651 }
2652 }
2653 else
2654 {
2655 // Current user has no rights for user account management
2656 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2657 }
2658
2659 // Send response
2660 sendMessage(&msg);
2661 }
2662
2663
2664 //
2665 // Notify client on user database update
2666 //
2667
2668 void ClientSession::onUserDBUpdate(int code, DWORD id, UserDatabaseObject *object)
2669 {
2670 CSCPMessage msg;
2671
2672 if (isAuthenticated())
2673 {
2674 msg.SetCode(CMD_USER_DB_UPDATE);
2675 msg.SetId(0);
2676 msg.SetVariable(VID_UPDATE_TYPE, (WORD)code);
2677
2678 switch(code)
2679 {
2680 case USER_DB_CREATE:
2681 case USER_DB_MODIFY:
2682 object->fillMessage(&msg);
2683 break;
2684 default:
2685 msg.SetVariable(VID_USER_ID, id);
2686 break;
2687 }
2688
2689 sendMessage(&msg);
2690 }
2691 }
2692
2693
2694 //
2695 // Change management status for the object
2696 //
2697
2698 void ClientSession::changeObjectMgmtStatus(CSCPMessage *pRequest)
2699 {
2700 CSCPMessage msg;
2701 DWORD dwObjectId;
2702 NetObj *pObject;
2703
2704 // Prepare response message
2705 msg.SetCode(CMD_REQUEST_COMPLETED);
2706 msg.SetId(pRequest->GetId());
2707
2708 // Get object id and check access rights
2709 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2710 pObject = FindObjectById(dwObjectId);
2711 if (pObject != NULL)
2712 {
2713 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2714 {
2715 if ((pObject->Type() != OBJECT_TEMPLATE) &&
2716 (pObject->Type() != OBJECT_TEMPLATEGROUP) &&
2717 (pObject->Type() != OBJECT_TEMPLATEROOT))
2718 {
2719 BOOL bIsManaged;
2720
2721 bIsManaged = (BOOL)pRequest->GetVariableShort(VID_MGMT_STATUS);
2722 pObject->setMgmtStatus(bIsManaged);
2723 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2724 }
2725 else
2726 {
2727 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
2728 }
2729 }
2730 else
2731 {
2732 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2733 }
2734 }
2735 else
2736 {
2737 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2738 }
2739
2740 // Send response
2741 sendMessage(&msg);
2742 }
2743
2744 /**
2745 * Set user's password
2746 */
2747 void ClientSession::setPassword(CSCPMessage *pRequest)
2748 {
2749 CSCPMessage msg;
2750 DWORD dwUserId;
2751
2752 // Prepare response message
2753 msg.SetCode(CMD_REQUEST_COMPLETED);
2754 msg.SetId(pRequest->GetId());
2755
2756 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2757
2758 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
2759 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
2760 (dwUserId == m_dwUserId)) // User can change password for itself
2761 {
2762 DWORD dwResult;
2763 TCHAR newPassword[1024], oldPassword[1024];
2764
2765 #ifdef UNICODE
2766 pRequest->GetVariableStr(VID_PASSWORD, newPassword, 256);
2767 if (pRequest->IsVariableExist(VID_OLD_PASSWORD))
2768 pRequest->GetVariableStr(VID_OLD_PASSWORD, oldPassword, 256);
2769 #else
2770 pRequest->GetVariableStrUTF8(VID_PASSWORD, newPassword, 1024);
2771 if (pRequest->IsVariableExist(VID_OLD_PASSWORD))
2772 pRequest->GetVariableStrUTF8(VID_OLD_PASSWORD, oldPassword, 1024);
2773 #endif
2774 else
2775 oldPassword[0] = 0;
2776 dwResult = SetUserPassword(dwUserId, newPassword, oldPassword, dwUserId == m_dwUserId);
2777 msg.SetVariable(VID_RCC, dwResult);
2778 }
2779 else
2780 {
2781 // Current user has no rights to change password for specific user
2782 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2783 }
2784
2785 // Send response
2786 sendMessage(&msg);
2787 }
2788
2789 /**
2790 * Send node's DCIs to client and lock data collection settings
2791 */
2792 void ClientSession::openNodeDCIList(CSCPMessage *pRequest)
2793 {
2794 CSCPMessage msg;
2795 DWORD dwObjectId;
2796 NetObj *pObject;
2797 BOOL bSuccess = FALSE;
2798 TCHAR szLockInfo[MAX_SESSION_NAME];
2799
2800 // Prepare response message
2801 msg.SetCode(CMD_REQUEST_COMPLETED);
2802 msg.SetId(pRequest->GetId());
2803
2804 // Get node id and check object class and access rights
2805 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2806 pObject = FindObjectById(dwObjectId);
2807 if (pObject != NULL)
2808 {
2809 if ((pObject->Type() == OBJECT_NODE) ||
2810 (pObject->Type() == OBJECT_CLUSTER) ||
2811 (pObject->Type() == OBJECT_MOBILEDEVICE) ||
2812 (pObject->Type() == OBJECT_TEMPLATE))
2813 {
2814 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2815 {
2816 // Try to lock DCI list
2817 if (((Template *)pObject)->lockDCIList(m_dwIndex, m_szUserName, szLockInfo))
2818 {
2819 bSuccess = TRUE;
2820 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2821
2822 // Modify list of open nodes DCI lists
2823 m_pOpenDCIList = (DWORD *)realloc(m_pOpenDCIList, sizeof(DWORD) * (m_dwOpenDCIListSize + 1));
2824 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
2825 m_dwOpenDCIListSize++;
2826 }
2827 else
2828 {
2829 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
2830 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
2831 }
2832 }
2833 else
2834 {
2835 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2836 }
2837 }
2838 else
2839 {
2840 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2841 }
2842 }
2843 else
2844 {
2845 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2846 }
2847
2848 // Send response
2849 sendMessage(&msg);
2850
2851 // If DCI list was successfully locked, send it to client
2852 if (bSuccess)
2853 ((Template *)pObject)->sendItemsToClient(this, pRequest->GetId());
2854 }
2855
2856 /**
2857 * Unlock node's data collection settings
2858 */
2859 void ClientSession::closeNodeDCIList(CSCPMessage *pRequest)
2860 {
2861 CSCPMessage msg;
2862 DWORD dwObjectId;
2863 NetObj *pObject;
2864
2865 // Prepare response message
2866 msg.SetCode(CMD_REQUEST_COMPLETED);
2867 msg.SetId(pRequest->GetId());
2868
2869 // Get node id and check object class and access rights
2870 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2871 pObject = FindObjectById(dwObjectId);
2872 if (pObject != NULL)
2873 {
2874 if ((pObject->Type() == OBJECT_NODE) ||
2875 (pObject->Type() == OBJECT_CLUSTER) ||
2876 (pObject->Type() == OBJECT_MOBILEDEVICE) ||
2877 (pObject->Type() == OBJECT_TEMPLATE))
2878 {
2879 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2880 {
2881 BOOL bSuccess;
2882
2883 // Try to unlock DCI list
2884 bSuccess = ((Template *)pObject)->unlockDCIList(m_dwIndex);
2885 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
2886
2887 // Modify list of open nodes DCI lists
2888 if (bSuccess)
2889 {
2890 DWORD i;
2891
2892 for(i = 0; i < m_dwOpenDCIListSize; i++)
2893 if (m_pOpenDCIList[i] == dwObjectId)
2894 {
2895 m_dwOpenDCIListSize--;
2896 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1],
2897 sizeof(DWORD) * (m_dwOpenDCIListSize - i));
2898 break;
2899 }
2900 }
2901
2902 // Queue template update
2903 if ((pObject->Type() == OBJECT_TEMPLATE) ||
2904 (pObject->Type() == OBJECT_CLUSTER))
2905 ((Template *)pObject)->queueUpdate();
2906 }
2907 else
2908 {
2909 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2910 }
2911 }
2912 else
2913 {
2914 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2915 }
2916 }
2917 else
2918 {
2919 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2920 }
2921
2922 // Send response
2923 sendMessage(&msg);
2924 }
2925
2926 /**
2927 * Create, modify, or delete data collection item for node
2928 */
2929 void ClientSession::modifyNodeDCI(CSCPMessage *pRequest)
2930 {
2931 CSCPMessage msg;
2932 DWORD dwObjectId;
2933 NetObj *pObject;
2934
2935 // Prepare response message
2936 msg.SetCode(CMD_REQUEST_COMPLETED);
2937 msg.SetId(pRequest->GetId());
2938
2939 // Get node id and check object class and access rights
2940 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2941 pObject = FindObjectById(dwObjectId);
2942 if (pObject != NULL)
2943 {
2944 if ((pObject->Type() == OBJECT_NODE) ||
2945 (pObject->Type() == OBJECT_CLUSTER) ||
2946 (pObject->Type() == OBJECT_MOBILEDEVICE) ||
2947 (pObject->Type() == OBJECT_TEMPLATE))
2948 {
2949 if (((Template *)pObject)->isLockedBySession(m_dwIndex))
2950 {
2951 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2952 {
2953 DWORD i, dwItemId, dwNumMaps, *pdwMapId, *pdwMapIndex;
2954 DCObject *dcObject;
2955 BOOL bSuccess = FALSE;
2956
2957 int dcObjectType = (int)pRequest->GetVariableShort(VID_DCOBJECT_TYPE);
2958 switch(pRequest->GetCode())
2959 {
2960 case CMD_CREATE_NEW_DCI:
2961 // Create dummy DCI
2962 switch(dcObjectType)
2963 {
2964 case DCO_TYPE_ITEM:
2965 dcObject = new DCItem(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL, DCI_DT_INT, 60, 30, (Node *)pObject);
2966 break;
2967 case DCO_TYPE_TABLE:
2968 dcObject = new DCTable(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL, 60, 30, (Node *)pObject);
2969 break;
2970 default:
2971 dcObject = NULL;
2972 break;
2973 }
2974 if (dcObject != NULL)
2975 {
2976 dcObject->setStatus(ITEM_STATUS_DISABLED, false);
2977 if ((bSuccess = ((Template *)pObject)->addDCObject(dcObject)))
2978 {
2979 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2980 // Return new item id to client
2981 msg.SetVariable(VID_DCI_ID, dcObject->getId());
2982 }
2983 else // Unable to add item to node
2984 {
2985 delete dcObject;
2986 msg.SetVariable(VID_RCC, RCC_DUPLICATE_DCI);
2987 }
2988 }
2989 else
2990 {
2991 msg.SetVariable(VID_RCC, RCC_INVALID_ARGUMENT);
2992 }
2993 break;
2994 case CMD_MODIFY_NODE_DCI:
2995 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
2996 bSuccess = ((Template *)pObject)->updateDCObject(dwItemId, pRequest, &dwNumMaps, &pdwMapIndex, &pdwMapId);
2997 if (bSuccess)
2998 {
2999 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3000
3001 // Send index to id mapping for newly created thresholds to client
3002 if (dcObjectType == DCO_TYPE_ITEM)
3003 {
3004 msg.SetVariable(VID_DCI_NUM_MAPS, dwNumMaps);
3005 for(i = 0; i < dwNumMaps; i++)
3006 {
3007 pdwMapId[i] = htonl(pdwMapId[i]);
3008 pdwMapIndex[i] = htonl(pdwMapIndex[i]);
3009 }
3010 msg.SetVariable(VID_DCI_MAP_IDS, (BYTE *)pdwMapId, sizeof(DWORD) * dwNumMaps);
3011 msg.SetVariable(VID_DCI_MAP_INDEXES, (BYTE *)pdwMapIndex, sizeof(DWORD) * dwNumMaps);
3012 safe_free(pdwMapId);
3013 safe_free(pdwMapIndex);
3014 }
3015 }
3016 else
3017 {
3018 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3019 }
3020 break;
3021 case CMD_DELETE_NODE_DCI:
3022 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3023 bSuccess = ((Template *)pObject)->deleteDCObject(dwItemId, TRUE);
3024 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_INVALID_DCI_ID);
3025 break;
3026 }
3027 if (bSuccess)
3028 ((Template *)pObject)->setDCIModificationFlag();
3029 }
3030 else // User doesn't have MODIFY rights on object
3031 {
3032 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3033 }
3034 }
3035 else // Nodes DCI list not locked by this session
3036 {
3037 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3038 }
3039 }
3040 else // Object is not a node
3041 {
3042 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3043 }
3044 }
3045 else // No object with given ID
3046 {
3047 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3048 }
3049
3050 // Send response
3051 sendMessage(&msg);
3052 }
3053
3054 /**
3055 * Change status for one or more DCIs
3056 */
3057 void ClientSession::changeDCIStatus(CSCPMessage *pRequest)
3058 {
3059 CSCPMessage msg;
3060 NetObj *pObject;
3061
3062 // Prepare response message
3063 msg.SetCode(CMD_REQUEST_COMPLETED);
3064 msg.SetId(pRequest->GetId());
3065
3066 // Get node id and check object class and access rights
3067 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3068 if (pObject != NULL)
3069 {
3070 if ((pObject->Type() == OBJECT_NODE) ||
3071 (pObject->Type() == OBJECT_CLUSTER) ||
3072 (pObject->Type() == OBJECT_MOBILEDEVICE) ||
3073 (pObject->Type() == OBJECT_TEMPLATE))
3074 {
3075 if (((Template *)pObject)->isLockedBySession(m_dwIndex))
3076 {
3077 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3078 {
3079 DWORD dwNumItems, *pdwItemList;
3080 int iStatus;
3081
3082 iStatus = pRequest->GetVariableShort(VID_DCI_STATUS);
3083 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
3084 pdwItemList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
3085 pRequest->GetVariableInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3086 if (((Template *)pObject)->setItemStatus(dwNumItems, pdwItemList, iStatus))
3087 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3088 else
3089 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3090 free(pdwItemList);
3091 }
3092 else // User doesn't have MODIFY rights on object
3093 {
3094 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3095 }
3096 }
3097 else // Nodes DCI list not locked by this session
3098 {
3099 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3100 }
3101 }
3102 else // Object is not a node
3103 {
3104 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3105 }
3106 }
3107 else // No object with given ID
3108 {
3109 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3110 }
3111
3112 // Send response
3113 sendMessage(&msg);
3114 }
3115
3116 /**
3117 * Clear all collected data for DCI
3118 */
3119 void ClientSession::clearDCIData(CSCPMessage *pRequest)
3120 {
3121 CSCPMessage msg;
3122 NetObj *pObject;
3123 DWORD dwItemId;
3124
3125 // Prepare response message
3126 msg.SetCode(CMD_REQUEST_COMPLETED);
3127 msg.SetId(pRequest->GetId());
3128
3129 // Get node id and check object class and access rights
3130 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3131 if (pObject != NULL)
3132 {
3133 if ((pObject->Type() == OBJECT_NODE) || (pObject->Type() == OBJECT_MOBILEDEVICE))
3134 {
3135 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_DELETE))
3136 {
3137 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3138 debugPrintf(4, _T("ClearDCIData: request for DCI %d at node %d"), dwItemId, pObject->Id());
3139 DCObject *dci = ((Template *)pObject)->getDCObjectById(dwItemId);
3140 if (dci != NULL)
3141 {
3142 msg.SetVariable(VID_RCC, dci->deleteAllData() ? RCC_SUCCESS : RCC_DB_FAILURE);
3143 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d"), dwItemId, pObject->Id());
3144 }
3145 else
3146 {
3147 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3148 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d not found"), dwItemId, pObject->Id());
3149 }
3150 }
3151 else // User doesn't have DELETE rights on object
3152 {
3153 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3154 }
3155 }
3156 else // Object is not a node
3157 {
3158 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3159 }
3160 }
3161 else // No object with given ID
3162 {
3163 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3164 }
3165
3166 // Send response
3167 sendMessage(&msg);
3168 }
3169
3170 /**
3171 * Copy or move DCI from one node or template to another
3172 */
3173 void ClientSession::copyDCI(CSCPMessage *pRequest)
3174 {
3175 CSCPMessage msg;
3176 NetObj *pSource, *pDestination;
3177 TCHAR szLockInfo[MAX_SESSION_NAME];
3178 BOOL bMove;
3179
3180 // Prepare response message
3181 msg.SetCode(CMD_REQUEST_COMPLETED);
3182 msg.SetId(pRequest->GetId());
3183
3184 // Get source and destination
3185 pSource = FindObjectById(pRequest->GetVariableLong(VID_SOURCE_OBJECT_ID));
3186 pDestination = FindObjectById(pRequest->GetVariableLong(VID_DESTINATION_OBJECT_ID));
3187 if ((pSource != NULL) && (pDestination != NULL))
3188 {
3189 // Check object types
3190 if (((pSource->Type() == OBJECT_NODE) || (pSource->Type() == OBJECT_MOBILEDEVICE) || (pSource->Type() == OBJECT_TEMPLATE) || (pSource->Type() == OBJECT_CLUSTER)) &&
3191 ((pDestination->Type() == OBJECT_NODE) || (pDestination->Type() == OBJECT_MOBILEDEVICE) || (pDestination->Type() == OBJECT_TEMPLATE) || (pDestination->Type() == OBJECT_CLUSTER)))
3192 {
3193 if (((Template *)pSource)->isLockedBySession(m_dwIndex))
3194 {
3195 bMove = pRequest->GetVariableShort(VID_MOVE_FLAG);
3196 // Check access rights
3197 if ((pSource->CheckAccessRights(m_dwUserId, bMove ? (OBJECT_ACCESS_READ | OBJECT_ACCESS_MODIFY) : OBJECT_ACCESS_READ)) &&
3198 (pDestination->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)))
3199 {
3200 // Attempt to lock destination's DCI list
3201 if ((pDestination->Id() == pSource->Id()) ||
3202 (((Template *)pDestination)->lockDCIList(m_dwIndex, m_szUserName, szLockInfo)))
3203 {
3204 DWORD i, *pdwItemList, dwNumItems;
3205 const DCObject *pSrcItem;
3206 DCObject *pDstItem;
3207 int iErrors = 0;
3208
3209 // Get list of items to be copied/moved
3210 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
3211 pdwItemList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
3212 pRequest->GetVariableInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3213
3214 // Copy items
3215 for(i = 0; i < dwNumItems; i++)
3216 {
3217 pSrcItem = ((Template *)pSource)->getDCObjectById(pdwItemList[i]);
3218 if (pSrcItem != NULL)
3219 {
3220 switch(pSrcItem->getType())
3221 {
3222 case DCO_TYPE_ITEM:
3223 pDstItem = new DCItem((DCItem *)pSrcItem);
3224 break;
3225 case DCO_TYPE_TABLE:
3226 pDstItem = new DCTable((DCTable *)pSrcItem);
3227 break;
3228 default:
3229 pDstItem = NULL;
3230 break;
3231 }
3232 if (pDstItem != NULL)
3233 {
3234 pDstItem->setTemplateId(0, 0);
3235 pDstItem->changeBinding(CreateUniqueId(IDG_ITEM),
3236 (Template *)pDestination, FALSE);
3237 if (((Template *)pDestination)->addDCObject(pDstItem))
3238 {
3239 if (bMove)
3240 {
3241 // Delete original item
3242 if (!((Template *)pSource)->deleteDCObject(pdwItemList[i], TRUE))
3243 {
3244 iErrors++;
3245 }
3246 }
3247 }
3248 else
3249 {
3250 delete pDstItem;
3251 iErrors++;
3252 }
3253 }
3254 else
3255 {
3256 DbgPrintf(2, _T("INTERNAL ERROR: ClientSession::CopyDCI(): unknown DCO type %d"), pSrcItem->getType());
3257 iErrors++;
3258 }
3259 }
3260 else
3261 {
3262 iErrors++;
3263 }
3264 }
3265
3266 // Cleanup
3267 free(pdwItemList);
3268 if (pDestination->Id() != pSource->Id())
3269 ((Template *)pDestination)->unlockDCIList(m_dwIndex);
3270 msg.SetVariable(VID_RCC, (iErrors == 0) ? RCC_SUCCESS : RCC_DCI_COPY_ERRORS);
3271
3272 // Queue template update
3273 if (pDestination->Type() == OBJECT_TEMPLATE)
3274 ((Template *)pDestination)->queueUpdate();
3275 }
3276 else // Destination's DCI list already locked by someone else
3277 {
3278 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
3279 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
3280 }
3281 }
3282 else // User doesn't have enough rights on object(s)
3283 {
3284 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3285 }
3286 }
3287 else // Source node DCI list not locked by this session
3288 {
3289 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3290 }
3291 }
3292 else // Object(s) is not a node
3293 {
3294 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3295 }
3296 }
3297 else // No object(s) with given ID
3298 {
3299 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3300 }
3301
3302 // Send response
3303 sendMessage(&msg);
3304 }
3305
3306 /**
3307 * Send list of thresholds for DCI
3308 */
3309 void ClientSession::sendDCIThresholds(CSCPMessage *request)
3310 {
3311 CSCPMessage msg;
3312 NetObj *object;
3313
3314 // Prepare response message
3315 msg.SetCode(CMD_REQUEST_COMPLETED);
3316 msg.SetId(request->GetId());
3317
3318 // Get node id and check object class and access rights
3319 object = FindObjectById(request->GetVariableLong(VID_OBJECT_ID));
3320 if (object != NULL)
3321 {
3322 if (object->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3323 {
3324 if ((object->Type() == OBJECT_NODE) || (object->Type() == OBJECT_MOBILEDEVICE))
3325 {
3326 DCObject *dci = ((Template *)object)->getDCObjectById(request->GetVariableLong(VID_DCI_ID));
3327 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
3328 {
3329 ((DCItem *)dci)->fillMessageWithThresholds(&msg);
3330 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3331 }
3332 else
3333 {
3334 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3335 }
3336 }
3337 else
3338 {
3339 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3340 }
3341 }
3342 else
3343 {
3344 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3345 }
3346 }
3347 else // No object with given ID
3348 {
3349 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3350 }
3351
3352 // Send response
3353 sendMessage(&msg);
3354 }
3355
3356 /**
3357 * Prepare statement for reading data from idata table
3358 */
3359 static DB_STATEMENT PrepareIDataSelect(DB_HANDLE hdb, DWORD nodeId, DWORD maxRows, const TCHAR *condition)
3360 {
3361 TCHAR query[512];
3362
3363 switch(g_nDBSyntax)
3364 {
3365 case DB_SYNTAX_MSSQL:
3366 _sntprintf(query, 512, _T("SELECT TOP %d idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC"),
3367 (int)maxRows, (int)nodeId, condition);
3368 break;
3369 case DB_SYNTAX_ORACLE:
3370 _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"),
3371 (int)nodeId, condition, (int)maxRows);
3372 break;
3373 case DB_SYNTAX_MYSQL:
3374 case DB_SYNTAX_PGSQL:
3375 case DB_SYNTAX_SQLITE:
3376 _sntprintf(query, 512, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC LIMIT %d"),
3377 (int)nodeId, condition, (int)maxRows);
3378 break;
3379 default:
3380 DbgPrintf(1, _T(">>> INTERNAL ERROR: unsupported database in PrepareTDataSelect"));
3381 return NULL; // Unsupported database
3382 }
3383 return DBPrepare(hdb, query);
3384 }
3385
3386 /**
3387 * Prepare statement for reading data from tdata table
3388 */
3389 static DB_STATEMENT PrepareTDataSelect(DB_HANDLE hdb, DWORD nodeId, DWORD maxRows, const TCHAR *condition)
3390 {
3391 TCHAR query[512];
3392
3393 switch(g_nDBSyntax)
3394 {
3395 case DB_SYNTAX_MSSQL:
3396 _sntprintf(query, 512, _T("SELECT TOP %d b.tdata_timestamp, b.tdata_value FROM tdata_%d a, tdata_%d b")
3397 _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=?")
3398 _T("%s AND a.tdata_timestamp=b.tdata_timestamp ORDER BY b.tdata_timestamp DESC"),
3399 (int)maxRows, (int)nodeId, (int)nodeId, condition);
3400 break;
3401 case DB_SYNTAX_ORACLE:
3402 _sntprintf(query, 512, _T("SELECT * FROM (SELECT b.tdata_timestamp, b.tdata_value FROM tdata_%d a, tdata_%d b")
3403 _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=?")
3404 _T("%s AND a.tdata_timestamp=b.tdata_timestamp ORDER BY b.tdata_timestamp DESC) WHERE ROWNUM<=%d"),
3405 (int)nodeId, (int)nodeId, condition, (int)maxRows);
3406 break;
3407 case DB_SYNTAX_MYSQL:
3408 case DB_SYNTAX_PGSQL:
3409 case DB_SYNTAX_SQLITE:
3410 _sntprintf(query, 512, _T("SELECT b.tdata_timestamp, b.tdata_value FROM tdata_%d a, tdata_%d b")
3411 _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=?")
3412 _T("%s AND a.tdata_timestamp=b.tdata_timestamp ORDER BY b.tdata_timestamp DESC LIMIT %d"),
3413 (int)nodeId, (int)nodeId, condition, (int)maxRows);
3414 break;
3415 default:
3416 DbgPrintf(1, _T(">>> INTERNAL ERROR: unsupported database in PrepareIDataSelect"));
3417 return NULL; // Unsupported database
3418 }
3419 return NULL;
3420 }
3421
3422 /**
3423 * Get collected data for table or simple DCI
3424 */
3425 bool ClientSession::getCollectedDataFromDB(CSCPMessage *request, CSCPMessage *response, DataCollectionTarget *dcTarget, int dciType)
3426 {
3427 // Find DCI object
3428 DCObject *dci = dcTarget->getDCObjectById(request->GetVariableLong(VID_DCI_ID));
3429 if (dci == NULL)
3430 {
3431 response->SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3432 return false;
3433 }
3434
3435 // DCI type in request should match actual DCI type
3436 if (dci->getType() != dciType)
3437 {
3438 response->SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3439 return false;
3440 }
3441
3442 // Check that all required data present in message
3443 if ((dciType == DCO_TYPE_TABLE) && (!request->IsVariableExist(VID_DATA_COLUMN) || !request->IsVariableExist(VID_INSTANCE)))
3444 {
3445 response->SetVariable(VID_RCC, RCC_INVALID_ARGUMENT);
3446 return false;
3447 }
3448
3449 // Get request parameters
3450 DWORD maxRows = request->GetVariableLong(VID_MAX_ROWS);
3451 DWORD timeFrom = request->GetVariableLong(VID_TIME_FROM);
3452 DWORD timeTo = request->GetVariableLong(VID_TIME_TO);
3453
3454 if ((maxRows == 0) || (maxRows > MAX_DCI_DATA_RECORDS))
3455 maxRows = MAX_DCI_DATA_RECORDS;
3456
3457 TCHAR condition[256] = _T("");
3458 if (timeFrom != 0)
3459 _tcscpy(condition, (dciType == DCO_TYPE_TABLE) ? _T(" AND a.tdata_timestamp>=?") : _T(" AND idata_timestamp>=?"));
3460 if (timeTo != 0)
3461 _tcscat(condition, (dciType == DCO_TYPE_TABLE) ? _T(" AND a.tdata_timestamp<=?") : _T(" AND idata_timestamp<=?"));
3462
3463 DCI_DATA_HEADER *pData = NULL;
3464 DCI_DATA_ROW *pCurr;
3465
3466 bool success = false;
3467 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
3468 DB_STATEMENT hStmt;
3469 switch(dciType)
3470 {
3471 case DCO_TYPE_ITEM:
3472 hStmt = PrepareIDataSelect(hdb, dcTarget->Id(), maxRows, condition);
3473 break;
3474 case DCO_TYPE_TABLE:
3475 hStmt = PrepareTDataSelect(hdb, dcTarget->Id(), maxRows, condition);
3476 break;
3477 default:
3478 hStmt = NULL;
3479 break;
3480 }
3481
3482 if (hStmt != NULL)
3483 {
3484 int pos = 1;
3485 DBBind(hStmt, pos++, DB_SQLTYPE_INTEGER, dci->getId());
3486 if (dciType == DCO_TYPE_TABLE)
3487 {
3488 DBBind(hStmt, pos++, DB_SQLTYPE_INTEGER, ((DCTable *)dci)->getInstanceColumnId());
3489 DBBind(hStmt, pos++, DB_SQLTYPE_VARCHAR, request->GetVariableStr(VID_INSTANCE), DB_BIND_DYNAMIC);
3490
3491 TCHAR dataColumn[MAX_COLUMN_NAME];
3492 request->GetVariableStr(VID_DATA_COLUMN, dataColumn, MAX_COLUMN_NAME);
3493 DBBind(hStmt, pos++, DB_SQLTYPE_INTEGER, DCTable::columnIdFromName(dataColumn));
3494 }
3495 if (timeFrom != 0)
3496 DBBind(hStmt, pos++, DB_SQLTYPE_INTEGER, timeFrom);
3497 if (timeTo != 0)
3498 DBBind(hStmt, pos++, DB_SQLTYPE_INTEGER, timeTo);
3499
3500 DB_RESULT hResult = DBSelectPrepared(hStmt);
3501 if (hResult != NULL)
3502 {
3503 static DWORD m_dwRowSize[] = { 8, 8, 12, 12, 516, 12 };
3504 #if !defined(UNICODE) || defined(UNICODE_UCS4)
3505 TCHAR szBuffer[MAX_DCI_STRING_VALUE];
3506 #endif
3507
3508 // Send CMD_REQUEST_COMPLETED message
3509 response->SetVariable(VID_RCC, RCC_SUCCESS);
3510 if (dciType == DCO_TYPE_ITEM)
3511 ((DCItem *)dci)->fillMessageWithThresholds(response);
3512 sendMessage(response);
3513
3514 DWORD numRows = (DWORD)DBGetNumRows(hResult);
3515
3516 int dataType;
3517 switch(dciType)
3518 {
3519 case DCO_TYPE_ITEM:
3520 dataType = ((DCItem *)dci)->getDataType();
3521 break;
3522 case DCO_TYPE_TABLE:
3523 dataType = DCI_DT_STRING;
3524 break;
3525 default:
3526 dataType = DCI_DT_STRING;
3527 break;
3528 }
3529
3530 // Allocate memory for data and prepare data header
3531 pData = (DCI_DATA_HEADER *)malloc(numRows * m_dwRowSize[dataType] + sizeof(DCI_DATA_HEADER));
3532 pData->dwDataType = htonl((DWORD)dataType);
3533 pData->dwItemId = htonl(dci->getId());
3534
3535 // Fill memory block with records
3536 pCurr = (DCI_DATA_ROW *)(((char *)pData) + sizeof(DCI_DATA_HEADER));
3537 for(DWORD i = 0; i < numRows; i++)
3538 {
3539 pCurr->dwTimeStamp = htonl(DBGetFieldULong(hResult, i, 0));
3540 switch(dataType)
3541 {
3542 case DCI_DT_INT:
3543 case DCI_DT_UINT:
3544 pCurr->value.dwInteger = htonl(DBGetFieldULong(hResult, i, 1));
3545 break;
3546 case DCI_DT_INT64:
3547 case DCI_DT_UINT64:
3548 pCurr->value.qwInt64 = htonq(DBGetFieldUInt64(hResult, i, 1));
3549 break;
3550 case DCI_DT_FLOAT:
3551 pCurr->value.dFloat = htond(DBGetFieldDouble(hResult, i, 1));
3552 break;
3553 case DCI_DT_STRING:
3554 #ifdef UNICODE
3555 #ifdef UNICODE_UCS4
3556 DBGetField(hResult, i, 1, szBuffer, MAX_DCI_STRING_VALUE);
3557 ucs4_to_ucs2(szBuffer, -1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3558 #else
3559 DBGetField(hResult, i, 1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3560 #endif
3561 #else
3562 DBGetField(hResult, i, 1, szBuffer, MAX_DCI_STRING_VALUE);
3563 mb_to_ucs2(szBuffer, -1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3564 #endif
3565 SwapWideString(pCurr->value.szString);
3566 break;
3567 }
3568 pCurr = (DCI_DATA_ROW *)(((char *)pCurr) + m_dwRowSize[dataType]);
3569 }
3570 DBFreeResult(hResult);
3571 pData->dwNumRows = htonl(numRows);
3572
3573 // Prepare and send raw message with fetched data
3574 CSCP_MESSAGE *msg =
3575 CreateRawNXCPMessage(CMD_DCI_DATA, request->GetId(), 0,
3576 numRows * m_dwRowSize[dataType] + sizeof(DCI_DATA_HEADER),
3577 pData, NULL);
3578 free(pData);
3579 sendRawMessage(msg);
3580 free(msg);
3581 success = true;
3582 }
3583 else
3584 {
3585 response->SetVariable(VID_RCC, RCC_DB_FAILURE);
3586 }
3587 DBFreeStatement(hStmt);
3588 }
3589 else
3590 {
3591 response->SetVariable(VID_RCC, RCC_DB_FAILURE);
3592 }
3593 DBConnectionPoolReleaseConnection(hdb);
3594 return success;
3595 }
3596
3597 /**
3598 * Get collected data
3599 */
3600 void ClientSession::getCollectedData(CSCPMessage *request)
3601 {
3602 CSCPMessage msg;
3603 bool success = false;
3604
3605 // Prepare response message
3606 msg.SetCode(CMD_REQUEST_COMPLETED);
3607 msg.SetId(request->GetId());
3608
3609 NetObj *object = FindObjectById(request->GetVariableLong(VID_OBJECT_ID));
3610 if (object != NULL)
3611 {
3612 if (object->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3613 {
3614 if ((object->Type() == OBJECT_NODE) || (object->Type() == OBJECT_MOBILEDEVICE))
3615 {
3616 if (!(g_dwFlags & AF_DB_CONNECTION_LOST))
3617 {
3618 success = getCollectedDataFromDB(request, &msg, (DataCollectionTarget *)object, DCO_TYPE_ITEM);
3619 }
3620 else
3621 {
3622 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
3623 }
3624 }
3625 else
3626 {
3627 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3628 }
3629 }
3630 else
3631 {
3632 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3633 }
3634 }
3635 else // No object with given ID
3636 {
3637 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3638 }
3639
3640 // Send response
3641 if (!success)
3642 sendMessage(&msg);
3643 }
3644
3645 /**
3646 * Get collected data for table DCI
3647 */
3648 void ClientSession::getTableCollectedData(CSCPMessage *request)
3649 {
3650 CSCPMessage msg;
3651 bool success = false;
3652
3653 // Prepare response message
3654 msg.SetCode(CMD_REQUEST_COMPLETED);
3655 msg.SetId(request->GetId());
3656
3657 NetObj *object = FindObjectById(request->GetVariableLong(VID_OBJECT_ID));
3658 if (object != NULL)
3659 {
3660 if (object->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3661 {
3662 if ((object->Type() == OBJECT_NODE) || (object->Type() == OBJECT_MOBILEDEVICE))
3663 {
3664 if (!(g_dwFlags & AF_DB_CONNECTION_LOST))
3665 {
3666 success = getCollectedDataFromDB(request, &msg, (DataCollectionTarget *)object, DCO_TYPE_TABLE);
3667 }
3668 else
3669 {
3670 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
3671 }
3672 }
3673 else
3674 {
3675 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3676 }
3677 }
3678 else
3679 {
3680 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3681 }
3682 }
3683 else
3684 {
3685 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3686 }
3687
3688 if (!success)
3689 sendMessage(&msg);
3690 }
3691
3692 /**
3693 * Send latest collected values for all DCIs of given node
3694 */
3695 void ClientSession::getLastValues(CSCPMessage *pRequest)
3696 {
3697 CSCPMessage msg;
3698 NetObj *pObject;
3699
3700 // Prepare response message
3701 msg.SetCode(CMD_REQUEST_COMPLETED);
3702 msg.SetId(pRequest->GetId());
3703
3704 // Get node id and check object class and access rights
3705 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3706 if (pObject != NULL)
3707 {
3708 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3709 {
3710 if ((pObject->Type() == OBJECT_NODE) || (pObject->Type() == OBJECT_MOBILEDEVICE))
3711 {
3712 msg.SetVariable(VID_RCC, ((DataCollectionTarget *)pObject)->getLastValues(&msg));
3713 }
3714 else
3715 {
3716 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3717 }
3718 }
3719 else
3720 {
3721 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3722 }
3723 }
3724 else // No object with given ID
3725 {
3726 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3727 }
3728