@@ -295,6 +295,12 @@ function syslog_partition_create($table) {
295295 $ cformat = 'd ' . date ('Ymd ' , $ time );
296296 $ lnow = date ('Y-m-d ' , $ time +86400 );
297297
298+ /* validate DDL interpolation values to prevent injection */
299+ if (!preg_match ('/^d\d{8}$/ ' , $ cformat ) || !preg_match ('/^\d{4}-\d{2}-\d{2}$/ ' , $ lnow )) {
300+ cacti_log ('SYSLOG ERROR: Invalid partition format values detected ' , false , 'SYSTEM ' );
301+ return false ;
302+ }
303+
298304 $ exists = syslog_db_fetch_row_prepared ("SELECT *
299305 FROM `information_schema`.`partitions`
300306 WHERE table_schema = ?
@@ -308,13 +314,19 @@ function syslog_partition_create($table) {
308314 $ lock_name = hash ('sha256 ' , $ syslogdb_default . 'syslog_partition_create. ' . $ table );
309315
310316 try {
311- syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
317+ $ locked = syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
318+
319+ if ((int )$ locked !== 1 ) {
320+ cacti_log ("SYSLOG WARNING: Failed to acquire partition create lock for ' $ table' " , false , 'SYSTEM ' );
321+ return false ;
322+ }
312323
313324 cacti_log ("SYSLOG: Creating new partition ' $ cformat' for table ' $ table' " , false , 'SYSTEM ' );
314325
315326 syslog_debug ("Creating new partition ' $ cformat' for table ' $ table' " );
316327
317- /* MySQL does not support parameter binding for DDL statements */
328+ /* MySQL does not support parameter binding for DDL statements;
329+ $cformat and $lnow are validated above via regex */
318330 syslog_db_execute_prepared ("ALTER TABLE ` " . $ syslogdb_default . "`.` $ table` REORGANIZE PARTITION dMaxValue INTO (
319331 PARTITION $ cformat VALUES LESS THAN (TO_DAYS(' $ lnow')),
320332 PARTITION dMaxValue VALUES LESS THAN MAXVALUE) " );
@@ -354,7 +366,12 @@ function syslog_partition_remove($table) {
354366 $ lock_name = hash ('sha256 ' , $ syslogdb_default . 'syslog_partition_remove. ' . $ table );
355367
356368 try {
357- syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
369+ $ locked = syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
370+
371+ if ((int )$ locked !== 1 ) {
372+ cacti_log ("SYSLOG WARNING: Failed to acquire partition remove lock for ' $ table' " , false , 'SYSTEM ' );
373+ return $ syslog_deleted ;
374+ }
358375
359376 $ i = 0 ;
360377 while ($ user_partitions > $ days ) {
@@ -445,8 +462,10 @@ function syslog_remove_items($table, $uniqueID) {
445462
446463 if (cacti_sizeof ($ rows )) {
447464 foreach ($ rows as $ remove ) {
448- $ sql = '' ;
449- $ sql1 = '' ;
465+ $ sql = '' ;
466+ $ sql1 = '' ;
467+ $ params = array ();
468+ $ params1 = array ();
450469
451470 if ($ remove ['type ' ] == 'facility ' ) {
452471 if ($ table == 'syslog_incoming ' ) {
@@ -1326,10 +1345,33 @@ function syslog_execute_ticket_command($alert, $hostlist, $context) {
13261345 $ command = trim (read_config_option ('syslog_ticket_command ' ));
13271346
13281347 if ($ command != '' ) {
1329- $ cparts = preg_split ('/\s+/ ' , trim ($ command ));
1330- $ executable = trim ($ cparts [0 ], '" \'' );
1348+ /*
1349+ * Extract the executable portion from the configured command.
1350+ * This allows for quoted paths and additional arguments in the
1351+ * configuration while still validating the executable itself.
1352+ */
1353+ $ executable = $ command ;
1354+ $ firstChar = substr ($ executable , 0 , 1 );
13311355
1332- if (is_executable ($ executable )) {
1356+ if ($ firstChar === '" ' || $ firstChar === "' " ) {
1357+ $ quoteChar = $ firstChar ;
1358+ $ closing = strpos ($ executable , $ quoteChar , 1 );
1359+
1360+ if ($ closing !== false ) {
1361+ $ executable = substr ($ executable , 1 , $ closing - 1 );
1362+ } else {
1363+ // Unbalanced quotes; fall back to trimming quotes/whitespace.
1364+ $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1365+ }
1366+ } else {
1367+ $ parts = preg_split ('/\s+/ ' , $ executable );
1368+ if (is_array ($ parts ) && isset ($ parts [0 ])) {
1369+ $ executable = $ parts [0 ];
1370+ }
1371+ $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1372+ }
1373+
1374+ if ($ executable !== '' && is_executable ($ executable )) {
13331375 $ command = $ command .
13341376 ' --alert-name= ' . cacti_escapeshellarg (clean_up_name ($ alert ['name ' ])) .
13351377 ' --severity= ' . cacti_escapeshellarg ($ alert ['severity ' ]) .
@@ -1356,31 +1398,51 @@ function syslog_execute_ticket_command($alert, $hostlist, $context) {
13561398}
13571399
13581400function syslog_execute_alert_command ($ alert , $ results , $ hostname ) {
1359- if ($ alert ['execute_command ' ] != 'on ' ) {
1360- return ;
1361- }
1401+ if ($ alert ['execute_command ' ] == 'on ' ) {
1402+ $ command = trim ($ alert ['command ' ]);
13621403
1363- $ command = trim ($ alert ['command ' ]);
1404+ if ($ command != '' ) {
1405+ $ command = alert_replace_variables ($ alert , $ results , $ hostname );
13641406
1365- if ($ command != '' ) {
1366- $ command = alert_replace_variables ($ alert , $ results , $ hostname );
1407+ /*
1408+ * Extract the executable portion from the command string.
1409+ * This allows for quoted paths and additional arguments.
1410+ */
1411+ $ executable = $ command ;
1412+ $ firstChar = substr ($ executable , 0 , 1 );
13671413
1368- $ cparts = preg_split ('/\s+/ ' , trim ($ command ));
1369- $ executable = trim ($ cparts [0 ], '" \'' );
1414+ if ($ firstChar === '" ' || $ firstChar === "' " ) {
1415+ $ quoteChar = $ firstChar ;
1416+ $ closing = strpos ($ executable , $ quoteChar , 1 );
13701417
1371- if (is_executable ($ executable )) {
1372- $ output = array ();
1373- $ returnCode = 0 ;
1418+ if ($ closing !== false ) {
1419+ $ executable = substr ($ executable , 1 , $ closing - 1 );
1420+ } else {
1421+ // Unbalanced quotes; fall back to trimming quotes/whitespace.
1422+ $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1423+ }
1424+ } else {
1425+ $ parts = preg_split ('/\s+/ ' , $ executable );
1426+ if (is_array ($ parts ) && isset ($ parts [0 ])) {
1427+ $ executable = $ parts [0 ];
1428+ }
1429+ $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1430+ }
13741431
1375- exec ($ command , $ output , $ returnCode );
1432+ if ($ executable !== '' && is_executable ($ executable )) {
1433+ $ output = array ();
1434+ $ returnCode = 0 ;
13761435
1377- $ logMessage = "SYSLOG NOTICE: Executing ' $ command' Command return code: $ returnCode " ;
1378- cacti_log ($ logMessage , true , 'SYSTEM ' );
1379- } else {
1380- if (strpos ($ executable , DIRECTORY_SEPARATOR ) === false ) {
1381- cacti_log (sprintf ('SYSLOG ERROR: Alert Command path \'%s \' is missing absolute path separator ' , $ executable ), false , 'SYSTEM ' );
1436+ exec ($ command , $ output , $ returnCode );
1437+
1438+ $ logMessage = "SYSLOG NOTICE: Executing ' $ command' Command return code: $ returnCode " ;
1439+ cacti_log ($ logMessage , true , 'SYSTEM ' );
13821440 } else {
1383- cacti_log (sprintf ('SYSLOG ERROR: Alert Command path \'%s \' is not executable ' , $ executable ), false , 'SYSTEM ' );
1441+ if (strpos ($ executable , DIRECTORY_SEPARATOR ) === false ) {
1442+ cacti_log (sprintf ('SYSLOG ERROR: Alert Command path \'%s \' is missing absolute path separator ' , $ executable ), false , 'SYSTEM ' );
1443+ } else {
1444+ cacti_log (sprintf ('SYSLOG ERROR: Alert Command path \'%s \' is not executable ' , $ executable ), false , 'SYSTEM ' );
1445+ }
13841446 }
13851447 }
13861448 }
@@ -1822,6 +1884,8 @@ function syslog_get_alert_sql(&$alert, $uniqueID) {
18221884function syslog_preprocess_incoming_records () {
18231885 global $ syslogdb_default ;
18241886
1887+ $ attempts = 0 ;
1888+
18251889 while (1 ) {
18261890 $ uniqueID = rand (1 , 127 );
18271891
@@ -1833,6 +1897,13 @@ function syslog_preprocess_incoming_records() {
18331897 if ($ count == 0 ) {
18341898 break ;
18351899 }
1900+
1901+ $ attempts ++;
1902+
1903+ if ($ attempts >= 256 ) {
1904+ cacti_log ('SYSLOG ERROR: Unable to find unused uniqueID after 256 attempts ' , false , 'SYSTEM ' );
1905+ return array ('uniqueID ' => 0 , 'incoming ' => 0 );
1906+ }
18361907 }
18371908
18381909 /* flag all records with the uniqueID prior to moving */
@@ -2088,7 +2159,7 @@ function syslog_incoming_to_syslog($uniqueID) {
20882159
20892160 syslog_debug (sprintf ('Moved %5s - Message(s) to the syslog table ' , $ moved ));
20902161
2091- syslog_db_execute_prepared ('DELETE FROM ` ' . $ syslogdb_default . '`.`syslog_incoming` WHERE status= ' . $ uniqueID );
2162+ syslog_db_execute_prepared ('DELETE FROM ` ' . $ syslogdb_default . '`.`syslog_incoming` WHERE status = ? ' , array ( $ uniqueID) );
20922163
20932164 syslog_debug (sprintf ('Deleted %5s - Already Processed Message(s) from incoming ' , db_affected_rows ($ syslog_cnn )));
20942165
0 commit comments