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