- Added encryption foundation
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 19 Jun 2005 19:20:41 +0000 (19:20 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 19 Jun 2005 19:20:41 +0000 (19:20 +0000)
- Encryption between server and agent almost working

20 files changed:
include/nms_agent.h
include/nms_common.h
include/nms_cscp.h
include/nxclapi.h
include/nxcscpapi.h
src/agent/core/messages.mc
src/agent/core/nxagentd.cpp
src/agent/core/nxagentd.h
src/agent/core/session.cpp
src/libnxcl/comm.cpp
src/libnxcl/main.cpp
src/server/core/admin.cpp
src/server/core/main.cpp
src/server/core/session.cpp
src/server/include/nms_core.h
src/server/include/nxsrvapi.h
src/server/libnxsrv/agent.cpp
src/server/libnxsrv/main.cpp
src/server/tools/nxget/nxget.cpp
src/server/tools/nxget/nxget.dsp

index fd32e53..78628e3 100644 (file)
 #define ERR_IO_FAILURE              ((DWORD)903)
 #define ERR_RESOURCE_BUSY           ((DWORD)904)
 #define ERR_EXEC_FAILED             ((DWORD)905)
+#define ERR_ENCRYPTION_REQUIRED     ((DWORD)906)
+#define ERR_NO_CIPHERS              ((DWORD)907)
+#define ERR_INVALID_PUBLIC_KEY      ((DWORD)908)
+#define ERR_INVALID_SESSION_KEY     ((DWORD)909)
 
 
 //
index 3ea1c08..2f69d4e 100644 (file)
@@ -56,6 +56,8 @@
 #define INVALID_POINTER_VALUE    ((void *)0xFFFFFFFF)
 #define MAX_DB_STRING            256
 #define MAX_PARAM_NAME           256
+
+#define NETXMS_MAX_CIPHERS       4
 #define NETXMS_RSA_KEYLEN        2048
 
 #ifndef LLONG_MAX
@@ -277,6 +279,13 @@ typedef int SOCKET;
 #include <openssl/crypto.h>
 #include <openssl/rsa.h>
 #include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#else
+
+// Prevent compilation errors on function prototypes
+#define RSA void
 
 #endif
 
index 0402f11..2c0d78f 100644 (file)
 // Constants
 //
 
-#define SERVER_LISTEN_PORT       4701
-#define MAX_DCI_STRING_VALUE     256
-#define CSCP_HEADER_SIZE         16
+#define SERVER_LISTEN_PORT             4701
+#define MAX_DCI_STRING_VALUE           256
+#define CSCP_HEADER_SIZE               16
+#define CSCP_ENCRYPTION_HEADER_SIZE    16
+#define CSCP_EH_UNENCRYPTED_BYTES      8
+#define CSCP_EH_ENCRYPTED_BYTES        (CSCP_ENCRYPTION_HEADER_SIZE - CSCP_EH_UNENCRYPTED_BYTES)
+
+
+//
+// Ciphers
+//
+
+#define CSCP_CIPHER_AES_256      0
+#define CSCP_CIPHER_BLOWFISH     1
+#define CSCP_CIPHER_IDEA         2
+#define CSCP_CIPHER_3DES         3
+
+#define CSCP_SUPPORT_AES_256     0x01
+#define CSCP_SUPPORT_BLOWFISH    0x02
+#define CSCP_SUPPORT_IDEA        0x04
+#define CSCP_SUPPORT_3DES        0x08
 
 
 //
@@ -87,6 +105,31 @@ typedef struct
 } CSCP_MESSAGE;
 
 
+//
+// Encrypted payload header
+//
+
+typedef struct
+{
+   DWORD dwChecksum;
+   DWORD dwReserved; // Align to 8-byte boundary
+} CSCP_ENCRYPTED_PAYLOAD_HEADER;
+
+
+//
+// Encrypted message structure
+//
+
+typedef struct
+{
+   WORD wCode;       // Should be CMD_ENCRYPTED_MESSAGE
+   BYTE nPadding;    // Number of bytes added to the end of message
+   BYTE nReserved;
+   DWORD dwSize;     // Size of encrypted message (including encryption header and padding)
+   BYTE data[1];     // Encrypted payload
+} CSCP_ENCRYPTED_MESSAGE;
+
+
 //
 // DCI data header structure
 //
@@ -140,6 +183,18 @@ typedef struct
 #pragma pack()
 
 
+//
+// CSCP encryption context
+//
+
+typedef struct
+{
+   int nCipher;            // Encryption algorithm
+   BYTE *pSessionKey;      // Current session key
+   int nKeyLen;            // Session key length in bytes
+} CSCP_ENCRYPTION_CONTEXT;
+
+
 //
 // Data types
 //
@@ -156,8 +211,9 @@ typedef struct
 // Message flags
 //
 
-#define MF_BINARY    0x0001
-#define MF_EOF       0x0002
+#define MF_BINARY          0x0001
+#define MF_EOF             0x0002
+#define MF_DONT_ENCRYPT    0x0004
 
 
 //
