Added data collection item properties dialog
[public/netxms.git] / src / server / core / session.cpp
CommitLineData
21e4b6f0
VK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004 Victor Kirhenshtein
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** $module: session.cpp
20**
21**/
22
23#include "nms_core.h"
24
25
2d5c8ac8
VK
26//
27// Fill CSCP message with user data
28//
29
30static void FillUserInfoMessage(CSCPMessage *pMsg, NMS_USER *pUser)
31{
32 pMsg->SetVariable(VID_USER_ID, pUser->dwId);
33 pMsg->SetVariable(VID_USER_NAME, pUser->szName);
34 pMsg->SetVariable(VID_USER_FLAGS, pUser->wFlags);
35 pMsg->SetVariable(VID_USER_SYS_RIGHTS, pUser->wSystemRights);
36 pMsg->SetVariable(VID_USER_FULL_NAME, pUser->szFullName);
37 pMsg->SetVariable(VID_USER_DESCRIPTION, pUser->szDescription);
38}
39
40
41//
42// Fill CSCP message with user group data
43//
44
45static void FillGroupInfoMessage(CSCPMessage *pMsg, NMS_USER_GROUP *pGroup)
46{
47 DWORD i, dwId;
48
49 pMsg->SetVariable(VID_USER_ID, pGroup->dwId);
50 pMsg->SetVariable(VID_USER_NAME, pGroup->szName);
51 pMsg->SetVariable(VID_USER_FLAGS, pGroup->wFlags);
52 pMsg->SetVariable(VID_USER_SYS_RIGHTS, pGroup->wSystemRights);
53 pMsg->SetVariable(VID_USER_DESCRIPTION, pGroup->szDescription);
54 pMsg->SetVariable(VID_NUM_MEMBERS, pGroup->dwNumMembers);
55 for(i = 0, dwId = VID_GROUP_MEMBER_BASE; i < pGroup->dwNumMembers; i++, dwId++)
56 pMsg->SetVariable(dwId, pGroup->pMembers[i]);
57}
58
59
21e4b6f0
VK
60//
61// Client session class constructor
62//
63
b54b2b11 64ClientSession::ClientSession(SOCKET hSocket, DWORD dwHostAddr)
21e4b6f0
VK
65{
66 m_pSendQueue = new Queue;
67 m_pMessageQueue = new Queue;
62f5857f 68 m_pUpdateQueue = new Queue;
21e4b6f0
VK
69 m_hSocket = hSocket;
70 m_dwIndex = INVALID_INDEX;
71 m_iState = STATE_CONNECTED;
72 m_pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
d16cf8a5
AK
73 m_hCondWriteThreadStopped = ConditionCreate(FALSE);
74 m_hCondProcessingThreadStopped = ConditionCreate(FALSE);
75 m_hCondUpdateThreadStopped = ConditionCreate(FALSE);
62f5857f 76 m_hMutexSendEvents = MutexCreate();
53512272 77 m_hMutexSendObjects = MutexCreate();
b54b2b11
VK
78 m_dwFlags = 0;
79 m_dwHostAddr = dwHostAddr;
80 strcpy(m_szUserName, "<not logged in>");
984542f8 81 m_dwUserId = INVALID_INDEX;
338493a0
VK
82 m_dwOpenDCIListSize = 0;
83 m_pOpenDCIList = NULL;
21e4b6f0
VK
84}
85
86
87//
88// Destructor
89//
90
91ClientSession::~ClientSession()
92{
93 shutdown(m_hSocket, 2);
94 closesocket(m_hSocket);
95 delete m_pSendQueue;
96 delete m_pMessageQueue;
62f5857f 97 delete m_pUpdateQueue;
338493a0 98 safe_free(m_pMsgBuffer);
ecb7e1ee
VK
99 ConditionDestroy(m_hCondWriteThreadStopped);
100 ConditionDestroy(m_hCondProcessingThreadStopped);
62f5857f
VK
101 ConditionDestroy(m_hCondUpdateThreadStopped);
102 MutexDestroy(m_hMutexSendEvents);
53512272 103 MutexDestroy(m_hMutexSendObjects);
338493a0 104 safe_free(m_pOpenDCIList);
21e4b6f0
VK
105}
106
107
108//
109// Print debug information
110//
111
112void ClientSession::DebugPrintf(char *szFormat, ...)
113{
114 if ((g_dwFlags & AF_STANDALONE) && (g_dwFlags & AF_DEBUG_CSCP))
115 {
116 va_list args;
117
118 printf("*CSCP(%d)* ", m_dwIndex);
119 va_start(args, szFormat);
120 vprintf(szFormat, args);
121 va_end(args);
122 }
123}
124
125
21e4b6f0
VK
126//
127// ReadThread()
128//
129
130void ClientSession::ReadThread(void)
131{
132 CSCP_MESSAGE *pRawMsg;
133 CSCPMessage *pMsg;
134 int iErr;
338493a0
VK
135 DWORD i;
136 NetObj *pObject;
21e4b6f0
VK
137
138 // Initialize raw message receiving function
139 RecvCSCPMessage(0, NULL, m_pMsgBuffer);
140
141 pRawMsg = (CSCP_MESSAGE *)malloc(65536);
142 while(1)
143 {
144 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer)) <= 0)
145 break;
146
147 // Check that actual received packet size is equal to encoded in packet
148 if (ntohs(pRawMsg->wSize) != iErr)
149 {
150 DebugPrintf("Actual message size doesn't match wSize value (%d,%d)\n", iErr, ntohs(pRawMsg->wSize));
151 continue; // Bad packet, wait for next
152 }
153
154 // Create message object from raw message
155 pMsg = new CSCPMessage(pRawMsg);
156 m_pMessageQueue->Put(pMsg);
157 }
158 if (iErr < 0)
159 WriteLog(MSG_SESSION_CLOSED, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
160 free(pRawMsg);
161
162 // Notify other threads to exit
ecb7e1ee
VK
163 m_pSendQueue->Put(INVALID_POINTER_VALUE);
164 m_pMessageQueue->Put(INVALID_POINTER_VALUE);
165
166 // Wait for other threads to finish
167 ConditionWait(m_hCondWriteThreadStopped, INFINITE);
168 ConditionWait(m_hCondProcessingThreadStopped, INFINITE);
54abbe0e
VK
169
170 // Remove all locks created by this session
171 RemoveAllSessionLocks(m_dwIndex);
338493a0
VK
172 for(i = 0; i < m_dwOpenDCIListSize; i++)
173 {
174 pObject = FindObjectById(m_pOpenDCIList[i]);
175 if (pObject != NULL)
176 if (pObject->Type() == OBJECT_NODE)
177 ((Node *)pObject)->UnlockDCIList(m_dwIndex);
178 }
21e4b6f0
VK
179}
180
181
182//
183// WriteThread()
184//
185
186void ClientSession::WriteThread(void)
187{
188 CSCP_MESSAGE *pMsg;
189
190 while(1)
191 {
192 pMsg = (CSCP_MESSAGE *)m_pSendQueue->GetOrBlock();
ecb7e1ee 193 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
21e4b6f0
VK
194 break;
195
196 if (send(m_hSocket, (const char *)pMsg, ntohs(pMsg->wSize), 0) <= 0)
197 {
7968a52d 198 MemFree(pMsg);
21e4b6f0
VK
199 break;
200 }
7968a52d 201 MemFree(pMsg);
21e4b6f0 202 }
ecb7e1ee 203 ConditionSet(m_hCondWriteThreadStopped);
21e4b6f0
VK
204}
205
206
207//
208// Message processing thread
209//
210
211void ClientSession::ProcessingThread(void)
212{
213 CSCPMessage *pMsg, *pReply;
74a5aa17 214 char szBuffer[128];
21e4b6f0
VK
215
216 while(1)
217 {
218 pMsg = (CSCPMessage *)m_pMessageQueue->GetOrBlock();
ecb7e1ee 219 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
21e4b6f0
VK
220 break;
221
74a5aa17 222 DebugPrintf("Received message %s\n", CSCPMessageCodeName(pMsg->GetCode(), szBuffer));
21e4b6f0
VK
223 if ((m_iState != STATE_AUTHENTICATED) && (pMsg->GetCode() != CMD_LOGIN))
224 {
225 delete pMsg;
226 continue;
227 }
228
229 switch(pMsg->GetCode())
230 {
231 case CMD_LOGIN:
e100f091 232 Login(pMsg);
21e4b6f0
VK
233 break;
234 case CMD_GET_OBJECTS:
e100f091 235 SendAllObjects(pMsg->GetId());
21e4b6f0
VK
236 break;
237 case CMD_GET_EVENTS:
74a5aa17 238 SendAllEvents(pMsg->GetId());
21e4b6f0
VK
239 break;
240 case CMD_GET_CONFIG_VARLIST:
241 SendAllConfigVars();
242 break;
b54b2b11
VK
243 case CMD_OPEN_EVENT_DB:
244 SendEventDB(pMsg->GetId());
245 break;
246 case CMD_CLOSE_EVENT_DB:
247 if (m_dwFlags & CSF_EVENT_DB_LOCKED)
248 {
b8bad201
VK
249 // Check if event configuration DB has been modified
250 if (m_dwFlags & CSF_EVENT_DB_MODIFIED)
4d5a05a0 251 ReloadEvents();
b54b2b11
VK
252 UnlockComponent(CID_EVENT_DB);
253 m_dwFlags &= ~CSF_EVENT_DB_LOCKED;
254 }
3a5042fd
VK
255 // Send reply
256 pReply = new CSCPMessage;
257 pReply->SetCode(CMD_REQUEST_COMPLETED);
258 pReply->SetId(pMsg->GetId());
259 pReply->SetVariable(VID_RCC, RCC_SUCCESS);
260 SendMessage(pReply);
261 delete pReply;
b54b2b11 262 break;
605d2931
VK
263 case CMD_SET_EVENT_INFO:
264 SetEventInfo(pMsg);
265 break;
24156e90
VK
266 case CMD_MODIFY_OBJECT:
267 ModifyObject(pMsg);
268 break;
c1c39152
VK
269 case CMD_SET_OBJECT_MGMT_STATUS:
270 ChangeObjectMgmtStatus(pMsg);
271 break;
23a32988
VK
272 case CMD_LOAD_USER_DB:
273 SendUserDB(pMsg->GetId());
274 break;
ff550544
VK
275 case CMD_CREATE_USER:
276 CreateUser(pMsg);
277 break;
278 case CMD_UPDATE_USER:
279 UpdateUser(pMsg);
280 break;
281 case CMD_DELETE_USER:
282 DeleteUser(pMsg);
283 break;
284 case CMD_LOCK_USER_DB:
285 LockUserDB(pMsg->GetId(), TRUE);
286 break;
287 case CMD_UNLOCK_USER_DB:
288 LockUserDB(pMsg->GetId(), FALSE);
289 break;
017e1e13
VK
290 case CMD_SET_PASSWORD:
291 SetPassword(pMsg);
292 break;
7257eb7d
VK
293 case CMD_GET_NODE_DCI_LIST:
294 OpenNodeDCIList(pMsg);
295 break;
296 case CMD_UNLOCK_NODE_DCI_LIST:
297 CloseNodeDCIList(pMsg);
298 break;
21e4b6f0
VK
299 default:
300 break;
301 }
302 delete pMsg;
303 }
ecb7e1ee 304 ConditionSet(m_hCondProcessingThreadStopped);
21e4b6f0
VK
305}
306
307
e100f091
VK
308//
309// Authenticate client
310//
311
312void ClientSession::Login(CSCPMessage *pRequest)
313{
314 CSCPMessage msg;
315 BYTE szPassword[SHA_DIGEST_LENGTH];
316 char szLogin[MAX_USER_NAME], szBuffer[32];
317
318 // Prepare responce message
319 msg.SetCode(CMD_LOGIN_RESP);
320 msg.SetId(pRequest->GetId());
321
322 if (m_iState != STATE_AUTHENTICATED)
323 {
324
325 pRequest->GetVariableStr(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
326 pRequest->GetVariableBinary(VID_PASSWORD, szPassword, SHA_DIGEST_LENGTH);
327
328 if (AuthenticateUser(szLogin, szPassword, &m_dwUserId, &m_dwSystemAccess))
329 {
330 m_iState = STATE_AUTHENTICATED;
331 sprintf(m_szUserName, "%s@%s", szLogin, IpToStr(m_dwHostAddr, szBuffer));
332 msg.SetVariable(VID_RCC, RCC_SUCCESS);
333 DebugPrintf("User %s authenticated\n", m_szUserName);
334 }
335 else
336 {
337 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
338 }
339 }
340 else
341 {
342 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
343 }
344
345 // Send responce
346 SendMessage(&msg);
347}
348
349
b54b2b11
VK
350//
351// Send event configuration to client
352//
353
354void ClientSession::SendEventDB(DWORD dwRqId)
355{
356 DB_ASYNC_RESULT hResult;
357 CSCPMessage msg;
358 char szBuffer[1024];
359
360 // Prepare responce message
3a5042fd 361 msg.SetCode(CMD_REQUEST_COMPLETED);
b54b2b11
VK
362 msg.SetId(dwRqId);
363
b8bad201
VK
364 if (!CheckSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB))
365 {
366 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
367 SendMessage(&msg);
368 }
369 else if (!LockComponent(CID_EVENT_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
b54b2b11
VK
370 {
371 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
372 msg.SetVariable(VID_LOCKED_BY, szBuffer);
373 SendMessage(&msg);
374 }
375 else
376 {
377 m_dwFlags |= CSF_EVENT_DB_LOCKED;
b8bad201 378 m_dwFlags &= ~CSF_EVENT_DB_MODIFIED;
b54b2b11
VK
379
380 msg.SetVariable(VID_RCC, RCC_SUCCESS);
381 SendMessage(&msg);
382 msg.DeleteAllVariables();
383
384 // Prepare data message
385 msg.SetCode(CMD_EVENT_DB_RECORD);
386 msg.SetId(dwRqId);
387
eafa21c7 388 hResult = DBAsyncSelect(g_hCoreDB, "SELECT event_id,name,severity,flags,message,description FROM events");
b54b2b11
VK
389 while(DBFetch(hResult))
390 {
391 msg.SetVariable(VID_EVENT_ID, DBGetFieldAsyncULong(hResult, 0));
392 msg.SetVariable(VID_NAME, DBGetFieldAsync(hResult, 1, szBuffer, 1024));
393 msg.SetVariable(VID_SEVERITY, DBGetFieldAsyncULong(hResult, 2));
394 msg.SetVariable(VID_FLAGS, DBGetFieldAsyncULong(hResult, 3));
395 msg.SetVariable(VID_MESSAGE, DBGetFieldAsync(hResult, 4, szBuffer, 1024));
396 msg.SetVariable(VID_DESCRIPTION, DBGetFieldAsync(hResult, 5, szBuffer, 1024));
397 SendMessage(&msg);
398 msg.DeleteAllVariables();
399 }
400 DBFreeAsyncResult(hResult);
3a5042fd
VK
401
402 // Send end-of-list indicator
403 msg.SetCode(CMD_EVENT_DB_EOF);
404 SendMessage(&msg);
b54b2b11
VK
405 }
406}
407
408
21e4b6f0
VK
409//
410// Send all objects to client
411//
412
e100f091 413void ClientSession::SendAllObjects(DWORD dwRqId)
21e4b6f0
VK
414{
415 DWORD i;
416 CSCPMessage msg;
417
e100f091
VK
418 // Send confirmation message
419 msg.SetCode(CMD_REQUEST_COMPLETED);
420 msg.SetId(dwRqId);
421 msg.SetVariable(VID_RCC, RCC_SUCCESS);
422 SendMessage(&msg);
423 msg.DeleteAllVariables();
424
53512272
VK
425 MutexLock(m_hMutexSendObjects, INFINITE);
426
21e4b6f0
VK
427 // Prepare message
428 msg.SetCode(CMD_OBJECT);
429
430 // Send objects, one per message
431 ObjectsGlobalLock();
432 for(i = 0; i < g_dwIdIndexSize; i++)
24156e90
VK
433 if (g_pIndexById[i].pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
434 {
435 g_pIndexById[i].pObject->CreateMessage(&msg);
436 SendMessage(&msg);
437 msg.DeleteAllVariables();
438 }
21e4b6f0
VK
439 ObjectsGlobalUnlock();
440
441 // Send end of list notification
442 msg.SetCode(CMD_OBJECT_LIST_END);
443 SendMessage(&msg);
53512272
VK
444
445 MutexUnlock(m_hMutexSendObjects);
21e4b6f0
VK
446}
447
448
449//
450// Send all events to client
451//
452
74a5aa17 453void ClientSession::SendAllEvents(DWORD dwRqId)
21e4b6f0 454{
21e4b6f0 455 CSCPMessage msg;
20177e8e 456 DB_ASYNC_RESULT hResult;
9c36ef66 457 NXC_EVENT event;
21e4b6f0 458
74a5aa17
VK
459 // Send confirmation message
460 msg.SetCode(CMD_REQUEST_COMPLETED);
461 msg.SetId(dwRqId);
462 msg.SetVariable(VID_RCC, RCC_SUCCESS);
463 SendMessage(&msg);
464 msg.DeleteAllVariables();
465
62f5857f
VK
466 MutexLock(m_hMutexSendEvents, INFINITE);
467
21e4b6f0 468 // Retrieve events from database
fa1d3757 469 hResult = DBAsyncSelect(g_hCoreDB, "SELECT event_id,timestamp,source,severity,message FROM event_log ORDER BY timestamp");
21e4b6f0
VK
470 if (hResult != NULL)
471 {
472 // Send events, one per message
20177e8e 473 while(DBFetch(hResult))
21e4b6f0 474 {
20177e8e
VK
475 event.dwEventId = htonl(DBGetFieldAsyncULong(hResult, 0));
476 event.dwTimeStamp = htonl(DBGetFieldAsyncULong(hResult, 1));
477 event.dwSourceId = htonl(DBGetFieldAsyncULong(hResult, 2));
478 event.dwSeverity = htonl(DBGetFieldAsyncULong(hResult, 3));
479 DBGetFieldAsync(hResult, 4, event.szMessage, MAX_EVENT_MSG_LENGTH);
74a5aa17 480 m_pSendQueue->Put(CreateRawCSCPMessage(CMD_EVENT, dwRqId, sizeof(NXC_EVENT), &event, NULL));
9c36ef66 481 }
20177e8e 482 DBFreeAsyncResult(hResult);
21e4b6f0
VK
483 }
484
485 // Send end of list notification
486 msg.SetCode(CMD_EVENT_LIST_END);
487 SendMessage(&msg);
62f5857f
VK
488
489 MutexUnlock(m_hMutexSendEvents);
21e4b6f0
VK
490}
491
492
493//
494// Send all configuration variables to client
495//
496
497void ClientSession::SendAllConfigVars(void)
498{
499 DWORD i, dwNumRecords;
500 CSCPMessage msg;
501 DB_RESULT hResult;
502
503 // Check user rights
504 if ((m_dwUserId != 0) && ((m_dwSystemAccess & SYSTEM_ACCESS_VIEW_CONFIG) == 0))
505 {
506 // Access denied
507 msg.SetCode(CMD_CONFIG_VARLIST_END);
a5f8dbb8 508 msg.SetVariable(VID_ERROR, (DWORD)1);
21e4b6f0
VK
509 SendMessage(&msg);
510 }
511 else
512 {
513 // Prepare message
514 msg.SetCode(CMD_CONFIG_VARIABLE);
515
516 // Retrieve configuration variables from database
517 hResult = DBSelect(g_hCoreDB, "SELECT name,value FROM config");
518 if (hResult != NULL)
519 {
520 // Send events, one per message
521 dwNumRecords = DBGetNumRows(hResult);
522 for(i = 0; i < dwNumRecords; i++)
523 {
a5f8dbb8
VK
524 msg.SetVariable(VID_NAME, DBGetField(hResult, i, 0));
525 msg.SetVariable(VID_VALUE, DBGetField(hResult, i, 1));
21e4b6f0
VK
526 SendMessage(&msg);
527 msg.DeleteAllVariables();
528 }
20177e8e 529 DBFreeResult(hResult);
21e4b6f0
VK
530 }
531
532 // Send end of list notification
533 msg.SetCode(CMD_CONFIG_VARLIST_END);
a5f8dbb8 534 msg.SetVariable(VID_ERROR, (DWORD)0);
21e4b6f0
VK
535 SendMessage(&msg);
536 }
537}
20177e8e
VK
538
539
540//
541// Close session forcibly
542//
543
544void ClientSession::Kill(void)
545{
546 // We shutdown socket connection, which will cause
547 // read thread to stop, and other threads will follow
548 shutdown(m_hSocket, 2);
549}
62f5857f
VK
550
551
552//
553// Handler for new events
554//
555
556void ClientSession::OnNewEvent(Event *pEvent)
557{
558 UPDATE_INFO *pUpdate;
559
984542f8
VK
560 if (m_iState == STATE_AUTHENTICATED)
561 {
562 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
563 pUpdate->dwCategory = INFO_CAT_EVENT;
564 pUpdate->pData = malloc(sizeof(NXC_EVENT));
565 pEvent->PrepareMessage((NXC_EVENT *)pUpdate->pData);
566 m_pUpdateQueue->Put(pUpdate);
567 }
62f5857f
VK
568}
569
570
571//
572// Handler for object changes
573//
574
53512272 575void ClientSession::OnObjectChange(NetObj *pObject)
62f5857f 576{
53512272
VK
577 UPDATE_INFO *pUpdate;
578
984542f8
VK
579 if (m_iState == STATE_AUTHENTICATED)
580 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
581 {
582 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
583 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
584 pUpdate->pData = pObject;
585 m_pUpdateQueue->Put(pUpdate);
586 pObject->IncRefCount();
587 }
62f5857f
VK
588}
589
590
591//
592// Update processing thread
593//
594
595void ClientSession::UpdateThread(void)
596{
597 UPDATE_INFO *pUpdate;
53512272 598 CSCPMessage msg;
62f5857f
VK
599
600 while(1)
601 {
602 pUpdate = (UPDATE_INFO *)m_pUpdateQueue->GetOrBlock();
603 if (pUpdate == INVALID_POINTER_VALUE) // Session termination indicator
604 break;
605
606 switch(pUpdate->dwCategory)
607 {
608 case INFO_CAT_EVENT:
609 MutexLock(m_hMutexSendEvents, INFINITE);
610 m_pSendQueue->Put(CreateRawCSCPMessage(CMD_EVENT, 0, sizeof(NXC_EVENT), pUpdate->pData, NULL));
611 MutexUnlock(m_hMutexSendEvents);
612 free(pUpdate->pData);
613 break;
53512272
VK
614 case INFO_CAT_OBJECT_CHANGE:
615 MutexLock(m_hMutexSendObjects, INFINITE);
616 msg.SetId(0);
617 msg.SetCode(CMD_OBJECT_UPDATE);
618 ((NetObj *)pUpdate->pData)->CreateMessage(&msg);
619 SendMessage(&msg);
620 MutexUnlock(m_hMutexSendObjects);
621 msg.DeleteAllVariables();
622 ((NetObj *)pUpdate->pData)->DecRefCount();
623 break;
62f5857f
VK
624 default:
625 break;
626 }
627
628 free(pUpdate);
629 }
630 ConditionSet(m_hCondUpdateThreadStopped);
631}
83f0529c
VK
632
633
634//
635// Send notification message to server
636//
637
638void ClientSession::Notify(DWORD dwCode)
639{
640 CSCPMessage msg;
641
642 msg.SetCode(CMD_NOTIFY);
643 msg.SetVariable(VID_NOTIFICATION_CODE, dwCode);
644 SendMessage(&msg);
645}
605d2931
VK
646
647
648//
649// Update event template
650//
651
652void ClientSession::SetEventInfo(CSCPMessage *pRequest)
653{
654 CSCPMessage msg;
655
656 // Prepare reply message
657 msg.SetCode(CMD_REQUEST_COMPLETED);
658 msg.SetId(pRequest->GetId());
659
660 // Check if we have event configuration database opened
661 if (!(m_dwFlags & CSF_EVENT_DB_LOCKED))
662 {
663 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
664 }
665 else
666 {
667 // Check access rights
668 if (CheckSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
669 {
670 char szQuery[4096], *pszName, *pszMessage, *pszDescription;
671 DWORD dwEventId;
672 BOOL bEventExist = FALSE;
673 DB_RESULT hResult;
674
675 // Check if event with specific id exists
676 dwEventId = pRequest->GetVariableLong(VID_EVENT_ID);
677 sprintf(szQuery, "SELECT event_id FROM events WHERE event_id=%ld", dwEventId);
678 hResult = DBSelect(g_hCoreDB, szQuery);
679 if (hResult != NULL)
680 {
681 if (DBGetNumRows(hResult) > 0)
682 bEventExist = TRUE;
683 DBFreeResult(hResult);
684 }
685
b8bad201 686 // Prepare and execute SQL query
eafa21c7
VK
687 pszName = pRequest->GetVariableStr(VID_NAME);
688 pszMessage = pRequest->GetVariableStr(VID_MESSAGE);
689 pszDescription = pRequest->GetVariableStr(VID_DESCRIPTION);
605d2931
VK
690 if (bEventExist)
691 sprintf(szQuery, "UPDATE events SET name='%s',severity=%ld,flags=%ld,message='%s',description='%s' WHERE event_id=%ld",
eafa21c7 692 pszName, pRequest->GetVariableLong(VID_SEVERITY), pRequest->GetVariableLong(VID_FLAGS),
b8bad201 693 pszMessage, pszDescription, dwEventId);
605d2931 694 else
b8bad201 695 sprintf(szQuery, "INSERT INTO events SET event_id,name,severity,flags,message,description VALUES (%ld,'%s',%ld,%ld,'%s','%s')",
eafa21c7
VK
696 dwEventId, pszName, pRequest->GetVariableLong(VID_SEVERITY),
697 pRequest->GetVariableLong(VID_FLAGS), pszMessage, pszDescription);
605d2931 698 if (DBQuery(g_hCoreDB, szQuery))
b8bad201 699 {
605d2931 700 msg.SetVariable(VID_RCC, RCC_SUCCESS);
b8bad201
VK
701 m_dwFlags |= CSF_EVENT_DB_MODIFIED;
702 }
605d2931 703 else
b8bad201 704 {
605d2931 705 msg.SetVariable(VID_RCC, RCC_DB_FAILURE);
b8bad201 706 }
605d2931
VK
707
708 MemFree(pszName);
709 MemFree(pszMessage);
710 MemFree(pszDescription);
711 }
712 else
713 {
714 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
715 }
716 }
717
718 // Send responce
719 SendMessage(&msg);
720}
24156e90
VK
721
722
723//
724// Modify object
725//
726
727void ClientSession::ModifyObject(CSCPMessage *pRequest)
728{
ff550544 729 DWORD dwObjectId, dwResult = RCC_SUCCESS;
24156e90
VK
730 NetObj *pObject;
731 CSCPMessage msg;
732
733 // Prepare reply message
734 msg.SetCode(CMD_REQUEST_COMPLETED);
735 msg.SetId(pRequest->GetId());
736
737 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
738 pObject = FindObjectById(dwObjectId);
739 if (pObject != NULL)
740 {
741 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
742 {
ff550544
VK
743 // If user attempts to change object's ACL, check
744 // if he has OBJECT_ACCESS_CONTROL permission
745 if (pRequest->IsVariableExist(VID_ACL_SIZE))
746 if (!pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_CONTROL))
747 dwResult = RCC_ACCESS_DENIED;
748
749 // If allowed, change object and set completion code
750 if (dwResult != RCC_ACCESS_DENIED)
751 dwResult = pObject->ModifyFromMessage(pRequest);
24156e90
VK
752 msg.SetVariable(VID_RCC, dwResult);
753 }
754 else
755 {
756 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
757 }
758 }
759 else
760 {
761 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
762 }
763
764 // Send responce
765 SendMessage(&msg);
766}
23a32988
VK
767
768
769//
770// Send users database to client
771//
772
773void ClientSession::SendUserDB(DWORD dwRqId)
774{
775 CSCPMessage msg;
2d5c8ac8 776 DWORD i;
23a32988
VK
777
778 // Prepare responce message
779 msg.SetCode(CMD_REQUEST_COMPLETED);
780 msg.SetId(dwRqId);
781 msg.SetVariable(VID_RCC, RCC_SUCCESS);
782 SendMessage(&msg);
783
784 // Send users
785 msg.SetCode(CMD_USER_DATA);
786 for(i = 0; i < g_dwNumUsers; i++)
787 {
2d5c8ac8 788 FillUserInfoMessage(&msg, &g_pUserList[i]);
23a32988
VK
789 SendMessage(&msg);
790 msg.DeleteAllVariables();
791 }
792
793 // Send groups
794 msg.SetCode(CMD_GROUP_DATA);
795 for(i = 0; i < g_dwNumGroups; i++)
796 {
2d5c8ac8 797 FillGroupInfoMessage(&msg, &g_pGroupList[i]);
23a32988
VK
798 SendMessage(&msg);
799 msg.DeleteAllVariables();
800 }
801
802 // Send end-of-database notification
803 msg.SetCode(CMD_USER_DB_EOF);
804 SendMessage(&msg);
805}
ff550544
VK
806
807
808//
809// Create new user
810//
811
812void ClientSession::CreateUser(CSCPMessage *pRequest)
813{
814 CSCPMessage msg;
815
816 // Prepare responce message
817 msg.SetCode(CMD_REQUEST_COMPLETED);
818 msg.SetId(pRequest->GetId());
819
820 // Check user rights
821 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
822 {
823 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
824 }
825 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
826 {
827 // User database have to be locked before any
828 // changes to user database can be made
829 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
830 }
831 else
832 {
984542f8 833 DWORD dwResult, dwUserId;
ff550544
VK
834 BOOL bIsGroup;
835 char szUserName[MAX_USER_NAME];
836
837 pRequest->GetVariableStr(VID_USER_NAME, szUserName, MAX_USER_NAME);
838 bIsGroup = pRequest->GetVariableShort(VID_IS_GROUP);
984542f8 839 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
ff550544 840 msg.SetVariable(VID_RCC, dwResult);
984542f8
VK
841 if (dwResult == RCC_SUCCESS)
842 msg.SetVariable(VID_USER_ID, dwUserId); // Send id of new user to client
ff550544
VK
843 }
844
845 // Send responce
846 SendMessage(&msg);
847}
848
849
850//
851// Update existing user's data
852//
853
854void ClientSession::UpdateUser(CSCPMessage *pRequest)
855{
612d43dc
VK
856 CSCPMessage msg;
857
858 // Prepare responce message
859 msg.SetCode(CMD_REQUEST_COMPLETED);
860 msg.SetId(pRequest->GetId());
861
862 // Check user rights
863 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
864 {
865 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
866 }
867 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
868 {
869 // User database have to be locked before any
870 // changes to user database can be made
871 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
872 }
873 else
874 {
86f31e8f 875 DWORD dwUserId, dwResult;
612d43dc
VK
876
877 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
878 if (dwUserId & GROUP_FLAG)
879 {
880 NMS_USER_GROUP group;
2d5c8ac8 881 DWORD i, dwId;
86f31e8f
VK
882
883 group.dwId = dwUserId;
2d5c8ac8
VK
884 pRequest->GetVariableStr(VID_USER_DESCRIPTION, group.szDescription, MAX_USER_DESCR);
885 pRequest->GetVariableStr(VID_USER_NAME, group.szName, MAX_USER_NAME);
886 group.wFlags = pRequest->GetVariableShort(VID_USER_FLAGS);
887 group.wSystemRights = pRequest->GetVariableShort(VID_USER_SYS_RIGHTS);
888 group.dwNumMembers = pRequest->GetVariableLong(VID_NUM_MEMBERS);
889 group.pMembers = (DWORD *)malloc(sizeof(DWORD) * group.dwNumMembers);
890 for(i = 0, dwId = VID_GROUP_MEMBER_BASE; i < group.dwNumMembers; i++, dwId++)
891 group.pMembers[i] = pRequest->GetVariableLong(dwId);
86f31e8f 892 dwResult = ModifyGroup(&group);
2d5c8ac8 893 safe_free(group.pMembers);
612d43dc
VK
894 }
895 else
896 {
897 NMS_USER user;
898
899 user.dwId = dwUserId;
900 pRequest->GetVariableStr(VID_USER_DESCRIPTION, user.szDescription, MAX_USER_DESCR);
901 pRequest->GetVariableStr(VID_USER_FULL_NAME, user.szFullName, MAX_USER_FULLNAME);
902 pRequest->GetVariableStr(VID_USER_NAME, user.szName, MAX_USER_NAME);
903 user.wFlags = pRequest->GetVariableShort(VID_USER_FLAGS);
86f31e8f
VK
904 user.wSystemRights = pRequest->GetVariableShort(VID_USER_SYS_RIGHTS);
905 dwResult = ModifyUser(&user);
612d43dc 906 }
86f31e8f 907 msg.SetVariable(VID_RCC, dwResult);
612d43dc
VK
908 }
909
910 // Send responce
911 SendMessage(&msg);
ff550544
VK
912}
913
914
915//
916// Delete user
917//
918
919void ClientSession::DeleteUser(CSCPMessage *pRequest)
920{
921 CSCPMessage msg;
922 DWORD dwUserId;
923
924 // Prepare responce message
925 msg.SetCode(CMD_REQUEST_COMPLETED);
926 msg.SetId(pRequest->GetId());
927
612d43dc
VK
928 // Check user rights
929 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
ff550544 930 {
612d43dc
VK
931 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
932 }
933 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
934 {
935 // User database have to be locked before any
936 // changes to user database can be made
937 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
938 }
939 else
940 {
941 // Get Id of user to be deleted
942 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
943
944 if (dwUserId != 0)
ff550544 945 {
612d43dc
VK
946 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
947 {
948 // Current user has no rights for user account management
949 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
950 }
951 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
952 {
953 // User database have to be locked before any
954 // changes to user database can be made
955 msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
956 }
957 else
958 {
959 DWORD dwResult;
960
961 dwResult = DeleteUserFromDB(dwUserId);
962 msg.SetVariable(VID_RCC, dwResult);
963 }
ff550544
VK
964 }
965 else
966 {
612d43dc
VK
967 // Nobody can delete system administrator account
968 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
ff550544
VK
969 }
970 }
ff550544
VK
971
972 // Send responce
973 SendMessage(&msg);
974}
975
976
977//
978// Lock/unlock user database
979//
980
981void ClientSession::LockUserDB(DWORD dwRqId, BOOL bLock)
982{
983 CSCPMessage msg;
984 char szBuffer[256];
985
986 // Prepare responce message
987 msg.SetCode(CMD_REQUEST_COMPLETED);
988 msg.SetId(dwRqId);
989
990 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
991 {
992 if (bLock)
993 {
994 if (!LockComponent(CID_USER_DB, m_dwIndex, m_szUserName, NULL, szBuffer))
995 {
996 msg.SetVariable(VID_RCC, RCC_COMPONENT_LOCKED);
997 msg.SetVariable(VID_LOCKED_BY, szBuffer);
998 }
999 else
1000 {
1001 m_dwFlags |= CSF_USER_DB_LOCKED;
1002 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1003 }
1004 }
1005 else
1006 {
1007 if (m_dwFlags & CSF_USER_DB_LOCKED)
1008 {
1009 UnlockComponent(CID_USER_DB);
1010 m_dwFlags &= ~CSF_USER_DB_LOCKED;
1011 }
1012 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1013 }
1014 }
1015 else
1016 {
1017 // Current user has no rights for user account management
1018 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1019 }
1020
1021 // Send responce
1022 SendMessage(&msg);
1023}
984542f8
VK
1024
1025
1026//
1027// Notify client on user database update
1028//
1029
1030void ClientSession::OnUserDBUpdate(int iCode, DWORD dwUserId, NMS_USER *pUser, NMS_USER_GROUP *pGroup)
1031{
1032 CSCPMessage msg;
1033
1034 if (m_iState == STATE_AUTHENTICATED)
1035 {
1036 msg.SetCode(CMD_USER_DB_UPDATE);
1037 msg.SetId(0);
1038 msg.SetVariable(VID_UPDATE_TYPE, (WORD)iCode);
984542f8
VK
1039
1040 switch(iCode)
1041 {
1042 case USER_DB_CREATE:
2d5c8ac8 1043 msg.SetVariable(VID_USER_ID, dwUserId);
984542f8 1044 if (dwUserId & GROUP_FLAG)
984542f8 1045 msg.SetVariable(VID_USER_NAME, pGroup->szName);
984542f8 1046 else
984542f8 1047 msg.SetVariable(VID_USER_NAME, pUser->szName);
2d5c8ac8
VK
1048 break;
1049 case USER_DB_MODIFY:
1050 if (dwUserId & GROUP_FLAG)
1051 FillGroupInfoMessage(&msg, pGroup);
1052 else
1053 FillUserInfoMessage(&msg, pUser);
984542f8
VK
1054 break;
1055 default:
2d5c8ac8 1056 msg.SetVariable(VID_USER_ID, dwUserId);
984542f8
VK
1057 break;
1058 }
1059
1060 SendMessage(&msg);
1061 }
1062}
017e1e13
VK
1063
1064
1065//
1066// Set user's password
1067//
1068
1069void ClientSession::SetPassword(CSCPMessage *pRequest)
1070{
1071 CSCPMessage msg;
1072 DWORD dwUserId;
1073
1074 // Prepare responce message
1075 msg.SetCode(CMD_REQUEST_COMPLETED);
1076 msg.SetId(pRequest->GetId());
1077
1078 dwUserId = pRequest->GetVariableLong(VID_USER_ID);
1079
1080 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
1081 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
1082 (dwUserId == m_dwUserId)) // User can change password for itself
1083 {
1084 DWORD dwResult;
1085 BYTE szPassword[SHA_DIGEST_LENGTH];
1086
1087 pRequest->GetVariableBinary(VID_PASSWORD, szPassword, SHA_DIGEST_LENGTH);
1088 dwResult = SetUserPassword(dwUserId, szPassword);
1089 msg.SetVariable(VID_RCC, dwResult);
1090 }
1091 else
1092 {
1093 // Current user has no rights to change password for specific user
1094 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1095 }
1096
1097 // Send responce
1098 SendMessage(&msg);
1099}
7257eb7d
VK
1100
1101
1102//
1103// Send node's DCIs to client and lock data collection settings
1104//
1105
1106void ClientSession::OpenNodeDCIList(CSCPMessage *pRequest)
1107{
1108 CSCPMessage msg;
3c55b85d
VK
1109 DWORD dwObjectId;
1110 NetObj *pObject;
1111 BOOL bSuccess = FALSE;
7257eb7d
VK
1112
1113 // Prepare responce message
1114 msg.SetCode(CMD_REQUEST_COMPLETED);
1115 msg.SetId(pRequest->GetId());
1116
3c55b85d
VK
1117 // Get node id and check object class and access rights
1118 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
1119 pObject = FindObjectById(dwObjectId);
1120 if (pObject != NULL)
1121 {
1122 if (pObject->Type() == OBJECT_NODE)
1123 {
1124 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
1125 {
1126 // Try to lock DCI list
1127 bSuccess = ((Node *)pObject)->LockDCIList(m_dwIndex);
1128 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_COMPONENT_LOCKED);
338493a0
VK
1129
1130 // Modify list of open nodes DCI lists
1131 if (bSuccess)
1132 {
1133 m_pOpenDCIList = (DWORD *)realloc(m_pOpenDCIList, sizeof(DWORD) * (m_dwOpenDCIListSize + 1));
1134 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
1135 m_dwOpenDCIListSize++;
1136 }
3c55b85d
VK
1137 }
1138 else
1139 {
1140 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1141 }
1142 }
1143 else
1144 {
1145 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
1146 }
1147 }
1148 else
1149 {
1150 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
1151 }
7257eb7d
VK
1152
1153 // Send responce
1154 SendMessage(&msg);
3c55b85d
VK
1155
1156 // If DCI list was successfully locked, send it to client
1157 if (bSuccess)
1158 ((Node *)pObject)->SendItemsToClient(this, pRequest->GetId());
7257eb7d
VK
1159}
1160
1161
1162//
1163// Unlock node's data collection settings
1164//
1165
1166void ClientSession::CloseNodeDCIList(CSCPMessage *pRequest)
1167{
1168 CSCPMessage msg;
3c55b85d
VK
1169 DWORD dwObjectId;
1170 NetObj *pObject;
7257eb7d
VK
1171
1172 // Prepare responce message
1173 msg.SetCode(CMD_REQUEST_COMPLETED);
1174 msg.SetId(pRequest->GetId());
1175
3c55b85d
VK
1176 // Get node id and check object class and access rights
1177 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
1178 pObject = FindObjectById(dwObjectId);
1179 if (pObject != NULL)
1180 {
1181 if (pObject->Type() == OBJECT_NODE)
1182 {
1183 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
1184 {
1185 BOOL bSuccess;
1186
1187 // Try to unlock DCI list
1188 bSuccess = ((Node *)pObject)->UnlockDCIList(m_dwIndex);
1189 msg.SetVariable(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
338493a0
VK
1190
1191 // Modify list of open nodes DCI lists
1192 if (bSuccess)
1193 {
1194 DWORD i;
1195
1196 for(i = 0; i < m_dwOpenDCIListSize; i++)
1197 if (m_pOpenDCIList[i] == dwObjectId)
1198 {
1199 m_dwOpenDCIListSize--;
1200 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1],
1201 sizeof(DWORD) * (m_dwOpenDCIListSize - i));
1202 break;
1203 }
1204 }
3c55b85d
VK
1205 }
1206 else
1207 {
1208 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1209 }
1210 }
1211 else
1212 {
1213 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
1214 }
1215 }
1216 else
1217 {
1218 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
1219 }
1220
7257eb7d
VK
1221 // Send responce
1222 SendMessage(&msg);
1223}
c1c39152
VK
1224
1225
1226//
1227// Change management status for the object
1228//
1229
1230void ClientSession::ChangeObjectMgmtStatus(CSCPMessage *pRequest)
1231{
1232 CSCPMessage msg;
1233 DWORD dwObjectId;
1234 NetObj *pObject;
1235
1236 // Prepare responce message
1237 msg.SetCode(CMD_REQUEST_COMPLETED);
1238 msg.SetId(pRequest->GetId());
1239
1240 // Get object id and check access rights
1241 dwObjectId = pRequest->GetVariableLong(VID_OBJECT_ID);
1242 pObject = FindObjectById(dwObjectId);
1243 if (pObject != NULL)
1244 {
1245 if (pObject->CheckAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
1246 {
1247 BOOL bIsManaged;
1248
1249 bIsManaged = (BOOL)pRequest->GetVariableShort(VID_MGMT_STATUS);
1250 pObject->SetMgmtStatus(bIsManaged);
1251 msg.SetVariable(VID_RCC, RCC_SUCCESS);
1252 }
1253 else
1254 {
1255 msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
1256 }
1257 }
1258 else
1259 {
1260 msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_ID);
1261 }
1262
1263 // Send responce
1264 SendMessage(&msg);
1265}