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