@@ -293,6 +349,9 @@ typedef struct
 #define CMD_ADM_MESSAGE             0x007F
 #define CMD_ADM_REQUEST             0x0080
 #define CMD_CHANGE_IP_ADDR          0x0081
+#define CMD_REQUEST_SESSION_KEY     0x0082
+#define CMD_ENCRYPTED_MESSAGE       0x0083
+#define CMD_SESSION_KEY             0x0084
 
 
 //
@@ -452,6 +511,10 @@ typedef struct
 #define VID_IP_ADDR_LIST            ((DWORD)151)
 #define VID_REMOVE_DCI              ((DWORD)152)
 #define VID_TEMPLATE_ID             ((DWORD)153)
+#define VID_PUBLIC_KEY              ((DWORD)154)
+#define VID_SESSION_KEY             ((DWORD)155)
+#define VID_CIPHER                  ((DWORD)156)
+#define VID_KEY_LENGTH              ((DWORD)157)
 
 // Variable ranges for object's ACL
 #define VID_ACL_USER_BASE           ((DWORD)0x00001000)
index 45e7a86..747dbd6 100644 (file)
@@ -262,6 +262,9 @@ typedef void * NXC_SESSION;
 #define RCC_VARIABLE_NOT_FOUND      ((DWORD)39)
 #define RCC_BAD_PROTOCOL            ((DWORD)40)
 #define RCC_ADDRESS_IN_USE          ((DWORD)41)
+#define RCC_NO_CIPHERS              ((DWORD)42)
+#define RCC_INVALID_PUBLIC_KEY      ((DWORD)43)
+#define RCC_INVALID_SESSION_KEY     ((DWORD)44)
 
 
 //
index 56a4fd4..6fe3c11 100644 (file)
@@ -69,6 +69,7 @@ private:
    DWORD m_dwId;
    DWORD m_dwNumVar;    // Number of variables
    CSCP_DF **m_ppVarList;   // List of variables
+   BOOL m_bDontEncrypt;
 
    void *Set(DWORD dwVarId, BYTE bType, void *pValue, DWORD dwSize = 0);
    void *Get(DWORD dwVarId, BYTE bType);
@@ -106,6 +107,8 @@ public:
    DWORD GetVariableInt32Array(DWORD dwVarId, DWORD dwNumElements, DWORD *pdwBuffer);
 
    void DeleteAllVariables(void);
+
+   void DisableEncryption(void) { m_bDontEncrypt = TRUE; }
 };
 
 
@@ -173,15 +176,29 @@ public:
 extern "C" {
 #endif
 
-int LIBNXCSCP_EXPORTABLE RecvCSCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg, 
-                                         CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize);
+int LIBNXCSCP_EXPORTABLE RecvCSCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg,
+                                         CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize,
+                                         CSCP_ENCRYPTION_CONTEXT *pCtx, 
+                                         BYTE *pDecryptionBuffer);
 CSCP_MESSAGE LIBNXCSCP_EXPORTABLE *CreateRawCSCPMessage(WORD wCode, DWORD dwId,
                                                         DWORD dwDataSize, void *pData,
                                                         CSCP_MESSAGE *pBuffer);
 TCHAR LIBNXCSCP_EXPORTABLE *CSCPMessageCodeName(WORD wCode, TCHAR *pszBuffer);
 BOOL LIBNXCSCP_EXPORTABLE SendFileOverCSCP(SOCKET hSocket, DWORD dwId, TCHAR *pszFile);
    
-BOOL LIBNXCSCP_EXPORTABLE InitCryptoLib(void);
+BOOL LIBNXCSCP_EXPORTABLE InitCryptoLib(DWORD dwEnabledCiphers);
+CSCP_ENCRYPTED_MESSAGE LIBNXCSCP_EXPORTABLE 
+   *CSCPEncryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx, CSCP_MESSAGE *pMsg);
+BOOL LIBNXCSCP_EXPORTABLE CSCPDecryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx,
+                                             CSCP_ENCRYPTED_MESSAGE *pMsg,
+                                             BYTE *pDecryptionBuffer);
+DWORD LIBNXCSCP_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg, 
+                                                  CSCP_ENCRYPTION_CONTEXT **ppCtx,
+                                                  CSCPMessage **ppResponce,
+                                                  RSA *pPrivateKey);
+void LIBNXCSCP_EXPORTABLE DestroyEncryptionContext(CSCP_ENCRYPTION_CONTEXT *pCtx);
+void LIBNXCSCP_EXPORTABLE PrepareKeyRequestMsg(CSCPMessage *pMsg, RSA *pServerKey);
+RSA LIBNXCSCP_EXPORTABLE *LoadRSAKeys(TCHAR *pszKeyFile);
 
 #ifdef __cplusplus
 }
index be1a105..27f724d 100644 (file)
@@ -170,4 +170,16 @@ Language=English
 Signal %1 received
 .
 
+MessageId=
+SymbolicName=MSG_INIT_CRYPTO_FAILED
+Language=English
+Failed to initialize cryptografy module
+.
+
+MessageId=
+SymbolicName=MSG_DECRYPTION_FAILURE
+Language=English
+Failed to decrypt received message
+.
+
 ;#endif
