Skip to content

Commit a86c5f5

Browse files
committed
feat(agent): ensure composer exists before retrieving info
1 parent f595c0a commit a86c5f5

File tree

6 files changed

+109
-40
lines changed

6 files changed

+109
-40
lines changed

agent/fw_hooks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extern void nr_phpunit_enable(TSRMLS_D);
5656
extern void nr_predis_enable(TSRMLS_D);
5757
extern void nr_zend_http_enable(TSRMLS_D);
5858
extern void nr_monolog_enable(TSRMLS_D);
59+
extern void nr_get_package_information(TSRMLS_D);
5960

6061
/* Vulnerability Management Packages */
6162
extern void nr_drupal_version(void);

agent/php_agent.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,3 +1229,36 @@ bool nr_php_function_is_static_method(const zend_function* func) {
12291229

12301230
return (func->common.fn_flags & ZEND_ACC_STATIC);
12311231
}
1232+
1233+
nr_composer_classification_t nr_composer_special(
1234+
const char* filename TSRMLS_DC) {
1235+
NR_UNUSED_TSRMLS;
1236+
1237+
if (nr_strcaseidx(filename, "vendor/composer/") >= 0) {
1238+
zval retval;
1239+
int result = -1;
1240+
char* func_string
1241+
= ""
1242+
"(function() {"
1243+
" try {"
1244+
" if (file_exists('vendor/composer/installed.php')) {"
1245+
" return 'SUCCESS';"
1246+
" } else {"
1247+
" return NULL;"
1248+
" }"
1249+
" } catch (exception $e) {"
1250+
" return NULL;"
1251+
" }"
1252+
"})();";
1253+
result = zend_eval_string(func_string, &retval, "check if file exists" TSRMLS_CC);
1254+
if (result == SUCCESS) {
1255+
NR_PHP_PROCESS_GLOBALS(composer_exists) = 1;
1256+
return FILE_EXISTS;
1257+
} else {
1258+
NR_PHP_PROCESS_GLOBALS(composer_exists) = 0;
1259+
return FILE_DOES_NOT_EXIST;
1260+
}
1261+
}
1262+
1263+
return FILE_DOES_NOT_EXIST;
1264+
}

agent/php_agent.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,9 @@ extern zval* nr_php_parse_str(const char* str, size_t len TSRMLS_DC);
847847
*/
848848
extern bool nr_php_function_is_static_method(const zend_function* func);
849849

850+
extern nr_composer_classification_t nr_composer_special(
851+
const char* filename TSRMLS_DC);
852+
850853
/*
851854
* Purpose : Get the execution data for the current PHP environment.
852855
*

agent/php_execute.c

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ typedef struct _nr_library_table_t {
476476
const char* library_name;
477477
const char* file_to_check;
478478
size_t file_to_check_len;
479+
nr_composer_special_fn_t special;
479480
nr_library_enable_fn_t enable;
480481
} nr_library_table_t;
481482

@@ -485,97 +486,97 @@ typedef struct _nr_library_table_t {
485486
// clang-format: off
486487
static nr_library_table_t libraries[] = {
487488
/* AWS-SDK-PHP 3 */
488-
{"AWS-SDK-PHP", NR_PSTR("aws-sdk-php/src/awsclient.php"), nr_aws_sdk_php_enable},
489+
{"AWS-SDK-PHP", NR_PSTR("aws-sdk-php/src/awsclient.php"), 0, nr_aws_sdk_php_enable},
489490

490491
/* Doctrine < 2.18 */
491-
{"Doctrine 2", NR_PSTR("doctrine/orm/query.php"), nr_doctrine2_enable},
492+
{"Doctrine 2", NR_PSTR("doctrine/orm/query.php"), 0, nr_doctrine2_enable},
492493
/* Doctrine 2.18 reworked the directory structure */
493-
{"Doctrine 2", NR_PSTR("doctrine/orm/src/query.php"), nr_doctrine2_enable},
494+
{"Doctrine 2", NR_PSTR("doctrine/orm/src/query.php"), 0, nr_doctrine2_enable},
494495

