@@ -153,11 +153,48 @@ function syslog_apply_selected_items_action($selected_items, $drp_action, $actio
153153 /* Re-serialize the sanitized array and URL-encode so the value is
154154 * safe to embed in a JS document.location string (avoids injection
155155 * via the raw request value that $export_items carries). */
156- $ _SESSION ['exporter ' ] = rawurlencode (serialize ($ selected_items ));
156+ $ safe_items = array_map ('intval ' , $ selected_items );
157+ $ _SESSION ['exporter ' ] = rawurlencode (serialize ($ safe_items ));
157158 }
158159 }
159160}
160161
162+ /**
163+ * Load and validate the XML import payload from either the textbox or file upload.
164+ *
165+ * @return string|false The raw XML string, or false when no input was provided.
166+ */
167+ function syslog_get_import_xml_payload () {
168+ $ import_text = get_nfilter_request_var ('import_text ' );
169+
170+ if (trim (get_nfilter_request_var ('import_text ' )) != '' ) {
171+ $ xml_data = $ import_text ;
172+ } elseif (isset ($ _FILES ['import_file ' ]['tmp_name ' ]) &&
173+ $ _FILES ['import_file ' ]['tmp_name ' ] != 'none ' &&
174+ $ _FILES ['import_file ' ]['tmp_name ' ] != '' ) {
175+ $ fp = fopen ($ _FILES ['import_file ' ]['tmp_name ' ], 'r ' );
176+ $ xml_data = fread ($ fp , filesize ($ _FILES ['import_file ' ]['tmp_name ' ]));
177+ fclose ($ fp );
178+ } else {
179+ return false ;
180+ }
181+
182+ /* Validate XML structure before processing */
183+ libxml_use_internal_errors (true );
184+ $ xml_test = simplexml_load_string ($ xml_data );
185+ $ xml_errors = libxml_get_errors ();
186+ libxml_clear_errors ();
187+ libxml_use_internal_errors (false );
188+
189+ if ($ xml_test === false || !empty ($ xml_errors )) {
190+ raise_message ('syslog_import_error ' , __ ('ERROR: Import data contains malformed XML. ' , 'syslog ' ), MESSAGE_LEVEL_ERROR );
191+
192+ return false ;
193+ }
194+
195+ return $ xml_data ;
196+ }
197+
161198function syslog_is_partitioned () {
162199 global $ syslogdb_default ;
163200
@@ -313,7 +350,12 @@ function syslog_partition_remove($table) {
313350 $ lock_name = hash ('sha256 ' , $ syslogdb_default . 'syslog_partition_remove. ' . $ table );
314351
315352 try {
316- syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
353+ $ lock_acquired = syslog_db_fetch_cell_prepared ('SELECT GET_LOCK(?, 10) ' , array ($ lock_name ));
354+
355+ if ($ lock_acquired != 1 ) {
356+ cacti_log ("SYSLOG WARNING: Unable to acquire partition lock for removal of table ' $ table' " , false , 'SYSTEM ' );
357+ return $ syslog_deleted ;
358+ }
317359
318360 $ i = 0 ;
319361 while ($ user_partitions > $ days ) {
@@ -382,6 +424,8 @@ function syslog_remove_items($table, $uniqueID) {
382424 global $ config , $ syslog_cnn , $ syslog_incoming_config ;
383425 global $ syslogdb_default ;
384426
427+ $ uniqueID = (int ) $ uniqueID ;
428+
385429 syslog_debug ('------------------------------------------------------------------------------------- ' );
386430 syslog_debug ('Processing Removal Rules... ' );
387431
@@ -790,6 +834,7 @@ function sql_hosts_where($tab) {
790834
791835 if (!isempty_request_var ('host ' ) && get_nfilter_request_var ('host ' ) != 'null ' ) {
792836 $ hostarray = explode (', ' , trim (get_nfilter_request_var ('host ' )));
837+ $ hostarray = array_map ('intval ' , $ hostarray );
793838 if ($ hostarray [0 ] != '0 ' ) {
794839 foreach ($ hostarray as $ host_id ) {
795840 input_validate_input_number ($ host_id );
@@ -1014,12 +1059,12 @@ function syslog_manage_items($from_table, $to_table) {
10141059 $ sql_sel = "SELECT seq FROM ` " . $ syslogdb_default . "`. $ from_table
10151060 WHERE facility_id IN
10161061 (SELECT distinct facility_id FROM ` " . $ syslogdb_default . "`syslog_facilities
1017- WHERE facility =' " . $ remove ['message ' ]. " ' ) " ;
1062+ WHERE facility = " . db_qstr ( $ remove ['message ' ]) . " ) " ;
10181063 } else {
10191064 $ sql_dlt = "DELETE FROM ` " . $ syslogdb_default . "`. $ from_table
10201065 WHERE facility_id IN
10211066 (SELECT distinct facility_id FROM ` " . $ syslogdb_default . "`syslog_facilities
1022- WHERE facility =' " . $ remove ['message ' ]. " ' ) " ;
1067+ WHERE facility = " . db_qstr ( $ remove ['message ' ]) . " ) " ;
10231068 }
10241069
10251070 } elseif ($ remove ['type ' ] == 'host ' ) {
@@ -1028,37 +1073,37 @@ function syslog_manage_items($from_table, $to_table) {
10281073 FROM ` " . $ syslogdb_default . "`. $ from_table
10291074 WHERE host_id in
10301075 (SELECT distinct host_id FROM ` " . $ syslogdb_default . "`syslog_hosts
1031- WHERE host =' " . $ remove ['message ' ]. " ' ) " ;
1076+ WHERE host = " . db_qstr ( $ remove ['message ' ]) . " ) " ;
10321077 } else {
10331078 $ sql_dlt = "DELETE FROM ` " . $ syslogdb_default . "`. $ from_table
10341079 WHERE host_id in
10351080 (SELECT distinct host_id FROM ` " . $ syslogdb_default . "`syslog_hosts
1036- WHERE host =' " . $ remove ['message ' ]. " ' ) " ;
1081+ WHERE host = " . db_qstr ( $ remove ['message ' ]) . " ) " ;
10371082 }
10381083 } elseif ($ remove ['type ' ] == 'messageb ' ) {
10391084 if ($ remove ['method ' ] != 'del ' ) {
10401085 $ sql_sel = "SELECT seq FROM ` " . $ syslogdb_default . "`. $ from_table
1041- WHERE message LIKE ' " . $ remove ['message ' ] . " %' " ;
1086+ WHERE message LIKE " . db_qstr ( $ remove ['message ' ] . ' % ' ) ;
10421087 } else {
10431088 $ sql_dlt = "DELETE FROM ` " . $ syslogdb_default . "`. $ from_table
1044- WHERE message LIKE ' " . $ remove ['message ' ] . " %' " ;
1089+ WHERE message LIKE " . db_qstr ( $ remove ['message ' ] . ' % ' ) ;
10451090 }
10461091
10471092 } elseif ($ remove ['type ' ] == 'messagec ' ) {
10481093 if ($ remove ['method ' ] != 'del ' ) {
10491094 $ sql_sel = "SELECT seq FROM ` " . $ syslogdb_default . "`. $ from_table
1050- WHERE message LIKE '% " . $ remove ['message ' ] . " %' " ;
1095+ WHERE message LIKE " . db_qstr ( ' % ' . $ remove ['message ' ] . ' % ' ) ;
10511096 } else {
10521097 $ sql_dlt = "DELETE FROM ` " . $ syslogdb_default . "`. $ from_table
1053- WHERE message LIKE '% " . $ remove ['message ' ] . " %' " ;
1098+ WHERE message LIKE " . db_qstr ( ' % ' . $ remove ['message ' ] . ' % ' ) ;
10541099 }
10551100 } elseif ($ remove ['type ' ] == 'messagee ' ) {
10561101 if ($ remove ['method ' ] != 'del ' ) {
10571102 $ sql_sel = "SELECT seq FROM ` " . $ syslogdb_default . "`. $ from_table
1058- WHERE message LIKE '% " . $ remove ['message ' ] . " ' " ;
1103+ WHERE message LIKE " . db_qstr ( ' % ' . $ remove ['message ' ]) ;
10591104 } else {
10601105 $ sql_dlt = "DELETE FROM ` " . $ syslogdb_default . "`. $ from_table
1061- WHERE message LIKE '% " . $ remove ['message ' ] . " ' " ;
1106+ WHERE message LIKE " . db_qstr ( ' % ' . $ remove ['message ' ]) ;
10621107 }
10631108 } elseif ($ remove ['type ' ] == 'sql ' ) {
10641109 if ($ remove ['method ' ] != 'del ' ) {
@@ -1576,73 +1621,10 @@ function syslog_process_alert($alert, $sql, $params, $count, $hostname = '') {
15761621
15771622 alert_setup_environment ($ alert , $ results , $ hostlist , $ hostname );
15781623
1579- /**
1580- * Open a ticket if this options have been selected.
1581- */
1582- $ command = read_config_option ('syslog_ticket_command ' );
1624+ syslog_execute_ticket_command ($ alert , $ hostlist , 'Ticket Command ' );
15831625
1584- if ($ command != '' ) {
1585- $ command = trim ($ command );
1586- }
1587-
1588- if ($ alert ['open_ticket ' ] == 'on ' && $ command != '' ) {
1589- $ executable = $ command ;
1590- $ firstChar = substr ($ executable , 0 , 1 );
1591-
1592- if ($ firstChar === '" ' || $ firstChar === "' " ) {
1593- $ closing = strpos ($ executable , $ firstChar , 1 );
1594-
1595- if ($ closing !== false ) {
1596- $ executable = substr ($ executable , 1 , $ closing - 1 );
1597- } else {
1598- $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1599- }
1600- } else {
1601- $ parts = preg_split ('/\s+/ ' , $ executable );
1602-
1603- if (is_array ($ parts ) && isset ($ parts [0 ])) {
1604- $ executable = $ parts [0 ];
1605- }
1606-
1607- $ executable = trim ($ executable , " \t\n\r\0\x0B\"' " );
1608- }
1609-
1610- if ($ executable !== '' && is_executable ($ executable )) {
1611- $ command = $ command .
1612- ' --alert-name= ' . cacti_escapeshellarg (clean_up_name ($ alert ['name ' ])) .
1613- ' --severity= ' . cacti_escapeshellarg ($ alert ['severity ' ]) .
1614- ' --hostlist= ' . cacti_escapeshellarg (implode (', ' ,$ hostlist )) .
1615- ' --message= ' . cacti_escapeshellarg ($ alert ['message ' ]);
1616-
1617- $ output = array ();
1618- $ return = 0 ;
1619-
1620- exec ($ command , $ output , $ return );
1621-
1622- if ($ return != 0 ) {
1623- cacti_log (sprintf ('ERROR: Ticket Command Failed. Alert:%s, Exit:%s, Output:%s ' , $ alert ['name ' ], $ return , implode (', ' , $ output )), false , 'SYSLOG ' );
1624- }
1625- }
1626- }
1627-
1628- if (trim ($ alert ['command ' ]) != '' && !$ found ) {
1629- $ command = alert_replace_variables ($ alert , $ results , $ hostname );
1630-
1631- $ logMessage = "SYSLOG NOTICE: Executing ' $ command' " ;
1632-
1633- $ cparts = explode (' ' , $ command );
1634-
1635- if (is_executable ($ cparts [0 ])) {
1636- exec ($ command , $ output , $ returnCode );
1637- } else {
1638- exec ('/bin/sh ' . $ command , $ output , $ returnCode );
1639- }
1640-
1641- // Append the return code to the log message without the dot
1642- $ logMessage .= " Command return code: $ returnCode " ;
1643-
1644- // Log the combined message
1645- cacti_log ($ logMessage , true , 'SYSTEM ' );
1626+ if (!$ found ) {
1627+ syslog_execute_alert_command ($ alert , $ results , $ hostname );
16461628 }
16471629
16481630 }
@@ -1660,49 +1642,10 @@ function syslog_process_alert($alert, $sql, $params, $count, $hostname = '') {
16601642
16611643 alert_setup_environment ($ alert , $ results , $ hostlist , $ hostname );
16621644
1663- $ command = read_config_option ( ' syslog_ticket_command ' );
1645+ syslog_execute_ticket_command ( $ alert , $ hostlist , ' Command ' );
16641646
1665- if ($ command != '' ) {
1666- $ command = trim ($ command );
1667- }
1668-
1669- if ($ alert ['open_ticket ' ] == 'on ' && $ command != '' ) {
1670- if (is_executable ($ command )) {
1671- $ command = $ command .
1672- ' --alert-name= ' . cacti_escapeshellarg (clean_up_name ($ alert ['name ' ])) .
1673- ' --severity= ' . cacti_escapeshellarg ($ alert ['severity ' ]) .
1674- ' --hostlist= ' . cacti_escapeshellarg (implode (', ' ,$ hostlist )) .
1675- ' --message= ' . cacti_escapeshellarg ($ alert ['message ' ]);
1676-
1677- $ output = array ();
1678- $ return = 0 ;
1679-
1680- exec ($ command , $ output , $ return );
1681-
1682- if ($ return != 0 ) {
1683- cacti_log (sprintf ('ERROR: Command Failed. Alert:%s, Exit:%s, Output:%s ' , $ alert ['name ' ], $ return , implode (', ' , $ output )), false , 'SYSLOG ' );
1684- }
1685- }
1686- }
1687-
1688- if (trim ($ alert ['command ' ]) != '' && !$ found ) {
1689- $ command = alert_replace_variables ($ alert , $ results , $ hostname );
1690-
1691- $ logMessage = "SYSLOG NOTICE: Executing ' $ command' " ;
1692-
1693- $ cparts = explode (' ' , $ command );
1694-
1695- if (is_executable ($ cparts [0 ])) {
1696- exec ($ command , $ output , $ returnCode );
1697- } else {
1698- exec ('/bin/sh ' . $ command , $ output , $ returnCode );
1699- }
1700-
1701- // Append the return code to the log message without the dot
1702- $ logMessage .= " Command return code: $ returnCode " ;
1703-
1704- // Log the combined message
1705- cacti_log ($ logMessage , true , 'SYSTEM ' );
1647+ if (!$ found ) {
1648+ syslog_execute_alert_command ($ alert , $ results , $ hostname );
17061649 }
17071650 }
17081651 }
@@ -2505,6 +2448,92 @@ function alert_setup_environment(&$alert, $results, $hostlist = array(), $hostna
25052448 putenv ('ALERT_MESSAGES= ' . cacti_escapeshellarg (trim (str_replace ("\0" , ' ' , $ results ['message ' ]))));
25062449}
25072450
2451+ /**
2452+ * syslog_execute_ticket_command - Execute the configured ticket command for an alert
2453+ *
2454+ * @param array $alert The alert definition
2455+ * @param array $hostlist The list of affected hosts
2456+ * @param string $context Logging context label
2457+ *
2458+ * @return void
2459+ */
2460+ function syslog_execute_ticket_command ($ alert , $ hostlist , $ context ) {
2461+ $ command = read_config_option ('syslog_ticket_command ' );
2462+
2463+ if ($ command != '' ) {
2464+ $ command = trim ($ command );
2465+ }
2466+
2467+ if ($ alert ['open_ticket ' ] == 'on ' && $ command != '' ) {
2468+ $ cparts = preg_split ('/\s+/ ' , trim ($ command ));
2469+ $ executable = trim ($ cparts [0 ], '" \'' );
2470+
2471+ if ($ executable === '' || strpos ($ executable , DIRECTORY_SEPARATOR ) === false ) {
2472+ cacti_log (sprintf ('SYSLOG ERROR: %s executable not found or not an absolute path. Alert:%s, Command:%s ' , $ context , $ alert ['name ' ], $ executable ), false , 'SYSLOG ' );
2473+ return ;
2474+ }
2475+
2476+ if (is_executable ($ executable )) {
2477+ $ command = cacti_escapeshellarg ($ executable ) .
2478+ ' --alert-name= ' . cacti_escapeshellarg (clean_up_name ($ alert ['name ' ])) .
2479+ ' --severity= ' . cacti_escapeshellarg ($ alert ['severity ' ]) .
2480+ ' --hostlist= ' . cacti_escapeshellarg (implode (', ' , $ hostlist )) .
2481+ ' --message= ' . cacti_escapeshellarg ($ alert ['message ' ]);
2482+
2483+ $ output = array ();
2484+ $ return = 0 ;
2485+
2486+ exec ($ command , $ output , $ return );
2487+
2488+ if ($ return != 0 ) {
2489+ cacti_log (sprintf ('ERROR: %s Failed. Alert:%s, Exit:%s, Output:%s ' , $ context , $ alert ['name ' ], $ return , implode (', ' , $ output )), false , 'SYSLOG ' );
2490+ }
2491+ } else {
2492+ cacti_log (sprintf ('SYSLOG ERROR: %s is not executable. Alert:%s, Command:%s ' , $ context , $ alert ['name ' ], $ executable ), false , 'SYSLOG ' );
2493+ }
2494+ }
2495+ }
2496+
2497+ /**
2498+ * syslog_execute_alert_command - Execute the alert-specific command
2499+ *
2500+ * @param array $alert The alert definition
2501+ * @param array $results The syslog result set
2502+ * @param string $hostname The hostname for host-level alerts
2503+ *
2504+ * @return void
2505+ */
2506+ function syslog_execute_alert_command ($ alert , $ results , $ hostname ) {
2507+ if (trim ($ alert ['command ' ]) == '' ) {
2508+ return ;
2509+ }
2510+
2511+ $ cparts = preg_split ('/\s+/ ' , trim ($ alert ['command ' ]));
2512+ $ executable = trim ($ cparts [0 ], '" \'' );
2513+
2514+ if ($ executable === '' || strpos ($ executable , DIRECTORY_SEPARATOR ) === false ) {
2515+ cacti_log (sprintf ('SYSLOG ERROR: Alert command executable not found or not an absolute path. Alert:%s, Command:%s ' , $ alert ['name ' ], $ executable ), false , 'SYSLOG ' );
2516+ return ;
2517+ }
2518+
2519+ if (is_executable ($ executable )) {
2520+ $ command = alert_replace_variables ($ alert , $ results , $ hostname );
2521+
2522+ $ logMessage = "SYSLOG NOTICE: Executing ' $ command' " ;
2523+
2524+ $ output = array ();
2525+ $ returnCode = 0 ;
2526+
2527+ exec ($ command , $ output , $ returnCode );
2528+
2529+ $ logMessage .= " Command return code: $ returnCode " ;
2530+
2531+ cacti_log ($ logMessage , true , 'SYSTEM ' );
2532+ } else {
2533+ cacti_log (sprintf ('SYSLOG ERROR: Alert command is not executable. Alert:%s, Command:%s ' , $ alert ['name ' ], $ executable ), false , 'SYSLOG ' );
2534+ }
2535+ }
2536+
25082537/**
25092538 * alert_replace_variables - add command line parameter to the syslog command
25102539 * or ticket opening script
@@ -2520,6 +2549,12 @@ function alert_replace_variables($alert, $results, $hostname = '') {
25202549
25212550 $ command = $ alert ['command ' ];
25222551
2552+ /* Escape the executable so the full command passed to exec() is safe */
2553+ $ cparts = preg_split ('/\s+/ ' , trim ($ command ), 2 );
2554+ $ executable = trim ($ cparts [0 ], '" \'' );
2555+ $ args = isset ($ cparts [1 ]) ? ' ' . $ cparts [1 ] : '' ;
2556+ $ command = cacti_escapeshellarg ($ executable ) . $ args ;
2557+
25232558 $ command = str_replace ('<ALERTID> ' , cacti_escapeshellarg ($ alert ['id ' ]), $ command );
25242559 $ command = str_replace ('<HOSTNAME> ' , cacti_escapeshellarg ($ hostname ), $ command );
25252560 $ command = str_replace ('<PRIORITY> ' , cacti_escapeshellarg ($ syslog_levels [$ results ['priority_id ' ]]), $ command );
0 commit comments