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