index 6d86bc9..d2dc949 100644 (file)
@@ -112,7 +112,7 @@ static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
 // Configuration file template
 //
 
-static NX_CFG_TEMPLATE cfgTemplate[] =
+static NX_CFG_TEMPLATE m_cfgTemplate[] =
 {
    { "Action", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszActionList },
    { "EnableActions", CT_BOOLEAN, 0, 0, AF_ENABLE_ACTIONS, 0, &g_dwFlags },
@@ -124,6 +124,7 @@ static NX_CFG_TEMPLATE cfgTemplate[] =
    { "LogUnresolvedSymbols", CT_BOOLEAN, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS, 0, &g_dwFlags },
    { "PlatformSuffix", CT_STRING, 0, 0, MAX_PSUFFIX_LENGTH, 0, g_szPlatformSuffix },
    { "RequireAuthentication", CT_BOOLEAN, 0, 0, AF_REQUIRE_AUTH, 0, &g_dwFlags },
+   { "RequireEncryption", CT_BOOLEAN, 0, 0, AF_REQUIRE_ENCRYPTION, 0, &g_dwFlags },
    { "Servers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszServerList },
    { "SharedSecret", CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret },
    { "StartupDelay", CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay },
@@ -305,6 +306,13 @@ BOOL Initialize(void)
    // Initialize logger for subagents
    InitSubAgentsLogger(WriteSubAgentMsg);
 
+   // Initialize cryptografy
+   if (!InitCryptoLib(0xFFFF))
+   {
+      WriteLog(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
+      return FALSE;
+   }
+
    // Initialize built-in parameters
    if (!InitParameterList())
       return FALSE;
@@ -599,7 +607,7 @@ int main(int argc, char *argv[])
    switch(iAction)
    {
       case ACTION_RUN_AGENT:
-         if (NxLoadConfig(g_szConfigFile, "", cfgTemplate, !(g_dwFlags & AF_DAEMON)) == NXCFG_ERR_OK)
+         if (NxLoadConfig(g_szConfigFile, "", m_cfgTemplate, !(g_dwFlags & AF_DAEMON)) == NXCFG_ERR_OK)
          {
             if ((!stricmp(g_szLogFile, "{syslog}")) || 
                 (!stricmp(g_szLogFile, "{eventlog}")))
@@ -677,7 +685,7 @@ int main(int argc, char *argv[])
          }
          break;
       case ACTION_CHECK_CONFIG:
-         if (NxLoadConfig(g_szConfigFile, "", cfgTemplate, !(g_dwFlags & AF_DAEMON)) != NXCFG_ERR_OK)
+         if (NxLoadConfig(g_szConfigFile, "", m_cfgTemplate, !(g_dwFlags & AF_DAEMON)) != NXCFG_ERR_OK)
          {
             ConsolePrintf("Configuration file check failed\n");
             iExitCode = 2;
index 412ad23..88c8163 100644 (file)
@@ -93,6 +93,7 @@
 #define AF_REQUIRE_AUTH             0x0008
 #define AF_LOG_UNRESOLVED_SYMBOLS   0x0010
 #define AF_ENABLE_ACTIONS           0x0020
+#define AF_REQUIRE_ENCRYPTION       0x0040
 #define AF_SHUTDOWN                 0x1000
 
 
@@ -223,6 +224,7 @@ private:
    BOOL m_bInstallationServer;
    int m_hCurrFile;
    DWORD m_dwFileRqId;
+   CSCP_ENCRYPTION_CONTEXT *m_pCtx;
 
    void Authenticate(CSCPMessage *pRequest, CSCPMessage *pMsg);
    void GetParameter(CSCPMessage *pRequest, CSCPMessage *pMsg);
index de5a07c..8492922 100644 (file)
@@ -93,6 +93,7 @@ CommSession::CommSession(SOCKET hSocket, DWORD dwHostAddr, BOOL bInstallationSer
    m_bIsAuthenticated = (g_dwFlags & AF_REQUIRE_AUTH) ? FALSE : TRUE;
    m_bInstallationServer = bInstallationServer;
    m_hCurrFile = -1;
+   m_pCtx = NULL;
 }
 
 
@@ -109,6 +110,7 @@ CommSession::~CommSession()
    safe_free(m_pMsgBuffer);
    if (m_hCurrFile != -1)
       close(m_hCurrFile);
+   DestroyEncryptionContext(m_pCtx);
 }
 
 
@@ -132,23 +134,35 @@ void CommSession::ReadThread(void)
 {
    CSCP_MESSAGE *pRawMsg;
    CSCPMessage *pMsg;
+   BYTE *pDecryptionBuffer = NULL;
    int iErr;
    char szBuffer[256];
    WORD wFlags;
 
    // Initialize raw message receiving function
-   RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0);
+   RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0, NULL, NULL);
 
    pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
+#ifdef _WITH_ENCRYPTION
+   pDecryptionBuffer = (BYTE *)malloc(RAW_MSG_SIZE);
+#endif
    while(1)
    {
-      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE)) <= 0)
+      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE,
+                                  m_pCtx, pDecryptionBuffer)) <= 0)
          break;
 
       // Check if message is too large
       if (iErr == 1)
          continue;
 
