- Added configuration parameter RunNetworkDiscovery
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 20 Jan 2004 08:48:23 +0000 (08:48 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 20 Jan 2004 08:48:23 +0000 (08:48 +0000)
- Added configuration parameter EnableAdminInterface
- Local administrative interface implemented
- Added access lists for objects
- Added EnableAccessControl and EnableEventAccessControl configuration paqrameters and appropriate application flags
- User management functions added (add, remove, etc.)

16 files changed:
.gitattributes
src/server/core/NmsCore.dsp
src/server/core/acl.cpp [new file with mode: 0644]
src/server/core/admin.cpp [new file with mode: 0644]
src/server/core/agent.cpp
src/server/core/config.cpp
src/server/core/datacoll.cpp
src/server/core/discovery.cpp
src/server/core/main.cpp
src/server/core/netobj.cpp
src/server/core/nms_core.h
src/server/core/nms_objects.h
src/server/core/nms_users.h
src/server/core/node.cpp
src/server/core/users.cpp
src/server/include/local_admin.h [copied from src/server/core/nms_users.h with 60% similarity]

index 3a6894b..9ee96fd 100644 (file)
@@ -12,6 +12,8 @@ sql/schema.sql -text
 sql/setup.sql -text
 src/server/core/NmsCore.dsp -text
 src/server/core/NmsCore.dsw -text
+src/server/core/acl.cpp -text
+src/server/core/admin.cpp -text
 src/server/core/agent.cpp -text
 src/server/core/client.cpp -text
 src/server/core/config.cpp -text
@@ -58,6 +60,7 @@ src/server/dbdrv/pgsql/pgsql.dsp -text
 src/server/dbdrv/pgsql/pgsql.dsw -text
 src/server/dbdrv/pgsql/pgsqldrv.h -text
 src/server/include/dbdrv.h -text
+src/server/include/local_admin.h -text
 src/server/include/nms_threads.h -text
 src/server/tools/nxadm/comm.cpp -text
 src/server/tools/nxadm/nxadm.cpp -text
index 0595864..86b68de 100644 (file)
@@ -87,6 +87,14 @@ LINK32=link.exe
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 # Begin Source File
 
+SOURCE=.\acl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\admin.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\agent.cpp
 # End Source File
 # Begin Source File
@@ -211,6 +219,10 @@ SOURCE=..\include\dbdrv.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\include\local_admin.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\include\nms_agent.h
 # End Source File
 # Begin Source File
diff --git a/src/server/core/acl.cpp b/src/server/core/acl.cpp
new file mode 100644 (file)
index 0000000..d05e723
--- /dev/null
@@ -0,0 +1,147 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: acl.cpp
+**
+**/
+
+#include "nms_core.h"
+
+
+//
+// Access list constructor
+//
+
+AccessList::AccessList()
+{
+   m_pElements = NULL;
+   m_dwNumElements = 0;
+   m_hMutex = MutexCreate();
+}
+
+
+//
+// Destructor
+//
+
+AccessList::~AccessList()
+{
+   if (m_pElements != NULL)
+      free(m_pElements);
+   MutexDestroy(m_hMutex);
+}
+
+
+//
+// Add element to list
+//
+
+void AccessList::AddElement(DWORD dwObjectId, DWORD dwAccessRights)
+{
+   DWORD i;
+
+   Lock();
+   for(i = 0; i < m_dwNumElements; i++)
+      if (m_pElements[i].dwObjectId == dwObjectId)    // Object already exist in list
+      {
+         m_pElements[i].dwAccessRights = dwAccessRights;
+         break;
+      }
+
+   if (i == m_dwNumElements)
+   {
+      m_pElements = (ACL_ELEMENT *)realloc(m_pElements, sizeof(ACL_ELEMENT) * (m_dwNumElements + 1));
+      m_pElements[m_dwNumElements].dwObjectId = dwObjectId;
+      m_pElements[m_dwNumElements].dwAccessRights = dwAccessRights;
+      m_dwNumElements++;
+   }
+   Unlock();
+}
+
+
+//
+// Delete element from list
+//
+
+void AccessList::DeleteElement(DWORD dwObjectId)
+{
+   DWORD i;
+
+   Lock();
+   for(i = 0; i < m_dwNumElements; i++)
+      if (m_pElements[i].dwObjectId == dwObjectId)
+      {
+         m_dwNumElements--;
+         memmove(&m_pElements[i], &m_pElements[i + 1], sizeof(ACL_ELEMENT) * (m_dwNumElements - i));
+         break;
+      }
+   Unlock();
+}
+
+
+//
+// Retrieve access rights for specific user object
+// Return TRUE on success and stores access rights to specific location
+// If user doesn't have explicit rights or via group, returns FALSE
+//
+
+BOOL AccessList::GetUserRights(DWORD dwUserId, DWORD *pdwAccessRights)
+{
+   DWORD i;
+   BOOL bFound = FALSE;
+
+   // Check for explicit rights
+   for(i = 0; i < m_dwNumElements; i++)
+      if (m_pElements[i].dwObjectId == dwUserId)
+      {
+         *pdwAccessRights = m_pElements[i].dwAccessRights;
+         bFound = TRUE;
+         break;
+      }
+
+   if (!bFound)
+   {
+      *pdwAccessRights = 0;   // Default: no access
+      for(i = 0; i < m_dwNumElements; i++)
+         if (m_pElements[i].dwObjectId & GROUP_FLAG)
+         {
+            if (CheckUserMembership(dwUserId, m_pElements[i].dwObjectId))
+            {
+               *pdwAccessRights |= m_pElements[i].dwAccessRights;
+               bFound = TRUE;
+            }
+         }
+   }
+
+   return bFound;
+}
+
+
+//
+// Enumerate all elements
+//
+
+void AccessList::EnumerateElements(void (* pHandler)(DWORD, DWORD, void *), void *pArg)
+{
+   DWORD i;
+
+   Lock();
+   for(i = 0; i < m_dwNumElements; i++)
+      pHandler(m_pElements[i].dwObjectId, m_pElements[i].dwAccessRights, pArg);
+   Unlock();
+}
diff --git a/src/server/core/admin.cpp b/src/server/core/admin.cpp
new file mode 100644 (file)
index 0000000..e57c4f8
--- /dev/null
@@ -0,0 +1,242 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: admin.cpp
+**
+**/
+
+#include "nms_core.h"
+#include <local_admin.h>
+
+
+//
+// Send success or error notification
+//
+
+#define SEND_ERROR() \
+   { \
+      wCmd = LA_RESP_ERROR; \
+      send(sock, (char *)&wCmd, sizeof(WORD), 0); \
+   }
+#define SEND_SUCCESS() \
+   { \
+      wCmd = LA_RESP_SUCCESS; \
+      send(sock, (char *)&wCmd, sizeof(WORD), 0); \
+   }
+
+
+
+//
+// Receive string from client
+//
+
+static BOOL RecvString(SOCKET sock, char *pBuffer, int iBufSize)
+{
+   int iError;
+   WORD wSize = 0;
+
+   // Receive string length
+   iError = recv(sock, (char *)&wSize, 2, 0);
+   if ((iError != 2) || (wSize > iBufSize - 1))
+      return FALSE;
+
+   iError = recv(sock, pBuffer, wSize, 0);
+   if (iError != wSize)
+      return FALSE;
+   pBuffer[iError] = 0;
+   return TRUE;
+}
+
+
+//
+// Send string to client
+//
+
+static BOOL SendString(SOCKET sock, char *szString)
+{
+   WORD wLen;
+
+   wLen = strlen(szString);
+   if (send(sock, (char *)&wLen, sizeof(WORD), 0) != 2)
+      return FALSE;
+
+   return send(sock, szString, wLen, 0) == wLen;
+}
+
+
+//
+// Request processing thread
+//
+
+static void ProcessingThread(void *pArg)
+{
+   SOCKET sock = (SOCKET)pArg;
+   WORD wCmd;
+   int iError;
+   char szBuffer[256];
+   DWORD dwTemp;
+
+   while(1)
+   {
+      iError = recv(sock, (char *)&wCmd, sizeof(WORD), 0);
+      if (iError != 2)
+         break;   // Communication error or closed connection
+
+      switch(wCmd)
+      {
+         case LA_CMD_LIST_CONFIG:
+            SEND_ERROR();
+            break;
+         case LA_CMD_GET_CONFIG:
+            // Receive variable name
+            if (RecvString(sock, szBuffer, 256))
+            {
+               char szValue[256];
+
+               if (ConfigReadStr(szBuffer, szValue, 255, ""))
+                  SendString(sock, szValue);
+               else
+                  SEND_ERROR();
+            }
+            else
+            {
+               goto close_connection;
+            }
+            break;
+         case LA_CMD_SET_CONFIG:
+            // Receive variable name
+            if (RecvString(sock, szBuffer, 256))
+            {
+               char szValue[256];
+
+               // Receive new value
+               if (RecvString(sock, szValue, 256))
+               {
+                  if (ConfigWriteStr(szBuffer, szValue, TRUE))
+                  {
+                     SEND_SUCCESS();
+                  }
+                  else
+                  {
+                     SEND_ERROR();
+                  }
+               }
+               else
+               {
+                  goto close_connection;
+               }
+            }
+            else
+            {
+               goto close_connection;
+            }
+            break;
+         case LA_CMD_GET_FLAGS:
+            // Send value of application flags
+            send(sock, (char *)&g_dwFlags, sizeof(DWORD), 0);
+            break;
+         case LA_CMD_SET_FLAGS:
+            iError = recv(sock, (char *)&dwTemp, sizeof(DWORD), 0);
+            if (iError == sizeof(DWORD))
+            {
+               dwTemp &= ~AF_STANDALONE;    // Standalone flag shouldn't be changed
+               g_dwFlags = dwTemp | (g_dwFlags & AF_STANDALONE);
+               SEND_SUCCESS();
+            }
+            else
+            {
+               goto close_connection;
+            }
+            break;
+         default:
+            break;
+      }
+   }
+
+close_connection:
+   shutdown(sock, 2);
+   closesocket(sock);
+}
+
+
+//
+// Local administrative interface listener thread
+//
+
+void LocalAdminListener(void *pArg)
+{
+   SOCKET sock, sockClient;
+   struct sockaddr_in servAddr;
+   int iSize, errorCount = 0;
+
+   // Create socket
+   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+   {
+      WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "LocalAdminListener");
+      return;
+   }
+
+   // Fill in local address structure
+   memset(&servAddr, 0, sizeof(struct sockaddr_in));
+   servAddr.sin_family = AF_INET;
+   servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+   servAddr.sin_port = htons(LOCAL_ADMIN_PORT);
+
+   // Bind socket
+   if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
+   {
+      WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", LOCAL_ADMIN_PORT, "LocalAdminListener", WSAGetLastError());
+      exit(1);
+   }
+
+   // Set up queue
+   listen(sock, SOMAXCONN);
+
+   // Wait for connection requests
+   while(!ShutdownInProgress())
+   {
+      iSize = sizeof(struct sockaddr_in);
+      if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
+      {
+         int error;
+
+#ifdef _WIN32
+         error = WSAGetLastError();
+         if (error != WSAEINTR)
+#else
+         error = errno;
+         if (error != EINTR)
+#endif
+            WriteLog(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
+         errorCount++;
+         if (errorCount > 1000)
+         {
+            WriteLog(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
+            errorCount = 0;
+         }
+         ThreadSleepMs(500);
+      }
+
+      errorCount = 0;     // Reset consecutive errors counter
+
+      // Create new session structure and threads
+      ThreadCreate(ProcessingThread, 0, (void *)sockClient);
+   }
+
+   closesocket(sock);
+}
index b692a2f..be16ef1 100644 (file)
@@ -1,6 +1,6 @@
 /* 
-** Project X - Network Management System
-** Copyright (C) 2003 Victor Kirhenshtein
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
index 4566136..dc4b488 100644 (file)
@@ -33,8 +33,10 @@ static char help_text[]="NMS Version " VERSION_STRING " Server\n"
                         "Valid options are:\n"
                         "   --config <file>   : Set non-default configuration file\n"
                         "                     : Default is " DEFAULT_CONFIG_FILE "\n"
+                        "   --debug-all       : Turn on all possible debug output\n"
                         "   --debug-cscp      : Print client-server communication protocol debug\n"
                         "                     : information to console.\n"
+                        "   --debug-dc        : Print data collection debug information to console.\n"
                         "   --debug-discovery : Print network discovery debug information to console.\n"
                         "   --debug-events    : Print events to console.\n"
                         "\n"
@@ -193,6 +195,10 @@ BOOL ParseCommandLine(int argc, char *argv[])
          i++;
          strcpy(g_szConfigFile, argv[i]);     // Next word should contain name of the config file
       }
+      else if (!strcmp(argv[i], "--debug-all"))
+      {
+         g_dwFlags |= AF_DEBUG_ALL;
+      }
       else if (!strcmp(argv[i], "--debug-events"))
       {
          g_dwFlags |= AF_DEBUG_EVENTS;
@@ -205,6 +211,10 @@ BOOL ParseCommandLine(int argc, char *argv[])
       {
          g_dwFlags |= AF_DEBUG_DISCOVERY;
       }
+      else if (!strcmp(argv[i], "--debug-dc"))
+      {
+         g_dwFlags |= AF_DEBUG_DC;
+      }
       else if (!strcmp(argv[i], "check-config"))
       {
          g_dwFlags |= AF_STANDALONE;
index 49a1093..c7976ff 100644 (file)
@@ -86,7 +86,7 @@ static void DataCollector(void *pArg)
       }
       else     /* pNode == NULL */
       {
-printf("** DC: Attempt to collect information for non-existing node.\n");
+         DbgPrintf(AF_DEBUG_DC, "*** DataCollector: Attempt to collect information for non-existing node.\n");
       }
       free(pEnvelope);
    }
@@ -117,7 +117,7 @@ static void ItemPoller(void *pArg)
       MutexUnlock(g_hMutexNodeIndex);
 
       dwElapsed = GetTickCount() - dwStart;
-      printf("*** ItemPoller: Time elapsed == %lu milliseconds ***\n", dwElapsed);
+      DbgPrintf(AF_DEBUG_DC, "*** ItemPoller: Time elapsed == %lu milliseconds ***\n", dwElapsed);
    }
 }
 
