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