495-
{"Guzzle 3", NR_PSTR("guzzle/http/client.php"), nr_guzzle3_enable},
496-
{"Guzzle 4-5", NR_PSTR("hasemitterinterface.php"), nr_guzzle4_enable},
497-
{"Guzzle 6", NR_PSTR("guzzle/src/functions_include.php"), nr_guzzle6_enable},
496+
{"Guzzle 3", NR_PSTR("guzzle/http/client.php"), 0, nr_guzzle3_enable},
497+
{"Guzzle 4-5", NR_PSTR("hasemitterinterface.php"), 0, nr_guzzle4_enable},
498+
{"Guzzle 6", NR_PSTR("guzzle/src/functions_include.php"), 0, nr_guzzle6_enable},
498499

499-
{"MongoDB", NR_PSTR("mongodb/src/client.php"), nr_mongodb_enable},
500+
{"MongoDB", NR_PSTR("mongodb/src/client.php"), 0, nr_mongodb_enable},
500501

501502
/*
502503
* The first path is for Composer installs, the second is for
503504
* /usr/local/bin.
504505
*/
505-
{"PHPUnit", NR_PSTR("phpunit/src/framework/test.php"), nr_phpunit_enable},
506-
{"PHPUnit", NR_PSTR("phpunit/framework/test.php"), nr_phpunit_enable},
506+
{"PHPUnit", NR_PSTR("phpunit/src/framework/test.php"), 0, nr_phpunit_enable},
507+
{"PHPUnit", NR_PSTR("phpunit/framework/test.php"), 0, nr_phpunit_enable},
507508

508-
{"Predis", NR_PSTR("predis/src/client.php"), nr_predis_enable},
509-
{"Predis", NR_PSTR("predis/client.php"), nr_predis_enable},
509+
{"Predis", NR_PSTR("predis/src/client.php"), 0, nr_predis_enable},
510+
{"Predis", NR_PSTR("predis/client.php"), 0, nr_predis_enable},
510511

511512
/*
512513
* Allow Zend Framework 1.x to be detected as a library as well as a
513514
* framework. This allows Zend_Http_Client to be instrumented when used
514515
* with other frameworks or even without a framework at all. This is
515516
* necessary for Magento in particular, which is built on ZF1.
516517
*/
517-
{"Zend_Http", NR_PSTR("zend/http/client.php"), nr_zend_http_enable},
518+
{"Zend_Http", NR_PSTR("zend/http/client.php"), 0, nr_zend_http_enable},
518519

519520
/*
520521
* Allow Laminas Framework 3.x to be detected as a library as well as a
521522
* framework. This allows Laminas_Http_Client to be instrumented when used
522523
* with other frameworks or even without a framework at all.
523524
*/
524-
{"Laminas_Http", NR_PSTR("laminas-http/src/client.php"), nr_laminas_http_enable},
525+
{"Laminas_Http", NR_PSTR("laminas-http/src/client.php"), 0, nr_laminas_http_enable},
525526