+      // Check for decryption failure
+      if (iErr == 2)
+      {
+         WriteLog(MSG_DECRYPTION_FAILURE, EVENTLOG_WARNING_TYPE, NULL);
+         continue;
+      }
+
       // Check that actual received packet size is equal to encoded in packet
       if ((int)ntohl(pRawMsg->dwSize) != iErr)
       {
@@ -204,12 +218,30 @@ void CommSession::ReadThread(void)
       {
          // Create message object from raw message
          pMsg = new CSCPMessage(pRawMsg);
-         m_pMessageQueue->Put(pMsg);
+         if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
+         {
+            if (m_pCtx == NULL)
+            {
+               CSCPMessage *pResponce;
+
+               SetupEncryptionContext(pMsg, &m_pCtx, &pResponce, NULL);
+               SendMessage(pResponce);
+               delete pResponce;
+            }
+            delete pMsg;
+         }
+         else
+         {
+            m_pMessageQueue->Put(pMsg);
+         }
       }
    }
    if (iErr < 0)
       WriteLog(MSG_SESSION_BROKEN, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
    free(pRawMsg);
+#ifdef _WITH_ENCRYPTION
+   free(pDecryptionBuffer);
+#endif
 
    // Notify other threads to exit
    m_pSendQueue->Put(INVALID_POINTER_VALUE);
@@ -239,12 +271,31 @@ void CommSession::WriteThread(void)
          break;
 
       DebugPrintf("Sending message %s", CSCPMessageCodeName(ntohs(pMsg->wCode), szBuffer));
-      if (SendEx(m_hSocket, (const char *)pMsg, ntohl(pMsg->dwSize), 0) <= 0)
+      if (m_pCtx != NULL)
       {
+         CSCP_ENCRYPTED_MESSAGE *pEnMsg;
+
+         pEnMsg = CSCPEncryptMessage(m_pCtx, pMsg);
+         free(pMsg);
+         if (pEnMsg != NULL)
+         {
+            if (SendEx(m_hSocket, (const char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) <= 0)
+            {
+               free(pEnMsg);
+               break;
+            }
+            free(pEnMsg);
+         }
+      }
+      else
+      {
+         if (SendEx(m_hSocket, (const char *)pMsg, ntohl(pMsg->dwSize), 0) <= 0)
+         {
+            free(pMsg);
+            break;
+         }
          free(pMsg);
-         break;
       }
-      free(pMsg);
    }
 }
 
@@ -278,6 +329,10 @@ void CommSession::ProcessingThread(void)
       {
          msg.SetVariable(VID_RCC, ERR_AUTH_REQUIRED);
       }
+      else if ((g_dwFlags & AF_REQUIRE_ENCRYPTION) && (m_pCtx == NULL))
+      {
+         msg.SetVariable(VID_RCC, ERR_ENCRYPTION_REQUIRED);
+      }
       else
       {
          switch(dwCommand)
index 618a600..259b42a 100644 (file)
@@ -42,7 +42,7 @@ THREAD_RESULT THREAD_CALL NetReceiver(NXCL_Session *pSession)
 
    // Initialize raw message receiving function
    pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
-   RecvCSCPMessage(0, NULL, pMsgBuffer, 0);
+   RecvCSCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL);
 
    // Allocate space for raw message
    pRawMsg = (CSCP_MESSAGE *)malloc(pSession->m_dwReceiverBufferSize);
index 011593f..fb35aa8 100644 (file)
@@ -56,7 +56,7 @@ void DebugPrintf(TCHAR *szFormat, ...)
 
 BOOL LIBNXCL_EXPORTABLE NXCInitialize(void)
 {
-   return TRUE;
+   return InitCryptoLib(0xFFFF);
 }
 
 
@@ -169,9 +169,11 @@ const TCHAR LIBNXCL_EXPORTABLE *NXCGetErrorText(DWORD dwError)
       _T("Action is used in event processing policy"),
       _T("Variable not found"),
       _T("Server uses incompatible version of communication protocol"),
-      _T("Address already in use")
+      _T("Address already in use"),
+      _T("Unable to select cipher"),
+      _T("Invalid public key")
    };
-   return ((dwError >= 0) && (dwError <= RCC_ADDRESS_IN_USE)) ? pszErrorText[dwError] : _T("Unknown error code");
+   return ((dwError >= 0) && (dwError <= RCC_INVALID_PUBLIC_KEY)) ? pszErrorText[dwError] : _T("Unknown error code");
 }
 
 
