object serialization to JSON written to audit log (currently only NetObj fields)
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 18 May 2017 21:35:46 +0000 (00:35 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 18 May 2017 21:35:46 +0000 (00:35 +0300)
12 files changed:
include/geolocation.h
include/nms_util.h
src/libnetxms/geolocation.cpp
src/libnetxms/json.cpp
src/libnetxms/pa.cpp
src/libnetxms/strmap.cpp
src/server/core/acl.cpp
src/server/core/netobj.cpp
src/server/core/session.cpp
src/server/core/tools.cpp
src/server/include/nms_objects.h
src/server/include/nms_users.h

index 7a44397..9cf83a7 100644 (file)
@@ -83,6 +83,8 @@ public:
 
        void fillMessage(NXCPMessage &msg) const;
 
+       json_t *toJson() const;
+
        static GeoLocation parseAgentData(const TCHAR *data);
 };
 
index b7f5908..703d980 100644 (file)
@@ -714,7 +714,7 @@ public:
 
    T *getBuffer() const { return (T*)__getBuffer(); }
 
-   json_t *toJson() const { json_t *a = json_array(); for(int i = 0; i < m_size; i++) json_array_append_new(a, json_integer(get(i))); return a; }
+   json_t *toJson() const { json_t *a = json_array(); for(int i = 0; i < size(); i++) json_array_append_new(a, json_integer(get(i))); return a; }
 };
 
 /**
@@ -829,6 +829,8 @@ public:
 
    void fillMessage(NXCPMessage *msg, UINT32 sizeFieldId, UINT32 baseFieldId) const;
    void loadMessage(const NXCPMessage *msg, UINT32 sizeFieldId, UINT32 baseFieldId);
+
+   json_t *toJson();
 };
 
 /**
@@ -1564,6 +1566,8 @@ public:
    const TCHAR *getStreetAddress() const { return CHECK_NULL_EX(m_streetAddress); }
    const TCHAR *getPostCode() const { return CHECK_NULL_EX(m_postcode); }
 
+   json_t *toJson() const;
+
    void setCountry(const TCHAR *country) { free(m_country); m_country = _tcsdup_ex(country); }
    void setCity(const TCHAR *city) { free(m_city); m_city = _tcsdup_ex(city); }
    void setStreetAddress(const TCHAR *streetAddress) { free(m_streetAddress); m_streetAddress = _tcsdup_ex(streetAddress); }
@@ -2303,6 +2307,19 @@ json_t LIBNETXMS_EXPORTABLE *json_string_w(const WCHAR *s);
 #define json_string_t json_string
 #endif
 
+json_t LIBNETXMS_EXPORTABLE *json_integer_array(const int *values, int size);
+
+/**
+ * Serialize ObjectArray as JSON
+ */
+template<typename T> json_t *json_object_array(ObjectArray<T> *a)
+{
+   json_t *root = json_array();
+   for(int i = 0; i < a->size(); i++)
+      json_array_append_new(root, a->get(i)->toJson());
+   return root;
+}
+
 #endif
 
 #endif   /* _nms_util_h_ */