526527
/*
527528
* Other frameworks, detected only, but not specifically
528529
* instrumented. We detect these as libraries so that we don't prevent
529530
* detection of a supported framework or library later (since a transaction
530531
* can only have one framework).
531532
*/
532-
{"Aura1", NR_PSTR("aura/framework/system.php"), NULL},
533-
{"Aura2", NR_PSTR("aura/di/src/containerinterface.php"), NULL},
534-
{"Aura3", NR_PSTR("aura/di/src/containerconfiginterface.php"), NULL},
535-
{"CakePHP3", NR_PSTR("cakephp/src/core/functions.php"), NULL},
536-
{"Fuel", NR_PSTR("fuel/core/classes/fuel.php"), NULL},
537-
{"Lithium", NR_PSTR("lithium/core/libraries.php"), NULL},
538-
{"Phpbb", NR_PSTR("phpbb/request/request.php"), NULL},
539-
{"Phpixie2", NR_PSTR("phpixie/core/classes/phpixie/pixie.php"), NULL},
540-
{"Phpixie3", NR_PSTR("phpixie/framework.php"), NULL},
541-
{"React", NR_PSTR("react/event-loop/src/loopinterface.php"), NULL},
542-
{"SilverStripe", NR_PSTR("injector/silverstripeinjectioncreator.php"), NULL},
543-
{"SilverStripe4", NR_PSTR("silverstripeserviceconfigurationlocator.php"), NULL},
544-
{"Typo3", NR_PSTR("classes/typo3/flow/core/bootstrap.php"), NULL},
545-
{"Typo3", NR_PSTR("typo3/sysext/core/classes/core/bootstrap.php"), NULL},
533+
{"Aura1", NR_PSTR("aura/framework/system.php"), 0, NULL},
534+
{"Aura2", NR_PSTR("aura/di/src/containerinterface.php"), 0, NULL},
535+
{"Aura3", NR_PSTR("aura/di/src/containerconfiginterface.php"), 0, NULL},
536+
{"CakePHP3", NR_PSTR("cakephp/src/core/functions.php"), 0, NULL},
537+
{"Fuel", NR_PSTR("fuel/core/classes/fuel.php"), 0, NULL},
538+
{"Lithium", NR_PSTR("lithium/core/libraries.php"), 0, NULL},
539+
{"Phpbb", NR_PSTR("phpbb/request/request.php"), 0, NULL},
540+
{"Phpixie2", NR_PSTR("phpixie/core/classes/phpixie/pixie.php"), 0, NULL},
541+
{"Phpixie3", NR_PSTR("phpixie/framework.php"), 0, NULL},
542+
{"React", NR_PSTR("react/event-loop/src/loopinterface.php"), 0, NULL},
543+
{"SilverStripe", NR_PSTR("injector/silverstripeinjectioncreator.php"), 0, NULL},
544+
{"SilverStripe4", NR_PSTR("silverstripeserviceconfigurationlocator.php"), 0, NULL},
545+
{"Typo3", NR_PSTR("classes/typo3/flow/core/bootstrap.php"), 0, NULL},
546+
{"Typo3", NR_PSTR("typo3/sysext/core/classes/core/bootstrap.php"), 0, NULL},
546547

547548
/*
548549
* Other CMS (content management systems), detected only, but
549550
* not specifically instrumented.
550551
*/
551-
{"Moodle", NR_PSTR("moodlelib.php"), NULL},
552+
{"Moodle", NR_PSTR("moodlelib.php"), 0, NULL},
552553
/*
553554
* It is likely that this will never be found, since the CodeIgniter.php
554555
* will get loaded first, and as such mark this transaction as belonging to
555556
* CodeIgniter, and not Expession Engine.
556557
*/
557-
{"ExpressionEngine", NR_PSTR("system/expressionengine/config/config.php"), NULL},
558+
{"ExpressionEngine", NR_PSTR("system/expressionengine/config/config.php"), 0, NULL},
558559
/*
559560
* ExpressionEngine 5, however, has a very obvious file we can look for.
560561
*/
561-
{"ExpressionEngine5", NR_PSTR("expressionengine/boot/boot.php"), NULL},
562+
{"ExpressionEngine5", NR_PSTR("expressionengine/boot/boot.php"), 0, NULL},
562563
/*
563564
* DokuWiki uses doku.php as an entry point, but has other files that are
564565
* loaded directly that this won't pick up. That's probably OK for
565566
* supportability metrics, but we'll add the most common name for the
566567
* configuration file as well just in case.
567568
*/
568-
{"DokuWiki", NR_PSTR("doku.php"), NULL},
569-
{"DokuWiki", NR_PSTR("conf/dokuwiki.php"), NULL},
569+
{"DokuWiki", NR_PSTR("doku.php"), 0, NULL},
570+
{"DokuWiki", NR_PSTR("conf/dokuwiki.php"), 0, NULL},
570571

571572
/*
572573
* SugarCRM no longer has a community edition, so this likely only works
573574
* with older versions.
574575
*/
575-
{"SugarCRM", NR_PSTR("sugarobjects/sugarconfig.php"), NULL},
576+
{"SugarCRM", NR_PSTR("sugarobjects/sugarconfig.php"), 0, NULL},
576577

577-
{"Xoops", NR_PSTR("class/xoopsload.php"), NULL},
578-
{"E107", NR_PSTR("e107_handlers/e107_class.php"), NULL},
578+
{"Xoops", NR_PSTR("class/xoopsload.php"), 0, NULL},
579+
{"E107", NR_PSTR("e107_handlers/e107_class.php"), 0, NULL},
579580
};
580581
// clang-format: on
581582

