Merge branch 'develop' of 10.3.0.4:public/netxms into develop
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server Library
0f506caa 4** Copyright (C) 2003-2013 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
0702ed69
VK
7** it under the terms of the GNU Lesser General Public License as published by
8** the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
0702ed69 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
25#include <stdarg.h>
26
f00612ba
VK
27#ifdef _WIN32
28#define open _open
29#define close _close
30#define write _write
8c1befb6 31#else
ff198273 32#define _tell(f) lseek(f,0,SEEK_CUR)
f00612ba
VK
33#endif
34
a3050773
VK
35/**
36 * Constants
37 */
8f4f648d 38#define MAX_MSG_SIZE 8388608
5039dede 39
a3050773
VK
40/**
41 * Static data
42 */
5039dede
AK
43#ifdef _WITH_ENCRYPTION
44static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
45#else
46static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
47#endif
48
a3050773
VK
49/**
50 * Set default encryption policy for agent communication
51 */
5039dede
AK
52void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
53{
54#ifdef _WITH_ENCRYPTION
55 m_iDefaultEncryptionPolicy = iPolicy;
56#endif
57}
58
a3050773
VK
59/**
60 * Receiver thread starter
61 */
62THREAD_RESULT THREAD_CALL AgentConnection::receiverThreadStarter(void *pArg)
5039dede 63{
a3050773 64 ((AgentConnection *)pArg)->receiverThread();
5039dede
AK
65 return THREAD_OK;
66}
67
a3050773
VK
68/**
69 * Constructor for AgentConnection
70 */
69c6604d 71AgentConnection::AgentConnection(UINT32 ipAddr, WORD port, int authMethod, const TCHAR *secret)
5039dede 72{
69c6604d
VK
73 m_dwAddr = ipAddr;
74 m_wPort = port;
75 m_iAuthMethod = authMethod;
76 if (secret != NULL)
5039dede
AK
77 {
78#ifdef UNICODE
69c6604d 79 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
08b214c6 80 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
5039dede 81#else
69c6604d 82 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
5039dede
AK
83#endif
84 }
85 else
86 {
87 m_szSecret[0] = 0;
88 }
89 m_hSocket = -1;
90 m_tLastCommandTime = 0;
91 m_dwNumDataLines = 0;
92 m_ppDataLines = NULL;
93 m_pMsgWaitQueue = new MsgWaitQueue;
94 m_dwRequestId = 1;
7c521895 95 m_connectionTimeout = 30000; // 30 seconds
5039dede
AK
96 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
97 m_bIsConnected = FALSE;
98 m_mutexDataLock = MutexCreate();
d3a7cf4c 99 m_mutexSocketWrite = MutexCreate();
5039dede
AK
100 m_hReceiverThread = INVALID_THREAD_HANDLE;
101 m_pCtx = NULL;
102 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
103 m_bUseProxy = FALSE;
104 m_dwRecvTimeout = 420000; // 7 minutes
105 m_nProtocolVersion = NXCP_VERSION;
106 m_hCurrFile = -1;
901a5a9b 107 m_deleteFileOnDownloadFailure = true;
bb85e341 108 m_condFileDownload = ConditionCreate(TRUE);
4685a2ad 109 m_fileUploadInProgress = false;
5039dede
AK
110}
111
a3050773
VK
112/**
113 * Destructor
114 */
5039dede
AK
115AgentConnection::~AgentConnection()
116{
117 // Disconnect from peer
7c521895 118 disconnect();
5039dede
AK
119
120 // Wait for receiver thread termination
121 ThreadJoin(m_hReceiverThread);
122
123 // Close socket if active
a3050773 124 lock();
5039dede
AK
125 if (m_hSocket != -1)
126 {
127 closesocket(m_hSocket);
128 m_hSocket = -1;
129 }
a3050773 130 unlock();
5039dede 131
a3050773 132 lock();
7c521895 133 destroyResultData();
a3050773 134 unlock();
5039dede
AK
135
136 delete m_pMsgWaitQueue;
98abc9f1
VK
137 if (m_pCtx != NULL)
138 m_pCtx->decRefCount();
5039dede
AK
139
140 if (m_hCurrFile != -1)
9f6d453a 141 {
5039dede 142 close(m_hCurrFile);
f480bdd4 143 onFileDownload(FALSE);
9f6d453a 144 }
5039dede
AK
145
146 MutexDestroy(m_mutexDataLock);
d3a7cf4c 147 MutexDestroy(m_mutexSocketWrite);
bb85e341 148 ConditionDestroy(m_condFileDownload);
5039dede
AK
149}
150
a3050773
VK
151/**
152 * Print message. This method is virtual and can be overrided in
153 * derived classes. Default implementation will print message to stdout.
154 */
af21affe 155void AgentConnection::printMsg(const TCHAR *format, ...)
5039dede
AK
156{
157 va_list args;
158
af21affe
VK
159 va_start(args, format);
160 _vtprintf(format, args);
5039dede
AK
161 va_end(args);
162 _tprintf(_T("\n"));
163}
164
a3050773
VK
165/**
166 * Receiver thread
167 */
168void AgentConnection::receiverThread()
5039dede 169{
967893bb 170 UINT32 msgBufferSize = 1024;
5039dede
AK
171 CSCPMessage *pMsg;
172 CSCP_MESSAGE *pRawMsg;
173 CSCP_BUFFER *pMsgBuffer;
174 BYTE *pDecryptionBuffer = NULL;
4685a2ad 175 int error;
5039dede
AK
176 TCHAR szBuffer[128], szIpAddr[16];
177 SOCKET nSocket;
178
179 // Initialize raw message receiving function
180 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
181 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
182
183 // Allocate space for raw message
8f4f648d 184 pRawMsg = (CSCP_MESSAGE *)malloc(msgBufferSize);
5039dede 185#ifdef _WITH_ENCRYPTION
8f4f648d 186 pDecryptionBuffer = (BYTE *)malloc(msgBufferSize);
5039dede
AK
187#endif
188
189 // Message receiving loop
190 while(1)
191 {
8f4f648d
VK
192 // Shrink buffer after receiving large message
193 if (msgBufferSize > 131072)
194 {
195 msgBufferSize = 131072;
196 pRawMsg = (CSCP_MESSAGE *)realloc(pRawMsg, msgBufferSize);
197 if (pDecryptionBuffer != NULL)
198 pDecryptionBuffer = (BYTE *)realloc(pDecryptionBuffer, msgBufferSize);
199 }
200
5039dede 201 // Receive raw message
a3050773 202 lock();
5039dede 203 nSocket = m_hSocket;
a3050773 204 unlock();
8f4f648d
VK
205 if ((error = RecvNXCPMessageEx(nSocket, &pRawMsg, pMsgBuffer, &msgBufferSize,
206 &m_pCtx, (pDecryptionBuffer != NULL) ? &pDecryptionBuffer : NULL,
207 m_dwRecvTimeout, MAX_MSG_SIZE)) <= 0)
5039dede 208 {
a2069340
VK
209 if (WSAGetLastError() != WSAESHUTDOWN)
210 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), error, WSAGetLastError());
5039dede
AK
211 break;
212 }
213
214 // Check if we get too large message
4685a2ad 215 if (error == 1)
5039dede 216 {
a3050773 217 printMsg(_T("Received too large message %s (%d bytes)"),
5039dede
AK
218 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
219 ntohl(pRawMsg->dwSize));
220 continue;
221 }
222
223 // Check if we are unable to decrypt message
4685a2ad 224 if (error == 2)
5039dede 225 {
a3050773 226 printMsg(_T("Unable to decrypt received message"));
5039dede
AK
227 continue;
228 }
229
230 // Check for timeout
4685a2ad 231 if (error == 3)
5039dede 232 {
4685a2ad
VK
233 if (m_fileUploadInProgress)
234 continue; // Receive timeout may occur when uploading large files via slow links
a3050773 235 printMsg(_T("Timed out waiting for message"));
5039dede
AK
236 break;
237 }
238
239 // Check that actual received packet size is equal to encoded in packet
4685a2ad 240 if ((int)ntohl(pRawMsg->dwSize) != error)
5039dede 241 {
a3050773 242 printMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), error);
5039dede
AK
243 continue; // Bad packet, wait for next
244 }
245
246 if (ntohs(pRawMsg->wFlags) & MF_BINARY)
247 {
248 // Convert message header to host format
249 pRawMsg->dwId = ntohl(pRawMsg->dwId);
250 pRawMsg->wCode = ntohs(pRawMsg->wCode);
251 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
08b214c6 252 DbgPrintf(6, _T("Received raw message %s from agent at %s"),
7c521895 253 NXCPMessageCodeName(pRawMsg->wCode, szBuffer), IpToStr(getIpAddr(), szIpAddr));
5039dede
AK
254
255 if ((pRawMsg->wCode == CMD_FILE_DATA) &&
bb85e341 256 (m_hCurrFile != -1) && (pRawMsg->dwId == m_dwDownloadRequestId))
5039dede
AK
257 {
258 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
259 {
260 if (ntohs(pRawMsg->wFlags) & MF_END_OF_FILE)
261 {
262 close(m_hCurrFile);
263 m_hCurrFile = -1;
264
f480bdd4 265 onFileDownload(TRUE);
5039dede 266 }
bb85e341
VK
267 else
268 {
269 if (m_downloadProgressCallback != NULL)
270 {
901a5a9b 271 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
bb85e341
VK
272 }
273 }
5039dede
AK
274 }
275 else
276 {
277 // I/O error
278 close(m_hCurrFile);
279 m_hCurrFile = -1;
280
f480bdd4 281 onFileDownload(FALSE);
5039dede
AK
282 }
283 }
284 }
285 else
286 {
287 // Create message object from raw message
288 pMsg = new CSCPMessage(pRawMsg, m_nProtocolVersion);
f480bdd4 289 switch(pMsg->GetCode())
5039dede 290 {
f480bdd4
VK
291 case CMD_TRAP:
292 onTrap(pMsg);
293 delete pMsg;
294 break;
295 case CMD_PUSH_DCI_DATA:
296 onDataPush(pMsg);
297 delete pMsg;
298 break;
90284364 299 case CMD_REQUEST_COMPLETED:
c17f6cbc 300 m_pMsgWaitQueue->put(pMsg);
f480bdd4 301 break;
9fa031cd 302 case CMD_FILE_MONITORING:
303 onFileMonitoringData(pMsg);
304 delete pMsg;
305 break;
90284364
VK
306 default:
307 if (processCustomMessage(pMsg))
308 delete pMsg;
309 else
c17f6cbc 310 m_pMsgWaitQueue->put(pMsg);
90284364 311 break;
5039dede
AK
312 }
313 }
314 }
315
316 // Close socket and mark connection as disconnected
a3050773 317 lock();
f2665675
VK
318 if (m_hCurrFile != -1)
319 {
320 close(m_hCurrFile);
321 m_hCurrFile = -1;
f480bdd4 322 onFileDownload(FALSE);
f2665675
VK
323 }
324
4685a2ad 325 if (error == 0)
5039dede
AK
326 shutdown(m_hSocket, SHUT_RDWR);
327 closesocket(m_hSocket);
328 m_hSocket = -1;
98abc9f1
VK
329 if (m_pCtx != NULL)
330 {
331 m_pCtx->decRefCount();
332 m_pCtx = NULL;
333 }
5039dede 334 m_bIsConnected = FALSE;
a3050773 335 unlock();
5039dede
AK
336
337 free(pRawMsg);
338 free(pMsgBuffer);
339#ifdef _WITH_ENCRYPTION
340 free(pDecryptionBuffer);
341#endif
342}
343
a3050773
VK
344/**
345 * Connect to agent
346 */
967893bb 347BOOL AgentConnection::connect(RSA *pServerKey, BOOL bVerbose, UINT32 *pdwError, UINT32 *pdwSocketError)
5039dede
AK
348{
349 struct sockaddr_in sa;
350 TCHAR szBuffer[256];
351 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
967893bb 352 UINT32 dwError = 0;
5039dede
AK
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);
4c0c75c7 374 if (m_hSocket == INVALID_SOCKET)
5039dede 375 {
a3050773 376 printMsg(_T("Call to socket() failed"));
5039dede
AK
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)
a3050773 398 printMsg(_T("Cannot establish connection with agent %s"),
5039dede
AK
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
a3050773 411 m_hReceiverThread = ThreadCreateEx(receiverThreadStarter, 0, this);
5039dede
AK
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 }
a3050773 445 printMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
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 }
a3050773 459 printMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
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;
a3050773 469 lock();
98abc9f1
VK
470 if (m_pCtx != NULL)
471 {
472 m_pCtx->decRefCount();
473 m_pCtx = NULL;
474 }
a3050773 475 unlock();
5039dede
AK
476 bSecondPass = TRUE;
477 bForceEncryption = FALSE;
478 goto setup_encryption;
479 }
480
481 bSuccess = TRUE;
482 dwError = ERR_SUCCESS;
483
484connect_cleanup:
485 if (!bSuccess)
486 {
c3acd0f6 487 if (pdwSocketError != NULL)
967893bb 488 *pdwSocketError = (UINT32)WSAGetLastError();
c3acd0f6 489
a3050773 490 lock();
5039dede
AK
491 if (m_hSocket != -1)
492 shutdown(m_hSocket, SHUT_RDWR);
a3050773 493 unlock();
5039dede
AK
494 ThreadJoin(m_hReceiverThread);
495 m_hReceiverThread = INVALID_THREAD_HANDLE;
496
a3050773 497 lock();
5039dede
AK
498 if (m_hSocket != -1)
499 {
500 closesocket(m_hSocket);
501 m_hSocket = -1;
502 }
503
98abc9f1
VK
504 if (m_pCtx != NULL)
505 {
506 m_pCtx->decRefCount();
507 m_pCtx = NULL;
508 }
5039dede 509
a3050773 510 unlock();
5039dede
AK
511 }
512 m_bIsConnected = bSuccess;
513 if (pdwError != NULL)
514 *pdwError = dwError;
515 return bSuccess;
516}
517
af21affe
VK
518/**
519 * Disconnect from agent
520 */
7c521895 521void AgentConnection::disconnect()
5039dede 522{
a3050773 523 lock();
f2665675
VK
524 if (m_hCurrFile != -1)
525 {
526 close(m_hCurrFile);
527 m_hCurrFile = -1;
f480bdd4 528 onFileDownload(FALSE);
f2665675 529 }
9fa031cd 530
5039dede
AK
531 if (m_hSocket != -1)
532 {
533 shutdown(m_hSocket, SHUT_RDWR);
534 }
7c521895 535 destroyResultData();
5039dede 536 m_bIsConnected = FALSE;
a3050773 537 unlock();
5039dede
AK
538}
539
af21affe
VK
540/**
541 * Set authentication data
542 */
543void AgentConnection::setAuthData(int method, const TCHAR *secret)
544{
545 m_iAuthMethod = method;
546#ifdef UNICODE
547 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
548 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
549#else
550 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
551#endif
552}
5039dede 553
af21affe
VK
554/**
555 * Destroy command execuion results data
556 */
7c521895 557void AgentConnection::destroyResultData()
5039dede 558{
967893bb 559 UINT32 i;
5039dede
AK
560
561 if (m_ppDataLines != NULL)
562 {
563 for(i = 0; i < m_dwNumDataLines; i++)
564 if (m_ppDataLines[i] != NULL)
565 free(m_ppDataLines[i]);
566 free(m_ppDataLines);
567 m_ppDataLines = NULL;
568 }
569 m_dwNumDataLines = 0;
570}
571
d51f2182
VK
572/**
573 * Get interface list from agent
574 */
98762401 575InterfaceList *AgentConnection::getInterfaceList()
5039dede 576{
98762401 577 InterfaceList *pIfList = NULL;
36e44abe 578 NX_INTERFACE_INFO iface;
967893bb 579 UINT32 i, dwBits;
5039dede
AK
580 TCHAR *pChar, *pBuf;
581
4687826e 582 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS)
5039dede 583 {
98762401 584 pIfList = new InterfaceList(m_dwNumDataLines);
5039dede
AK
585
586 // Parse result set. Each line should have the following format:
587 // index ip_address/mask_bits iftype mac_address name
588 for(i = 0; i < m_dwNumDataLines; i++)
589 {
590 pBuf = m_ppDataLines[i];
36e44abe 591 memset(&iface, 0, sizeof(NX_INTERFACE_INFO));
5039dede
AK
592
593 // Index
594 pChar = _tcschr(pBuf, ' ');
595 if (pChar != NULL)
596 {
597 *pChar = 0;
98762401 598 iface.dwIndex = _tcstoul(pBuf, NULL, 10);
5039dede
AK
599 pBuf = pChar + 1;
600 }
601
602 // Address and mask
603 pChar = _tcschr(pBuf, _T(' '));
604 if (pChar != NULL)
605 {
606 TCHAR *pSlash;
607 static TCHAR defaultMask[] = _T("24");
608
609 *pChar = 0;
610 pSlash = _tcschr(pBuf, _T('/'));
611 if (pSlash != NULL)
612 {
613 *pSlash = 0;
614 pSlash++;
615 }
616 else // Just a paranoia protection, should'n happen if agent working correctly
617 {
618 pSlash = defaultMask;
619 }
98762401 620 iface.dwIpAddr = ntohl(_t_inet_addr(pBuf));
5039dede 621 dwBits = _tcstoul(pSlash, NULL, 10);
98762401 622 iface.dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
5039dede
AK
623 pBuf = pChar + 1;
624 }
625
626 // Interface type
627 pChar = _tcschr(pBuf, ' ');
628 if (pChar != NULL)
629 {
630 *pChar = 0;
98762401 631 iface.dwType = _tcstoul(pBuf, NULL, 10);
5039dede
AK
632 pBuf = pChar + 1;
633 }
634
635 // MAC address
636 pChar = _tcschr(pBuf, ' ');
637 if (pChar != NULL)
638 {
639 *pChar = 0;
98762401 640 StrToBin(pBuf, iface.bMacAddr, MAC_ADDR_LENGTH);
5039dede
AK
641 pBuf = pChar + 1;
642 }
643
478d4ff4
VK
644 // Name (set description to name)
645 nx_strncpy(iface.szName, pBuf, MAX_DB_STRING);
646 nx_strncpy(iface.szDescription, pBuf, MAX_DB_STRING);
98762401
VK
647
648 pIfList->add(&iface);
5039dede
AK
649 }
650
a3050773 651 lock();
7c521895 652 destroyResultData();
a3050773 653 unlock();
5039dede
AK
654 }
655
656 return pIfList;
657}
658
659
660//
661// Get parameter value
662//
663
967893bb 664UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TCHAR *pszBuffer)
5039dede
AK
665{
666 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 667 UINT32 dwRqId, dwRetCode;
5039dede
AK
668
669 if (m_bIsConnected)
670 {
671 dwRqId = m_dwRequestId++;
672 msg.SetCode(CMD_GET_PARAMETER);
673 msg.SetId(dwRqId);
674 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 675 if (sendMessage(&msg))
5039dede 676 {
7c521895 677 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
678 if (pResponse != NULL)
679 {
680 dwRetCode = pResponse->GetVariableLong(VID_RCC);
681 if (dwRetCode == ERR_SUCCESS)
682 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
683 delete pResponse;
684 }
685 else
686 {
687 dwRetCode = ERR_REQUEST_TIMEOUT;
688 }
689 }
690 else
691 {
692 dwRetCode = ERR_CONNECTION_BROKEN;
693 }
694 }
695 else
696 {
697 dwRetCode = ERR_NOT_CONNECTED;
698 }
699
700 return dwRetCode;
701}
702
703
704//
705// Get ARP cache
706//
707
4687826e 708ARP_CACHE *AgentConnection::getArpCache()
5039dede
AK
709{
710 ARP_CACHE *pArpCache = NULL;
711 TCHAR szByte[4], *pBuf, *pChar;
967893bb 712 UINT32 i, j;
5039dede 713
4687826e 714 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS)
5039dede
AK
715 {
716 // Create empty structure
717 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
718 pArpCache->dwNumEntries = m_dwNumDataLines;
719 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
720 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
721
722 szByte[2] = 0;
723
724 // Parse data lines
725 // Each line has form of XXXXXXXXXXXX a.b.c.d n
726 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
727 // a.b.c.d is an IP address in decimal dotted notation
728 // n is an interface index
729 for(i = 0; i < m_dwNumDataLines; i++)
730 {
731 pBuf = m_ppDataLines[i];
732 if (_tcslen(pBuf) < 20) // Invalid line
733 continue;
734
735 // MAC address
736 for(j = 0; j < 6; j++)
737 {
738 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
739 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
740 pBuf+=2;
741 }
742
743 // IP address
744 while(*pBuf == ' ')
745 pBuf++;
746 pChar = _tcschr(pBuf, _T(' '));
747 if (pChar != NULL)
748 *pChar = 0;
749 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
750
751 // Interface index
752 if (pChar != NULL)
753 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
754 }
755
a3050773 756 lock();
7c521895 757 destroyResultData();
a3050773 758 unlock();
5039dede
AK
759 }
760 return pArpCache;
761}
762
763
764//
765// Send dummy command to agent (can be used for keepalive)
766//
767
967893bb 768UINT32 AgentConnection::nop()
5039dede
AK
769{
770 CSCPMessage msg(m_nProtocolVersion);
967893bb 771 UINT32 dwRqId;
5039dede
AK
772
773 dwRqId = m_dwRequestId++;
774 msg.SetCode(CMD_KEEPALIVE);
775 msg.SetId(dwRqId);
7c521895
VK
776 if (sendMessage(&msg))
777 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
778 else
779 return ERR_CONNECTION_BROKEN;
780}
781
782
783//
784// Wait for request completion code
785//
786
967893bb 787UINT32 AgentConnection::waitForRCC(UINT32 dwRqId, UINT32 dwTimeOut)
5039dede
AK
788{
789 CSCPMessage *pMsg;
967893bb 790 UINT32 dwRetCode;
5039dede 791
c17f6cbc 792 pMsg = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
5039dede
AK
793 if (pMsg != NULL)
794 {
795 dwRetCode = pMsg->GetVariableLong(VID_RCC);
796 delete pMsg;
797 }
798 else
799 {
800 dwRetCode = ERR_REQUEST_TIMEOUT;
801 }
802 return dwRetCode;
803}
804
805
806//
807// Send message to agent
808//
809
7c521895 810BOOL AgentConnection::sendMessage(CSCPMessage *pMsg)
5039dede 811{
5039dede
AK
812 BOOL bResult;
813
98abc9f1
VK
814 CSCP_MESSAGE *pRawMsg = pMsg->CreateMessage();
815 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
816 if (pCtx != NULL)
5039dede 817 {
98abc9f1 818 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(pCtx, pRawMsg);
5039dede
AK
819 if (pEnMsg != NULL)
820 {
d3a7cf4c 821 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
5039dede
AK
822 free(pEnMsg);
823 }
824 else
825 {
826 bResult = FALSE;
827 }
98abc9f1 828 pCtx->decRefCount();
5039dede
AK
829 }
830 else
831 {
d3a7cf4c 832 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
5039dede
AK
833 }
834 free(pRawMsg);
835 return bResult;
836}
837
d51f2182
VK
838/**
839 * Trap handler. Should be overriden in derived classes to implement
840 * actual trap processing. Default implementation do nothing.
841 */
f480bdd4
VK
842void AgentConnection::onTrap(CSCPMessage *pMsg)
843{
844}
845
d51f2182
VK
846/**
847 * Data push handler. Should be overriden in derived classes to implement
848 * actual data push processing. Default implementation do nothing.
849 */
f480bdd4 850void AgentConnection::onDataPush(CSCPMessage *pMsg)
5039dede
AK
851{
852}
853
9fa031cd 854/**
855 * Monitoring data handler. Should be overriden in derived classes to implement
856 * actual monitoring data processing. Default implementation do nothing.
857 */
858void AgentConnection::onFileMonitoringData(CSCPMessage *pMsg)
859{
860}
861
d51f2182
VK
862/**
863 * Custom message handler
864 * If returns true, message considered as processed and will not be placed in wait queue
865 */
90284364
VK
866bool AgentConnection::processCustomMessage(CSCPMessage *pMsg)
867{
868 return false;
869}
870
d51f2182
VK
871/**
872 * Get list of values
873 */
967893bb 874UINT32 AgentConnection::getList(const TCHAR *pszParam)
5039dede
AK
875{
876 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 877 UINT32 i, dwRqId, dwRetCode;
5039dede
AK
878
879 if (m_bIsConnected)
880 {
7c521895 881 destroyResultData();
5039dede
AK
882 dwRqId = m_dwRequestId++;
883 msg.SetCode(CMD_GET_LIST);
884 msg.SetId(dwRqId);
885 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 886 if (sendMessage(&msg))
5039dede 887 {
7c521895 888 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
889 if (pResponse != NULL)
890 {
891 dwRetCode = pResponse->GetVariableLong(VID_RCC);
892 if (dwRetCode == ERR_SUCCESS)
893 {
894 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
895 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
896 for(i = 0; i < m_dwNumDataLines; i++)
897 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
898 }
899 delete pResponse;
900 }
901 else
902 {
903 dwRetCode = ERR_REQUEST_TIMEOUT;
904 }
905 }
906 else
907 {
908 dwRetCode = ERR_CONNECTION_BROKEN;
909 }
910 }
911 else
912 {
913 dwRetCode = ERR_NOT_CONNECTED;
914 }
915
916 return dwRetCode;
917}
918
d51f2182
VK
919/**
920 * Get table
921 */
967893bb 922UINT32 AgentConnection::getTable(const TCHAR *pszParam, Table **table)
4687826e
VK
923{
924 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 925 UINT32 dwRqId, dwRetCode;
4687826e
VK
926
927 *table = NULL;
928 if (m_bIsConnected)
929 {
930 dwRqId = m_dwRequestId++;
931 msg.SetCode(CMD_GET_TABLE);
932 msg.SetId(dwRqId);
933 msg.SetVariable(VID_PARAMETER, pszParam);
934 if (sendMessage(&msg))
935 {
936 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
937 if (pResponse != NULL)
938 {
939 dwRetCode = pResponse->GetVariableLong(VID_RCC);
940 if (dwRetCode == ERR_SUCCESS)
941 {
942 *table = new Table(pResponse);
943 }
944 delete pResponse;
945 }
946 else
947 {
948 dwRetCode = ERR_REQUEST_TIMEOUT;
949 }
950 }
951 else
952 {
953 dwRetCode = ERR_CONNECTION_BROKEN;
954 }
955 }
956 else
957 {
958 dwRetCode = ERR_NOT_CONNECTED;
959 }
960
961 return dwRetCode;
962}
963
975f38fc
VK
964/**
965 * Authenticate to agent
966 */
967893bb 967UINT32 AgentConnection::authenticate(BOOL bProxyData)
5039dede
AK
968{
969 CSCPMessage msg(m_nProtocolVersion);
967893bb 970 UINT32 dwRqId;
5039dede
AK
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
967893bb 1017UINT32 AgentConnection::execAction(const TCHAR *pszAction, int argc, TCHAR **argv)
5039dede
AK
1018{
1019 CSCPMessage msg(m_nProtocolVersion);
967893bb 1020 UINT32 dwRqId;
5039dede
AK
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);
967893bb 1030 msg.SetVariable(VID_NUM_ARGS, (UINT32)argc);
5039dede
AK
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
967893bb 1045UINT32 AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede 1046{
967893bb 1047 UINT32 dwRqId, dwResult;
5039dede
AK
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 1078 NXCPEncryptionContext *ctx = acquireEncryptionContext();
9fa031cd 1079 if (SendFileOverNXCP(m_hSocket, dwRqId, localFile, ctx, 0, 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
967893bb 1094UINT32 AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede 1095{
967893bb 1096 UINT32 dwRqId, dwResult;
5039dede
AK
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
967893bb 1128UINT32 AgentConnection::checkNetworkService(UINT32 *pdwStatus, UINT32 dwIpAddr, int iServiceType,
5039dede
AK
1129 WORD wPort, WORD wProto,
1130 const TCHAR *pszRequest, const TCHAR *pszResponse)
1131{
967893bb 1132 UINT32 dwRqId, dwResult;
5039dede
AK
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
074498ac 1179/**
86c126f5 1180 * Get list of supported parameters from agent
074498ac 1181 */
967893bb 1182UINT32 AgentConnection::getSupportedParameters(ObjectArray<AgentParameterDefinition> **paramList, ObjectArray<AgentTableDefinition> **tableList)
5039dede 1183{
967893bb 1184 UINT32 dwRqId, dwResult;
5039dede
AK
1185 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1186
cc8ce218
VK
1187 *paramList = NULL;
1188 *tableList = NULL;
5039dede
AK
1189
1190 if (!m_bIsConnected)
1191 return ERR_NOT_CONNECTED;
1192
1193 dwRqId = m_dwRequestId++;
1194
1195 msg.SetCode(CMD_GET_PARAMETER_LIST);
1196 msg.SetId(dwRqId);
1197
7c521895 1198 if (sendMessage(&msg))
5039dede 1199 {
7c521895 1200 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1201 if (pResponse != NULL)
1202 {
1203 dwResult = pResponse->GetVariableLong(VID_RCC);
cc8ce218 1204 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1205 if (dwResult == ERR_SUCCESS)
1206 {
967893bb 1207 UINT32 count = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
86c126f5 1208 ObjectArray<AgentParameterDefinition> *plist = new ObjectArray<AgentParameterDefinition>(count, 16, true);
967893bb 1209 for(UINT32 i = 0, dwId = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1210 {
86c126f5
VK
1211 plist->add(new AgentParameterDefinition(pResponse, dwId));
1212 dwId += 3;
5039dede 1213 }
86c126f5 1214 *paramList = plist;
cc8ce218
VK
1215 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1216
1217 count = pResponse->GetVariableLong(VID_NUM_TABLES);
86c126f5 1218 ObjectArray<AgentTableDefinition> *tlist = new ObjectArray<AgentTableDefinition>(count, 16, true);
967893bb 1219 for(UINT32 i = 0, dwId = VID_TABLE_LIST_BASE; i < count; i++)
cc8ce218 1220 {
86c126f5
VK
1221 tlist->add(new AgentTableDefinition(pResponse, dwId));
1222 dwId += 3;
cc8ce218 1223 }
86c126f5 1224 *tableList = tlist;
cc8ce218
VK
1225 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1226 }
5039dede
AK
1227 delete pResponse;
1228 }
1229 else
1230 {
1231 dwResult = ERR_REQUEST_TIMEOUT;
1232 }
1233 }
1234 else
1235 {
1236 dwResult = ERR_CONNECTION_BROKEN;
1237 }
1238
1239 return dwResult;
1240}
1241
074498ac
VK
1242/**
1243 * Setup encryption
1244 */
967893bb 1245UINT32 AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1246{
1247#ifdef _WITH_ENCRYPTION
1248 CSCPMessage msg(m_nProtocolVersion), *pResp;
967893bb 1249 UINT32 dwRqId, dwError, dwResult;
5039dede
AK
1250
1251 dwRqId = m_dwRequestId++;
1252
9e9d631e 1253 PrepareKeyRequestMsg(&msg, pServerKey, false);
5039dede 1254 msg.SetId(dwRqId);
7c521895 1255 if (sendMessage(&msg))
5039dede 1256 {
7c521895 1257 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1258 if (pResp != NULL)
1259 {
1260 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1261 switch(dwResult)
1262 {
1263 case RCC_SUCCESS:
1264 dwError = ERR_SUCCESS;
1265 break;
1266 case RCC_NO_CIPHERS:
1267 dwError = ERR_NO_CIPHERS;
1268 break;
1269 case RCC_INVALID_PUBLIC_KEY:
1270 dwError = ERR_INVALID_PUBLIC_KEY;
1271 break;
1272 case RCC_INVALID_SESSION_KEY:
1273 dwError = ERR_INVALID_SESSION_KEY;
1274 break;
1275 default:
1276 dwError = ERR_INTERNAL_ERROR;
1277 break;
1278 }
1279 delete pResp;
1280 }
1281 else
1282 {
1283 dwError = ERR_REQUEST_TIMEOUT;
1284 }
1285 }
1286 else
1287 {
1288 dwError = ERR_CONNECTION_BROKEN;
1289 }
1290
1291 return dwError;
1292#else
1293 return ERR_NOT_IMPLEMENTED;
1294#endif
1295}
1296
1297
1298//
1299// Get configuration file from agent
1300//
1301
967893bb 1302UINT32 AgentConnection::getConfigFile(TCHAR **ppszConfig, UINT32 *pdwSize)
5039dede 1303{
967893bb 1304 UINT32 i, dwRqId, dwResult;
5039dede
AK
1305 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1306#ifdef UNICODE
1307 BYTE *pBuffer;
1308#endif
1309
1310 *ppszConfig = NULL;
1311 *pdwSize = 0;
1312
1313 if (!m_bIsConnected)
1314 return ERR_NOT_CONNECTED;
1315
1316 dwRqId = m_dwRequestId++;
1317
1318 msg.SetCode(CMD_GET_AGENT_CONFIG);
1319 msg.SetId(dwRqId);
1320
7c521895 1321 if (sendMessage(&msg))
5039dede 1322 {
7c521895 1323 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1324 if (pResponse != NULL)
1325 {
1326 dwResult = pResponse->GetVariableLong(VID_RCC);
1327 if (dwResult == ERR_SUCCESS)
1328 {
1329 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1330 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1331#ifdef UNICODE
1332 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1333 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
08b214c6 1334 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pBuffer, *pdwSize, *ppszConfig, *pdwSize);
5039dede
AK
1335 free(pBuffer);
1336#else
1337 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1338#endif
1339 (*ppszConfig)[*pdwSize] = 0;
1340
1341 // We expect text file, so replace all non-printable characters with spaces
1342 for(i = 0; i < *pdwSize; i++)
1343 if (((*ppszConfig)[i] < _T(' ')) &&
1344 ((*ppszConfig)[i] != _T('\t')) &&
1345 ((*ppszConfig)[i] != _T('\r')) &&
1346 ((*ppszConfig)[i] != _T('\n')))
1347 (*ppszConfig)[i] = _T(' ');
1348 }
1349 delete pResponse;
1350 }
1351 else
1352 {
1353 dwResult = ERR_REQUEST_TIMEOUT;
1354 }
1355 }
1356 else
1357 {
1358 dwResult = ERR_CONNECTION_BROKEN;
1359 }
1360
1361 return dwResult;
1362}
1363
1364
1365//
1366// Get configuration file from agent
1367//
1368
967893bb 1369UINT32 AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede 1370{
967893bb 1371 UINT32 dwRqId, dwResult;
5039dede
AK
1372 CSCPMessage msg(m_nProtocolVersion);
1373#ifdef UNICODE
1374 int nChars;
1375 BYTE *pBuffer;
1376#endif
1377
1378 if (!m_bIsConnected)
1379 return ERR_NOT_CONNECTED;
1380
1381 dwRqId = m_dwRequestId++;
1382
1383 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1384 msg.SetId(dwRqId);
1385#ifdef UNICODE
465b3f2d 1386 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1387 pBuffer = (BYTE *)malloc(nChars + 1);
1388 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1389 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
5039dede
AK
1390 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1391 free(pBuffer);
1392#else
967893bb 1393 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (UINT32)strlen(pszConfig));
5039dede
AK
1394#endif
1395
7c521895 1396 if (sendMessage(&msg))
5039dede 1397 {
7c521895 1398 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1399 }
1400 else
1401 {
1402 dwResult = ERR_CONNECTION_BROKEN;
1403 }
1404
1405 return dwResult;
1406}
1407
1408
1409//
1410// Get routing table from agent
1411//
1412
4687826e 1413ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede
AK
1414{
1415 ROUTING_TABLE *pRT = NULL;
967893bb 1416 UINT32 i, dwBits;
5039dede
AK
1417 TCHAR *pChar, *pBuf;
1418
4687826e 1419 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
5039dede
AK
1420 {
1421 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1422 pRT->iNumEntries = m_dwNumDataLines;
1423 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1424 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1425 for(i = 0; i < m_dwNumDataLines; i++)
1426 {
1427 pBuf = m_ppDataLines[i];
1428
1429 // Destination address and mask
1430 pChar = _tcschr(pBuf, _T(' '));
1431 if (pChar != NULL)
1432 {
1433 TCHAR *pSlash;
1434 static TCHAR defaultMask[] = _T("24");
1435
1436 *pChar = 0;
1437 pSlash = _tcschr(pBuf, _T('/'));
1438 if (pSlash != NULL)
1439 {
1440 *pSlash = 0;
1441 pSlash++;
1442 }
1443 else // Just a paranoia protection, should'n happen if agent working correctly
1444 {
1445 pSlash = defaultMask;
1446 }
1447 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1448 dwBits = _tcstoul(pSlash, NULL, 10);
1449 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1450 pBuf = pChar + 1;
1451 }
1452
1453 // Next hop address
1454 pChar = _tcschr(pBuf, _T(' '));
1455 if (pChar != NULL)
1456 {
1457 *pChar = 0;
1458 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1459 pBuf = pChar + 1;
1460 }
1461
1462 // Interface index
1463 pChar = _tcschr(pBuf, ' ');
1464 if (pChar != NULL)
1465 {
1466 *pChar = 0;
1467 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1468 pBuf = pChar + 1;
1469 }
1470
1471 // Route type
1472 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1473 }
1474
a3050773 1475 lock();
7c521895 1476 destroyResultData();
a3050773 1477 unlock();
5039dede
AK
1478 }
1479
1480 return pRT;
1481}
1482
1483
1484//
1485// Set proxy information
1486//
1487
967893bb 1488void AgentConnection::setProxy(UINT32 dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede
AK
1489{
1490 m_dwProxyAddr = dwAddr;
1491 m_wProxyPort = wPort;
1492 m_iProxyAuth = iAuthMethod;
1493 if (pszSecret != NULL)
1494 {
1495#ifdef UNICODE
1496 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1497 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1498#else
1499 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1500#endif
1501 }
1502 else
1503 {
1504 m_szProxySecret[0] = 0;
1505 }
1506 m_bUseProxy = TRUE;
1507}
1508
1509
1510//
1511// Setup proxy connection
1512//
1513
967893bb 1514UINT32 AgentConnection::setupProxyConnection()
5039dede
AK
1515{
1516 CSCPMessage msg(m_nProtocolVersion);
967893bb 1517 UINT32 dwRqId;
5039dede
AK
1518
1519 dwRqId = m_dwRequestId++;
1520 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1521 msg.SetId(dwRqId);
967893bb 1522 msg.SetVariable(VID_IP_ADDRESS, (UINT32)ntohl(m_dwAddr));
5039dede 1523 msg.SetVariable(VID_AGENT_PORT, m_wPort);
7c521895
VK
1524 if (sendMessage(&msg))
1525 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1526 else
1527 return ERR_CONNECTION_BROKEN;
1528}
1529
1530
1531//
1532// Enable trap receiving on connection
1533//
1534
967893bb 1535UINT32 AgentConnection::enableTraps()
5039dede
AK
1536{
1537 CSCPMessage msg(m_nProtocolVersion);
967893bb 1538 UINT32 dwRqId;
5039dede
AK
1539
1540 dwRqId = m_dwRequestId++;
1541 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1542 msg.SetId(dwRqId);
7c521895
VK
1543 if (sendMessage(&msg))
1544 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1545 else
1546 return ERR_CONNECTION_BROKEN;
1547}
1548
1549
1550//
1551// Send custom request to agent
1552//
1553
45d84f8a 1554CSCPMessage *AgentConnection::customRequest(CSCPMessage *pRequest, const TCHAR *recvFile, bool appendFile,
bb85e341 1555 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede 1556{
967893bb 1557 UINT32 dwRqId, rcc;
5039dede
AK
1558 CSCPMessage *msg = NULL;
1559
1560 dwRqId = m_dwRequestId++;
1561 pRequest->SetId(dwRqId);
1562 if (recvFile != NULL)
1563 {
7c521895 1564 rcc = prepareFileDownload(recvFile, dwRqId, appendFile, downloadProgressCallback, cbArg);
5039dede
AK
1565 if (rcc != ERR_SUCCESS)
1566 {
1567 // Create fake response message
1568 msg = new CSCPMessage;
1569 msg->SetCode(CMD_REQUEST_COMPLETED);
1570 msg->SetId(dwRqId);
1571 msg->SetVariable(VID_RCC, rcc);
1572 }
1573 }
1574
1575 if (msg == NULL)
1576 {
7c521895 1577 if (sendMessage(pRequest))
5039dede 1578 {
7c521895 1579 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1580 if ((msg != NULL) && (recvFile != NULL))
1581 {
1582 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1583 {
bb85e341 1584 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1585 {
bb85e341 1586 if (!m_fileDownloadSucceeded)
5039dede
AK
1587 {
1588 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
901a5a9b 1589 if (m_deleteFileOnDownloadFailure)
08b214c6 1590 _tremove(recvFile);
5039dede
AK
1591 }
1592 }
1593 else
1594 {
1595 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1596 }
1597 }
1598 else
1599 {
1600 close(m_hCurrFile);
1601 m_hCurrFile = -1;
08b214c6 1602 _tremove(recvFile);
5039dede
AK
1603 }
1604 }
1605 }
1606 }
1607
1608 return msg;
1609}
1610
1611
1612//
1613// Prepare for file upload
1614//
1615
967893bb 1616UINT32 AgentConnection::prepareFileDownload(const TCHAR *fileName, UINT32 rqId, bool append,
bb85e341 1617 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1618{
1619 if (m_hCurrFile != -1)
1620 return ERR_RESOURCE_BUSY;
1621
9f6d453a 1622 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
bb85e341 1623 ConditionReset(m_condFileDownload);
08b214c6 1624 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
901a5a9b
VK
1625 if (m_hCurrFile == -1)
1626 {
1627 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1628 fileName, _tcserror(errno), append, rqId);
1629 }
1630 else
1631 {
1632 if (append)
1633 lseek(m_hCurrFile, 0, SEEK_END);
1634 }
bb85e341
VK
1635 m_dwDownloadRequestId = rqId;
1636 m_downloadProgressCallback = downloadProgressCallback;
1637 m_downloadProgressCallbackArg = cbArg;
5039dede
AK
1638 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1639}
1640
1641
1642//
1643// File upload completion handler
1644//
1645
f480bdd4 1646void AgentConnection::onFileDownload(BOOL success)
5039dede 1647{
901a5a9b
VK
1648 if (!success && m_deleteFileOnDownloadFailure)
1649 _tremove(m_currentFileName);
bb85e341
VK
1650 m_fileDownloadSucceeded = success;
1651 ConditionSet(m_condFileDownload);
5039dede 1652}
1f385e47
VK
1653
1654
1655//
1656// Enable trap receiving on connection
1657//
1658
967893bb 1659UINT32 AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1f385e47
VK
1660{
1661 CSCPMessage msg(m_nProtocolVersion);
967893bb 1662 UINT32 dwRqId, rcc;
1f385e47
VK
1663
1664 *info = NULL;
1665 dwRqId = m_dwRequestId++;
1666 msg.SetCode(CMD_GET_POLICY_INVENTORY);
1667 msg.SetId(dwRqId);
1668 if (sendMessage(&msg))
1669 {
1670 CSCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1671 if (response != NULL)
1672 {
1673 rcc = response->GetVariableLong(VID_RCC);
1674 if (rcc == ERR_SUCCESS)
1675 *info = new AgentPolicyInfo(response);
1676 delete response;
1677 }
1678 else
1679 {
1680 rcc = ERR_REQUEST_TIMEOUT;
1681 }
1682 }
1683 else
1684 {
1685 rcc = ERR_CONNECTION_BROKEN;
1686 }
1687 return rcc;
1688}
1689
1690
1691//
1692// Uninstall policy by GUID
1693//
1694
967893bb 1695UINT32 AgentConnection::uninstallPolicy(uuid_t guid)
1f385e47 1696{
967893bb 1697 UINT32 rqId, rcc;
1f385e47
VK
1698 CSCPMessage msg(m_nProtocolVersion);
1699
1700 rqId = generateRequestId();
1701 msg.SetId(rqId);
1702 msg.SetCode(CMD_UNINSTALL_AGENT_POLICY);
1703 msg.SetVariable(VID_GUID, guid, UUID_LENGTH);
1704 if (sendMessage(&msg))
1705 {
1706 rcc = waitForRCC(rqId, m_dwCommandTimeout);
1707 }
1708 else
1709 {
1710 rcc = ERR_CONNECTION_BROKEN;
1711 }
1712 return rcc;
1713}
98abc9f1 1714
86c126f5
VK
1715/**
1716 * Acquire encryption context
1717 */
98abc9f1
VK
1718NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
1719{
a3050773 1720 lock();
98abc9f1
VK
1721 NXCPEncryptionContext *ctx = m_pCtx;
1722 if (ctx != NULL)
1723 ctx->incRefCount();
a3050773 1724 unlock();
98abc9f1
VK
1725 return ctx;
1726}
86c126f5
VK
1727
1728/**
1729 * Create new agent parameter definition from NXCP message
1730 */
967893bb 1731AgentParameterDefinition::AgentParameterDefinition(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1732{
1733 m_name = msg->GetVariableStr(baseId);
1734 m_description = msg->GetVariableStr(baseId + 1);
1735 m_dataType = (int)msg->GetVariableShort(baseId + 2);
1736}
1737
1738/**
1739 * Create new agent parameter definition from another definition object
1740 */
1741AgentParameterDefinition::AgentParameterDefinition(AgentParameterDefinition *src)
1742{
1743 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1744 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1745 m_dataType = src->m_dataType;
1746}
1747
1748/**
1749 * Destructor for agent parameter definition
1750 */
1751AgentParameterDefinition::~AgentParameterDefinition()
1752{
1753 safe_free(m_name);
1754 safe_free(m_description);
1755}
1756
1757/**
1758 * Fill NXCP message
1759 */
967893bb 1760UINT32 AgentParameterDefinition::fillMessage(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1761{
1762 msg->SetVariable(baseId, m_name);
1763 msg->SetVariable(baseId + 1, m_description);
1764 msg->SetVariable(baseId + 2, (WORD)m_dataType);
1765 return 3;
1766}
1767
1768/**
1769 * Create new agent table definition from NXCP message
1770 */
967893bb 1771AgentTableDefinition::AgentTableDefinition(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1772{
1773 m_name = msg->GetVariableStr(baseId);
1774 m_description = msg->GetVariableStr(baseId + 2);
1775
1776 TCHAR *instanceColumns = msg->GetVariableStr(baseId + 1);
1777 if (instanceColumns != NULL)
1778 {
1779 m_instanceColumns = new StringList(instanceColumns, _T("|"));
1780 free(instanceColumns);
1781 }
1782 else
1783 {
1784 m_instanceColumns = new StringList;
1785 }
1786
1787 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
1788}
1789
1790/**
1791 * Create new agent table definition from another definition object
1792 */
1793AgentTableDefinition::AgentTableDefinition(AgentTableDefinition *src)
1794{
1795 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1796 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1797 m_instanceColumns = new StringList(src->m_instanceColumns);
1798 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
1799 for(int i = 0; i < src->m_columns->size(); i++)
1800 {
1801 m_columns->add(new AgentTableColumnDefinition(src->m_columns->get(i)));
1802 }
1803}
1804/**
1805 * Destructor for agent table definition
1806 */
1807AgentTableDefinition::~AgentTableDefinition()
1808{
1809 safe_free(m_name);
1810 safe_free(m_description);
1811 delete m_instanceColumns;
1812 delete m_columns;
1813}
1814
1815/**
1816 * Fill NXCP message
1817 */
967893bb 1818UINT32 AgentTableDefinition::fillMessage(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1819{
1820 msg->SetVariable(baseId + 1, m_name);
1821 msg->SetVariable(baseId + 2, m_description);
1822
1823 TCHAR *instanceColumns = m_instanceColumns->join(_T("|"));
1824 msg->SetVariable(baseId + 3, instanceColumns);
1825 free(instanceColumns);
1826
967893bb 1827 UINT32 varId = baseId + 4;
86c126f5
VK
1828 for(int i = 0; i < m_columns->size(); i++)
1829 {
1830 msg->SetVariable(varId++, m_columns->get(i)->m_name);
1831 msg->SetVariable(varId++, (WORD)m_columns->get(i)->m_dataType);
1832 }
1833
1834 msg->SetVariable(baseId, varId - baseId);
1835 return varId - baseId;
1836}