index 52e03df..bac1b5b 100644 (file)
@@ -169,11 +169,25 @@ GeoLocation& GeoLocation::operator =(const GeoLocation &src)
  */
 void GeoLocation::fillMessage(NXCPMessage &msg) const
 {
-       msg.setField(VID_GEOLOCATION_TYPE, (WORD)m_type);
+       msg.setField(VID_GEOLOCATION_TYPE, (UINT16)m_type);
        msg.setField(VID_LATITUDE, m_lat);
        msg.setField(VID_LONGITUDE, m_lon);
-       msg.setField(VID_ACCURACY, (WORD)m_accuracy);
-       msg.setField(VID_GEOLOCATION_TIMESTAMP, (QWORD)m_timestamp);
+       msg.setField(VID_ACCURACY, (UINT16)m_accuracy);
+       msg.setField(VID_GEOLOCATION_TIMESTAMP, (UINT64)m_timestamp);
+}
+
+/**
+ * Convert to JSON
+ */
+json_t *GeoLocation::toJson() const
+{
+   json_t *root = json_object();
+   json_object_set_new(root, "type", json_integer(m_type));
+   json_object_set_new(root, "latitude", json_real(m_lat));
+   json_object_set_new(root, "longitude", json_real(m_lon));
+   json_object_set_new(root, "accuracy", json_integer(m_accuracy));
+   json_object_set_new(root, "timestamp", json_integer(m_timestamp));
+   return root;
 }
 
 /**
index 81cb01f..8271198 100644 (file)
@@ -32,3 +32,14 @@ json_t LIBNETXMS_EXPORTABLE *json_string_w(const WCHAR *s)
    free(us);
    return js;
 }
+
+/**
+ * Create JSON array from integer array
+ */
+json_t LIBNETXMS_EXPORTABLE *json_integer_array(const int *values, int size)
+{
+   json_t *a = json_array();
+   for(int i = 0; i < size; i++)
+      json_array_append_new(a, json_integer(values[i]));
+   return a;
+}
index 4ac29f6..582d7d8 100644 (file)
@@ -50,8 +50,21 @@ PostalAddress::PostalAddress(const TCHAR *country, const TCHAR *city, const TCHA
  */
 PostalAddress::~PostalAddress()
 {
-   safe_free(m_country);
-   safe_free(m_city);
-   safe_free(m_streetAddress);
-   safe_free(m_postcode);
+   free(m_country);
+   free(m_city);
+   free(m_streetAddress);
+   free(m_postcode);
+}
+
+/**
+ * Serialize as JSON
+ */
+json_t *PostalAddress::toJson() const
+{
+   json_t *root = json_object();
+   json_object_set_new(root, "country", json_string_t(m_country));
+   json_object_set_new(root, "city", json_string_t(m_city));
+   json_object_set_new(root, "streetAddress", json_string_t(m_streetAddress));
+   json_object_set_new(root, "postcode", json_string_t(m_postcode));
+   return root;
 }
index d037bbe..63ba58d 100644 (file)
@@ -189,3 +189,20 @@ void StringMap::loadMessage(const NXCPMessage *msg, UINT32 sizeFieldId, UINT32 b
       setPreallocated(key, value);
    }
 }
+
+/**
+ * Serialize as JSON
+ */
+json_t *StringMap::toJson()
+{
+   json_t *root = json_array();
+   StringMapEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      json_t *e = json_array();
+      json_array_append_new(e, json_string_t(m_ignoreCase ? entry->originalKey : entry->key));
+      json_array_append_new(e, json_string_t((TCHAR *)entry->value));
+      json_array_append_new(root, e);
+   }
+   return root;
+}
index 8d8351a..1c024c0 100644 (file)
@@ -146,6 +146,22 @@ void AccessList::fillMessage(NXCPMessage *pMsg)
 }
 
 /**
+ * Serialize as JSON
+ */
+json_t *AccessList::toJson()
+{
+   json_t *root = json_array();
+   for(int i = 0; i < m_size; i++)
+   {
+      json_t *e = json_object();
+      json_object_set_new(e, "userId", json_integer(m_elements[i].dwUserId));
+      json_object_set_new(e, "access", json_integer(m_elements[i].dwAccessRights));
+      json_array_append_new(root, e);
+   }
+   return root;
+}
+
+/**
  * Delete all elements
  */
 void AccessList::deleteAll()
index 6d1ff77..8a37e5d 100644 (file)
@@ -67,8 +67,7 @@ NetObj::NetObj()
    m_parentList = new ObjectArray<NetObj>(4, 4, false);
    m_accessList = new AccessList();
    m_inheritAccessRights = true;
-       m_dwNumTrustedNodes = 0;
-       m_pdwTrustedNodes = NULL;
+       m_trustedNodes = NULL;
    m_pollRequestor = NULL;
    m_statusCalcAlg = SA_CALCULATE_DEFAULT;
    m_statusPropAlg = SA_PROPAGATE_DEFAULT;
@@ -101,8 +100,8 @@ NetObj::~NetObj()
    delete m_childList;
    delete m_parentList;
    delete m_accessList;
