New parameters added
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
f77084bb
VK
1/*
2** NetXMS - Network Management System
3** Server Library
4** Copyright (C) 2003, 2004 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
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**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** $module: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
1ba9a162 25#include <stdarg.h>
f77084bb
VK
26
27
28//
29// Constants
30//
31
32#define RECEIVER_BUFFER_SIZE 262144
33
34
35//
36// Receiver thread starter
37//
38
ccdbbb52 39THREAD_RESULT THREAD_CALL AgentConnection::ReceiverThreadStarter(void *pArg)
f77084bb
VK
40{
41 ((AgentConnection *)pArg)->ReceiverThread();
ccdbbb52 42 return THREAD_OK;
f77084bb
VK
43}
44
45
46//
47// Default constructor for AgentConnection - normally shouldn't be used
48//
49
50AgentConnection::AgentConnection()
51{
52 m_dwAddr = inet_addr("127.0.0.1");
53 m_wPort = AGENT_LISTEN_PORT;
54 m_iAuthMethod = AUTH_NONE;
55 m_szSecret[0] = 0;
56 m_hSocket = -1;
57 m_tLastCommandTime = 0;
58 m_dwNumDataLines = 0;
59 m_ppDataLines = NULL;
60 m_pMsgWaitQueue = new MsgWaitQueue;
d1d0b3be 61 m_dwRequestId = 1;
f77084bb 62 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
1c62be36 63 m_bIsConnected = FALSE;
38e832d6 64 m_mutexDataLock = MutexCreate();
ccdbbb52 65 m_hReceiverThread = INVALID_THREAD_HANDLE;
e44ac467 66 m_pCtx = NULL;
f77084bb
VK
67}
68
69
70//
71// Normal constructor for AgentConnection
72//
73
268774a0 74AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort, int iAuthMethod, TCHAR *pszSecret)
f77084bb
VK
75{
76 m_dwAddr = dwAddr;
77 m_wPort = wPort;
78 m_iAuthMethod = iAuthMethod;
268774a0
VK
79 if (pszSecret != NULL)
80 {
81#ifdef UNICODE
82 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
83 pszSecret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
84#else
85 strncpy(m_szSecret, pszSecret, MAX_SECRET_LENGTH);
86#endif
87 }
f77084bb 88 else
268774a0 89 {
f77084bb 90 m_szSecret[0] = 0;
268774a0 91 }
f77084bb
VK
92 m_hSocket = -1;
93 m_tLastCommandTime = 0;
94 m_dwNumDataLines = 0;
95 m_ppDataLines = NULL;
96 m_pMsgWaitQueue = new MsgWaitQueue;
d1d0b3be 97 m_dwRequestId = 1;
f77084bb 98 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
1c62be36 99 m_bIsConnected = FALSE;
38e832d6 100 m_mutexDataLock = MutexCreate();
ccdbbb52 101 m_hReceiverThread = INVALID_THREAD_HANDLE;
e44ac467 102 m_pCtx = NULL;
f77084bb
VK
103}
104
105
106//
107// Destructor
108//
109
110AgentConnection::~AgentConnection()
111{
1a60d114
VK
112 // Disconnect from peer
113 Disconnect();
38e832d6
VK
114
115 // Wait for receiver thread termination
ccdbbb52 116 ThreadJoin(m_hReceiverThread);
ba8681ba
VK
117 if (m_hSocket != -1)
118 closesocket(m_hSocket);
38e832d6
VK
119
120 Lock();
f77084bb 121 DestroyResultData();
38e832d6
VK
122 Unlock();
123
f77084bb 124 delete m_pMsgWaitQueue;
e44ac467 125 DestroyEncryptionContext(m_pCtx);
38e832d6
VK
126
127 MutexDestroy(m_mutexDataLock);
f77084bb
VK
128}
129
130
131//
059f6632
VK
132// Print message. This function is virtual and can be overrided in
133// derived classes. Default implementation will print message to stdout.
f77084bb
VK
134//
135
268774a0 136void AgentConnection::PrintMsg(TCHAR *pszFormat, ...)
f77084bb
VK
137{
138 va_list args;
139
140 va_start(args, pszFormat);
268774a0 141 _vtprintf(pszFormat, args);
f77084bb 142 va_end(args);
268774a0 143 _tprintf(_T("\n"));
f77084bb
VK
144}
145
146
147//
148// Receiver thread
149//
150
151void AgentConnection::ReceiverThread(void)
152{
153 CSCPMessage *pMsg;
154 CSCP_MESSAGE *pRawMsg;
155 CSCP_BUFFER *pMsgBuffer;
e44ac467 156 BYTE *pDecryptionBuffer = NULL;
f77084bb 157 int iErr;
268774a0 158 TCHAR szBuffer[128];
f77084bb
VK
159
160 // Initialize raw message receiving function
9d72bde1 161 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
e44ac467 162 RecvCSCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL);
f77084bb
VK
163
164 // Allocate space for raw message
9d72bde1 165 pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
e44ac467
VK
166#ifdef _WITH_ENCRYPTION
167 pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
168#endif
f77084bb
VK
169
170 // Message receiving loop
171 while(1)
172 {
173 // Receive raw message
e44ac467 174 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
1ba3c17a 175 &m_pCtx, pDecryptionBuffer)) <= 0)
f77084bb
VK
176 break;
177
178 // Check if we get too large message
179 if (iErr == 1)
180 {
268774a0 181 PrintMsg(_T("Received too large message %s (%ld bytes)"),
f77084bb
VK
182 CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
183 ntohl(pRawMsg->dwSize));
184 continue;
185 }
186
e44ac467
VK
187 // Check if we are unable to decrypt message
188 if (iErr == 2)
189 {
190 PrintMsg(_T("Unable to decrypt received message"));
191 continue;
192 }
193
f77084bb
VK
194 // Check that actual received packet size is equal to encoded in packet
195 if ((int)ntohl(pRawMsg->dwSize) != iErr)
196 {
268774a0 197 PrintMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), iErr);
f77084bb
VK
198 continue; // Bad packet, wait for next
199 }
200
201 // Create message object from raw message
202 pMsg = new CSCPMessage(pRawMsg);
203 if (pMsg->GetCode() == CMD_TRAP)
204 {
901c96c7 205 OnTrap(pMsg);
f77084bb
VK
206 delete pMsg;
207 }
208 else
209 {
210 m_pMsgWaitQueue->Put(pMsg);
211 }
212 }
213
1c62be36 214 // Close socket and mark connection as disconnected
ba8681ba
VK
215 if (iErr == 0)
216 shutdown(m_hSocket, SHUT_RDWR);
217 closesocket(m_hSocket);
218 m_hSocket = -1;
e44ac467
VK
219 DestroyEncryptionContext(m_pCtx);
220 m_pCtx = NULL;
ba8681ba 221 m_bIsConnected = FALSE;
1c62be36 222
9d72bde1
VK
223 free(pRawMsg);
224 free(pMsgBuffer);
f77084bb
VK
225}
226
227
228//
229// Connect to agent
230//
231
1ba3c17a 232BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
f77084bb
VK
233{
234 struct sockaddr_in sa;
268774a0 235 TCHAR szBuffer[256];
f77084bb 236 BOOL bSuccess = FALSE;
d1d0b3be 237 DWORD dwError;
f77084bb 238
1ba3c17a
VK
239 if (pdwError != NULL)
240 *pdwError = ERR_INTERNAL_ERROR;
241
1c62be36 242 // Check if already connected
ba8681ba 243 if (m_bIsConnected)
1c62be36
VK
244 return FALSE;
245
ccdbbb52
VK
246 // Wait for receiver thread from previous connection, if any
247 ThreadJoin(m_hReceiverThread);
248 m_hReceiverThread = INVALID_THREAD_HANDLE;
249
ba8681ba
VK
250 // Check if we need to close existing socket
251 if (m_hSocket != -1)
252 closesocket(m_hSocket);
253
f77084bb
VK
254 // Create socket
255 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
256 if (m_hSocket == -1)
257 {
268774a0 258 PrintMsg(_T("Call to socket() failed"));
f77084bb
VK
259 goto connect_cleanup;
260 }
261
262 // Fill in address structure
263 memset(&sa, 0, sizeof(sa));
264 sa.sin_addr.s_addr = m_dwAddr;
265 sa.sin_family = AF_INET;
266 sa.sin_port = htons(m_wPort);
267
268 // Connect to server
269 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
270 {
271 if (bVerbose)
205acaf4 272 PrintMsg(_T("Cannot establish connection with agent %s"), IpToStr(ntohl(m_dwAddr), szBuffer));
1ba3c17a 273 dwError = ERR_CONNECT_FAILED;
f77084bb
VK
274 goto connect_cleanup;
275 }
276
277 // Start receiver thread
ccdbbb52 278 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
f77084bb 279
e44ac467
VK
280 // Setup encryption
281 if (pServerKey != NULL)
282 {
283 dwError = SetupEncryption(pServerKey);
284 if (dwError != ERR_SUCCESS)
285 goto connect_cleanup;
286 }
287
f77084bb 288 // Authenticate itself to agent
d1d0b3be 289 if ((dwError = Authenticate()) != ERR_SUCCESS)
f77084bb 290 {
205acaf4 291 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be
VK
292 AgentErrorCodeToText(dwError));
293 goto connect_cleanup;
f77084bb
VK
294 }
295
296 // Test connectivity
d1d0b3be 297 if ((dwError = Nop()) != ERR_SUCCESS)
f77084bb 298 {
205acaf4 299 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be 300 AgentErrorCodeToText(dwError));
f77084bb
VK
301 goto connect_cleanup;
302 }
303
304 bSuccess = TRUE;
1ba3c17a 305 dwError = ERR_SUCCESS;
f77084bb
VK
306
307connect_cleanup:
308 if (!bSuccess)
309 {
310 if (m_hSocket != -1)
f77084bb 311 shutdown(m_hSocket, 2);
ba8681ba
VK
312 ThreadJoin(m_hReceiverThread);
313 m_hReceiverThread = INVALID_THREAD_HANDLE;
314
315 if (m_hSocket != -1)
f77084bb 316 closesocket(m_hSocket);
e44ac467
VK
317
318 DestroyEncryptionContext(m_pCtx);
319 m_pCtx = NULL;
f77084bb 320 }
1c62be36 321 m_bIsConnected = bSuccess;
1ba3c17a
VK
322 if (pdwError != NULL)
323 *pdwError = dwError;
f77084bb
VK
324 return bSuccess;
325}
326
327
328//
329// Disconnect from agent
330//
331
332void AgentConnection::Disconnect(void)
333{
1c62be36 334 Lock();
f77084bb
VK
335 if (m_hSocket != -1)
336 {
ba8681ba 337 shutdown(m_hSocket, SHUT_RDWR);
f77084bb
VK
338 }
339 DestroyResultData();
1c62be36
VK
340 m_bIsConnected = FALSE;
341 Unlock();
f77084bb
VK
342}
343
344
345//
346// Destroy command execuion results data
347//
348
349void AgentConnection::DestroyResultData(void)
350{
351 DWORD i;
352
353 if (m_ppDataLines != NULL)
354 {
355 for(i = 0; i < m_dwNumDataLines; i++)
356 if (m_ppDataLines[i] != NULL)
9d72bde1
VK
357 free(m_ppDataLines[i]);
358 free(m_ppDataLines);
f77084bb
VK
359 m_ppDataLines = NULL;
360 }
361 m_dwNumDataLines = 0;
362}
363
364
365//
366// Get interface list from agent
367//
368
369INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
370{
1c62be36
VK
371 INTERFACE_LIST *pIfList = NULL;
372 DWORD i;
268774a0 373 TCHAR *pChar, *pBuf;
1c62be36 374
268774a0 375 if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
1c62be36 376 {
9d72bde1 377 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
1c62be36 378 pIfList->iNumEntries = m_dwNumDataLines;
9d72bde1 379 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * m_dwNumDataLines);
1c62be36
VK
380 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * m_dwNumDataLines);
381 for(i = 0; i < m_dwNumDataLines; i++)
382 {
383 pBuf = m_ppDataLines[i];
384
385 // Index
268774a0 386 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
387 if (pChar != NULL)
388 {
389 *pChar = 0;
268774a0 390 pIfList->pInterfaces[i].dwIndex = _tcstoul(pBuf, NULL, 10);
1c62be36
VK
391 pBuf = pChar + 1;
392 }
393
394 // Address and mask
268774a0 395 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
396 if (pChar != NULL)
397 {
268774a0 398 TCHAR *pSlash;
1c62be36
VK
399
400 *pChar = 0;
268774a0 401 pSlash = _tcschr(pBuf, _T('/'));
1c62be36
VK
402 if (pSlash != NULL)
403 {
404 *pSlash = 0;
405 pSlash++;
406 }
407 else // Just a paranoia protection, should'n happen if agent working correctly
408 {
268774a0 409 pSlash = _T("24");
1c62be36 410 }
205acaf4
VK
411 pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
412 pIfList->pInterfaces[i].dwIpNetMask = ~(0xFFFFFFFF >> _tcstoul(pSlash, NULL, 10));
1c62be36
VK
413 pBuf = pChar + 1;
414 }
415
416 // Interface type
268774a0 417 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
418 if (pChar != NULL)
419 {
420 *pChar = 0;
205acaf4 421 pIfList->pInterfaces[i].dwType = _tcstoul(pBuf, NULL, 10);
1c62be36 422 pBuf = pChar + 1;
b50f1100
VK
423 }
424
425 // MAC address
426 pChar = _tcschr(pBuf, ' ');
427 if (pChar != NULL)
428 {
429 *pChar = 0;
430 StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
431 pBuf = pChar + 1;
1c62be36
VK
432 }
433
434 // Name
268774a0 435 _tcsncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
1c62be36
VK
436 }
437
9d72bde1 438 Lock();
1c62be36 439 DestroyResultData();
9d72bde1 440 Unlock();
1c62be36
VK
441 }
442
443 return pIfList;
f77084bb
VK
444}
445
446
447//
448// Get parameter value
449//
450
268774a0 451DWORD AgentConnection::GetParameter(TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
f77084bb
VK
452{
453 CSCPMessage msg, *pResponce;
454 DWORD dwRqId, dwRetCode;
455
1c62be36 456 if (m_bIsConnected)
f77084bb 457 {
1c62be36
VK
458 dwRqId = m_dwRequestId++;
459 msg.SetCode(CMD_GET_PARAMETER);
460 msg.SetId(dwRqId);
461 msg.SetVariable(VID_PARAMETER, pszParam);
462 if (SendMessage(&msg))
f77084bb 463 {
1c62be36
VK
464 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
465 if (pResponce != NULL)
466 {
467 dwRetCode = pResponce->GetVariableLong(VID_RCC);
468 if (dwRetCode == ERR_SUCCESS)
469 pResponce->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
470 delete pResponce;
471 }
472 else
473 {
474 dwRetCode = ERR_REQUEST_TIMEOUT;
475 }
f77084bb
VK
476 }
477 else
478 {
1c62be36 479 dwRetCode = ERR_CONNECTION_BROKEN;
f77084bb
VK
480 }
481 }
482 else
483 {
1c62be36 484 dwRetCode = ERR_NOT_CONNECTED;
f77084bb
VK
485 }
486
487 return dwRetCode;
488}
489
490
491//
492// Get ARP cache
493//
494
495ARP_CACHE *AgentConnection::GetArpCache(void)
496{
1c62be36 497 ARP_CACHE *pArpCache = NULL;
268774a0 498 TCHAR szByte[4], *pBuf, *pChar;
1c62be36
VK
499 DWORD i, j;
500
268774a0 501 if (GetList(_T("Net.ArpCache")) == ERR_SUCCESS)
1c62be36
VK
502 {
503 // Create empty structure
9d72bde1 504 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
1c62be36 505 pArpCache->dwNumEntries = m_dwNumDataLines;
9d72bde1 506 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
1c62be36
VK
507 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
508
509 szByte[2] = 0;
510
511 // Parse data lines
512 // Each line has form of XXXXXXXXXXXX a.b.c.d
513 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
514 // and a.b.c.d is an IP address in decimal dotted notation
515 for(i = 0; i < m_dwNumDataLines; i++)
516 {
517 pBuf = m_ppDataLines[i];
268774a0 518 if (_tcslen(pBuf) < 20) // Invalid line
1c62be36
VK
519 continue;
520
521 // MAC address
522 for(j = 0; j < 6; j++)
523 {
268774a0
VK
524 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
525 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
1c62be36
VK
526 pBuf+=2;
527 }
528
529 // IP address
530 while(*pBuf == ' ')
531 pBuf++;
268774a0 532 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
533 if (pChar != NULL)
534 *pChar = 0;
205acaf4 535 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
1c62be36
VK
536
537 // Interface index
538 if (pChar != NULL)
268774a0 539 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
1c62be36
VK
540 }
541
542 DestroyResultData();
543 }
544 return pArpCache;
f77084bb
VK
545}
546
547
548//
549// Send dummy command to agent (can be used for keepalive)
550//
551
552DWORD AgentConnection::Nop(void)
553{
554 CSCPMessage msg;
555 DWORD dwRqId;
556
557 dwRqId = m_dwRequestId++;
558 msg.SetCode(CMD_KEEPALIVE);
559 msg.SetId(dwRqId);
560 if (SendMessage(&msg))
561 return WaitForRCC(dwRqId, m_dwCommandTimeout);
562 else
563 return ERR_CONNECTION_BROKEN;
564}
565
566
567//
568// Wait for request completion code
569//
570
571DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
572{
573 CSCPMessage *pMsg;
574 DWORD dwRetCode;
575
576 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
577 if (pMsg != NULL)
578 {
579 dwRetCode = pMsg->GetVariableLong(VID_RCC);
580 delete pMsg;
581 }
582 else
583 {
584 dwRetCode = ERR_REQUEST_TIMEOUT;
585 }
586 return dwRetCode;
587}
588
589
590//
591// Send message to agent
592//
593
594BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
595{
596 CSCP_MESSAGE *pRawMsg;
e44ac467 597 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
f77084bb
VK
598 BOOL bResult;
599
600 pRawMsg = pMsg->CreateMessage();
e44ac467
VK
601 if (m_pCtx != NULL)
602 {
603 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
604 if (pEnMsg != NULL)
605 {
606 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
607 free(pEnMsg);
608 }
609 else
610 {
611 bResult = FALSE;
612 }
613 }
614 else
615 {
616 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
617 }
9d72bde1 618 free(pRawMsg);
f77084bb
VK
619 return bResult;
620}
901c96c7
VK
621
622
623//
624// Trap handler. Should be overriden in derived classes to implement
625// actual trap processing. Default implementation do nothing.
626//
627
628void AgentConnection::OnTrap(CSCPMessage *pMsg)
629{
630}
631
632
633//
634// Get list of values
635//
636
268774a0 637DWORD AgentConnection::GetList(TCHAR *pszParam)
901c96c7
VK
638{
639 CSCPMessage msg, *pResponce;
640 DWORD i, dwRqId, dwRetCode;
641
1c62be36 642 if (m_bIsConnected)
901c96c7 643 {
1c62be36
VK
644 DestroyResultData();
645 dwRqId = m_dwRequestId++;
646 msg.SetCode(CMD_GET_LIST);
647 msg.SetId(dwRqId);
648 msg.SetVariable(VID_PARAMETER, pszParam);
649 if (SendMessage(&msg))
901c96c7 650 {
1c62be36
VK
651 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
652 if (pResponce != NULL)
653 {
654 dwRetCode = pResponce->GetVariableLong(VID_RCC);
655 if (dwRetCode == ERR_SUCCESS)
656 {
657 m_dwNumDataLines = pResponce->GetVariableLong(VID_NUM_STRINGS);
268774a0 658 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
1c62be36
VK
659 for(i = 0; i < m_dwNumDataLines; i++)
660 m_ppDataLines[i] = pResponce->GetVariableStr(VID_ENUM_VALUE_BASE + i);
661 }
662 delete pResponce;
663 }
664 else
901c96c7 665 {
1c62be36 666 dwRetCode = ERR_REQUEST_TIMEOUT;
901c96c7 667 }
901c96c7
VK
668 }
669 else
670 {
1c62be36 671 dwRetCode = ERR_CONNECTION_BROKEN;
901c96c7
VK
672 }
673 }
674 else
675 {
1c62be36 676 dwRetCode = ERR_NOT_CONNECTED;
901c96c7
VK
677 }
678
679 return dwRetCode;
680}
d1d0b3be
VK
681
682
683//
684// Authenticate to agent
685//
686
687DWORD AgentConnection::Authenticate(void)
688{
689 CSCPMessage msg;
690 DWORD dwRqId;
691 BYTE hash[32];
268774a0
VK
692#ifdef UNICODE
693 WCHAR szBuffer[MAX_SECRET_LENGTH];
694#endif
d1d0b3be
VK
695
696 if (m_iAuthMethod == AUTH_NONE)
697 return ERR_SUCCESS; // No authentication required
698
699 dwRqId = m_dwRequestId++;
700 msg.SetCode(CMD_AUTHENTICATE);
701 msg.SetId(dwRqId);
702 msg.SetVariable(VID_AUTH_METHOD, (WORD)m_iAuthMethod);
703 switch(m_iAuthMethod)
704 {
705 case AUTH_PLAINTEXT:
268774a0
VK
706#ifdef UNICODE
707 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szSecret, -1, szBuffer, MAX_SECRET_LENGTH);
708 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
709#else
d1d0b3be 710 msg.SetVariable(VID_SHARED_SECRET, m_szSecret);
268774a0 711#endif
d1d0b3be
VK
712 break;
713 case AUTH_MD5_HASH:
714 CalculateMD5Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
715 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
716 break;
717 case AUTH_SHA1_HASH:
718 CalculateSHA1Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
719 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
720 break;
721 default:
722 break;
723 }
724 if (SendMessage(&msg))
725 return WaitForRCC(dwRqId, m_dwCommandTimeout);
726 else
727 return ERR_CONNECTION_BROKEN;
728}
3c774461
VK
729
730
731//
732// Execute action on agent
733//
734
268774a0 735DWORD AgentConnection::ExecAction(TCHAR *pszAction, int argc, TCHAR **argv)
3c774461
VK
736{
737 CSCPMessage msg;
738 DWORD dwRqId;
739 int i;
740
1c62be36
VK
741 if (!m_bIsConnected)
742 return ERR_NOT_CONNECTED;
743
3c774461
VK
744 dwRqId = m_dwRequestId++;
745 msg.SetCode(CMD_ACTION);
746 msg.SetId(dwRqId);
747 msg.SetVariable(VID_ACTION_NAME, pszAction);
748 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
749 for(i = 0; i < argc; i++)
750 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
751
752 if (SendMessage(&msg))
753 return WaitForRCC(dwRqId, m_dwCommandTimeout);
754 else
755 return ERR_CONNECTION_BROKEN;
756}
d096bcdd
VK
757
758
759//
760// Upload file to agent
761//
762
763DWORD AgentConnection::UploadFile(TCHAR *pszFile)
764{
765 DWORD dwRqId, dwResult;
766 CSCPMessage msg;
767 int i;
768
769 if (!m_bIsConnected)
770 return ERR_NOT_CONNECTED;
771
772 dwRqId = m_dwRequestId++;
773
774 msg.SetCode(CMD_TRANSFER_FILE);
775 msg.SetId(dwRqId);
776 for(i = _tcslen(pszFile) - 1;
777 (i >= 0) && (pszFile[i] != '\\') && (pszFile[i] != '/'); i--);
778 msg.SetVariable(VID_FILE_NAME, &pszFile[i + 1]);
779
780 if (SendMessage(&msg))
781 {
782 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
783 }
784 else
785 {
786 dwResult = ERR_CONNECTION_BROKEN;
787 }
788
789 if (dwResult == ERR_SUCCESS)
790 {
1ba3c17a 791 if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile, m_pCtx))
d096bcdd
VK
792 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
793 else
794 dwResult = ERR_IO_FAILURE;
795 }
796
797 return dwResult;
798}
e925a5fc
VK
799
800
801//
802// Send upgrade command
803//
804
805DWORD AgentConnection::StartUpgrade(TCHAR *pszPkgName)
806{
807 DWORD dwRqId, dwResult;
808 CSCPMessage msg;
809 int i;
810
811 if (!m_bIsConnected)
812 return ERR_NOT_CONNECTED;
813
814 dwRqId = m_dwRequestId++;
815
816 msg.SetCode(CMD_UPGRADE_AGENT);
817 msg.SetId(dwRqId);
818 for(i = _tcslen(pszPkgName) - 1;
819 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
820 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
821
822 if (SendMessage(&msg))
823 {
824 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
825 }
826 else
827 {
828 dwResult = ERR_CONNECTION_BROKEN;
829 }
830
831 return dwResult;
832}
3f0ca036
VK
833
834
835//
836// Check status of network service via agent
837//
838
839DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
840 WORD wPort, WORD wProto,
841 TCHAR *pszRequest, TCHAR *pszResponce)
842{
843 DWORD dwRqId, dwResult;
844 CSCPMessage msg, *pResponce;
845 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
846
847 if (!m_bIsConnected)
848 return ERR_NOT_CONNECTED;
849
850 dwRqId = m_dwRequestId++;
851
852 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
853 msg.SetId(dwRqId);
854 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
855 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
856 msg.SetVariable(VID_IP_PORT,
857 (wPort != 0) ? wPort :
25376fc7 858 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
3f0ca036 859 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
25376fc7 860 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
3f0ca036
VK
861 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
862 msg.SetVariable(VID_SERVICE_RESPONCE, pszResponce);
863
864 if (SendMessage(&msg))
865 {
866 // Wait up to 90 seconds for results
867 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
868 if (pResponce != NULL)
869 {
870 dwResult = pResponce->GetVariableLong(VID_RCC);
871 if (dwResult == ERR_SUCCESS)
872 {
873 *pdwStatus = pResponce->GetVariableLong(VID_SERVICE_STATUS);
874 }
875 delete pResponce;
876 }
877 else
878 {
879 dwResult = ERR_REQUEST_TIMEOUT;
880 }
881 }
882 else
883 {
884 dwResult = ERR_CONNECTION_BROKEN;
885 }
886
887 return dwResult;
888}
125c0e81
VK
889
890
891//
892// Get list of supported parameters from subagent
893//
894
895DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
896{
897 DWORD i, dwId, dwRqId, dwResult;
898 CSCPMessage msg, *pResponce;
899
900 if (!m_bIsConnected)
901 return ERR_NOT_CONNECTED;
902
903 *pdwNumParams = 0;
904 *ppParamList = NULL;
905
906 dwRqId = m_dwRequestId++;
907
908 msg.SetCode(CMD_GET_PARAMETER_LIST);
909 msg.SetId(dwRqId);
910
911 if (SendMessage(&msg))
912 {
913 // Wait up to 90 seconds for results
914 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
915 if (pResponce != NULL)
916 {
917 dwResult = pResponce->GetVariableLong(VID_RCC);
918 if (dwResult == ERR_SUCCESS)
919 {
920 *pdwNumParams = pResponce->GetVariableLong(VID_NUM_PARAMETERS);
921 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * *pdwNumParams);
922 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
923 {
924 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
925 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
926 (*ppParamList)[i].iDataType = (int)pResponce->GetVariableShort(dwId++);
927 }
928 }
929 delete pResponce;
930 }
931 else
932 {
933 dwResult = ERR_REQUEST_TIMEOUT;
934 }
935 }
936 else
937 {
938 dwResult = ERR_CONNECTION_BROKEN;
939 }
940
941 return dwResult;
942}
e44ac467
VK
943
944
945//
946// Setup encryption
947//
948
949DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
950{
951#ifdef _WITH_ENCRYPTION
952 CSCPMessage msg, *pResp;
953 DWORD dwRqId, dwError, dwResult;
954
955 dwRqId = m_dwRequestId++;
956
957 PrepareKeyRequestMsg(&msg, pServerKey);
958 msg.SetId(dwRqId);
959 if (SendMessage(&msg))
960 {
961 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
962 if (pResp != NULL)
963 {
964 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey);
965 switch(dwResult)
966 {
967 case RCC_SUCCESS:
968 dwError = ERR_SUCCESS;
969 break;
970 case RCC_NO_CIPHERS:
971 dwError = ERR_NO_CIPHERS;
972 break;
973 case RCC_INVALID_PUBLIC_KEY:
974 dwError = ERR_INVALID_PUBLIC_KEY;
975 break;
976 case RCC_INVALID_SESSION_KEY:
977 dwError = ERR_INVALID_SESSION_KEY;
978 break;
979 default:
980 dwError = ERR_INTERNAL_ERROR;
981 break;
982 }
983 }
984 else
985 {
986 dwError = ERR_REQUEST_TIMEOUT;
987 }
988 }
989 else
990 {
991 dwError = ERR_CONNECTION_BROKEN;
992 }
993
994 return dwError;
995#else
996 return ERR_NOT_IMPLEMENTED;
997#endif
998}