Rollback from r3608 to r3606
[public/netxms.git] / src / server / core / session.cpp
CommitLineData
5039dede
AK
1/* $Id$ */
2/*
3** NetXMS - Network Management System
4** Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: session.cpp
21**
22**/
23
24#include "nxcore.h"
25#include "nxmp_parser.h"
26
27#ifdef _WIN32
28#include <psapi.h>
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
38// WARNING! this hack works only for d2i_X509(); be carefull when adding new code
39#ifdef OPENSSL_CONST
40# undef OPENSSL_CONST
41#endif
42#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
43# define OPENSSL_CONST const
44#else
45# define OPENSSL_CONST
46#endif
47
48
49//
50// Constants
51//
52
53#define TRAP_CREATE 1
54#define TRAP_UPDATE 2
55#define TRAP_DELETE 3
56
57#define RAW_MSG_SIZE 262144
58
59
60//
61// Externals
62//
63
64extern Queue g_statusPollQueue;
65extern Queue g_configPollQueue;
66extern Queue g_routePollQueue;
67extern Queue g_discoveryPollQueue;
68extern Queue g_nodePollerQueue;
69extern Queue g_conditionPollerQueue;
70extern Queue *g_pItemQueue;
71
72void UnregisterSession(DWORD dwIndex);
73void ResetDiscoveryPoller(void);
74
75
76//
77// Node poller start data
78//
79
80typedef struct
81{
82 ClientSession *pSession;
83 Node *pNode;
84 int iPollType;
85 DWORD dwRqId;
86} POLLER_START_DATA;
87
88
89//
90// Additional processing thread strt data
91//
92
93typedef struct
94{
95 ClientSession *pSession;
96 CSCPMessage *pMsg;
97} PROCTHREAD_START_DATA;
98
99
100//
101// Object tool acl entry
102//
103
104typedef struct
105{
106 DWORD dwToolId;
107 DWORD dwUserId;
108} OBJECT_TOOL_ACL;
109
110
111//
112// Graph ACL entry
113//
114
115struct GRAPH_ACL_ENTRY
116{
117 DWORD dwGraphId;
118 DWORD dwUserId;
119 DWORD dwAccess;
120};
121
122
123//
124// Additional message processing thread starters
125//
126
127#define CALL_IN_NEW_THREAD(func, msg) \
128{ \
129 PROCTHREAD_START_DATA *pData = (PROCTHREAD_START_DATA *)malloc(sizeof(PROCTHREAD_START_DATA)); \
130 pData->pSession = this; \
131 pData->pMsg = msg; \
132 msg = NULL; /* prevent deletion by main processing thread*/ \
133 m_dwRefCount++; \
134 ThreadCreate(ThreadStarter_##func, 0, pData); \
135}
136
137#define DEFINE_THREAD_STARTER(func) \
138THREAD_RESULT THREAD_CALL ClientSession::ThreadStarter_##func(void *pArg) \
139{ \
140 ((PROCTHREAD_START_DATA *)pArg)->pSession->func(((PROCTHREAD_START_DATA *)pArg)->pMsg); \
141 ((PROCTHREAD_START_DATA *)pArg)->pSession->m_dwRefCount--; \
142 delete ((PROCTHREAD_START_DATA *)pArg)->pMsg; \
143 free(pArg); \
144 return THREAD_OK; \
145}
146
147DEFINE_THREAD_STARTER(GetCollectedData)
148DEFINE_THREAD_STARTER(ClearDCIData)
149DEFINE_THREAD_STARTER(QueryL2Topology)
150DEFINE_THREAD_STARTER(SendEventLog)
151DEFINE_THREAD_STARTER(SendSyslog)
152DEFINE_THREAD_STARTER(CreateObject)
153DEFINE_THREAD_STARTER(GetServerFile)
154
155
156//
157// Fill CSCP message with user data
158//
159
160static void FillUserInfoMessage(CSCPMessage *pMsg, NETXMS_USER *pUser)
161{
162 pMsg->SetVariable(VID_USER_ID, pUser->dwId);
163 pMsg->SetVariable(VID_USER_NAME, pUser->szName);
164 pMsg->SetVariable(VID_USER_FLAGS, pUser->wFlags);
165 pMsg->SetVariable(VID_USER_SYS_RIGHTS, pUser->dwSystemRights);
166 pMsg->SetVariable(VID_USER_FULL_NAME, pUser->szFullName);
167 pMsg->SetVariable(VID_USER_DESCRIPTION, pUser->szDescription);
168 pMsg->SetVariable(VID_GUID, pUser->guid, UUID_LENGTH);
169 pMsg->SetVariable(VID_AUTH_METHOD, (WORD)pUser->nAuthMethod);
170 pMsg->SetVariable(VID_CERT_MAPPING_METHOD, (WORD)pUser->nCertMappingMethod);
171 pMsg->SetVariable(VID_CERT_MAPPING_DATA, CHECK_NULL_EX(pUser->pszCertMappingData));
172}
173
174
175//
176// Fill CSCP message with user group data
177//
178
179static void FillGroupInfoMessage(CSCPMessage *pMsg, NETXMS_USER_GROUP *pGroup)
180{
181 DWORD i, dwId;
182
183 pMsg->SetVariable(VID_USER_ID, pGroup->dwId);
184 pMsg->SetVariable(VID_USER_NAME, pGroup->szName);
185 pMsg->SetVariable(VID_USER_FLAGS, pGroup->wFlags);
186 pMsg->SetVariable(VID_USER_SYS_RIGHTS, pGroup->dwSystemRights);
187 pMsg->SetVariable(VID_USER_DESCRIPTION, pGroup->szDescription);
188 pMsg->SetVariable(VID_NUM_MEMBERS, pGroup->dwNumMembers);
189 pMsg->SetVariable(VID_GUID, pGroup->guid, UUID_LENGTH);
190 for(i = 0, dwId = VID_GROUP_MEMBER_BASE; i < pGroup->dwNumMembers; i++, dwId++)
191 pMsg->SetVariable(dwId, pGroup->pMembers[i]);
192}
193
194
195//
196// Client communication read thread starter
197//
198
199THREAD_RESULT THREAD_CALL ClientSession::ReadThreadStarter(void *pArg)
200{
201 ((ClientSession *)pArg)->ReadThread();
202
203 // When ClientSession::ReadThread exits, all other session
204 // threads are already stopped, so we can safely destroy
205 // session object
206 UnregisterSession(((ClientSession *)pArg)->GetIndex());
207 delete (ClientSession *)pArg;
208 return THREAD_OK;
209}
210
211
212//
213// Client communication write thread starter
214//
215
216THREAD_RESULT THREAD_CALL ClientSession::WriteThreadStarter(void *pArg)
217{
218 ((ClientSession *)pArg)->WriteThread();
219 return THREAD_OK;
220}
221
222
223//
224// Received message processing thread starter
225//
226
227THREAD_RESULT THREAD_CALL ClientSession::ProcessingThreadStarter(void *pArg)
228{
229 ((ClientSession *)pArg)->ProcessingThread();
230 return THREAD_OK;
231}
232
233
234//
235// Information update processing thread starter
236//
237
238THREAD_RESULT THREAD_CALL ClientSession::UpdateThreadStarter(void *pArg)
239{
240 ((ClientSession *)pArg)->UpdateThread();
241 return THREAD_OK;
242}
243
244
245//
246// Forced node poll thread starter
247//
248
249THREAD_RESULT THREAD_CALL ClientSession::PollerThreadStarter(void *pArg)
250{
251 ((POLLER_START_DATA *)pArg)->pSession->PollerThread(
252 ((POLLER_START_DATA *)pArg)->pNode,
253 ((POLLER_START_DATA *)pArg)->iPollType,
254 ((POLLER_START_DATA *)pArg)->dwRqId);
255 ((POLLER_START_DATA *)pArg)->pSession->DecRefCount();
256 free(pArg);
257 return THREAD_OK;
258}
259
260
261//
262// Client session class constructor
263//
264
265ClientSession::ClientSession(SOCKET hSocket, DWORD dwHostAddr)
266{
267 m_pSendQueue = new Queue;
268 m_pMessageQueue = new Queue;
269 m_pUpdateQueue = new Queue;
270 m_hSocket = hSocket;
271 m_dwIndex = INVALID_INDEX;
272 m_iState = SESSION_STATE_INIT;
273 m_pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
274 m_pCtx = NULL;
275 m_hWriteThread = INVALID_THREAD_HANDLE;
276 m_hProcessingThread = INVALID_THREAD_HANDLE;
277 m_hUpdateThread = INVALID_THREAD_HANDLE;
278 m_mutexSendEvents = MutexCreate();
279 m_mutexSendSyslog = MutexCreate();
280 m_mutexSendTrapLog = MutexCreate();
281 m_mutexSendObjects = MutexCreate();
282 m_mutexSendAlarms = MutexCreate();
283 m_mutexSendActions = MutexCreate();
284 m_mutexSendAuditLog = MutexCreate();
285 m_mutexSendSituations = MutexCreate();
286 m_mutexPollerInit = MutexCreate();
287 m_dwFlags = 0;
288 m_dwHostAddr = dwHostAddr;
289 IpToStr(dwHostAddr, m_szWorkstation);
290 strcpy(m_szUserName, "<not logged in>");
291 m_dwUserId = INVALID_INDEX;
292 m_dwOpenDCIListSize = 0;
293 m_pOpenDCIList = NULL;
294 m_ppEPPRuleList = NULL;
295 m_hCurrFile = -1;
296 m_dwFileRqId = 0;
297 m_dwRefCount = 0;
298 m_dwEncryptionRqId = 0;
299 m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
300 m_dwActiveChannels = 0;
301}
302
303
304//
305// Destructor
306//
307
308ClientSession::~ClientSession()
309{
310 if (m_hSocket != -1)
311 closesocket(m_hSocket);
312 delete m_pSendQueue;
313 delete m_pMessageQueue;
314 delete m_pUpdateQueue;
315 safe_free(m_pMsgBuffer);
316 MutexDestroy(m_mutexSendEvents);
317 MutexDestroy(m_mutexSendSyslog);
318 MutexDestroy(m_mutexSendTrapLog);
319 MutexDestroy(m_mutexSendObjects);
320 MutexDestroy(m_mutexSendAlarms);
321 MutexDestroy(m_mutexSendActions);
322 MutexDestroy(m_mutexSendAuditLog);
323 MutexDestroy(m_mutexSendSituations);
324 MutexDestroy(m_mutexPollerInit);
325 safe_free(m_pOpenDCIList);
326 if (m_ppEPPRuleList != NULL)
327 {
328 DWORD i;
329
330 if (m_dwFlags & CSF_EPP_UPLOAD) // Aborted in the middle of EPP transfer
331 for(i = 0; i < m_dwRecordsUploaded; i++)
332 delete m_ppEPPRuleList[i];
333 free(m_ppEPPRuleList);
334 }
335 DestroyEncryptionContext(m_pCtx);
336 if (m_condEncryptionSetup != INVALID_CONDITION_HANDLE)
337 ConditionDestroy(m_condEncryptionSetup);
338}
339
340
341//
342// Start all threads
343//
344
345void ClientSession::Run(void)
346{
347 m_hWriteThread = ThreadCreateEx(WriteThreadStarter, 0, this);
348 m_hProcessingThread = ThreadCreateEx(ProcessingThreadStarter, 0, this);
349 m_hUpdateThread = ThreadCreateEx(UpdateThreadStarter, 0, this);
350 ThreadCreate(ReadThreadStarter, 0, this);
351}
352
353
354//
355// Print debug information
356//
357
358void ClientSession::DebugPrintf(int level, const TCHAR *format, ...)
359{
360 if (level <= g_nDebugLevel)
361 {
362 va_list args;
363 TCHAR buffer[4096];
364
365 va_start(args, format);
366 _vsntprintf(buffer, 4096, format, args);
367 va_end(args);
368 DbgPrintf(level, _T("[CLSN-%d] %s"), m_dwIndex, buffer);
369 }
370}
371
372
373//
374// ReadThread()
375//
376
377void ClientSession::ReadThread(void)
378{
379 CSCP_MESSAGE *pRawMsg;
380 CSCPMessage *pMsg;
381 BYTE *pDecryptionBuffer = NULL;
382 TCHAR szBuffer[256];
383 int iErr;
384 DWORD i;
385 NetObj *pObject;
386 WORD wFlags;
387
388 // Initialize raw message receiving function
389 RecvNXCPMessage(0, NULL, m_pMsgBuffer, 0, NULL, NULL, 0);
390
391 pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
392#ifdef _WITH_ENCRYPTION
393 pDecryptionBuffer = (BYTE *)malloc(RAW_MSG_SIZE);
394#endif
395 while(1)
396 {
397 if ((iErr = RecvNXCPMessage(m_hSocket, pRawMsg,
398 m_pMsgBuffer, RAW_MSG_SIZE,
399 &m_pCtx, pDecryptionBuffer, INFINITE)) <= 0)
400 break;
401
402 // Check if message is too large
403 if (iErr == 1)
404 {
405 DebugPrintf(4, "Received message %s is too large (%d bytes)",
406 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
407 ntohl(pRawMsg->dwSize));
408 continue;
409 }
410
411 // Check for decryption error
412 if (iErr == 2)
413 {
414 DebugPrintf(4, "Unable to decrypt received message");
415 continue;
416 }
417
418 // Check that actual received packet size is equal to encoded in packet
419 if ((int)ntohl(pRawMsg->dwSize) != iErr)
420 {
421 DebugPrintf(4, "Actual message size doesn't match wSize value (%d,%d)", iErr, ntohl(pRawMsg->dwSize));
422 continue; // Bad packet, wait for next
423 }
424
425 // Special handling for raw messages
426 wFlags = ntohs(pRawMsg->wFlags);
427 if (wFlags & MF_BINARY)
428 {
429 // Convert message header to host format
430 pRawMsg->dwId = ntohl(pRawMsg->dwId);
431 pRawMsg->wCode = ntohs(pRawMsg->wCode);
432 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
433 DebugPrintf(6, "Received raw message %s", NXCPMessageCodeName(pRawMsg->wCode, szBuffer));
434
435 if ((pRawMsg->wCode == CMD_FILE_DATA) ||
436 (pRawMsg->wCode == CMD_ABORT_FILE_TRANSFER))
437 {
438 if ((m_hCurrFile != -1) && (m_dwFileRqId == pRawMsg->dwId))
439 {
440 if (pRawMsg->wCode == CMD_FILE_DATA)
441 {
442 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
443 {
444 if (wFlags & MF_END_OF_FILE)
445 {
446 CSCPMessage msg;
447
448 close(m_hCurrFile);
449 m_hCurrFile = -1;
450
451 msg.SetCode(CMD_REQUEST_COMPLETED);
452 msg.SetId(pRawMsg->dwId);
453 msg.SetVariable(VID_RCC, RCC_SUCCESS);
454 SendMessage(&msg);
455
456 OnFileUpload(TRUE);
457 }
458 }
459 else
460 {
461 // I/O error
462 CSCPMessage msg;
463
464 close(m_hCurrFile);
465 m_hCurrFile = -1;
466
467 msg.SetCode(CMD_REQUEST_COMPLETED);
468 msg.SetId(pRawMsg->dwId);
469 msg.SetVariable(VID_RCC, RCC_IO_ERROR);
470 SendMessage(&msg);
471
472 OnFileUpload(FALSE);
473 }
474 }
475 else
476 {
477 // Abort current file transfer because of client's problem
478 close(m_hCurrFile);
479 m_hCurrFile = -1;
480
481 OnFileUpload(FALSE);
482 }
483 }
484 else
485 {
486 DebugPrintf(4, "Out of state message (ID: %d)", pRawMsg->dwId);
487 }
488 }
489 }
490 else
491 {
492 // Create message object from raw message
493 pMsg = new CSCPMessage(pRawMsg);
494 if ((pMsg->GetCode() == CMD_SESSION_KEY) && (pMsg->GetId() == m_dwEncryptionRqId))
495 {
496 m_dwEncryptionResult = SetupEncryptionContext(pMsg, &m_pCtx, NULL, g_pServerKey, NXCP_VERSION);
497 ConditionSet(m_condEncryptionSetup);
498 m_dwEncryptionRqId = 0;
499 delete pMsg;
500 }
501 else if (pMsg->GetCode() == CMD_KEEPALIVE)
502 {
503 DebugPrintf(6, "Received message %s", NXCPMessageCodeName(pMsg->GetCode(), szBuffer));
504 RespondToKeepalive(pMsg->GetId());
505 delete pMsg;
506 }
507 else
508 {
509 m_pMessageQueue->Put(pMsg);
510 }
511 }
512 }
513 if (iErr < 0)
514 nxlog_write(MSG_SESSION_CLOSED, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
515 free(pRawMsg);
516#ifdef _WITH_ENCRYPTION
517 free(pDecryptionBuffer);
518#endif
519
520 // Notify other threads to exit
521 m_pSendQueue->Clear();
522 m_pSendQueue->Put(INVALID_POINTER_VALUE);
523 m_pMessageQueue->Clear();
524 m_pMessageQueue->Put(INVALID_POINTER_VALUE);
525 m_pUpdateQueue->Clear();
526 m_pUpdateQueue->Put(INVALID_POINTER_VALUE);
527
528 // Wait for other threads to finish
529 ThreadJoin(m_hWriteThread);
530 ThreadJoin(m_hProcessingThread);
531 ThreadJoin(m_hUpdateThread);
532
533 // Abort current file upload operation, if any
534 if (m_hCurrFile != -1)
535 {
536 close(m_hCurrFile);
537 m_hCurrFile = -1;
538 OnFileUpload(FALSE);
539 }
540
541 // Remove all locks created by this session
542 RemoveAllSessionLocks(m_dwIndex);
543 for(i = 0; i < m_dwOpenDCIListSize; i++)
544 {
545 pObject = FindObjectById(m_pOpenDCIList[i]);
546 if (pObject != NULL)
547 if ((pObject->Type() == OBJECT_NODE) ||
548 (pObject->Type() == OBJECT_CLUSTER) ||
549 (pObject->Type() == OBJECT_TEMPLATE))
550 ((Template *)pObject)->UnlockDCIList(m_dwIndex);
551 }
552
553 // Waiting while reference count becomes 0
554 if (m_dwRefCount > 0)
555 {
556 DebugPrintf(3, "Waiting for pending requests...");
557 do
558 {
559 ThreadSleep(1);
560 } while(m_dwRefCount > 0);
561 }
562
563 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_szWorkstation, 0, _T("User logged out (client: %s)"), m_szClientInfo);
564 DebugPrintf(3, "Session closed");
565}
566
567
568//
569// WriteThread()
570//
571
572void ClientSession::WriteThread(void)
573{
574 CSCP_MESSAGE *pRawMsg;
575 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
576 char szBuffer[128];
577 BOOL bResult;
578
579 while(1)
580 {
581 pRawMsg = (CSCP_MESSAGE *)m_pSendQueue->GetOrBlock();
582 if (pRawMsg == INVALID_POINTER_VALUE) // Session termination indicator
583 break;
584
585 DebugPrintf(6, "Sending message %s", NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer));
586 if (m_pCtx != NULL)
587 {
588 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
589 if (pEnMsg != NULL)
590 {
591 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
592 free(pEnMsg);
593 }
594 else
595 {
596 bResult = FALSE;
597 }
598 }
599 else
600 {
601 bResult = (SendEx(m_hSocket, (const char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
602 }
603 free(pRawMsg);
604
605 if (!bResult)
606 {
607 closesocket(m_hSocket);
608 m_hSocket = -1;
609 break;
610 }
611 }
612}
613
614
615//
616// Update processing thread
617//
618
619void ClientSession::UpdateThread(void)
620{
621 UPDATE_INFO *pUpdate;
622 CSCPMessage msg;
623
624 while(1)
625 {
626 pUpdate = (UPDATE_INFO *)m_pUpdateQueue->GetOrBlock();
627 if (pUpdate == INVALID_POINTER_VALUE) // Session termination indicator
628 break;
629
630 switch(pUpdate->dwCategory)
631 {
632 case INFO_CAT_EVENT:
633 MutexLock(m_mutexSendEvents, INFINITE);
634 SendMessage((CSCPMessage *)pUpdate->pData);
635 MutexUnlock(m_mutexSendEvents);
636 delete (CSCPMessage *)pUpdate->pData;
637 break;
638 case INFO_CAT_SYSLOG_MSG:
639 MutexLock(m_mutexSendSyslog, INFINITE);
640 msg.SetCode(CMD_SYSLOG_RECORDS);
641 CreateMessageFromSyslogMsg(&msg, (NX_LOG_RECORD *)pUpdate->pData);
642 SendMessage(&msg);
643 MutexUnlock(m_mutexSendSyslog);
644 free(pUpdate->pData);
645 break;
646 case INFO_CAT_SNMP_TRAP:
647 MutexLock(m_mutexSendTrapLog, INFINITE);
648 SendMessage((CSCPMessage *)pUpdate->pData);
649 MutexUnlock(m_mutexSendTrapLog);
650 delete (CSCPMessage *)pUpdate->pData;
651 break;
652 case INFO_CAT_AUDIT_RECORD:
653 MutexLock(m_mutexSendAuditLog, INFINITE);
654 SendMessage((CSCPMessage *)pUpdate->pData);
655 MutexUnlock(m_mutexSendAuditLog);
656 delete (CSCPMessage *)pUpdate->pData;
657 break;
658 case INFO_CAT_OBJECT_CHANGE:
659 MutexLock(m_mutexSendObjects, INFINITE);
660 msg.SetCode(CMD_OBJECT_UPDATE);
661 ((NetObj *)pUpdate->pData)->CreateMessage(&msg);
662 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
663 ((NetObj *)pUpdate->pData)->CommentsToMessage(&msg);
664 SendMessage(&msg);
665 MutexUnlock(m_mutexSendObjects);
666 msg.DeleteAllVariables();
667 ((NetObj *)pUpdate->pData)->DecRefCount();
668 break;
669 case INFO_CAT_ALARM:
670 MutexLock(m_mutexSendAlarms, INFINITE);
671 msg.SetCode(CMD_ALARM_UPDATE);
672 msg.SetVariable(VID_NOTIFICATION_CODE, pUpdate->dwCode);
673 FillAlarmInfoMessage(&msg, (NXC_ALARM *)pUpdate->pData);
674 SendMessage(&msg);
675 MutexUnlock(m_mutexSendAlarms);
676 msg.DeleteAllVariables();
677 free(pUpdate->pData);
678 break;
679 case INFO_CAT_ACTION:
680 MutexLock(m_mutexSendActions, INFINITE);
681 msg.SetCode(CMD_ACTION_DB_UPDATE);
682 msg.SetVariable(VID_NOTIFICATION_CODE, pUpdate->dwCode);
683 msg.SetVariable(VID_ACTION_ID, ((NXC_ACTION *)pUpdate->pData)->dwId);
684 if (pUpdate->dwCode != NX_NOTIFY_ACTION_DELETED)
685 FillActionInfoMessage(&msg, (NXC_ACTION *)pUpdate->pData);
686 SendMessage(&msg);
687 MutexUnlock(m_mutexSendActions);
688 msg.DeleteAllVariables();
689 free(pUpdate->pData);
690 break;
691 case INFO_CAT_SITUATION:
692 MutexLock(m_mutexSendSituations, INFINITE);
693 SendMessage((CSCPMessage *)pUpdate->pData);
694 MutexUnlock(m_mutexSendSituations);
695 delete (CSCPMessage *)pUpdate->pData;
696 break;
697 default:
698 break;
699 }
700
701 free(pUpdate);
702 }
703}
704
705
706//
707// Message processing thread
708//
709
710void ClientSession::ProcessingThread(void)
711{
712 CSCPMessage *pMsg;
713 char szBuffer[128];
714 DWORD i;
715 int status;
716
717 while(1)
718 {
719 pMsg = (CSCPMessage *)m_pMessageQueue->GetOrBlock();
720 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
721 break;
722
723 m_wCurrentCmd = pMsg->GetCode();
724 DebugPrintf(6, "Received message %s", NXCPMessageCodeName(m_wCurrentCmd, szBuffer));
725 if (!(m_dwFlags & CSF_AUTHENTICATED) &&
726 (m_wCurrentCmd != CMD_LOGIN) &&
727 (m_wCurrentCmd != CMD_GET_SERVER_INFO) &&
728 (m_wCurrentCmd != CMD_REQUEST_ENCRYPTION) &&
729 (m_wCurrentCmd != CMD_GET_MY_CONFIG))
730 {
731 delete pMsg;
732 continue;
733 }
734
735 m_iState = SESSION_STATE_PROCESSING;
736 switch(m_wCurrentCmd)
737 {
738 case CMD_LOGIN:
739 Login(pMsg);
740 break;
741 case CMD_GET_SERVER_INFO:
742 SendServerInfo(pMsg->GetId());
743 break;
744 case CMD_KEEPALIVE:
745 RespondToKeepalive(pMsg->GetId());
746 break;
747 case CMD_GET_MY_CONFIG:
748 SendConfigForAgent(pMsg);
749 break;
750 case CMD_GET_OBJECTS:
751 SendAllObjects(pMsg);
752 break;
753 case CMD_GET_EVENTS:
754 CALL_IN_NEW_THREAD(SendEventLog, pMsg);
755 break;
756 case CMD_GET_CONFIG_VARLIST:
757 SendAllConfigVars(pMsg->GetId());
758 break;
759 case CMD_SET_CONFIG_VARIABLE:
760 SetConfigVariable(pMsg);
761 break;
762 case CMD_DELETE_CONFIG_VARIABLE:
763 DeleteConfigVariable(pMsg);
764 break;
765 case CMD_CONFIG_GET_CLOB:
766 GetConfigCLOB(pMsg);
767 break;
768 case CMD_CONFIG_SET_CLOB:
769 SetConfigCLOB(pMsg);
770 break;
771 case CMD_LOAD_EVENT_DB:
772 SendEventDB(pMsg->GetId());
773 break;
774 case CMD_LOCK_EVENT_DB:
775 LockEventDB(pMsg->GetId());
776 break;
777 case CMD_UNLOCK_EVENT_DB:
778 UnlockEventDB(pMsg->GetId());
779 break;
780 case CMD_SET_EVENT_INFO:
781 SetEventInfo(pMsg);
782 break;
783 case CMD_DELETE_EVENT_TEMPLATE:
784 DeleteEventTemplate(pMsg);
785 break;
786 case CMD_GENERATE_EVENT_CODE:
787 GenerateEventCode(pMsg->GetId());
788 break;
789 case CMD_MODIFY_OBJECT:
790 ModifyObject(pMsg);
791 break;
792 case CMD_SET_OBJECT_MGMT_STATUS:
793 ChangeObjectMgmtStatus(pMsg);
794 break;
795 case CMD_LOAD_USER_DB:
796 SendUserDB(pMsg->GetId());
797 break;
798 case CMD_CREATE_USER:
799 CreateUser(pMsg);
800 break;
801 case CMD_UPDATE_USER:
802 UpdateUser(pMsg);
803 break;
804 case CMD_DELETE_USER:
805 DeleteUser(pMsg);
806 break;
807 case CMD_LOCK_USER_DB:
808 LockUserDB(pMsg->GetId(), TRUE);
809 break;
810 case CMD_UNLOCK_USER_DB:
811 LockUserDB(pMsg->GetId(), FALSE);
812 break;
813 case CMD_SET_PASSWORD:
814 SetPassword(pMsg);
815 break;
816 case CMD_GET_NODE_DCI_LIST:
817 OpenNodeDCIList(pMsg);
818 break;
819 case CMD_UNLOCK_NODE_DCI_LIST:
820 CloseNodeDCIList(pMsg);
821 break;
822 case CMD_CREATE_NEW_DCI:
823 case CMD_MODIFY_NODE_DCI:
824 case CMD_DELETE_NODE_DCI:
825 ModifyNodeDCI(pMsg);
826 break;
827 case CMD_SET_DCI_STATUS:
828 ChangeDCIStatus(pMsg);
829 break;
830 case CMD_COPY_DCI:
831 CopyDCI(pMsg);
832 break;
833 case CMD_APPLY_TEMPLATE:
834 ApplyTemplate(pMsg);
835 break;
836 case CMD_GET_DCI_DATA:
837 CALL_IN_NEW_THREAD(GetCollectedData, pMsg);
838 break;
839 case CMD_CLEAR_DCI_DATA:
840 CALL_IN_NEW_THREAD(ClearDCIData, pMsg);
841 break;
842 case CMD_OPEN_EPP:
843 OpenEPP(pMsg->GetId());
844 break;
845 case CMD_CLOSE_EPP:
846 CloseEPP(pMsg->GetId());
847 break;
848 case CMD_SAVE_EPP:
849 SaveEPP(pMsg);
850 break;
851 case CMD_EPP_RECORD:
852 ProcessEPPRecord(pMsg);
853 break;
854 case CMD_GET_MIB_TIMESTAMP:
855 SendMIBTimestamp(pMsg->GetId());
856 break;
857 case CMD_GET_MIB:
858 SendMIB(pMsg->GetId());
859 break;
860 case CMD_CREATE_OBJECT:
861 CALL_IN_NEW_THREAD(CreateObject, pMsg);
862 break;
863 case CMD_BIND_OBJECT:
864 ChangeObjectBinding(pMsg, TRUE);
865 break;
866 case CMD_UNBIND_OBJECT:
867 ChangeObjectBinding(pMsg, FALSE);
868 break;
869 case CMD_GET_IMAGE_LIST:
870 SendImageCatalogue(this, pMsg->GetId(), pMsg->GetVariableShort(VID_IMAGE_FORMAT));
871 break;
872 case CMD_LOAD_IMAGE_FILE:
873 SendImageFile(this, pMsg->GetId(), pMsg->GetVariableLong(VID_IMAGE_ID),
874 pMsg->GetVariableShort(VID_IMAGE_FORMAT));
875 break;
876 case CMD_GET_DEFAULT_IMAGE_LIST:
877 SendDefaultImageList(this, pMsg->GetId());
878 break;
879 case CMD_GET_ALL_ALARMS:
880 SendAllAlarms(pMsg->GetId(), pMsg->GetVariableShort(VID_IS_ACK));
881 break;
882 case CMD_GET_ALARM:
883 break;
884 case CMD_ACK_ALARM:
885 AcknowledgeAlarm(pMsg);
886 break;
887 case CMD_TERMINATE_ALARM:
888 TerminateAlarm(pMsg);
889 break;
890 case CMD_DELETE_ALARM:
891 DeleteAlarm(pMsg);
892 break;
893 case CMD_LOCK_ACTION_DB:
894 LockActionDB(pMsg->GetId(), TRUE);
895 break;
896 case CMD_UNLOCK_ACTION_DB:
897 LockActionDB(pMsg->GetId(), FALSE);
898 break;
899 case CMD_CREATE_ACTION:
900 CreateAction(pMsg);
901 break;
902 case CMD_MODIFY_ACTION:
903 UpdateAction(pMsg);
904 break;
905 case CMD_DELETE_ACTION:
906 DeleteAction(pMsg);
907 break;
908 case CMD_LOAD_ACTIONS:
909 SendAllActions(pMsg->GetId());
910 break;
911 case CMD_GET_CONTAINER_CAT_LIST:
912 SendContainerCategories(pMsg->GetId());
913 break;
914 case CMD_DELETE_OBJECT:
915 DeleteObject(pMsg);
916 break;
917 case CMD_POLL_NODE:
918 ForcedNodePoll(pMsg);
919 break;
920 case CMD_TRAP:
921 OnTrap(pMsg);
922 break;
923 case CMD_WAKEUP_NODE:
924 OnWakeUpNode(pMsg);
925 break;
926 case CMD_LOCK_TRAP_CFG:
927 LockTrapCfg(pMsg->GetId(), TRUE);
928 break;
929 case CMD_UNLOCK_TRAP_CFG:
930 LockTrapCfg(pMsg->GetId(), FALSE);
931 break;
932 case CMD_CREATE_TRAP:
933 EditTrap(TRAP_CREATE, pMsg);
934 break;
935 case CMD_MODIFY_TRAP:
936 EditTrap(TRAP_UPDATE, pMsg);
937 break;
938 case CMD_DELETE_TRAP:
939 EditTrap(TRAP_DELETE, pMsg);
940 break;
941 case CMD_LOAD_TRAP_CFG:
942 SendAllTraps(pMsg->GetId());
943 break;
944 case CMD_GET_TRAP_CFG_RO:
945 SendAllTraps2(pMsg->GetId());
946 break;
947 case CMD_QUERY_PARAMETER:
948 QueryParameter(pMsg);
949 break;
950 case CMD_LOCK_PACKAGE_DB:
951 LockPackageDB(pMsg->GetId(), TRUE);
952 break;
953 case CMD_UNLOCK_PACKAGE_DB:
954 LockPackageDB(pMsg->GetId(), FALSE);
955 break;
956 case CMD_GET_PACKAGE_LIST:
957 SendAllPackages(pMsg->GetId());
958 break;
959 case CMD_INSTALL_PACKAGE:
960 InstallPackage(pMsg);
961 break;
962 case CMD_REMOVE_PACKAGE:
963 RemovePackage(pMsg);
964 break;
965 case CMD_GET_PARAMETER_LIST:
966 SendParametersList(pMsg);
967 break;
968 case CMD_DEPLOY_PACKAGE:
969 DeployPackage(pMsg);
970 break;
971 case CMD_GET_LAST_VALUES:
972 SendLastValues(pMsg);
973 break;
974 case CMD_GET_USER_VARIABLE:
975 GetUserVariable(pMsg);
976 break;
977 case CMD_SET_USER_VARIABLE:
978 SetUserVariable(pMsg);
979 break;
980 case CMD_DELETE_USER_VARIABLE:
981 DeleteUserVariable(pMsg);
982 break;
983 case CMD_ENUM_USER_VARIABLES:
984 EnumUserVariables(pMsg);
985 break;
986 case CMD_COPY_USER_VARIABLE:
987 CopyUserVariable(pMsg);
988 break;
989 case CMD_CHANGE_IP_ADDR:
990 ChangeObjectIP(pMsg);
991 break;
992 case CMD_REQUEST_ENCRYPTION:
993 SetupEncryption(pMsg->GetId());
994 break;
995 case CMD_GET_AGENT_CONFIG:
996 GetAgentConfig(pMsg);
997 break;
998 case CMD_UPDATE_AGENT_CONFIG:
999 UpdateAgentConfig(pMsg);
1000 break;
1001 case CMD_EXECUTE_ACTION:
1002 ExecuteAction(pMsg);
1003 break;
1004 case CMD_GET_OBJECT_TOOLS:
1005 SendObjectTools(pMsg->GetId());
1006 break;
1007 case CMD_EXEC_TABLE_TOOL:
1008 ExecTableTool(pMsg);
1009 break;
1010 case CMD_LOCK_OBJECT_TOOLS:
1011 LockObjectTools(pMsg->GetId(), TRUE);
1012 break;
1013 case CMD_UNLOCK_OBJECT_TOOLS:
1014 LockObjectTools(pMsg->GetId(), FALSE);
1015 break;
1016 case CMD_GET_OBJECT_TOOL_DETAILS:
1017 SendObjectToolDetails(pMsg);
1018 break;
1019 case CMD_UPDATE_OBJECT_TOOL:
1020 UpdateObjectTool(pMsg);
1021 break;
1022 case CMD_DELETE_OBJECT_TOOL:
1023 DeleteObjectTool(pMsg);
1024 break;
1025 case CMD_GENERATE_OBJECT_TOOL_ID:
1026 GenerateObjectToolId(pMsg->GetId());
1027 break;
1028 case CMD_CHANGE_SUBSCRIPTION:
1029 ChangeSubscription(pMsg);
1030 break;
1031 case CMD_GET_SYSLOG:
1032 CALL_IN_NEW_THREAD(SendSyslog, pMsg);
1033 break;
1034 case CMD_GET_LPP_LIST:
1035 SendLogPoliciesList(pMsg->GetId());
1036 break;
1037 case CMD_REQUEST_NEW_LPP_ID:
1038 CreateNewLPPID(pMsg->GetId());
1039 break;
1040 case CMD_OPEN_LPP:
1041 OpenLPP(pMsg);
1042 break;
1043 case CMD_GET_SERVER_STATS:
1044 SendServerStats(pMsg->GetId());
1045 break;
1046 case CMD_GET_SCRIPT_LIST:
1047 SendScriptList(pMsg->GetId());
1048 break;
1049 case CMD_GET_SCRIPT:
1050 SendScript(pMsg);
1051 break;
1052 case CMD_UPDATE_SCRIPT:
1053 UpdateScript(pMsg);
1054 break;
1055 case CMD_RENAME_SCRIPT:
1056 RenameScript(pMsg);
1057 break;
1058 case CMD_DELETE_SCRIPT:
1059 DeleteScript(pMsg);
1060 break;
1061 case CMD_GET_SESSION_LIST:
1062 SendSessionList(pMsg->GetId());
1063 break;
1064 case CMD_KILL_SESSION:
1065 KillSession(pMsg);
1066 break;
1067 case CMD_GET_TRAP_LOG:
1068 SendTrapLog(pMsg);
1069 break;
1070 case CMD_START_SNMP_WALK:
1071 StartSnmpWalk(pMsg);
1072 break;
1073 case CMD_GET_MAP_LIST:
1074 SendMapList(pMsg->GetId());
1075 break;
1076 case CMD_RESOLVE_MAP_NAME:
1077 ResolveMapName(pMsg);
1078 break;
1079 case CMD_CREATE_MAP:
1080 CreateMap(pMsg);
1081 break;
1082 case CMD_RENAME_MAP:
1083 RenameMap(pMsg);
1084 break;
1085 case CMD_SAVE_MAP:
1086 SaveMap(pMsg);
1087 break;
1088 case CMD_SUBMAP_DATA:
1089 ProcessSubmapData(pMsg);
1090 break;
1091 case CMD_LOAD_MAP:
1092 LoadMap(pMsg);
1093 break;
1094 case CMD_UPLOAD_SUBMAP_BK_IMAGE:
1095 RecvSubmapBkImage(pMsg);
1096 break;
1097 case CMD_GET_SUBMAP_BK_IMAGE:
1098 SendSubmapBkImage(pMsg);
1099 break;
1100 case CMD_RESOLVE_DCI_NAMES:
1101 ResolveDCINames(pMsg);
1102 break;
1103 case CMD_GET_DCI_INFO:
1104 SendDCIInfo(pMsg);
1105 break;
1106 case CMD_GET_DCI_EVENTS_LIST:
1107 SendDCIEventList(pMsg);
1108 break;
1109 case CMD_GET_SYSTEM_DCI_LIST:
1110 SendSystemDCIList(pMsg);
1111 break;
1112 case CMD_PUSH_DCI_DATA:
1113 PushDCIData(pMsg);
1114 break;
1115 case CMD_GET_AGENT_CFG_LIST:
1116 SendAgentCfgList(pMsg->GetId());
1117 break;
1118 case CMD_OPEN_AGENT_CONFIG:
1119 OpenAgentConfig(pMsg);
1120 break;
1121 case CMD_SAVE_AGENT_CONFIG:
1122 SaveAgentConfig(pMsg);
1123 break;
1124 case CMD_DELETE_AGENT_CONFIG:
1125 DeleteAgentConfig(pMsg);
1126 break;
1127 case CMD_SWAP_AGENT_CONFIGS:
1128 SwapAgentConfigs(pMsg);
1129 break;
1130 case CMD_GET_OBJECT_COMMENTS:
1131 SendObjectComments(pMsg);
1132 break;
1133 case CMD_UPDATE_OBJECT_COMMENTS:
1134 UpdateObjectComments(pMsg);
1135 break;
1136 case CMD_GET_ADDR_LIST:
1137 GetAddrList(pMsg);
1138 break;
1139 case CMD_SET_ADDR_LIST:
1140 SetAddrList(pMsg);
1141 break;
1142 case CMD_RESET_COMPONENT:
1143 ResetComponent(pMsg);
1144 break;
1145 case CMD_CREATE_MGMT_PACK:
1146 CreateManagementPack(pMsg);
1147 break;
1148 case CMD_INSTALL_MGMT_PACK:
1149 InstallManagementPack(pMsg);
1150 break;
1151 case CMD_GET_GRAPH_LIST:
1152 SendGraphList(pMsg->GetId());
1153 break;
1154 case CMD_DEFINE_GRAPH:
1155 DefineGraph(pMsg);
1156 break;
1157 case CMD_DELETE_GRAPH:
1158 DeleteGraph(pMsg);
1159 break;
1160 case CMD_ADD_CA_CERTIFICATE:
1161 AddCACertificate(pMsg);
1162 break;
1163 case CMD_DELETE_CERTIFICATE:
1164 DeleteCertificate(pMsg);
1165 break;
1166 case CMD_UPDATE_CERT_COMMENTS:
1167 UpdateCertificateComments(pMsg);
1168 break;
1169 case CMD_GET_CERT_LIST:
1170 SendCertificateList(pMsg->GetId());
1171 break;
1172 case CMD_QUERY_L2_TOPOLOGY:
1173 CALL_IN_NEW_THREAD(QueryL2Topology, pMsg);
1174 break;
1175 case CMD_SEND_SMS:
1176 SendSMS(pMsg);
1177 break;
1178 case CMD_GET_COMMUNITY_LIST:
1179 SendCommunityList(pMsg->GetId());
1180 break;
1181 case CMD_UPDATE_COMMUNITY_LIST:
1182 UpdateCommunityList(pMsg);
1183 break;
1184 case CMD_GET_SITUATION_LIST:
1185 SendSituationList(pMsg->GetId());
1186 break;
1187 case CMD_CREATE_SITUATION:
1188 CreateSituation(pMsg);
1189 break;
1190 case CMD_UPDATE_SITUATION:
1191 UpdateSituation(pMsg);
1192 break;
1193 case CMD_DELETE_SITUATION:
1194 DeleteSituation(pMsg);
1195 break;
1196 case CMD_DEL_SITUATION_INSTANCE:
1197 DeleteSituationInstance(pMsg);
1198 break;
1199 case CMD_WEBMAP_ADD:
1200 WebMapAdd(pMsg);
1201 break;
1202 case CMD_WEBMAP_UPDATE_PROPS:
1203 WebMapUpdateProps(pMsg);
1204 break;
1205 case CMD_WEBMAP_UPDATE_DATA:
1206 WebMapUpdateData(pMsg);
1207 break;
1208 case CMD_WEBMAP_DELETE:
1209 WebMapDelete(pMsg);
1210 break;
1211 case CMD_WEBMAP_GET_DATA:
1212 WebMapGetData(pMsg);
1213 break;
1214 case CMD_WEBMAP_GET_LIST:
1215 WebMapGetList(pMsg->GetId());
1216 break;
1217 case CMD_REGISTER_AGENT:
1218 RegisterAgent(pMsg);
1219 break;
1220 case CMD_GET_SERVER_FILE:
1221 CALL_IN_NEW_THREAD(GetServerFile, pMsg);
1222 break;
1223 default:
1224 // Pass message to loaded modules
1225 for(i = 0; i < g_dwNumModules; i++)
1226 {
1227 if (g_pModuleList[i].pfCommandHandler != NULL)
1228 {
1229 status = g_pModuleList[i].pfCommandHandler(m_wCurrentCmd, pMsg, this);
1230 if (status != NXMOD_COMMAND_IGNORED)
1231 {
1232 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
1233 {
1234 pMsg = NULL; // Prevent deletion
1235 m_dwRefCount++;
1236 }
1237 break; // Message was processed by the module
1238 }
1239 }
1240 }
1241 if (i == g_dwNumModules)
1242 {
1243 CSCPMessage response;
1244
1245 response.SetId(pMsg->GetId());
1246 response.SetCode(CMD_REQUEST_COMPLETED);
1247 response.SetVariable(VID_RCC, RCC_NOT_IMPLEMENTED);
1248 SendMessage(&response);
1249 }
1250 break;
1251 }
1252 delete pMsg;
1253 m_iState = (m_dwFlags & CSF_AUTHENTICATED) ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
1254 }
1255}
1256
1257
1258//
1259// Respond to client's keepalive message
1260//
1261
1262void ClientSession::RespondToKeepalive(DWORD dwRqId)
1263{
1264 CSCPMessage msg;
1265
1266 msg.SetCode(CMD_REQUEST_COMPLETED);
1267 msg.SetId(dwRqId);
1268 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1269 SendMessage(&msg);
1270}
1271
1272
1273//
1274// Process received file
1275//
1276
1277void ClientSession::OnFileUpload(BOOL bSuccess)
1278{
1279 // Do processing specific to command initiated file upload
1280 switch(m_dwUploadCommand)
1281 {
1282 case CMD_INSTALL_PACKAGE:
1283 if (!bSuccess)
1284 {
1285 TCHAR szQuery[256];
1286
1287 _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_dwUploadData);
1288 DBQuery(g_hCoreDB, szQuery);
1289 }
1290 break;
1291 default:
1292 break;
1293 }
1294
1295 // Remove received file in case of failure
1296 if (!bSuccess)
1297 _tunlink(m_szCurrFileName);
1298}
1299
1300
1301//
1302// Send server information to client
1303//
1304
1305void ClientSession::SendServerInfo(DWORD dwRqId)
1306{
1307 CSCPMessage msg;
1308 TCHAR szBuffer[1024];
1309 String strURL;
1310
1311 // Prepare response message
1312 msg.SetCode(CMD_REQUEST_COMPLETED);
1313 msg.SetId(dwRqId);
1314
1315 // Generate challenge for certificate authentication
1316#ifdef _WITH_ENCRYPTION
1317 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
1318#else
1319 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
1320#endif
1321
1322 // Fill message with server info
1323 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1324 msg.SetVariable(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
1325 msg.SetVariable(VID_SERVER_ID, (BYTE *)&g_qwServerId, sizeof(QWORD));
1326 msg.SetVariable(VID_SUPPORTED_ENCRYPTION, (DWORD)0);
1327 msg.SetVariable(VID_PROTOCOL_VERSION, (DWORD)CLIENT_PROTOCOL_VERSION);
1328 msg.SetVariable(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
1329
1330#if defined(_WIN32)
1331 TIME_ZONE_INFORMATION tz;
1332 WCHAR wst[4], wdt[8], *curr;
1333 int i;
1334
1335 GetTimeZoneInformation(&tz);
1336
1337 // Create 3 letter abbreviation for standard name
1338 for(i = 0, curr = tz.StandardName; (*curr != 0) && (i < 3); curr++)
1339 if (iswupper(*curr))
1340 wst[i++] = *curr;
1341 while(i < 3)
1342 wst[i++] = L'X';
1343 wst[i] = 0;
1344
1345 // Create abbreviation for DST name
1346 for(i = 0, curr = tz.DaylightName; (*curr != 0) && (i < 7); curr++)
1347 if (iswupper(*curr))
1348 wdt[i++] = *curr;
1349 while(i < 3)
1350 wdt[i++] = L'X';
1351 wdt[i] = 0;
1352
1353#ifdef UNICODE
1354 swprintf(szBuffer, L"%s%c%02d%s", wst, (tz.Bias >= 0) ? '+' : '-',
1355 abs(tz.Bias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1356#else
1357 sprintf(szBuffer, "%S%c%02d%S", wst, (tz.Bias >= 0) ? '+' : '-',
1358 abs(tz.Bias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1359#endif
1360#elif HAVE_DECL_TIMEZONE
1361 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (timezone >= 0) ? '+' : '-',
1362 abs(timezone) / 3600, (tzname[1] != NULL) ? tzname[1] : "");
1363#elif HAVE_TM_GMTOFF
1364 time_t t;
1365 struct tm *loc;
1366 int gmtOffset;
1367#if HAVE_LOCALTIME_R
1368 struct tm tmbuff;
1369#endif
1370
1371 t = time(NULL);
1372#if HAVE_LOCALTIME_R
1373 loc = localtime_r(&t, &tmbuff);
1374#else
1375 loc = localtime(&t);
1376#endif
1377 gmtOffset = -loc->tm_gmtoff / 3600;
1378 if (loc->tm_isdst)
1379 gmtOffset++;
1380 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1381 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1382#else
1383 szBuffer[0] = 0;
1384#endif
1385 msg.SetVariable(VID_TIMEZONE, szBuffer);
1386 DebugPrintf(2, "Server time zone: %s", szBuffer);
1387
1388 ConfigReadStr(_T("WindowsConsoleUpgradeURL"), szBuffer, 1024,
1389 _T("http://www.netxms.org/download/netxms-%version%.exe"));
1390 strURL = szBuffer;
1391 strURL.Translate(_T("%version%"), NETXMS_VERSION_STRING);
1392 msg.SetVariable(VID_CONSOLE_UPGRADE_URL, (TCHAR *)strURL);
1393
1394 // Send response
1395 SendMessage(&msg);
1396}
1397
1398
1399//
1400// Authenticate client
1401//
1402
1403void ClientSession::Login(CSCPMessage *pRequest)
1404{
1405 CSCPMessage msg;
1406 TCHAR szLogin[MAX_USER_NAME], szPassword[MAX_DB_STRING], szBuffer[32];
1407 int nAuthType;
1408 BOOL bChangePasswd;
1409 DWORD dwResult;
1410#ifdef _WITH_ENCRYPTION
1411 X509 *pCert;
1412#endif
1413
1414 // Prepare response message
1415 msg.SetCode(CMD_LOGIN_RESP);
1416 msg.SetId(pRequest->GetId());
1417
1418 // Get client info string
1419 if (pRequest->IsVariableExist(VID_CLIENT_INFO))
1420 {
1421 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
1422
1423 pRequest->GetVariableStr(VID_CLIENT_INFO, szClientInfo, 32);
1424 pRequest->GetVariableStr(VID_OS_INFO, szOSInfo, 32);
1425 pRequest->GetVariableStr(VID_LIBNXCL_VERSION, szLibVersion, 16);
1426 _sntprintf(m_szClientInfo, 96, _T("%s (%s; libnxcl %s)"),
1427 szClientInfo, szOSInfo, szLibVersion);
1428 }
1429
1430 if (!(m_dwFlags & CSF_AUTHENTICATED))
1431 {
1432 pRequest->GetVariableStr(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
1433 nAuthType = (int)pRequest->GetVariableShort(VID_AUTH_TYPE);
1434 switch(nAuthType)
1435 {
1436 case NETXMS_AUTH_TYPE_PASSWORD:
1437 pRequest->GetVariableStr(VID_PASSWORD, szPassword, MAX_DB_STRING);
1438 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
1439 &m_dwSystemAccess, &bChangePasswd);
1440 break;
1441 case NETXMS_AUTH_TYPE_CERTIFICATE:
1442#ifdef _WITH_ENCRYPTION
1443 pCert = CertificateFromLoginMessage(pRequest);
1444 if (pCert != NULL)
1445 {
1446 BYTE signature[256];
1447 DWORD dwSigLen;
1448
1449 dwSigLen = pRequest->GetVariableBinary(VID_SIGNATURE, signature, 256);
1450 dwResult = AuthenticateUser(szLogin, (TCHAR *)signature, dwSigLen, pCert,
1451 m_challenge, &m_dwUserId, &m_dwSystemAccess, &bChangePasswd);
1452 X509_free(pCert);
1453 }
1454 else
1455 {
1456 dwResult = RCC_BAD_CERTIFICATE;
1457 }
1458#else
1459 dwResult = RCC_NOT_IMPLEMENTED;
1460#endif
1461 break;
1462 default:
1463 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
1464 break;
1465 }
1466
1467 if (dwResult == RCC_SUCCESS)
1468 {
1469 m_dwFlags |= CSF_AUTHENTICATED;
1470 sprintf(m_szUserName, "%s@%s", szLogin, IpToStr(m_dwHostAddr, szBuffer));
1471 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1472 msg.SetVariable(VID_USER_SYS_RIGHTS, m_dwSystemAccess);
1473 msg.SetVariable(VID_USER_ID, m_dwUserId);
1474 msg.SetVariable(VID_CHANGE_PASSWD_FLAG, (WORD)bChangePasswd);
1475 msg.SetVariable(VID_DBCONN_STATUS, (WORD)((g_dwFlags & AF_DB_CONNECTION_LOST) ? FALSE : TRUE));
1476 DebugPrintf(3, "User %s authenticated", m_szUserName);
1477 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_szWorkstation, 0,
1478 _T("User \"%s\" logged in (client info: %s)"), szLogin, m_szClientInfo);
1479 }
1480 else
1481 {
1482 msg.SetVariable(VID_RCC, dwResult);
1483 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szWorkstation, 0,
1484 _T("User \"%s\" login failed with error code %d (client info: %s)"),
1485 szLogin, dwResult, m_szClientInfo);
1486 }
1487 }
1488 else
1489 {
1490 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1491 }
1492
1493 // Send response
1494 SendMessage(&msg);
1495}
1496
1497
1498//
1499// Send event configuration to client
1500//
1501
1502void ClientSession::SendEventDB(DWORD dwRqId)
1503{
1504 DB_ASYNC_RESULT hResult;
1505 CSCPMessage msg;
1506 char szBuffer[1024];
1507
1508 // Prepare response message
1509 msg.SetCode(CMD_REQUEST_COMPLETED);
1510 msg.SetId(dwRqId);
1511
1512 if (CheckSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB))
1513 {
1514 if (!(g_dwFlags & AF_DB_CONNECTION_LOST))
1515 {
1516 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1517 SendMessage(&msg);
1518 msg.DeleteAllVariables();
1519
1520 // Prepare data message
1521 msg.SetCode(CMD_EVENT_DB_RECORD);
1522 msg.SetId(dwRqId);
1523
1524 hResult = DBAsyncSelect(g_hCoreDB, "SELECT event_code,event_name,severity,flags,message,description FROM event_cfg");
1525 if (hResult != NULL)
1526 {
1527 while(DBFetch(hResult))
1528 {
1529 msg.SetVariable(VID_EVENT_CODE, DBGetFieldAsyncULong(hResult, 0));
1530 msg.SetVariable(VID_NAME, DBGetFieldAsync(hResult, 1, szBuffer, 1024));
1531 msg.SetVariable(VID_SEVERITY, DBGetFieldAsyncULong(hResult, 2));
1532 msg.SetVariable(VID_FLAGS, DBGetFieldAsyncULong(hResult, 3));
1533
1534 DBGetFieldAsync(hResult, 4, szBuffer, 1024);
1535 DecodeSQLString(szBuffer);
1536 msg.SetVariable(VID_MESSAGE, szBuffer);
1537
1538 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
1539 DecodeSQLString(szBuffer);
1540 msg.SetVariable(VID_DESCRIPTION, szBuffer);
1541
1542 SendMessage(&msg);
1543 msg.DeleteAllVariables();
1544 }
1545 DBFreeAsyncResult(g_hCoreDB, hResult);
1546 }
1547
1548 // End-of-list indicator
1549 msg.SetVariable(VID_EVENT_CODE, (DWORD)0);
1550 }
1551 else
1552 {
1553 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
1554 }
1555 }
1556 else
1557 {
1558 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1559 }
1560 SendMessage(&msg);
1561}
1562
1563
1564//
1565// Lock event configuration database
1566//
1567
1568void ClientSession::LockEventDB(DWORD dwRqId)
1569{
1570 CSCPMessage msg;
1571 char szBuffer[1024];
1572
1573 // Prepare response message
1574 msg.SetCode(CMD_REQUEST_COMPLETED);
1575 msg.SetId(dwRqId);
1576
1577 if (!CheckSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1578 {
1579 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1580 }
1581 else if (!LockComponent(CID_EVENT_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
1582 {
1583 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
1584 msg.SetVariable(VID_LOCKED_BY, szBuffer);
1585 }
1586 else
1587 {
1588 m_dwFlags |= CSF_EVENT_DB_LOCKED;
1589 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1590 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
1591 _T("Event configuration database locked"));
1592 }
1593 SendMessage(&msg);
1594}
1595
1596
1597//
1598// Close event configuration database
1599//
1600
1601void ClientSession::UnlockEventDB(DWORD dwRqId)
1602{
1603 CSCPMessage msg;
1604
1605 msg.SetCode(CMD_REQUEST_COMPLETED);
1606 msg.SetId(dwRqId);
1607
1608 if (m_dwFlags & CSF_EVENT_DB_LOCKED)
1609 {
1610 UnlockComponent(CID_EVENT_DB);
1611 m_dwFlags &= ~CSF_EVENT_DB_LOCKED;
1612 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1613 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
1614 _T("Event configuration database unlocked"));
1615 }
1616 else
1617 {
1618 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1619 }
1620 SendMessage(&msg);
1621}
1622
1623
1624//
1625// Update event template
1626//
1627
1628void ClientSession::SetEventInfo(CSCPMessage *pRequest)
1629{
1630 CSCPMessage msg;
1631
1632 // Prepare reply message
1633 msg.SetCode(CMD_REQUEST_COMPLETED);
1634 msg.SetId(pRequest->GetId());
1635
1636 // Check if we have event configuration database opened
1637 if (!(m_dwFlags & CSF_EVENT_DB_LOCKED))
1638 {
1639 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1640 }
1641 else
1642 {
1643 // Check access rights
1644 if (CheckSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1645 {
1646 char szQuery[4096], szName[MAX_EVENT_NAME];
1647 DWORD dwEventCode;
1648 BOOL bEventExist = FALSE;
1649 DB_RESULT hResult;
1650
1651 // Check if event with specific code exists
1652 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
1653 sprintf(szQuery, "SELECT event_code FROM event_cfg WHERE event_code=%d", dwEventCode);
1654 hResult = DBSelect(g_hCoreDB, szQuery);
1655 if (hResult != NULL)
1656 {
1657 if (DBGetNumRows(hResult) > 0)
1658 bEventExist = TRUE;
1659 DBFreeResult(hResult);
1660 }
1661
1662 // Check that we are not trying to create event below 100000
1663 if (bEventExist || (dwEventCode >= FIRST_USER_EVENT_ID))
1664 {
1665 // Prepare and execute SQL query
1666 pRequest->GetVariableStr(VID_NAME, szName, MAX_EVENT_NAME);
1667 if (IsValidObjectName(szName))
1668 {
1669 char szMessage[MAX_DB_STRING], *pszDescription, *pszEscMsg, *pszEscDescr;
1670
1671 pRequest->GetVariableStr(VID_MESSAGE, szMessage, MAX_DB_STRING);
1672 pszEscMsg = EncodeSQLString(szMessage);
1673
1674 pszDescription = pRequest->GetVariableStr(VID_DESCRIPTION);
1675 pszEscDescr = EncodeSQLString(pszDescription);
1676 safe_free(pszDescription);
1677
1678 if (bEventExist)
1679 {
1680 sprintf(szQuery, "UPDATE event_cfg SET event_name='%s',severity=%d,flags=%d,message='%s',description='%s' WHERE event_code=%d",
1681 szName, pRequest->GetVariableLong(VID_SEVERITY), pRequest->GetVariableLong(VID_FLAGS),
1682 pszEscMsg, pszEscDescr, dwEventCode);
1683 }
1684 else
1685 {
1686 sprintf(szQuery, "INSERT INTO event_cfg (event_code,event_name,severity,flags,"
1687 "message,description) VALUES (%d,'%s',%d,%d,'%s','%s')",
1688 dwEventCode, szName, pRequest->GetVariableLong(VID_SEVERITY),
1689 pRequest->GetVariableLong(VID_FLAGS), pszEscMsg, pszEscDescr);
1690 }
1691
1692 free(pszEscMsg);
1693 free(pszEscDescr);
1694
1695 if (DBQuery(g_hCoreDB, szQuery))
1696 {
1697 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1698 ReloadEvents();
1699 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
1700 }
1701 else
1702 {
1703 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
1704 }
1705 }
1706 else
1707 {
1708 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
1709 }
1710 }
1711 else
1712 {
1713 msg.SetVariable(VID_RCC, RCC_INVALID_EVENT_CODE);
1714 }
1715 }
1716 else
1717 {
1718 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1719 }
1720 }
1721
1722 // Send response
1723 SendMessage(&msg);
1724}
1725
1726
1727//
1728// Delete event template
1729//
1730
1731void ClientSession::DeleteEventTemplate(CSCPMessage *pRequest)
1732{
1733 CSCPMessage msg;
1734 DWORD dwEventCode;
1735
1736 // Prepare reply message
1737 msg.SetCode(CMD_REQUEST_COMPLETED);
1738 msg.SetId(pRequest->GetId());
1739
1740 // Check if we have event configuration database opened
1741 if (!(m_dwFlags & CSF_EVENT_DB_LOCKED))
1742 {
1743 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1744 }
1745 else
1746 {
1747 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
1748
1749 // Check access rights
1750 if (CheckSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
1751 {
1752 TCHAR szQuery[256];
1753
1754 _stprintf(szQuery, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
1755 if (DBQuery(g_hCoreDB, szQuery))
1756 {
1757 DeleteEventTemplateFromList(dwEventCode);
1758 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
1759 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1760
1761 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
1762 _T("Event template %d deleted"), dwEventCode);
1763 }
1764 else
1765 {
1766 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
1767 }
1768 }
1769 else
1770 {
1771 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1772 }
1773 }
1774
1775 // Send response
1776 SendMessage(&msg);
1777}
1778
1779
1780//
1781// Generate ID for new event template
1782//
1783
1784void ClientSession::GenerateEventCode(DWORD dwRqId)
1785{
1786 CSCPMessage msg;
1787
1788 // Prepare reply message
1789 msg.SetCode(CMD_REQUEST_COMPLETED);
1790 msg.SetId(dwRqId);
1791
1792 // Check if we have event configuration database opened
1793 if (!(m_dwFlags & CSF_EVENT_DB_LOCKED))
1794 {
1795 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1796 }
1797 else
1798 {
1799 // Check access rights
1800 if (CheckSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1801 {
1802 msg.SetVariable(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
1803 }
1804 else
1805 {
1806 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1807 }
1808 }
1809
1810 // Send response
1811 SendMessage(&msg);
1812}
1813
1814
1815//
1816// Send all objects to client
1817//
1818
1819void ClientSession::SendAllObjects(CSCPMessage *pRequest)
1820{
1821 DWORD i, dwTimeStamp;
1822 CSCPMessage msg;
1823
1824 // Send confirmation message
1825 msg.SetCode(CMD_REQUEST_COMPLETED);
1826 msg.SetId(pRequest->GetId());
1827 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1828 SendMessage(&msg);
1829 msg.DeleteAllVariables();
1830
1831 // Change "sync comments" flag
1832 if (pRequest->GetVariableShort(VID_SYNC_COMMENTS))
1833 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
1834 else
1835 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
1836
1837 // Get client's last known time stamp
1838 dwTimeStamp = pRequest->GetVariableLong(VID_TIMESTAMP);
1839
1840 MutexLock(m_mutexSendObjects, INFINITE);
1841
1842 // Prepare message
1843 msg.SetCode(CMD_OBJECT);
1844
1845 // Send objects, one per message
1846 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1847 for(i = 0; i < g_dwIdIndexSize; i++)
1848 if ((((NetObj *)g_pIndexById[i].pObject)->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ)) &&
1849 (((NetObj *)g_pIndexById[i].pObject)->TimeStamp() >= dwTimeStamp) &&
1850 (!(((NetObj *)g_pIndexById[i].pObject)->IsHidden())))
1851 {
1852 ((NetObj *)g_pIndexById[i].pObject)->CreateMessage(&msg);
1853 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
1854 ((NetObj *)g_pIndexById[i].pObject)->CommentsToMessage(&msg);
1855 SendMessage(&msg);
1856 msg.DeleteAllVariables();
1857 }
1858 RWLockUnlock(g_rwlockIdIndex);
1859
1860 // Send end of list notification
1861 msg.SetCode(CMD_OBJECT_LIST_END);
1862 SendMessage(&msg);
1863
1864 MutexUnlock(m_mutexSendObjects);
1865}
1866
1867
1868//
1869// Send event log records to client
1870//
1871
1872void ClientSession::SendEventLog(CSCPMessage *pRequest)
1873{
1874 CSCPMessage msg;
1875 DB_ASYNC_RESULT hResult = NULL;
1876 DB_RESULT hTempResult;
1877 DWORD dwRqId, dwMaxRecords, dwNumRows, dwId;
1878 TCHAR szQuery[1024], szBuffer[1024];
1879 WORD wRecOrder;
1880
1881 dwRqId = pRequest->GetId();
1882 dwMaxRecords = pRequest->GetVariableLong(VID_MAX_RECORDS);
1883 wRecOrder = ((g_dwDBSyntax == DB_SYNTAX_MSSQL) || (g_dwDBSyntax == DB_SYNTAX_ORACLE)) ? RECORD_ORDER_REVERSED : RECORD_ORDER_NORMAL;
1884
1885 // Prepare confirmation message
1886 msg.SetCode(CMD_REQUEST_COMPLETED);
1887 msg.SetId(dwRqId);
1888
1889 MutexLock(m_mutexSendEvents, INFINITE);
1890
1891 // Retrieve events from database
1892 switch(g_dwDBSyntax)
1893 {
1894 case DB_SYNTAX_MYSQL:
1895 case DB_SYNTAX_PGSQL:
1896 case DB_SYNTAX_SQLITE:
1897 hTempResult = DBSelect(g_hCoreDB, _T("SELECT count(*) FROM event_log"));
1898 if (hTempResult != NULL)
1899 {
1900 if (DBGetNumRows(hTempResult) > 0)
1901 {
1902 dwNumRows = DBGetFieldULong(hTempResult, 0, 0);
1903 }
1904 else
1905 {
1906 dwNumRows = 0;
1907 }
1908 DBFreeResult(hTempResult);
1909 }
1910 _sntprintf(szQuery, 1024,
1911 _T("SELECT event_id,event_code,event_timestamp,event_source,")
1912 _T("event_severity,event_message,user_tag FROM event_log ")
1913 _T("ORDER BY event_id LIMIT %u OFFSET %u"),
1914 dwMaxRecords, dwNumRows - min(dwNumRows, dwMaxRecords));
1915 break;
1916 case DB_SYNTAX_MSSQL:
1917 _sntprintf(szQuery, 1024,
1918 _T("SELECT TOP %u event_id,event_code,event_timestamp,event_source,")
1919 _T("event_severity,event_message,user_tag FROM event_log ")
1920 _T("ORDER BY event_id DESC"), dwMaxRecords);
1921 break;
1922 case DB_SYNTAX_ORACLE:
1923 _sntprintf(szQuery, 1024,
1924 _T("SELECT event_id,event_code,event_timestamp,event_source,")
1925 _T("event_severity,event_message,user_tag FROM event_log ")
1926 _T("WHERE ROWNUM <= %u ORDER BY event_id DESC"), dwMaxRecords);
1927 break;
1928 default:
1929 szQuery[0] = 0;
1930 break;
1931 }
1932 hResult = DBAsyncSelect(g_hCoreDB, szQuery);
1933 if (hResult != NULL)
1934 {
1935 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1936 SendMessage(&msg);
1937 msg.DeleteAllVariables();
1938 msg.SetCode(CMD_EVENTLOG_RECORDS);
1939
1940 for(dwId = VID_EVENTLOG_MSG_BASE, dwNumRows = 0; DBFetch(hResult); dwNumRows++)
1941 {
1942 if (dwNumRows == 10)
1943 {
1944 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
1945 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
1946 SendMessage(&msg);
1947 msg.DeleteAllVariables();
1948 dwNumRows = 0;
1949 dwId = VID_EVENTLOG_MSG_BASE;
1950 }
1951 msg.SetVariable(dwId++, DBGetFieldAsyncUInt64(hResult, 0));
1952 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 1));
1953 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 2));
1954 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 3));
1955 msg.SetVariable(dwId++, (WORD)DBGetFieldAsyncLong(hResult, 4));
1956 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
1957 DecodeSQLString(szBuffer);
1958 msg.SetVariable(dwId++, szBuffer);
1959 DBGetFieldAsync(hResult, 6, szBuffer, 1024);
1960 DecodeSQLString(szBuffer);
1961 msg.SetVariable(dwId++, szBuffer);
1962 }
1963 DBFreeAsyncResult(g_hCoreDB, hResult);
1964
1965 // Send remaining records with End-Of-Sequence notification
1966 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
1967 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
1968 msg.SetEndOfSequence();
1969 SendMessage(&msg);
1970 }
1971 else
1972 {
1973 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
1974 SendMessage(&msg);
1975 }
1976
1977 MutexUnlock(m_mutexSendEvents);
1978}
1979
1980
1981//
1982// Send all configuration variables to client
1983//
1984
1985void ClientSession::SendAllConfigVars(DWORD dwRqId)
1986{
1987 DWORD i, dwId, dwNumRecords;
1988 CSCPMessage msg;
1989 DB_RESULT hResult;
1990 TCHAR szBuffer[MAX_DB_STRING];
1991
1992 // Prepare message
1993 msg.SetCode(CMD_REQUEST_COMPLETED);
1994 msg.SetId(dwRqId);
1995
1996 // Check user rights
1997 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
1998 {
1999 // Retrieve configuration variables from database
2000 hResult = DBSelect(g_hCoreDB, "SELECT var_name,var_value,need_server_restart FROM config WHERE is_visible=1");
2001 if (hResult != NULL)
2002 {
2003 // Send events, one per message
2004 dwNumRecords = DBGetNumRows(hResult);
2005 msg.SetVariable(VID_NUM_VARIABLES, dwNumRecords);
2006 for(i = 0, dwId = VID_VARLIST_BASE; i < dwNumRecords; i++)
2007 {
2008 msg.SetVariable(dwId++, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2009 DBGetField(hResult, i, 1, szBuffer, MAX_DB_STRING);
2010 DecodeSQLString(szBuffer);
2011 msg.SetVariable(dwId++, szBuffer);
2012 msg.SetVariable(dwId++, (WORD)DBGetFieldLong(hResult, i, 2));
2013 }
2014 DBFreeResult(hResult);
2015 }
2016 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2017 }
2018 else
2019 {
2020 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2021 }
2022
2023 // Send response
2024 SendMessage(&msg);
2025}
2026
2027
2028//
2029// Set configuration variable's value
2030//
2031
2032void ClientSession::SetConfigVariable(CSCPMessage *pRequest)
2033{
2034 CSCPMessage msg;
2035 TCHAR szName[MAX_OBJECT_NAME], szValue[MAX_DB_STRING];
2036
2037 // Prepare response message
2038 msg.SetCode(CMD_REQUEST_COMPLETED);
2039 msg.SetId(pRequest->GetId());
2040
2041 // Check user rights
2042 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2043 {
2044 pRequest->GetVariableStr(VID_NAME, szName, MAX_OBJECT_NAME);
2045 pRequest->GetVariableStr(VID_VALUE, szValue, MAX_DB_STRING);
2046 if (ConfigWriteStr(szName, szValue, TRUE))
2047 {
2048 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2049 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
2050 _T("Server configuration variable \"%s\" set to \"%s\""), szName, szValue);
2051 }
2052 else
2053 {
2054 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2055 }
2056 }
2057 else
2058 {
2059 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2060 }
2061
2062 // Send response
2063 SendMessage(&msg);
2064}
2065
2066
2067//
2068// Delete configuration variable
2069//
2070
2071void ClientSession::DeleteConfigVariable(CSCPMessage *pRequest)
2072{
2073 CSCPMessage msg;
2074 TCHAR szName[MAX_OBJECT_NAME], szQuery[1024];
2075
2076 // Prepare response message
2077 msg.SetCode(CMD_REQUEST_COMPLETED);
2078 msg.SetId(pRequest->GetId());
2079
2080 // Check user rights
2081 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2082 {
2083 pRequest->GetVariableStr(VID_NAME, szName, MAX_OBJECT_NAME);
2084 _sntprintf(szQuery, 1024, _T("DELETE FROM config WHERE var_name='%s'"), szName);
2085 if (DBQuery(g_hCoreDB, szQuery))
2086 {
2087 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2088 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_szWorkstation, 0,
2089 _T("Server configuration variable \"%s\" deleted"), szName);
2090 }
2091 else
2092 {
2093 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2094 }
2095 }
2096 else
2097 {
2098 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2099 }
2100
2101 // Send response
2102 SendMessage(&msg);
2103}
2104
2105
2106//
2107// Set configuration clob
2108//
2109
2110void ClientSession::SetConfigCLOB(CSCPMessage *pRequest)
2111{
2112 CSCPMessage msg;
2113 TCHAR name[MAX_OBJECT_NAME], *value;
2114
2115 msg.SetId(pRequest->GetId());
2116 msg.SetCode(CMD_REQUEST_COMPLETED);
2117
2118 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2119 {
2120 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2121 value = pRequest->GetVariableStr(VID_VALUE);
2122 if (value != NULL)
2123 {
2124 msg.SetVariable(VID_RCC, ConfigWriteCLOB(name, value, TRUE) ? RCC_SUCCESS : RCC_DB_FAILURE);
2125 free(value);
2126 }
2127 else
2128 {
2129 msg.SetVariable(VID_RCC, RCC_INVALID_REQUEST);
2130 }
2131 }
2132 else
2133 {
2134 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2135 }
2136
2137 SendMessage(&msg);
2138}
2139
2140
2141//
2142// Get value of configuration clob
2143//
2144
2145void ClientSession::GetConfigCLOB(CSCPMessage *pRequest)
2146{
2147 CSCPMessage msg;
2148 TCHAR name[MAX_OBJECT_NAME], *value;
2149
2150 msg.SetId(pRequest->GetId());
2151 msg.SetCode(CMD_REQUEST_COMPLETED);
2152
2153 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2154 {
2155 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2156 value = ConfigReadCLOB(name, NULL);
2157 if (value != NULL)
2158 {
2159 msg.SetVariable(VID_VALUE, value);
2160 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2161 free(value);
2162 }
2163 else
2164 {
2165 msg.SetVariable(VID_RCC, RCC_UNKNOWN_VARIABLE);
2166 }
2167 }
2168 else
2169 {
2170 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2171 }
2172
2173 SendMessage(&msg);
2174}
2175
2176
2177//
2178// Close session forcibly
2179//
2180
2181void ClientSession::Kill(void)
2182{
2183 // We shutdown socket connection, which will cause
2184 // read thread to stop, and other threads will follow
2185 shutdown(m_hSocket, 2);
2186}
2187
2188
2189//
2190// Handler for new events
2191//
2192
2193void ClientSession::OnNewEvent(Event *pEvent)
2194{
2195 UPDATE_INFO *pUpdate;
2196 CSCPMessage *msg;
2197
2198 if (IsAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_EVENTS))
2199 {
2200 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2201 pUpdate->dwCategory = INFO_CAT_EVENT;
2202 msg = new CSCPMessage;
2203 msg->SetCode(CMD_EVENTLOG_RECORDS);
2204 pEvent->PrepareMessage(msg);
2205 pUpdate->pData = msg;
2206 m_pUpdateQueue->Put(pUpdate);
2207 }
2208}
2209
2210
2211//
2212// Handler for object changes
2213//
2214
2215void ClientSession::OnObjectChange(NetObj *pObject)
2216{
2217 UPDATE_INFO *pUpdate;
2218
2219 if (IsAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_OBJECTS))
2220 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2221 {
2222 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2223 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
2224 pUpdate->pData = pObject;
2225 pObject->IncRefCount();
2226 m_pUpdateQueue->Put(pUpdate);
2227 }
2228}
2229
2230
2231//
2232// Send notification message to server
2233//
2234
2235void ClientSession::Notify(DWORD dwCode, DWORD dwData)
2236{
2237 CSCPMessage msg;
2238
2239 msg.SetCode(CMD_NOTIFY);
2240 msg.SetVariable(VID_NOTIFICATION_CODE, dwCode);
2241 msg.SetVariable(VID_NOTIFICATION_DATA, dwData);
2242 SendMessage(&msg);
2243}
2244
2245
2246//
2247// Modify object
2248//
2249
2250void ClientSession::ModifyObject(CSCPMessage *pRequest)
2251{
2252 DWORD dwObjectId, dwResult = RCC_SUCCESS;
2253 NetObj *pObject;
2254 CSCPMessage msg;
2255
2256 // Prepare reply message
2257 msg.SetCode(CMD_REQUEST_COMPLETED);
2258 msg.SetId(pRequest->GetId());
2259
2260 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2261 pObject = FindObjectById(dwObjectId);
2262 if (pObject != NULL)
2263 {
2264 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2265 {
2266 // If user attempts to change object's ACL, check
2267 // if he has OBJECT_ACCESS_ACL permission
2268 if (pRequest->IsVariableExist(VID_ACL_SIZE))
2269 if (!pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
2270 dwResult = RCC_ACCESS_DENIED;
2271
2272 // If allowed, change object and set completion code
2273 if (dwResult != RCC_ACCESS_DENIED)
2274 dwResult = pObject->ModifyFromMessage(pRequest);
2275 msg.SetVariable(VID_RCC, dwResult);
2276
2277 if (dwResult == RCC_SUCCESS)
2278 {
2279 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_szWorkstation, dwObjectId,
2280 _T("Object modified from client"));
2281 }
2282 else
2283 {
2284 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_szWorkstation, dwObjectId,
2285 _T("Failed to modify object from client - error %d"), dwResult);
2286 }
2287 }
2288 else
2289 {
2290 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2291 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_szWorkstation, dwObjectId,
2292 _T("Failed to modify object from client - access denied"), dwResult);
2293 }
2294 }
2295 else
2296 {
2297 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2298 }
2299
2300 // Send response
2301 SendMessage(&msg);
2302}
2303
2304
2305//
2306// Send users database to client
2307//
2308
2309void ClientSession::SendUserDB(DWORD dwRqId)
2310{
2311 CSCPMessage msg;
2312 DWORD i;
2313
2314 // Prepare response message
2315 msg.SetCode(CMD_REQUEST_COMPLETED);
2316 msg.SetId(dwRqId);
2317 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2318 SendMessage(&msg);
2319
2320 // Send users
2321 msg.SetCode(CMD_USER_DATA);
2322 for(i = 0; i < g_dwNumUsers; i++)
2323 {
2324 FillUserInfoMessage(&msg, &g_pUserList[i]);
2325 SendMessage(&msg);
2326 msg.DeleteAllVariables();
2327 }
2328
2329 // Send groups
2330 msg.SetCode(CMD_GROUP_DATA);
2331 for(i = 0; i < g_dwNumGroups; i++)
2332 {
2333 FillGroupInfoMessage(&msg, &g_pGroupList[i]);
2334 SendMessage(&msg);
2335 msg.DeleteAllVariables();
2336 }
2337
2338 // Send end-of-database notification
2339 msg.SetCode(CMD_USER_DB_EOF);
2340 SendMessage(&msg);
2341}
2342
2343
2344//
2345// Create new user
2346//
2347
2348void ClientSession::CreateUser(CSCPMessage *pRequest)
2349{
2350 CSCPMessage msg;
2351
2352 // Prepare response message
2353 msg.SetCode(CMD_REQUEST_COMPLETED);
2354 msg.SetId(pRequest->GetId());
2355
2356 // Check user rights
2357 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2358 {
2359 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2360 }
2361 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2362 {
2363 // User database have to be locked before any
2364 // changes to user database can be made
2365 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2366 }
2367 else
2368 {
2369 DWORD dwResult, dwUserId;
2370 BOOL bIsGroup;
2371 char szUserName[MAX_USER_NAME];
2372
2373 pRequest->GetVariableStr(VID_USER_NAME, szUserName, MAX_USER_NAME);
2374 if (IsValidObjectName(szUserName))
2375 {
2376 bIsGroup = pRequest->GetVariableShort(VID_IS_GROUP);
2377 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
2378 msg.SetVariable(VID_RCC, dwResult);
2379 if (dwResult == RCC_SUCCESS)
2380 msg.SetVariable(VID_USER_ID, dwUserId); // Send id of new user to client
2381 }
2382 else
2383 {
2384 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
2385 }
2386 }
2387
2388 // Send response
2389 SendMessage(&msg);
2390}
2391
2392
2393//
2394// Update existing user's data
2395//
2396
2397void ClientSession::UpdateUser(CSCPMessage *pRequest)
2398{
2399 CSCPMessage msg;
2400
2401 // Prepare response message
2402 msg.SetCode(CMD_REQUEST_COMPLETED);
2403 msg.SetId(pRequest->GetId());
2404
2405 // Check user rights
2406 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2407 {
2408 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2409 }
2410 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2411 {
2412 // User database have to be locked before any
2413 // changes to user database can be made
2414 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2415 }
2416 else
2417 {
2418 DWORD dwUserId, dwResult;
2419
2420 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2421 if (dwUserId & GROUP_FLAG)
2422 {
2423 NETXMS_USER_GROUP group;
2424 DWORD i, dwId;
2425
2426 group.dwId = dwUserId;
2427 pRequest->GetVariableStr(VID_USER_DESCRIPTION, group.szDescription, MAX_USER_DESCR);
2428 pRequest->GetVariableStr(VID_USER_NAME, group.szName, MAX_USER_NAME);
2429 group.wFlags = pRequest->GetVariableShort(VID_USER_FLAGS);
2430 group.dwSystemRights = pRequest->GetVariableLong(VID_USER_SYS_RIGHTS);
2431 group.dwNumMembers = pRequest->GetVariableLong(VID_NUM_MEMBERS);
2432 group.pMembers = (DWORD *)malloc(sizeof(DWORD) * group.dwNumMembers);
2433 for(i = 0, dwId = VID_GROUP_MEMBER_BASE; i < group.dwNumMembers; i++, dwId++)
2434 group.pMembers[i] = pRequest->GetVariableLong(dwId);
2435 dwResult = ModifyGroup(&group);
2436 safe_free(group.pMembers);
2437 }
2438 else
2439 {
2440 NETXMS_USER user;
2441
2442 user.dwId = dwUserId;
2443 pRequest->GetVariableStr(VID_USER_DESCRIPTION, user.szDescription, MAX_USER_DESCR);
2444 pRequest->GetVariableStr(VID_USER_FULL_NAME, user.szFullName, MAX_USER_FULLNAME);
2445 pRequest->GetVariableStr(VID_USER_NAME, user.szName, MAX_USER_NAME);
2446 user.wFlags = pRequest->GetVariableShort(VID_USER_FLAGS);
2447 user.dwSystemRights = pRequest->GetVariableLong(VID_USER_SYS_RIGHTS);
2448 user.nAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
2449 user.nCertMappingMethod = pRequest->GetVariableShort(VID_CERT_MAPPING_METHOD);
2450 user.pszCertMappingData = pRequest->GetVariableStr(VID_CERT_MAPPING_DATA);
2451 dwResult = ModifyUser(&user);
2452 safe_free(user.pszCertMappingData);
2453 }
2454 msg.SetVariable(VID_RCC, dwResult);
2455 }
2456
2457 // Send response
2458 SendMessage(&msg);
2459}
2460
2461
2462//
2463// Delete user
2464//
2465
2466void ClientSession::DeleteUser(CSCPMessage *pRequest)
2467{
2468 CSCPMessage msg;
2469 DWORD dwUserId;
2470
2471 // Prepare response message
2472 msg.SetCode(CMD_REQUEST_COMPLETED);
2473 msg.SetId(pRequest->GetId());
2474
2475 // Check user rights
2476 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2477 {
2478 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2479 }
2480 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2481 {
2482 // User database have to be locked before any
2483 // changes to user database can be made
2484 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2485 }
2486 else
2487 {
2488 // Get Id of user to be deleted
2489 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2490
2491 if (dwUserId != 0)
2492 {
2493 DWORD dwResult;
2494
2495 dwResult = DeleteUserFromDB(dwUserId);
2496 msg.SetVariable(VID_RCC, dwResult);
2497 }
2498 else
2499 {
2500 // Nobody can delete system administrator account
2501 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2502 }
2503 }
2504
2505 // Send response
2506 SendMessage(&msg);
2507}
2508
2509
2510//
2511// Lock/unlock user database
2512//
2513
2514void ClientSession::LockUserDB(DWORD dwRqId, BOOL bLock)
2515{
2516 CSCPMessage msg;
2517 char szBuffer[256];
2518
2519 // Prepare response message
2520 msg.SetCode(CMD_REQUEST_COMPLETED);
2521 msg.SetId(dwRqId);
2522
2523 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
2524 {
2525 if (bLock)
2526 {
2527 if (!LockComponent(CID_USER_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
2528 {
2529 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
2530 msg.SetVariable(VID_LOCKED_BY, szBuffer);
2531 }
2532 else
2533 {
2534 m_dwFlags |= CSF_USER_DB_LOCKED;
2535 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2536 }
2537 }
2538 else
2539 {
2540 if (m_dwFlags & CSF_USER_DB_LOCKED)
2541 {
2542 UnlockComponent(CID_USER_DB);
2543 m_dwFlags &= ~CSF_USER_DB_LOCKED;
2544 }
2545 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2546 }
2547 }
2548 else
2549 {
2550 // Current user has no rights for user account management
2551 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2552 }
2553
2554 // Send response
2555 SendMessage(&msg);
2556}
2557
2558
2559//
2560// Notify client on user database update
2561//
2562
2563void ClientSession::OnUserDBUpdate(int iCode, DWORD dwUserId, NETXMS_USER *pUser, NETXMS_USER_GROUP *pGroup)
2564{
2565 CSCPMessage msg;
2566
2567 if (IsAuthenticated())
2568 {
2569 msg.SetCode(CMD_USER_DB_UPDATE);
2570 msg.SetId(0);
2571 msg.SetVariable(VID_UPDATE_TYPE, (WORD)iCode);
2572
2573 switch(iCode)
2574 {
2575 case USER_DB_CREATE:
2576 msg.SetVariable(VID_USER_ID, dwUserId);
2577 if (dwUserId & GROUP_FLAG)
2578 msg.SetVariable(VID_USER_NAME, pGroup->szName);
2579 else
2580 msg.SetVariable(VID_USER_NAME, pUser->szName);
2581 break;
2582 case USER_DB_MODIFY:
2583 if (dwUserId & GROUP_FLAG)
2584 FillGroupInfoMessage(&msg, pGroup);
2585 else
2586 FillUserInfoMessage(&msg, pUser);
2587 break;
2588 default:
2589 msg.SetVariable(VID_USER_ID, dwUserId);
2590 break;
2591 }
2592
2593 SendMessage(&msg);
2594 }
2595}
2596
2597
2598//
2599// Change management status for the object
2600//
2601
2602void ClientSession::ChangeObjectMgmtStatus(CSCPMessage *pRequest)
2603{
2604 CSCPMessage msg;
2605 DWORD dwObjectId;
2606 NetObj *pObject;
2607
2608 // Prepare response message
2609 msg.SetCode(CMD_REQUEST_COMPLETED);
2610 msg.SetId(pRequest->GetId());
2611
2612 // Get object id and check access rights
2613 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2614 pObject = FindObjectById(dwObjectId);
2615 if (pObject != NULL)
2616 {
2617 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2618 {
2619 if ((pObject->Type() != OBJECT_TEMPLATE) &&
2620 (pObject->Type() != OBJECT_TEMPLATEGROUP) &&
2621 (pObject->Type() != OBJECT_TEMPLATEROOT))
2622 {
2623 BOOL bIsManaged;
2624
2625 bIsManaged = (BOOL)pRequest->GetVariableShort(VID_MGMT_STATUS);
2626 pObject->SetMgmtStatus(bIsManaged);
2627 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2628 }
2629 else
2630 {
2631 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
2632 }
2633 }
2634 else
2635 {
2636 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2637 }
2638 }
2639 else
2640 {
2641 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2642 }
2643
2644 // Send response
2645 SendMessage(&msg);
2646}
2647
2648
2649//
2650// Set user's password
2651//
2652
2653void ClientSession::SetPassword(CSCPMessage *pRequest)
2654{
2655 CSCPMessage msg;
2656 DWORD dwUserId;
2657
2658 // Prepare response message
2659 msg.SetCode(CMD_REQUEST_COMPLETED);
2660 msg.SetId(pRequest->GetId());
2661
2662 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2663
2664 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
2665 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
2666 (dwUserId == m_dwUserId)) // User can change password for itself
2667 {
2668 DWORD dwResult;
2669 BYTE szPassword[SHA1_DIGEST_SIZE];
2670
2671 pRequest->GetVariableBinary(VID_PASSWORD, szPassword, SHA1_DIGEST_SIZE);
2672 dwResult = SetUserPassword(dwUserId, szPassword, dwUserId == m_dwUserId);
2673 msg.SetVariable(VID_RCC, dwResult);
2674 }
2675 else
2676 {
2677 // Current user has no rights to change password for specific user
2678 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2679 }
2680
2681 // Send response
2682 SendMessage(&msg);
2683}
2684
2685
2686//
2687// Send node's DCIs to client and lock data collection settings
2688//
2689
2690void ClientSession::OpenNodeDCIList(CSCPMessage *pRequest)
2691{
2692 CSCPMessage msg;
2693 DWORD dwObjectId;
2694 NetObj *pObject;
2695 BOOL bSuccess = FALSE;
2696 TCHAR szLockInfo[MAX_SESSION_NAME];
2697
2698 // Prepare response message
2699 msg.SetCode(CMD_REQUEST_COMPLETED);
2700 msg.SetId(pRequest->GetId());
2701
2702 // Get node id and check object class and access rights
2703 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2704 pObject = FindObjectById(dwObjectId);
2705 if (pObject != NULL)
2706 {
2707 if ((pObject->Type() == OBJECT_NODE) ||
2708 (pObject->Type() == OBJECT_CLUSTER) ||
2709 (pObject->Type() == OBJECT_TEMPLATE))
2710 {
2711 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2712 {
2713 // Try to lock DCI list
2714 if (((Template *)pObject)->LockDCIList(m_dwIndex, m_szUserName, szLockInfo))
2715 {
2716 bSuccess = TRUE;
2717 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2718
2719 // Modify list of open nodes DCI lists
2720 m_pOpenDCIList = (DWORD *)realloc(m_pOpenDCIList, sizeof(DWORD) * (m_dwOpenDCIListSize + 1));
2721 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
2722 m_dwOpenDCIListSize++;
2723 }
2724 else
2725 {
2726 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
2727 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
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 else
2741 {
2742 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2743 }
2744
2745 // Send response
2746 SendMessage(&msg);
2747
2748 // If DCI list was successfully locked, send it to client
2749 if (bSuccess)
2750 ((Template *)pObject)->SendItemsToClient(this, pRequest->GetId());
2751}
2752
2753
2754//
2755// Unlock node's data collection settings
2756//
2757
2758void ClientSession::CloseNodeDCIList(CSCPMessage *pRequest)
2759{
2760 CSCPMessage msg;
2761 DWORD dwObjectId;
2762 NetObj *pObject;
2763
2764 // Prepare response message
2765 msg.SetCode(CMD_REQUEST_COMPLETED);
2766 msg.SetId(pRequest->GetId());
2767
2768 // Get node id and check object class and access rights
2769 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2770 pObject = FindObjectById(dwObjectId);
2771 if (pObject != NULL)
2772 {
2773 if ((pObject->Type() == OBJECT_NODE) ||
2774 (pObject->Type() == OBJECT_CLUSTER) ||
2775 (pObject->Type() == OBJECT_TEMPLATE))
2776 {
2777 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2778 {
2779 BOOL bSuccess;
2780
2781 // Try to unlock DCI list
2782 bSuccess = ((Template *)pObject)->UnlockDCIList(m_dwIndex);
2783 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
2784
2785 // Modify list of open nodes DCI lists
2786 if (bSuccess)
2787 {
2788 DWORD i;
2789
2790 for(i = 0; i < m_dwOpenDCIListSize; i++)
2791 if (m_pOpenDCIList[i] == dwObjectId)
2792 {
2793 m_dwOpenDCIListSize--;
2794 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1],
2795 sizeof(DWORD) * (m_dwOpenDCIListSize - i));
2796 break;
2797 }
2798 }
2799
2800 // Queue template update
2801 if ((pObject->Type() == OBJECT_TEMPLATE) ||
2802 (pObject->Type() == OBJECT_CLUSTER))
2803 ((Template *)pObject)->QueueUpdate();
2804 }
2805 else
2806 {
2807 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2808 }
2809 }
2810 else
2811 {
2812 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2813 }
2814 }
2815 else
2816 {
2817 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2818 }
2819
2820 // Send response
2821 SendMessage(&msg);
2822}
2823
2824
2825//
2826// Create, modify, or delete data collection item for node
2827//
2828
2829void ClientSession::ModifyNodeDCI(CSCPMessage *pRequest)
2830{
2831 CSCPMessage msg;
2832 DWORD dwObjectId;
2833 NetObj *pObject;
2834
2835 // Prepare response message
2836 msg.SetCode(CMD_REQUEST_COMPLETED);
2837 msg.SetId(pRequest->GetId());
2838
2839 // Get node id and check object class and access rights
2840 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2841 pObject = FindObjectById(dwObjectId);
2842 if (pObject != NULL)
2843 {
2844 if ((pObject->Type() == OBJECT_NODE) ||
2845 (pObject->Type() == OBJECT_CLUSTER) ||
2846 (pObject->Type() == OBJECT_TEMPLATE))
2847 {
2848 if (((Template *)pObject)->IsLockedBySession(m_dwIndex))
2849 {
2850 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2851 {
2852 DWORD i, dwItemId, dwNumMaps, *pdwMapId, *pdwMapIndex;
2853 DCItem *pItem;
2854 BOOL bSuccess;
2855
2856 switch(pRequest->GetCode())
2857 {
2858 case CMD_CREATE_NEW_DCI:
2859 // Create dummy DCI
2860 pItem = new DCItem(CreateUniqueId(IDG_ITEM), "no name", DS_INTERNAL,
2861 DCI_DT_INT, 60, 30, (Node *)pObject);
2862 pItem->SetStatus(ITEM_STATUS_DISABLED);
2863 if (((Template *)pObject)->AddItem(pItem))
2864 {
2865 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2866 // Return new item id to client
2867 msg.SetVariable(VID_DCI_ID, pItem->Id());
2868 }
2869 else // Unable to add item to node
2870 {
2871 delete pItem;
2872 msg.SetVariable(VID_RCC, RCC_DUPLICATE_DCI);
2873 }
2874 break;
2875 case CMD_MODIFY_NODE_DCI:
2876 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
2877 bSuccess = ((Template *)pObject)->UpdateItem(dwItemId, pRequest, &dwNumMaps,
2878 &pdwMapIndex, &pdwMapId);
2879 if (bSuccess)
2880 {
2881 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2882
2883 // Send index to id mapping for newly created thresholds to client
2884 msg.SetVariable(VID_DCI_NUM_MAPS, dwNumMaps);
2885 for(i = 0; i < dwNumMaps; i++)
2886 {
2887 pdwMapId[i] = htonl(pdwMapId[i]);
2888 pdwMapIndex[i] = htonl(pdwMapIndex[i]);
2889 }
2890 msg.SetVariable(VID_DCI_MAP_IDS, (BYTE *)pdwMapId, sizeof(DWORD) * dwNumMaps);
2891 msg.SetVariable(VID_DCI_MAP_INDEXES, (BYTE *)pdwMapIndex, sizeof(DWORD) * dwNumMaps);
2892 safe_free(pdwMapId);
2893 safe_free(pdwMapIndex);
2894 }
2895 else
2896 {
2897 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
2898 }
2899 break;
2900 case CMD_DELETE_NODE_DCI:
2901 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
2902 bSuccess = ((Template *)pObject)->DeleteItem(dwItemId, TRUE);
2903 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_INVALID_DCI_ID);
2904 break;
2905 }
2906 if (bSuccess)
2907 ((Template *)pObject)->SetDCIModificationFlag();
2908 }
2909 else // User doesn't have MODIFY rights on object
2910 {
2911 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2912 }
2913 }
2914 else // Nodes DCI list not locked by this session
2915 {
2916 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2917 }
2918 }
2919 else // Object is not a node
2920 {
2921 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2922 }
2923 }
2924 else // No object with given ID
2925 {
2926 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2927 }
2928
2929 // Send response
2930 SendMessage(&msg);
2931}
2932
2933
2934//
2935// Change status for one or more DCIs
2936//
2937
2938void ClientSession::ChangeDCIStatus(CSCPMessage *pRequest)
2939{
2940 CSCPMessage msg;
2941 NetObj *pObject;
2942
2943 // Prepare response message
2944 msg.SetCode(CMD_REQUEST_COMPLETED);
2945 msg.SetId(pRequest->GetId());
2946
2947 // Get node id and check object class and access rights
2948 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
2949 if (pObject != NULL)
2950 {
2951 if ((pObject->Type() == OBJECT_NODE) ||
2952 (pObject->Type() == OBJECT_CLUSTER) ||
2953 (pObject->Type() == OBJECT_TEMPLATE))
2954 {
2955 if (((Template *)pObject)->IsLockedBySession(m_dwIndex))
2956 {
2957 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2958 {
2959 DWORD dwNumItems, *pdwItemList;
2960 int iStatus;
2961
2962 iStatus = pRequest->GetVariableShort(VID_DCI_STATUS);
2963 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
2964 pdwItemList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
2965 pRequest->GetVariableInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
2966 if (((Template *)pObject)->SetItemStatus(dwNumItems, pdwItemList, iStatus))
2967 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2968 else
2969 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
2970 free(pdwItemList);
2971 }
2972 else // User doesn't have MODIFY rights on object
2973 {
2974 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2975 }
2976 }
2977 else // Nodes DCI list not locked by this session
2978 {
2979 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2980 }
2981 }
2982 else // Object is not a node
2983 {
2984 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
2985 }
2986 }
2987 else // No object with given ID
2988 {
2989 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2990 }
2991
2992 // Send response
2993 SendMessage(&msg);
2994}
2995
2996
2997//
2998// Clear all collected data for DCI
2999//
3000
3001void ClientSession::ClearDCIData(CSCPMessage *pRequest)
3002{
3003 CSCPMessage msg;
3004 NetObj *pObject;
3005 DWORD dwItemId;
3006 DCItem *dci;
3007
3008 // Prepare response message
3009 msg.SetCode(CMD_REQUEST_COMPLETED);
3010 msg.SetId(pRequest->GetId());
3011
3012 // Get node id and check object class and access rights
3013 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3014 if (pObject != NULL)
3015 {
3016 if (pObject->Type() == OBJECT_NODE)
3017 {
3018 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_DELETE))
3019 {
3020 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3021 DebugPrintf(4, _T("ClearDCIData: request for DCI %d at node %d"), dwItemId, pObject->Id());
3022 dci = ((Template *)pObject)->GetItemById(dwItemId);
3023 if (dci != NULL)
3024 {
3025 msg.SetVariable(VID_RCC, dci->DeleteAllData() ? RCC_SUCCESS : RCC_DB_FAILURE);
3026 DebugPrintf(4, _T("ClearDCIData: DCI %d at node %d"), dwItemId, pObject->Id());
3027 }
3028 else
3029 {
3030 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3031 DebugPrintf(4, _T("ClearDCIData: DCI %d at node %d not found"), dwItemId, pObject->Id());
3032 }
3033 }
3034 else // User doesn't have DELETE rights on object
3035 {
3036 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3037 }
3038 }
3039 else // Object is not a node
3040 {
3041 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3042 }
3043 }
3044 else // No object with given ID
3045 {
3046 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3047 }
3048
3049 // Send response
3050 SendMessage(&msg);
3051}
3052
3053
3054//
3055// Copy or move DCI from one node or template to another
3056//
3057
3058void ClientSession::CopyDCI(CSCPMessage *pRequest)
3059{
3060 CSCPMessage msg;
3061 NetObj *pSource, *pDestination;
3062 TCHAR szLockInfo[MAX_SESSION_NAME];
3063 BOOL bMove;
3064
3065 // Prepare response message
3066 msg.SetCode(CMD_REQUEST_COMPLETED);
3067 msg.SetId(pRequest->GetId());
3068
3069 // Get source and destination
3070 pSource = FindObjectById(pRequest->GetVariableLong(VID_SOURCE_OBJECT_ID));
3071 pDestination = FindObjectById(pRequest->GetVariableLong(VID_DESTINATION_OBJECT_ID));
3072 if ((pSource != NULL) && (pDestination != NULL))
3073 {
3074 // Check object types
3075 if (((pSource->Type() == OBJECT_NODE) || (pSource->Type() == OBJECT_TEMPLATE) || (pSource->Type() == OBJECT_CLUSTER)) &&
3076 ((pDestination->Type() == OBJECT_NODE) || (pDestination->Type() == OBJECT_TEMPLATE) || (pDestination->Type() == OBJECT_CLUSTER)))
3077 {
3078 if (((Template *)pSource)->IsLockedBySession(m_dwIndex))
3079 {
3080 bMove = pRequest->GetVariableShort(VID_MOVE_FLAG);
3081 // Check access rights
3082 if ((pSource->CheckAccessRights(m_dwUserId, bMove ? (OBJECT_ACCESS_READ | OBJECT_ACCESS_MODIFY) : OBJECT_ACCESS_READ)) &&
3083 (pDestination->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)))
3084 {
3085 // Attempt to lock destination's DCI list
3086 if ((pDestination->Id() == pSource->Id()) ||
3087 (((Template *)pDestination)->LockDCIList(m_dwIndex, m_szUserName, szLockInfo)))
3088 {
3089 DWORD i, *pdwItemList, dwNumItems;
3090 const DCItem *pSrcItem;
3091 DCItem *pDstItem;
3092 int iErrors = 0;
3093
3094 // Get list of items to be copied/moved
3095 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
3096 pdwItemList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
3097 pRequest->GetVariableInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3098
3099 // Copy items
3100 for(i = 0; i < dwNumItems; i++)
3101 {
3102 pSrcItem = ((Template *)pSource)->GetItemById(pdwItemList[i]);
3103 if (pSrcItem != NULL)
3104 {
3105 pDstItem = new DCItem(pSrcItem);
3106 pDstItem->SetTemplateId(0, 0);
3107 pDstItem->ChangeBinding(CreateUniqueId(IDG_ITEM),
3108 (Template *)pDestination, FALSE);
3109 if (((Template *)pDestination)->AddItem(pDstItem))
3110 {
3111 if (bMove)
3112 {
3113 // Delete original item
3114 if (!((Template *)pSource)->DeleteItem(pdwItemList[i], TRUE))
3115 {
3116 iErrors++;
3117 }
3118 }
3119 }
3120 else
3121 {
3122 delete pDstItem;
3123 iErrors++;
3124 }
3125 }
3126 else
3127 {
3128 iErrors++;
3129 }
3130 }
3131
3132 // Cleanup
3133 free(pdwItemList);
3134 if (pDestination->Id() != pSource->Id())
3135 ((Template *)pDestination)->UnlockDCIList(m_dwIndex);
3136 msg.SetVariable(VID_RCC, (iErrors == 0) ? RCC_SUCCESS : RCC_DCI_COPY_ERRORS);
3137
3138 // Queue template update
3139 if (pDestination->Type() == OBJECT_TEMPLATE)
3140 ((Template *)pDestination)->QueueUpdate();
3141 }
3142 else // Destination's DCI list already locked by someone else
3143 {
3144 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
3145 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
3146 }
3147 }
3148 else // User doesn't have enough rights on object(s)
3149 {
3150 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3151 }
3152 }
3153 else // Source node DCI list not locked by this session
3154 {
3155 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3156 }
3157 }
3158 else // Object(s) is not a node
3159 {
3160 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3161 }
3162 }
3163 else // No object(s) with given ID
3164 {
3165 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3166 }
3167
3168 // Send response
3169 SendMessage(&msg);
3170}
3171
3172
3173//
3174// Get collected data
3175//
3176
3177void ClientSession::GetCollectedData(CSCPMessage *pRequest)
3178{
3179 CSCPMessage msg;
3180 DWORD dwObjectId;
3181 NetObj *pObject;
3182 BOOL bSuccess = FALSE;
3183 static DWORD m_dwRowSize[] = { 8, 8, 12, 12, 260, 12 };
3184#if !defined(UNICODE) || defined(UNICODE_UCS4)
3185 TCHAR szBuffer[MAX_DCI_STRING_VALUE];
3186#endif
3187
3188 // Prepare response message
3189 msg.SetCode(CMD_REQUEST_COMPLETED);
3190 msg.SetId(pRequest->GetId());
3191
3192 // Get node id and check object class and access rights
3193 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
3194 pObject = FindObjectById(dwObjectId);
3195 if (pObject != NULL)
3196 {
3197 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3198 {
3199 if (!(g_dwFlags & AF_DB_CONNECTION_LOST))
3200 {
3201 DB_ASYNC_RESULT hResult;
3202 DWORD i, dwItemId, dwMaxRows, dwTimeFrom, dwTimeTo;
3203 DWORD dwNumRows = 0;
3204 TCHAR szQuery[512], szCond[256];
3205 int iPos = 0, iType;
3206 DCI_DATA_HEADER *pData = NULL;
3207 DCI_DATA_ROW *pCurr;
3208
3209 // Get request parameters
3210 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3211 dwMaxRows = pRequest->GetVariableLong(VID_MAX_ROWS);
3212 dwTimeFrom = pRequest->GetVariableLong(VID_TIME_FROM);
3213 dwTimeTo = pRequest->GetVariableLong(VID_TIME_TO);
3214
3215 if ((dwMaxRows == 0) || (dwMaxRows > MAX_DCI_DATA_RECORDS))
3216 dwMaxRows = MAX_DCI_DATA_RECORDS;
3217
3218 szCond[0] = 0;
3219 if (dwTimeFrom != 0)
3220 {
3221 _stprintf(szCond, _T(" AND idata_timestamp>=%d"), dwTimeFrom);
3222 iPos = (int)_tcslen(szCond);
3223 }
3224 if (dwTimeTo != 0)
3225 {
3226 _stprintf(&szCond[iPos], _T(" AND idata_timestamp<=%d"), dwTimeTo);
3227 }
3228
3229 // Get item's data type to determine actual row size
3230 iType = ((Node *)pObject)->GetItemType(dwItemId);
3231//DWORD s=GetTickCount();
3232 // Create database-dependent query for fetching N rows
3233 switch(g_dwDBSyntax)
3234 {
3235 case DB_SYNTAX_MSSQL:
3236 _stprintf(szQuery, _T("SELECT TOP %d idata_timestamp,idata_value FROM idata_%d WHERE item_id=%d%s ORDER BY idata_timestamp DESC"),
3237 dwMaxRows, dwObjectId, dwItemId, szCond);
3238 break;
3239 case DB_SYNTAX_ORACLE:
3240 _stprintf(szQuery, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=%d%s AND ROWNUM <= %d ORDER BY idata_timestamp DESC"),
3241 dwObjectId, dwItemId, szCond, dwMaxRows);
3242 break;
3243 case DB_SYNTAX_MYSQL:
3244 case DB_SYNTAX_PGSQL:
3245 case DB_SYNTAX_SQLITE:
3246 _stprintf(szQuery, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=%d%s ORDER BY idata_timestamp DESC LIMIT %d"),
3247 dwObjectId, dwItemId, szCond, dwMaxRows);
3248 break;
3249 default:
3250 _stprintf(szQuery, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=%d%s ORDER BY idata_timestamp DESC LIMIT %d"),
3251 dwObjectId, dwItemId, szCond, dwMaxRows);
3252 break;
3253 }
3254 hResult = DBSelect(g_hCoreDB, szQuery);
3255//printf("[%d] **** QUERY DONE\n", GetTickCount() - s);
3256 if (hResult != NULL)
3257 {
3258 // Send CMD_REQUEST_COMPLETED message
3259 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3260 SendMessage(&msg);
3261
3262 dwNumRows = DBGetNumRows(hResult);
3263
3264 // Allocate memory for data and prepare data header
3265 pData = (DCI_DATA_HEADER *)malloc(dwNumRows * m_dwRowSize[iType] + sizeof(DCI_DATA_HEADER));
3266 pData->dwDataType = htonl((DWORD)iType);
3267 pData->dwItemId = htonl(dwItemId);
3268
3269 // Fill memory block with records
3270 pCurr = (DCI_DATA_ROW *)(((char *)pData) + sizeof(DCI_DATA_HEADER));
3271 for(i = 0; i < dwNumRows; i++)
3272 {
3273 pCurr->dwTimeStamp = htonl(DBGetFieldULong(hResult, i, 0));
3274 switch(iType)
3275 {
3276 case DCI_DT_INT:
3277 case DCI_DT_UINT:
3278 pCurr->value.dwInteger = htonl(DBGetFieldULong(hResult, i, 1));
3279 break;
3280 case DCI_DT_INT64:
3281 case DCI_DT_UINT64:
3282 pCurr->value.qwInt64 = htonq(DBGetFieldUInt64(hResult, i, 1));
3283 break;
3284 case DCI_DT_FLOAT:
3285 pCurr->value.dFloat = htond(DBGetFieldDouble(hResult, i, 1));
3286 break;
3287 case DCI_DT_STRING:
3288#ifdef UNICODE
3289#ifdef UNICODE_UCS4
3290 DBGetField(hResult, i, 1, szBuffer, MAX_DCI_STRING_VALUE);
3291 ucs4_to_ucs2(szBuffer, -1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3292#else
3293 DBGetField(hResult, i, 1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3294#endif
3295#else
3296 DBGetField(hResult, i, 1, szBuffer, MAX_DCI_STRING_VALUE);
3297 mb_to_ucs2(szBuffer, -1, pCurr->value.szString, MAX_DCI_STRING_VALUE);
3298#endif
3299 SwapWideString(pCurr->value.szString);
3300 break;
3301 }
3302 pCurr = (DCI_DATA_ROW *)(((char *)pCurr) + m_dwRowSize[iType]);
3303 }
3304 DBFreeResult(hResult);
3305 pData->dwNumRows = htonl(dwNumRows);
3306//printf("[%d] **** %d ROWS\n", GetTickCount() - s, dwNumRows);
3307
3308 // Prepare and send raw message with fetched data
3309 m_pSendQueue->Put(
3310 CreateRawNXCPMessage(CMD_DCI_DATA, pRequest->GetId(), 0,
3311 dwNumRows * m_dwRowSize[iType] + sizeof(DCI_DATA_HEADER),
3312 pData, NULL));
3313 free(pData);
3314 bSuccess = TRUE;
3315 }
3316 else
3317 {
3318 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
3319 }
3320 }
3321 else
3322 {
3323 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
3324 }
3325 }
3326 else
3327 {
3328 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3329 }
3330 }
3331 else // No object with given ID
3332 {
3333 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3334 }
3335
3336 // Send response
3337 if (!bSuccess)
3338 SendMessage(&msg);
3339}
3340
3341
3342//
3343// Send latest collected values for all DCIs of given node
3344//
3345
3346void ClientSession::SendLastValues(CSCPMessage *pRequest)
3347{
3348 CSCPMessage msg;
3349 NetObj *pObject;
3350
3351 // Prepare response message
3352 msg.SetCode(CMD_REQUEST_COMPLETED);
3353 msg.SetId(pRequest->GetId());
3354
3355 // Get node id and check object class and access rights
3356 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3357 if (pObject != NULL)
3358 {
3359 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3360 {
3361 if (pObject->Type() == OBJECT_NODE)
3362 {
3363 msg.SetVariable(VID_RCC, ((Node *)pObject)->GetLastValues(&msg));
3364 }
3365 else
3366 {
3367 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3368 }
3369 }
3370 else
3371 {
3372 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3373 }
3374 }
3375 else // No object with given ID
3376 {
3377 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3378 }
3379
3380 // Send response
3381 SendMessage(&msg);
3382}
3383
3384
3385//
3386// Open event processing policy
3387//
3388
3389void ClientSession::OpenEPP(DWORD dwRqId)
3390{
3391 CSCPMessage msg;
3392 char szBuffer[256];
3393 BOOL bSuccess = FALSE;
3394
3395 // Prepare response message
3396 msg.SetCode(CMD_REQUEST_COMPLETED);
3397 msg.SetId(dwRqId);
3398
3399 if (m_dwSystemAccess & SYSTEM_ACCESS_EPP)
3400 {
3401 if (!LockComponent(CID_EPP, m_dwIndex, m_szUserName, NULL, szBuffer))
3402 {
3403 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
3404 msg.SetVariable(VID_LOCKED_BY, szBuffer);
3405 }
3406 else
3407 {
3408 m_dwFlags |= CSF_EPP_LOCKED;
3409 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3410 msg.SetVariable(VID_NUM_RULES, g_pEventPolicy->NumRules());
3411 bSuccess = TRUE;
3412 }
3413 }
3414 else
3415 {
3416 // Current user has no rights for event policy management
3417 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3418 }
3419
3420 // Send response
3421 SendMessage(&msg);
3422
3423 // Send policy to client
3424 if (bSuccess)
3425 g_pEventPolicy->SendToClient(this, dwRqId);
3426}
3427
3428
3429//
3430// Close event processing policy
3431//
3432
3433void ClientSession::CloseEPP(DWORD dwRqId)
3434{
3435 CSCPMessage msg;
3436
3437 // Prepare response message
3438 msg.SetCode(CMD_REQUEST_COMPLETED);
3439 msg.SetId(dwRqId);
3440
3441 if (m_dwSystemAccess & SYSTEM_ACCESS_EPP)
3442 {
3443 if (m_dwFlags & CSF_EPP_LOCKED)
3444 {
3445 UnlockComponent(CID_EPP);
3446 m_dwFlags &= ~CSF_EPP_LOCKED;
3447 }
3448 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3449 }
3450 else
3451 {
3452 // Current user has no rights for event policy management
3453 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3454 }
3455
3456 // Send response
3457 SendMessage(&msg);
3458}
3459
3460
3461//
3462// Save event processing policy
3463//
3464
3465void ClientSession::SaveEPP(CSCPMessage *pRequest)
3466{
3467 CSCPMessage msg;
3468
3469 // Prepare response message
3470 msg.SetCode(CMD_REQUEST_COMPLETED);
3471 msg.SetId(pRequest->GetId());
3472
3473 if (m_dwSystemAccess & SYSTEM_ACCESS_EPP)
3474 {
3475 if (m_dwFlags & CSF_EPP_LOCKED)
3476 {
3477 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3478 m_dwNumRecordsToUpload = pRequest->GetVariableLong(VID_NUM_RULES);
3479 m_dwRecordsUploaded = 0;
3480 if (m_dwNumRecordsToUpload == 0)
3481 {
3482 g_pEventPolicy->ReplacePolicy(0, NULL);
3483 g_pEventPolicy->SaveToDB();
3484 }
3485 else
3486 {
3487 m_dwFlags |= CSF_EPP_UPLOAD;
3488 m_ppEPPRuleList = (EPRule **)malloc(sizeof(EPRule *) * m_dwNumRecordsToUpload);
3489 memset(m_ppEPPRuleList, 0, sizeof(EPRule *) * m_dwNumRecordsToUpload);
3490 }
3491 DebugPrintf(5, "Accepted EPP upload request for %d rules", m_dwNumRecordsToUpload);
3492 }
3493 else
3494 {
3495 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3496 }
3497 }
3498 else
3499 {
3500 // Current user has no rights for event policy management
3501 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3502 }
3503
3504 // Send response
3505 SendMessage(&msg);
3506}
3507
3508
3509//
3510// Process EPP rule received from client
3511//
3512
3513void ClientSession::ProcessEPPRecord(CSCPMessage *pRequest)
3514{
3515 if (!(m_dwFlags & CSF_EPP_LOCKED))
3516 {
3517 CSCPMessage msg;
3518
3519 msg.SetCode(CMD_REQUEST_COMPLETED);
3520 msg.SetId(pRequest->GetId());
3521 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3522 SendMessage(&msg);
3523 }
3524 else
3525 {
3526 if (m_dwRecordsUploaded < m_dwNumRecordsToUpload)
3527 {
3528 m_ppEPPRuleList[m_dwRecordsUploaded] = new EPRule(pRequest);
3529 m_dwRecordsUploaded++;
3530 if (m_dwRecordsUploaded == m_dwNumRecordsToUpload)
3531 {
3532 CSCPMessage msg;
3533
3534 // All records received, replace event policy...
3535 DebugPrintf(5, "Replacing event processing policy with a new one at %p (%d rules)",
3536 m_ppEPPRuleList, m_dwNumRecordsToUpload);
3537 g_pEventPolicy->ReplacePolicy(m_dwNumRecordsToUpload, m_ppEPPRuleList);
3538 g_pEventPolicy->SaveToDB();
3539 m_ppEPPRuleList = NULL;
3540
3541 // ... and send final confirmation
3542 msg.SetCode(CMD_REQUEST_COMPLETED);
3543 msg.SetId(pRequest->GetId());
3544 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3545 SendMessage(&msg);
3546
3547 m_dwFlags &= ~CSF_EPP_UPLOAD;
3548 }
3549 }
3550 }
3551}
3552
3553
3554//
3555// Send compiled MIB file to client
3556//
3557
3558void ClientSession::SendMIB(DWORD dwRqId)
3559{
3560 char szBuffer[MAX_PATH];
3561
3562 // Send compiled MIB file
3563 strcpy(szBuffer, g_szDataDir);
3564 strcat(szBuffer, DFILE_COMPILED_MIB);
3565 SendFileOverNXCP(m_hSocket, dwRqId, szBuffer, m_pCtx);
3566}
3567
3568
3569//
3570// Send timestamp of compiled MIB file to client
3571//
3572
3573void ClientSession::SendMIBTimestamp(DWORD dwRqId)
3574{
3575 CSCPMessage msg;
3576 char szBuffer[MAX_PATH];
3577 DWORD dwResult, dwTimeStamp;
3578
3579 // Prepare response message
3580 msg.SetCode(CMD_REQUEST_COMPLETED);
3581 msg.SetId(dwRqId);
3582
3583 strcpy(szBuffer, g_szDataDir);
3584 strcat(szBuffer, DFILE_COMPILED_MIB);
3585 dwResult = SNMPGetMIBTreeTimestamp(szBuffer, &dwTimeStamp);
3586 if (dwResult == SNMP_ERR_SUCCESS)
3587 {
3588 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3589 msg.SetVariable(VID_TIMESTAMP, dwTimeStamp);
3590 }
3591 else
3592 {
3593 switch(dwResult)
3594 {
3595 case SNMP_ERR_FILE_IO:
3596 msg.SetVariable(VID_RCC, RCC_FILE_IO_ERROR);
3597 break;
3598 case SNMP_ERR_BAD_FILE_HEADER:
3599 msg.SetVariable(VID_RCC, RCC_CORRUPTED_MIB_FILE);
3600 break;
3601 default:
3602 msg.SetVariable(VID_RCC, RCC_INTERNAL_ERROR);
3603 break;
3604 }
3605 }
3606
3607 // Send response
3608 SendMessage(&msg);
3609}
3610
3611
3612//
3613// Create new object
3614//
3615
3616void ClientSession::CreateObject(CSCPMessage *pRequest)
3617{
3618 CSCPMessage msg;
3619 NetObj *pObject, *pParent;
3620 int iClass, iServiceType;
3621 TCHAR szObjectName[MAX_OBJECT_NAME];
3622 TCHAR *pszRequest, *pszResponse, *pszComments;
3623 DWORD dwIpAddr;
3624 WORD wIpProto, wIpPort;
3625 BOOL bParentAlwaysValid = FALSE;
3626
3627 // Prepare response message
3628 msg.SetCode(CMD_REQUEST_COMPLETED);
3629 msg.SetId(pRequest->GetId());
3630
3631 iClass = pRequest->GetVariableShort(VID_OBJECT_CLASS);
3632
3633 // Find parent object
3634 pParent = FindObjectById(pRequest->GetVariableLong(VID_PARENT_ID));
3635 if (iClass == OBJECT_NODE)
3636 {
3637 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
3638 if ((pParent == NULL) && (dwIpAddr != 0))
3639 {
3640 pParent = FindSubnetForNode(dwIpAddr);
3641 bParentAlwaysValid = TRUE;
3642 }
3643 }
3644 if ((pParent != NULL) || (iClass == OBJECT_NODE))
3645 {
3646 // User should have create access to parent object
3647 if ((pParent != NULL) ?
3648 pParent->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_CREATE) :
3649 g_pEntireNet->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_CREATE))
3650 {
3651 // Parent object should be of valid type
3652 if (bParentAlwaysValid || IsValidParentClass(iClass, (pParent != NULL) ? pParent->Type() : -1))
3653 {
3654 pRequest->GetVariableStr(VID_OBJECT_NAME, szObjectName, MAX_OBJECT_NAME);
3655 if (IsValidObjectName(szObjectName, TRUE))
3656 {
3657 // Create new object
3658 switch(iClass)
3659 {
3660 case OBJECT_NODE:
3661 pObject = PollNewNode(dwIpAddr,
3662 pRequest->GetVariableLong(VID_IP_NETMASK),
3663 pRequest->GetVariableLong(VID_CREATION_FLAGS),
3664 szObjectName,
3665 pRequest->GetVariableLong(VID_PROXY_NODE),
3666 pRequest->GetVariableLong(VID_SNMP_PROXY),
3667 (pParent != NULL) ? ((pParent->Type() == OBJECT_CLUSTER) ? (Cluster *)pParent : NULL) : NULL);
3668 break;
3669 case OBJECT_CONTAINER:
3670 pObject = new Container(szObjectName,
3671 pRequest->GetVariableLong(VID_CATEGORY));
3672 NetObjInsert(pObject, TRUE);
3673 break;
3674 case OBJECT_TEMPLATEGROUP:
3675 pObject = new TemplateGroup(szObjectName);
3676 NetObjInsert(pObject, TRUE);
3677 pObject->CalculateCompoundStatus(); // Force status change to NORMAL
3678 break;
3679 case OBJECT_TEMPLATE:
3680 pObject = new Template(szObjectName);
3681 NetObjInsert(pObject, TRUE);
3682 pObject->CalculateCompoundStatus(); // Force status change to NORMAL
3683 break;
3684 case OBJECT_CLUSTER:
3685 pObject = new Cluster(szObjectName);
3686 NetObjInsert(pObject, TRUE);
3687 break;
3688 case OBJECT_NETWORKSERVICE:
3689 iServiceType = (int)pRequest->GetVariableShort(VID_SERVICE_TYPE);
3690 wIpProto = pRequest->GetVariableShort(VID_IP_PROTO);
3691 wIpPort = pRequest->GetVariableShort(VID_IP_PORT);
3692 pszRequest = pRequest->GetVariableStr(VID_SERVICE_REQUEST);
3693 pszResponse = pRequest->GetVariableStr(VID_SERVICE_RESPONSE);
3694 pObject = new NetworkService(iServiceType, wIpProto, wIpPort,
3695 pszRequest, pszResponse, (Node *)pParent);
3696 pObject->SetName(szObjectName);
3697 NetObjInsert(pObject, TRUE);
3698 break;
3699 case OBJECT_VPNCONNECTOR:
3700 pObject = new VPNConnector(TRUE);
3701 pObject->SetName(szObjectName);
3702 NetObjInsert(pObject, TRUE);
3703 break;
3704 case OBJECT_CONDITION:
3705 pObject = new Condition(TRUE);
3706 pObject->SetName(szObjectName);
3707 NetObjInsert(pObject, TRUE);
3708 break;
3709 default:
3710 break;
3711 }
3712
3713 // If creation was successful do binding and set comments if needed
3714 if (pObject != NULL)
3715 {
3716 if (pParent != NULL) // parent can be NULL for nodes
3717 {
3718 pParent->AddChild(pObject);
3719 pObject->AddParent(pParent);
3720 pParent->CalculateCompoundStatus();
3721 if (pParent->Type() == OBJECT_CLUSTER)
3722 {
3723 ((Cluster *)pParent)->ApplyToNode((Node *)pObject);
3724 }
3725 }
3726
3727 pszComments = pRequest->GetVariableStr(VID_COMMENTS);
3728 if (pszComments != NULL)
3729 pObject->SetComments(pszComments);
3730
3731 pObject->Unhide();
3732 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3733 msg.SetVariable(VID_OBJECT_ID, pObject->Id());
3734 }
3735 else
3736 {
3737 // :DIRTY HACK:
3738 // PollNewNode will return NULL only if IP already
3739 // in use. some new() can fail there too, but server will
3740 // crash in that case
3741 if (iClass == OBJECT_NODE)
3742 {
3743 msg.SetVariable(VID_RCC, RCC_ALREADY_EXIST);
3744 }
3745 else
3746 {
3747 msg.SetVariable(VID_RCC, RCC_OBJECT_CREATION_FAILED);
3748 }
3749 }
3750 }
3751 else
3752 {
3753 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
3754 }
3755 }
3756 else
3757 {
3758 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3759 }
3760 }
3761 else
3762 {
3763 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3764 }
3765 }
3766 else
3767 {
3768 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3769 }
3770
3771 // Send response
3772 SendMessage(&msg);
3773}
3774
3775
3776//
3777// Bind/unbind object
3778//
3779
3780void ClientSession::ChangeObjectBinding(CSCPMessage *pRequest, BOOL bBind)
3781{
3782 CSCPMessage msg;
3783 NetObj *pParent, *pChild;
3784
3785 // Prepare response message
3786 msg.SetCode(CMD_REQUEST_COMPLETED);
3787 msg.SetId(pRequest->GetId());
3788
3789 // Get parent and child objects
3790 pParent = FindObjectById(pRequest->GetVariableLong(VID_PARENT_ID));
3791 pChild = FindObjectById(pRequest->GetVariableLong(VID_CHILD_ID));
3792
3793 // Check access rights and change binding
3794 if ((pParent != NULL) && (pChild != NULL))
3795 {
3796 // User should have modify access to both objects
3797 if ((pParent->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)) &&
3798 (pChild->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)))
3799 {
3800 // Parent object should be container or service root,
3801 // or template group/root for templates
3802 // For unbind, it can also be template
3803 if ((pParent->Type() == OBJECT_CONTAINER) ||
3804 (pParent->Type() == OBJECT_SERVICEROOT) ||
3805 ((pParent->Type() == OBJECT_TEMPLATE) && (!bBind)) ||
3806 ((pParent->Type() == OBJECT_TEMPLATEGROUP) && (pChild->Type() == OBJECT_TEMPLATE)) ||
3807 ((pParent->Type() == OBJECT_TEMPLATEROOT) && (pChild->Type() == OBJECT_TEMPLATE)))
3808 {
3809 if (bBind)
3810 {
3811 // Prevent loops
3812 if (!pChild->IsChild(pParent->Id()))
3813 {
3814 pParent->AddChild(pChild);
3815 pChild->AddParent(pParent);
3816 pParent->CalculateCompoundStatus();
3817 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3818 }
3819 else
3820 {
3821 msg.SetVariable(VID_RCC, RCC_OBJECT_LOOP);
3822 }
3823 }
3824 else
3825 {
3826 pParent->DeleteChild(pChild);
3827 pChild->DeleteParent(pParent);
3828 if ((pParent->Type() == OBJECT_TEMPLATE) &&
3829 (pChild->Type() == OBJECT_NODE))
3830 {
3831 ((Template *)pParent)->QueueRemoveFromNode(pChild->Id(),
3832 pRequest->GetVariableShort(VID_REMOVE_DCI));
3833 }
3834 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3835 }
3836 }
3837 else
3838 {
3839 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3840 }
3841 }
3842 else
3843 {
3844 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3845 }
3846 }
3847 else
3848 {
3849 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3850 }
3851
3852 // Send response
3853 SendMessage(&msg);
3854}
3855
3856
3857//
3858// Delete object
3859//
3860
3861void ClientSession::DeleteObject(CSCPMessage *pRequest)
3862{
3863 CSCPMessage msg;
3864 NetObj *pObject;
3865
3866 // Prepare response message
3867 msg.SetCode(CMD_REQUEST_COMPLETED);
3868 msg.SetId(pRequest->GetId());
3869
3870 // Find object to be deleted
3871 pObject = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3872 if (pObject != NULL)
3873 {
3874 // Check if it is a built-in object, like "Entire Network"
3875 if (pObject->Id() >= 10)
3876 {
3877 // Check access rights
3878 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_DELETE))
3879 {
3880 pObject->Delete(FALSE);
3881 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3882 }
3883 else
3884 {
3885 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3886 }
3887 }
3888 else
3889 {
3890 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3891 }
3892 }
3893 else
3894 {
3895 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3896 }
3897
3898 // Send response
3899 SendMessage(&msg);
3900}
3901
3902
3903//
3904// Process changes in alarms
3905//
3906
3907void ClientSession::OnAlarmUpdate(DWORD dwCode, NXC_ALARM *pAlarm)
3908{
3909 UPDATE_INFO *pUpdate;
3910 NetObj *pObject;
3911
3912 if (IsAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_ALARMS))
3913 {
3914 pObject = FindObjectById(pAlarm->dwSourceObject);
3915 if (pObject != NULL)
3916 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ_ALARMS))
3917 {
3918 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
3919 pUpdate->dwCategory = INFO_CAT_ALARM;
3920 pUpdate->dwCode = dwCode;
3921 pUpdate->pData = nx_memdup(pAlarm, sizeof(NXC_ALARM));
3922 m_pUpdateQueue->Put(pUpdate);
3923 }
3924 }
3925}
3926
3927
3928//
3929// Send all alarms to client
3930//
3931
3932void ClientSession::SendAllAlarms(DWORD dwRqId, BOOL bIncludeAck)
3933{
3934 MutexLock(m_mutexSendAlarms, INFINITE);
3935 g_alarmMgr.SendAlarmsToClient(dwRqId, bIncludeAck, this);
3936 MutexUnlock(m_mutexSendAlarms);
3937}
3938
3939
3940//
3941// Acknowledge alarm
3942//
3943
3944void ClientSession::AcknowledgeAlarm(CSCPMessage *pRequest)
3945{
3946 CSCPMessage msg;
3947 NetObj *pObject;
3948 DWORD dwAlarmId;
3949
3950 // Prepare response message
3951 msg.SetCode(CMD_REQUEST_COMPLETED);
3952 msg.SetId(pRequest->GetId());
3953
3954 // Get alarm id and it's source object
3955 dwAlarmId = pRequest->GetVariableLong(VID_ALARM_ID);
3956 pObject = g_alarmMgr.GetAlarmSourceObject(dwAlarmId);
3957 if (pObject != NULL)
3958 {
3959 // User should have "acknowledge alarm" right to the object
3960 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_ACK_ALARMS))
3961 {
3962 msg.SetVariable(VID_RCC, g_alarmMgr.AckById(dwAlarmId, m_dwUserId));
3963 }
3964 else
3965 {
3966 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3967 }
3968 }
3969 else
3970 {
3971 // Normally, for existing alarms pObject will not be NULL,
3972 // so we assume that alarm id is invalid
3973 msg.SetVariable(VID_RCC, RCC_INVALID_ALARM_ID);
3974 }
3975
3976 // Send response
3977 SendMessage(&msg);
3978}
3979
3980
3981//
3982// Terminate alarm
3983//
3984
3985void ClientSession::TerminateAlarm(CSCPMessage *pRequest)
3986{
3987 CSCPMessage msg;
3988 NetObj *pObject;
3989 DWORD dwAlarmId;
3990
3991 // Prepare response message
3992 msg.SetCode(CMD_REQUEST_COMPLETED);
3993 msg.SetId(pRequest->GetId());
3994
3995 // Get alarm id and it's source object
3996 dwAlarmId = pRequest->GetVariableLong(VID_ALARM_ID);
3997 pObject = g_alarmMgr.GetAlarmSourceObject(dwAlarmId);
3998 if (pObject != NULL)
3999 {
4000 // User should have "terminate alarm" right to the object
4001 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_TERM_ALARMS))
4002 {
4003 msg.SetVariable(VID_RCC, g_alarmMgr.TerminateById(dwAlarmId, m_dwUserId));
4004 }
4005 else
4006 {
4007 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
4008 }
4009 }
4010 else
4011 {
4012 // Normally, for existing alarms pObject will not be NULL,
4013 // so we assume that alarm id is invalid
4014 msg.SetVariable(VID_RCC, RCC_INVALID_ALARM_ID);
4015 }
4016
4017 // Send response
4018 SendMessage(&msg);
4019}
4020
4021
4022//
4023// Delete alarm
4024//
4025
4026void ClientSession::DeleteAlarm(CSCPMessage *pRequest)
4027{
4028 CSCPMessage msg;
4029 NetObj *pObject;
4030 DWORD dwAlarmId;
4031
4032 // Prepare response message
4033 msg.SetCode(CMD_REQUEST_COMPLETED);
4034 msg.SetId(pRequest->GetId());
4035
4036 // Get alarm id and it's source object
4037 dwAlarmId = pRequest->GetVariableLong(VID_ALARM_ID);
4038 pObject = g_alarmMgr.GetAlarmSourceObject(dwAlarmId);
4039 if (pObject != NULL)
4040 {
4041 // User should have "terminate alarm" right to the object
4042 // and system right "delete alarms"
4043 if ((pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_TERM_ALARMS)) &&
4044 (m_dwSystemAccess & SYSTEM_ACCESS_DELETE_ALARMS))
4045 {
4046 g_alarmMgr.DeleteAlarm(dwAlarmId);
4047 msg.SetVariable(VID_RCC, RCC_SUCCESS);
4048 }
4049 else
4050 {
4051 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
4052 }
4053 }
4054 else
4055 {
4056 // Normally, for existing alarms pObject will not be NULL,
4057 // so we assume that alarm id is invalid
4058 msg.SetVariable(VID_RCC, RCC_INVALID_ALARM_ID);
4059 }
4060
4061 // Send response
4062 SendMessage(&msg);
4063}
4064
4065
4066//
4067// Lock/unlock action configuration database
4068//
4069
4070void ClientSession::LockActionDB(DWORD dwRqId, BOOL bLock)
4071{
4072 CSCPMessage msg;
4073 char szBuffer[256];
4074
4075 // Prepare response message
4076 msg.SetCode(CMD_REQUEST_COMPLETED);
4077 msg.SetId(dwRqId);
4078
4079 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_ACTIONS)
4080 {
4081 if (bLock)
4082 {
4083 if (!LockComponent(CID_ACTION_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
4084 {
4085 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
4086 msg.SetVariable(VID_LOCKED_BY, szBuffer);
4087 }
4088 else
4089 {
4090 m_dwFlags |= CSF_ACTION_DB_LOCKED;
4091 msg.SetVariable(VID_RCC, RCC_SUCCESS);
4092 }
4093 }
4094 else
4095 {
4096 if (m_dwFlags & CSF_ACTION_DB_LOCKED)
4097 {