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