- Added encryption foundation
[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
VK
174 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
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
e44ac467 232BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose)
f77084bb
VK
233{
234 struct sockaddr_in sa;
268774a0 235 TCHAR szBuffer[256];
f77084bb 236 BOOL bSuccess = FALSE;
d1d0b3be 237 DWORD dwError;
f77084bb 238
1c62be36 239 // Check if already connected
ba8681ba 240 if (m_bIsConnected)
1c62be36
VK
241 return FALSE;
242
ccdbbb52
VK
243 // Wait for receiver thread from previous connection, if any
244 ThreadJoin(m_hReceiverThread);
245 m_hReceiverThread = INVALID_THREAD_HANDLE;
246
ba8681ba
VK
247 // Check if we need to close existing socket
248 if (m_hSocket != -1)
249 closesocket(m_hSocket);
250
f77084bb
VK
251 // Create socket
252 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
253 if (m_hSocket == -1)
254 {
268774a0 255 PrintMsg(_T("Call to socket() failed"));
f77084bb
VK
256 goto connect_cleanup;
257 }
258
259 // Fill in address structure
260 memset(&sa, 0, sizeof(sa));
261 sa.sin_addr.s_addr = m_dwAddr;
262 sa.sin_family = AF_INET;
263 sa.sin_port = htons(m_wPort);
264
265 // Connect to server
266 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
267 {
268 if (bVerbose)
205acaf4 269 PrintMsg(_T("Cannot establish connection with agent %s"), IpToStr(ntohl(m_dwAddr), szBuffer));
f77084bb
VK
270 goto connect_cleanup;
271 }
272
273 // Start receiver thread
ccdbbb52 274 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
f77084bb 275
e44ac467
VK
276 // Setup encryption
277 if (pServerKey != NULL)
278 {
279 dwError = SetupEncryption(pServerKey);
280 if (dwError != ERR_SUCCESS)
281 goto connect_cleanup;
282 }
283
f77084bb 284 // Authenticate itself to agent
d1d0b3be 285 if ((dwError = Authenticate()) != ERR_SUCCESS)
f77084bb 286 {
205acaf4 287 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be
VK
288 AgentErrorCodeToText(dwError));
289 goto connect_cleanup;
f77084bb
VK
290 }
291
292 // Test connectivity
d1d0b3be 293 if ((dwError = Nop()) != ERR_SUCCESS)
f77084bb 294 {
205acaf4 295 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
d1d0b3be 296 AgentErrorCodeToText(dwError));
f77084bb
VK
297 goto connect_cleanup;
298 }
299
300 bSuccess = TRUE;
301
302connect_cleanup:
303 if (!bSuccess)
304 {
305 if (m_hSocket != -1)
f77084bb 306 shutdown(m_hSocket, 2);
ba8681ba
VK
307 ThreadJoin(m_hReceiverThread);
308 m_hReceiverThread = INVALID_THREAD_HANDLE;
309
310 if (m_hSocket != -1)
f77084bb 311 closesocket(m_hSocket);
e44ac467
VK
312
313 DestroyEncryptionContext(m_pCtx);
314 m_pCtx = NULL;
f77084bb 315 }
1c62be36 316 m_bIsConnected = bSuccess;
f77084bb
VK
317 return bSuccess;
318}
319
320
321//
322// Disconnect from agent
323//
324
325void AgentConnection::Disconnect(void)
326{
1c62be36 327 Lock();
f77084bb
VK
328 if (m_hSocket != -1)
329 {
ba8681ba 330 shutdown(m_hSocket, SHUT_RDWR);
f77084bb
VK
331 }
332 DestroyResultData();
1c62be36
VK
333 m_bIsConnected = FALSE;
334 Unlock();
f77084bb
VK
335}
336
337
338//
339// Destroy command execuion results data
340//
341
342void AgentConnection::DestroyResultData(void)
343{
344 DWORD i;
345
346 if (m_ppDataLines != NULL)
347 {
348 for(i = 0; i < m_dwNumDataLines; i++)
349 if (m_ppDataLines[i] != NULL)
9d72bde1
VK
350 free(m_ppDataLines[i]);
351 free(m_ppDataLines);
f77084bb
VK
352 m_ppDataLines = NULL;
353 }
354 m_dwNumDataLines = 0;
355}
356
357
358//
359// Get interface list from agent
360//
361
362INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
363{
1c62be36
VK
364 INTERFACE_LIST *pIfList = NULL;
365 DWORD i;
268774a0 366 TCHAR *pChar, *pBuf;
1c62be36 367
268774a0 368 if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
1c62be36 369 {
9d72bde1 370 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
1c62be36 371 pIfList->iNumEntries = m_dwNumDataLines;
9d72bde1 372 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * m_dwNumDataLines);
1c62be36
VK
373 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * m_dwNumDataLines);
374 for(i = 0; i < m_dwNumDataLines; i++)
375 {
376 pBuf = m_ppDataLines[i];
377
378 // Index
268774a0 379 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
380 if (pChar != NULL)
381 {
382 *pChar = 0;
268774a0 383 pIfList->pInterfaces[i].dwIndex = _tcstoul(pBuf, NULL, 10);
1c62be36
VK
384 pBuf = pChar + 1;
385 }
386
387 // Address and mask
268774a0 388 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
389 if (pChar != NULL)
390 {
268774a0 391 TCHAR *pSlash;
1c62be36
VK
392
393 *pChar = 0;
268774a0 394 pSlash = _tcschr(pBuf, _T('/'));
1c62be36
VK
395 if (pSlash != NULL)
396 {
397 *pSlash = 0;
398 pSlash++;
399 }
400 else // Just a paranoia protection, should'n happen if agent working correctly
401 {
268774a0 402 pSlash = _T("24");
1c62be36 403 }
205acaf4
VK
404 pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
405 pIfList->pInterfaces[i].dwIpNetMask = ~(0xFFFFFFFF >> _tcstoul(pSlash, NULL, 10));
1c62be36
VK
406 pBuf = pChar + 1;
407 }
408
409 // Interface type
268774a0 410 pChar = _tcschr(pBuf, ' ');
1c62be36
VK
411 if (pChar != NULL)
412 {
413 *pChar = 0;
205acaf4 414 pIfList->pInterfaces[i].dwType = _tcstoul(pBuf, NULL, 10);
1c62be36 415 pBuf = pChar + 1;
b50f1100
VK
416 }
417
418 // MAC address
419 pChar = _tcschr(pBuf, ' ');
420 if (pChar != NULL)
421 {
422 *pChar = 0;
423 StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
424 pBuf = pChar + 1;
1c62be36
VK
425 }
426
427 // Name
268774a0 428 _tcsncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
1c62be36
VK
429 }
430
9d72bde1 431 Lock();
1c62be36 432 DestroyResultData();
9d72bde1 433 Unlock();
1c62be36
VK
434 }
435
436 return pIfList;
f77084bb
VK
437}
438
439
440//
441// Get parameter value
442//
443
268774a0 444DWORD AgentConnection::GetParameter(TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
f77084bb
VK
445{
446 CSCPMessage msg, *pResponce;
447 DWORD dwRqId, dwRetCode;
448
1c62be36 449 if (m_bIsConnected)
f77084bb 450 {
1c62be36
VK
451 dwRqId = m_dwRequestId++;
452 msg.SetCode(CMD_GET_PARAMETER);
453 msg.SetId(dwRqId);
454 msg.SetVariable(VID_PARAMETER, pszParam);
455 if (SendMessage(&msg))
f77084bb 456 {
1c62be36
VK
457 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
458 if (pResponce != NULL)
459 {
460 dwRetCode = pResponce->GetVariableLong(VID_RCC);
461 if (dwRetCode == ERR_SUCCESS)
462 pResponce->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
463 delete pResponce;
464 }
465 else
466 {
467 dwRetCode = ERR_REQUEST_TIMEOUT;
468 }
f77084bb
VK
469 }
470 else
471 {
1c62be36 472 dwRetCode = ERR_CONNECTION_BROKEN;
f77084bb
VK
473 }
474 }
475 else
476 {
1c62be36 477 dwRetCode = ERR_NOT_CONNECTED;
f77084bb
VK
478 }
479
480 return dwRetCode;
481}
482
483
484//
485// Get ARP cache
486//
487
488ARP_CACHE *AgentConnection::GetArpCache(void)
489{
1c62be36 490 ARP_CACHE *pArpCache = NULL;
268774a0 491 TCHAR szByte[4], *pBuf, *pChar;
1c62be36
VK
492 DWORD i, j;
493
268774a0 494 if (GetList(_T("Net.ArpCache")) == ERR_SUCCESS)
1c62be36
VK
495 {
496 // Create empty structure
9d72bde1 497 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
1c62be36 498 pArpCache->dwNumEntries = m_dwNumDataLines;
9d72bde1 499 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
1c62be36
VK
500 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
501
502 szByte[2] = 0;
503
504 // Parse data lines
505 // Each line has form of XXXXXXXXXXXX a.b.c.d
506 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
507 // and a.b.c.d is an IP address in decimal dotted notation
508 for(i = 0; i < m_dwNumDataLines; i++)
509 {
510 pBuf = m_ppDataLines[i];
268774a0 511 if (_tcslen(pBuf) < 20) // Invalid line
1c62be36
VK
512 continue;
513
514 // MAC address
515 for(j = 0; j < 6; j++)
516 {
268774a0
VK
517 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
518 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
1c62be36
VK
519 pBuf+=2;
520 }
521
522 // IP address
523 while(*pBuf == ' ')
524 pBuf++;
268774a0 525 pChar = _tcschr(pBuf, _T(' '));
1c62be36
VK
526 if (pChar != NULL)
527 *pChar = 0;
205acaf4 528 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
1c62be36
VK
529
530 // Interface index
531 if (pChar != NULL)
268774a0 532 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
1c62be36
VK
533 }
534
535 DestroyResultData();
536 }
537 return pArpCache;
f77084bb
VK
538}
539
540
541//
542// Send dummy command to agent (can be used for keepalive)
543//
544
545DWORD AgentConnection::Nop(void)
546{
547 CSCPMessage msg;
548 DWORD dwRqId;
549
550 dwRqId = m_dwRequestId++;
551 msg.SetCode(CMD_KEEPALIVE);
552 msg.SetId(dwRqId);
553 if (SendMessage(&msg))
554 return WaitForRCC(dwRqId, m_dwCommandTimeout);
555 else
556 return ERR_CONNECTION_BROKEN;
557}
558
559
560//
561// Wait for request completion code
562//
563
564DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
565{
566 CSCPMessage *pMsg;
567 DWORD dwRetCode;
568
569 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
570 if (pMsg != NULL)
571 {
572 dwRetCode = pMsg->GetVariableLong(VID_RCC);
573 delete pMsg;
574 }
575 else
576 {
577 dwRetCode = ERR_REQUEST_TIMEOUT;
578 }
579 return dwRetCode;
580}
581
582
583//
584// Send message to agent
585//
586
587BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
588{
589 CSCP_MESSAGE *pRawMsg;
e44ac467 590 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
f77084bb
VK
591 BOOL bResult;
592
593 pRawMsg = pMsg->CreateMessage();
e44ac467
VK
594 if (m_pCtx != NULL)
595 {
596 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
597 if (pEnMsg != NULL)
598 {
599 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
600 free(pEnMsg);
601 }
602 else
603 {
604 bResult = FALSE;
605 }
606 }
607 else
608 {
609 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
610 }
9d72bde1 611 free(pRawMsg);
f77084bb
VK
612 return bResult;
613}
901c96c7
VK
614
615
616//
617// Trap handler. Should be overriden in derived classes to implement
618// actual trap processing. Default implementation do nothing.
619//
620
621void AgentConnection::OnTrap(CSCPMessage *pMsg)
622{
623}
624
625
626//
627// Get list of values
628//
629
268774a0 630DWORD AgentConnection::GetList(TCHAR *pszParam)
901c96c7
VK
631{
632 CSCPMessage msg, *pResponce;
633 DWORD i, dwRqId, dwRetCode;
634
1c62be36 635 if (m_bIsConnected)
901c96c7 636 {
1c62be36
VK
637 DestroyResultData();
638 dwRqId = m_dwRequestId++;
639 msg.SetCode(CMD_GET_LIST);
640 msg.SetId(dwRqId);
641 msg.SetVariable(VID_PARAMETER, pszParam);
642 if (SendMessage(&msg))
901c96c7 643 {
1c62be36
VK
644 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
645 if (pResponce != NULL)
646 {
647 dwRetCode = pResponce->GetVariableLong(VID_RCC);
648 if (dwRetCode == ERR_SUCCESS)
649 {
650 m_dwNumDataLines = pResponce->GetVariableLong(VID_NUM_STRINGS);
268774a0 651 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
1c62be36
VK
652 for(i = 0; i < m_dwNumDataLines; i++)
653 m_ppDataLines[i] = pResponce->GetVariableStr(VID_ENUM_VALUE_BASE + i);
654 }
655 delete pResponce;
656 }
657 else
901c96c7 658 {
1c62be36 659 dwRetCode = ERR_REQUEST_TIMEOUT;
901c96c7 660 }
901c96c7
VK
661 }
662 else
663 {
1c62be36 664 dwRetCode = ERR_CONNECTION_BROKEN;
901c96c7
VK
665 }
666 }
667 else
668 {
1c62be36 669 dwRetCode = ERR_NOT_CONNECTED;
901c96c7
VK
670 }
671
672 return dwRetCode;
673}
d1d0b3be
VK
674
675
676//
677// Authenticate to agent
678//
679
680DWORD AgentConnection::Authenticate(void)
681{
682 CSCPMessage msg;
683 DWORD dwRqId;
684 BYTE hash[32];
268774a0
VK
685#ifdef UNICODE
686 WCHAR szBuffer[MAX_SECRET_LENGTH];
687#endif
d1d0b3be
VK
688
689 if (m_iAuthMethod == AUTH_NONE)
690 return ERR_SUCCESS; // No authentication required
691
692 dwRqId = m_dwRequestId++;
693 msg.SetCode(CMD_AUTHENTICATE);
694 msg.SetId(dwRqId);
695 msg.SetVariable(VID_AUTH_METHOD, (WORD)m_iAuthMethod);
696 switch(m_iAuthMethod)
697 {
698 case AUTH_PLAINTEXT:
268774a0
VK
699#ifdef UNICODE
700 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szSecret, -1, szBuffer, MAX_SECRET_LENGTH);
701 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
702#else
d1d0b3be 703 msg.SetVariable(VID_SHARED_SECRET, m_szSecret);
268774a0 704#endif
d1d0b3be
VK
705 break;
706 case AUTH_MD5_HASH:
707 CalculateMD5Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
708 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
709 break;
710 case AUTH_SHA1_HASH:
711 CalculateSHA1Hash((BYTE *)m_szSecret, strlen(m_szSecret), hash);
712 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
713 break;
714 default:
715 break;
716 }
717 if (SendMessage(&msg))
718 return WaitForRCC(dwRqId, m_dwCommandTimeout);
719 else
720 return ERR_CONNECTION_BROKEN;
721}
3c774461
VK
722
723
724//
725// Execute action on agent
726//
727
268774a0 728DWORD AgentConnection::ExecAction(TCHAR *pszAction, int argc, TCHAR **argv)
3c774461
VK
729{
730 CSCPMessage msg;
731 DWORD dwRqId;
732 int i;
733
1c62be36
VK
734 if (!m_bIsConnected)
735 return ERR_NOT_CONNECTED;
736
3c774461
VK
737 dwRqId = m_dwRequestId++;
738 msg.SetCode(CMD_ACTION);
739 msg.SetId(dwRqId);
740 msg.SetVariable(VID_ACTION_NAME, pszAction);
741 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
742 for(i = 0; i < argc; i++)
743 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
744
745 if (SendMessage(&msg))
746 return WaitForRCC(dwRqId, m_dwCommandTimeout);
747 else
748 return ERR_CONNECTION_BROKEN;
749}
d096bcdd
VK
750
751
752//
753// Upload file to agent
754//
755
756DWORD AgentConnection::UploadFile(TCHAR *pszFile)
757{
758 DWORD dwRqId, dwResult;
759 CSCPMessage msg;
760 int i;
761
762 if (!m_bIsConnected)
763 return ERR_NOT_CONNECTED;
764
765 dwRqId = m_dwRequestId++;
766
767 msg.SetCode(CMD_TRANSFER_FILE);
768 msg.SetId(dwRqId);
769 for(i = _tcslen(pszFile) - 1;
770 (i >= 0) && (pszFile[i] != '\\') && (pszFile[i] != '/'); i--);
771 msg.SetVariable(VID_FILE_NAME, &pszFile[i + 1]);
772
773 if (SendMessage(&msg))
774 {
775 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
776 }
777 else
778 {
779 dwResult = ERR_CONNECTION_BROKEN;
780 }
781
782 if (dwResult == ERR_SUCCESS)
783 {
784 if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile))
785 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
786 else
787 dwResult = ERR_IO_FAILURE;
788 }
789
790 return dwResult;
791}
e925a5fc
VK
792
793
794//
795// Send upgrade command
796//
797
798DWORD AgentConnection::StartUpgrade(TCHAR *pszPkgName)
799{
800 DWORD dwRqId, dwResult;
801 CSCPMessage msg;
802 int i;
803
804 if (!m_bIsConnected)
805 return ERR_NOT_CONNECTED;
806
807 dwRqId = m_dwRequestId++;
808
809 msg.SetCode(CMD_UPGRADE_AGENT);
810 msg.SetId(dwRqId);
811 for(i = _tcslen(pszPkgName) - 1;
812 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
813 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
814
815 if (SendMessage(&msg))
816 {
817 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
818 }
819 else
820 {
821 dwResult = ERR_CONNECTION_BROKEN;
822 }
823
824 return dwResult;
825}
3f0ca036
VK
826
827
828//
829// Check status of network service via agent
830//
831
832DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
833 WORD wPort, WORD wProto,
834 TCHAR *pszRequest, TCHAR *pszResponce)
835{
836 DWORD dwRqId, dwResult;
837 CSCPMessage msg, *pResponce;
838 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
839
840 if (!m_bIsConnected)
841 return ERR_NOT_CONNECTED;
842
843 dwRqId = m_dwRequestId++;
844
845 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
846 msg.SetId(dwRqId);
847 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
848 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
849 msg.SetVariable(VID_IP_PORT,
850 (wPort != 0) ? wPort :
25376fc7 851 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
3f0ca036 852 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
25376fc7 853 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
3f0ca036
VK
854 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
855 msg.SetVariable(VID_SERVICE_RESPONCE, pszResponce);
856
857 if (SendMessage(&msg))
858 {
859 // Wait up to 90 seconds for results
860 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
861 if (pResponce != NULL)
862 {
863 dwResult = pResponce->GetVariableLong(VID_RCC);
864 if (dwResult == ERR_SUCCESS)
865 {
866 *pdwStatus = pResponce->GetVariableLong(VID_SERVICE_STATUS);
867 }
868 delete pResponce;
869 }
870 else
871 {
872 dwResult = ERR_REQUEST_TIMEOUT;
873 }
874 }
875 else
876 {
877 dwResult = ERR_CONNECTION_BROKEN;
878 }
879
880 return dwResult;
881}
125c0e81
VK
882
883
884//
885// Get list of supported parameters from subagent
886//
887
888DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
889{
890 DWORD i, dwId, dwRqId, dwResult;
891 CSCPMessage msg, *pResponce;
892
893 if (!m_bIsConnected)
894 return ERR_NOT_CONNECTED;
895
896 *pdwNumParams = 0;
897 *ppParamList = NULL;
898
899 dwRqId = m_dwRequestId++;
900
901 msg.SetCode(CMD_GET_PARAMETER_LIST);
902 msg.SetId(dwRqId);
903
904 if (SendMessage(&msg))
905 {
906 // Wait up to 90 seconds for results
907 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
908 if (pResponce != NULL)
909 {
910 dwResult = pResponce->GetVariableLong(VID_RCC);
911 if (dwResult == ERR_SUCCESS)
912 {
913 *pdwNumParams = pResponce->GetVariableLong(VID_NUM_PARAMETERS);
914 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * *pdwNumParams);
915 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
916 {
917 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
918 pResponce->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
919 (*ppParamList)[i].iDataType = (int)pResponce->GetVariableShort(dwId++);
920 }
921 }
922 delete pResponce;
923 }
924 else
925 {
926 dwResult = ERR_REQUEST_TIMEOUT;
927 }
928 }
929 else
930 {
931 dwResult = ERR_CONNECTION_BROKEN;
932 }
933
934 return dwResult;
935}
e44ac467
VK
936
937
938//
939// Setup encryption
940//
941
942DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
943{
944#ifdef _WITH_ENCRYPTION
945 CSCPMessage msg, *pResp;
946 DWORD dwRqId, dwError, dwResult;
947
948 dwRqId = m_dwRequestId++;
949
950 PrepareKeyRequestMsg(&msg, pServerKey);
951 msg.SetId(dwRqId);
952 if (SendMessage(&msg))
953 {
954 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
955 if (pResp != NULL)
956 {
957 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey);
958 switch(dwResult)
959 {
960 case RCC_SUCCESS:
961 dwError = ERR_SUCCESS;
962 break;
963 case RCC_NO_CIPHERS:
964 dwError = ERR_NO_CIPHERS;
965 break;
966 case RCC_INVALID_PUBLIC_KEY:
967 dwError = ERR_INVALID_PUBLIC_KEY;
968 break;
969 case RCC_INVALID_SESSION_KEY:
970 dwError = ERR_INVALID_SESSION_KEY;
971 break;
972 default:
973 dwError = ERR_INTERNAL_ERROR;
974 break;
975 }
976 }
977 else
978 {
979 dwError = ERR_REQUEST_TIMEOUT;
980 }
981 }
982 else
983 {
984 dwError = ERR_CONNECTION_BROKEN;
985 }
986
987 return dwError;
988#else
989 return ERR_NOT_IMPLEMENTED;
990#endif
991}