@@ -133,8 +133,11 @@ static void StatCollector(void *pArg)
       if (SleepAndCheckForShutdown(10))
          break;      // Shutdown has arrived
 
-      printf("*** Poller Queue size: %d ***\n", m_pItemQueue->Size());
-      printf("*** DB Writer Queue size: %d ***\n", g_pLazyRequestQueue->Size());
+      if (g_dwFlags & AF_DEBUG_DC)
+      {
+         printf("*** Poller Queue size: %d ***\n", m_pItemQueue->Size());
+         printf("*** DB Writer Queue size: %d ***\n", g_pLazyRequestQueue->Size());
+      }
    }
 }
 
index 500e953..49b7d55 100644 (file)
@@ -157,7 +157,7 @@ INTERFACE_LIST *GetLocalInterfaceList(void)
 // Check if management server node presented in node list
 //
 
-static void CheckForMgmtNode(void)
+void CheckForMgmtNode(void)
 {
    INTERFACE_LIST *pIfList;
    Node *pNode;
index 3a127c6..5ad31c4 100644 (file)
@@ -39,6 +39,7 @@ void ConfigurationPoller(void *pArg);
 void EventProcessor(void *pArg);
 void WatchdogThread(void *pArg);
 void ClientListener(void *pArg);
+void LocalAdminListener(void *pArg);
 void DBWriteThread(void *pArg);
 
 
@@ -46,7 +47,7 @@ void DBWriteThread(void *pArg);
 // Global variables
 //
 
-DWORD g_dwFlags = 0;
+DWORD g_dwFlags = AF_USE_EVENT_LOG;
 char g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
 char g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
 DB_HANDLE g_hCoreDB = 0;
@@ -90,6 +91,10 @@ static void LoadGlobalConfig()
    g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
    g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
    g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
+   if (ConfigReadInt("EnableAccessControl", 1))
+      g_dwFlags |= AF_ENABLE_ACCESS_CONTROL;
+   if (ConfigReadInt("EnableEventsAccessControl", 1))
+      g_dwFlags |= AF_ENABLE_EVENTS_ACCESS_CONTROL;
 }
 
 
