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