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