index b2af318..60df1d9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: admin.cpp,v 1.9 2005-04-07 15:50:58 victor Exp $ */
+/* $Id: admin.cpp,v 1.10 2005-06-19 19:20:40 victor Exp $ */
 
 /* 
 ** NetXMS - Network Management System
@@ -49,13 +49,13 @@ static THREAD_RESULT THREAD_CALL ProcessingThread(void *pArg)
 
    pRawMsg = (CSCP_MESSAGE *)malloc(MAX_MSG_SIZE);
    pRecvBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
-   RecvCSCPMessage(0, NULL, pRecvBuffer, 0);
+   RecvCSCPMessage(0, NULL, pRecvBuffer, 0, NULL, NULL);
    ctx.hSocket = sock;
    ctx.pMsg = &responce;
 
    while(1)
    {
-      iError = RecvCSCPMessage(sock, pRawMsg, pRecvBuffer, MAX_MSG_SIZE);
+      iError = RecvCSCPMessage(sock, pRawMsg, pRecvBuffer, MAX_MSG_SIZE, NULL, NULL);
       if (iError <= 0)
          break;   // Communication error or closed connection
 
@@ -163,6 +163,10 @@ THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg)
 /*
 
 $Log: not supported by cvs2svn $
+Revision 1.9  2005/04/07 15:50:58  victor
+- Implemented save and restore for DCI graph windows
+- More commands added to server console
+
 Revision 1.8  2005/04/06 16:16:25  victor
 Local administrator interface completely rewritten
 
index a627dcf..32b7904 100644 (file)
@@ -195,45 +195,18 @@ static BOOL InitCryptografy(void)
 #ifdef _WITH_ENCRYPTION
    char szKeyFile[MAX_PATH];
    BOOL bResult = FALSE;
-   int fd, iLen;
+   int fd;
+   DWORD dwLen;
    BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
 
-   if (!InitCryptoLib())
+   if (!InitCryptoLib(0xFFFF))
       return FALSE;
 
    strcpy(szKeyFile, g_szDataDir);
    strcat(szKeyFile, DFILE_KEYS);
    fd = open(szKeyFile, O_RDONLY | O_BINARY);
-   if (fd != -1)
-   {
-      if (read(fd, &iLen, sizeof(int)) == sizeof(int))
-      {
-         pKeyBuffer = (BYTE *)malloc(iLen);
-         pBufPos = pKeyBuffer;
-         if (read(fd, pKeyBuffer, iLen) == iLen)
-         {
-            BYTE hash2[SHA1_DIGEST_SIZE];
-
-            read(fd, hash, SHA1_DIGEST_SIZE);
-            CalculateSHA1Hash(pKeyBuffer, iLen, hash2);
-            if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
-            {
-               g_pServerKey = d2i_RSAPublicKey(NULL, (const BYTE **)&pBufPos, iLen);
-               if (g_pServerKey != NULL)
-               {
-                  if (d2i_RSAPrivateKey(&g_pServerKey, (const BYTE **)&pBufPos,
-                                        iLen - (pBufPos - pKeyBuffer)) != NULL)
-                  {
-                     bResult = TRUE;
-                  }
-               }
-            }
-         }
-         free(pKeyBuffer);
-      }
-      close(fd);
-   }
-   else
+   g_pServerKey = LoadRSAKeys(szKeyFile);
+   if (g_pServerKey == NULL)
    {
       DbgPrintf(AF_DEBUG_MISC, "Generating RSA key pair...");
       g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, 0);
@@ -242,17 +215,17 @@ static BOOL InitCryptografy(void)
          fd = open(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
          if (fd != -1)
          {
-            iLen = i2d_RSAPublicKey(g_pServerKey, NULL);
-            iLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
-            pKeyBuffer = (BYTE *)malloc(iLen);
+            dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
+            dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
+            pKeyBuffer = (BYTE *)malloc(dwLen);
 
             pBufPos = pKeyBuffer;
             i2d_RSAPublicKey(g_pServerKey, &pBufPos);
             i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
-            write(fd, &iLen, sizeof(int));
-            write(fd, pKeyBuffer, iLen);
+            write(fd, &dwLen, sizeof(DWORD));
+            write(fd, pKeyBuffer, dwLen);
 
-            CalculateSHA1Hash(pKeyBuffer, iLen, hash);
+            CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
             write(fd, hash, SHA1_DIGEST_SIZE);
             
             close(fd);
index e0dbd4e..1af1fb0 100644 (file)
@@ -268,12 +268,12 @@ void ClientSession::ReadThread(void)
    WORD wFlags;
 
    // Initialize raw message receiving function
-   RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0);
+   RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0, NULL, NULL);
 
    pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
    while(1)
    {
-      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE)) <= 0)
+      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE, NULL, NULL)) <= 0)
          break;
 
       // Check if message is too large
index 19559a7..10137ad 100644 (file)
@@ -109,35 +109,6 @@ typedef __console_ctx * CONSOLE_CTX;
 // Common constants and macros
 //
 
-#ifdef _WIN32
-
-# define DEFAULT_SHELL         "cmd.exe"
-# define DEFAULT_LOG_FILE      "C:\\NetXMS.log"
-# define DEFAULT_DATA_DIR      "C:\\NetXMS\\var"
-
-# define DDIR_MIBS             "\\mibs"
-# define DDIR_IMAGES           "\\images"
-# define DDIR_PACKAGES         "\\packages"
-# define DFILE_KEYS            "\\server_key"
-
-#else    /* _WIN32 */
-
-# define DEFAULT_SHELL         "/bin/sh"
-
-# ifndef DATADIR
-#  define DATADIR              "/var/netxms"
-# endif
-
-# define DEFAULT_LOG_FILE      DATADIR"/log/netxmsd.log"
-# define DEFAULT_DATA_DIR      DATADIR
-
-# define DDIR_MIBS             "/mibs"
-# define DDIR_IMAGES           "/images"
-# define DDIR_PACKAGES         "/packages"
-# define DFILE_KEYS            "/.server_key"
-
-#endif   /* _WIN32 */
-
 #define MAX_LINE_SIZE         4096
 
 #define GROUP_FLAG_BIT     ((DWORD)0x80000000)
