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