transformation now possible in DCI instance filtering script; code refactoring
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server Library
0f506caa 4** Copyright (C) 2003-2013 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
0702ed69
VK
7** it under the terms of the GNU Lesser General Public License as published by
8** the Free Software Foundation; either version 3 of the License, or
5039dede
AK
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**
0702ed69 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
25#include <stdarg.h>
26
f00612ba
VK
27#ifdef _WIN32
28#define open _open
29#define close _close
30#define write _write
8c1befb6 31#else
ff198273 32#define _tell(f) lseek(f,0,SEEK_CUR)
f00612ba
VK
33#endif
34
a3050773
VK
35/**
36 * Constants
37 */
5039dede
AK
38#define RECEIVER_BUFFER_SIZE 262144
39
a3050773
VK
40/**
41 * Static data
42 */
5039dede
AK
43#ifdef _WITH_ENCRYPTION
44static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
45#else
46static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
47#endif
48
a3050773
VK
49/**
50 * Set default encryption policy for agent communication
51 */
5039dede
AK
52void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
53{
54#ifdef _WITH_ENCRYPTION
55 m_iDefaultEncryptionPolicy = iPolicy;
56#endif
57}
58
a3050773
VK
59/**
60 * Receiver thread starter
61 */
62THREAD_RESULT THREAD_CALL AgentConnection::receiverThreadStarter(void *pArg)
5039dede 63{
a3050773 64 ((AgentConnection *)pArg)->receiverThread();
5039dede
AK
65 return THREAD_OK;
66}
67
a3050773
VK
68/**
69 * Constructor for AgentConnection
70 */
71AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede
AK
72{
73 m_dwAddr = dwAddr;
74 m_wPort = wPort;
75 m_iAuthMethod = iAuthMethod;
76 if (pszSecret != NULL)
77 {
78#ifdef UNICODE
08b214c6
VK
79 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pszSecret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
80 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
5039dede
AK
81#else
82 nx_strncpy(m_szSecret, pszSecret, MAX_SECRET_LENGTH);
83#endif
84 }
85 else
86 {
87 m_szSecret[0] = 0;
88 }
89 m_hSocket = -1;
90 m_tLastCommandTime = 0;
91 m_dwNumDataLines = 0;
92 m_ppDataLines = NULL;
93 m_pMsgWaitQueue = new MsgWaitQueue;
94 m_dwRequestId = 1;
7c521895 95 m_connectionTimeout = 30000; // 30 seconds
5039dede
AK
96 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
97 m_bIsConnected = FALSE;
98 m_mutexDataLock = MutexCreate();
d3a7cf4c 99 m_mutexSocketWrite = MutexCreate();
5039dede
AK
100 m_hReceiverThread = INVALID_THREAD_HANDLE;
101 m_pCtx = NULL;
102 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
103 m_bUseProxy = FALSE;
104 m_dwRecvTimeout = 420000; // 7 minutes
105 m_nProtocolVersion = NXCP_VERSION;
106 m_hCurrFile = -1;
901a5a9b 107 m_deleteFileOnDownloadFailure = true;
bb85e341 108 m_condFileDownload = ConditionCreate(TRUE);
4685a2ad 109 m_fileUploadInProgress = false;
5039dede
AK
110}
111
a3050773
VK
112/**
113 * Destructor
114 */
5039dede
AK
115AgentConnection::~AgentConnection()
116{
117 // Disconnect from peer
7c521895 118 disconnect();
5039dede
AK
119
120 // Wait for receiver thread termination
121 ThreadJoin(m_hReceiverThread);
122
123 // Close socket if active
a3050773 124 lock();
5039dede
AK
125 if (m_hSocket != -1)
126 {
127 closesocket(m_hSocket);
128 m_hSocket = -1;
129 }
a3050773 130 unlock();
5039dede 131
a3050773 132 lock();
7c521895 133 destroyResultData();
a3050773 134 unlock();
5039dede
AK
135
136 delete m_pMsgWaitQueue;
98abc9f1
VK
137 if (m_pCtx != NULL)
138 m_pCtx->decRefCount();
5039dede
AK
139
140 if (m_hCurrFile != -1)
9f6d453a 141 {
5039dede 142 close(m_hCurrFile);
f480bdd4 143 onFileDownload(FALSE);
9f6d453a 144 }
5039dede
AK
145
146 MutexDestroy(m_mutexDataLock);
d3a7cf4c 147 MutexDestroy(m_mutexSocketWrite);
bb85e341 148 ConditionDestroy(m_condFileDownload);
5039dede
AK
149}
150
a3050773
VK
151/**
152 * Print message. This method is virtual and can be overrided in
153 * derived classes. Default implementation will print message to stdout.
154 */
155void AgentConnection::printMsg(const TCHAR *pszFormat, ...)
5039dede
AK
156{
157 va_list args;
158
159 va_start(args, pszFormat);
160 _vtprintf(pszFormat, args);
161 va_end(args);
162 _tprintf(_T("\n"));
163}
164
a3050773
VK
165/**
166 * Receiver thread
167 */
168void AgentConnection::receiverThread()
5039dede
AK
169{
170 CSCPMessage *pMsg;
171 CSCP_MESSAGE *pRawMsg;
172 CSCP_BUFFER *pMsgBuffer;
173 BYTE *pDecryptionBuffer = NULL;
4685a2ad 174 int error;
5039dede
AK
175 TCHAR szBuffer[128], szIpAddr[16];
176 SOCKET nSocket;
177
178 // Initialize raw message receiving function
179 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
180 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
181
182 // Allocate space for raw message
183 pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
184#ifdef _WITH_ENCRYPTION
185 pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
186#endif
187
188 // Message receiving loop
189 while(1)
190 {
191 // Receive raw message
a3050773 192 lock();
5039dede 193 nSocket = m_hSocket;
a3050773 194 unlock();
4685a2ad 195 if ((error = RecvNXCPMessage(nSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
5039dede
AK
196 &m_pCtx, pDecryptionBuffer, m_dwRecvTimeout)) <= 0)
197 {
a2069340
VK
198 if (WSAGetLastError() != WSAESHUTDOWN)
199 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), error, WSAGetLastError());
5039dede
AK
200 break;
201 }
202
203 // Check if we get too large message
4685a2ad 204 if (error == 1)
5039dede 205 {
a3050773 206 printMsg(_T("Received too large message %s (%d bytes)"),
5039dede
AK
207 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
208 ntohl(pRawMsg->dwSize));
209 continue;
210 }
211
212 // Check if we are unable to decrypt message
4685a2ad 213 if (error == 2)
5039dede 214 {
a3050773 215 printMsg(_T("Unable to decrypt received message"));
5039dede
AK
216 continue;
217 }
218
219 // Check for timeout
4685a2ad 220 if (error == 3)
5039dede 221 {
4685a2ad
VK
222 if (m_fileUploadInProgress)
223 continue; // Receive timeout may occur when uploading large files via slow links
a3050773 224 printMsg(_T("Timed out waiting for message"));
5039dede
AK
225 break;
226 }
227
228 // Check that actual received packet size is equal to encoded in packet
4685a2ad 229 if ((int)ntohl(pRawMsg->dwSize) != error)
5039dede 230 {
a3050773 231 printMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), error);
5039dede
AK
232 continue; // Bad packet, wait for next
233 }
234
235 if (ntohs(pRawMsg->wFlags) & MF_BINARY)
236 {
237 // Convert message header to host format
238 pRawMsg->dwId = ntohl(pRawMsg->dwId);
239 pRawMsg->wCode = ntohs(pRawMsg->wCode);
240 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
08b214c6 241 DbgPrintf(6, _T("Received raw message %s from agent at %s"),
7c521895 242 NXCPMessageCodeName(pRawMsg->wCode, szBuffer), IpToStr(getIpAddr(), szIpAddr));
5039dede
AK
243
244 if ((pRawMsg->wCode == CMD_FILE_DATA) &&
bb85e341 245 (m_hCurrFile != -1) && (pRawMsg->dwId == m_dwDownloadRequestId))
5039dede
AK
246 {
247 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
248 {
249 if (ntohs(pRawMsg->wFlags) & MF_END_OF_FILE)
250 {
251 close(m_hCurrFile);
252 m_hCurrFile = -1;
253
f480bdd4 254 onFileDownload(TRUE);
5039dede 255 }
bb85e341
VK
256 else
257 {
258 if (m_downloadProgressCallback != NULL)
259 {
901a5a9b 260 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
bb85e341
VK
261 }
262 }
5039dede
AK
263 }
264 else
265 {
266 // I/O error
267 close(m_hCurrFile);
268 m_hCurrFile = -1;
269
f480bdd4 270 onFileDownload(FALSE);
5039dede
AK
271 }
272 }
273 }
274 else
275 {
276 // Create message object from raw message
277 pMsg = new CSCPMessage(pRawMsg, m_nProtocolVersion);
f480bdd4 278 switch(pMsg->GetCode())
5039dede 279 {
f480bdd4
VK
280 case CMD_TRAP:
281 onTrap(pMsg);
282 delete pMsg;
283 break;
284 case CMD_PUSH_DCI_DATA:
285 onDataPush(pMsg);
286 delete pMsg;
287 break;
90284364 288 case CMD_REQUEST_COMPLETED:
c17f6cbc 289 m_pMsgWaitQueue->put(pMsg);
f480bdd4 290 break;
90284364
VK
291 default:
292 if (processCustomMessage(pMsg))
293 delete pMsg;
294 else
c17f6cbc 295 m_pMsgWaitQueue->put(pMsg);
90284364 296 break;
5039dede
AK
297 }
298 }
299 }
300
301 // Close socket and mark connection as disconnected
a3050773 302 lock();
f2665675
VK
303 if (m_hCurrFile != -1)
304 {
305 close(m_hCurrFile);
306 m_hCurrFile = -1;
f480bdd4 307 onFileDownload(FALSE);
f2665675
VK
308 }
309
4685a2ad 310 if (error == 0)
5039dede
AK
311 shutdown(m_hSocket, SHUT_RDWR);
312 closesocket(m_hSocket);
313 m_hSocket = -1;
98abc9f1
VK
314 if (m_pCtx != NULL)
315 {
316 m_pCtx->decRefCount();
317 m_pCtx = NULL;
318 }
5039dede 319 m_bIsConnected = FALSE;
a3050773 320 unlock();
5039dede
AK
321
322 free(pRawMsg);
323 free(pMsgBuffer);
324#ifdef _WITH_ENCRYPTION
325 free(pDecryptionBuffer);
326#endif
327}
328
a3050773
VK
329/**
330 * Connect to agent
331 */
c3acd0f6 332BOOL AgentConnection::connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError, DWORD *pdwSocketError)
5039dede
AK
333{
334 struct sockaddr_in sa;
335 TCHAR szBuffer[256];
336 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
337 DWORD dwError = 0;
338
339 if (pdwError != NULL)
340 *pdwError = ERR_INTERNAL_ERROR;
341
c3acd0f6
VK
342 if (pdwSocketError != NULL)
343 *pdwSocketError = 0;
344
5039dede
AK
345 // Check if already connected
346 if (m_bIsConnected)
347 return FALSE;
348
349 // Wait for receiver thread from previous connection, if any
350 ThreadJoin(m_hReceiverThread);
351 m_hReceiverThread = INVALID_THREAD_HANDLE;
352
353 // Check if we need to close existing socket
354 if (m_hSocket != -1)
355 closesocket(m_hSocket);
356
357 // Create socket
358 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
359 if (m_hSocket == -1)
360 {
a3050773 361 printMsg(_T("Call to socket() failed"));
5039dede
AK
362 goto connect_cleanup;
363 }
364
365 // Fill in address structure
366 memset(&sa, 0, sizeof(sa));
367 sa.sin_family = AF_INET;
368 if (m_bUseProxy)
369 {
370 sa.sin_addr.s_addr = m_dwProxyAddr;
371 sa.sin_port = htons(m_wProxyPort);
372 }
373 else
374 {
375 sa.sin_addr.s_addr = m_dwAddr;
376 sa.sin_port = htons(m_wPort);
377 }
378
379 // Connect to server
7c521895 380 if (ConnectEx(m_hSocket, (struct sockaddr *)&sa, sizeof(sa), m_connectionTimeout) == -1)
5039dede
AK
381 {
382 if (bVerbose)
a3050773 383 printMsg(_T("Cannot establish connection with agent %s"),
5039dede
AK
384 IpToStr(ntohl(m_bUseProxy ? m_dwProxyAddr : m_dwAddr), szBuffer));
385 dwError = ERR_CONNECT_FAILED;
386 goto connect_cleanup;
387 }
388
d3a7cf4c 389 if (!NXCPGetPeerProtocolVersion(m_hSocket, &m_nProtocolVersion, m_mutexSocketWrite))
5039dede
AK
390 {
391 dwError = ERR_INTERNAL_ERROR;
392 goto connect_cleanup;
393 }
394
395 // Start receiver thread
a3050773 396 m_hReceiverThread = ThreadCreateEx(receiverThreadStarter, 0, this);
5039dede
AK
397
398 // Setup encryption
399setup_encryption:
400 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
401 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
402 (bForceEncryption)) // Agent require encryption
403 {
404 if (pServerKey != NULL)
405 {
7c521895 406 dwError = setupEncryption(pServerKey);
5039dede
AK
407 if ((dwError != ERR_SUCCESS) &&
408 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
409 goto connect_cleanup;
410 }
411 else
412 {
413 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
414 {
415 dwError = ERR_ENCRYPTION_REQUIRED;
416 goto connect_cleanup;
417 }
418 }
419 }
420
421 // Authenticate itself to agent
7c521895 422 if ((dwError = authenticate(m_bUseProxy && !bSecondPass)) != ERR_SUCCESS)
5039dede
AK
423 {
424 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
425 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
426 {
427 bForceEncryption = TRUE;
428 goto setup_encryption;
429 }
a3050773 430 printMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
431 AgentErrorCodeToText(dwError));
432 goto connect_cleanup;
433 }
434
435 // Test connectivity
45d84f8a 436 if ((dwError = nop()) != ERR_SUCCESS)
5039dede
AK
437 {
438 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
439 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
440 {
441 bForceEncryption = TRUE;
442 goto setup_encryption;
443 }
a3050773 444 printMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
445 AgentErrorCodeToText(dwError));
446 goto connect_cleanup;
447 }
448
449 if (m_bUseProxy && !bSecondPass)
450 {
7c521895 451 dwError = setupProxyConnection();
5039dede
AK
452 if (dwError != ERR_SUCCESS)
453 goto connect_cleanup;
a3050773 454 lock();
98abc9f1
VK
455 if (m_pCtx != NULL)
456 {
457 m_pCtx->decRefCount();
458 m_pCtx = NULL;
459 }
a3050773 460 unlock();
5039dede
AK
461 bSecondPass = TRUE;
462 bForceEncryption = FALSE;
463 goto setup_encryption;
464 }
465
466 bSuccess = TRUE;
467 dwError = ERR_SUCCESS;
468
469connect_cleanup:
470 if (!bSuccess)
471 {
c3acd0f6
VK
472 if (pdwSocketError != NULL)
473 *pdwSocketError = (DWORD)WSAGetLastError();
474
a3050773 475 lock();
5039dede
AK
476 if (m_hSocket != -1)
477 shutdown(m_hSocket, SHUT_RDWR);
a3050773 478 unlock();
5039dede
AK
479 ThreadJoin(m_hReceiverThread);
480 m_hReceiverThread = INVALID_THREAD_HANDLE;
481
a3050773 482 lock();
5039dede
AK
483 if (m_hSocket != -1)
484 {
485 closesocket(m_hSocket);
486 m_hSocket = -1;
487 }
488
98abc9f1
VK
489 if (m_pCtx != NULL)
490 {
491 m_pCtx->decRefCount();
492 m_pCtx = NULL;
493 }
5039dede 494
a3050773 495 unlock();
5039dede
AK
496 }
497 m_bIsConnected = bSuccess;
498 if (pdwError != NULL)
499 *pdwError = dwError;
500 return bSuccess;
501}
502
503
504//
505// Disconnect from agent
506//
507
7c521895 508void AgentConnection::disconnect()
5039dede 509{
a3050773 510 lock();
f2665675
VK
511 if (m_hCurrFile != -1)
512 {
513 close(m_hCurrFile);
514 m_hCurrFile = -1;
f480bdd4 515 onFileDownload(FALSE);
f2665675
VK
516 }
517
5039dede
AK
518 if (m_hSocket != -1)
519 {
520 shutdown(m_hSocket, SHUT_RDWR);
521 }
7c521895 522 destroyResultData();
5039dede 523 m_bIsConnected = FALSE;
a3050773 524 unlock();
5039dede
AK
525}
526
527
528//
529// Destroy command execuion results data
530//
531
7c521895 532void AgentConnection::destroyResultData()
5039dede
AK
533{
534 DWORD i;
535
536 if (m_ppDataLines != NULL)
537 {
538 for(i = 0; i < m_dwNumDataLines; i++)
539 if (m_ppDataLines[i] != NULL)
540 free(m_ppDataLines[i]);
541 free(m_ppDataLines);
542 m_ppDataLines = NULL;
543 }
544 m_dwNumDataLines = 0;
545}
546
d51f2182
VK
547/**
548 * Get interface list from agent
549 */
98762401 550InterfaceList *AgentConnection::getInterfaceList()
5039dede 551{
98762401 552 InterfaceList *pIfList = NULL;
36e44abe 553 NX_INTERFACE_INFO iface;
5039dede
AK
554 DWORD i, dwBits;
555 TCHAR *pChar, *pBuf;
556
4687826e 557 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS)
5039dede 558 {
98762401 559 pIfList = new InterfaceList(m_dwNumDataLines);
5039dede
AK
560
561 // Parse result set. Each line should have the following format:
562 // index ip_address/mask_bits iftype mac_address name
563 for(i = 0; i < m_dwNumDataLines; i++)
564 {
565 pBuf = m_ppDataLines[i];
36e44abe 566 memset(&iface, 0, sizeof(NX_INTERFACE_INFO));
5039dede
AK
567
568 // Index
569 pChar = _tcschr(pBuf, ' ');
570 if (pChar != NULL)
571 {
572 *pChar = 0;
98762401 573 iface.dwIndex = _tcstoul(pBuf, NULL, 10);
5039dede
AK
574 pBuf = pChar + 1;
575 }
576
577 // Address and mask
578 pChar = _tcschr(pBuf, _T(' '));
579 if (pChar != NULL)
580 {
581 TCHAR *pSlash;
582 static TCHAR defaultMask[] = _T("24");
583
584 *pChar = 0;
585 pSlash = _tcschr(pBuf, _T('/'));
586 if (pSlash != NULL)
587 {
588 *pSlash = 0;
589 pSlash++;
590 }
591 else // Just a paranoia protection, should'n happen if agent working correctly
592 {
593 pSlash = defaultMask;
594 }
98762401 595 iface.dwIpAddr = ntohl(_t_inet_addr(pBuf));
5039dede 596 dwBits = _tcstoul(pSlash, NULL, 10);
98762401 597 iface.dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
5039dede
AK
598 pBuf = pChar + 1;
599 }
600
601 // Interface type
602 pChar = _tcschr(pBuf, ' ');
603 if (pChar != NULL)
604 {
605 *pChar = 0;
98762401 606 iface.dwType = _tcstoul(pBuf, NULL, 10);
5039dede
AK
607 pBuf = pChar + 1;
608 }
609
610 // MAC address
611 pChar = _tcschr(pBuf, ' ');
612 if (pChar != NULL)
613 {
614 *pChar = 0;
98762401 615 StrToBin(pBuf, iface.bMacAddr, MAC_ADDR_LENGTH);
5039dede
AK
616 pBuf = pChar + 1;
617 }
618
478d4ff4
VK
619 // Name (set description to name)
620 nx_strncpy(iface.szName, pBuf, MAX_DB_STRING);
621 nx_strncpy(iface.szDescription, pBuf, MAX_DB_STRING);
98762401
VK
622
623 pIfList->add(&iface);
5039dede
AK
624 }
625
a3050773 626 lock();
7c521895 627 destroyResultData();
a3050773 628 unlock();
5039dede
AK
629 }
630
631 return pIfList;
632}
633
634
635//
636// Get parameter value
637//
638
4687826e 639DWORD AgentConnection::getParameter(const TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
5039dede
AK
640{
641 CSCPMessage msg(m_nProtocolVersion), *pResponse;
642 DWORD dwRqId, dwRetCode;
643
644 if (m_bIsConnected)
645 {
646 dwRqId = m_dwRequestId++;
647 msg.SetCode(CMD_GET_PARAMETER);
648 msg.SetId(dwRqId);
649 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 650 if (sendMessage(&msg))
5039dede 651 {
7c521895 652 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
653 if (pResponse != NULL)
654 {
655 dwRetCode = pResponse->GetVariableLong(VID_RCC);
656 if (dwRetCode == ERR_SUCCESS)
657 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
658 delete pResponse;
659 }
660 else
661 {
662 dwRetCode = ERR_REQUEST_TIMEOUT;
663 }
664 }
665 else
666 {
667 dwRetCode = ERR_CONNECTION_BROKEN;
668 }
669 }
670 else
671 {
672 dwRetCode = ERR_NOT_CONNECTED;
673 }
674
675 return dwRetCode;
676}
677
678
679//
680// Get ARP cache
681//
682
4687826e 683ARP_CACHE *AgentConnection::getArpCache()
5039dede
AK
684{
685 ARP_CACHE *pArpCache = NULL;
686 TCHAR szByte[4], *pBuf, *pChar;
687 DWORD i, j;
688
4687826e 689 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS)
5039dede
AK
690 {
691 // Create empty structure
692 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
693 pArpCache->dwNumEntries = m_dwNumDataLines;
694 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
695 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
696
697 szByte[2] = 0;
698
699 // Parse data lines
700 // Each line has form of XXXXXXXXXXXX a.b.c.d n
701 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
702 // a.b.c.d is an IP address in decimal dotted notation
703 // n is an interface index
704 for(i = 0; i < m_dwNumDataLines; i++)
705 {
706 pBuf = m_ppDataLines[i];
707 if (_tcslen(pBuf) < 20) // Invalid line
708 continue;
709
710 // MAC address
711 for(j = 0; j < 6; j++)
712 {
713 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
714 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
715 pBuf+=2;
716 }
717
718 // IP address
719 while(*pBuf == ' ')
720 pBuf++;
721 pChar = _tcschr(pBuf, _T(' '));
722 if (pChar != NULL)
723 *pChar = 0;
724 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
725
726 // Interface index
727 if (pChar != NULL)
728 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
729 }
730
a3050773 731 lock();
7c521895 732 destroyResultData();
a3050773 733 unlock();
5039dede
AK
734 }
735 return pArpCache;
736}
737
738
739//
740// Send dummy command to agent (can be used for keepalive)
741//
742
7c521895 743DWORD AgentConnection::nop()
5039dede
AK
744{
745 CSCPMessage msg(m_nProtocolVersion);
746 DWORD dwRqId;
747
748 dwRqId = m_dwRequestId++;
749 msg.SetCode(CMD_KEEPALIVE);
750 msg.SetId(dwRqId);
7c521895
VK
751 if (sendMessage(&msg))
752 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
753 else
754 return ERR_CONNECTION_BROKEN;
755}
756
757
758//
759// Wait for request completion code
760//
761
7c521895 762DWORD AgentConnection::waitForRCC(DWORD dwRqId, DWORD dwTimeOut)
5039dede
AK
763{
764 CSCPMessage *pMsg;
765 DWORD dwRetCode;
766
c17f6cbc 767 pMsg = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
5039dede
AK
768 if (pMsg != NULL)
769 {
770 dwRetCode = pMsg->GetVariableLong(VID_RCC);
771 delete pMsg;
772 }
773 else
774 {
775 dwRetCode = ERR_REQUEST_TIMEOUT;
776 }
777 return dwRetCode;
778}
779
780
781//
782// Send message to agent
783//
784
7c521895 785BOOL AgentConnection::sendMessage(CSCPMessage *pMsg)
5039dede 786{
5039dede
AK
787 BOOL bResult;
788
98abc9f1
VK
789 CSCP_MESSAGE *pRawMsg = pMsg->CreateMessage();
790 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
791 if (pCtx != NULL)
5039dede 792 {
98abc9f1 793 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(pCtx, pRawMsg);
5039dede
AK
794 if (pEnMsg != NULL)
795 {
d3a7cf4c 796 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
5039dede
AK
797 free(pEnMsg);
798 }
799 else
800 {
801 bResult = FALSE;
802 }
98abc9f1 803 pCtx->decRefCount();
5039dede
AK
804 }
805 else
806 {
d3a7cf4c 807 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
5039dede
AK
808 }
809 free(pRawMsg);
810 return bResult;
811}
812
d51f2182
VK
813/**
814 * Trap handler. Should be overriden in derived classes to implement
815 * actual trap processing. Default implementation do nothing.
816 */
f480bdd4
VK
817void AgentConnection::onTrap(CSCPMessage *pMsg)
818{
819}
820
d51f2182
VK
821/**
822 * Data push handler. Should be overriden in derived classes to implement
823 * actual data push processing. Default implementation do nothing.
824 */
f480bdd4 825void AgentConnection::onDataPush(CSCPMessage *pMsg)
5039dede
AK
826{
827}
828
d51f2182
VK
829/**
830 * Custom message handler
831 * If returns true, message considered as processed and will not be placed in wait queue
832 */
90284364
VK
833bool AgentConnection::processCustomMessage(CSCPMessage *pMsg)
834{
835 return false;
836}
837
d51f2182
VK
838/**
839 * Get list of values
840 */
4687826e 841DWORD AgentConnection::getList(const TCHAR *pszParam)
5039dede
AK
842{
843 CSCPMessage msg(m_nProtocolVersion), *pResponse;
844 DWORD i, dwRqId, dwRetCode;
845
846 if (m_bIsConnected)
847 {
7c521895 848 destroyResultData();
5039dede
AK
849 dwRqId = m_dwRequestId++;
850 msg.SetCode(CMD_GET_LIST);
851 msg.SetId(dwRqId);
852 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 853 if (sendMessage(&msg))
5039dede 854 {
7c521895 855 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
856 if (pResponse != NULL)
857 {
858 dwRetCode = pResponse->GetVariableLong(VID_RCC);
859 if (dwRetCode == ERR_SUCCESS)
860 {
861 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
862 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
863 for(i = 0; i < m_dwNumDataLines; i++)
864 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
865 }
866 delete pResponse;
867 }
868 else
869 {
870 dwRetCode = ERR_REQUEST_TIMEOUT;
871 }
872 }
873 else
874 {
875 dwRetCode = ERR_CONNECTION_BROKEN;
876 }
877 }
878 else
879 {
880 dwRetCode = ERR_NOT_CONNECTED;
881 }
882
883 return dwRetCode;
884}
885
d51f2182
VK
886/**
887 * Get table
888 */
4687826e
VK
889DWORD AgentConnection::getTable(const TCHAR *pszParam, Table **table)
890{
891 CSCPMessage msg(m_nProtocolVersion), *pResponse;
892 DWORD dwRqId, dwRetCode;
893
894 *table = NULL;
895 if (m_bIsConnected)
896 {
897 dwRqId = m_dwRequestId++;
898 msg.SetCode(CMD_GET_TABLE);
899 msg.SetId(dwRqId);
900 msg.SetVariable(VID_PARAMETER, pszParam);
901 if (sendMessage(&msg))
902 {
903 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
904 if (pResponse != NULL)
905 {
906 dwRetCode = pResponse->GetVariableLong(VID_RCC);
907 if (dwRetCode == ERR_SUCCESS)
908 {
909 *table = new Table(pResponse);
910 }
911 delete pResponse;
912 }
913 else
914 {
915 dwRetCode = ERR_REQUEST_TIMEOUT;
916 }
917 }
918 else
919 {
920 dwRetCode = ERR_CONNECTION_BROKEN;
921 }
922 }
923 else
924 {
925 dwRetCode = ERR_NOT_CONNECTED;
926 }
927
928 return dwRetCode;
929}
930
931
5039dede
AK
932//
933// Authenticate to agent
934//
935
7c521895 936DWORD AgentConnection::authenticate(BOOL bProxyData)
5039dede
AK
937{
938 CSCPMessage msg(m_nProtocolVersion);
939 DWORD dwRqId;
940 BYTE hash[32];
941 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
08b214c6 942 const char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
5039dede
AK
943#ifdef UNICODE
944 WCHAR szBuffer[MAX_SECRET_LENGTH];
945#endif
946
947 if (iAuthMethod == AUTH_NONE)
948 return ERR_SUCCESS; // No authentication required
949
950 dwRqId = m_dwRequestId++;
951 msg.SetCode(CMD_AUTHENTICATE);
952 msg.SetId(dwRqId);
953 msg.SetVariable(VID_AUTH_METHOD, (WORD)iAuthMethod);
954 switch(iAuthMethod)
955 {
956 case AUTH_PLAINTEXT:
957#ifdef UNICODE
958 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
959 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
960#else
961 msg.SetVariable(VID_SHARED_SECRET, pszSecret);
962#endif
963 break;
964 case AUTH_MD5_HASH:
965 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
966 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
967 break;
968 case AUTH_SHA1_HASH:
969 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
970 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
971 break;
972 default:
973 break;
974 }
7c521895
VK
975 if (sendMessage(&msg))
976 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
977 else
978 return ERR_CONNECTION_BROKEN;
979}
980
981
982//
983// Execute action on agent
984//
985
4687826e 986DWORD AgentConnection::execAction(const TCHAR *pszAction, int argc, TCHAR **argv)
5039dede
AK
987{
988 CSCPMessage msg(m_nProtocolVersion);
989 DWORD dwRqId;
990 int i;
991
992 if (!m_bIsConnected)
993 return ERR_NOT_CONNECTED;
994
995 dwRqId = m_dwRequestId++;
996 msg.SetCode(CMD_ACTION);
997 msg.SetId(dwRqId);
998 msg.SetVariable(VID_ACTION_NAME, pszAction);
999 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
1000 for(i = 0; i < argc; i++)
1001 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
1002
7c521895
VK
1003 if (sendMessage(&msg))
1004 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1005 else
1006 return ERR_CONNECTION_BROKEN;
1007}
1008
1009
1010//
1011// Upload file to agent
1012//
1013
619e5c9b 1014DWORD AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede
AK
1015{
1016 DWORD dwRqId, dwResult;
1017 CSCPMessage msg(m_nProtocolVersion);
1018 int i;
1019
1020 if (!m_bIsConnected)
1021 return ERR_NOT_CONNECTED;
1022
1023 dwRqId = m_dwRequestId++;
1024
1025 msg.SetCode(CMD_TRANSFER_FILE);
1026 msg.SetId(dwRqId);
619e5c9b
VK
1027 for(i = (int)_tcslen(localFile) - 1;
1028 (i >= 0) && (localFile[i] != '\\') && (localFile[i] != '/'); i--);
1029 msg.SetVariable(VID_FILE_NAME, &localFile[i + 1]);
1030 if (destinationFile != NULL)
f0c1d2a4 1031 {
619e5c9b 1032 msg.SetVariable(VID_DESTINATION_FILE_NAME, destinationFile);
f0c1d2a4 1033 }
5039dede 1034
7c521895 1035 if (sendMessage(&msg))
5039dede 1036 {
7c521895 1037 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1038 }
1039 else
1040 {
1041 dwResult = ERR_CONNECTION_BROKEN;
1042 }
1043
1044 if (dwResult == ERR_SUCCESS)
1045 {
4685a2ad 1046 m_fileUploadInProgress = true;
98abc9f1
VK
1047 NXCPEncryptionContext *ctx = acquireEncryptionContext();
1048 if (SendFileOverNXCP(m_hSocket, dwRqId, localFile, ctx, 0, progressCallback, cbArg, m_mutexSocketWrite))
7c521895 1049 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1050 else
1051 dwResult = ERR_IO_FAILURE;
4685a2ad 1052 m_fileUploadInProgress = false;
5039dede
AK
1053 }
1054
1055 return dwResult;
1056}
1057
1058
1059//
1060// Send upgrade command
1061//
1062
4687826e 1063DWORD AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede
AK
1064{
1065 DWORD dwRqId, dwResult;
1066 CSCPMessage msg(m_nProtocolVersion);
1067 int i;
1068
1069 if (!m_bIsConnected)
1070 return ERR_NOT_CONNECTED;
1071
1072 dwRqId = m_dwRequestId++;
1073
1074 msg.SetCode(CMD_UPGRADE_AGENT);
1075 msg.SetId(dwRqId);
1076 for(i = (int)_tcslen(pszPkgName) - 1;
1077 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
1078 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
1079
7c521895 1080 if (sendMessage(&msg))
5039dede 1081 {
7c521895 1082 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1083 }
1084 else
1085 {
1086 dwResult = ERR_CONNECTION_BROKEN;
1087 }
1088
1089 return dwResult;
1090}
1091
1092
1093//
1094// Check status of network service via agent
1095//
1096
4687826e 1097DWORD AgentConnection::checkNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
5039dede
AK
1098 WORD wPort, WORD wProto,
1099 const TCHAR *pszRequest, const TCHAR *pszResponse)
1100{
1101 DWORD dwRqId, dwResult;
1102 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1103 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
1104
1105 if (!m_bIsConnected)
1106 return ERR_NOT_CONNECTED;
1107
1108 dwRqId = m_dwRequestId++;
1109
1110 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
1111 msg.SetId(dwRqId);
1112 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
1113 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
1114 msg.SetVariable(VID_IP_PORT,
1115 (wPort != 0) ? wPort :
1116 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
1117 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
1118 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1119 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1120 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
1121
7c521895 1122 if (sendMessage(&msg))
5039dede
AK
1123 {
1124 // Wait up to 90 seconds for results
7c521895 1125 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
5039dede
AK
1126 if (pResponse != NULL)
1127 {
1128 dwResult = pResponse->GetVariableLong(VID_RCC);
1129 if (dwResult == ERR_SUCCESS)
1130 {
1131 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
1132 }
1133 delete pResponse;
1134 }
1135 else
1136 {
1137 dwResult = ERR_REQUEST_TIMEOUT;
1138 }
1139 }
1140 else
1141 {
1142 dwResult = ERR_CONNECTION_BROKEN;
1143 }
1144
1145 return dwResult;
1146}
1147
074498ac
VK
1148/**
1149 * Get list of supported parameters from subagent
1150 */
cc8ce218 1151DWORD AgentConnection::getSupportedParameters(StructArray<NXC_AGENT_PARAM> **paramList, StructArray<NXC_AGENT_TABLE> **tableList)
5039dede 1152{
cc8ce218 1153 DWORD dwRqId, dwResult;
5039dede
AK
1154 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1155
cc8ce218
VK
1156 *paramList = NULL;
1157 *tableList = NULL;
5039dede
AK
1158
1159 if (!m_bIsConnected)
1160 return ERR_NOT_CONNECTED;
1161
1162 dwRqId = m_dwRequestId++;
1163
1164 msg.SetCode(CMD_GET_PARAMETER_LIST);
1165 msg.SetId(dwRqId);
1166
7c521895 1167 if (sendMessage(&msg))
5039dede 1168 {
7c521895 1169 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1170 if (pResponse != NULL)
1171 {
1172 dwResult = pResponse->GetVariableLong(VID_RCC);
cc8ce218 1173 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1174 if (dwResult == ERR_SUCCESS)
1175 {
cc8ce218
VK
1176 DWORD count = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
1177 NXC_AGENT_PARAM *plist = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * count);
1178 for(DWORD i = 0, dwId = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1179 {
cc8ce218
VK
1180 pResponse->GetVariableStr(dwId++, plist[i].szName, MAX_PARAM_NAME);
1181 pResponse->GetVariableStr(dwId++, plist[i].szDescription, MAX_DB_STRING);
1182 plist[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
5039dede 1183 }
cc8ce218
VK
1184 *paramList = new StructArray<NXC_AGENT_PARAM>(plist, (int)count);
1185 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1186
1187 count = pResponse->GetVariableLong(VID_NUM_TABLES);
1188 NXC_AGENT_TABLE *tlist = (NXC_AGENT_TABLE *)malloc(sizeof(NXC_AGENT_TABLE) * count);
1189 for(DWORD i = 0, dwId = VID_TABLE_LIST_BASE; i < count; i++)
1190 {
1191 pResponse->GetVariableStr(dwId++, tlist[i].name, MAX_PARAM_NAME);
1192 pResponse->GetVariableStr(dwId++, tlist[i].instanceColumn, MAX_DB_STRING);
1193 pResponse->GetVariableStr(dwId++, tlist[i].description, MAX_DB_STRING);
1194 }
1195 *tableList = new StructArray<NXC_AGENT_TABLE>(tlist, (int)count);
1196 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1197 }
5039dede
AK
1198 delete pResponse;
1199 }
1200 else
1201 {
1202 dwResult = ERR_REQUEST_TIMEOUT;
1203 }
1204 }
1205 else
1206 {
1207 dwResult = ERR_CONNECTION_BROKEN;
1208 }
1209
1210 return dwResult;
1211}
1212
074498ac
VK
1213/**
1214 * Setup encryption
1215 */
7c521895 1216DWORD AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1217{
1218#ifdef _WITH_ENCRYPTION
1219 CSCPMessage msg(m_nProtocolVersion), *pResp;
1220 DWORD dwRqId, dwError, dwResult;
1221
1222 dwRqId = m_dwRequestId++;
1223
9e9d631e 1224 PrepareKeyRequestMsg(&msg, pServerKey, false);
5039dede 1225 msg.SetId(dwRqId);
7c521895 1226 if (sendMessage(&msg))
5039dede 1227 {
7c521895 1228 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1229 if (pResp != NULL)
1230 {
1231 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1232 switch(dwResult)
1233 {
1234 case RCC_SUCCESS:
1235 dwError = ERR_SUCCESS;
1236 break;
1237 case RCC_NO_CIPHERS:
1238 dwError = ERR_NO_CIPHERS;
1239 break;
1240 case RCC_INVALID_PUBLIC_KEY:
1241 dwError = ERR_INVALID_PUBLIC_KEY;
1242 break;
1243 case RCC_INVALID_SESSION_KEY:
1244 dwError = ERR_INVALID_SESSION_KEY;
1245 break;
1246 default:
1247 dwError = ERR_INTERNAL_ERROR;
1248 break;
1249 }
1250 delete pResp;
1251 }
1252 else
1253 {
1254 dwError = ERR_REQUEST_TIMEOUT;
1255 }
1256 }
1257 else
1258 {
1259 dwError = ERR_CONNECTION_BROKEN;
1260 }
1261
1262 return dwError;
1263#else
1264 return ERR_NOT_IMPLEMENTED;
1265#endif
1266}
1267
1268
1269//
1270// Get configuration file from agent
1271//
1272
4687826e 1273DWORD AgentConnection::getConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
5039dede
AK
1274{
1275 DWORD i, dwRqId, dwResult;
1276 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1277#ifdef UNICODE
1278 BYTE *pBuffer;
1279#endif
1280
1281 *ppszConfig = NULL;
1282 *pdwSize = 0;
1283
1284 if (!m_bIsConnected)
1285 return ERR_NOT_CONNECTED;
1286
1287 dwRqId = m_dwRequestId++;
1288
1289 msg.SetCode(CMD_GET_AGENT_CONFIG);
1290 msg.SetId(dwRqId);
1291
7c521895 1292 if (sendMessage(&msg))
5039dede 1293 {
7c521895 1294 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1295 if (pResponse != NULL)
1296 {
1297 dwResult = pResponse->GetVariableLong(VID_RCC);
1298 if (dwResult == ERR_SUCCESS)
1299 {
1300 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1301 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1302#ifdef UNICODE
1303 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1304 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
08b214c6 1305 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pBuffer, *pdwSize, *ppszConfig, *pdwSize);
5039dede
AK
1306 free(pBuffer);
1307#else
1308 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1309#endif
1310 (*ppszConfig)[*pdwSize] = 0;
1311
1312 // We expect text file, so replace all non-printable characters with spaces
1313 for(i = 0; i < *pdwSize; i++)
1314 if (((*ppszConfig)[i] < _T(' ')) &&
1315 ((*ppszConfig)[i] != _T('\t')) &&
1316 ((*ppszConfig)[i] != _T('\r')) &&
1317 ((*ppszConfig)[i] != _T('\n')))
1318 (*ppszConfig)[i] = _T(' ');
1319 }
1320 delete pResponse;
1321 }
1322 else
1323 {
1324 dwResult = ERR_REQUEST_TIMEOUT;
1325 }
1326 }
1327 else
1328 {
1329 dwResult = ERR_CONNECTION_BROKEN;
1330 }
1331
1332 return dwResult;
1333}
1334
1335
1336//
1337// Get configuration file from agent
1338//
1339
45d84f8a 1340DWORD AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede
AK
1341{
1342 DWORD dwRqId, dwResult;
1343 CSCPMessage msg(m_nProtocolVersion);
1344#ifdef UNICODE
1345 int nChars;
1346 BYTE *pBuffer;
1347#endif
1348
1349 if (!m_bIsConnected)
1350 return ERR_NOT_CONNECTED;
1351
1352 dwRqId = m_dwRequestId++;
1353
1354 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1355 msg.SetId(dwRqId);
1356#ifdef UNICODE
465b3f2d 1357 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1358 pBuffer = (BYTE *)malloc(nChars + 1);
1359 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1360 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
5039dede
AK
1361 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1362 free(pBuffer);
1363#else
1364 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (DWORD)strlen(pszConfig));
1365#endif
1366
7c521895 1367 if (sendMessage(&msg))
5039dede 1368 {
7c521895 1369 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1370 }
1371 else
1372 {
1373 dwResult = ERR_CONNECTION_BROKEN;
1374 }
1375
1376 return dwResult;
1377}
1378
1379
1380//
1381// Get routing table from agent
1382//
1383
4687826e 1384ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede
AK
1385{
1386 ROUTING_TABLE *pRT = NULL;
1387 DWORD i, dwBits;
1388 TCHAR *pChar, *pBuf;
1389
4687826e 1390 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
5039dede
AK
1391 {
1392 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1393 pRT->iNumEntries = m_dwNumDataLines;
1394 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1395 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1396 for(i = 0; i < m_dwNumDataLines; i++)
1397 {
1398 pBuf = m_ppDataLines[i];
1399
1400 // Destination address and mask
1401 pChar = _tcschr(pBuf, _T(' '));
1402 if (pChar != NULL)
1403 {
1404 TCHAR *pSlash;
1405 static TCHAR defaultMask[] = _T("24");
1406
1407 *pChar = 0;
1408 pSlash = _tcschr(pBuf, _T('/'));
1409 if (pSlash != NULL)
1410 {
1411 *pSlash = 0;
1412 pSlash++;
1413 }
1414 else // Just a paranoia protection, should'n happen if agent working correctly
1415 {
1416 pSlash = defaultMask;
1417 }
1418 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1419 dwBits = _tcstoul(pSlash, NULL, 10);
1420 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1421 pBuf = pChar + 1;
1422 }
1423
1424 // Next hop address
1425 pChar = _tcschr(pBuf, _T(' '));
1426 if (pChar != NULL)
1427 {
1428 *pChar = 0;
1429 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1430 pBuf = pChar + 1;
1431 }
1432
1433 // Interface index
1434 pChar = _tcschr(pBuf, ' ');
1435 if (pChar != NULL)
1436 {
1437 *pChar = 0;
1438 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1439 pBuf = pChar + 1;
1440 }
1441
1442 // Route type
1443 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1444 }
1445
a3050773 1446 lock();
7c521895 1447 destroyResultData();
a3050773 1448 unlock();
5039dede
AK
1449 }
1450
1451 return pRT;
1452}
1453
1454
1455//
1456// Set proxy information
1457//
1458
7c521895 1459void AgentConnection::setProxy(DWORD dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede
AK
1460{
1461 m_dwProxyAddr = dwAddr;
1462 m_wProxyPort = wPort;
1463 m_iProxyAuth = iAuthMethod;
1464 if (pszSecret != NULL)
1465 {
1466#ifdef UNICODE
1467 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1468 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1469#else
1470 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1471#endif
1472 }
1473 else
1474 {
1475 m_szProxySecret[0] = 0;
1476 }
1477 m_bUseProxy = TRUE;
1478}
1479
1480
1481//
1482// Setup proxy connection
1483//
1484
7c521895 1485DWORD AgentConnection::setupProxyConnection()
5039dede
AK
1486{
1487 CSCPMessage msg(m_nProtocolVersion);
1488 DWORD dwRqId;
1489
1490 dwRqId = m_dwRequestId++;
1491 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1492 msg.SetId(dwRqId);
1493 msg.SetVariable(VID_IP_ADDRESS, (DWORD)ntohl(m_dwAddr));
1494 msg.SetVariable(VID_AGENT_PORT, m_wPort);
7c521895
VK
1495 if (sendMessage(&msg))
1496 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1497 else
1498 return ERR_CONNECTION_BROKEN;
1499}
1500
1501
1502//
1503// Enable trap receiving on connection
1504//
1505
7c521895 1506DWORD AgentConnection::enableTraps()
5039dede
AK
1507{
1508 CSCPMessage msg(m_nProtocolVersion);
1509 DWORD dwRqId;
1510
1511 dwRqId = m_dwRequestId++;
1512 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1513 msg.SetId(dwRqId);
7c521895
VK
1514 if (sendMessage(&msg))
1515 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1516 else
1517 return ERR_CONNECTION_BROKEN;
1518}
1519
1520
1521//
1522// Send custom request to agent
1523//
1524
45d84f8a 1525CSCPMessage *AgentConnection::customRequest(CSCPMessage *pRequest, const TCHAR *recvFile, bool appendFile,
bb85e341 1526 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1527{
1528 DWORD dwRqId, rcc;
1529 CSCPMessage *msg = NULL;
1530
1531 dwRqId = m_dwRequestId++;
1532 pRequest->SetId(dwRqId);
1533 if (recvFile != NULL)
1534 {
7c521895 1535 rcc = prepareFileDownload(recvFile, dwRqId, appendFile, downloadProgressCallback, cbArg);
5039dede
AK
1536 if (rcc != ERR_SUCCESS)
1537 {
1538 // Create fake response message
1539 msg = new CSCPMessage;
1540 msg->SetCode(CMD_REQUEST_COMPLETED);
1541 msg->SetId(dwRqId);
1542 msg->SetVariable(VID_RCC, rcc);
1543 }
1544 }
1545
1546 if (msg == NULL)
1547 {
7c521895 1548 if (sendMessage(pRequest))
5039dede 1549 {
7c521895 1550 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1551 if ((msg != NULL) && (recvFile != NULL))
1552 {
1553 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1554 {
bb85e341 1555 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1556 {
bb85e341 1557 if (!m_fileDownloadSucceeded)
5039dede
AK
1558 {
1559 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
901a5a9b 1560 if (m_deleteFileOnDownloadFailure)
08b214c6 1561 _tremove(recvFile);
5039dede
AK
1562 }
1563 }
1564 else
1565 {
1566 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1567 }
1568 }
1569 else
1570 {
1571 close(m_hCurrFile);
1572 m_hCurrFile = -1;
08b214c6 1573 _tremove(recvFile);
5039dede
AK
1574 }
1575 }
1576 }
1577 }
1578
1579 return msg;
1580}
1581
1582
1583//
1584// Prepare for file upload
1585//
1586
7c521895 1587DWORD AgentConnection::prepareFileDownload(const TCHAR *fileName, DWORD rqId, bool append,
bb85e341 1588 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1589{
1590 if (m_hCurrFile != -1)
1591 return ERR_RESOURCE_BUSY;
1592
9f6d453a 1593 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
bb85e341 1594 ConditionReset(m_condFileDownload);
08b214c6 1595 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
901a5a9b
VK
1596 if (m_hCurrFile == -1)
1597 {
1598 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1599 fileName, _tcserror(errno), append, rqId);
1600 }
1601 else
1602 {
1603 if (append)
1604 lseek(m_hCurrFile, 0, SEEK_END);
1605 }
bb85e341
VK
1606 m_dwDownloadRequestId = rqId;
1607 m_downloadProgressCallback = downloadProgressCallback;
1608 m_downloadProgressCallbackArg = cbArg;
5039dede
AK
1609 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1610}
1611
1612
1613//
1614// File upload completion handler
1615//
1616
f480bdd4 1617void AgentConnection::onFileDownload(BOOL success)
5039dede 1618{
901a5a9b
VK
1619 if (!success && m_deleteFileOnDownloadFailure)
1620 _tremove(m_currentFileName);
bb85e341
VK
1621 m_fileDownloadSucceeded = success;
1622 ConditionSet(m_condFileDownload);
5039dede 1623}
1f385e47
VK
1624
1625
1626//
1627// Enable trap receiving on connection
1628//
1629
1630DWORD AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1631{
1632 CSCPMessage msg(m_nProtocolVersion);
1633 DWORD dwRqId, rcc;
1634
1635 *info = NULL;
1636 dwRqId = m_dwRequestId++;
1637 msg.SetCode(CMD_GET_POLICY_INVENTORY);
1638 msg.SetId(dwRqId);
1639 if (sendMessage(&msg))
1640 {
1641 CSCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1642 if (response != NULL)
1643 {
1644 rcc = response->GetVariableLong(VID_RCC);
1645 if (rcc == ERR_SUCCESS)
1646 *info = new AgentPolicyInfo(response);
1647 delete response;
1648 }
1649 else
1650 {
1651 rcc = ERR_REQUEST_TIMEOUT;
1652 }
1653 }
1654 else
1655 {
1656 rcc = ERR_CONNECTION_BROKEN;
1657 }
1658 return rcc;
1659}
1660
1661
1662//
1663// Uninstall policy by GUID
1664//
1665
1666DWORD AgentConnection::uninstallPolicy(uuid_t guid)
1667{
1668 DWORD rqId, rcc;
1669 CSCPMessage msg(m_nProtocolVersion);
1670
1671 rqId = generateRequestId();
1672 msg.SetId(rqId);
1673 msg.SetCode(CMD_UNINSTALL_AGENT_POLICY);
1674 msg.SetVariable(VID_GUID, guid, UUID_LENGTH);
1675 if (sendMessage(&msg))
1676 {
1677 rcc = waitForRCC(rqId, m_dwCommandTimeout);
1678 }
1679 else
1680 {
1681 rcc = ERR_CONNECTION_BROKEN;
1682 }
1683 return rcc;
1684}
98abc9f1
VK
1685
1686
1687//
1688// Acquire encryption context
1689//
1690
1691NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
1692{
a3050773 1693 lock();
98abc9f1
VK
1694 NXCPEncryptionContext *ctx = m_pCtx;
1695 if (ctx != NULL)
1696 ctx->incRefCount();
a3050773 1697 unlock();
98abc9f1
VK
1698 return ctx;
1699}