index e16bb52..d1cde5f 100644 (file)
 //
 
 #ifdef _WIN32
-#define DEFAULT_CONFIG_FILE   _T("C:\\netxmsd.conf")
-#else
-#define DEFAULT_CONFIG_FILE   _T("/etc/netxmsd.conf")
-#endif
+
+# define DEFAULT_CONFIG_FILE   _T("C:\\netxmsd.conf")
+
+# define DEFAULT_SHELL         "cmd.exe"
+# define DEFAULT_LOG_FILE      "C:\\NetXMS.log"
+# define DEFAULT_DATA_DIR      "C:\\NetXMS\\var"
+
+# define DDIR_MIBS             "\\mibs"
+# define DDIR_IMAGES           "\\images"
+# define DDIR_PACKAGES         "\\packages"
+# define DFILE_KEYS            "\\server_key"
+
+#else    /* _WIN32 */
+
+# define DEFAULT_CONFIG_FILE   _T("/etc/netxmsd.conf")
+
+# define DEFAULT_SHELL         "/bin/sh"
+
+# ifndef DATADIR
+#  define DATADIR              "/var/netxms"
+# endif
+
+# define DEFAULT_LOG_FILE      DATADIR"/log/netxmsd.log"
+# define DEFAULT_DATA_DIR      DATADIR
+
+# define DDIR_MIBS             "/mibs"
+# define DDIR_IMAGES           "/images"
+# define DDIR_PACKAGES         "/packages"
+# define DFILE_KEYS            "/.server_key"
+
+#endif   /* _WIN32 */
 
 
 //
@@ -150,6 +177,7 @@ private:
    BOOL m_bIsConnected;
    MUTEX m_mutexDataLock;
    THREAD m_hReceiverThread;
+   CSCP_ENCRYPTION_CONTEXT *m_pCtx;
 
    void ReceiverThread(void);
    static THREAD_RESULT THREAD_CALL ReceiverThreadStarter(void *);
@@ -160,6 +188,7 @@ protected:
    CSCPMessage *WaitForMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut) { return m_pMsgWaitQueue->WaitForMessage(wCode, dwId, dwTimeOut); }
    DWORD WaitForRCC(DWORD dwRqId, DWORD dwTimeOut);
    DWORD Authenticate(void);
+   DWORD SetupEncryption(RSA *pServerKey);
 
    virtual void PrintMsg(TCHAR *pszFormat, ...);
    virtual void OnTrap(CSCPMessage *pMsg);
@@ -172,7 +201,7 @@ public:
    AgentConnection(DWORD dwAddr, WORD wPort = AGENT_LISTEN_PORT, int iAuthMethod = AUTH_NONE, TCHAR *szSecret = NULL);
    ~AgentConnection();
 
-   BOOL Connect(BOOL bVerbose = FALSE);
+   BOOL Connect(RSA *pServerKey = NULL, BOOL bVerbose = FALSE);
    void Disconnect(void);
    BOOL IsConnected(void) { return m_bIsConnected; }
 
index fe63bc6..127de0b 100644 (file)
@@ -63,6 +63,7 @@ AgentConnection::AgentConnection()
    m_bIsConnected = FALSE;
    m_mutexDataLock = MutexCreate();
    m_hReceiverThread = INVALID_THREAD_HANDLE;
+   m_pCtx = NULL;
 }
 
 
@@ -98,6 +99,7 @@ AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort, int iAuthMethod, TCHA
    m_bIsConnected = FALSE;
    m_mutexDataLock = MutexCreate();
    m_hReceiverThread = INVALID_THREAD_HANDLE;
+   m_pCtx = NULL;
 }
 
 
@@ -120,6 +122,7 @@ AgentConnection::~AgentConnection()
    Unlock();
 
    delete m_pMsgWaitQueue;
+   DestroyEncryptionContext(m_pCtx);
 
    MutexDestroy(m_mutexDataLock);
 }
@@ -150,21 +153,26 @@ void AgentConnection::ReceiverThread(void)
    CSCPMessage *pMsg;
    CSCP_MESSAGE *pRawMsg;
    CSCP_BUFFER *pMsgBuffer;
+   BYTE *pDecryptionBuffer = NULL;
    int iErr;
    TCHAR szBuffer[128];
 
    // Initialize raw message receiving function
    pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
-   RecvCSCPMessage(0, NULL, pMsgBuffer, 0);
+   RecvCSCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL);
 
    // Allocate space for raw message
    pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
