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