Added new config parameter DefaultRTQueryInterval
[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
109 strncpy(m_szSecret, pszSecret, MAX_SECRET_LENGTH);
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 {
268774a0 206 PrintMsg(_T("Received too large message %s (%ld 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
ba8681ba
VK
240 if (iErr == 0)
241 shutdown(m_hSocket, SHUT_RDWR);
242 closesocket(m_hSocket);
243 m_hSocket = -1;
e44ac467
VK
244 DestroyEncryptionContext(m_pCtx);
245 m_pCtx = NULL;
ba8681ba 246 m_bIsConnected = FALSE;
1c62be36 247
9d72bde1
VK
248 free(pRawMsg);
249 free(pMsgBuffer);
3332c970
VK
250#ifdef _WITH_ENCRYPTION
251 free(pDecryptionBuffer);
252#endif
f77084bb
VK
253}
254
255
256//
257// Connect to agent
258//
259
1ba3c17a 260BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
f77084bb
VK
261{
262 struct sockaddr_in sa;
268774a0 263 TCHAR szBuffer[256];
f9a4ab9a
VK
264 BOOL bSuccess = FALSE, bForceEncryption = FALSE;
265 DWORD dwError = 0;
f77084bb 266
1ba3c17a
VK
267 if (pdwError != NULL)
268 *pdwError = ERR_INTERNAL_ERROR;
269
1c62be36 270 // Check if already connected
ba8681ba 271 if (m_bIsConnected)
1c62be36
VK
272 return FALSE;
273
ccdbbb52
VK
274 // Wait for receiver thread from previous connection, if any
275 ThreadJoin(m_hReceiverThread);
276 m_hReceiverThread = INVALID_THREAD_HANDLE;
277
ba8681ba
VK
278 // Check if we need to close existing socket
279 if (m_hSocket != -1)
280 closesocket(m_hSocket);
281
f77084bb
VK
282 // Create socket
283 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
284 if (m_hSocket == -1)
285 {
268774a0 286 PrintMsg(_T("Call to socket() failed"));
f77084bb
VK
287 goto connect_cleanup;
288 }
289
290 // Fill in address structure
291 memset(&sa, 0, sizeof(sa));
292 sa.sin_addr.s_addr = m_dwAddr;
293 sa.sin_family = AF_INET;
294 sa.sin_port = htons(m_wPort);
295
296 // Connect to server
297 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
298 {
299 if (bVerbose)
205acaf4 300 PrintMsg(_T("Cannot establish connection with agent %s"), IpToStr(ntohl(m_dwAddr), szBuffer));
1ba3c17a 301 dwError = ERR_CONNECT_FAILED;
f77084bb
VK
302 goto connect_cleanup;
303 }
304
305 // Start receiver thread
ccdbbb52 306 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
f77084bb 307
e44ac467 308 // Setup encryption
f9a4ab9a
VK
309setup_encryption:
310 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
311 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
312 (bForceEncryption)) // Agent require encryption
e44ac467 313 {
f9a4ab9a
VK
314 if (pServerKey != NULL)
315 {
316 dwError = SetupEncryption(pServerKey);
317 if ((dwError != ERR_SUCCESS) &&
318 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
319 goto connect_cleanup;
320 }
321 else
322 {
323 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
324 {
325 dwError = ERR_ENCRYPTION_REQUIRED;
326 goto connect_cleanup;
327 }
328 }
e44ac467
VK
329 }
330
f77084bb 331 // Authenticate itself to agent
d1d0b3be 332 if ((dwError = Authenticate()) != ERR_SUCCESS)
f77084bb 333 {
f9a4ab9a
VK
334 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
335 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
336 {
337 bForceEncryption = TRUE;
338 goto setup_encryption;
339 }
205acaf4 340 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be
VK
341 AgentErrorCodeToText(dwError));
342 goto connect_cleanup;
f77084bb
VK
343 }
344
345 // Test connectivity
d1d0b3be 346 if ((dwError = Nop()) != ERR_SUCCESS)
f77084bb 347 {
f9a4ab9a
VK
348 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
349 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
350 {
351 bForceEncryption = TRUE;
352 goto setup_encryption;
353 }
205acaf4 354 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be 355 AgentErrorCodeToText(dwError));
f77084bb
VK
356 goto connect_cleanup;
357 }
358
359 bSuccess = TRUE;
1ba3c17a 360 dwError = ERR_SUCCESS;
f77084bb
VK
361
362connect_cleanup:
363 if (!bSuccess)
364 {
365 if (m_hSocket != -1)
f77084bb 366 shutdown(m_hSocket, 2);
ba8681ba
VK
367 ThreadJoin(m_hReceiverThread);
368 m_hReceiverThread = INVALID_THREAD_HANDLE;
369
370 if (m_hSocket != -1)
f77084bb 371 closesocket(m_hSocket);
e44ac467
VK
372
373 DestroyEncryptionContext(m_pCtx);
374 m_pCtx = NULL;
f77084bb 375 }
1c62be36 376 m_bIsConnected = bSuccess;
1ba3c17a
VK
377 if (pdwError != NULL)
378 *pdwError = dwError;
f77084bb
VK
379 return bSuccess;
380}
381
382
383//
384// Disconnect from agent
385//
386
387void AgentConnection::Disconnect(void)
388{
1c62be36 389 Lock();
f77084bb
VK
390 if (m_hSocket != -1)
391 {
ba8681ba 392 shutdown(m_hSocket, SHUT_RDWR);
f77084bb
VK
393 }
394 DestroyResultData();
1c62be36
VK
395 m_bIsConnected = FALSE;
396 Unlock();
f77084bb
VK
397}
398
399
400//
401// Destroy command execuion results data
402//
403
404void AgentConnection::DestroyResultData(void)
405{
406 DWORD i;
407
408 if (m_ppDataLines != NULL)
409 {
410 for(i = 0; i < m_dwNumDataLines; i++)
411 if (m_ppDataLines[i] != NULL)
9d72bde1
VK
412 free(m_ppDataLines[i]);
413 free(m_ppDataLines);
f77084bb
VK
414 m_ppDataLines = NULL;
415 }
416 m_dwNumDataLines = 0;
417}
418
419
420//
421// Get interface list from agent
422//
423
424INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
425{
1c62be36
VK
426 INTERFACE_LIST *pIfList = NULL;
427 DWORD i;
268774a0 428 TCHAR *pChar, *pBuf;
1c62be36 429
268774a0 430 if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
1c62be36 431 {
9d72bde1 432 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
1c62be36 433 pIfList->iNumEntries = m_dwNumDataLines;
9d72bde1 434 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * m_dwNumDataLines);
1c62be36
VK
435 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * m_dwNumDataLines);
436 for(i = 0; i < m_dwNumDataLines; i++)
437 {
438 pBuf = m_ppDataLines[i];
439
440 // Index
268774a0 441 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
442 if (pChar != NULL)
443 {
444 *pChar = 0;
268774a0 445 pIfList->pInterfaces[i].dwIndex = _tcstoul(pBuf, NULL, 10);
1c62be36
VK
446 pBuf = pChar + 1;
447 }
448
449 // Address and mask
268774a0 450 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
451 if (pChar != NULL)
452 {
268774a0 453 TCHAR *pSlash;
1c62be36
VK
454
455 *pChar = 0;
268774a0 456 pSlash = _tcschr(pBuf, _T('/'));
1c62be36
VK
457 if (pSlash != NULL)
458 {
459 *pSlash = 0;
460 pSlash++;
461 }
462 else // Just a paranoia protection, should'n happen if agent working correctly
463 {
268774a0 464 pSlash = _T("24");
1c62be36 465 }
205acaf4
VK
466 pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
467 pIfList->pInterfaces[i].dwIpNetMask = ~(0xFFFFFFFF >> _tcstoul(pSlash, NULL, 10));
1c62be36
VK
468 pBuf = pChar + 1;
469 }
470
471 // Interface type
268774a0 472 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
473 if (pChar != NULL)
474 {
475 *pChar = 0;
205acaf4 476 pIfList->pInterfaces[i].dwType = _tcstoul(pBuf, NULL, 10);
1c62be36 477 pBuf = pChar + 1;
b50f1100
VK
478 }
479
480 // MAC address
481 pChar = _tcschr(pBuf, ' ');
482 if (pChar != NULL)
483 {
484 *pChar = 0;
485 StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
486 pBuf = pChar + 1;
1c62be36
VK
487 }
488
489 // Name
268774a0 490 _tcsncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
1c62be36
VK
491 }
492
9d72bde1 493 Lock();
1c62be36 494 DestroyResultData();
9d72bde1 495 Unlock();
1c62be36
VK
496 }
497
498 return pIfList;
f77084bb
VK
499}
500
501
502//
503// Get parameter value
504//
505
268774a0 506DWORD AgentConnection::GetParameter(TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
f77084bb
VK
507{
508 CSCPMessage msg, *pResponce;
509 DWORD dwRqId, dwRetCode;
510
1c62be36 511 if (m_bIsConnected)
f77084bb 512 {
1c62be36
VK
513 dwRqId = m_dwRequestId++;
514 msg.SetCode(CMD_GET_PARAMETER);
515 msg.SetId(dwRqId);
516 msg.SetVariable(VID_PARAMETER, pszParam);
517 if (SendMessage(&msg))
f77084bb 518 {
1c62be36
VK
519 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
520 if (pResponce != NULL)
521 {
522 dwRetCode = pResponce->GetVariableLong(VID_RCC);
523 if (dwRetCode == ERR_SUCCESS)
524 pResponce->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
525 delete pResponce;
526 }
527 else
528 {
529 dwRetCode = ERR_REQUEST_TIMEOUT;
530 }
f77084bb
VK
531 }
532 else
533 {
1c62be36 534 dwRetCode = ERR_CONNECTION_BROKEN;
f77084bb
VK
535 }
536 }
537 else
538 {
1c62be36 539 dwRetCode = ERR_NOT_CONNECTED;
f77084bb
VK
540 }
541
542 return dwRetCode;
543}
544
545
546//
547// Get ARP cache
548//
549
550ARP_CACHE *AgentConnection::GetArpCache(void)
551{
1c62be36 552 ARP_CACHE *pArpCache = NULL;
268774a0 553 TCHAR szByte[4], *pBuf, *pChar;
1c62be36
VK
554 DWORD i, j;
555
268774a0 556 if (GetList(_T("Net.ArpCache")) == ERR_SUCCESS)
1c62be36
VK
557 {
558 // Create empty structure
9d72bde1 559 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
1c62be36 560 pArpCache->dwNumEntries = m_dwNumDataLines;
9d72bde1 561 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
1c62be36
VK
562 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
563
564 szByte[2] = 0;
565
566 // Parse data lines
567 // Each line has form of XXXXXXXXXXXX a.b.c.d
568 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
569 // and a.b.c.d is an IP address in decimal dotted notation
570 for(i = 0; i < m_dwNumDataLines; i++)
571 {
572 pBuf = m_ppDataLines[i];
268774a0 573 if (_tcslen(pBuf) < 20) // Invalid line
1c62be36
VK
574 continue;
575
576 // MAC address
577 for(j = 0; j < 6; j++)
578 {
268774a0
VK
579 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
580 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
1c62be36
VK
581 pBuf+=2;
582 }
583
584 // IP address
585 while(*pBuf == ' ')
586 pBuf++;
268774a0 587 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
588 if (pChar != NULL)
589 *pChar = 0;
205acaf4 590 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
1c62be36
VK
591
592 // Interface index
593 if (pChar != NULL)
268774a0 594 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
1c62be36
VK
595 }
596
597 DestroyResultData();
598 }
599 return pArpCache;
f77084bb
VK
600}
601
602
603//
604// Send dummy command to agent (can be used for keepalive)
605//
606
607DWORD AgentConnection::Nop(void)
608{
609 CSCPMessage msg;
610 DWORD dwRqId;
611
612 dwRqId = m_dwRequestId++;
613 msg.SetCode(CMD_KEEPALIVE);
614 msg.SetId(dwRqId);
615 if (SendMessage(&msg))
616 return WaitForRCC(dwRqId, m_dwCommandTimeout);
617 else
618 return ERR_CONNECTION_BROKEN;
619}
620
621
622//
623// Wait for request completion code
624//
625
626DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
627{
628 CSCPMessage *pMsg;
629 DWORD dwRetCode;
630
631 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
632 if (pMsg != NULL)
633 {
634 dwRetCode = pMsg->GetVariableLong(VID_RCC);
635 delete pMsg;
636 }
637 else
638 {
639 dwRetCode = ERR_REQUEST_TIMEOUT;
640 }
641 return dwRetCode;
642}
643
644
645//
646// Send message to agent
647//
648
649BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
650{
651 CSCP_MESSAGE *pRawMsg;
e44ac467 652 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
f77084bb
VK
653 BOOL bResult;
654
655 pRawMsg = pMsg->CreateMessage();
e44ac467
VK
656 if (m_pCtx != NULL)
657 {
658 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
659 if (pEnMsg != NULL)
660 {
661 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
662 free(pEnMsg);
663 }
664 else
665 {
666 bResult = FALSE;
667 }
668 }
669 else
670 {
671 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
672 }
9d72bde1 673 free(pRawMsg);
f77084bb
VK
674 return bResult;
675}
901c96c7
VK
676
677
678//
679// Trap handler. Should be overriden in derived classes to implement
680// actual trap processing. Default implementation do nothing.
681//
682
683void AgentConnection::OnTrap(CSCPMessage *pMsg)
684{
685}
686
687
688//
689// Get list of values
690//
691
268774a0 692DWORD AgentConnection::GetList(TCHAR *pszParam)
901c96c7
VK
693{
694 CSCPMessage msg, *pResponce;
695 DWORD i, dwRqId, dwRetCode;
696
1c62be36 697 if (m_bIsConnected)
901c96c7 698 {
1c62be36
VK
699 DestroyResultData();
700 dwRqId = m_dwRequestId++;
701 msg.SetCode(CMD_GET_LIST);
702 msg.SetId(dwRqId);
703 msg.SetVariable(VID_PARAMETER, pszParam);
704 if (SendMessage(&msg))
901c96c7 705 {
1c62be36
VK
706 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
707 if (pResponce != NULL)
708 {
709 dwRetCode = pResponce->GetVariableLong(VID_RCC);
710 if (dwRetCode == ERR_SUCCESS)
711 {
712 m_dwNumDataLines = pResponce->GetVariableLong(VID_NUM_STRINGS);
268774a0 713 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
1c62be36
VK
714 for(i = 0; i < m_dwNumDataLines; i++)
715 m_ppDataLines[i] = pResponce->GetVariableStr(VID_ENUM_VALUE_BASE + i);
716 }
717 delete pResponce;
718 }
719 else
901c96c7 720 {
1c62be36 721 dwRetCode = ERR_REQUEST_TIMEOUT;
901c96c7 722 }
901c96c7
VK
723 }
724 else
725 {
1c62be36 726 dwRetCode = ERR_CONNECTION_BROKEN;
901c96c7
VK
727 }
728 }
729 else
730 {
1c62be36 731 dwRetCode = ERR_NOT_CONNECTED;
901c96c7
VK
732 }
733
734 return dwRetCode;
735}
d1d0b3be
VK
736
737
738//
739// Authenticate to agent
740//
741
742DWORD AgentConnection::Authenticate(void)
743{
744 CSCPMessage msg;
745 DWORD dwRqId;
746 BYTE hash[32];
268774a0
VK
747#ifdef UNICODE
748 WCHAR szBuffer[MAX_SECRET_LENGTH];
749#endif
d1d0b3be
VK
750
751 if (m_iAuthMethod == AUTH_NONE)
752 return ERR_SUCCESS; // No authentication required
753
754 dwRqId = m_dwRequestId++;
755 msg.SetCode(CMD_AUTHENTICATE);
756 msg.SetId(dwRqId);
757 msg.SetVariable(VID_AUTH_METHOD, (WORD)m_iAuthMethod);
758 switch(m_iAuthMethod)
759 {
760 case AUTH_PLAINTEXT:
268774a0
VK
761#ifdef UNICODE
762 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szSecret, -1, szBuffer, MAX_SECRET_LENGTH);
763 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
764#else
d1d0b3be 765 msg.SetVariable(VID_SHARED_SECRET, m_szSecret);
268774a0 766#endif
d1d0b3be
VK
767 break;
768 case AUTH_MD5_HASH:
769 CalculateMD5Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
770 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
771 break;
772 case AUTH_SHA1_HASH:
773 CalculateSHA1Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
774 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
775 break;
776 default:
777 break;
778 }
779 if (SendMessage(&msg))
780 return WaitForRCC(dwRqId, m_dwCommandTimeout);
781 else
782 return ERR_CONNECTION_BROKEN;
783}
3c774461
VK
784
785
786//
787// Execute action on agent
788//
789
268774a0 790DWORD AgentConnection::ExecAction(TCHAR *pszAction, int argc, TCHAR **argv)
3c774461
VK
791{
792 CSCPMessage msg;
793 DWORD dwRqId;
794 int i;
795
1c62be36
VK
796 if (!m_bIsConnected)
797 return ERR_NOT_CONNECTED;
798
3c774461
VK
799 dwRqId = m_dwRequestId++;
800 msg.SetCode(CMD_ACTION);
801 msg.SetId(dwRqId);
802 msg.SetVariable(VID_ACTION_NAME, pszAction);
803 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
804 for(i = 0; i < argc; i++)
805 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
806
807 if (SendMessage(&msg))
808 return WaitForRCC(dwRqId, m_dwCommandTimeout);
809 else
810 return ERR_CONNECTION_BROKEN;
811}
d096bcdd
VK
812
813
814//
815// Upload file to agent
816//
817
818DWORD AgentConnection::UploadFile(TCHAR *pszFile)
819{
820 DWORD dwRqId, dwResult;
821 CSCPMessage msg;
822 int i;
823
824 if (!m_bIsConnected)
825 return ERR_NOT_CONNECTED;
826
827 dwRqId = m_dwRequestId++;
828
829 msg.SetCode(CMD_TRANSFER_FILE);
830 msg.SetId(dwRqId);
831 for(i = _tcslen(pszFile) - 1;
832 (i >= 0) && (pszFile[i] != '\\') && (pszFile[i] != '/'); i--);
833 msg.SetVariable(VID_FILE_NAME, &pszFile[i + 1]);
834
835 if (SendMessage(&msg))
836 {
837 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
838 }
839 else
840 {
841 dwResult = ERR_CONNECTION_BROKEN;
842 }
843
844 if (dwResult == ERR_SUCCESS)
845 {
1ba3c17a 846 if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile, m_pCtx))
d096bcdd
VK
847 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
848 else
849 dwResult = ERR_IO_FAILURE;
850 }
851
852 return dwResult;
853}
e925a5fc
VK
854
855
856//
857// Send upgrade command
858//
859
860DWORD AgentConnection::StartUpgrade(TCHAR *pszPkgName)
861{
862 DWORD dwRqId, dwResult;
863 CSCPMessage msg;
864 int i;
865
866 if (!m_bIsConnected)
867 return ERR_NOT_CONNECTED;
868
869 dwRqId = m_dwRequestId++;
870
871 msg.SetCode(CMD_UPGRADE_AGENT);
872 msg.SetId(dwRqId);
873 for(i = _tcslen(pszPkgName) - 1;
874 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
875 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
876
877 if (SendMessage(&msg))
878 {
879 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
880 }
881 else
882 {
883 dwResult = ERR_CONNECTION_BROKEN;
884 }
885
886 return dwResult;
887}
3f0ca036
VK
888
889
890//
891// Check status of network service via agent
892//
893
894DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
895 WORD wPort, WORD wProto,
896 TCHAR *pszRequest, TCHAR *pszResponce)
897{
898 DWORD dwRqId, dwResult;
899 CSCPMessage msg, *pResponce;
900 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
901
902 if (!m_bIsConnected)
903 return ERR_NOT_CONNECTED;
904
905 dwRqId = m_dwRequestId++;
906
907 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
908 msg.SetId(dwRqId);
909 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
910 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
911 msg.SetVariable(VID_IP_PORT,
912 (wPort != 0) ? wPort :
25376fc7 913 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
3f0ca036 914 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
25376fc7 915 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
3f0ca036
VK
916 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
917 msg.SetVariable(VID_SERVICE_RESPONCE, pszResponce);
918
919 if (SendMessage(&msg))
920 {
921 // Wait up to 90 seconds for results
922 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
923 if (pResponce != NULL)
924 {
925 dwResult = pResponce->GetVariableLong(VID_RCC);
926 if (dwResult == ERR_SUCCESS)
927 {
928 *pdwStatus = pResponce->GetVariableLong(VID_SERVICE_STATUS);
929 }
930 delete pResponce;
931 }
932 else
933 {
934 dwResult = ERR_REQUEST_TIMEOUT;
935 }
936 }
937 else
938 {
939 dwResult = ERR_CONNECTION_BROKEN;
940 }
941
942 return dwResult;
943}
125c0e81
VK
944
945
946//
947// Get list of supported parameters from subagent
948//
949
950DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
951{
952 DWORD i, dwId, dwRqId, dwResult;
953 CSCPMessage msg, *pResponce;
954
125c0e81
VK
955 *pdwNumParams = 0;
956 *ppParamList = NULL;
957
cb27dff1
VK
958 if (!m_bIsConnected)
959 return ERR_NOT_CONNECTED;
960
125c0e81
VK
961 dwRqId = m_dwRequestId++;
962
963 msg.SetCode(CMD_GET_PARAMETER_LIST);
964 msg.SetId(dwRqId);
965
966 if (SendMessage(&msg))
967 {
125c0e81
VK
968 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
969 if (pResponce != NULL)
970 {
971 dwResult = pResponce->GetVariableLong(VID_RCC);
972 if (dwResult == ERR_SUCCESS)
973 {
974 *pdwNumParams = pResponce->GetVariableLong(VID_NUM_PARAMETERS);
975 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * *pdwNumParams);
976 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
977 {
978 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
979 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
980 (*ppParamList)[i].iDataType = (int)pResponce->GetVariableShort(dwId++);
981 }
982 }
983 delete pResponce;
984 }
985 else
986 {
987 dwResult = ERR_REQUEST_TIMEOUT;
988 }
989 }
990 else
991 {
992 dwResult = ERR_CONNECTION_BROKEN;
993 }
994
995 return dwResult;
996}
e44ac467
VK
997
998
999//
1000// Setup encryption
1001//
1002
1003DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
1004{
1005#ifdef _WITH_ENCRYPTION
1006 CSCPMessage msg, *pResp;
1007 DWORD dwRqId, dwError, dwResult;
1008
1009 dwRqId = m_dwRequestId++;
1010
1011 PrepareKeyRequestMsg(&msg, pServerKey);
1012 msg.SetId(dwRqId);
1013 if (SendMessage(&msg))
1014 {
1015 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
1016 if (pResp != NULL)
1017 {
1018 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey);
1019 switch(dwResult)
1020 {
1021 case RCC_SUCCESS:
1022 dwError = ERR_SUCCESS;
1023 break;
1024 case RCC_NO_CIPHERS:
1025 dwError = ERR_NO_CIPHERS;
1026 break;
1027 case RCC_INVALID_PUBLIC_KEY:
1028 dwError = ERR_INVALID_PUBLIC_KEY;
1029 break;
1030 case RCC_INVALID_SESSION_KEY:
1031 dwError = ERR_INVALID_SESSION_KEY;
1032 break;
1033 default:
1034 dwError = ERR_INTERNAL_ERROR;
1035 break;
1036 }
1037 }
1038 else
1039 {
1040 dwError = ERR_REQUEST_TIMEOUT;
1041 }
1042 }
1043 else
1044 {
1045 dwError = ERR_CONNECTION_BROKEN;
1046 }
1047
1048 return dwError;
1049#else
1050 return ERR_NOT_IMPLEMENTED;
1051#endif
1052}
cb27dff1
VK
1053
1054
1055//
1056// Get configuration file from agent
1057//
1058
1059DWORD AgentConnection::GetConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
1060{
1061 DWORD i, dwRqId, dwResult;
1062 CSCPMessage msg, *pResponce;
1063#ifdef UNICODE
1064 BYTE *pBuffer;
1065#endif
1066
1067 *ppszConfig = NULL;
1068 *pdwSize = 0;
1069
1070 if (!m_bIsConnected)
1071 return ERR_NOT_CONNECTED;
1072
1073 dwRqId = m_dwRequestId++;
1074
1075 msg.SetCode(CMD_GET_AGENT_CONFIG);
1076 msg.SetId(dwRqId);
1077
1078 if (SendMessage(&msg))
1079 {
1080 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1081 if (pResponce != NULL)
1082 {
1083 dwResult = pResponce->GetVariableLong(VID_RCC);
1084 if (dwResult == ERR_SUCCESS)
1085 {
1086 *pdwSize = pResponce->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1087 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1088#ifdef UNICODE
1089 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1090 pResponce->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
1091 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pBuffer, *pdwSize, *ppszConfig, *pdwSize);
1092 free(pBuffer);
1093#else
1094 pResponce->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1095#endif
1096 (*ppszConfig)[*pdwSize] = 0;
1097
1098 // We expect text file, so replace all non-printable characters with spaces
1099 for(i = 0; i < *pdwSize; i++)
1100 if (((*ppszConfig)[i] < _T(' ')) &&
1101 ((*ppszConfig)[i] != _T('\t')) &&
1102 ((*ppszConfig)[i] != _T('\r')) &&
1103 ((*ppszConfig)[i] != _T('\n')))
1104 (*ppszConfig)[i] = _T(' ');
1105 }
1106 delete pResponce;
1107 }
1108 else
1109 {
1110 dwResult = ERR_REQUEST_TIMEOUT;
1111 }
1112 }
1113 else
1114 {
1115 dwResult = ERR_CONNECTION_BROKEN;
1116 }
1117
1118 return dwResult;
1119}