@@ -584,15 +585,15 @@ static size_t num_libraries = sizeof(libraries) / sizeof(nr_library_table_t);
584585
// clang-format: off
585586
static nr_library_table_t logging_frameworks[] = {
586587
/* Monolog - Logging for PHP */
587-
{"Monolog", NR_PSTR("monolog/logger.php"), nr_monolog_enable},
588+
{"Monolog", NR_PSTR("monolog/logger.php"), 0, nr_monolog_enable},
588589
/* Consolidation/Log - Logging for PHP */
589-
{"Consolidation/Log", NR_PSTR("consolidation/log/src/logger.php"), NULL},
590+
{"Consolidation/Log", NR_PSTR("consolidation/log/src/logger.php"), 0, NULL},
590591
/* laminas-log - Logging for PHP */
591-
{"laminas-log", NR_PSTR("laminas-log/src/logger.php"), NULL},
592+
{"laminas-log", NR_PSTR("laminas-log/src/logger.php"), 0, NULL},
592593
/* cakephp-log - Logging for PHP */
593-
{"cakephp-log", NR_PSTR("cakephp/log/log.php"), NULL},
594+
{"cakephp-log", NR_PSTR("cakephp/log/log.php"), 0, NULL},
594595
/* Analog - Logging for PHP */
595-
{"Analog", NR_PSTR("analog/analog.php"), NULL},
596+
{"Analog", NR_PSTR("analog/analog.php"), 0, NULL},
596597
};
597598
// clang-format: on
598599

@@ -931,6 +932,28 @@ static void nr_execute_handle_library(const char* filename,
931932
}
932933
}
933934

935+
static void nr_execute_handle_composer(const char* filename,
936+
const size_t filename_len TSRMLS_DC) {
937+
size_t i;
938+
939+
for (i = 0; i < num_libraries; i++) {
940+
if (nr_striendswith(STR_AND_LEN(filename),
941+
STR_AND_LEN(libraries[i].file_to_check))) {
942+
if (libraries[i].special) {
943+
nr_composer_classification_t special
944+
= libraries[i].special(filename TSRMLS_CC);
945+
if (FILE_EXISTS == special) {
946+
nr_fw_support_add_library_supportability_metric(
947+
NRPRG(txn), libraries[i].library_name);
948+
if (NULL != libraries[i].enable) {
949+
libraries[i].enable(TSRMLS_C);
950+
}
951+
}
952+
}
953+
}
954+
}
955+
}
956+
934957
static void nr_execute_handle_logging_framework(const char* filename,
935958
const size_t filename_len
936959
TSRMLS_DC) {
@@ -999,6 +1022,7 @@ static void nr_php_user_instrumentation_from_file(const char* filename,
9991022
nr_execute_handle_framework(all_frameworks, num_all_frameworks, filename,
10001023
filename_len TSRMLS_CC);
10011024
nr_execute_handle_library(filename, filename_len TSRMLS_CC);
1025+
nr_execute_handle_composer(filename, filename_len);
10021026
nr_execute_handle_logging_framework(filename, filename_len TSRMLS_CC);
10031027
if (NRINI(vulnerability_management_package_detection_enabled)) {
10041028
nr_execute_handle_package(filename);

agent/php_execute.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ typedef enum {
4141
typedef nr_framework_classification_t (*nr_framework_special_fn_t)(
4242
const char* filename TSRMLS_DC);
4343

44+
typedef enum {
45+
FILE_EXISTS, /* The file we are looking for exists */
46+
FILE_DOES_NOT_EXIST, /* The file we are looking for does not exist */
47+
} nr_composer_classification_t;
48+
typedef nr_composer_classification_t (*nr_composer_special_fn_t)(
49+
const char* filename);
50+
4451
/*
4552
* Version specific metadata that we have to gather before we call the original
4653
* execute_ex handler, as different versions of PHP behave differently in terms

agent/php_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef struct _nrphpglobals_t {
7676
int preload_framework_library_detection; /* Enables preloading framework and
7777
library detection */
7878
char* docker_id; /* 64 byte hex docker ID parsed from /proc/self/mountinfo */
79+
int composer_exists; /* Check if composer exists*/
7980

8081
/* Original PHP callback pointer contents */
8182
nrphperrfn_t orig_error_cb;

0 commit comments

Comments
 (0)