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