Minor changes
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
f77084bb
VK
1/*
2** NetXMS - Network Management System
3** Server Library
4** Copyright (C) 2003, 2004 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** $module: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
1ba9a162 25#include <stdarg.h>
f77084bb
VK
26
27
28//
29// Constants
30//
31
32#define RECEIVER_BUFFER_SIZE 262144
33
34
f9a4ab9a
VK
35//
36// Static data
37//
38
39#ifdef _WITH_ENCRYPTION
40static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
41#else
42static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
43#endif
44
45
46//
47// Set default encryption policy for agent communication
48//
49
50void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
51{
52#ifdef _WITH_ENCRYPTION
53 m_iDefaultEncryptionPolicy = iPolicy;
54#endif
55}
56
57
f77084bb
VK
58//
59// Receiver thread starter
60//
61
ccdbbb52 62THREAD_RESULT THREAD_CALL AgentConnection::ReceiverThreadStarter(void *pArg)
f77084bb
VK
63{
64 ((AgentConnection *)pArg)->ReceiverThread();
ccdbbb52 65 return THREAD_OK;
f77084bb
VK
66}
67
68
69//
70// Default constructor for AgentConnection - normally shouldn't be used
71//
72
73AgentConnection::AgentConnection()
74{
75 m_dwAddr = inet_addr("127.0.0.1");
76 m_wPort = AGENT_LISTEN_PORT;
77 m_iAuthMethod = AUTH_NONE;
78 m_szSecret[0] = 0;
79 m_hSocket = -1;
80 m_tLastCommandTime = 0;
81 m_dwNumDataLines = 0;
82 m_ppDataLines = NULL;
83 m_pMsgWaitQueue = new MsgWaitQueue;
d1d0b3be 84 m_dwRequestId = 1;
f77084bb 85 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
1c62be36 86 m_bIsConnected = FALSE;
38e832d6 87 m_mutexDataLock = MutexCreate();
ccdbbb52 88 m_hReceiverThread = INVALID_THREAD_HANDLE;
e44ac467 89 m_pCtx = NULL;
f9a4ab9a 90 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
f77084bb
VK
91}
92
93
94//
95// Normal constructor for AgentConnection
96//
97
268774a0 98AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort, int iAuthMethod, TCHAR *pszSecret)
f77084bb
VK
99{
100 m_dwAddr = dwAddr;
101 m_wPort = wPort;
102 m_iAuthMethod = iAuthMethod;
268774a0
VK
103 if (pszSecret != NULL)
104 {
105#ifdef UNICODE
106 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
107 pszSecret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
108#else
c81979bc 109 nx_strncpy(m_szSecret, pszSecret, MAX_SECRET_LENGTH);
268774a0
VK
110#endif
111 }
f77084bb 112 else
268774a0 113 {
f77084bb 114 m_szSecret[0] = 0;
268774a0 115 }
f77084bb
VK
116 m_hSocket = -1;
117 m_tLastCommandTime = 0;
118 m_dwNumDataLines = 0;
119 m_ppDataLines = NULL;
120 m_pMsgWaitQueue = new MsgWaitQueue;
d1d0b3be 121 m_dwRequestId = 1;
f77084bb 122 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
1c62be36 123 m_bIsConnected = FALSE;
38e832d6 124 m_mutexDataLock = MutexCreate();
ccdbbb52 125 m_hReceiverThread = INVALID_THREAD_HANDLE;
e44ac467 126 m_pCtx = NULL;
f9a4ab9a 127 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
f77084bb
VK
128}
129
130
131//
132// Destructor
133//
134
135AgentConnection::~AgentConnection()
136{
1a60d114
VK
137 // Disconnect from peer
138 Disconnect();
38e832d6
VK
139
140 // Wait for receiver thread termination
ccdbbb52 141 ThreadJoin(m_hReceiverThread);
ba8681ba
VK
142 if (m_hSocket != -1)
143 closesocket(m_hSocket);
38e832d6
VK
144
145 Lock();
f77084bb 146 DestroyResultData();
38e832d6
VK
147 Unlock();
148
f77084bb 149 delete m_pMsgWaitQueue;
e44ac467 150 DestroyEncryptionContext(m_pCtx);
38e832d6
VK
151
152 MutexDestroy(m_mutexDataLock);
f77084bb
VK
153}
154
155
156//
059f6632
VK
157// Print message. This function is virtual and can be overrided in
158// derived classes. Default implementation will print message to stdout.
f77084bb
VK
159//
160
268774a0 161void AgentConnection::PrintMsg(TCHAR *pszFormat, ...)
f77084bb
VK
162{
163 va_list args;
164
165 va_start(args, pszFormat);
268774a0 166 _vtprintf(pszFormat, args);
f77084bb 167 va_end(args);
268774a0 168 _tprintf(_T("\n"));
f77084bb
VK
169}
170
171
172//
173// Receiver thread
174//
175
176void AgentConnection::ReceiverThread(void)
177{
178 CSCPMessage *pMsg;
179 CSCP_MESSAGE *pRawMsg;
180 CSCP_BUFFER *pMsgBuffer;
e44ac467 181 BYTE *pDecryptionBuffer = NULL;
f77084bb 182 int iErr;
268774a0 183 TCHAR szBuffer[128];
f77084bb
VK
184
185 // Initialize raw message receiving function
9d72bde1 186 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
e44ac467 187 RecvCSCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL);
f77084bb
VK
188
189 // Allocate space for raw message
9d72bde1 190 pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
e44ac467
VK
191#ifdef _WITH_ENCRYPTION
192 pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
193#endif
f77084bb
VK
194
195 // Message receiving loop
196 while(1)
197 {
198 // Receive raw message
e44ac467 199 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
1ba3c17a 200 &m_pCtx, pDecryptionBuffer)) <= 0)
f77084bb
VK
201 break;
202
203 // Check if we get too large message
204 if (iErr == 1)
205 {
0212dc5a 206 PrintMsg(_T("Received too large message %s (%d bytes)"),
f77084bb
VK
207 CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
208 ntohl(pRawMsg->dwSize));
209 continue;
210 }
211
e44ac467
VK
212 // Check if we are unable to decrypt message
213 if (iErr == 2)
214 {
215 PrintMsg(_T("Unable to decrypt received message"));
216 continue;
217 }
218
f77084bb
VK
219 // Check that actual received packet size is equal to encoded in packet
220 if ((int)ntohl(pRawMsg->dwSize) != iErr)
221 {
268774a0 222 PrintMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), iErr);
f77084bb
VK
223 continue; // Bad packet, wait for next
224 }
225
226 // Create message object from raw message
227 pMsg = new CSCPMessage(pRawMsg);
228 if (pMsg->GetCode() == CMD_TRAP)
229 {
901c96c7 230 OnTrap(pMsg);
f77084bb
VK
231 delete pMsg;
232 }
233 else
234 {
235 m_pMsgWaitQueue->Put(pMsg);
236 }
237 }
238
1c62be36 239 // Close socket and mark connection as disconnected
0a0bd13b 240 Lock();
ba8681ba
VK
241 if (iErr == 0)
242 shutdown(m_hSocket, SHUT_RDWR);
243 closesocket(m_hSocket);
244 m_hSocket = -1;
e44ac467
VK
245 DestroyEncryptionContext(m_pCtx);
246 m_pCtx = NULL;
ba8681ba 247 m_bIsConnected = FALSE;
966f3ac2 248 Unlock();
1c62be36 249
9d72bde1
VK
250 free(pRawMsg);
251 free(pMsgBuffer);
3332c970
VK
252#ifdef _WITH_ENCRYPTION
253 free(pDecryptionBuffer);
254#endif
f77084bb
VK
255}
256
257
258//
259// Connect to agent
260//
261
1ba3c17a 262BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
f77084bb
VK
263{
264 struct sockaddr_in sa;
268774a0 265 TCHAR szBuffer[256];
f9a4ab9a
VK
266 BOOL bSuccess = FALSE, bForceEncryption = FALSE;
267 DWORD dwError = 0;
f77084bb 268
1ba3c17a
VK
269 if (pdwError != NULL)
270 *pdwError = ERR_INTERNAL_ERROR;
271
1c62be36 272 // Check if already connected
ba8681ba 273 if (m_bIsConnected)
1c62be36
VK
274 return FALSE;
275
ccdbbb52
VK
276 // Wait for receiver thread from previous connection, if any
277 ThreadJoin(m_hReceiverThread);
278 m_hReceiverThread = INVALID_THREAD_HANDLE;
279
ba8681ba
VK
280 // Check if we need to close existing socket
281 if (m_hSocket != -1)
282 closesocket(m_hSocket);
283
f77084bb
VK
284 // Create socket
285 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
286 if (m_hSocket == -1)
287 {
268774a0 288 PrintMsg(_T("Call to socket() failed"));
f77084bb
VK
289 goto connect_cleanup;
290 }
291
292 // Fill in address structure
293 memset(&sa, 0, sizeof(sa));
294 sa.sin_addr.s_addr = m_dwAddr;
295 sa.sin_family = AF_INET;
296 sa.sin_port = htons(m_wPort);
297
298 // Connect to server
299 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
300 {
301 if (bVerbose)
205acaf4 302 PrintMsg(_T("Cannot establish connection with agent %s"), IpToStr(ntohl(m_dwAddr), szBuffer));
1ba3c17a 303 dwError = ERR_CONNECT_FAILED;
f77084bb
VK
304 goto connect_cleanup;
305 }
306
307 // Start receiver thread
ccdbbb52 308 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
f77084bb 309
e44ac467 310 // Setup encryption
f9a4ab9a
VK
311setup_encryption:
312 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
313 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
314 (bForceEncryption)) // Agent require encryption
e44ac467 315 {
f9a4ab9a
VK
316 if (pServerKey != NULL)
317 {
318 dwError = SetupEncryption(pServerKey);
319 if ((dwError != ERR_SUCCESS) &&
320 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
321 goto connect_cleanup;
322 }
323 else
324 {
325 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
326 {
327 dwError = ERR_ENCRYPTION_REQUIRED;
328 goto connect_cleanup;
329 }
330 }
e44ac467
VK
331 }
332
f77084bb 333 // Authenticate itself to agent
d1d0b3be 334 if ((dwError = Authenticate()) != ERR_SUCCESS)
f77084bb 335 {
f9a4ab9a
VK
336 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
337 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
338 {
339 bForceEncryption = TRUE;
340 goto setup_encryption;
341 }
205acaf4 342 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be
VK
343 AgentErrorCodeToText(dwError));
344 goto connect_cleanup;
f77084bb
VK
345 }
346
347 // Test connectivity
d1d0b3be 348 if ((dwError = Nop()) != ERR_SUCCESS)
f77084bb 349 {
f9a4ab9a
VK
350 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
351 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
352 {
353 bForceEncryption = TRUE;
354 goto setup_encryption;
355 }
205acaf4 356 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be 357 AgentErrorCodeToText(dwError));
f77084bb
VK
358 goto connect_cleanup;
359 }
360
361 bSuccess = TRUE;
1ba3c17a 362 dwError = ERR_SUCCESS;
f77084bb
VK
363
364connect_cleanup:
365 if (!bSuccess)
366 {
0a0bd13b 367 Lock();
f77084bb 368 if (m_hSocket != -1)
56684b7a 369 shutdown(m_hSocket, SHUT_RDWR);
0a0bd13b 370 Unlock();
ba8681ba
VK
371 ThreadJoin(m_hReceiverThread);
372 m_hReceiverThread = INVALID_THREAD_HANDLE;
373
0a0bd13b 374 Lock();
ba8681ba 375 if (m_hSocket != -1)
0a0bd13b 376 {
f77084bb 377 closesocket(m_hSocket);
0a0bd13b
VK
378 m_hSocket = -1;
379 }
e44ac467
VK
380
381 DestroyEncryptionContext(m_pCtx);
382 m_pCtx = NULL;
966f3ac2
VK
383
384 Unlock();
f77084bb 385 }
1c62be36 386 m_bIsConnected = bSuccess;
1ba3c17a
VK
387 if (pdwError != NULL)
388 *pdwError = dwError;
f77084bb
VK
389 return bSuccess;
390}
391
392
393//
394// Disconnect from agent
395//
396
397void AgentConnection::Disconnect(void)
398{
1c62be36 399 Lock();
f77084bb
VK
400 if (m_hSocket != -1)
401 {
ba8681ba 402 shutdown(m_hSocket, SHUT_RDWR);
f77084bb
VK
403 }
404 DestroyResultData();
1c62be36
VK
405 m_bIsConnected = FALSE;
406 Unlock();
f77084bb
VK
407}
408
409
410//
411// Destroy command execuion results data
412//
413
414void AgentConnection::DestroyResultData(void)
415{
416 DWORD i;
417
418 if (m_ppDataLines != NULL)
419 {
420 for(i = 0; i < m_dwNumDataLines; i++)
421 if (m_ppDataLines[i] != NULL)
9d72bde1
VK
422 free(m_ppDataLines[i]);
423 free(m_ppDataLines);
f77084bb
VK
424 m_ppDataLines = NULL;
425 }
426 m_dwNumDataLines = 0;
427}
428
429
430//
431// Get interface list from agent
432//
433
434INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
435{
1c62be36 436 INTERFACE_LIST *pIfList = NULL;
66485623 437 DWORD i, dwBits;
268774a0 438 TCHAR *pChar, *pBuf;
1c62be36 439
268774a0 440 if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
1c62be36 441 {
9d72bde1 442 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
1c62be36 443 pIfList->iNumEntries = m_dwNumDataLines;
9d72bde1 444 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * m_dwNumDataLines);
1c62be36
VK
445 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * m_dwNumDataLines);
446 for(i = 0; i < m_dwNumDataLines; i++)
447 {
448 pBuf = m_ppDataLines[i];
449
450 // Index
268774a0 451 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
452 if (pChar != NULL)
453 {
454 *pChar = 0;
268774a0 455 pIfList->pInterfaces[i].dwIndex = _tcstoul(pBuf, NULL, 10);
1c62be36
VK
456 pBuf = pChar + 1;
457 }
458
459 // Address and mask
268774a0 460 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
461 if (pChar != NULL)
462 {
268774a0 463 TCHAR *pSlash;
1c62be36
VK
464
465 *pChar = 0;
268774a0 466 pSlash = _tcschr(pBuf, _T('/'));
1c62be36
VK
467 if (pSlash != NULL)
468 {
469 *pSlash = 0;
470 pSlash++;
471 }
472 else // Just a paranoia protection, should'n happen if agent working correctly
473 {
268774a0 474 pSlash = _T("24");
1c62be36 475 }
205acaf4 476 pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
66485623
VK
477 dwBits = _tcstoul(pSlash, NULL, 10);
478 pIfList->pInterfaces[i].dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1c62be36
VK
479 pBuf = pChar + 1;
480 }
481
482 // Interface type
268774a0 483 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
484 if (pChar != NULL)
485 {
486 *pChar = 0;
205acaf4 487 pIfList->pInterfaces[i].dwType = _tcstoul(pBuf, NULL, 10);
1c62be36 488 pBuf = pChar + 1;
b50f1100
VK
489 }
490
491 // MAC address
492 pChar = _tcschr(pBuf, ' ');
493 if (pChar != NULL)
494 {
495 *pChar = 0;
496 StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
497 pBuf = pChar + 1;
1c62be36
VK
498 }
499
500 // Name
c81979bc 501 nx_strncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
1c62be36
VK
502 }
503
9d72bde1 504 Lock();
1c62be36 505 DestroyResultData();
9d72bde1 506 Unlock();
1c62be36
VK
507 }
508
509 return pIfList;
f77084bb
VK
510}
511
512
513//
514// Get parameter value
515//
516
268774a0 517DWORD AgentConnection::GetParameter(TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
f77084bb 518{
1a17feb0 519 CSCPMessage msg, *pResponse;
f77084bb
VK
520 DWORD dwRqId, dwRetCode;
521
1c62be36 522 if (m_bIsConnected)
f77084bb 523 {
1c62be36
VK
524 dwRqId = m_dwRequestId++;
525 msg.SetCode(CMD_GET_PARAMETER);
526 msg.SetId(dwRqId);
527 msg.SetVariable(VID_PARAMETER, pszParam);
528 if (SendMessage(&msg))
f77084bb 529 {
1a17feb0
VK
530 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
531 if (pResponse != NULL)
1c62be36 532 {
1a17feb0 533 dwRetCode = pResponse->GetVariableLong(VID_RCC);
1c62be36 534 if (dwRetCode == ERR_SUCCESS)
1a17feb0
VK
535 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
536 delete pResponse;
1c62be36
VK
537 }
538 else
539 {
540 dwRetCode = ERR_REQUEST_TIMEOUT;
541 }
f77084bb
VK
542 }
543 else
544 {
1c62be36 545 dwRetCode = ERR_CONNECTION_BROKEN;
f77084bb
VK
546 }
547 }
548 else
549 {
1c62be36 550 dwRetCode = ERR_NOT_CONNECTED;
f77084bb
VK
551 }
552
553 return dwRetCode;
554}
555
556
557//
558// Get ARP cache
559//
560
561ARP_CACHE *AgentConnection::GetArpCache(void)
562{
1c62be36 563 ARP_CACHE *pArpCache = NULL;
268774a0 564 TCHAR szByte[4], *pBuf, *pChar;
1c62be36
VK
565 DWORD i, j;
566
268774a0 567 if (GetList(_T("Net.ArpCache")) == ERR_SUCCESS)
1c62be36
VK
568 {
569 // Create empty structure
9d72bde1 570 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
1c62be36 571 pArpCache->dwNumEntries = m_dwNumDataLines;
9d72bde1 572 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
1c62be36
VK
573 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
574
575 szByte[2] = 0;
576
577 // Parse data lines
578 // Each line has form of XXXXXXXXXXXX a.b.c.d
579 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
580 // and a.b.c.d is an IP address in decimal dotted notation
581 for(i = 0; i < m_dwNumDataLines; i++)
582 {
583 pBuf = m_ppDataLines[i];
268774a0 584 if (_tcslen(pBuf) < 20) // Invalid line
1c62be36
VK
585 continue;
586
587 // MAC address
588 for(j = 0; j < 6; j++)
589 {
268774a0
VK
590 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
591 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
1c62be36
VK
592 pBuf+=2;
593 }
594
595 // IP address
596 while(*pBuf == ' ')
597 pBuf++;
268774a0 598 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
599 if (pChar != NULL)
600 *pChar = 0;
205acaf4 601 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
1c62be36
VK
602
603 // Interface index
604 if (pChar != NULL)
268774a0 605 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
1c62be36
VK
606 }
607
608 DestroyResultData();
609 }
610 return pArpCache;
f77084bb
VK
611}
612
613
614//
615// Send dummy command to agent (can be used for keepalive)
616//
617
618DWORD AgentConnection::Nop(void)
619{
620 CSCPMessage msg;
621 DWORD dwRqId;
622
623 dwRqId = m_dwRequestId++;
624 msg.SetCode(CMD_KEEPALIVE);
625 msg.SetId(dwRqId);
626 if (SendMessage(&msg))
627 return WaitForRCC(dwRqId, m_dwCommandTimeout);
628 else
629 return ERR_CONNECTION_BROKEN;
630}
631
632
633//
634// Wait for request completion code
635//
636
637DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
638{
639 CSCPMessage *pMsg;
640 DWORD dwRetCode;
641
642 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
643 if (pMsg != NULL)
644 {
645 dwRetCode = pMsg->GetVariableLong(VID_RCC);
646 delete pMsg;
647 }
648 else
649 {
650 dwRetCode = ERR_REQUEST_TIMEOUT;
651 }
652 return dwRetCode;
653}
654
655
656//
657// Send message to agent
658//
659
660BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
661{
662 CSCP_MESSAGE *pRawMsg;
e44ac467 663 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
f77084bb
VK
664 BOOL bResult;
665
666 pRawMsg = pMsg->CreateMessage();
e44ac467
VK
667 if (m_pCtx != NULL)
668 {
669 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
670 if (pEnMsg != NULL)
671 {
672 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
673 free(pEnMsg);
674 }
675 else
676 {
677 bResult = FALSE;
678 }
679 }
680 else
681 {
682 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
683 }
9d72bde1 684 free(pRawMsg);
f77084bb
VK
685 return bResult;
686}
901c96c7
VK
687
688
689//
690// Trap handler. Should be overriden in derived classes to implement
691// actual trap processing. Default implementation do nothing.
692//
693
694void AgentConnection::OnTrap(CSCPMessage *pMsg)
695{
696}
697
698
699//
700// Get list of values
701//
702
268774a0 703DWORD AgentConnection::GetList(TCHAR *pszParam)
901c96c7 704{
1a17feb0 705 CSCPMessage msg, *pResponse;
901c96c7
VK
706 DWORD i, dwRqId, dwRetCode;
707
1c62be36 708 if (m_bIsConnected)
901c96c7 709 {
1c62be36
VK
710 DestroyResultData();
711 dwRqId = m_dwRequestId++;
712 msg.SetCode(CMD_GET_LIST);
713 msg.SetId(dwRqId);
714 msg.SetVariable(VID_PARAMETER, pszParam);
715 if (SendMessage(&msg))
901c96c7 716 {
1a17feb0
VK
717 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
718 if (pResponse != NULL)
1c62be36 719 {
1a17feb0 720 dwRetCode = pResponse->GetVariableLong(VID_RCC);
1c62be36
VK
721 if (dwRetCode == ERR_SUCCESS)
722 {
1a17feb0 723 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
268774a0 724 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
1c62be36 725 for(i = 0; i < m_dwNumDataLines; i++)
1a17feb0 726 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
1c62be36 727 }
1a17feb0 728 delete pResponse;
1c62be36
VK
729 }
730 else
901c96c7 731 {
1c62be36 732 dwRetCode = ERR_REQUEST_TIMEOUT;
901c96c7 733 }
901c96c7
VK
734 }
735 else
736 {
1c62be36 737 dwRetCode = ERR_CONNECTION_BROKEN;
901c96c7
VK
738 }
739 }
740 else
741 {
1c62be36 742 dwRetCode = ERR_NOT_CONNECTED;
901c96c7
VK
743 }
744
745 return dwRetCode;
746}
d1d0b3be
VK
747
748
749//
750// Authenticate to agent
751//
752
753DWORD AgentConnection::Authenticate(void)
754{
755 CSCPMessage msg;
756 DWORD dwRqId;
757 BYTE hash[32];
268774a0
VK
758#ifdef UNICODE
759 WCHAR szBuffer[MAX_SECRET_LENGTH];
760#endif
d1d0b3be
VK
761
762 if (m_iAuthMethod == AUTH_NONE)
763 return ERR_SUCCESS; // No authentication required
764
765 dwRqId = m_dwRequestId++;
766 msg.SetCode(CMD_AUTHENTICATE);
767 msg.SetId(dwRqId);
768 msg.SetVariable(VID_AUTH_METHOD, (WORD)m_iAuthMethod);
769 switch(m_iAuthMethod)
770 {
771 case AUTH_PLAINTEXT:
268774a0
VK
772#ifdef UNICODE
773 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szSecret, -1, szBuffer, MAX_SECRET_LENGTH);
774 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
775#else
d1d0b3be 776 msg.SetVariable(VID_SHARED_SECRET, m_szSecret);
268774a0 777#endif
d1d0b3be
VK
778 break;
779 case AUTH_MD5_HASH:
780 CalculateMD5Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
781 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
782 break;
783 case AUTH_SHA1_HASH:
784 CalculateSHA1Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
785 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
786 break;
787 default:
788 break;
789 }
790 if (SendMessage(&msg))
791 return WaitForRCC(dwRqId, m_dwCommandTimeout);
792 else
793 return ERR_CONNECTION_BROKEN;
794}
3c774461
VK
795
796
797//
798// Execute action on agent
799//
800
268774a0 801DWORD AgentConnection::ExecAction(TCHAR *pszAction, int argc, TCHAR **argv)
3c774461
VK
802{
803 CSCPMessage msg;
804 DWORD dwRqId;
805 int i;
806
1c62be36
VK
807 if (!m_bIsConnected)
808 return ERR_NOT_CONNECTED;
809
3c774461
VK
810 dwRqId = m_dwRequestId++;
811 msg.SetCode(CMD_ACTION);
812 msg.SetId(dwRqId);
813 msg.SetVariable(VID_ACTION_NAME, pszAction);
814 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
815 for(i = 0; i < argc; i++)
816 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
817
818 if (SendMessage(&msg))
819 return WaitForRCC(dwRqId, m_dwCommandTimeout);
820 else
821 return ERR_CONNECTION_BROKEN;
822}
d096bcdd
VK
823
824
825//
826// Upload file to agent
827//
828
829DWORD AgentConnection::UploadFile(TCHAR *pszFile)
830{
831 DWORD dwRqId, dwResult;
832 CSCPMessage msg;
833 int i;
834
835 if (!m_bIsConnected)
836 return ERR_NOT_CONNECTED;
837
838 dwRqId = m_dwRequestId++;
839
840 msg.SetCode(CMD_TRANSFER_FILE);
841 msg.SetId(dwRqId);
842 for(i = _tcslen(pszFile) - 1;
843 (i >= 0) && (pszFile[i] != '\\') && (pszFile[i] != '/'); i--);
844 msg.SetVariable(VID_FILE_NAME, &pszFile[i + 1]);
845
846 if (SendMessage(&msg))
847 {
848 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
849 }
850 else
851 {
852 dwResult = ERR_CONNECTION_BROKEN;
853 }
854
855 if (dwResult == ERR_SUCCESS)
856 {
1ba3c17a 857 if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile, m_pCtx))
d096bcdd
VK
858 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
859 else
860 dwResult = ERR_IO_FAILURE;
861 }
862
863 return dwResult;
864}
e925a5fc
VK
865
866
867//
868// Send upgrade command
869//
870
871DWORD AgentConnection::StartUpgrade(TCHAR *pszPkgName)
872{
873 DWORD dwRqId, dwResult;
874 CSCPMessage msg;
875 int i;
876
877 if (!m_bIsConnected)
878 return ERR_NOT_CONNECTED;
879
880 dwRqId = m_dwRequestId++;
881
882 msg.SetCode(CMD_UPGRADE_AGENT);
883 msg.SetId(dwRqId);
884 for(i = _tcslen(pszPkgName) - 1;
885 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
886 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
887
888 if (SendMessage(&msg))
889 {
890 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
891 }
892 else
893 {
894 dwResult = ERR_CONNECTION_BROKEN;
895 }
896
897 return dwResult;
898}
3f0ca036
VK
899
900
901//
902// Check status of network service via agent
903//
904
905DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
906 WORD wPort, WORD wProto,
1a17feb0 907 TCHAR *pszRequest, TCHAR *pszResponse)
3f0ca036
VK
908{
909 DWORD dwRqId, dwResult;
1a17feb0 910 CSCPMessage msg, *pResponse;
3f0ca036
VK
911 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
912
913 if (!m_bIsConnected)
914 return ERR_NOT_CONNECTED;
915
916 dwRqId = m_dwRequestId++;
917
918 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
919 msg.SetId(dwRqId);
920 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
921 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
922 msg.SetVariable(VID_IP_PORT,
923 (wPort != 0) ? wPort :
25376fc7 924 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
3f0ca036 925 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
25376fc7 926 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
3f0ca036 927 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1a17feb0 928 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
3f0ca036
VK
929
930 if (SendMessage(&msg))
931 {
932 // Wait up to 90 seconds for results
1a17feb0
VK
933 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
934 if (pResponse != NULL)
3f0ca036 935 {
1a17feb0 936 dwResult = pResponse->GetVariableLong(VID_RCC);
3f0ca036
VK
937 if (dwResult == ERR_SUCCESS)
938 {
1a17feb0 939 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
3f0ca036 940 }
1a17feb0 941 delete pResponse;
3f0ca036
VK
942 }
943 else
944 {
945 dwResult = ERR_REQUEST_TIMEOUT;
946 }
947 }
948 else
949 {
950 dwResult = ERR_CONNECTION_BROKEN;
951 }
952
953 return dwResult;
954}
125c0e81
VK
955
956
957//
958// Get list of supported parameters from subagent
959//
960
961DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
962{
963 DWORD i, dwId, dwRqId, dwResult;
1a17feb0 964 CSCPMessage msg, *pResponse;
125c0e81 965
125c0e81
VK
966 *pdwNumParams = 0;
967 *ppParamList = NULL;
968
cb27dff1
VK
969 if (!m_bIsConnected)
970 return ERR_NOT_CONNECTED;
971
125c0e81
VK
972 dwRqId = m_dwRequestId++;
973
974 msg.SetCode(CMD_GET_PARAMETER_LIST);
975 msg.SetId(dwRqId);
976
977 if (SendMessage(&msg))
978 {
1a17feb0
VK
979 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
980 if (pResponse != NULL)
125c0e81 981 {
1a17feb0 982 dwResult = pResponse->GetVariableLong(VID_RCC);
125c0e81
VK
983 if (dwResult == ERR_SUCCESS)
984 {
1a17feb0 985 *pdwNumParams = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
125c0e81
VK
986 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * *pdwNumParams);
987 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
988 {
1a17feb0
VK
989 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
990 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
991 (*ppParamList)[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
125c0e81
VK
992 }
993 }
1a17feb0 994 delete pResponse;
125c0e81
VK
995 }
996 else
997 {
998 dwResult = ERR_REQUEST_TIMEOUT;
999 }
1000 }
1001 else
1002 {
1003 dwResult = ERR_CONNECTION_BROKEN;
1004 }
1005
1006 return dwResult;
1007}
e44ac467
VK
1008
1009
1010//
1011// Setup encryption
1012//
1013
1014DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
1015{
1016#ifdef _WITH_ENCRYPTION
1017 CSCPMessage msg, *pResp;
1018 DWORD dwRqId, dwError, dwResult;
1019
1020 dwRqId = m_dwRequestId++;
1021
1022 PrepareKeyRequestMsg(&msg, pServerKey);
1023 msg.SetId(dwRqId);
1024 if (SendMessage(&msg))
1025 {
1026 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
1027 if (pResp != NULL)
1028 {
1029 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey);
1030 switch(dwResult)
1031 {
1032 case RCC_SUCCESS:
1033 dwError = ERR_SUCCESS;
1034 break;
1035 case RCC_NO_CIPHERS:
1036 dwError = ERR_NO_CIPHERS;
1037 break;
1038 case RCC_INVALID_PUBLIC_KEY:
1039 dwError = ERR_INVALID_PUBLIC_KEY;
1040 break;
1041 case RCC_INVALID_SESSION_KEY:
1042 dwError = ERR_INVALID_SESSION_KEY;
1043 break;
1044 default:
1045 dwError = ERR_INTERNAL_ERROR;
1046 break;
1047 }
1048 }
1049 else
1050 {
1051 dwError = ERR_REQUEST_TIMEOUT;
1052 }
1053 }
1054 else
1055 {
1056 dwError = ERR_CONNECTION_BROKEN;
1057 }
1058
1059 return dwError;
1060#else
1061 return ERR_NOT_IMPLEMENTED;
1062#endif
1063}
cb27dff1
VK
1064
1065
1066//
1067// Get configuration file from agent
1068//
1069
1070DWORD AgentConnection::GetConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
1071{
1072 DWORD i, dwRqId, dwResult;
1a17feb0 1073 CSCPMessage msg, *pResponse;
cb27dff1
VK
1074#ifdef UNICODE
1075 BYTE *pBuffer;
1076#endif
1077
1078 *ppszConfig = NULL;
1079 *pdwSize = 0;
1080
1081 if (!m_bIsConnected)
1082 return ERR_NOT_CONNECTED;
1083
1084 dwRqId = m_dwRequestId++;
1085
1086 msg.SetCode(CMD_GET_AGENT_CONFIG);
1087 msg.SetId(dwRqId);
1088
1089 if (SendMessage(&msg))
1090 {
1a17feb0
VK
1091 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1092 if (pResponse != NULL)
cb27dff1 1093 {
1a17feb0 1094 dwResult = pResponse->GetVariableLong(VID_RCC);
cb27dff1
VK
1095 if (dwResult == ERR_SUCCESS)
1096 {
1a17feb0 1097 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
cb27dff1
VK
1098 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1099#ifdef UNICODE
1100 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1a17feb0 1101 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
cb27dff1
VK
1102 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pBuffer, *pdwSize, *ppszConfig, *pdwSize);
1103 free(pBuffer);
1104#else
1a17feb0 1105 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
cb27dff1
VK
1106#endif
1107 (*ppszConfig)[*pdwSize] = 0;
1108
1109 // We expect text file, so replace all non-printable characters with spaces
1110 for(i = 0; i < *pdwSize; i++)
1111 if (((*ppszConfig)[i] < _T(' ')) &&
1112 ((*ppszConfig)[i] != _T('\t')) &&
1113 ((*ppszConfig)[i] != _T('\r')) &&
1114 ((*ppszConfig)[i] != _T('\n')))
1115 (*ppszConfig)[i] = _T(' ');
1116 }
1a17feb0 1117 delete pResponse;
cb27dff1
VK
1118 }
1119 else
1120 {
1121 dwResult = ERR_REQUEST_TIMEOUT;
1122 }
1123 }
3c2c7839
VK
1124 else
1125 {
1126 dwResult = ERR_CONNECTION_BROKEN;
1127 }
1128
1129 return dwResult;
1130}
1131
1132
1133//
1134// Get configuration file from agent
1135//
1136
1137DWORD AgentConnection::UpdateConfigFile(TCHAR *pszConfig)
1138{
1139 DWORD dwRqId, dwResult;
1140 CSCPMessage msg;
1141#ifdef UNICODE
1142 int nChars;
1143 BYTE *pBuffer;
1144#endif
1145
1146 if (!m_bIsConnected)
1147 return ERR_NOT_CONNECTED;
1148
1149 dwRqId = m_dwRequestId++;
1150
1151 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1152 msg.SetId(dwRqId);
1153#ifdef UNICODE
1154 nChars = _tcslen(pszConfig);
1155 pBuffer = (BYTE *)malloc(nChars + 1);
1156 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1157 pszConfig, nChars, pBuffer, nChars + 1, NULL, NULL);
1158 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1159 free(pBuffer);
1160#else
1161 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, strlen(pszConfig));
1162#endif
1163
1164 if (SendMessage(&msg))
1165 {
1166 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1167 }
cb27dff1
VK
1168 else
1169 {
1170 dwResult = ERR_CONNECTION_BROKEN;
1171 }
1172
1173 return dwResult;
1174}
6a4f307b
VK
1175
1176
1177//
1178// Get routing table from agent
1179//
1180
1181ROUTING_TABLE *AgentConnection::GetRoutingTable(void)
1182{
1183 ROUTING_TABLE *pRT = NULL;
66485623 1184 DWORD i, dwBits;
6a4f307b
VK
1185 TCHAR *pChar, *pBuf;
1186
1187 if (GetList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
1188 {
1189 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1190 pRT->iNumEntries = m_dwNumDataLines;
1191 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1192 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1193 for(i = 0; i < m_dwNumDataLines; i++)
1194 {
1195 pBuf = m_ppDataLines[i];
1196
1197 // Destination address and mask
1198 pChar = _tcschr(pBuf, _T(' '));
1199 if (pChar != NULL)
1200 {
1201 TCHAR *pSlash;
1202
1203 *pChar = 0;
1204 pSlash = _tcschr(pBuf, _T('/'));
1205 if (pSlash != NULL)
1206 {
1207 *pSlash = 0;
1208 pSlash++;
1209 }
1210 else // Just a paranoia protection, should'n happen if agent working correctly
1211 {
1212 pSlash = _T("24");
1213 }
1214 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
66485623
VK
1215 dwBits = _tcstoul(pSlash, NULL, 10);
1216 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
6a4f307b
VK
1217 pBuf = pChar + 1;
1218 }
1219
1220 // Next hop address
1221 pChar = _tcschr(pBuf, _T(' '));
1222 if (pChar != NULL)
1223 {
1224 *pChar = 0;
1225 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1226 pBuf = pChar + 1;
1227 }
1228
1229 // Interface index
1230 pChar = _tcschr(pBuf, ' ');
1231 if (pChar != NULL)
1232 {
1233 *pChar = 0;
1234 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1235 pBuf = pChar + 1;
1236 }
1237
1238 // Route type
1239 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1240 }
1241
1242 Lock();
1243 DestroyResultData();
1244 Unlock();
1245 }
1246
1247 return pRT;
1248}