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