Implemented list "FileSystem.MountPoints" for Windows
[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
547
548//
549// Get interface list from agent
550//
551
98762401 552InterfaceList *AgentConnection::getInterfaceList()
5039dede 553{
98762401 554 InterfaceList *pIfList = NULL;
36e44abe 555 NX_INTERFACE_INFO iface;
5039dede
AK
556 DWORD i, dwBits;
557 TCHAR *pChar, *pBuf;
558
4687826e 559 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS)
5039dede 560 {
98762401 561 pIfList = new InterfaceList(m_dwNumDataLines);
5039dede
AK
562
563 // Parse result set. Each line should have the following format:
564 // index ip_address/mask_bits iftype mac_address name
565 for(i = 0; i < m_dwNumDataLines; i++)
566 {
567 pBuf = m_ppDataLines[i];
36e44abe 568 memset(&iface, 0, sizeof(NX_INTERFACE_INFO));
5039dede
AK
569
570 // Index
571 pChar = _tcschr(pBuf, ' ');
572 if (pChar != NULL)
573 {
574 *pChar = 0;
98762401 575 iface.dwIndex = _tcstoul(pBuf, NULL, 10);
5039dede
AK
576 pBuf = pChar + 1;
577 }
578
579 // Address and mask
580 pChar = _tcschr(pBuf, _T(' '));
581 if (pChar != NULL)
582 {
583 TCHAR *pSlash;
584 static TCHAR defaultMask[] = _T("24");
585
586 *pChar = 0;
587 pSlash = _tcschr(pBuf, _T('/'));
588 if (pSlash != NULL)
589 {
590 *pSlash = 0;
591 pSlash++;
592 }
593 else // Just a paranoia protection, should'n happen if agent working correctly
594 {
595 pSlash = defaultMask;
596 }
98762401 597 iface.dwIpAddr = ntohl(_t_inet_addr(pBuf));
5039dede 598 dwBits = _tcstoul(pSlash, NULL, 10);
98762401 599 iface.dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
5039dede
AK
600 pBuf = pChar + 1;
601 }
602
603 // Interface type
604 pChar = _tcschr(pBuf, ' ');
605 if (pChar != NULL)
606 {
607 *pChar = 0;
98762401 608 iface.dwType = _tcstoul(pBuf, NULL, 10);
5039dede
AK
609 pBuf = pChar + 1;
610 }
611
612 // MAC address
613 pChar = _tcschr(pBuf, ' ');
614 if (pChar != NULL)
615 {
616 *pChar = 0;
98762401 617 StrToBin(pBuf, iface.bMacAddr, MAC_ADDR_LENGTH);
5039dede
AK
618 pBuf = pChar + 1;
619 }
620
478d4ff4
VK
621 // Name (set description to name)
622 nx_strncpy(iface.szName, pBuf, MAX_DB_STRING);
623 nx_strncpy(iface.szDescription, pBuf, MAX_DB_STRING);
98762401
VK
624
625 pIfList->add(&iface);
5039dede
AK
626 }
627
a3050773 628 lock();
7c521895 629 destroyResultData();
a3050773 630 unlock();
5039dede
AK
631 }
632
633 return pIfList;
634}
635
636
637//
638// Get parameter value
639//
640
4687826e 641DWORD AgentConnection::getParameter(const TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
5039dede
AK
642{
643 CSCPMessage msg(m_nProtocolVersion), *pResponse;
644 DWORD dwRqId, dwRetCode;
645
646 if (m_bIsConnected)
647 {
648 dwRqId = m_dwRequestId++;
649 msg.SetCode(CMD_GET_PARAMETER);
650 msg.SetId(dwRqId);
651 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 652 if (sendMessage(&msg))
5039dede 653 {
7c521895 654 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
655 if (pResponse != NULL)
656 {
657 dwRetCode = pResponse->GetVariableLong(VID_RCC);
658 if (dwRetCode == ERR_SUCCESS)
659 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
660 delete pResponse;
661 }
662 else
663 {
664 dwRetCode = ERR_REQUEST_TIMEOUT;
665 }
666 }
667 else
668 {
669 dwRetCode = ERR_CONNECTION_BROKEN;
670 }
671 }
672 else
673 {
674 dwRetCode = ERR_NOT_CONNECTED;
675 }
676
677 return dwRetCode;
678}
679
680
681//
682// Get ARP cache
683//
684
4687826e 685ARP_CACHE *AgentConnection::getArpCache()
5039dede
AK
686{
687 ARP_CACHE *pArpCache = NULL;
688 TCHAR szByte[4], *pBuf, *pChar;
689 DWORD i, j;
690
4687826e 691 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS)
5039dede
AK
692 {
693 // Create empty structure
694 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
695 pArpCache->dwNumEntries = m_dwNumDataLines;
696 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
697 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
698
699 szByte[2] = 0;
700
701 // Parse data lines
702 // Each line has form of XXXXXXXXXXXX a.b.c.d n
703 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
704 // a.b.c.d is an IP address in decimal dotted notation
705 // n is an interface index
706 for(i = 0; i < m_dwNumDataLines; i++)
707 {
708 pBuf = m_ppDataLines[i];
709 if (_tcslen(pBuf) < 20) // Invalid line
710 continue;
711
712 // MAC address
713 for(j = 0; j < 6; j++)
714 {
715 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
716 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
717 pBuf+=2;
718 }
719
720 // IP address
721 while(*pBuf == ' ')
722 pBuf++;
723 pChar = _tcschr(pBuf, _T(' '));
724 if (pChar != NULL)
725 *pChar = 0;
726 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
727
728 // Interface index
729 if (pChar != NULL)
730 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
731 }
732
a3050773 733 lock();
7c521895 734 destroyResultData();
a3050773 735 unlock();
5039dede
AK
736 }
737 return pArpCache;
738}
739
740
741//
742// Send dummy command to agent (can be used for keepalive)
743//
744
7c521895 745DWORD AgentConnection::nop()
5039dede
AK
746{
747 CSCPMessage msg(m_nProtocolVersion);
748 DWORD dwRqId;
749
750 dwRqId = m_dwRequestId++;
751 msg.SetCode(CMD_KEEPALIVE);
752 msg.SetId(dwRqId);
7c521895
VK
753 if (sendMessage(&msg))
754 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
755 else
756 return ERR_CONNECTION_BROKEN;
757}
758
759
760//
761// Wait for request completion code
762//
763
7c521895 764DWORD AgentConnection::waitForRCC(DWORD dwRqId, DWORD dwTimeOut)
5039dede
AK
765{
766 CSCPMessage *pMsg;
767 DWORD dwRetCode;
768
c17f6cbc 769 pMsg = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
5039dede
AK
770 if (pMsg != NULL)
771 {
772 dwRetCode = pMsg->GetVariableLong(VID_RCC);
773 delete pMsg;
774 }
775 else
776 {
777 dwRetCode = ERR_REQUEST_TIMEOUT;
778 }
779 return dwRetCode;
780}
781
782
783//
784// Send message to agent
785//
786
7c521895 787BOOL AgentConnection::sendMessage(CSCPMessage *pMsg)
5039dede 788{
5039dede
AK
789 BOOL bResult;
790
98abc9f1
VK
791 CSCP_MESSAGE *pRawMsg = pMsg->CreateMessage();
792 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
793 if (pCtx != NULL)
5039dede 794 {
98abc9f1 795 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(pCtx, pRawMsg);
5039dede
AK
796 if (pEnMsg != NULL)
797 {
d3a7cf4c 798 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
5039dede
AK
799 free(pEnMsg);
800 }
801 else
802 {
803 bResult = FALSE;
804 }
98abc9f1 805 pCtx->decRefCount();
5039dede
AK
806 }
807 else
808 {
d3a7cf4c 809 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
5039dede
AK
810 }
811 free(pRawMsg);
812 return bResult;
813}
814
815
816//
817// Trap handler. Should be overriden in derived classes to implement
818// actual trap processing. Default implementation do nothing.
819//
820
f480bdd4
VK
821void AgentConnection::onTrap(CSCPMessage *pMsg)
822{
823}
824
825
826//
827// Data push handler. Should be overriden in derived classes to implement
828// actual data push processing. Default implementation do nothing.
829//
830
831void AgentConnection::onDataPush(CSCPMessage *pMsg)
5039dede
AK
832{
833}
834
835
90284364
VK
836//
837// Custom message handler
838// If returns true, message considered as processed and will not be placed in wait queue
839//
840
841bool AgentConnection::processCustomMessage(CSCPMessage *pMsg)
842{
843 return false;
844}
845
846
5039dede
AK
847//
848// Get list of values
849//
850
4687826e 851DWORD AgentConnection::getList(const TCHAR *pszParam)
5039dede
AK
852{
853 CSCPMessage msg(m_nProtocolVersion), *pResponse;
854 DWORD i, dwRqId, dwRetCode;
855
856 if (m_bIsConnected)
857 {
7c521895 858 destroyResultData();
5039dede
AK
859 dwRqId = m_dwRequestId++;
860 msg.SetCode(CMD_GET_LIST);
861 msg.SetId(dwRqId);
862 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 863 if (sendMessage(&msg))
5039dede 864 {
7c521895 865 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
866 if (pResponse != NULL)
867 {
868 dwRetCode = pResponse->GetVariableLong(VID_RCC);
869 if (dwRetCode == ERR_SUCCESS)
870 {
871 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
872 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
873 for(i = 0; i < m_dwNumDataLines; i++)
874 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
875 }
876 delete pResponse;
877 }
878 else
879 {
880 dwRetCode = ERR_REQUEST_TIMEOUT;
881 }
882 }
883 else
884 {
885 dwRetCode = ERR_CONNECTION_BROKEN;
886 }
887 }
888 else
889 {
890 dwRetCode = ERR_NOT_CONNECTED;
891 }
892
893 return dwRetCode;
894}
895
896
4687826e
VK
897//
898// Get table
899//
900
901DWORD AgentConnection::getTable(const TCHAR *pszParam, Table **table)
902{
903 CSCPMessage msg(m_nProtocolVersion), *pResponse;
904 DWORD dwRqId, dwRetCode;
905
906 *table = NULL;
907 if (m_bIsConnected)
908 {
909 dwRqId = m_dwRequestId++;
910 msg.SetCode(CMD_GET_TABLE);
911 msg.SetId(dwRqId);
912 msg.SetVariable(VID_PARAMETER, pszParam);
913 if (sendMessage(&msg))
914 {
915 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
916 if (pResponse != NULL)
917 {
918 dwRetCode = pResponse->GetVariableLong(VID_RCC);
919 if (dwRetCode == ERR_SUCCESS)
920 {
921 *table = new Table(pResponse);
922 }
923 delete pResponse;
924 }
925 else
926 {
927 dwRetCode = ERR_REQUEST_TIMEOUT;
928 }
929 }
930 else
931 {
932 dwRetCode = ERR_CONNECTION_BROKEN;
933 }
934 }
935 else
936 {
937 dwRetCode = ERR_NOT_CONNECTED;
938 }
939
940 return dwRetCode;
941}
942
943
5039dede
AK
944//
945// Authenticate to agent
946//
947
7c521895 948DWORD AgentConnection::authenticate(BOOL bProxyData)
5039dede
AK
949{
950 CSCPMessage msg(m_nProtocolVersion);
951 DWORD dwRqId;
952 BYTE hash[32];
953 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
08b214c6 954 const char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
5039dede
AK
955#ifdef UNICODE
956 WCHAR szBuffer[MAX_SECRET_LENGTH];
957#endif
958
959 if (iAuthMethod == AUTH_NONE)
960 return ERR_SUCCESS; // No authentication required
961
962 dwRqId = m_dwRequestId++;
963 msg.SetCode(CMD_AUTHENTICATE);
964 msg.SetId(dwRqId);
965 msg.SetVariable(VID_AUTH_METHOD, (WORD)iAuthMethod);
966 switch(iAuthMethod)
967 {
968 case AUTH_PLAINTEXT:
969#ifdef UNICODE
970 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
971 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
972#else
973 msg.SetVariable(VID_SHARED_SECRET, pszSecret);
974#endif
975 break;
976 case AUTH_MD5_HASH:
977 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
978 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
979 break;
980 case AUTH_SHA1_HASH:
981 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
982 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
983 break;
984 default:
985 break;
986 }
7c521895
VK
987 if (sendMessage(&msg))
988 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
989 else
990 return ERR_CONNECTION_BROKEN;
991}
992
993
994//
995// Execute action on agent
996//
997
4687826e 998DWORD AgentConnection::execAction(const TCHAR *pszAction, int argc, TCHAR **argv)
5039dede
AK
999{
1000 CSCPMessage msg(m_nProtocolVersion);
1001 DWORD dwRqId;
1002 int i;
1003
1004 if (!m_bIsConnected)
1005 return ERR_NOT_CONNECTED;
1006
1007 dwRqId = m_dwRequestId++;
1008 msg.SetCode(CMD_ACTION);
1009 msg.SetId(dwRqId);
1010 msg.SetVariable(VID_ACTION_NAME, pszAction);
1011 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
1012 for(i = 0; i < argc; i++)
1013 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
1014
7c521895
VK
1015 if (sendMessage(&msg))
1016 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1017 else
1018 return ERR_CONNECTION_BROKEN;
1019}
1020
1021
1022//
1023// Upload file to agent
1024//
1025
619e5c9b 1026DWORD AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede
AK
1027{
1028 DWORD dwRqId, dwResult;
1029 CSCPMessage msg(m_nProtocolVersion);
1030 int i;
1031
1032 if (!m_bIsConnected)
1033 return ERR_NOT_CONNECTED;
1034
1035 dwRqId = m_dwRequestId++;
1036
1037 msg.SetCode(CMD_TRANSFER_FILE);
1038 msg.SetId(dwRqId);
619e5c9b
VK
1039 for(i = (int)_tcslen(localFile) - 1;
1040 (i >= 0) && (localFile[i] != '\\') && (localFile[i] != '/'); i--);
1041 msg.SetVariable(VID_FILE_NAME, &localFile[i + 1]);
1042 if (destinationFile != NULL)
f0c1d2a4 1043 {
619e5c9b 1044 msg.SetVariable(VID_DESTINATION_FILE_NAME, destinationFile);
f0c1d2a4 1045 }
5039dede 1046
7c521895 1047 if (sendMessage(&msg))
5039dede 1048 {
7c521895 1049 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1050 }
1051 else
1052 {
1053 dwResult = ERR_CONNECTION_BROKEN;
1054 }
1055
1056 if (dwResult == ERR_SUCCESS)
1057 {
4685a2ad 1058 m_fileUploadInProgress = true;
98abc9f1
VK
1059 NXCPEncryptionContext *ctx = acquireEncryptionContext();
1060 if (SendFileOverNXCP(m_hSocket, dwRqId, localFile, ctx, 0, progressCallback, cbArg, m_mutexSocketWrite))
7c521895 1061 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1062 else
1063 dwResult = ERR_IO_FAILURE;
4685a2ad 1064 m_fileUploadInProgress = false;
5039dede
AK
1065 }
1066
1067 return dwResult;
1068}
1069
1070
1071//
1072// Send upgrade command
1073//
1074
4687826e 1075DWORD AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede
AK
1076{
1077 DWORD dwRqId, dwResult;
1078 CSCPMessage msg(m_nProtocolVersion);
1079 int i;
1080
1081 if (!m_bIsConnected)
1082 return ERR_NOT_CONNECTED;
1083
1084 dwRqId = m_dwRequestId++;
1085
1086 msg.SetCode(CMD_UPGRADE_AGENT);
1087 msg.SetId(dwRqId);
1088 for(i = (int)_tcslen(pszPkgName) - 1;
1089 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
1090 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
1091
7c521895 1092 if (sendMessage(&msg))
5039dede 1093 {
7c521895 1094 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1095 }
1096 else
1097 {
1098 dwResult = ERR_CONNECTION_BROKEN;
1099 }
1100
1101 return dwResult;
1102}
1103
1104
1105//
1106// Check status of network service via agent
1107//
1108
4687826e 1109DWORD AgentConnection::checkNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
5039dede
AK
1110 WORD wPort, WORD wProto,
1111 const TCHAR *pszRequest, const TCHAR *pszResponse)
1112{
1113 DWORD dwRqId, dwResult;
1114 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1115 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
1116
1117 if (!m_bIsConnected)
1118 return ERR_NOT_CONNECTED;
1119
1120 dwRqId = m_dwRequestId++;
1121
1122 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
1123 msg.SetId(dwRqId);
1124 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
1125 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
1126 msg.SetVariable(VID_IP_PORT,
1127 (wPort != 0) ? wPort :
1128 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
1129 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
1130 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1131 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1132 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
1133
7c521895 1134 if (sendMessage(&msg))
5039dede
AK
1135 {
1136 // Wait up to 90 seconds for results
7c521895 1137 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
5039dede
AK
1138 if (pResponse != NULL)
1139 {
1140 dwResult = pResponse->GetVariableLong(VID_RCC);
1141 if (dwResult == ERR_SUCCESS)
1142 {
1143 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
1144 }
1145 delete pResponse;
1146 }
1147 else
1148 {
1149 dwResult = ERR_REQUEST_TIMEOUT;
1150 }
1151 }
1152 else
1153 {
1154 dwResult = ERR_CONNECTION_BROKEN;
1155 }
1156
1157 return dwResult;
1158}
1159
074498ac
VK
1160/**
1161 * Get list of supported parameters from subagent
1162 */
cc8ce218 1163DWORD AgentConnection::getSupportedParameters(StructArray<NXC_AGENT_PARAM> **paramList, StructArray<NXC_AGENT_TABLE> **tableList)
5039dede 1164{
cc8ce218 1165 DWORD dwRqId, dwResult;
5039dede
AK
1166 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1167
cc8ce218
VK
1168 *paramList = NULL;
1169 *tableList = NULL;
5039dede
AK
1170
1171 if (!m_bIsConnected)
1172 return ERR_NOT_CONNECTED;
1173
1174 dwRqId = m_dwRequestId++;
1175
1176 msg.SetCode(CMD_GET_PARAMETER_LIST);
1177 msg.SetId(dwRqId);
1178
7c521895 1179 if (sendMessage(&msg))
5039dede 1180 {
7c521895 1181 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1182 if (pResponse != NULL)
1183 {
1184 dwResult = pResponse->GetVariableLong(VID_RCC);
cc8ce218 1185 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1186 if (dwResult == ERR_SUCCESS)
1187 {
cc8ce218
VK
1188 DWORD count = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
1189 NXC_AGENT_PARAM *plist = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * count);
1190 for(DWORD i = 0, dwId = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1191 {
cc8ce218
VK
1192 pResponse->GetVariableStr(dwId++, plist[i].szName, MAX_PARAM_NAME);
1193 pResponse->GetVariableStr(dwId++, plist[i].szDescription, MAX_DB_STRING);
1194 plist[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
5039dede 1195 }
cc8ce218
VK
1196 *paramList = new StructArray<NXC_AGENT_PARAM>(plist, (int)count);
1197 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1198
1199 count = pResponse->GetVariableLong(VID_NUM_TABLES);
1200 NXC_AGENT_TABLE *tlist = (NXC_AGENT_TABLE *)malloc(sizeof(NXC_AGENT_TABLE) * count);
1201 for(DWORD i = 0, dwId = VID_TABLE_LIST_BASE; i < count; i++)
1202 {
1203 pResponse->GetVariableStr(dwId++, tlist[i].name, MAX_PARAM_NAME);
1204 pResponse->GetVariableStr(dwId++, tlist[i].instanceColumn, MAX_DB_STRING);
1205 pResponse->GetVariableStr(dwId++, tlist[i].description, MAX_DB_STRING);
1206 }
1207 *tableList = new StructArray<NXC_AGENT_TABLE>(tlist, (int)count);
1208 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1209 }
5039dede
AK
1210 delete pResponse;
1211 }
1212 else
1213 {
1214 dwResult = ERR_REQUEST_TIMEOUT;
1215 }
1216 }
1217 else
1218 {
1219 dwResult = ERR_CONNECTION_BROKEN;
1220 }
1221
1222 return dwResult;
1223}
1224
074498ac
VK
1225/**
1226 * Setup encryption
1227 */
7c521895 1228DWORD AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1229{
1230#ifdef _WITH_ENCRYPTION
1231 CSCPMessage msg(m_nProtocolVersion), *pResp;
1232 DWORD dwRqId, dwError, dwResult;
1233
1234 dwRqId = m_dwRequestId++;
1235
9e9d631e 1236 PrepareKeyRequestMsg(&msg, pServerKey, false);
5039dede 1237 msg.SetId(dwRqId);
7c521895 1238 if (sendMessage(&msg))
5039dede 1239 {
7c521895 1240 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1241 if (pResp != NULL)
1242 {
1243 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1244 switch(dwResult)
1245 {
1246 case RCC_SUCCESS:
1247 dwError = ERR_SUCCESS;
1248 break;
1249 case RCC_NO_CIPHERS:
1250 dwError = ERR_NO_CIPHERS;
1251 break;
1252 case RCC_INVALID_PUBLIC_KEY:
1253 dwError = ERR_INVALID_PUBLIC_KEY;
1254 break;
1255 case RCC_INVALID_SESSION_KEY:
1256 dwError = ERR_INVALID_SESSION_KEY;
1257 break;
1258 default:
1259 dwError = ERR_INTERNAL_ERROR;
1260 break;
1261 }
1262 delete pResp;
1263 }
1264 else
1265 {
1266 dwError = ERR_REQUEST_TIMEOUT;
1267 }
1268 }
1269 else
1270 {
1271 dwError = ERR_CONNECTION_BROKEN;
1272 }
1273
1274 return dwError;
1275#else
1276 return ERR_NOT_IMPLEMENTED;
1277#endif
1278}
1279
1280
1281//
1282// Get configuration file from agent
1283//
1284
4687826e 1285DWORD AgentConnection::getConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
5039dede
AK
1286{
1287 DWORD i, dwRqId, dwResult;
1288 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1289#ifdef UNICODE
1290 BYTE *pBuffer;
1291#endif
1292
1293 *ppszConfig = NULL;
1294 *pdwSize = 0;
1295
1296 if (!m_bIsConnected)
1297 return ERR_NOT_CONNECTED;
1298
1299 dwRqId = m_dwRequestId++;
1300
1301 msg.SetCode(CMD_GET_AGENT_CONFIG);
1302 msg.SetId(dwRqId);
1303
7c521895 1304 if (sendMessage(&msg))
5039dede 1305 {
7c521895 1306 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1307 if (pResponse != NULL)
1308 {
1309 dwResult = pResponse->GetVariableLong(VID_RCC);
1310 if (dwResult == ERR_SUCCESS)
1311 {
1312 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1313 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1314#ifdef UNICODE
1315 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1316 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
08b214c6 1317 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pBuffer, *pdwSize, *ppszConfig, *pdwSize);
5039dede
AK
1318 free(pBuffer);
1319#else
1320 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1321#endif
1322 (*ppszConfig)[*pdwSize] = 0;
1323
1324 // We expect text file, so replace all non-printable characters with spaces
1325 for(i = 0; i < *pdwSize; i++)
1326 if (((*ppszConfig)[i] < _T(' ')) &&
1327 ((*ppszConfig)[i] != _T('\t')) &&
1328 ((*ppszConfig)[i] != _T('\r')) &&
1329 ((*ppszConfig)[i] != _T('\n')))
1330 (*ppszConfig)[i] = _T(' ');
1331 }
1332 delete pResponse;
1333 }
1334 else
1335 {
1336 dwResult = ERR_REQUEST_TIMEOUT;
1337 }
1338 }
1339 else
1340 {
1341 dwResult = ERR_CONNECTION_BROKEN;
1342 }
1343
1344 return dwResult;
1345}
1346
1347
1348//
1349// Get configuration file from agent
1350//
1351
45d84f8a 1352DWORD AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede
AK
1353{
1354 DWORD dwRqId, dwResult;
1355 CSCPMessage msg(m_nProtocolVersion);
1356#ifdef UNICODE
1357 int nChars;
1358 BYTE *pBuffer;
1359#endif
1360
1361 if (!m_bIsConnected)
1362 return ERR_NOT_CONNECTED;
1363
1364 dwRqId = m_dwRequestId++;
1365
1366 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1367 msg.SetId(dwRqId);
1368#ifdef UNICODE
465b3f2d 1369 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1370 pBuffer = (BYTE *)malloc(nChars + 1);
1371 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1372 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
5039dede
AK
1373 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1374 free(pBuffer);
1375#else
1376 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (DWORD)strlen(pszConfig));
1377#endif
1378
7c521895 1379 if (sendMessage(&msg))
5039dede 1380 {
7c521895 1381 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1382 }
1383 else
1384 {
1385 dwResult = ERR_CONNECTION_BROKEN;
1386 }
1387
1388 return dwResult;
1389}
1390
1391
1392//
1393// Get routing table from agent
1394//
1395
4687826e 1396ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede
AK
1397{
1398 ROUTING_TABLE *pRT = NULL;
1399 DWORD i, dwBits;
1400 TCHAR *pChar, *pBuf;
1401
4687826e 1402 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
5039dede
AK
1403 {
1404 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1405 pRT->iNumEntries = m_dwNumDataLines;
1406 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1407 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1408 for(i = 0; i < m_dwNumDataLines; i++)
1409 {
1410 pBuf = m_ppDataLines[i];
1411
1412 // Destination address and mask
1413 pChar = _tcschr(pBuf, _T(' '));
1414 if (pChar != NULL)
1415 {
1416 TCHAR *pSlash;
1417 static TCHAR defaultMask[] = _T("24");
1418
1419 *pChar = 0;
1420 pSlash = _tcschr(pBuf, _T('/'));
1421 if (pSlash != NULL)
1422 {
1423 *pSlash = 0;
1424 pSlash++;
1425 }
1426 else // Just a paranoia protection, should'n happen if agent working correctly
1427 {
1428 pSlash = defaultMask;
1429 }
1430 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1431 dwBits = _tcstoul(pSlash, NULL, 10);
1432 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1433 pBuf = pChar + 1;
1434 }
1435
1436 // Next hop address
1437 pChar = _tcschr(pBuf, _T(' '));
1438 if (pChar != NULL)
1439 {
1440 *pChar = 0;
1441 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1442 pBuf = pChar + 1;
1443 }
1444
1445 // Interface index
1446 pChar = _tcschr(pBuf, ' ');
1447 if (pChar != NULL)
1448 {
1449 *pChar = 0;
1450 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1451 pBuf = pChar + 1;
1452 }
1453
1454 // Route type
1455 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1456 }
1457
a3050773 1458 lock();
7c521895 1459 destroyResultData();
a3050773 1460 unlock();
5039dede
AK
1461 }
1462
1463 return pRT;
1464}
1465
1466
1467//
1468// Set proxy information
1469//
1470
7c521895 1471void AgentConnection::setProxy(DWORD dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede
AK
1472{
1473 m_dwProxyAddr = dwAddr;
1474 m_wProxyPort = wPort;
1475 m_iProxyAuth = iAuthMethod;
1476 if (pszSecret != NULL)
1477 {
1478#ifdef UNICODE
1479 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1480 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1481#else
1482 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1483#endif
1484 }
1485 else
1486 {
1487 m_szProxySecret[0] = 0;
1488 }
1489 m_bUseProxy = TRUE;
1490}
1491
1492
1493//
1494// Setup proxy connection
1495//
1496
7c521895 1497DWORD AgentConnection::setupProxyConnection()
5039dede
AK
1498{
1499 CSCPMessage msg(m_nProtocolVersion);
1500 DWORD dwRqId;
1501
1502 dwRqId = m_dwRequestId++;
1503 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1504 msg.SetId(dwRqId);
1505 msg.SetVariable(VID_IP_ADDRESS, (DWORD)ntohl(m_dwAddr));
1506 msg.SetVariable(VID_AGENT_PORT, m_wPort);
7c521895
VK
1507 if (sendMessage(&msg))
1508 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1509 else
1510 return ERR_CONNECTION_BROKEN;
1511}
1512
1513
1514//
1515// Enable trap receiving on connection
1516//
1517
7c521895 1518DWORD AgentConnection::enableTraps()
5039dede
AK
1519{
1520 CSCPMessage msg(m_nProtocolVersion);
1521 DWORD dwRqId;
1522
1523 dwRqId = m_dwRequestId++;
1524 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1525 msg.SetId(dwRqId);
7c521895
VK
1526 if (sendMessage(&msg))
1527 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1528 else
1529 return ERR_CONNECTION_BROKEN;
1530}
1531
1532
1533//
1534// Send custom request to agent
1535//
1536
45d84f8a 1537CSCPMessage *AgentConnection::customRequest(CSCPMessage *pRequest, const TCHAR *recvFile, bool appendFile,
bb85e341 1538 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1539{
1540 DWORD dwRqId, rcc;
1541 CSCPMessage *msg = NULL;
1542
1543 dwRqId = m_dwRequestId++;
1544 pRequest->SetId(dwRqId);
1545 if (recvFile != NULL)
1546 {
7c521895 1547 rcc = prepareFileDownload(recvFile, dwRqId, appendFile, downloadProgressCallback, cbArg);
5039dede
AK
1548 if (rcc != ERR_SUCCESS)
1549 {
1550 // Create fake response message
1551 msg = new CSCPMessage;
1552 msg->SetCode(CMD_REQUEST_COMPLETED);
1553 msg->SetId(dwRqId);
1554 msg->SetVariable(VID_RCC, rcc);
1555 }
1556 }
1557
1558 if (msg == NULL)
1559 {
7c521895 1560 if (sendMessage(pRequest))
5039dede 1561 {
7c521895 1562 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1563 if ((msg != NULL) && (recvFile != NULL))
1564 {
1565 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1566 {
bb85e341 1567 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1568 {
bb85e341 1569 if (!m_fileDownloadSucceeded)
5039dede
AK
1570 {
1571 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
901a5a9b 1572 if (m_deleteFileOnDownloadFailure)
08b214c6 1573 _tremove(recvFile);
5039dede
AK
1574 }
1575 }
1576 else
1577 {
1578 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1579 }
1580 }
1581 else
1582 {
1583 close(m_hCurrFile);
1584 m_hCurrFile = -1;
08b214c6 1585 _tremove(recvFile);
5039dede
AK
1586 }
1587 }
1588 }
1589 }
1590
1591 return msg;
1592}
1593
1594
1595//
1596// Prepare for file upload
1597//
1598
7c521895 1599DWORD AgentConnection::prepareFileDownload(const TCHAR *fileName, DWORD rqId, bool append,
bb85e341 1600 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1601{
1602 if (m_hCurrFile != -1)
1603 return ERR_RESOURCE_BUSY;
1604
9f6d453a 1605 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
bb85e341 1606 ConditionReset(m_condFileDownload);
08b214c6 1607 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
901a5a9b
VK
1608 if (m_hCurrFile == -1)
1609 {
1610 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1611 fileName, _tcserror(errno), append, rqId);
1612 }
1613 else
1614 {
1615 if (append)
1616 lseek(m_hCurrFile, 0, SEEK_END);
1617 }
bb85e341
VK
1618 m_dwDownloadRequestId = rqId;
1619 m_downloadProgressCallback = downloadProgressCallback;
1620 m_downloadProgressCallbackArg = cbArg;
5039dede
AK
1621 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1622}
1623
1624
1625//
1626// File upload completion handler
1627//
1628
f480bdd4 1629void AgentConnection::onFileDownload(BOOL success)
5039dede 1630{
901a5a9b
VK
1631 if (!success && m_deleteFileOnDownloadFailure)
1632 _tremove(m_currentFileName);
bb85e341
VK
1633 m_fileDownloadSucceeded = success;
1634 ConditionSet(m_condFileDownload);
5039dede 1635}
1f385e47
VK
1636
1637
1638//
1639// Enable trap receiving on connection
1640//
1641
1642DWORD AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1643{
1644 CSCPMessage msg(m_nProtocolVersion);
1645 DWORD dwRqId, rcc;
1646
1647 *info = NULL;
1648 dwRqId = m_dwRequestId++;
1649 msg.SetCode(CMD_GET_POLICY_INVENTORY);
1650 msg.SetId(dwRqId);
1651 if (sendMessage(&msg))
1652 {
1653 CSCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1654 if (response != NULL)
1655 {
1656 rcc = response->GetVariableLong(VID_RCC);
1657 if (rcc == ERR_SUCCESS)
1658 *info = new AgentPolicyInfo(response);
1659 delete response;
1660 }
1661 else
1662 {
1663 rcc = ERR_REQUEST_TIMEOUT;
1664 }
1665 }
1666 else
1667 {
1668 rcc = ERR_CONNECTION_BROKEN;
1669 }
1670 return rcc;
1671}
1672
1673
1674//
1675// Uninstall policy by GUID
1676//
1677
1678DWORD AgentConnection::uninstallPolicy(uuid_t guid)
1679{
1680 DWORD rqId, rcc;
1681 CSCPMessage msg(m_nProtocolVersion);
1682
1683 rqId = generateRequestId();
1684 msg.SetId(rqId);
1685 msg.SetCode(CMD_UNINSTALL_AGENT_POLICY);
1686 msg.SetVariable(VID_GUID, guid, UUID_LENGTH);
1687 if (sendMessage(&msg))
1688 {
1689 rcc = waitForRCC(rqId, m_dwCommandTimeout);
1690 }
1691 else
1692 {
1693 rcc = ERR_CONNECTION_BROKEN;
1694 }
1695 return rcc;
1696}
98abc9f1
VK
1697
1698
1699//
1700// Acquire encryption context
1701//
1702
1703NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
1704{
a3050773 1705 lock();
98abc9f1
VK
1706 NXCPEncryptionContext *ctx = m_pCtx;
1707 if (ctx != NULL)
1708 ctx->incRefCount();
a3050773 1709 unlock();
98abc9f1
VK
1710 return ctx;
1711}