+#ifdef _WITH_ENCRYPTION
+   pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
+#endif
 
    // Message receiving loop
    while(1)
    {
       // Receive raw message
-      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE)) <= 0)
+      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
+                                  m_pCtx, pDecryptionBuffer)) <= 0)
          break;
 
       // Check if we get too large message
@@ -176,6 +184,13 @@ void AgentConnection::ReceiverThread(void)
          continue;
       }
 
+      // Check if we are unable to decrypt message
+      if (iErr == 2)
+      {
+         PrintMsg(_T("Unable to decrypt received message"));
+         continue;
+      }
+
       // Check that actual received packet size is equal to encoded in packet
       if ((int)ntohl(pRawMsg->dwSize) != iErr)
       {
@@ -201,6 +216,8 @@ void AgentConnection::ReceiverThread(void)
       shutdown(m_hSocket, SHUT_RDWR);
    closesocket(m_hSocket);
    m_hSocket = -1;
+   DestroyEncryptionContext(m_pCtx);
+   m_pCtx = NULL;
    m_bIsConnected = FALSE;
 
    free(pRawMsg);
@@ -212,7 +229,7 @@ void AgentConnection::ReceiverThread(void)
 // Connect to agent
 //
 
-BOOL AgentConnection::Connect(BOOL bVerbose)
+BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose)
 {
    struct sockaddr_in sa;
    TCHAR szBuffer[256];
@@ -256,6 +273,14 @@ BOOL AgentConnection::Connect(BOOL bVerbose)
    // Start receiver thread
    m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
 
+   // Setup encryption
+   if (pServerKey != NULL)
+   {
+      dwError = SetupEncryption(pServerKey);
+      if (dwError != ERR_SUCCESS)
+         goto connect_cleanup;
+   }
+
    // Authenticate itself to agent
    if ((dwError = Authenticate()) != ERR_SUCCESS)
    {
@@ -284,6 +309,9 @@ connect_cleanup:
 
       if (m_hSocket != -1)
          closesocket(m_hSocket);
+
+      DestroyEncryptionContext(m_pCtx);
+      m_pCtx = NULL;
    }
    m_bIsConnected = bSuccess;
    return bSuccess;
@@ -559,10 +587,27 @@ DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
 BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
 {
    CSCP_MESSAGE *pRawMsg;
+   CSCP_ENCRYPTED_MESSAGE *pEnMsg;
    BOOL bResult;
 
    pRawMsg = pMsg->CreateMessage();
-   bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
+   if (m_pCtx != NULL)
+   {
+      pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
+      if (pEnMsg != NULL)
+      {
+         bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
+         free(pEnMsg);
+      }
+      else
+      {
+         bResult = FALSE;
+      }
+   }
+   else
+   {
+      bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
+   }
    free(pRawMsg);
    return bResult;
 }
@@ -888,3 +933,59 @@ DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PAR
 
    return dwResult;
 }
+
+
+//
+// Setup encryption
+//
+
+DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
+{
+#ifdef _WITH_ENCRYPTION
+   CSCPMessage msg, *pResp;
+   DWORD dwRqId, dwError, dwResult;
+
+   dwRqId = m_dwRequestId++;
+
+   PrepareKeyRequestMsg(&msg, pServerKey);
+   msg.SetId(dwRqId);
+   if (SendMessage(&msg))
+   {
+      pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
+      if (pResp != NULL)
+      {
+         dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey);
+         switch(dwResult)
+         {
+            case RCC_SUCCESS:
+               dwError = ERR_SUCCESS;
+               break;
+            case RCC_NO_CIPHERS:
+               dwError = ERR_NO_CIPHERS;
+               break;
+            case RCC_INVALID_PUBLIC_KEY:
+               dwError = ERR_INVALID_PUBLIC_KEY;
+               break;
+            case RCC_INVALID_SESSION_KEY:
+               dwError = ERR_INVALID_SESSION_KEY;
+               break;
+            default:
+               dwError = ERR_INTERNAL_ERROR;
+               break;
+         }
+      }
+      else
+      {
+         dwError = ERR_REQUEST_TIMEOUT;
+      }
+   }
+   else
+   {
+      dwError = ERR_CONNECTION_BROKEN;
+   }
+
+   return dwError;
+#else
+   return ERR_NOT_IMPLEMENTED;
+#endif
+}
index 96638a1..a5ad116 100644 (file)
@@ -52,6 +52,7 @@ static struct
    { ERR_IO_FAILURE, _T("I/O failure") },
    { ERR_RESOURCE_BUSY, _T("Resource busy") },
    { ERR_EXEC_FAILED, _T("External program execution failed") },
+   { ERR_ENCRYPTION_REQUIRED, _T("Encryption required") },
    { -1, NULL }
 };
 
