From 1e5e37907cff21dd9dcab5a121679a5c821e3059 Mon Sep 17 00:00:00 2001
From: Michal Nowacki <mnowacki@newrelic.com>
Date: Fri, 21 Jun 2024 12:03:51 -0400
Subject: [PATCH 1/5] expose app metadata for csec via global symbol

Rather than providing a PHP user function to expose app metadata to PHP
userland, export a global symbol for cseg agent to use.
---
 agent/csec_metadata.c    | 69 +++++++++++++++++-----------------------
 agent/csec_metadata.h    | 45 +++++++++++++++++++-------
 agent/export.syms        |  1 +
 agent/php_api_internal.h |  2 --
 agent/php_newrelic.c     |  2 --
 5 files changed, 64 insertions(+), 55 deletions(-)

diff --git a/agent/csec_metadata.c b/agent/csec_metadata.c
index ba43b9c1a..0a9d9d47c 100644
--- a/agent/csec_metadata.c
+++ b/agent/csec_metadata.c
@@ -1,48 +1,37 @@
-#include "csec_metadata.h"
-#include "util_strings.h"
-#include "php_hash.h"
-#include "php_api_internal.h"
-
-static void nr_csec_php_add_assoc_string_const(zval* arr,
-                                          const char* key,
-                                          const char* value) {
-  char* val = NULL;
-
-  if (NULL == arr || NULL == key || NULL == value) {
-    return;
-  }
+/*
+ * Copyright 2020 New Relic Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
-  val = nr_strdup(value);
-  nr_php_add_assoc_string(arr, key, val);
-  nr_free(val);
-}
-
-#ifdef TAGS
-void zif_newrelic_get_security_metadata(void); /* ctags landing pad only */
-void newrelic_get_security_metadata(void);     /* ctags landing pad only */
-#endif
-PHP_FUNCTION(newrelic_get_security_metadata) {
+#include "csec_metadata.h"
 
-  NR_UNUSED_RETURN_VALUE;
-  NR_UNUSED_RETURN_VALUE_PTR;
-  NR_UNUSED_RETURN_VALUE_USED;
-  NR_UNUSED_THIS_PTR;
-  NR_UNUSED_EXECUTE_DATA;
+#include "util_memory.h"
 
-  array_init(return_value);
+#include "nr_axiom.h"
+#include "nr_agent.h"
+#include "nr_app.h"
+#include "php_includes.h"
+#include "php_compat.h"
+#include "php_newrelic.h"
 
-  nr_csec_php_add_assoc_string_const(return_value, KEY_ENTITY_NAME, nr_app_get_entity_name(NRPRG(app)));
-  nr_csec_php_add_assoc_string_const(return_value, KEY_ENTITY_TYPE, nr_app_get_entity_type(NRPRG(app)));
-  nr_csec_php_add_assoc_string_const(return_value, KEY_ENTITY_GUID, nr_app_get_entity_guid(NRPRG(app)));
-  nr_csec_php_add_assoc_string_const(return_value, KEY_HOSTNAME, nr_app_get_host_name(NRPRG(app)));
-  nr_csec_php_add_assoc_string_const(return_value, KEY_LICENSE, NRPRG(license).value);
+int nr_php_csec_get_metadata(nr_php_csec_metadata_t* csec_metadata) {
+  if (NULL == csec_metadata) {
+    return -1;
+  }
 
-  if (NRPRG(app)) {
-    nr_csec_php_add_assoc_string_const(return_value, KEY_AGENT_RUN_ID, NRPRG(app)->agent_run_id);
-    nr_csec_php_add_assoc_string_const(return_value, KEY_ACCOUNT_ID, NRPRG(app)->account_id);
-    nr_csec_php_add_assoc_string_const(return_value, KEY_PLICENSE, NRPRG(app)->plicense);
-    int high_security = NRPRG(app)->info.high_security;
-    add_assoc_long(return_value, KEY_HIGH_SECURITY, (long)high_security);
+  if (NULL == NRPRG(app)) {
+    return -2;
   }
 
+  csec_metadata->high_security = NRPRG(app)->info.high_security;
+  csec_metadata->entity_name = nr_strdup(nr_app_get_entity_name(NRPRG(app)));
+  csec_metadata->entity_type = nr_strdup(nr_app_get_entity_type(NRPRG(app)));
+  csec_metadata->entity_guid = nr_strdup(nr_app_get_entity_guid(NRPRG(app)));
+  csec_metadata->host_name = nr_strdup(nr_app_get_host_name(NRPRG(app)));
+  csec_metadata->agent_run_id = nr_strdup(NRPRG(app)->agent_run_id);
+  csec_metadata->account_id = nr_strdup(NRPRG(app)->account_id);
+  csec_metadata->license = nr_strdup(NRPRG(license).value);
+  csec_metadata->plicense = nr_strdup(NRPRG(app)->plicense);
+
+  return 0;
 }
diff --git a/agent/csec_metadata.h b/agent/csec_metadata.h
index 1716f6da4..572ce0718 100644
--- a/agent/csec_metadata.h
+++ b/agent/csec_metadata.h
@@ -1,12 +1,35 @@
-#include "php_agent.h"
-#include "util_hashmap.h"
+/*
+ * Copyright 2020 New Relic Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
-#define KEY_ENTITY_NAME "entity.name"
-#define KEY_ENTITY_TYPE "entity.type"
-#define KEY_ENTITY_GUID "entity.guid"
-#define KEY_HOSTNAME "hostname"
-#define KEY_AGENT_RUN_ID "agent.run.id"
-#define KEY_ACCOUNT_ID "account.id"
-#define KEY_LICENSE "license"
-#define KEY_PLICENSE "plicense"
-#define KEY_HIGH_SECURITY "high_security"
+#ifndef CSEC_METADATA_H
+#define CSEC_METADATA_H
+
+typedef struct _nr_php_csec_metadata_t {
+  int high_security;  /* Indicates if high security been set locally for this
+                         application */
+  char* license;      /* License key provided */
+  char* plicense;     /* Printable license (abbreviated for security) */
+  char* host_name;    /* Local host name reported to the daemon */
+  char* entity_name;  /* Entity name related to this application */
+  char* entity_type;  /* Entity type */
+  char* account_id;   /* Security : Added for getting account id */
+  char* entity_guid;  /* Entity guid related to this application */
+  char* agent_run_id; /* The collector's agent run ID; assigned from the
+                         New Relic backend */
+} nr_php_csec_metadata_t;
+
+/*
+ * Purpose : Return app meta data by populating nr_php_csec_metadata_t
+ *           structure. The caller is responsible for freeing the memory
+ *           allocated for the strings in the structure.
+ *
+ * Params  : Pointer to a nr_php_csec_metadata_t structure
+ *
+ * Returns : 0 for success
+ *          -1 for invalid input
+ *          -2 for invalid internal state
+ */
+extern int nr_php_csec_get_metadata(nr_php_csec_metadata_t*);
+#endif
diff --git a/agent/export.syms b/agent/export.syms
index c1252e827..7e8f1e2c4 100644
--- a/agent/export.syms
+++ b/agent/export.syms
@@ -1 +1,2 @@
 get_module
+nr_php_csec_get_metadata
diff --git a/agent/php_api_internal.h b/agent/php_api_internal.h
index f8ae9a653..61db36648 100644
--- a/agent/php_api_internal.h
+++ b/agent/php_api_internal.h
@@ -16,8 +16,6 @@
  */
 extern PHP_FUNCTION(newrelic_get_request_metadata);
 
-extern PHP_FUNCTION(newrelic_get_security_metadata);
-
 #ifdef ENABLE_TESTING_API
 
 /*
diff --git a/agent/php_newrelic.c b/agent/php_newrelic.c
index fb81d65b2..912dff365 100644
--- a/agent/php_newrelic.c
+++ b/agent/php_newrelic.c
@@ -342,11 +342,9 @@ static zend_function_entry newrelic_functions[] = {
 #ifdef PHP8
     PHP_FE(newrelic_get_linking_metadata, newrelic_arginfo_void)
     PHP_FE(newrelic_get_trace_metadata, newrelic_arginfo_void)
-    PHP_FE(newrelic_get_security_metadata, newrelic_arginfo_void)
 #else
     PHP_FE(newrelic_get_linking_metadata, 0)
     PHP_FE(newrelic_get_trace_metadata, 0)
-    PHP_FE(newrelic_get_security_metadata, 0)
 #endif /* PHP 8 */
     /*
      * Integration test helpers

From 8b573533761e5ca2eba52595404552edf8f58059 Mon Sep 17 00:00:00 2001
From: Michal Nowacki <mnowacki@newrelic.com>
Date: Fri, 21 Jun 2024 12:34:52 -0400
Subject: [PATCH 2/5] make `nr_php_csec_get_metadata` easier to use

---
 agent/csec_metadata.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/agent/csec_metadata.h b/agent/csec_metadata.h
index 572ce0718..ca7a8f332 100644
--- a/agent/csec_metadata.h
+++ b/agent/csec_metadata.h
@@ -32,4 +32,6 @@ typedef struct _nr_php_csec_metadata_t {
  *          -2 for invalid internal state
  */
 extern int nr_php_csec_get_metadata(nr_php_csec_metadata_t*);
+typedef int (*nr_php_csec_get_metadata_t)(nr_php_csec_metadata_t*);
+#define NR_PHP_CSEC_GET_METADATA "nr_php_csec_get_metadata"
 #endif

From d162d86f08c65f3cee6e5c4fd543c7a763e801ef Mon Sep 17 00:00:00 2001
From: Michal Nowacki <mnowacki@newrelic.com>
Date: Tue, 25 Jun 2024 19:17:09 -0400
Subject: [PATCH 3/5] refactor to avoid 'transport' struct

Replace 'transport' struct, which would have to be versioned, with a simple
getter API of `get(key, &ptr)` signature.
---
 agent/csec_metadata.c | 60 ++++++++++++++++++++++++++++++++++---------
 agent/csec_metadata.h | 39 ++++++++++++++--------------
 2 files changed, 68 insertions(+), 31 deletions(-)

diff --git a/agent/csec_metadata.c b/agent/csec_metadata.c
index 0a9d9d47c..0f9571a7b 100644
--- a/agent/csec_metadata.c
+++ b/agent/csec_metadata.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 New Relic Corporation. All rights reserved.
+ * Copyright 2024 New Relic Corporation. All rights reserved.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -14,8 +14,10 @@
 #include "php_compat.h"
 #include "php_newrelic.h"
 
-int nr_php_csec_get_metadata(nr_php_csec_metadata_t* csec_metadata) {
-  if (NULL == csec_metadata) {
+int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t key, void** p) {
+  const char* value = NULL;
+
+  if (NULL == p) {
     return -1;
   }
 
@@ -23,15 +25,49 @@ int nr_php_csec_get_metadata(nr_php_csec_metadata_t* csec_metadata) {
     return -2;
   }
 
-  csec_metadata->high_security = NRPRG(app)->info.high_security;
-  csec_metadata->entity_name = nr_strdup(nr_app_get_entity_name(NRPRG(app)));
-  csec_metadata->entity_type = nr_strdup(nr_app_get_entity_type(NRPRG(app)));
-  csec_metadata->entity_guid = nr_strdup(nr_app_get_entity_guid(NRPRG(app)));
-  csec_metadata->host_name = nr_strdup(nr_app_get_host_name(NRPRG(app)));
-  csec_metadata->agent_run_id = nr_strdup(NRPRG(app)->agent_run_id);
-  csec_metadata->account_id = nr_strdup(NRPRG(app)->account_id);
-  csec_metadata->license = nr_strdup(NRPRG(license).value);
-  csec_metadata->plicense = nr_strdup(NRPRG(app)->plicense);
+  switch (key) {
+    case NR_PHP_CSEC_METADATA_HIGH_SECURITY:
+      *p = nr_zalloc(sizeof(int));
+      if (NULL == *p) {
+        return -3;
+      }
+      *((int*)*p) = NRPRG(app)->info.high_security;
+      return 0;
+    case NR_PHP_CSEC_METADATA_ENTITY_NAME:
+      value = nr_app_get_entity_name(NRPRG(app));
+      break;
+    case NR_PHP_CSEC_METADATA_ENTITY_TYPE:
+      value = nr_app_get_entity_type(NRPRG(app));
+      break;
+    case NR_PHP_CSEC_METADATA_ENTITY_GUID:
+      value = nr_app_get_entity_guid(NRPRG(app));
+      break;
+    case NR_PHP_CSEC_METADATA_HOST_NAME:
+      value = nr_app_get_host_name(NRPRG(app));
+      break;
+    case NR_PHP_CSEC_METADATA_AGENT_RUN_ID:
+      value = NRPRG(app)->agent_run_id;
+      break;
+    case NR_PHP_CSEC_METADATA_ACCOUNT_ID:
+      value = NRPRG(app)->account_id;
+      break;
+    case NR_PHP_CSEC_METADATA_LICENSE:
+      value = NRPRG(license).value;
+      break;
+    case NR_PHP_CSEC_METADATA_PLICENSE:
+      value = NRPRG(app)->plicense;
+      break;
+    default:
+      return -4;
+  }
 
+  if (NULL == value) {
+    return -5;
+  }
+
+  *p = nr_strdup(value);
+  if (NULL == *p) {
+    return -3;
+  }
   return 0;
 }
diff --git a/agent/csec_metadata.h b/agent/csec_metadata.h
index ca7a8f332..c47bf97d9 100644
--- a/agent/csec_metadata.h
+++ b/agent/csec_metadata.h
@@ -1,37 +1,38 @@
 /*
- * Copyright 2020 New Relic Corporation. All rights reserved.
+ * Copyright 2024 New Relic Corporation. All rights reserved.
  * SPDX-License-Identifier: Apache-2.0
  */
 
 #ifndef CSEC_METADATA_H
 #define CSEC_METADATA_H
 
-typedef struct _nr_php_csec_metadata_t {
-  int high_security;  /* Indicates if high security been set locally for this
-                         application */
-  char* license;      /* License key provided */
-  char* plicense;     /* Printable license (abbreviated for security) */
-  char* host_name;    /* Local host name reported to the daemon */
-  char* entity_name;  /* Entity name related to this application */
-  char* entity_type;  /* Entity type */
-  char* account_id;   /* Security : Added for getting account id */
-  char* entity_guid;  /* Entity guid related to this application */
-  char* agent_run_id; /* The collector's agent run ID; assigned from the
-                         New Relic backend */
-} nr_php_csec_metadata_t;
+typedef enum {
+    NR_PHP_CSEC_METADATA_HIGH_SECURITY = 1,
+    NR_PHP_CSEC_METADATA_ENTITY_NAME,
+    NR_PHP_CSEC_METADATA_ENTITY_TYPE,
+    NR_PHP_CSEC_METADATA_ENTITY_GUID,
+    NR_PHP_CSEC_METADATA_HOST_NAME,
+    NR_PHP_CSEC_METADATA_AGENT_RUN_ID,
+    NR_PHP_CSEC_METADATA_ACCOUNT_ID,
+    NR_PHP_CSEC_METADATA_LICENSE,
+    NR_PHP_CSEC_METADATA_PLICENSE
+} nr_php_csec_metadata_key_t;
 
 /*
- * Purpose : Return app meta data by populating nr_php_csec_metadata_t
- *           structure. The caller is responsible for freeing the memory
- *           allocated for the strings in the structure.
+ * Purpose : Copy requested app meta data into allocated *value.
+ *           The caller is responsible for freeing the memory
+ *           allocated.
  *
  * Params  : Pointer to a nr_php_csec_metadata_t structure
  *
  * Returns : 0 for success
  *          -1 for invalid input
  *          -2 for invalid internal state
+ *          -3 for inability to allocate memory
+ *          -4 for invalid metadata key
+ *          -5 for inability to retrieve metadata value
  */
-extern int nr_php_csec_get_metadata(nr_php_csec_metadata_t*);
-typedef int (*nr_php_csec_get_metadata_t)(nr_php_csec_metadata_t*);
+extern int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t k, void** value);
+typedef int (*nr_php_csec_get_metadata_t)(const nr_php_csec_metadata_key_t k, void** value);
 #define NR_PHP_CSEC_GET_METADATA "nr_php_csec_get_metadata"
 #endif

From c1981dbeb76ce53ec2fd74b2af1b3fc357eb6644 Mon Sep 17 00:00:00 2001
From: Michal Nowacki <mnowacki@newrelic.com>
Date: Wed, 26 Jun 2024 14:24:01 -0400
Subject: [PATCH 4/5] simplify return value - always a string

This approach adds some level of protection (compiler type checking) from
misusing the API.
---
 agent/csec_metadata.c | 12 ++++++------
 agent/csec_metadata.h |  7 ++++---
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/agent/csec_metadata.c b/agent/csec_metadata.c
index 0f9571a7b..af8af2d91 100644
--- a/agent/csec_metadata.c
+++ b/agent/csec_metadata.c
@@ -14,7 +14,7 @@
 #include "php_compat.h"
 #include "php_newrelic.h"
 
-int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t key, void** p) {
+int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t key, char** p) {
   const char* value = NULL;
 
   if (NULL == p) {
@@ -27,12 +27,12 @@ int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t key, void** p) {
 
   switch (key) {
     case NR_PHP_CSEC_METADATA_HIGH_SECURITY:
-      *p = nr_zalloc(sizeof(int));
-      if (NULL == *p) {
-        return -3;
+      if (NRPRG(app)->info.high_security) {
+        value = "true";
+      } else {
+        value = "false";
       }
-      *((int*)*p) = NRPRG(app)->info.high_security;
-      return 0;
+      break;
     case NR_PHP_CSEC_METADATA_ENTITY_NAME:
       value = nr_app_get_entity_name(NRPRG(app));
       break;
diff --git a/agent/csec_metadata.h b/agent/csec_metadata.h
index c47bf97d9..a98b79339 100644
--- a/agent/csec_metadata.h
+++ b/agent/csec_metadata.h
@@ -21,7 +21,8 @@ typedef enum {
 /*
  * Purpose : Copy requested app meta data into allocated *value.
  *           The caller is responsible for freeing the memory
- *           allocated.
+ *           allocated. The value is a string representation of
+ *           the requested metadata.
  *
  * Params  : Pointer to a nr_php_csec_metadata_t structure
  *
@@ -32,7 +33,7 @@ typedef enum {
  *          -4 for invalid metadata key
  *          -5 for inability to retrieve metadata value
  */
-extern int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t k, void** value);
-typedef int (*nr_php_csec_get_metadata_t)(const nr_php_csec_metadata_key_t k, void** value);
+extern int nr_php_csec_get_metadata(const nr_php_csec_metadata_key_t k, char** value);
+typedef int (*nr_php_csec_get_metadata_t)(const nr_php_csec_metadata_key_t k, char** value);
 #define NR_PHP_CSEC_GET_METADATA "nr_php_csec_get_metadata"
 #endif

From 2f616e16fc087f09b34c63cfafff995c103c8402 Mon Sep 17 00:00:00 2001
From: Anmol Jain <anmoljain@newrelic.com>
Date: Wed, 22 Jan 2025 12:40:58 +0530
Subject: [PATCH 5/5] remove csec agent config, update status log for csec
 config

---
 agent/php_minit.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/agent/php_minit.c b/agent/php_minit.c
index 6a013e238..d6410e40f 100644
--- a/agent/php_minit.c
+++ b/agent/php_minit.c
@@ -719,11 +719,14 @@ PHP_MINIT_FUNCTION(newrelic) {
   nr_wordpress_minit();
   nr_php_set_opcode_handlers();
 
-  if (!NR_PHP_PROCESS_GLOBALS(nr_security_agent_enabled) || !NR_PHP_PROCESS_GLOBALS(nr_security_enabled) || NR_PHP_PROCESS_GLOBALS(high_security)) {
-    nrl_info(NRL_INIT, "New Relic Security is completely disabled by one of the user provided config `newrelic.security.enabled`, `newrelic.security.agent.enabled` or `newrelic.high_security`. Not loading security capabilities.");
-    nrl_debug(NRL_INIT, "newrelic.security.agent.enabled : %s", NR_PHP_PROCESS_GLOBALS(nr_security_enabled) ? "true" : "false");
-    nrl_debug(NRL_INIT, "newrelic.security.enabled : %s", NR_PHP_PROCESS_GLOBALS(nr_security_agent_enabled) ? "true" : "false");
-    nrl_debug(NRL_INIT, "newrelic.high_security : %s", NR_PHP_PROCESS_GLOBALS(high_security) ? "true" : "false");
+  if (NR_PHP_PROCESS_GLOBALS(nr_security_agent_enabled)
+      && NR_PHP_PROCESS_GLOBALS(nr_security_enabled)
+      && !NR_PHP_PROCESS_GLOBALS(high_security)) {
+    nrl_info(
+        NRL_INIT,
+        "New Relic Security is enabled by the user provided config "
+        "`newrelic.security.enabled`, `newrelic.security.agent.enabled` and "
+        "`newrelic.high_security`. Security capabilities will be loaded.");
   }
 
   nrl_debug(NRL_INIT, "MINIT processing done");