@@ -156,13 +161,18 @@ BOOL Initialize(void)
    // Start threads
    ThreadCreate(WatchdogThread, 0, NULL);
    ThreadCreate(HouseKeeper, 0, NULL);
-   ThreadCreate(DiscoveryThread, 0, NULL);
    ThreadCreate(Syncer, 0, NULL);
    ThreadCreate(NodePoller, 0, NULL);
    ThreadCreate(StatusPoller, 0, NULL);
    ThreadCreate(ConfigurationPoller, 0, NULL);
    ThreadCreate(ClientListener, 0, NULL);
-   
+
+   // Start network discovery thread if required
+   if (ConfigReadInt("RunNetworkDiscovery", 1))
+      ThreadCreate(DiscoveryThread, 0, NULL);
+   else
+      CheckForMgmtNode();
+
    // Start event processors
    iNumThreads = ConfigReadInt("NumberOfEventProcessors", 1);
    for(i = 0; i < iNumThreads; i++)
@@ -171,6 +181,10 @@ BOOL Initialize(void)
    // Start database "lazy" write thread
    ThreadCreate(DBWriteThread, 0, NULL);
 
+   // Start local administartive interface listener if required
+   if (ConfigReadInt("EnableAdminInterface", 1))
+      ThreadCreate(LocalAdminListener, 0, NULL);
+
    return TRUE;
 }
 
