API for reading FDB
[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 msg.SetVariable(VID_ALARM_LIST_DISP_LIMIT, ConfigReadULong(_T("AlarmListDisplayLimit"), 4096));
1893 debugPrintf(3, _T("User %s authenticated"), m_szUserName);
1894 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, 0,
1895 _T("User \"%s\" logged in (client info: %s)"), szLogin, m_szClientInfo);
1896 }
1897 else
1898 {
1899 msg.SetVariable(VID_RCC, dwResult);
1900 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, 0,
1901 _T("User \"%s\" login failed with error code %d (client info: %s)"),
1902 szLogin, dwResult, m_szClientInfo);
1903 if (intruderLockout)
1904 {
1905 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, 0,
1906 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
1907 }
1908 }
1909 }
1910 else
1911 {
1912 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1913 }
1914
1915 // Send response
1916 sendMessage(&msg);
1917 }
1918
1919 /**
1920 * Send event configuration to client
1921 */
1922 void ClientSession::sendEventDB(UINT32 dwRqId)
1923 {
1924 DB_ASYNC_RESULT hResult;
1925 CSCPMessage msg;
1926 TCHAR szBuffer[4096];
1927
1928 // Prepare response message
1929 msg.SetCode(CMD_REQUEST_COMPLETED);
1930 msg.SetId(dwRqId);
1931
1932 if (checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EPP))
1933 {
1934 if (!(g_flags & AF_DB_CONNECTION_LOST))
1935 {
1936 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1937 sendMessage(&msg);
1938 msg.deleteAllVariables();
1939
1940 // Prepare data message
1941 msg.SetCode(CMD_EVENT_DB_RECORD);
1942 msg.SetId(dwRqId);
1943
1944 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1945 hResult = DBAsyncSelect(hdb, _T("SELECT event_code,event_name,severity,flags,message,description FROM event_cfg"));
1946 if (hResult != NULL)
1947 {
1948 while(DBFetch(hResult))
1949 {
1950 msg.SetVariable(VID_EVENT_CODE, DBGetFieldAsyncULong(hResult, 0));
1951 msg.SetVariable(VID_NAME, DBGetFieldAsync(hResult, 1, szBuffer, 1024));
1952 msg.SetVariable(VID_SEVERITY, DBGetFieldAsyncULong(hResult, 2));
1953 msg.SetVariable(VID_FLAGS, DBGetFieldAsyncULong(hResult, 3));
1954
1955 DBGetFieldAsync(hResult, 4, szBuffer, 4096);
1956 msg.SetVariable(VID_MESSAGE, szBuffer);
1957
1958 DBGetFieldAsync(hResult, 5, szBuffer, 4096);
1959 msg.SetVariable(VID_DESCRIPTION, szBuffer);
1960
1961 sendMessage(&msg);
1962 msg.deleteAllVariables();
1963 }
1964 DBFreeAsyncResult(hResult);
1965 }
1966 DBConnectionPoolReleaseConnection(hdb);
1967
1968 // End-of-list indicator
1969 msg.SetVariable(VID_EVENT_CODE, (UINT32)0);
1970 msg.setEndOfSequence();
1971 }
1972 else
1973 {
1974 msg.SetVariable(VID_RCC, RCC_DB_CONNECTION_LOST);
1975 }
1976 }
1977 else
1978 {
1979 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1980 }
1981 sendMessage(&msg);
1982 }
1983
1984 /**
1985 * Callback for sending event configuration change notifications
1986 */
1987 static void SendEventDBChangeNotification(ClientSession *session, void *arg)
1988 {
1989 if (session->isAuthenticated() &&
1990 (session->checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) ||
1991 session->checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) ||
1992 session->checkSysAccessRights(SYSTEM_ACCESS_EPP)))
1993 session->postMessage((CSCPMessage *)arg);
1994 }
1995
1996 /**
1997 * Update event template
1998 */
1999 void ClientSession::modifyEventTemplate(CSCPMessage *pRequest)
2000 {
2001 CSCPMessage msg;
2002
2003 // Prepare reply message
2004 msg.SetCode(CMD_REQUEST_COMPLETED);
2005 msg.SetId(pRequest->GetId());
2006
2007 // Check access rights
2008 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
2009 {
2010 TCHAR szQuery[8192], szName[MAX_EVENT_NAME];
2011
2012 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2013
2014 // Check if event with specific code exists
2015 UINT32 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
2016 bool bEventExist = IsDatabaseRecordExist(hdb, _T("event_cfg"), _T("event_code"), dwEventCode);
2017
2018 // Check that we are not trying to create event below 100000
2019 if (bEventExist || (dwEventCode >= FIRST_USER_EVENT_ID))
2020 {
2021 // Prepare and execute SQL query
2022 pRequest->GetVariableStr(VID_NAME, szName, MAX_EVENT_NAME);
2023 if (IsValidObjectName(szName))
2024 {
2025 TCHAR szMessage[MAX_EVENT_MSG_LENGTH], *pszDescription;
2026
2027 pRequest->GetVariableStr(VID_MESSAGE, szMessage, MAX_EVENT_MSG_LENGTH);
2028 pszDescription = pRequest->GetVariableStr(VID_DESCRIPTION);
2029
2030 if (bEventExist)
2031 {
2032 _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"),
2033 szName, pRequest->GetVariableLong(VID_SEVERITY), pRequest->GetVariableLong(VID_FLAGS),
2034 (const TCHAR *)DBPrepareString(g_hCoreDB, szMessage),
2035 (const TCHAR *)DBPrepareString(g_hCoreDB, pszDescription), dwEventCode);
2036 }
2037 else
2038 {
2039 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO event_cfg (event_code,event_name,severity,flags,")
2040 _T("message,description) VALUES (%d,'%s',%d,%d,%s,%s)"),
2041 dwEventCode, szName, pRequest->GetVariableLong(VID_SEVERITY),
2042 pRequest->GetVariableLong(VID_FLAGS), (const TCHAR *)DBPrepareString(g_hCoreDB, szMessage),
2043 (const TCHAR *)DBPrepareString(g_hCoreDB, pszDescription));
2044 }
2045
2046 safe_free(pszDescription);
2047
2048 if (DBQuery(hdb, szQuery))
2049 {
2050 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2051 ReloadEvents();
2052 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
2053
2054 CSCPMessage nmsg(pRequest);
2055 nmsg.SetCode(CMD_EVENT_DB_UPDATE);
2056 nmsg.SetVariable(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_CHANGED);
2057 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2058 }
2059 else
2060 {
2061 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2062 }
2063 }
2064 else
2065 {
2066 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
2067 }
2068 }
2069 else
2070 {
2071 msg.SetVariable(VID_RCC, RCC_INVALID_EVENT_CODE);
2072 }
2073 DBConnectionPoolReleaseConnection(hdb);
2074 }
2075 else
2076 {
2077 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2078 }
2079
2080 // Send response
2081 sendMessage(&msg);
2082 }
2083
2084 /**
2085 * Delete event template
2086 */
2087 void ClientSession::deleteEventTemplate(CSCPMessage *pRequest)
2088 {
2089 CSCPMessage msg;
2090 UINT32 dwEventCode;
2091
2092 // Prepare reply message
2093 msg.SetCode(CMD_REQUEST_COMPLETED);
2094 msg.SetId(pRequest->GetId());
2095
2096 dwEventCode = pRequest->GetVariableLong(VID_EVENT_CODE);
2097
2098 // Check access rights
2099 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
2100 {
2101 TCHAR szQuery[256];
2102
2103 _sntprintf(szQuery, 256, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
2104 if (DBQuery(g_hCoreDB, szQuery))
2105 {
2106 DeleteEventTemplateFromList(dwEventCode);
2107 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
2108
2109 CSCPMessage nmsg;
2110 nmsg.SetCode(CMD_EVENT_DB_UPDATE);
2111 nmsg.SetVariable(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_DELETED);
2112 nmsg.SetVariable(VID_EVENT_CODE, dwEventCode);
2113 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2114
2115 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2116
2117 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, 0,
2118 _T("Event template %d deleted"), dwEventCode);
2119 }
2120 else
2121 {
2122 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2123 }
2124 }
2125 else
2126 {
2127 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2128 }
2129
2130 // Send response
2131 sendMessage(&msg);
2132 }
2133
2134 /**
2135 * Generate event code for new event template
2136 */
2137 void ClientSession::generateEventCode(UINT32 dwRqId)
2138 {
2139 CSCPMessage msg;
2140
2141 // Prepare reply message
2142 msg.SetCode(CMD_REQUEST_COMPLETED);
2143 msg.SetId(dwRqId);
2144
2145 // Check access rights
2146 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
2147 {
2148 msg.SetVariable(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
2149 }
2150 else
2151 {
2152 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2153 }
2154
2155 // Send response
2156 sendMessage(&msg);
2157 }
2158
2159 /**
2160 * Send all objects to client
2161 */
2162 void ClientSession::sendAllObjects(CSCPMessage *pRequest)
2163 {
2164 CSCPMessage msg;
2165
2166 // Send confirmation message
2167 msg.SetCode(CMD_REQUEST_COMPLETED);
2168 msg.SetId(pRequest->GetId());
2169 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2170 sendMessage(&msg);
2171 msg.deleteAllVariables();
2172
2173 // Change "sync comments" flag
2174 if (pRequest->GetVariableShort(VID_SYNC_COMMENTS))
2175 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2176 else
2177 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2178
2179 // Get client's last known time stamp
2180 UINT32 dwTimeStamp = pRequest->GetVariableLong(VID_TIMESTAMP);
2181
2182 // Prepare message
2183 msg.SetCode(CMD_OBJECT);
2184
2185 // Send objects, one per message
2186 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects(true);
2187 MutexLock(m_mutexSendObjects);
2188 for(int i = 0; i < objects->size(); i++)
2189 {
2190 NetObj *object = objects->get(i);
2191 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2192 (object->getTimeStamp() >= dwTimeStamp) &&
2193 !object->isHidden() && !object->isSystem())
2194 {
2195 object->CreateMessage(&msg);
2196 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2197 object->commentsToMessage(&msg);
2198 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2199 {
2200 // mask passwords
2201 msg.SetVariable(VID_SHARED_SECRET, _T("********"));
2202 msg.SetVariable(VID_SNMP_AUTH_PASSWORD, _T("********"));
2203 msg.SetVariable(VID_SNMP_PRIV_PASSWORD, _T("********"));
2204 }
2205 sendMessage(&msg);
2206 msg.deleteAllVariables();
2207 }
2208 object->decRefCount();
2209 }
2210 delete objects;
2211
2212 // Send end of list notification
2213 msg.SetCode(CMD_OBJECT_LIST_END);
2214 sendMessage(&msg);
2215
2216 MutexUnlock(m_mutexSendObjects);
2217 }
2218
2219 /**
2220 * Send selected objects to client
2221 */
2222 void ClientSession::sendSelectedObjects(CSCPMessage *pRequest)
2223 {
2224 CSCPMessage msg;
2225
2226 // Send confirmation message
2227 msg.SetCode(CMD_REQUEST_COMPLETED);
2228 msg.SetId(pRequest->GetId());
2229 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2230 sendMessage(&msg);
2231 msg.deleteAllVariables();
2232
2233 // Change "sync comments" flag
2234 if (pRequest->GetVariableShort(VID_SYNC_COMMENTS))
2235 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2236 else
2237 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2238
2239 UINT32 dwTimeStamp = pRequest->GetVariableLong(VID_TIMESTAMP);
2240 UINT32 numObjects = pRequest->GetVariableLong(VID_NUM_OBJECTS);
2241 UINT32 *objects = (UINT32 *)malloc(sizeof(UINT32) * numObjects);
2242 pRequest->getFieldAsInt32Array(VID_OBJECT_LIST, numObjects, objects);
2243 UINT32 options = pRequest->GetVariableShort(VID_FLAGS);
2244
2245 MutexLock(m_mutexSendObjects);
2246
2247 // Prepare message
2248 msg.SetCode((options & OBJECT_SYNC_SEND_UPDATES) ? CMD_OBJECT_UPDATE : CMD_OBJECT);
2249
2250 // Send objects, one per message
2251 for(UINT32 i = 0; i < numObjects; i++)
2252 {
2253 NetObj *object = FindObjectById(objects[i]);
2254 if ((object != NULL) &&
2255 object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2256 (object->getTimeStamp() >= dwTimeStamp) &&
2257 !object->isHidden() && !object->isSystem())
2258 {
2259 object->CreateMessage(&msg);
2260 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2261 object->commentsToMessage(&msg);
2262 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2263 {
2264 // mask passwords
2265 msg.SetVariable(VID_SHARED_SECRET, _T("********"));
2266 msg.SetVariable(VID_SNMP_AUTH_PASSWORD, _T("********"));
2267 msg.SetVariable(VID_SNMP_PRIV_PASSWORD, _T("********"));
2268 }
2269 sendMessage(&msg);
2270 msg.deleteAllVariables();
2271 }
2272 }
2273
2274 MutexUnlock(m_mutexSendObjects);
2275 safe_free(objects);
2276
2277 if (options & OBJECT_SYNC_DUAL_CONFIRM)
2278 {
2279 msg.SetCode(CMD_REQUEST_COMPLETED);
2280 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2281 sendMessage(&msg);
2282 }
2283 }
2284
2285 /**
2286 * Send event log records to client
2287 */
2288 void ClientSession::sendEventLog(CSCPMessage *pRequest)
2289 {
2290 CSCPMessage msg;
2291 DB_ASYNC_RESULT hResult = NULL;
2292 DB_RESULT hTempResult;
2293 UINT32 dwRqId, dwMaxRecords, dwNumRows, dwId;
2294 TCHAR szQuery[1024], szBuffer[1024];
2295 WORD wRecOrder;
2296
2297 dwRqId = pRequest->GetId();
2298 dwMaxRecords = pRequest->GetVariableLong(VID_MAX_RECORDS);
2299 wRecOrder = ((g_nDBSyntax == DB_SYNTAX_MSSQL) || (g_nDBSyntax == DB_SYNTAX_ORACLE)) ? RECORD_ORDER_REVERSED : RECORD_ORDER_NORMAL;
2300
2301 // Prepare confirmation message
2302 msg.SetCode(CMD_REQUEST_COMPLETED);
2303 msg.SetId(dwRqId);
2304
2305 MutexLock(m_mutexSendEvents);
2306 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2307
2308 // Retrieve events from database
2309 switch(g_nDBSyntax)
2310 {
2311 case DB_SYNTAX_MYSQL:
2312 case DB_SYNTAX_PGSQL:
2313 case DB_SYNTAX_SQLITE:
2314 dwNumRows = 0;
2315 hTempResult = DBSelect(hdb, _T("SELECT count(*) FROM event_log"));
2316 if (hTempResult != NULL)
2317 {
2318 if (DBGetNumRows(hTempResult) > 0)
2319 {
2320 dwNumRows = DBGetFieldULong(hTempResult, 0, 0);
2321 }
2322 DBFreeResult(hTempResult);
2323 }
2324 _sntprintf(szQuery, 1024,
2325 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2326 _T("event_severity,event_message,user_tag FROM event_log ")
2327 _T("ORDER BY event_id LIMIT %u OFFSET %u"),
2328 dwMaxRecords, dwNumRows - min(dwNumRows, dwMaxRecords));
2329 break;
2330 case DB_SYNTAX_MSSQL:
2331 _sntprintf(szQuery, 1024,
2332 _T("SELECT TOP %u event_id,event_code,event_timestamp,event_source,")
2333 _T("event_severity,event_message,user_tag FROM event_log ")
2334 _T("ORDER BY event_id DESC"), dwMaxRecords);
2335 break;
2336 case DB_SYNTAX_ORACLE:
2337 _sntprintf(szQuery, 1024,
2338 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2339 _T("event_severity,event_message,user_tag FROM event_log ")
2340 _T("WHERE ROWNUM <= %u ORDER BY event_id DESC"), dwMaxRecords);
2341 break;
2342 case DB_SYNTAX_DB2:
2343 _sntprintf(szQuery, 1024,
2344 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2345 _T("event_severity,event_message,user_tag FROM event_log ")
2346 _T("ORDER BY event_id DESC FETCH FIRST %u ROWS ONLY"), dwMaxRecords);
2347 break;
2348 default:
2349 szQuery[0] = 0;
2350 break;
2351 }
2352 hResult = DBAsyncSelect(hdb, szQuery);
2353 if (hResult != NULL)
2354 {
2355 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2356 sendMessage(&msg);
2357 msg.deleteAllVariables();
2358 msg.SetCode(CMD_EVENTLOG_RECORDS);
2359
2360 for(dwId = VID_EVENTLOG_MSG_BASE, dwNumRows = 0; DBFetch(hResult); dwNumRows++)
2361 {
2362 if (dwNumRows == 10)
2363 {
2364 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
2365 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
2366 sendMessage(&msg);
2367 msg.deleteAllVariables();
2368 dwNumRows = 0;
2369 dwId = VID_EVENTLOG_MSG_BASE;
2370 }
2371 msg.SetVariable(dwId++, DBGetFieldAsyncUInt64(hResult, 0));
2372 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 1));
2373 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 2));
2374 msg.SetVariable(dwId++, DBGetFieldAsyncULong(hResult, 3));
2375 msg.SetVariable(dwId++, (WORD)DBGetFieldAsyncLong(hResult, 4));
2376 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
2377 msg.SetVariable(dwId++, szBuffer);
2378 DBGetFieldAsync(hResult, 6, szBuffer, 1024);
2379 msg.SetVariable(dwId++, szBuffer);
2380 msg.SetVariable(dwId++, (UINT32)0); // Do not send parameters
2381 }
2382 DBFreeAsyncResult(hResult);
2383
2384 // Send remaining records with End-Of-Sequence notification
2385 msg.SetVariable(VID_NUM_RECORDS, dwNumRows);
2386 msg.SetVariable(VID_RECORDS_ORDER, wRecOrder);
2387 msg.setEndOfSequence();
2388 sendMessage(&msg);
2389 }
2390 else
2391 {
2392 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2393 sendMessage(&msg);
2394 }
2395
2396 DBConnectionPoolReleaseConnection(hdb);
2397 MutexUnlock(m_mutexSendEvents);
2398 }
2399
2400 /**
2401 * Send all configuration variables to client
2402 */
2403 void ClientSession::sendAllConfigVars(UINT32 dwRqId)
2404 {
2405 UINT32 i, dwId, dwNumRecords;
2406 CSCPMessage msg;
2407 DB_RESULT hResult;
2408 TCHAR szBuffer[MAX_DB_STRING];
2409
2410 // Prepare message
2411 msg.SetCode(CMD_REQUEST_COMPLETED);
2412 msg.SetId(dwRqId);
2413
2414 // Check user rights
2415 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2416 {
2417 // Retrieve configuration variables from database
2418 hResult = DBSelect(g_hCoreDB, _T("SELECT var_name,var_value,need_server_restart FROM config WHERE is_visible=1"));
2419 if (hResult != NULL)
2420 {
2421 // Send events, one per message
2422 dwNumRecords = DBGetNumRows(hResult);
2423 msg.SetVariable(VID_NUM_VARIABLES, dwNumRecords);
2424 for(i = 0, dwId = VID_VARLIST_BASE; i < dwNumRecords; i++)
2425 {
2426 msg.SetVariable(dwId++, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2427 DBGetField(hResult, i, 1, szBuffer, MAX_DB_STRING);
2428 DecodeSQLString(szBuffer);
2429 msg.SetVariable(dwId++, szBuffer);
2430 msg.SetVariable(dwId++, (WORD)DBGetFieldLong(hResult, i, 2));
2431 }
2432 DBFreeResult(hResult);
2433 }
2434 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2435 }
2436 else
2437 {
2438 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2439 }
2440
2441 // Send response
2442 sendMessage(&msg);
2443 }
2444
2445 /**
2446 * Set configuration variable's value
2447 */
2448 void ClientSession::setConfigVariable(CSCPMessage *pRequest)
2449 {
2450 CSCPMessage msg;
2451 TCHAR szName[MAX_OBJECT_NAME], szValue[MAX_DB_STRING];
2452
2453 // Prepare response message
2454 msg.SetCode(CMD_REQUEST_COMPLETED);
2455 msg.SetId(pRequest->GetId());
2456
2457 // Check user rights
2458 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2459 {
2460 pRequest->GetVariableStr(VID_NAME, szName, MAX_OBJECT_NAME);
2461 pRequest->GetVariableStr(VID_VALUE, szValue, MAX_DB_STRING);
2462 if (ConfigWriteStr(szName, szValue, TRUE))
2463 {
2464 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2465 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, 0,
2466 _T("Server configuration variable \"%s\" set to \"%s\""), szName, szValue);
2467 }
2468 else
2469 {
2470 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2471 }
2472 }
2473 else
2474 {
2475 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2476 }
2477
2478 // Send response
2479 sendMessage(&msg);
2480 }
2481
2482 /**
2483 * Delete configuration variable
2484 */
2485 void ClientSession::deleteConfigVariable(CSCPMessage *pRequest)
2486 {
2487 CSCPMessage msg;
2488
2489 // Prepare response message
2490 msg.SetCode(CMD_REQUEST_COMPLETED);
2491 msg.SetId(pRequest->GetId());
2492
2493 // Check user rights
2494 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2495 {
2496 TCHAR name[MAX_OBJECT_NAME];
2497 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2498 if (ConfigDelete(name))
2499 {
2500 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2501 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, 0, _T("Server configuration variable \"%s\" deleted"), name);
2502 }
2503 else
2504 {
2505 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2506 }
2507 }
2508 else
2509 {
2510 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2511 }
2512
2513 // Send response
2514 sendMessage(&msg);
2515 }
2516
2517 /**
2518 * Set configuration clob
2519 */
2520 void ClientSession::setConfigCLOB(CSCPMessage *pRequest)
2521 {
2522 CSCPMessage msg;
2523 TCHAR name[MAX_OBJECT_NAME], *value;
2524
2525 msg.SetId(pRequest->GetId());
2526 msg.SetCode(CMD_REQUEST_COMPLETED);
2527
2528 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2529 {
2530 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2531 value = pRequest->GetVariableStr(VID_VALUE);
2532 if (value != NULL)
2533 {
2534 if (ConfigWriteCLOB(name, value, TRUE))
2535 {
2536 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2537 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, 0,
2538 _T("Server configuration variable \"%s\" set to \"%s\""), name, value);
2539 free(value);
2540 }
2541 else
2542 {
2543 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
2544 }
2545 }
2546 else
2547 {
2548 msg.SetVariable(VID_RCC, RCC_INVALID_REQUEST);
2549 }
2550 }
2551 else
2552 {
2553 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2554 }
2555
2556 sendMessage(&msg);
2557 }
2558
2559 /**
2560 * Get value of configuration clob
2561 */
2562 void ClientSession::getConfigCLOB(CSCPMessage *pRequest)
2563 {
2564 CSCPMessage msg;
2565 TCHAR name[MAX_OBJECT_NAME], *value;
2566
2567 msg.SetId(pRequest->GetId());
2568 msg.SetCode(CMD_REQUEST_COMPLETED);
2569
2570 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2571 {
2572 pRequest->GetVariableStr(VID_NAME, name, MAX_OBJECT_NAME);
2573 value = ConfigReadCLOB(name, NULL);
2574 if (value != NULL)
2575 {
2576 msg.SetVariable(VID_VALUE, value);
2577 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2578 free(value);
2579 }
2580 else
2581 {
2582 msg.SetVariable(VID_RCC, RCC_UNKNOWN_VARIABLE);
2583 }
2584 }
2585 else
2586 {
2587 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2588 }
2589
2590 sendMessage(&msg);
2591 }
2592
2593 /**
2594 * Close session
2595 */
2596 void ClientSession::kill()
2597 {
2598 // We shutdown socket connection, which will cause
2599 // read thread to stop, and other threads will follow
2600 shutdown(m_hSocket, 2);
2601 }
2602
2603 /**
2604 * Handler for new events
2605 */
2606 void ClientSession::onNewEvent(Event *pEvent)
2607 {
2608 UPDATE_INFO *pUpdate;
2609 CSCPMessage *msg;
2610
2611 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_EVENTS))
2612 {
2613 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2614 pUpdate->dwCategory = INFO_CAT_EVENT;
2615 msg = new CSCPMessage;
2616 msg->SetCode(CMD_EVENTLOG_RECORDS);
2617 pEvent->prepareMessage(msg);
2618 pUpdate->pData = msg;
2619 m_pUpdateQueue->Put(pUpdate);
2620 }
2621 }
2622
2623 /**
2624 * Handler for object changes
2625 */
2626 void ClientSession::onObjectChange(NetObj *object)
2627 {
2628 UPDATE_INFO *pUpdate;
2629
2630 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_OBJECTS))
2631 if (object->isDeleted() || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2632 {
2633 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2634 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
2635 pUpdate->pData = object;
2636 object->incRefCount();
2637 m_pUpdateQueue->Put(pUpdate);
2638 }
2639 }
2640
2641 /**
2642 * Send notification message to server
2643 */
2644 void ClientSession::notify(UINT32 dwCode, UINT32 dwData)
2645 {
2646 CSCPMessage msg;
2647
2648 msg.SetCode(CMD_NOTIFY);
2649 msg.SetVariable(VID_NOTIFICATION_CODE, dwCode);
2650 msg.SetVariable(VID_NOTIFICATION_DATA, dwData);
2651 sendMessage(&msg);
2652 }
2653
2654 /**
2655 * Modify object
2656 */
2657 void ClientSession::modifyObject(CSCPMessage *pRequest)
2658 {
2659 UINT32 dwObjectId, dwResult = RCC_SUCCESS;
2660 NetObj *object;
2661 CSCPMessage msg;
2662
2663 // Prepare reply message
2664 msg.SetCode(CMD_REQUEST_COMPLETED);
2665 msg.SetId(pRequest->GetId());
2666
2667 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2668 object = FindObjectById(dwObjectId);
2669 if (object != NULL)
2670 {
2671 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2672 {
2673 // If user attempts to change object's ACL, check
2674 // if he has OBJECT_ACCESS_ACL permission
2675 if (pRequest->isFieldExist(VID_ACL_SIZE))
2676 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
2677 dwResult = RCC_ACCESS_DENIED;
2678
2679 // If user attempts to rename object, check object's name
2680 if (pRequest->isFieldExist(VID_OBJECT_NAME))
2681 {
2682 TCHAR name[256];
2683 pRequest->GetVariableStr(VID_OBJECT_NAME, name, 256);
2684 if (!IsValidObjectName(name, TRUE))
2685 dwResult = RCC_INVALID_OBJECT_NAME;
2686 }
2687
2688 // If allowed, change object and set completion code
2689 if (dwResult == RCC_SUCCESS)
2690 {
2691 dwResult = object->ModifyFromMessage(pRequest);
2692 if (dwResult == RCC_SUCCESS)
2693 {
2694 object->postModify();
2695 }
2696 }
2697 msg.SetVariable(VID_RCC, dwResult);
2698
2699 if (dwResult == RCC_SUCCESS)
2700 {
2701 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, dwObjectId,
2702 _T("Object %s modified from client"), object->Name());
2703 }
2704 else
2705 {
2706 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, dwObjectId,
2707 _T("Failed to modify object from client - error %d"), dwResult);
2708 }
2709 }
2710 else
2711 {
2712 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2713 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, dwObjectId,
2714 _T("Failed to modify object from client - access denied"), dwResult);
2715 }
2716 }
2717 else
2718 {
2719 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
2720 }
2721
2722 // Send response
2723 sendMessage(&msg);
2724 }
2725
2726 /**
2727 * Send users database to client
2728 */
2729 void ClientSession::sendUserDB(UINT32 dwRqId)
2730 {
2731 CSCPMessage msg;
2732 UserDatabaseObject **users;
2733 int i, userCount;
2734
2735 // Prepare response message
2736 msg.SetCode(CMD_REQUEST_COMPLETED);
2737 msg.SetId(dwRqId);
2738 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2739 sendMessage(&msg);
2740 msg.deleteAllVariables();
2741
2742 // Send user database
2743 users = OpenUserDatabase(&userCount);
2744 for(i = 0; i < userCount; i++)
2745 {
2746 msg.SetCode((users[i]->getId() & GROUP_FLAG) ? CMD_GROUP_DATA : CMD_USER_DATA);
2747 users[i]->fillMessage(&msg);
2748 sendMessage(&msg);
2749 msg.deleteAllVariables();
2750 }
2751 CloseUserDatabase();
2752
2753 // Send end-of-database notification
2754 msg.SetCode(CMD_USER_DB_EOF);
2755 sendMessage(&msg);
2756 }
2757
2758 /**
2759 * Create new user
2760 */
2761 void ClientSession::createUser(CSCPMessage *pRequest)
2762 {
2763 CSCPMessage msg;
2764
2765 // Prepare response message
2766 msg.SetCode(CMD_REQUEST_COMPLETED);
2767 msg.SetId(pRequest->GetId());
2768
2769 // Check user rights
2770 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2771 {
2772 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2773 }
2774 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2775 {
2776 // User database have to be locked before any
2777 // changes to user database can be made
2778 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2779 }
2780 else
2781 {
2782 UINT32 dwResult, dwUserId;
2783 BOOL bIsGroup;
2784 TCHAR szUserName[MAX_USER_NAME];
2785
2786 pRequest->GetVariableStr(VID_USER_NAME, szUserName, MAX_USER_NAME);
2787 if (IsValidObjectName(szUserName))
2788 {
2789 bIsGroup = pRequest->GetVariableShort(VID_IS_GROUP);
2790 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
2791 msg.SetVariable(VID_RCC, dwResult);
2792 if (dwResult == RCC_SUCCESS)
2793 {
2794 msg.SetVariable(VID_USER_ID, dwUserId); // Send id of new user to client
2795 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, dwUserId, _T("%s %s created"), bIsGroup ? _T("Group") : _T("User"), szUserName);
2796 }
2797 }
2798 else
2799 {
2800 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
2801 }
2802 }
2803
2804 // Send response
2805 sendMessage(&msg);
2806 }
2807
2808 /**
2809 * Update existing user's data
2810 */
2811 void ClientSession::updateUser(CSCPMessage *pRequest)
2812 {
2813 CSCPMessage msg;
2814
2815 // Prepare response message
2816 msg.SetCode(CMD_REQUEST_COMPLETED);
2817 msg.SetId(pRequest->GetId());
2818
2819 // Check user rights
2820 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2821 {
2822 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2823 }
2824 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2825 {
2826 // User database have to be locked before any
2827 // changes to user database can be made
2828 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2829 }
2830 else
2831 {
2832 UINT32 result = ModifyUserDatabaseObject(pRequest);
2833 if (result == RCC_SUCCESS)
2834 {
2835 TCHAR name[MAX_DB_STRING];
2836 UINT32 id = pRequest->GetVariableLong(VID_USER_ID);
2837 ResolveUserId(id, name, MAX_DB_STRING);
2838 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, id,
2839 _T("%s %s modified"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2840 }
2841 msg.SetVariable(VID_RCC, result);
2842 }
2843
2844 // Send response
2845 sendMessage(&msg);
2846 }
2847
2848 /**
2849 * Delete user
2850 */
2851 void ClientSession::deleteUser(CSCPMessage *pRequest)
2852 {
2853 CSCPMessage msg;
2854 UINT32 dwUserId;
2855
2856 // Prepare response message
2857 msg.SetCode(CMD_REQUEST_COMPLETED);
2858 msg.SetId(pRequest->GetId());
2859
2860 // Check user rights
2861 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2862 {
2863 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2864 }
2865 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2866 {
2867 // User database have to be locked before any
2868 // changes to user database can be made
2869 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2870 }
2871 else
2872 {
2873 // Get Id of user to be deleted
2874 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
2875
2876 if ((dwUserId != 0) && (dwUserId != GROUP_EVERYONE))
2877 {
2878 if (!IsLoggedIn(dwUserId))
2879 {
2880 TCHAR name[MAX_DB_STRING];
2881 ResolveUserId(dwUserId, name, MAX_DB_STRING);
2882 UINT32 rcc = DeleteUserDatabaseObject(dwUserId);
2883 msg.SetVariable(VID_RCC, rcc);
2884 if(rcc == RCC_SUCCESS)
2885 {
2886 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, dwUserId,
2887 _T("%s %s [%d] deleted"), (dwUserId & GROUP_FLAG) ? _T("Group") : _T("User"), name, dwUserId);
2888 }
2889 }
2890 else
2891 {
2892 // logger in users cannot be deleted
2893 msg.SetVariable(VID_RCC, RCC_USER_LOGGED_IN);
2894 }
2895 }
2896 else
2897 {
2898 // System administrator account and everyone group cannot be deleted
2899 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2900 }
2901 }
2902
2903 // Send response
2904 sendMessage(&msg);
2905 }
2906
2907 /**
2908 * Lock/unlock user database
2909 */
2910 void ClientSession::lockUserDB(UINT32 dwRqId, BOOL bLock)
2911 {
2912 CSCPMessage msg;
2913 TCHAR szBuffer[256];
2914
2915 // Prepare response message
2916 msg.SetCode(CMD_REQUEST_COMPLETED);
2917 msg.SetId(dwRqId);
2918
2919 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
2920 {
2921 if (bLock)
2922 {
2923 if (!LockComponent(CID_USER_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
2924 {
2925 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
2926 msg.SetVariable(VID_LOCKED_BY, szBuffer);
2927 }
2928 else
2929 {
2930 m_dwFlags |= CSF_USER_DB_LOCKED;
2931 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2932 }
2933 }
2934 else
2935 {
2936 if (m_dwFlags & CSF_USER_DB_LOCKED)
2937 {
2938 UnlockComponent(CID_USER_DB);
2939 m_dwFlags &= ~CSF_USER_DB_LOCKED;
2940 }
2941 msg.SetVariable(VID_RCC, RCC_SUCCESS);
2942 }
2943 }
2944 else
2945 {
2946 // Current user has no rights for user account management
2947 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
2948 }
2949
2950 // Send response
2951 sendMessage(&msg);
2952 }
2953
2954 /**
2955 * Notify client on user database update
2956 */
2957 void ClientSession::onUserDBUpdate(int code, UINT32 id, UserDatabaseObject *object)
2958 {
2959 CSCPMessage msg;
2960
2961 if (isAuthenticated())
2962 {
2963 msg.SetCode(CMD_USER_DB_UPDATE);
2964 msg.SetId(0);
2965 msg.SetVariable(VID_UPDATE_TYPE, (WORD)code);
2966
2967 switch(code)
2968 {
2969 case USER_DB_CREATE:
2970 case USER_DB_MODIFY:
2971 object->fillMessage(&msg);
2972 break;
2973 default:
2974 msg.SetVariable(VID_USER_ID, id);
2975 break;
2976 }
2977
2978 sendMessage(&msg);
2979 }
2980 }
2981
2982 /**
2983 * Change management status for the object
2984 */
2985 void ClientSession::changeObjectMgmtStatus(CSCPMessage *pRequest)
2986 {
2987 CSCPMessage msg;
2988 UINT32 dwObjectId;
2989 NetObj *object;
2990
2991 // Prepare response message
2992 msg.SetCode(CMD_REQUEST_COMPLETED);
2993 msg.SetId(pRequest->GetId());
2994
2995 // Get object id and check access rights
2996 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
2997 object = FindObjectById(dwObjectId);
2998 if (object != NULL)
2999 {
3000 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3001 {
3002 if ((object->Type() != OBJECT_TEMPLATE) &&
3003 (object->Type() != OBJECT_TEMPLATEGROUP) &&
3004 (object->Type() != OBJECT_TEMPLATEROOT))
3005 {
3006 BOOL bIsManaged = (BOOL)pRequest->GetVariableShort(VID_MGMT_STATUS);
3007 object->setMgmtStatus(bIsManaged);
3008 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3009 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, object->Id(),
3010 _T("Object %s set to %s state"), object->Name(), bIsManaged ? _T("managed") : _T("unmanaged"));
3011 }
3012 else
3013 {
3014 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3015 }
3016 }
3017 else
3018 {
3019 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3020 }
3021 }
3022 else
3023 {
3024 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3025 }
3026
3027 // Send response
3028 sendMessage(&msg);
3029 }
3030
3031 /**
3032 * Set user's password
3033 */
3034 void ClientSession::setPassword(CSCPMessage *pRequest)
3035 {
3036 CSCPMessage msg;
3037 UINT32 dwUserId;
3038
3039 // Prepare response message
3040 msg.SetCode(CMD_REQUEST_COMPLETED);
3041 msg.SetId(pRequest->GetId());
3042
3043 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
3044
3045 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
3046 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
3047 (dwUserId == m_dwUserId)) // User can change password for itself
3048 {
3049 UINT32 dwResult;
3050 TCHAR newPassword[1024], oldPassword[1024];
3051
3052 #ifdef UNICODE
3053 pRequest->GetVariableStr(VID_PASSWORD, newPassword, 256);
3054 if (pRequest->isFieldExist(VID_OLD_PASSWORD))
3055 pRequest->GetVariableStr(VID_OLD_PASSWORD, oldPassword, 256);
3056 #else
3057 pRequest->GetVariableStrUTF8(VID_PASSWORD, newPassword, 1024);
3058 if (pRequest->isFieldExist(VID_OLD_PASSWORD))
3059 pRequest->GetVariableStrUTF8(VID_OLD_PASSWORD, oldPassword, 1024);
3060 #endif
3061 else
3062 oldPassword[0] = 0;
3063 dwResult = SetUserPassword(dwUserId, newPassword, oldPassword, dwUserId == m_dwUserId);
3064 msg.SetVariable(VID_RCC, dwResult);
3065
3066 if (dwResult == RCC_SUCCESS)
3067 {
3068 TCHAR userName[MAX_DB_STRING];
3069 ResolveUserId(dwUserId, userName, MAX_DB_STRING);
3070 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, 0, _T("Changed password for user %s"), userName);
3071 }
3072 }
3073 else
3074 {
3075 // Current user has no rights to change password for specific user
3076 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3077 }
3078
3079 // Send response
3080 sendMessage(&msg);
3081 }
3082
3083 /**
3084 * Send node's DCIs to client and lock data collection settings
3085 */
3086 void ClientSession::openNodeDCIList(CSCPMessage *pRequest)
3087 {
3088 CSCPMessage msg;
3089 UINT32 dwObjectId;
3090 NetObj *object;
3091 BOOL bSuccess = FALSE;
3092 TCHAR szLockInfo[MAX_SESSION_NAME];
3093
3094 // Prepare response message
3095 msg.SetCode(CMD_REQUEST_COMPLETED);
3096 msg.SetId(pRequest->GetId());
3097
3098 // Get node id and check object class and access rights
3099 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
3100 object = FindObjectById(dwObjectId);
3101 if (object != NULL)
3102 {
3103 if ((object->Type() == OBJECT_NODE) ||
3104 (object->Type() == OBJECT_CLUSTER) ||
3105 (object->Type() == OBJECT_MOBILEDEVICE) ||
3106 (object->Type() == OBJECT_TEMPLATE))
3107 {
3108 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3109 {
3110 // Try to lock DCI list
3111 if (((Template *)object)->lockDCIList(m_dwIndex, m_szUserName, szLockInfo))
3112 {
3113 bSuccess = TRUE;
3114 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3115
3116 // Modify list of open nodes DCI lists
3117 m_pOpenDCIList = (UINT32 *)realloc(m_pOpenDCIList, sizeof(UINT32) * (m_dwOpenDCIListSize + 1));
3118 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
3119 m_dwOpenDCIListSize++;
3120 }
3121 else
3122 {
3123 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
3124 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
3125 }
3126 }
3127 else
3128 {
3129 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3130 }
3131 }
3132 else
3133 {
3134 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3135 }
3136 }
3137 else
3138 {
3139 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3140 }
3141
3142 // Send response
3143 sendMessage(&msg);
3144
3145 // If DCI list was successfully locked, send it to client
3146 if (bSuccess)
3147 ((Template *)object)->sendItemsToClient(this, pRequest->GetId());
3148 }
3149
3150 /**
3151 * Unlock node's data collection settings
3152 */
3153 void ClientSession::closeNodeDCIList(CSCPMessage *pRequest)
3154 {
3155 CSCPMessage msg;
3156 UINT32 dwObjectId;
3157 NetObj *object;
3158
3159 // Prepare response message
3160 msg.SetCode(CMD_REQUEST_COMPLETED);
3161 msg.SetId(pRequest->GetId());
3162
3163 // Get node id and check object class and access rights
3164 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
3165 object = FindObjectById(dwObjectId);
3166 if (object != NULL)
3167 {
3168 if ((object->Type() == OBJECT_NODE) ||
3169 (object->Type() == OBJECT_CLUSTER) ||
3170 (object->Type() == OBJECT_MOBILEDEVICE) ||
3171 (object->Type() == OBJECT_TEMPLATE))
3172 {
3173 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3174 {
3175 BOOL bSuccess;
3176
3177 // Try to unlock DCI list
3178 bSuccess = ((Template *)object)->unlockDCIList(m_dwIndex);
3179 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
3180
3181 // Modify list of open nodes DCI lists
3182 if (bSuccess)
3183 {
3184 UINT32 i;
3185
3186 for(i = 0; i < m_dwOpenDCIListSize; i++)
3187 if (m_pOpenDCIList[i] == dwObjectId)
3188 {
3189 m_dwOpenDCIListSize--;
3190 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1], sizeof(UINT32) * (m_dwOpenDCIListSize - i));
3191 break;
3192 }
3193 }
3194
3195 // Queue template update
3196 if ((object->Type() == OBJECT_TEMPLATE) || (object->Type() == OBJECT_CLUSTER))
3197 ((Template *)object)->queueUpdate();
3198 }
3199 else
3200 {
3201 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3202 }
3203 }
3204 else
3205 {
3206 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3207 }
3208 }
3209 else
3210 {
3211 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3212 }
3213
3214 // Send response
3215 sendMessage(&msg);
3216 }
3217
3218 /**
3219 * Create, modify, or delete data collection item for node
3220 */
3221 void ClientSession::modifyNodeDCI(CSCPMessage *pRequest)
3222 {
3223 CSCPMessage msg;
3224 UINT32 dwObjectId;
3225 NetObj *object;
3226
3227 // Prepare response message
3228 msg.SetCode(CMD_REQUEST_COMPLETED);
3229 msg.SetId(pRequest->GetId());
3230
3231 // Get node id and check object class and access rights
3232 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
3233 object = FindObjectById(dwObjectId);
3234 if (object != NULL)
3235 {
3236 if ((object->Type() == OBJECT_NODE) ||
3237 (object->Type() == OBJECT_CLUSTER) ||
3238 (object->Type() == OBJECT_MOBILEDEVICE) ||
3239 (object->Type() == OBJECT_TEMPLATE))
3240 {
3241 if (((Template *)object)->isLockedBySession(m_dwIndex))
3242 {
3243 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3244 {
3245 UINT32 i, dwItemId, dwNumMaps, *pdwMapId, *pdwMapIndex;
3246 DCObject *dcObject;
3247 BOOL bSuccess = FALSE;
3248
3249 int dcObjectType = (int)pRequest->GetVariableShort(VID_DCOBJECT_TYPE);
3250 switch(pRequest->GetCode())
3251 {
3252 case CMD_CREATE_NEW_DCI:
3253 // Create dummy DCI
3254 switch(dcObjectType)
3255 {
3256 case DCO_TYPE_ITEM:
3257 dcObject = new DCItem(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL, DCI_DT_INT,
3258 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3259 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3260 break;
3261 case DCO_TYPE_TABLE:
3262 dcObject = new DCTable(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL,
3263 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3264 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3265 break;
3266 default:
3267 dcObject = NULL;
3268 break;
3269 }
3270 if (dcObject != NULL)
3271 {
3272 dcObject->setStatus(ITEM_STATUS_DISABLED, false);
3273 if ((bSuccess = ((Template *)object)->addDCObject(dcObject)))
3274 {
3275 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3276 // Return new item id to client
3277 msg.SetVariable(VID_DCI_ID, dcObject->getId());
3278 }
3279 else // Unable to add item to node
3280 {
3281 delete dcObject;
3282 msg.SetVariable(VID_RCC, RCC_DUPLICATE_DCI);
3283 }
3284 }
3285 else
3286 {
3287 msg.SetVariable(VID_RCC, RCC_INVALID_ARGUMENT);
3288 }
3289 break;
3290 case CMD_MODIFY_NODE_DCI:
3291 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3292 bSuccess = ((Template *)object)->updateDCObject(dwItemId, pRequest, &dwNumMaps, &pdwMapIndex, &pdwMapId);
3293 if (bSuccess)
3294 {
3295 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3296
3297 // Send index to id mapping for newly created thresholds to client
3298 if (dcObjectType == DCO_TYPE_ITEM)
3299 {
3300 msg.SetVariable(VID_DCI_NUM_MAPS, dwNumMaps);
3301 for(i = 0; i < dwNumMaps; i++)
3302 {
3303 pdwMapId[i] = htonl(pdwMapId[i]);
3304 pdwMapIndex[i] = htonl(pdwMapIndex[i]);
3305 }
3306 msg.SetVariable(VID_DCI_MAP_IDS, (BYTE *)pdwMapId, sizeof(UINT32) * dwNumMaps);
3307 msg.SetVariable(VID_DCI_MAP_INDEXES, (BYTE *)pdwMapIndex, sizeof(UINT32) * dwNumMaps);
3308 safe_free(pdwMapId);
3309 safe_free(pdwMapIndex);
3310 }
3311 }
3312 else
3313 {
3314 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3315 }
3316 break;
3317 case CMD_DELETE_NODE_DCI:
3318 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3319 bSuccess = ((Template *)object)->deleteDCObject(dwItemId, true);
3320 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_INVALID_DCI_ID);
3321 break;
3322 }
3323 if (bSuccess)
3324 ((Template *)object)->setDCIModificationFlag();
3325 }
3326 else // User doesn't have MODIFY rights on object
3327 {
3328 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3329 }
3330 }
3331 else // Nodes DCI list not locked by this session
3332 {
3333 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3334 }
3335 }
3336 else // Object is not a node
3337 {
3338 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3339 }
3340 }
3341 else // No object with given ID
3342 {
3343 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3344 }
3345
3346 // Send response
3347 sendMessage(&msg);
3348 }
3349
3350 /**
3351 * Change status for one or more DCIs
3352 */
3353 void ClientSession::changeDCIStatus(CSCPMessage *pRequest)
3354 {
3355 CSCPMessage msg;
3356 NetObj *object;
3357
3358 // Prepare response message
3359 msg.SetCode(CMD_REQUEST_COMPLETED);
3360 msg.SetId(pRequest->GetId());
3361
3362 // Get node id and check object class and access rights
3363 object = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3364 if (object != NULL)
3365 {
3366 if ((object->Type() == OBJECT_NODE) ||
3367 (object->Type() == OBJECT_CLUSTER) ||
3368 (object->Type() == OBJECT_MOBILEDEVICE) ||
3369 (object->Type() == OBJECT_TEMPLATE))
3370 {
3371 if (((Template *)object)->isLockedBySession(m_dwIndex))
3372 {
3373 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3374 {
3375 UINT32 dwNumItems, *pdwItemList;
3376 int iStatus;
3377
3378 iStatus = pRequest->GetVariableShort(VID_DCI_STATUS);
3379 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
3380 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * dwNumItems);
3381 pRequest->getFieldAsInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3382 if (((Template *)object)->setItemStatus(dwNumItems, pdwItemList, iStatus))
3383 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3384 else
3385 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3386 free(pdwItemList);
3387 }
3388 else // User doesn't have MODIFY rights on object
3389 {
3390 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3391 }
3392 }
3393 else // Nodes DCI list not locked by this session
3394 {
3395 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3396 }
3397 }
3398 else // Object is not a node
3399 {
3400 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3401 }
3402 }
3403 else // No object with given ID
3404 {
3405 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3406 }
3407
3408 // Send response
3409 sendMessage(&msg);
3410 }
3411
3412 /**
3413 * Clear all collected data for DCI
3414 */
3415 void ClientSession::clearDCIData(CSCPMessage *pRequest)
3416 {
3417 CSCPMessage msg;
3418 NetObj *object;
3419 UINT32 dwItemId;
3420
3421 // Prepare response message
3422 msg.SetCode(CMD_REQUEST_COMPLETED);
3423 msg.SetId(pRequest->GetId());
3424
3425 // Get node id and check object class and access rights
3426 object = FindObjectById(pRequest->GetVariableLong(VID_OBJECT_ID));
3427 if (object != NULL)
3428 {
3429 if ((object->Type() == OBJECT_NODE) || (object->Type() == OBJECT_MOBILEDEVICE) || (object->Type() == OBJECT_CLUSTER))
3430 {
3431 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_DELETE))
3432 {
3433 dwItemId = pRequest->GetVariableLong(VID_DCI_ID);
3434 debugPrintf(4, _T("ClearDCIData: request for DCI %d at node %d"), dwItemId, object->Id());
3435 DCObject *dci = ((Template *)object)->getDCObjectById(dwItemId);
3436 if (dci != NULL)
3437 {
3438 msg.SetVariable(VID_RCC, dci->deleteAllData() ? RCC_SUCCESS : RCC_DB_FAILURE);
3439 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d"), dwItemId, object->Id());
3440 }
3441 else
3442 {
3443 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3444 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d not found"), dwItemId, object->Id());
3445 }
3446 }
3447 else // User doesn't have DELETE rights on object
3448 {
3449 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3450 }
3451 }
3452 else // Object is not a node
3453 {
3454 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3455 }
3456 }
3457 else // No object with given ID
3458 {
3459 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3460 }
3461
3462 // Send response
3463 sendMessage(&msg);
3464 }
3465
3466 /**
3467 * Copy or move DCI from one node or template to another
3468 */
3469 void ClientSession::copyDCI(CSCPMessage *pRequest)
3470 {
3471 CSCPMessage msg;
3472 NetObj *pSource, *pDestination;
3473 TCHAR szLockInfo[MAX_SESSION_NAME];
3474 BOOL bMove;
3475
3476 // Prepare response message
3477 msg.SetCode(CMD_REQUEST_COMPLETED);
3478 msg.SetId(pRequest->GetId());
3479
3480 // Get source and destination
3481 pSource = FindObjectById(pRequest->GetVariableLong(VID_SOURCE_OBJECT_ID));
3482 pDestination = FindObjectById(pRequest->GetVariableLong(VID_DESTINATION_OBJECT_ID));
3483 if ((pSource != NULL) && (pDestination != NULL))
3484 {
3485 // Check object types
3486 if (((pSource->Type() == OBJECT_NODE) || (pSource->Type() == OBJECT_MOBILEDEVICE) || (pSource->Type() == OBJECT_TEMPLATE) || (pSource->Type() == OBJECT_CLUSTER)) &&
3487 ((pDestination->Type() == OBJECT_NODE) || (pDestination->Type() == OBJECT_MOBILEDEVICE) || (pDestination->Type() == OBJECT_TEMPLATE) || (pDestination->Type() == OBJECT_CLUSTER)))
3488 {
3489 if (((Template *)pSource)->isLockedBySession(m_dwIndex))
3490 {
3491 bMove = pRequest->GetVariableShort(VID_MOVE_FLAG);
3492 // Check access rights
3493 if ((pSource->checkAccessRights(m_dwUserId, bMove ? (OBJECT_ACCESS_READ | OBJECT_ACCESS_MODIFY) : OBJECT_ACCESS_READ)) &&
3494 (pDestination->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)))
3495 {
3496 // Attempt to lock destination's DCI list
3497 if ((pDestination->Id() == pSource->Id()) ||
3498 (((Template *)pDestination)->lockDCIList(m_dwIndex, m_szUserName, szLockInfo)))
3499 {
3500 UINT32 i, *pdwItemList, dwNumItems;
3501 const DCObject *pSrcItem;
3502 DCObject *pDstItem;
3503 int iErrors = 0;
3504
3505 // Get list of items to be copied/moved
3506 dwNumItems = pRequest->GetVariableLong(VID_NUM_ITEMS);
3507 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * dwNumItems);
3508 pRequest->getFieldAsInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3509
3510 // Copy items
3511 for(i = 0; i < dwNumItems; i++)
3512 {
3513 pSrcItem = ((Template *)pSource)->getDCObjectById(pdwItemList[i]);
3514 if (pSrcItem != NULL)
3515 {
3516 switch(pSrcItem->getType())
3517 {
3518 case DCO_TYPE_ITEM:
3519 pDstItem = new DCItem((DCItem *)pSrcItem);
3520 break;
3521 case DCO_TYPE_TABLE:
3522 pDstItem = new DCTable((DCTable *)pSrcItem);
3523 break;
3524 default:
3525 pDstItem = NULL;
3526 break;
3527 }
3528 if (pDstItem != NULL)
3529 {
3530 pDstItem->setTemplateId(0, 0);
3531 pDstItem->changeBinding(CreateUniqueId(IDG_ITEM),
3532 (Template *)pDestination, FALSE);
3533 if (((Template *)pDestination)->addDCObject(pDstItem))
3534 {
3535 if (bMove)
3536 {
3537 // Delete original item
3538 if (!((Template *)pSource)->deleteDCObject(pdwItemList[i], TRUE))
3539 {
3540 iErrors++;
3541 }
3542 }
3543 }
3544 else
3545 {
3546 delete pDstItem;
3547 iErrors++;
3548 }
3549 }
3550 else
3551 {
3552 DbgPrintf(2, _T("INTERNAL ERROR: ClientSession::CopyDCI(): unknown DCO type %d"), pSrcItem->getType());
3553 iErrors++;
3554 }
3555 }
3556 else
3557 {
3558 iErrors++;
3559 }
3560 }
3561
3562 // Cleanup
3563 free(pdwItemList);
3564 if (pDestination->Id() != pSource->Id())
3565 ((Template *)pDestination)->unlockDCIList(m_dwIndex);
3566 msg.SetVariable(VID_RCC, (iErrors == 0) ? RCC_SUCCESS : RCC_DCI_COPY_ERRORS);
3567
3568 // Queue template update
3569 if (pDestination->Type() == OBJECT_TEMPLATE)
3570 ((Template *)pDestination)->queueUpdate();
3571 }
3572 else // Destination's DCI list already locked by someone else
3573 {
3574 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
3575 msg.SetVariable(VID_LOCKED_BY, szLockInfo);
3576 }
3577 }
3578 else // User doesn't have enough rights on object(s)
3579 {
3580 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3581 }
3582 }
3583 else // Source node DCI list not locked by this session
3584 {
3585 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3586 }
3587 }
3588 else // Object(s) is not a node
3589 {
3590 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3591 }
3592 }
3593 else // No object(s) with given ID
3594 {
3595 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3596 }
3597
3598 // Send response
3599 sendMessage(&msg);
3600 }
3601
3602 /**
3603 * Send list of thresholds for DCI
3604 */
3605 void ClientSession::sendDCIThresholds(CSCPMessage *request)
3606 {
3607 CSCPMessage msg;
3608 NetObj *object;
3609
3610 // Prepare response message
3611 msg.SetCode(CMD_REQUEST_COMPLETED);
3612 msg.SetId(request->GetId());
3613
3614 // Get node id and check object class and access rights
3615 object = FindObjectById(request->GetVariableLong(VID_OBJECT_ID));
3616 if (object != NULL)
3617 {
3618 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3619 {
3620 if ((object->Type() == OBJECT_NODE) || (object->Type() == OBJECT_MOBILEDEVICE) || (object->Type() == OBJECT_CLUSTER))
3621 {
3622 DCObject *dci = ((Template *)object)->getDCObjectById(request->GetVariableLong(VID_DCI_ID));
3623 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
3624 {
3625 ((DCItem *)dci)->fillMessageWithThresholds(&msg);
3626 msg.SetVariable(VID_RCC, RCC_SUCCESS);
3627 }
3628 else
3629 {
3630 msg.SetVariable(VID_RCC, RCC_INVALID_DCI_ID);
3631 }
3632 }
3633 else
3634 {
3635 msg.SetVariable(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3636 }
3637 }
3638 else
3639 {
3640 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
3641 }
3642 }
3643 else // No object with given ID
3644 {
3645 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
3646 }
3647
3648 // Send response
3649 sendMessage(&msg);
3650 }
3651
3652 /**
3653 * Prepare statement for reading data from idata table
3654 */
3655 static DB_STATEMENT PrepareIDataSelect(DB_HANDLE hdb, UINT32 nodeId, UINT32 maxRows, const TCHAR *condition)
3656 {
3657 TCHAR query[512];
3658
3659 switch(g_nDBSyntax)
3660 {
3661 case DB_SYNTAX_MSSQL:
3662 _sntprintf(query, 512, _T("SELECT TOP %d idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC"),
3663 (int)maxRows, (int)nodeId, condition);
3664 break;
3665 case DB_SYNTAX_ORACLE:
3666 _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"),
3667 (int)nodeId, condition, (int)maxRows);
3668 break;
3669 case DB_SYNTAX_MYSQL:
3670 case DB_SYNTAX_PGSQL:
3671 case DB_SYNTAX_SQLITE:
3672 _sntprintf(query, 512, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC LIMIT %d"),
3673 (int)nodeId, condition, (int)maxRows);
3674 break;
3675 case DB_SYNTAX_DB2:
3676 _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"),
3677 (int)nodeId, condition, (int)maxRows);
3678 break;
3679 default:
3680 DbgPrintf(1, _T(">>> INTERNAL ERROR: unsupported database in PrepareIDataSelect"));
3681 return NULL; // Unsupported database
3682 }
3683 return DBPrepare(hdb, query);
3684 }
3685
3686 /**
3687 * Prepare statement for reading data from tdata table
3688 */
3689 static DB_STATEMENT PrepareTDataSelect(DB_HANDLE hdb, UINT32 nodeId, UINT32 maxRows, const TCHAR *condition)
3690 {
3691 TCHAR query[1024];
3692
3693 switch(g_nDBSyntax)
3694 {
3695 case DB_SYNTAX_MSSQL:
3696 _sntprintf(query, 1024,
3697 _T("SELECT TOP %d d.tdata_timestamp, r.value FROM tdata_%d d")
3698 _T(" INNER JOIN tdata_records_%d rec ON rec.record_id=d.record_id ")
3699 _T(" INNER JOIN tdata_rows_%d r ON r.row_id=rec.row_id ")
3700 _T("WHERE d.item_id=? AND rec.instance=? AND r.column_id=? %s ")
3701 _T("ORDER BY d.tdata_timestamp DESC"),