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