index b73d446..c4d72f4 100644 (file)
@@ -39,6 +39,8 @@ NetObj::NetObj()
    m_pChildList = NULL;
    m_dwParentCount = 0;
    m_pParentList = NULL;
+   m_pAccessList = new AccessList;
+   m_bInheritAccessRights = TRUE;
 }
 
 
@@ -53,6 +55,7 @@ NetObj::~NetObj()
       free(m_pChildList);
    if (m_pParentList != NULL)
       free(m_pParentList);
+   delete m_pAccessList;
 }
 
 
@@ -306,3 +309,65 @@ void NetObj::CalculateCompoundStatus(void)
       m_bIsModified = TRUE;
    }
 }
+
+
+//
+// Load ACL from database
+//
+
+BOOL NetObj::LoadACLFromDB(void)
+{
+   char szQuery[256];
+   DB_RESULT hResult;
+   BOOL bSuccess = FALSE;
+
+   sprintf(szQuery, "SELECT user_id,access_rights FROM acl WHERE object_id=%d", m_dwId);
+   hResult = DBSelect(g_hCoreDB, szQuery);
+   if (hResult != NULL)
+   {
+      int i, iNumRows;
+
+      iNumRows = DBGetNumRows(hResult);
+      for(i = 0; i < iNumRows; i++)
+         m_pAccessList->AddElement(DBGetFieldULong(hResult, i, 0), 
+                                   DBGetFieldULong(hResult, i, 1));
+      DBFreeResult(hResult);
+      bSuccess = TRUE;
+   }
+
+   return bSuccess;
+}
+
+
+//
+// Handler for ACL elements enumeration
+//
+
+static void EnumerationHandler(DWORD dwUserId, DWORD dwAccessRights, void *pArg)
+{
+   char szQuery[256];
+
+   sprintf(szQuery, "INSERT INTO acl (objecft_id,user_id,access_rights) VALUES (%d,%d,%d)",
+           (DWORD)pArg, dwUserId, dwAccessRights);
+   DBQuery(g_hCoreDB, szQuery);
+}
+
+
+//
+// Save ACL to database
+//
+
+BOOL NetObj::SaveACLToDB(void)
+{
+   char szQuery[256];
+   BOOL bSuccess = FALSE;
+
+   sprintf(szQuery, "DELETE FROM acl WHERE object_id=%d", m_dwId);
+   if (DBQuery(g_hCoreDB, szQuery))
+   {
+      m_pAccessList->EnumerateElements(EnumerationHandler, (void *)m_dwId);
+      bSuccess = TRUE;
+   }
+
+   return bSuccess;
+}
index 15e3ffb..62da80a 100644 (file)
@@ -52,8 +52,8 @@
 #include <dbdrv.h>
 #include <nms_cscp.h>
 #include <nms_util.h>