-       safe_free(m_pdwTrustedNodes);
-   safe_free(m_comments);
+       delete m_trustedNodes;
+   free(m_comments);
    delete m_moduleData;
    delete m_postalAddress;
    delete m_dashboards;
@@ -1086,9 +1085,15 @@ void NetObj::fillMessageInternal(NXCPMessage *pMsg)
    pMsg->setField(VID_COMMENTS, CHECK_NULL_EX(m_comments));
        pMsg->setField(VID_IMAGE, m_image);
        pMsg->setField(VID_DRILL_DOWN_OBJECT_ID, m_submapId);
-       pMsg->setField(VID_NUM_TRUSTED_NODES, m_dwNumTrustedNodes);
-       if (m_dwNumTrustedNodes > 0)
-               pMsg->setFieldFromInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
+       if ((m_trustedNodes != NULL) && (m_trustedNodes->size() > 0))
+       {
+          pMsg->setField(VID_NUM_TRUSTED_NODES, m_trustedNodes->size());
+               pMsg->setFieldFromInt32Array(VID_TRUSTED_NODES, m_trustedNodes);
+       }
+       else
+       {
+          pMsg->setField(VID_NUM_TRUSTED_NODES, (UINT32)0);
+       }
    pMsg->setFieldFromInt32Array(VID_DASHBOARDS, m_dashboards);
 
    m_customAttributes.fillMessage(pMsg, VID_NUM_CUSTOM_ATTRIBUTES, VID_CUSTOM_ATTRIBUTES_BASE);
@@ -1250,9 +1255,11 @@ UINT32 NetObj::modifyFromMessageInternal(NXCPMessage *pRequest)
        // Change trusted nodes list
    if (pRequest->isFieldExist(VID_NUM_TRUSTED_NODES))
    {
-      m_dwNumTrustedNodes = pRequest->getFieldAsUInt32(VID_NUM_TRUSTED_NODES);
-               m_pdwTrustedNodes = (UINT32 *)realloc(m_pdwTrustedNodes, sizeof(UINT32) * m_dwNumTrustedNodes);
-               pRequest->getFieldAsInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
+      if (m_trustedNodes == NULL)
+         m_trustedNodes = new IntegerArray<UINT32>();
+      else
+         m_trustedNodes->clear();
+               pRequest->getFieldAsInt32Array(VID_TRUSTED_NODES, m_trustedNodes);
    }
 
    // Change custom attributes
