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