-#include "nms_objects.h"
 #include "nms_users.h"
+#include "nms_objects.h"
 #include "nms_dcoll.h"
 #include "messages.h"
 
 // Application flags
 //
 
-#define AF_STANDALONE      0x0001
-#define AF_USE_EVENT_LOG   0x0002
-#define AF_DEBUG_EVENTS    0x0004
-#define AF_DEBUG_CSCP      0x0008
-#define AF_DEBUG_DISCOVERY 0x0010
-#define AF_SHUTDOWN        0x8000
+#define AF_STANDALONE                     0x00000001
+#define AF_USE_EVENT_LOG                  0x00000002
+#define AF_ENABLE_ACCESS_CONTROL          0x00000004
+#define AF_ENABLE_EVENTS_ACCESS_CONTROL   0x00000008
+#define AF_DEBUG_EVENTS                   0x00000100
+#define AF_DEBUG_CSCP                     0x00000200
+#define AF_DEBUG_DISCOVERY                0x00000400
+#define AF_DEBUG_DC                       0x00000800
+#define AF_DEBUG_ALL                      0x0000FF00
+#define AF_SHUTDOWN                       0x80000000
 
 #define ShutdownInProgress()  (g_dwFlags & AF_SHUTDOWN)
 
@@ -293,6 +297,8 @@ DWORD WatchdogAddThread(char *szName);
 void WatchdogNotify(DWORD dwId);
 void WatchdogPrintStatus(void);
 
+void CheckForMgmtNode(void);
+
 #ifdef _WIN32
 
 void InitService(void);
index 0dcc18f..294e6de 100644 (file)
@@ -234,9 +234,15 @@ protected:
    DWORD m_dwParentCount;  // Number of parent objects
    NetObj **m_pParentList; // Array of pointers to parent objects
 
+   AccessList *m_pAccessList;
+   BOOL m_bInheritAccessRights;
+
    void Lock(void) { MutexLock(m_hMutex, INFINITE); }
    void Unlock(void) { MutexUnlock(m_hMutex); }
 
+   BOOL LoadACLFromDB(void);
+   BOOL SaveACLToDB(void);
+
 public:
    NetObj();
    virtual ~NetObj();
index 6e43238..126154e 100644 (file)
 #define MAX_USER_NAME      64
 #define MAX_USER_PASSWORD  64
 
+#define GROUP_FLAG         0x01000000
+
+
+//
+// Global rights
+//
+
+#define SYSTEM_ACCESS_MANAGE_USERS  0x0001
+
+
+//
+// Object access rights
+//
+
+#define OBJECT_ACCESS_READ          0x00000001
+#define OBJECT_ACCESS_MODIFY        0x00000002
+#define OBJECT_ACCESS_CREATE        0x00000004
+#define OBJECT_ACCESS_DELETE        0x00000008
+#define OBJECT_ACCESS_MOVE          0x00000010
+
+
+//
+// User/group flags
+//
+
+#define UF_MODIFIED                 0x0001
+#define UF_DELETED                  0x0002
+
 
 //
 // User structure