@@ -1696,22 +1703,18 @@ void NetObj::commentsToMessage(NXCPMessage *pMsg)
  */
 bool NetObj::loadTrustedNodes(DB_HANDLE hdb)
 {
-       DB_RESULT hResult;
        TCHAR query[256];
-       int i, count;
-
        _sntprintf(query, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_id);
-       hResult = DBSelect(hdb, query);
+       DB_RESULT hResult = DBSelect(hdb, query);
        if (hResult != NULL)
        {
-               count = DBGetNumRows(hResult);
+               int count = DBGetNumRows(hResult);
                if (count > 0)
                {
-                       m_dwNumTrustedNodes = count;
-                       m_pdwTrustedNodes = (UINT32 *)malloc(sizeof(UINT32) * count);
-                       for(i = 0; i < count; i++)
+                  m_trustedNodes = new IntegerArray<UINT32>(count);
+                       for(int i = 0; i < count; i++)
                        {
-                               m_pdwTrustedNodes[i] = DBGetFieldULong(hResult, i, 0);
+                               m_trustedNodes->add(DBGetFieldULong(hResult, i, 0));
                        }
                }
                DBFreeResult(hResult);
@@ -1724,24 +1727,26 @@ bool NetObj::loadTrustedNodes(DB_HANDLE hdb)
  */
 bool NetObj::saveTrustedNodes(DB_HANDLE hdb)
 {
-       TCHAR query[256];
-       UINT32 i;
-       bool rc = false;
-
-       _sntprintf(query, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_id);
-       if (DBQuery(hdb, query))
+   bool success = executeQueryOnObject(hdb, _T("DELETE FROM trusted_nodes WHERE source_object_id=?"));
+       if (success && (m_trustedNodes != NULL) && (m_trustedNodes->size() > 0))
        {
-               for(i = 0; i < m_dwNumTrustedNodes; i++)
-               {
-                       _sntprintf(query, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
-                                  m_id, m_pdwTrustedNodes[i]);
-                       if (!DBQuery(hdb, query))
-                               break;
-               }
-               if (i == m_dwNumTrustedNodes)
-                       rc = true;
+          DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"));
+          if (hStmt != NULL)
+          {
+             DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
+         for(int i = 0; (i < m_trustedNodes->size()) && success; i++)
+         {
+            DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_trustedNodes->get(i));
+            success = DBExecute(hStmt);
+         }
+         DBFreeStatement(hStmt);
+          }
+          else
+          {
+             success = false;
+          }
        }
-       return rc;
+       return success;
 }
 
 /**
@@ -1750,27 +1755,12 @@ bool NetObj::saveTrustedNodes(DB_HANDLE hdb)
  */
 bool NetObj::isTrustedNode(UINT32 id)
 {
-       bool rc;
-
-       if (g_flags & AF_CHECK_TRUSTED_NODES)
-       {
-               UINT32 i;
+   if (!(g_flags & AF_CHECK_TRUSTED_NODES))
+      return true;
 
-               lockProperties();
-               for(i = 0, rc = false; i < m_dwNumTrustedNodes; i++)
-               {
-                       if (m_pdwTrustedNodes[i] == id)
-                       {
-                               rc = true;
-                               break;
-                       }
-               }
-               unlockProperties();
-       }
-       else
-       {
-               rc = true;
-       }
+   lockProperties();
+   bool rc = (m_trustedNodes != NULL) ? m_trustedNodes->contains(id) : false;
+   unlockProperties();
        return rc;
 }
 
@@ -2230,5 +2220,50 @@ NXSL_Value *NetObj::createNXSLObject()
  */
 json_t *NetObj::toJson()
 {
-   return NULL;
+   json_t *root = json_object();
+   json_object_set_new(root, "id", json_integer(m_id));
+   json_object_set_new(root, "guid", m_guid.toJson());
+   json_object_set_new(root, "timestamp", json_integer(m_timestamp));
+   json_object_set_new(root, "name", json_string_t(m_name));
+   json_object_set_new(root, "comments", json_string_t(m_comments));
+   json_object_set_new(root, "status", json_integer(m_status));
+   json_object_set_new(root, "statusCalcAlg", json_integer(m_statusCalcAlg));
+   json_object_set_new(root, "statusPropAlg", json_integer(m_statusPropAlg));
+   json_object_set_new(root, "fixedStatus", json_integer(m_fixedStatus));
+   json_object_set_new(root, "statusShift", json_integer(m_statusShift));
+   json_object_set_new(root, "statusTranslation", json_integer_array(m_statusTranslation, 4));
+   json_object_set_new(root, "statusSingleThreshold", json_integer(m_statusSingleThreshold));
+   json_object_set_new(root, "statusThresholds", json_integer_array(m_statusThresholds, 4));
+   json_object_set_new(root, "isModified", json_boolean(m_isModified));
+   json_object_set_new(root, "isDeleted", json_boolean(m_isDeleted));
+   json_object_set_new(root, "isHidden", json_boolean(m_isHidden));
+   json_object_set_new(root, "isSystem", json_boolean(m_isSystem));
+   json_object_set_new(root, "maintenanceMode", json_boolean(m_maintenanceMode));
+   json_object_set_new(root, "maintenanceEventId", json_integer(m_maintenanceEventId));
+   json_object_set_new(root, "image", m_image.toJson());
+   json_object_set_new(root, "geoLocation", m_geoLocation.toJson());
+   json_object_set_new(root, "postalAddress", m_postalAddress->toJson());
+   json_object_set_new(root, "submapId", json_integer(m_submapId));
+   json_object_set_new(root, "dashboards", m_dashboards->toJson());
+   json_object_set_new(root, "urls", json_object_array(m_urls));
+   json_object_set_new(root, "accessList", m_accessList->toJson());
+   json_object_set_new(root, "inheritAccessRights", json_boolean(m_inheritAccessRights));
+   json_object_set_new(root, "trustedNodes", (m_trustedNodes != NULL) ? m_trustedNodes->toJson() : json_array());
+   json_object_set_new(root, "customAttributes", m_customAttributes.toJson());
+
+   json_t *children = json_array();
+   lockChildList(false);
+   for(int i = 0; i < m_childList->size(); i++)
+      json_array_append_new(children, json_integer(m_childList->get(i)->getId()));
+   unlockChildList();
+   json_object_set_new(root, "children", children);
+
+   json_t *parents = json_array();
+   lockParentList(false);
+   for(int i = 0; i < m_parentList->size(); i++)
+      json_array_append_new(parents, json_integer(m_parentList->get(i)->getId()));
+   unlockParentList();
+   json_object_set_new(root, "parents", parents);
+
+   return root;
 }
index 4564bf4..d24293d 100644 (file)
@@ -2740,6 +2740,8 @@ void ClientSession::modifyObject(NXCPMessage *pRequest)
    {
       if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
       {
+         json_t *oldValue = object->toJson();
+
          // If user attempts to change object's ACL, check
          // if he has OBJECT_ACCESS_ACL permission
          if (pRequest->isFieldExist(VID_ACL_SIZE))
@@ -2784,20 +2786,17 @@ void ClientSession::modifyObject(NXCPMessage *pRequest)
 
                        if (dwResult == RCC_SUCCESS)
                        {
-                               WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, dwObjectId,
-                                                                 _T("Object %s modified from client"), object->getName());
-                       }
-                       else
-                       {
-                               WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
-                                                                 _T("Failed to modify object from client - error %d"), dwResult);
+                          json_t *newValue = object->toJson();
+                          writeAuditLogWithValues(AUDIT_OBJECTS, true, dwObjectId, oldValue, newValue,
+                                                                           _T("Object %s modified from client"), object->getName());
+                json_decref(newValue);
                        }
+                       json_decref(oldValue);
       }
       else
       {
          msg.setField(VID_RCC, RCC_ACCESS_DENIED);
-                       WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
-                                                         _T("Failed to modify object from client - access denied"), dwResult);
+                       writeAuditLog(AUDIT_OBJECTS, false, dwObjectId, _T("Access denied on object modification"));
       }
    }
    else
