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