@@ -41,15 +69,72 @@ typedef struct
    DWORD dwId;
    char szName[MAX_USER_NAME];
    char szPassword[MAX_USER_PASSWORD];
+   WORD wSystemRights;      // System-wide user's rights
+   WORD wFlags;
 } NMS_USER;
 
 
 //
+// Group structure
+//
+
+typedef struct
+{
+   DWORD dwId;
+   char szName[MAX_USER_NAME];
+   WORD wSystemRights;
+   WORD wFlags;
+   DWORD dwNumMembers;
+   DWORD *pMembers;
+} NMS_USER_GROUP;
+
+
+//
+// Access list element structure
+//
+
+typedef struct
+{
+   DWORD dwObjectId;
+   DWORD dwAccessRights;
+} ACL_ELEMENT;
+
+
+//
+// Access list class
+//
+
+class AccessList
+{
+private:
+   DWORD m_dwNumElements;
+   ACL_ELEMENT *m_pElements;
+   MUTEX m_hMutex;
+
+   void Lock(void) { MutexLock(m_hMutex, INFINITE); }
+   void Unlock(void) { MutexUnlock(m_hMutex); }
+
+public:
+   AccessList();
+   ~AccessList();
+
+   BOOL GetUserRights(DWORD dwUserId, DWORD *pdwAccessRights);
+   void AddElement(DWORD dwObjectId, DWORD dwAccessRights);
+   void DeleteElement(DWORD dwObjectId);
+
+   void EnumerateElements(void (* pHandler)(DWORD, DWORD, void *), void *pArg);
+};
+
+
+//
 // Functions
 //
 
 BOOL LoadUsers(void);
 void SaveUsers(void);
+void AddUserToGroup(DWORD dwUserId, DWORD dwGroupId);
+void DeleteUserFromGroup(DWORD dwUserId, DWORD dwGroupId);
+BOOL CheckUserMembership(DWORD dwUserId, DWORD dwGroupId);
 BOOL AuthenticateUser(char *szName, char *szPassword, DWORD *pdwId);
 
 
index a2ec5bf..9e30b12 100644 (file)
@@ -186,6 +186,7 @@ BOOL Node::CreateFromDB(DWORD dwId)
 
    DBFreeResult(hResult);
    LoadItemsFromDB();
+   LoadACLFromDB();
    return bResult;
 }
 
index be770e7..cdcb0e8 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003 Victor Kirhenshtein
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 
 
 //
-// Global data
+// Static data
 //
 
-NMS_USER *g_pUserList;
-int g_iNumUsers;
+static NMS_USER *m_pUserList = NULL;
+static DWORD m_dwNumUsers = 0;
+static NMS_USER_GROUP *m_pGroupList = NULL;
+static DWORD m_dwNumGroups = 0;
+static MUTEX m_hMutexUserAccess;
+static MUTEX m_hMutexGroupAccess;
+
+
+//
+// Initialize user handling subsystem
+//
+
+void InitUsers(void)
+{
+   m_hMutexUserAccess = MutexCreate();
+   m_hMutexGroupAccess = MutexCreate();
+}
 
 
 //