index 95de838..fb2547d 100644 (file)
@@ -402,6 +402,18 @@ void ObjectUrl::fillMessage(NXCPMessage *msg, UINT32 baseId)
 }
 
 /**
+ * Serialize object to JSON
+ */
+json_t *ObjectUrl::toJson() const
+{
+   json_t *root = json_object();
+   json_object_set_new(root, "id", json_integer(m_id));
+   json_object_set_new(root, "url", json_string_t(m_url));
+   json_object_set_new(root, "description", json_string_t(m_description));
+   return root;
+}
+
+/**
  * Distance array sorting callback
  */
 int DistanceSortCallback(const void *obj1, const void *obj2)
index 6e22d60..2bef28f 100644 (file)
@@ -467,6 +467,8 @@ public:
    UINT32 getId() const { return m_id; }
    const TCHAR *getUrl() const { return m_url; }
    const TCHAR *getDescription() const { return m_description; }
+
+   json_t *toJson() const;
 };
 
 /**
@@ -519,8 +521,7 @@ protected:
    bool m_inheritAccessRights;
    MUTEX m_mutexACL;
 
-       UINT32 m_dwNumTrustedNodes;     // Trusted nodes
-       UINT32 *m_pdwTrustedNodes;
+   IntegerArray<UINT32> *m_trustedNodes;
 
        StringMap m_customAttributes;
    StringObjectMap<ModuleData> *m_moduleData;
index f185ff2..a6f4b0a 100644 (file)
@@ -380,6 +380,8 @@ public:
    void enumerateElements(void (* pHandler)(UINT32, UINT32, void *), void *pArg);
 
    void fillMessage(NXCPMessage *pMsg);
+
+   json_t *toJson();
 };
 
 /**