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