index af14092..7376949 100644 (file)
@@ -159,16 +159,18 @@ static int ListParameters(AgentConnection *pConn)
 int main(int argc, char *argv[])
 {
    char *eptr;
-   BOOL bStart = TRUE, bBatchMode = FALSE, bShowNames = FALSE;
+   BOOL bStart = TRUE, bBatchMode = FALSE, bShowNames = FALSE, bEncrypt = FALSE;
    int i, ch, iPos, iExitCode = 3, iCommand = CMD_GET, iInterval = 0;
    int iAuthMethod = AUTH_NONE, iServiceType = NETSRV_SSH;
    WORD wAgentPort = AGENT_LISTEN_PORT, wServicePort = 0, wServiceProto = 0;
    DWORD dwTimeout = 3000, dwServiceAddr = 0;
-   char szSecret[MAX_SECRET_LENGTH] = "", szRequest[MAX_DB_STRING] = "", szResponce[MAX_DB_STRING] = "";
+   char szSecret[MAX_SECRET_LENGTH] = "", szRequest[MAX_DB_STRING] = "";
+   char szKeyFile[MAX_PATH] = DEFAULT_DATA_DIR DFILE_KEYS, szResponce[MAX_DB_STRING] = "";
+   RSA *pServerKey = NULL;
 
    // Parse command line
    opterr = 1;
-   while((ch = getopt(argc, argv, "a:bi:hIlnp:P:qr:R:s:S:t:vw:")) != -1)
+   while((ch = getopt(argc, argv, "a:behi:IK:lnp:P:qr:R:s:S:t:vw:")) != -1)
    {
       switch(ch)
       {
@@ -178,9 +180,16 @@ int main(int argc, char *argv[])
                    "   -a <auth>    : Authentication method. Valid methods are \"none\",\n"
                    "                  \"plain\", \"md5\" and \"sha1\". Default is \"none\".\n"
                    "   -b           : Batch mode - get all parameters listed on command line.\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -e           : Encrypt connection.\n"
+#endif
                    "   -h           : Display help and exit.\n"
                    "   -i <seconds> : Get specified parameter(s) continously with given interval.\n"
                    "   -I           : Get list of supported parameters.\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -K <file>    : Specify server's key file\n"
+                   "                  (default is " DEFAULT_DATA_DIR DFILE_KEYS ").\n"
+#endif
                    "   -l           : Get list of values for enum parameter.\n"
                    "   -n           : Show parameter's name in result.\n"
                    "   -p <port>    : Specify agent's port number. Default is %d.\n"
@@ -309,6 +318,20 @@ int main(int argc, char *argv[])
                dwTimeout = (DWORD)i * 1000;  // Convert to milliseconds
             }
             break;
+#ifdef _WITH_ENCRYPTION
+         case 'e':
+            bEncrypt = TRUE;
+            break;
+         case 'K':
+            strncpy(szKeyFile, optarg, MAX_PATH);
+            break;
+#else
+         case 'e':
+         case 'K':
+            printf("ERROR: This tool was compiled without encryption support\n");
+            bStart = FALSE;
+            break;
+#endif
          case '?':
             bStart = FALSE;
             break;
@@ -331,6 +354,19 @@ int main(int argc, char *argv[])
          bStart = FALSE;
       }
 
+      // Load server key if requested
+#ifdef _WITH_ENCRYPTION
+      if (bEncrypt && bStart)
+      {
+         pServerKey = LoadRSAKeys(szKeyFile);
+         if (pServerKey == NULL)
+         {
+            printf("Error loading RSA keys from \"%s\"\n", szKeyFile);
+            bStart = FALSE;
+         }
+      }
+#endif
+
       // If everything is ok, start communications
       if (bStart)
       {
@@ -349,7 +385,7 @@ int main(int argc, char *argv[])
             AgentConnection conn(m_dwAddr, wAgentPort, iAuthMethod, szSecret);
 
             conn.SetCommandTimeout(dwTimeout);
-            if (conn.Connect(m_bVerbose))
+            if (conn.Connect(pServerKey, m_bVerbose))
             {
                do
                {
index 40c6143..6835ab8 100644 (file)
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib libnetxms.lib libnxsrv.lib /nologo /version:0.1 /subsystem:console /machine:I386 /libpath:"..\..\..\libnetxms\Release" /libpath:"..\..\libnxsrv\Release"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib libnetxms.lib libnxsrv.lib libnxcscp.lib /nologo /version:0.1 /subsystem:console /machine:I386 /libpath:"..\..\..\libnetxms\Release" /libpath:"..\..\..\libnxcscp\Release" /libpath:"..\..\libnxsrv\Release"
 # Begin Special Build Tool
 SOURCE="$(InputPath)"
 PostBuild_Desc=Copy files
@@ -79,7 +79,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib libnetxms.lib libnxsrv.lib /nologo /version:0.1 /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\libnetxms\Debug" /libpath:"..\..\libnxsrv\Debug"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib libnetxms.lib libnxsrv.lib libnxcscp.lib /nologo /version:0.1 /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\libnetxms\Debug" /libpath:"..\..\..\libnxcscp\Debug" /libpath:"..\..\libnxsrv\Debug"
 # Begin Special Build Tool
 SOURCE="$(InputPath)"
 PostBuild_Desc=Copy Files
@@ -113,6 +113,10 @@ SOURCE=..\..\..\..\include\nms_common.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\..\include\nms_core.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\..\include\nms_util.h
 # End Source File
 # Begin Source File