@@ -38,22 +53,52 @@ int g_iNumUsers;
 BOOL LoadUsers(void)
 {
    DB_RESULT hResult;
-   int i;
+   DWORD i, iNumRows;
+
+   // Load users
+   hResult = DBSelect(g_hCoreDB, "SELECT id,name,password,access FROM users ORDER BY id");
+   if (hResult == 0)
+      return FALSE;
+
+   m_dwNumUsers = DBGetNumRows(hResult);
+   m_pUserList = (NMS_USER *)malloc(sizeof(NMS_USER) * m_dwNumUsers);
+   for(i = 0; i < m_dwNumUsers; i++)
+   {
+      m_pUserList[i].dwId = DBGetFieldULong(hResult, i, 0);
+      strncpy(m_pUserList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
+      strncpy(m_pUserList[i].szPassword, DBGetField(hResult, i, 2), MAX_USER_PASSWORD);
+      m_pUserList[i].wSystemRights = (WORD)DBGetFieldLong(hResult, i, 3);
+      m_pUserList[i].wFlags = 0;
+   }
+
+   DBFreeResult(hResult);
 
-   hResult = DBSelect(g_hCoreDB, "SELECT id,name,password FROM users ORDER BY id");
+   // Load groups
+   hResult = DBSelect(g_hCoreDB, "SELECT id,name,access FROM groups ORDER BY id");
    if (hResult == 0)
       return FALSE;
 
-   g_iNumUsers = DBGetNumRows(hResult);
-   g_pUserList = (NMS_USER *)malloc(sizeof(NMS_USER) * g_iNumUsers);
-   for(i = 0; i < g_iNumUsers; i++)
+   m_dwNumGroups = DBGetNumRows(hResult);
+   m_pGroupList = (NMS_USER_GROUP *)malloc(sizeof(NMS_USER_GROUP) * m_dwNumGroups);
+   for(i = 0; i < m_dwNumGroups; i++)
    {
-      g_pUserList[i].dwId = DBGetFieldULong(hResult, i, 0);
-      strncpy(g_pUserList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
-      strncpy(g_pUserList[i].szPassword, DBGetField(hResult, i, 2), MAX_USER_PASSWORD);
+      m_pGroupList[i].dwId = DBGetFieldULong(hResult, i, 0);
+      strncpy(m_pGroupList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
+      m_pGroupList[i].wSystemRights = (WORD)DBGetFieldLong(hResult, i, 2);
+      m_pGroupList[i].wFlags = 0;
    }
 
    DBFreeResult(hResult);
+
+   // Add users to groups
+   hResult = DBSelect(g_hCoreDB, "SELECT user_id,group_id FROM UserGroupMembers");
+   if (hResult == 0)
+      return FALSE;
+
+   iNumRows = DBGetNumRows(hResult);
+   for(i = 0; i < iNumRows; i++)
+      AddUserToGroup(DBGetFieldULong(hResult, i, 0), DBGetFieldULong(hResult, i, 1));
+
    return TRUE;
 }
 
@@ -64,6 +109,111 @@ BOOL LoadUsers(void)
 
 void SaveUsers(void)
 {
+   DWORD i;
+   char szQuery[1024];
+
+   // Save users
+   MutexLock(m_hMutexUserAccess, INFINITE);
+   for(i = 0; i < m_dwNumUsers; i++)
+   {
+      if (m_pUserList[i].wFlags & UF_DELETED)
+      {
+         // Delete user record from database
+         sprintf(szQuery, "DELETE FROM users WHERE id=%d", m_pUserList[i].dwId);
+         DBQuery(g_hCoreDB, szQuery);
+
+         // Delete user record from memory
+         m_dwNumUsers--;
+         memmove(&m_pUserList[i], &m_pUserList[i + 1], sizeof(NMS_USER) * (m_dwNumUsers - i));
+         i--;
+      }
+      else if (m_pUserList[i].wFlags & UF_MODIFIED)
+      {
+         DB_RESULT hResult;
+         BOOL bUserExists = FALSE;
+
+         // Check if user record exists in database
+         sprintf(szQuery, "SELECT name FROM users WHERE id=%d", m_pUserList[i].dwId);
+         hResult = DBSelect(g_hCoreDB, szQuery);
+         if (hResult != NULL)
+         {
+            if (DBGetNumRows(hResult) != 0)
+               bUserExists = TRUE;
+            DBFreeResult(hResult);
+         }
+
+         // Create or update record in database
+         if (bUserExists)
+            sprintf(szQuery, "UPDATE users SET name='%s',password='%s',access=%d WHERE id=%d",
+                    m_pUserList[i].szName, m_pUserList[i].szPassword, 
+                    m_pUserList[i].wSystemRights, m_pUserList[i].dwId);
+         else
+            sprintf(szQuery, "INSERT INTO users (id,name,password,access) VALUES (%d,'%s','%s',%d)",
+                    m_pUserList[i].dwId, m_pUserList[i].szName, 
+                    m_pUserList[i].szPassword, m_pUserList[i].wSystemRights);
+         DBQuery(g_hCoreDB, szQuery);
+      }
+   }
+   MutexUnlock(m_hMutexUserAccess);
+
+   // Save groups
+   MutexLock(m_hMutexGroupAccess, INFINITE);
+   for(i = 0; i < m_dwNumGroups; i++)
+   {
+      if (m_pGroupList[i].wFlags & UF_DELETED)
+      {
+         // Delete group record from database
+         sprintf(szQuery, "DELETE FROM usergroups WHERE id=%d", m_pGroupList[i].dwId);
+         DBQuery(g_hCoreDB, szQuery);
+         sprintf(szQuery, "DELETE FROM usergroupmembers WHERE group_id=%d", m_pGroupList[i].dwId);
+         DBQuery(g_hCoreDB, szQuery);
+
+         // Delete group record from memory
+         if (m_pGroupList[i].pMembers != NULL)
+            free(m_pGroupList[i].pMembers);
+         m_dwNumGroups--;
+         memmove(&m_pGroupList[i], &m_pGroupList[i + 1], sizeof(NMS_USER_GROUP) * (m_dwNumGroups - i));
+         i--;
+      }
+      else if (m_pGroupList[i].wFlags & UF_MODIFIED)
+      {
+         DB_RESULT hResult;
+         BOOL bGroupExists = FALSE;
+
+         // Check if group record exists in database
+         sprintf(szQuery, "SELECT name FROM usergroups WHERE id=%d", m_pGroupList[i].dwId);
+         hResult = DBSelect(g_hCoreDB, szQuery);
+         if (hResult != NULL)
+         {
+            if (DBGetNumRows(hResult) != 0)
+               bGroupExists = TRUE;
+            DBFreeResult(hResult);
+         }
+
+         // Create or update record in database
+         if (bGroupExists)
+            sprintf(szQuery, "UPDATE usergroups SET name='%s',access=%d WHERE id=%d",
+                    m_pGroupList[i].szName, m_pGroupList[i].wSystemRights, m_pGroupList[i].dwId);
+         else
+            sprintf(szQuery, "INSERT INTO usergroupss (id,name,access) VALUES (%d,'%s',%d)",
+                    m_pGroupList[i].dwId, m_pGroupList[i].szName, m_pGroupList[i].wSystemRights);
+         DBQuery(g_hCoreDB, szQuery);
+
+         if (bGroupExists)
+         {
+            sprintf(szQuery, "DELETE FROM usergroupmembers WHERE group_id=%d", m_pGroupList[i].dwId);
+            DBQuery(g_hCoreDB, szQuery);
+         }
+
+         for(DWORD j = 0; j < m_pGroupList[i].dwNumMembers; j++)
+         {
+            sprintf(szQuery, "INSERT INTO UserGroupMembers (group_id, user_id) VALUES (%d, %d)",
+                    m_pGroupList[i].dwId, m_pGroupList[i].pMembers[j]);
+            DBQuery(g_hCoreDB, szQuery);
+         }
+      }
+   }
+   MutexUnlock(m_hMutexGroupAccess);
 }
 
 
@@ -76,14 +226,47 @@ void SaveUsers(void)
 
 BOOL AuthenticateUser(char *szName, char *szPassword, DWORD *pdwId)
 {
-   int i;
+   DWORD i;
+   BOOL bResult = FALSE;
 
-   for(i = 0; i < g_iNumUsers; i++)
-      if (!strcmp(szName, g_pUserList[i].szName) &&
-          !strcmp(szPassword, g_pUserList[i].szPassword))
+   MutexLock(m_hMutexUserAccess, INFINITE);
+   for(i = 0; i < m_dwNumUsers; i++)
+      if (!strcmp(szName, m_pUserList[i].szName) &&
+          !strcmp(szPassword, m_pUserList[i].szPassword) &&
+          !(m_pUserList[i].wFlags & UF_DELETED))
       {
-         *pdwId = g_pUserList[i].dwId;
-         return TRUE;
+         *pdwId = m_pUserList[i].dwId;
+         bResult = TRUE;
+         break;
       }
+   MutexUnlock(m_hMutexUserAccess);
+   return bResult;
+}
+
+
+//
+// Add user to group
+//
+
+void AddUserToGroup(DWORD dwUserId, DWORD dwGroupId)
+{
+}
+
+
+//
+// Delete user from group
+//
+
+void DeleteUserFromGroup(DWORD dwUserId, DWORD dwGroupId)
+{
+}
+
+
+//
+// Check if user is a member of specific group
+//
+
+BOOL CheckUserMembership(DWORD dwUserId, DWORD dwGroupId)
+{
    return FALSE;
 }
similarity index 60%
copy from src/server/core/nms_users.h
copy to src/server/include/local_admin.h
index 6e43238..a4a81a2 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003 Victor Kirhenshtein
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 **
-** $module: nms_users.h
+** $module: local_admin.h
 **
 **/
 
-#ifndef _nms_users_h_
-#define _nms_users_h_
+#ifndef _local_admin_h_
+#define _local_admin_h_
 
 
 //
 // Constants
 //
 
-#define MAX_USER_NAME      64
-#define MAX_USER_PASSWORD  64
+#define LOCAL_ADMIN_PORT      58942
 
+#define LA_RESP_SUCCESS       0x7777
+#define LA_RESP_ERROR         0xFFFF
 
-//
-// User structure
-//
-
-typedef struct
-{
-   DWORD dwId;
-   char szName[MAX_USER_NAME];
-   char szPassword[MAX_USER_PASSWORD];
-} NMS_USER;
-
-
-//
-// Functions
-//
-
-BOOL LoadUsers(void);
-void SaveUsers(void);
-BOOL AuthenticateUser(char *szName, char *szPassword, DWORD *pdwId);
-
-
-//
-// Global variables
-//
-
-extern NMS_USER *g_pUserList;
+#define LA_CMD_LIST_CONFIG    1
+#define LA_CMD_GET_CONFIG     2
+#define LA_CMD_SET_CONFIG     3
+#define LA_CMD_STOP           4
+#define LA_CMD_GET_FLAGS      5
+#define LA_CMD_SET_FLAGS      6
 
 
-#endif
+#endif   /* _local_admin_h_ */