Ryan Prather
7f2f6a9046
Some formatting Die if installer.php fails to create password file Update target counts after importing eChecklist and CKL
12671 lines
429 KiB
PHP
12671 lines
429 KiB
PHP
<?php
|
|
/**
|
|
* File: database.inc
|
|
* Author: Ryan Prather
|
|
* Purpose: This file will contain all the variables and functions to operate a database
|
|
* and for the ST&E Manager to interact with
|
|
* Created: Sep 11, 2013
|
|
*
|
|
* Portions Copyright 2016-2018: Cyber Perspectives, LLC, All rights reserved
|
|
* Released under the Apache v2.0 License
|
|
*
|
|
* Portions Copyright (c) 2012-2015, Salient Federal Solutions
|
|
* Portions Copyright (c) 2008-2011, Science Applications International Corporation (SAIC)
|
|
* Released under Modified BSD License
|
|
*
|
|
* See license.txt for details
|
|
*
|
|
* Change Log:
|
|
* - Sep 11, 2013 - File created
|
|
* - Sep 1, 2016 - Copyright Updated, way to many updates to list
|
|
* - Oct 24, 2016 - Updated delete_Scan function to check for return of scan array
|
|
* Changed SQL updating host list to REPLACE instead (fixes updating the finding count)
|
|
* Added get_Running_Script_Status function to return the status of the script
|
|
* Added is_Connected function to check the status of the DB connection (and reconnect if there are issues)
|
|
* Updated tcp/udp_port variable to use functions instead
|
|
* - Nov 7, 2016 - Several changes when getting and saving tcp/udp port data
|
|
* - Nov 16, 2016 - Changed error for failed DB connect to include attempted server
|
|
* - Jan 30, 2017 - Formatting
|
|
* - Jan 31, 2017 - Cleaned up db_helper functionality
|
|
* - Feb 15, 2017 - Started process to migrate some query to be created with the db_helper class and fixed a couple bugs
|
|
* - Mar 3, 2017 - Added IS and NOT_LIKE defined constants, added check if ` or AS is present, then not adding a `,
|
|
* Documentation, Fixed error in db_helper::order method, Started converting db class methods to use db_helper
|
|
* - Mar 8, 2017 - Converted a couple more queries to use db_helper object and formatting
|
|
* - Mar 13, 2017 - Fixed bugs with db_helper::where functions and added fields function
|
|
* - Mar 14, 2017 - Fixed bug in db::get_Software method
|
|
* - Mar 20, 2017 - Updated CCE and CCI methods to use db_helper object
|
|
* - Mar 22, 2017 - Updated get_Nessus save_Nessus method to use db_helper object,
|
|
* Fixed bug in db_helper::debug and db::get_Checklist
|
|
* - Apr 5, 2017 - Converted a few other methods to use db_helper class, switch positions for parameters in db::save_Target method,
|
|
* Added documentation in a few places, fixed bug with Nessus parsing
|
|
* - Apr 7, 2017 - Replaced function get_STE_Category_List with get_STE_Cat_List (and updated required files),
|
|
* Converted more methods to use db_helper, fixed a couple typos (add_Source -> add_Sources),
|
|
* Changed save_Target to save the short_sw_string as the os_string instead
|
|
* - Apr 10, 2017 - More db_helper conversions and bug fixes
|
|
* - May 13, 2017 - Always lots of changes here
|
|
* Added get_Checklist_By_Filename method
|
|
* Converted get_Category_Checklists function to use db_helper class
|
|
* Converted save_SV_Rule method to use db_helper class
|
|
* Converted over a few other methods to use db_helper class
|
|
* - May 19, 2017 - Converted over more methods to use db_helper class
|
|
* Fixed typo, added deleting category interview data when deleting category
|
|
* - May 22, 2017 - Simplified get_ScanData function to not retrieve all data for target host lists (took too much time)
|
|
* Converted save_IA_Controls method to use db_helper class
|
|
* - May 25, 2017 - Added 'start' flag to db_helper::flags method to start at a different record (supporting paging in DataTables library)
|
|
* Converted over a couple methods to use db_helper class
|
|
* - Jun 27, 2017 - Set default target classification if not present, fixed bug #264
|
|
* - Jul 13, 2017 - Revised several method to use db_helper class and removed db::add_PDI method and moved to just using save_PDI method
|
|
* - Jul 21, 2017 - Cleaned up port saving in save_Interface method
|
|
* - Jul 24, 2017 - Added save_EMASS_CCIs() and get_EMASS_CCIs() to create and retrieve the rmf.emass_cci table
|
|
* - Aug 28, 2017 - Fixed typo w/cve_reference table #276
|
|
* - Aug 28, 2017 - Added delete_Target_Software, fixed error when deleting all software or checklists (wouldn't save correctly), and cleaned up delete_Target method
|
|
* - Oct 26, 2017 - Formatting and bug fix for #326
|
|
* - Oct 27, 2017 - Change filtering for get_ports, added delete_Interface method
|
|
* - Dec 27, 2017 - Migrate methods to use db_helper and syntax updates
|
|
* - Jan 1, 2018 - Added get_Software_Id method that gets all the software IDs from a list of CPEs
|
|
* - Jan 10, 2018 - Added a couple functions and formatting
|
|
* - Jan 15, 2018 - Fixed bug in get_Category_Findings
|
|
* - Jan 16, 2018 - Added include for host_list.inc, updated to use host_list class, fixed bug in delete_Scan method
|
|
Moved scan deletion here
|
|
* - Jan 20, 2018 - Fixed typo in save_STE method
|
|
* - May 24, 2018 - Added defaulting where clause operator to '='
|
|
* - May 26, 2018 - Updated autocategorization to removed any extranious spaces before or after the string
|
|
* - May 31, 2018 - Changes to support renaming sagacity.pdi_catalog.check_content field and scan error detection
|
|
* - Jun 2, 2018 - Formatting and added set_Setting_Array method
|
|
* - Jun 5, 2018 - Changed set_Setting_Array method to use SQL update instead of replace
|
|
* - Sep 5, 2018 - Fix for #8
|
|
*/
|
|
include_once 'base.inc';
|
|
include_once 'software.inc';
|
|
include_once 'checklist.inc';
|
|
include_once 'ste.inc';
|
|
include_once 'target.inc';
|
|
include_once 'scan.inc';
|
|
include_once 'pdi_catalog.inc';
|
|
include_once 'port.inc';
|
|
include_once 'sites.inc';
|
|
include_once 'sources.inc';
|
|
include_once 'ste_cat.inc';
|
|
include_once 'system.inc';
|
|
include_once 'interfaces.inc';
|
|
include_once 'script.inc';
|
|
include_once 'stigs.inc';
|
|
include_once 'golddisk.inc';
|
|
include_once 'finding.inc';
|
|
include_once 'ia_control.inc';
|
|
include_once 'retina.inc';
|
|
include_once 'sv_rule.inc';
|
|
include_once 'nessus.inc';
|
|
include_once 'echecklist.inc';
|
|
include_once 'cve.inc';
|
|
include_once 'advisories.inc';
|
|
include_once 'iavm.inc';
|
|
include_once 'oval.inc';
|
|
include_once 'cce.inc';
|
|
include_once 'proc_ia_controls.inc';
|
|
include_once 'error.inc';
|
|
include_once 'question.inc';
|
|
include_once 'cci.inc';
|
|
include_once 'rmf_control.inc';
|
|
include_once 'cpe.inc';
|
|
include_once 'nasl.inc';
|
|
include_once 'uuid.inc';
|
|
include_once 'host_list.inc';
|
|
|
|
// @TODO - Make sure all save functions accept a class object or array of that class that is being saved. Otherwise, only primative types will be passed in.
|
|
/**
|
|
* Constant to decide if the database queries will run automatically after creating them
|
|
*
|
|
* @var boolean
|
|
*/
|
|
define('AUTORUN', false);
|
|
|
|
/**
|
|
* Global to represent an IN statement (e.g. WHERE field IN (1,2))
|
|
*
|
|
* @var int
|
|
*/
|
|
define('IN', 1);
|
|
|
|
/**
|
|
* Global to represent a NOT IN statement (e.g. WHERE field NOT IN (1,2))
|
|
*
|
|
* @var int
|
|
*/
|
|
define('NOT_IN', 64);
|
|
|
|
/**
|
|
* Global to represent a BETWEEN statement (e.g. WHERE field BETWEEN 1 and 2)
|
|
*
|
|
* @var int
|
|
*/
|
|
define('BETWEEN', 2);
|
|
|
|
/**
|
|
* Global to represent a LIKE statement (e.g. WHERE field LIKE '%value%')
|
|
*
|
|
* @var int
|
|
*/
|
|
define('LIKE', 4);
|
|
|
|
/**
|
|
* Global to represent an IS NOT statement (e.g. WHERE field IS NOT NULL)
|
|
*
|
|
* @var int
|
|
*/
|
|
define('IS_NOT', 8);
|
|
|
|
/**
|
|
* Global to represent an IS statement (e.g. WHERE field IS NULL)
|
|
*
|
|
* @var int
|
|
*/
|
|
define('IS', 16);
|
|
|
|
/**
|
|
* Global to represent an NOT LIKE statement (e.g. WHERE field NOT LIKE '%value%'
|
|
*
|
|
* @var int
|
|
*/
|
|
define('NOT_LIKE', 32);
|
|
|
|
/**
|
|
* Class to help the database
|
|
*
|
|
* @author Ryan Prather
|
|
*/
|
|
class db_helper
|
|
{
|
|
|
|
const SELECT = 1;
|
|
const SELECT_COUNT = 2;
|
|
const CREATE_TABLE = 3;
|
|
const DROP = 4;
|
|
const DELETE = 5;
|
|
const INSERT = 6;
|
|
const REPLACE = 7;
|
|
const UPDATE = 8;
|
|
const EXTENDED_INSERT = 9;
|
|
const EXTENDED_REPLACE = 10;
|
|
const EXTENDED_UPDATE = 11;
|
|
const ALTER_TABLE = 12;
|
|
const TRUNCATE = 13;
|
|
|
|
/**
|
|
* The mysqli connection
|
|
*
|
|
* @var mysqli
|
|
*/
|
|
public $c;
|
|
|
|
/**
|
|
* To store the SQL statement
|
|
*
|
|
* @var string
|
|
*/
|
|
public $sql = null;
|
|
|
|
/**
|
|
* A string to store the type of query that is being run
|
|
*
|
|
* @var string
|
|
*/
|
|
public $query_type = null;
|
|
|
|
/**
|
|
* The result of the query
|
|
*
|
|
* @var mixed
|
|
*/
|
|
private $result = null;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param mysqli $dbh [by ref]
|
|
* mysqli object to perform queries.
|
|
*/
|
|
public function __construct(&$dbh)
|
|
{
|
|
if (!is_null($dbh) && is_a($dbh, "mysqli")) {
|
|
$this->c = $dbh;
|
|
}
|
|
else {
|
|
throw(new Exception("Could not create database helper class", E_ERROR));
|
|
}
|
|
|
|
$this->c->real_query("SET time_zone='+00:00'");
|
|
$this->c->real_query("SET sql_mode=''");
|
|
}
|
|
|
|
/**
|
|
* Function to execute the statement
|
|
*
|
|
* @param mixed $return [optional]
|
|
* MYSQLI constant to control what is returned from the mysqli_result object
|
|
* @param string $sql [optional]
|
|
* Optional SQL query
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function execute($return = MYSQLI_ASSOC, $sql = null)
|
|
{
|
|
if (!is_null($sql)) {
|
|
$this->sql = $sql;
|
|
}
|
|
|
|
if (is_a($this->c, 'mysqli')) {
|
|
if (!$this->c->ping()) {
|
|
$this->c = null;
|
|
$this->c = new mysqli(DB_SERVER, 'web', db::decrypt_pwd(), 'sagacity');
|
|
}
|
|
}
|
|
else {
|
|
throw(new Exception('Database was not connected', E_ERROR));
|
|
}
|
|
|
|
try {
|
|
if (in_array($this->query_type, [self::SELECT, self::SELECT_COUNT])) {
|
|
$this->result = $this->c->query($this->sql);
|
|
if ($this->c->error) {
|
|
$this->debug(E_ERROR);
|
|
}
|
|
}
|
|
elseif ($this->query_type == self::DELETE) {
|
|
$this->c->real_query($this->sql);
|
|
if ($this->c->error) {
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
$this->c->real_query($this->sql);
|
|
if ($this->c->error) {
|
|
$this->debug(E_ERROR, $this->c->error);
|
|
}
|
|
}
|
|
|
|
$this->result = $this->check_results($return);
|
|
}
|
|
catch (Exception $e) {
|
|
die($e->getTraceAsString());
|
|
}
|
|
|
|
return $this->result;
|
|
}
|
|
|
|
/**
|
|
* Function to check the results and return what is expected
|
|
*
|
|
* @param mixed $return_type [optional]
|
|
* Optional return mysqli_result return type
|
|
*
|
|
* @return mixed
|
|
*/
|
|
function check_results($return_type = MYSQLI_ASSOC)
|
|
{
|
|
$res = null;
|
|
|
|
if ($this->c->error) {
|
|
$this->debug(E_ERROR);
|
|
}
|
|
elseif (LOG_LEVEL == E_DEBUG) {
|
|
$this->debug(E_DEBUG);
|
|
}
|
|
|
|
switch ($this->query_type) {
|
|
case self::SELECT_COUNT:
|
|
if (!is_a($this->result, 'mysqli_result')) {
|
|
$this->debug(E_ERROR);
|
|
}
|
|
|
|
if ($this->result->num_rows == 1) {
|
|
$res = $this->result->fetch_assoc()['count'];
|
|
}
|
|
elseif ($this->result->num_rows > 1) {
|
|
$res = $this->result->num_rows;
|
|
}
|
|
|
|
mysqli_free_result($this->result);
|
|
|
|
return $res;
|
|
case self::SELECT:
|
|
if (!is_a($this->result, 'mysqli_result')) {
|
|
$this->debug(E_ERROR);
|
|
}
|
|
|
|
if ($this->result->num_rows == 1) {
|
|
$res = $this->result->fetch_array($return_type);
|
|
}
|
|
elseif ($this->result->num_rows > 1) {
|
|
$res = $this->fetch_all($return_type);
|
|
}
|
|
|
|
mysqli_free_result($this->result);
|
|
|
|
return $res;
|
|
case self::INSERT:
|
|
if ($this->c->error) {
|
|
$this->debug(E_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
if ($this->c->insert_id) {
|
|
return $this->c->insert_id;
|
|
}
|
|
elseif ($this->c->affected_rows) {
|
|
return $this->c->affected_rows;
|
|
}
|
|
|
|
return 1;
|
|
case self::EXTENDED_INSERT:
|
|
case self::EXTENDED_REPLACE:
|
|
case self::EXTENDED_UPDATE:
|
|
case self::REPLACE:
|
|
case self::UPDATE:
|
|
case self::DELETE:
|
|
case self::ALTER_TABLE:
|
|
if ($this->c->error && $this->c->errno == 1060) {
|
|
return ($this->c->affected_rows ? $this->c->affected_rows : true);
|
|
}
|
|
elseif ($this->c->error) {
|
|
$this->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
elseif ($this->c->affected_rows) {
|
|
return $this->c->affected_rows;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
case self::CREATE_TABLE:
|
|
case self::DROP:
|
|
case self::TRUNCATE:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to pass through calling the query function (used for backwards compatibility and for more complex queries that aren't currently supported)
|
|
*
|
|
* @param string $sql [optional]
|
|
* Optional query to pass in and execute
|
|
*
|
|
* @return mysqli_result
|
|
*/
|
|
public function query($sql = null)
|
|
{
|
|
if (is_null($sql)) {
|
|
return $this->c->query($this->sql);
|
|
}
|
|
else {
|
|
return $this->c->query($sql);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A function to build a select query
|
|
*
|
|
* @param string $table_name
|
|
* The table to query
|
|
* @param array $fields [optional]
|
|
* Optional array of fields to return (defaults to '*')
|
|
* @param array $where [optional]
|
|
* Optional 2-dimensional array to build where clause from
|
|
* @param array $flags [optional]
|
|
* Optional 2-dimensional array to allow other flags
|
|
*
|
|
* @see db_helper::where()
|
|
* @see db_helper::flags()
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function select($table_name, $fields = null, $where = null, $flags = null)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::SELECT;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "SELECT " . $this->fields($fields) . " FROM $table_name";
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
|
|
if (isset($flags['table_joins']) && is_array($flags['table_joins'])) {
|
|
$this->sql .= " " . implode(" ", $flags['table_joins']);
|
|
}
|
|
|
|
if (!is_null($where) && is_array($where) && count($where)) {
|
|
$this->sql .= $this->where($where);
|
|
}
|
|
|
|
if (!is_null($flags) && is_array($flags) && count($flags)) {
|
|
$this->sql .= $this->flags($flags);
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build a query to check the number of rows in a table
|
|
*
|
|
* @param string $table_name
|
|
* The table to query
|
|
* @param array $where [optional]
|
|
* Optional 2-dimensional array to build where clause
|
|
* @param array $flags [optional]
|
|
* Optional 2-dimensional array to add flags
|
|
*
|
|
* @see db_helper::where()
|
|
* @see db_helper::flags()
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function select_count($table_name, $where = null, $flags = null)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::SELECT_COUNT;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "SELECT COUNT(1) AS 'count' FROM $table_name";
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
|
|
if (isset($flags['table_joins']) && is_array($flags['table_joins'])) {
|
|
$this->sql .= " " . implode(" ", $flags['table_joins']);
|
|
}
|
|
|
|
if (!is_null($where) && is_array($where) && count($where)) {
|
|
$this->sql .= $this->where($where);
|
|
}
|
|
|
|
if (!is_null($flags) && is_array($flags) && count($flags)) {
|
|
$this->sql .= $this->flags($flags);
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build an insert query statement
|
|
*
|
|
* @param string $table_name
|
|
* Table name to query
|
|
* @param array $params
|
|
* Name/value pair to insert into the table
|
|
* @param boolean $to_ignore [optional]
|
|
* Optional boolean to decide if the "IGNORE" will be added
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function insert($table_name, $params, $to_ignore = false)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::INSERT;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "INSERT " . ($to_ignore ? "IGNORE " : "") . "INTO $table_name " .
|
|
"(`" . implode("`,`", array_keys($params)) . "`)";
|
|
}
|
|
|
|
$this->sql .= " VALUES (" . implode(",", array_map([$this, '_escape'], array_values($params))) . ")";
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to create an extended insert query statement
|
|
*
|
|
* @param string $table_name
|
|
* The table name that the data is going to be inserted on
|
|
* @param array $fields
|
|
* An array of field names that each value represents
|
|
* @param array $params
|
|
* An array of array of values
|
|
* @param boolean $to_ignore [optional]
|
|
* Boolean to decide if we need to use the INSERT IGNORE INTO syntax
|
|
*
|
|
* @return NULL|string
|
|
* Returns the SQL if AUTORUN is set to false, else it returns the output from running.
|
|
*/
|
|
public function extended_insert($table_name, $fields, $params, $to_ignore = false)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::EXTENDED_INSERT;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "INSERT " . ($to_ignore ? "IGNORE " : "") . "INTO $table_name " .
|
|
"(`" . implode("`,`", $fields) . "`)";
|
|
}
|
|
else {
|
|
throw(new Exception("Missing table name in extended_insert", E_ERROR));
|
|
}
|
|
|
|
if (is_array($params) && count($params)) {
|
|
$this->sql .= " VALUES ";
|
|
if (isset($params[0]) && is_array($params[0])) {
|
|
foreach ($params as $p) {
|
|
$this->sql .= "(" . implode(",", array_map([$this, '_escape'], array_values($p))) . "),";
|
|
}
|
|
}
|
|
else {
|
|
if (count($params) != count($fields)) {
|
|
throw(new Exception("Inconsistent number of fields in fields and values"));
|
|
}
|
|
$this->sql .= "(" . implode("),(", array_map([$this, '_escape'], array_values($params))) . "),";
|
|
}
|
|
}
|
|
else {
|
|
throw new \InvalidArgumentException("Expected array parameters");
|
|
}
|
|
|
|
$this->sql = substr($this->sql, 0, -1);
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Build a statement to update a table
|
|
*
|
|
* @param string $table_name
|
|
* The table name to update
|
|
* @param array $params
|
|
* Name/value pairs of the field name and value
|
|
* @param array $where [optional]
|
|
* Two-dimensional array to create where clause
|
|
* @param array $flags [optional]
|
|
* Two-dimensional array to create other flag options (table_joins, order, and group)
|
|
*
|
|
* @see db_helper::where()
|
|
* @see db_helper::flags()
|
|
*
|
|
* @return NULL|string
|
|
*/
|
|
public function update($table_name, $params, $where = null, $flags = null)
|
|
{
|
|
$this->sql = "UPDATE ";
|
|
$this->query_type = self::UPDATE;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql .= $table_name;
|
|
|
|
if (isset($flags['table_joins'])) {
|
|
$this->sql .= " " . implode(" ", $flags['table_joins']);
|
|
unset($flags['table_joins']);
|
|
}
|
|
|
|
$this->sql .= " SET ";
|
|
}
|
|
|
|
foreach ($params as $f => $p) {
|
|
if ((strpos($f, "`") === false) &&
|
|
(strpos($f, ".") === false) &&
|
|
(strpos($f, "*") === false) &&
|
|
(stripos($f, " as ") === false)) {
|
|
$f = "`{$f}`";
|
|
}
|
|
|
|
if (!is_null($p)) {
|
|
$this->sql .= "$f={$this->_escape($p)},";
|
|
}
|
|
else {
|
|
$this->sql .= "$f=NULL,";
|
|
}
|
|
}
|
|
|
|
$this->sql = substr($this->sql, 0, -1);
|
|
|
|
if (!is_null($where) && is_array($where) && count($where)) {
|
|
$this->sql .= $this->where($where);
|
|
}
|
|
|
|
if (!is_null($flags) && is_array($flags) && count($flags)) {
|
|
$this->sql .= $this->flags($flags);
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to offer an extended updated functionality by using two different tables.
|
|
*
|
|
* @param string $to_be_updated
|
|
* The table that you want to update (alias 'tbu' is automatically added)
|
|
* @param string $original
|
|
* The table with the data you want to overwrite to_be_updated table (alias 'o' is automatically added)
|
|
* @param string $using
|
|
* The common index value between them that will join the fields
|
|
* @param array|string $params
|
|
* If string only a single field is updated (tbu.$params = o.$params)
|
|
* If array each element in the array is a field to be updated (tbu.$param = o.$param)
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function extended_update($to_be_updated, $original, $using, $params)
|
|
{
|
|
$this->sql = "UPDATE ";
|
|
$this->query_type = self::EXTENDED_UPDATE;
|
|
|
|
if (!is_null($to_be_updated) && !is_null($original) && !is_null($using)) {
|
|
$this->sql .= "$to_be_updated tbu INNER JOIN $original o USING ($using) SET ";
|
|
}
|
|
|
|
if (is_array($params) && count($params)) {
|
|
foreach ($params as $param) {
|
|
$this->sql .= "tbu.$param = o.$param,";
|
|
}
|
|
$this->sql = substr($this->sql, 0, -1);
|
|
}
|
|
elseif (is_string($params)) {
|
|
$this->sql .= "tbu.$params = o.$params";
|
|
}
|
|
else {
|
|
throw(new Exception("Do not understand datatype of \$params", E_ERROR));
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQL_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build a replace query
|
|
*
|
|
* @param string $table_name
|
|
* The table to update
|
|
* @param array $params
|
|
* Name/value pair to insert
|
|
*
|
|
* @return NULL|string
|
|
*/
|
|
public function replace($table_name, $params)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::REPLACE;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "REPLACE INTO $table_name " .
|
|
"(`" . implode("`,`", array_keys($params)) . "`)";
|
|
}
|
|
|
|
$this->sql .= " VALUES (" . implode(",", array_map(array($this, '_escape'), array_values($params))) . ")";
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build an extended replace statement
|
|
*
|
|
* @param string $table_name
|
|
* Table name to update
|
|
* @param array $fields
|
|
* Array of fields
|
|
* @param array $params
|
|
* Two-dimensional array of values
|
|
*
|
|
* @return NULL|string
|
|
*/
|
|
public function extended_replace($table_name, $fields, $params)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::EXTENDED_REPLACE;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "REPLACE INTO $table_name " .
|
|
"(`" . implode("`,`", $fields) . "`)";
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
|
|
if (is_array($params) && count($params)) {
|
|
$this->sql .= " VALUES ";
|
|
foreach ($params as $p) {
|
|
$this->sql .= "(" . implode(",", array_map(array($this, '_escape'), array_values($p))) . "),";
|
|
}
|
|
}
|
|
|
|
$this->sql = substr($this->sql, 0, -1);
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build a delete statement
|
|
*
|
|
* @param string $table_name
|
|
* Table name to act on
|
|
* @param array $fields [optional]
|
|
* Optional list of fields to delete (used when including multiple tables)
|
|
* @param array $where [optional]
|
|
* Optional 2-dimensional array to build where clause from
|
|
* @param array $table_joins [optional]
|
|
* Optional 2-dimensional array to add other flags
|
|
*
|
|
* @see db_helper::where()
|
|
* @see db_helper::flags()
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function delete($table_name, $fields = null, $where = null, $table_joins = null)
|
|
{
|
|
$this->sql = "DELETE";
|
|
$this->query_type = self::DELETE;
|
|
|
|
if (!is_null($fields) && is_array($fields)) {
|
|
$this->sql .= " " . implode(",", $fields);
|
|
}
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql .= " FROM $table_name";
|
|
}
|
|
else {
|
|
throw(new Exception("Failed to create delete query, no table name"));
|
|
}
|
|
|
|
if (!is_null($table_joins) && is_array($table_joins) && count($table_joins)) {
|
|
$this->sql .= " " . implode(" ", $table_joins);
|
|
}
|
|
|
|
if (!is_null($where) && is_array($where) && count($where)) {
|
|
$this->sql .= $this->where($where);
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to build a drop table statement (automatically executes)
|
|
*
|
|
* @param string $schema
|
|
* Schema the table resides in
|
|
* @param string $table_name
|
|
* Table to drop
|
|
* @param boolean $is_tmp [optional]
|
|
* Optional boolean if this is a temporary table
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function drop($schema, $table_name, $is_tmp = false)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::DROP;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "DROP " . ($is_tmp ? "TEMPORARY " : "") . "TABLE IF EXISTS `$schema`.`$table_name`";
|
|
}
|
|
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
/**
|
|
* Function to build a truncate table statement (automatically executes)
|
|
*
|
|
* @param string $table_name
|
|
* Table to truncate
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function truncate($table_name)
|
|
{
|
|
$this->sql = null;
|
|
$this->query_type = self::TRUNCATE;
|
|
|
|
if (!is_null($table_name) && is_string($table_name)) {
|
|
$this->sql = "TRUNCATE TABLE $table_name";
|
|
}
|
|
|
|
return $this->execute(MYSQLI_BOTH);
|
|
}
|
|
|
|
/**
|
|
* Function to build a create temporary table statement
|
|
*
|
|
* @param string $table_name
|
|
* Name to give the table when creating
|
|
* @param boolean $is_tmp [optional]
|
|
* Optional boolean to make the table a temporary table
|
|
* @param mixed $select [optional]
|
|
* Optional parameter if null uses last built statement
|
|
* If string, will be made the SQL statement executed to create the table
|
|
* If array, 2-dimensional array with "field", "datatype" values to build table fields
|
|
*
|
|
* @return NULL|string
|
|
*/
|
|
public function create_table($table_name, $is_tmp = false, $select = null)
|
|
{
|
|
$this->query_type = self::CREATE_TABLE;
|
|
|
|
if (is_null($select) && !is_null($this->sql) && substr($this->sql, 0, 6) == 'SELECT') {
|
|
$this->sql = "CREATE " . ($is_tmp ? "TEMPORARY" : "") . " TABLE IF NOT EXISTS $table_name AS ($this->sql)";
|
|
}
|
|
if (!is_null($table_name) && is_string($table_name) && is_string($select)) {
|
|
$this->sql = "CREATE " . ($is_tmp ? "TEMPORARY" : "") . " TABLE IF NOT EXISTS $table_name AS ($select)";
|
|
}
|
|
elseif (!is_null($table_name) && is_string($table_name) && is_array($select)) {
|
|
$this->sql = "CREATE " . ($is_tmp ? "TEMPORARY" : "") . " TABLE IF NOT EXISTS $table_name (";
|
|
foreach ($select as $field) {
|
|
$this->sql .= "{$field['field']} {$field['datatype']}" .
|
|
(isset($field['default']) ? " {$field['default']}" : '') .
|
|
(isset($field['option']) ? " {$field['option']}" : '') . ",";
|
|
}
|
|
$this->sql = substr($this->sql, 0, -1) . ")";
|
|
}
|
|
|
|
if (AUTORUN) {
|
|
return $this->execute();
|
|
}
|
|
|
|
return $this->sql;
|
|
}
|
|
|
|
/**
|
|
* Function to create a table using a stdClass object derived from JSON
|
|
*
|
|
* @param stdClass $json
|
|
*/
|
|
public function create_table_json($json)
|
|
{
|
|
$this->query_type = self::CREATE_TABLE;
|
|
$this->c->select_db($json->schema);
|
|
|
|
$this->sql = "CREATE TABLE IF NOT EXISTS `{$json->name}` (";
|
|
foreach ($json->fields as $field) {
|
|
$this->sql .= "`{$field->name}` {$field->dataType}";
|
|
|
|
if ($field->dataType == 'enum') {
|
|
$this->sql .= "('" . implode("','", $field->values) . "')";
|
|
}
|
|
|
|
if ($field->ai) {
|
|
$this->sql .= " AUTO_INCREMENT";
|
|
}
|
|
|
|
if ($field->nn) {
|
|
$this->sql .= " NOT NULL";
|
|
}
|
|
else {
|
|
if ($field->default === null) {
|
|
$this->sql .= " DEFAULT NULL";
|
|
}
|
|
elseif (strlen($field->default)) {
|
|
$this->sql .= " DEFAULT '{$field->default}'";
|
|
}
|
|
}
|
|
|
|
if ($field != end($json->fields)) {
|
|
$this->sql .= ",";
|
|
}
|
|
}
|
|
|
|
if (isset($json->index) && is_array($json->index) && count($json->index)) {
|
|
foreach ($json->index as $ind) {
|
|
$this->sql .= ", " . strtoupper($ind->type) . " `{$ind->id}` (`{$ind->ref}`)";
|
|
}
|
|
}
|
|
|
|
if (isset($json->constraints) && is_array($json->constraints) && count($json->constraints)) {
|
|
foreach ($json->constraints as $con) {
|
|
$this->sql .= ", CONSTRAINT `{$con->id}` " .
|
|
"FOREIGN KEY (`{$con->local}`) " .
|
|
"REFERENCES `{$con->schema}`.`{$con->table}` (`{$con->field}`) " .
|
|
"ON DELETE " . (is_null($con->delete) ? "NO ACTION" : strtoupper($con->delete)) . " " .
|
|
"ON UPDATE " . (is_null($con->update) ? "NO ACTION" : strtoupper($con->update));
|
|
}
|
|
}
|
|
|
|
if (isset($json->unique) && is_array($json->unique) && count($json->unique)) {
|
|
$this->sql .= ", UNIQUE(`" . implode("`,`", $json->unique) . "`)";
|
|
}
|
|
|
|
if (isset($json->primary_key) && is_array($json->primary_key) && count($json->primary_key)) {
|
|
$this->sql .= ", PRIMARY KEY(`" . implode("`,`", $json->primary_key) . "`))";
|
|
}
|
|
else {
|
|
$this->sql = substr($this->sql, 0, -1) . ")";
|
|
}
|
|
|
|
$this->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to alter a existing table
|
|
*
|
|
* @param string $table_name
|
|
* Table to alter
|
|
* @param string $action
|
|
* What action should be taken ('add-column', 'drop-column', 'modify-column')
|
|
* @param array $params [optional]
|
|
* Optional 2-dimensional array of parameters to act on. $action will dictate what parameters need to be present
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function alter_table($table_name, $action, $params)
|
|
{
|
|
$this->query_type = self::ALTER_TABLE;
|
|
$this->sql = "ALTER TABLE $table_name ";
|
|
if ($action == 'add-column') {
|
|
$nn = ($params->nn ? " NOT NULL" : "");
|
|
$default = null;
|
|
if ($params->default === null) {
|
|
$default = " DEFAULT NULL";
|
|
}
|
|
elseif (strlen($params->default)) {
|
|
$default = " DEFAULT '{$params->default}'";
|
|
}
|
|
$this->sql .= "ADD COLUMN {$params->name} {$params->dataType}" .
|
|
$nn . $default;
|
|
}
|
|
elseif ($action == 'drop-column') {
|
|
$this->sql .= "DROP COLUMN ";
|
|
foreach ($params as $col) {
|
|
$this->sql .= "{$col['name']},";
|
|
}
|
|
$this->sql = substr($this->sql, 0, -1);
|
|
}
|
|
elseif ($action == 'modify-column') {
|
|
|
|
}
|
|
|
|
$this->debug(E_DEBUG);
|
|
|
|
return $this->execute();
|
|
}
|
|
|
|
/**
|
|
* Check to see if a field in a table exists
|
|
*
|
|
* @param string $schema
|
|
* Schema that contains tables
|
|
* @param string $table_name
|
|
* Table to check
|
|
* @param string $field_name
|
|
* Field name to find
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if field is found in that schema and table, otherwise FALSE
|
|
*/
|
|
public function field_exists($schema, $table_name, $field_name)
|
|
{
|
|
$this->c->select_db($schema);
|
|
|
|
$fdata = $this->field_data($schema, $table_name);
|
|
|
|
foreach ($fdata as $field) {
|
|
if ($field->name == $field_name) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to get the column data (datatype, flags, defaults, etc)
|
|
*
|
|
* @param string $schema
|
|
* Schema to search for table in
|
|
* @param string $table_name
|
|
* Table to query
|
|
* @param mixed $field [optional]
|
|
* Optional field to retrieve data (if null, returns data from all fields)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function field_data($schema, $table_name, $field = null)
|
|
{
|
|
$this->c->select_db($schema);
|
|
|
|
if (is_null($field)) {
|
|
$res = $this->c->query("SELECT * FROM $table_name LIMIT 1");
|
|
}
|
|
elseif (is_array($field)) {
|
|
$res = $this->c->query("SELECT `" . implode("`,`", $field) . "` FROM $table_name LIMIT 1");
|
|
}
|
|
elseif (is_string($field)) {
|
|
$res = $this->c->query("SELECT $field FROM $table_name LIMIT 1");
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
|
|
$fields = null;
|
|
if (is_a($res, 'mysqli_result')) {
|
|
$fields = $res->fetch_fields();
|
|
foreach ($fields as $i => $f) {
|
|
$fields["{$f->name}"] = $f;
|
|
unset($fields[$i]);
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Function to check that all field parameters are set correctly
|
|
*
|
|
* @param object $field_data
|
|
* @param object $check
|
|
* @param object $pks
|
|
* @param object $index
|
|
*
|
|
* @return array
|
|
*/
|
|
public function field_check($field_data, $check, $pks, $index)
|
|
{
|
|
$default = null;
|
|
$ret = null;
|
|
|
|
$nn = ($check->nn ? " NOT NULL" : null);
|
|
if ($check->default === null) {
|
|
$default = " DEFAULT NULL";
|
|
}
|
|
elseif (strlen($check->default)) {
|
|
$default = " DEFAULT '{$check->default}'";
|
|
}
|
|
|
|
if ($field_data->type != $check->type && $check->type != MYSQLI_TYPE_ENUM) {
|
|
$this->debug("{$field_data->name} wrong datatype, changing to {$check->dataType}");
|
|
$ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}" .
|
|
"{$nn}{$default}";
|
|
}
|
|
elseif (!is_null($check->length) && $field_data->length != $check->length) {
|
|
$this->debug("{$field_data->name} incorrect size ({$field_data->length} != {$check->length})");
|
|
$ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}" .
|
|
"{$nn}{$default}";
|
|
}
|
|
elseif ($check->type == MYSQLI_TYPE_ENUM && !($field_data->flags & MYSQLI_ENUM_FLAG)) {
|
|
$ret = " CHANGE COLUMN `{$field_data->name}` `{$check->name}` {$check->dataType}('" . implode("','", $check->values) . "')" .
|
|
"{$nn}{$default}";
|
|
}
|
|
|
|
if (!is_null($index) && is_array($index) && count($index)) {
|
|
foreach ($index as $ind) {
|
|
if ($check->name == $ind->ref && !($field_data->flags & MYSQLI_MULTIPLE_KEY_FLAG)) {
|
|
$this->debug("{$field_data->name} is not an index");
|
|
$ret .= ($ret ? "," : "") .
|
|
" ADD INDEX `{$ind->id}` (`{$ind->ref}` ASC)";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (in_array($check->name, $pks) && !($field_data->flags & MYSQLI_PRI_KEY_FLAG)) {
|
|
$ret .= ($ret ? "," : "") .
|
|
" DROP PRIMARY KEY, ADD PRIMARY KEY(`" . implode("`,`", $pks) . "`)";
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to check for the existence of a table within a schema
|
|
*
|
|
* @param string $schema
|
|
* Schema to search for table
|
|
* @param string $table_name
|
|
* Table to search for
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if table is found in that schema, otherwise FALSE
|
|
*/
|
|
public function table_exists($schema, $table_name)
|
|
{
|
|
$this->c->select_db($schema);
|
|
$res = $this->c->query("SHOW TABLES LIKE '$table_name'");
|
|
if ($res->num_rows > 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to detect if string is a JSON object or not
|
|
*
|
|
* @param string $val
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isJson($val)
|
|
{
|
|
json_decode($val);
|
|
return (json_last_error() == JSON_ERROR_NONE);
|
|
}
|
|
|
|
/**
|
|
* Function to escape SQL characters to prevent SQL injection
|
|
*
|
|
* @param mixed $val
|
|
* Value to escape
|
|
*
|
|
* @return string
|
|
* Escaped value
|
|
*/
|
|
public function _escape($val)
|
|
{
|
|
if (is_null($val)) {
|
|
return 'NULL';
|
|
}
|
|
elseif (is_numeric($val) || is_string($val)) {
|
|
if ($this->isJson($val)) {
|
|
return "'{$this->c->real_escape_string($val)}'";
|
|
}
|
|
elseif (strtolower($val) == 'now()') {
|
|
return $val;
|
|
}
|
|
elseif (preg_match("/\.`\w+`/", $val)) {
|
|
return $val;
|
|
}
|
|
return "'{$this->c->real_escape_string($val)}'";
|
|
}
|
|
elseif (is_a($val, 'DateTime')) {
|
|
return "'{$val->format(MYSQL_DT_FORMAT)}'";
|
|
}
|
|
elseif (is_bool($val)) {
|
|
return $val ? "'1'" : "'0'";
|
|
}
|
|
elseif (gettype($val) == 'object') {
|
|
$this->debug(E_ERROR, "Unknown object to escape " . get_class($val) . " in SQL string {$this->sql}");
|
|
}
|
|
else {
|
|
$this->debug(E_ERROR, "Unknown datatype to escape in SQL string {$this->sql} " . gettype($val));
|
|
}
|
|
|
|
throw(new Exception("Unknown datatype to escape in SQL string {$this->sql} " . gettype($val), E_ERROR));
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve all results
|
|
*
|
|
* @param string $resulttype
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function fetch_all($resulttype = MYSQLI_ASSOC)
|
|
{
|
|
$res = [];
|
|
if (method_exists('mysqli_result', 'fetch_all')) { # Compatibility layer with PHP < 5.3
|
|
$res = $this->result->fetch_all($resulttype);
|
|
}
|
|
else {
|
|
while ($tmp = $this->result->fetch_array($resulttype)) {
|
|
$res[] = $tmp;
|
|
}
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Function to debug the class
|
|
*
|
|
* @param int $errno
|
|
* @param string $errmsg
|
|
*/
|
|
public function debug($errno = E_NOTICE, $errmsg = null)
|
|
{
|
|
check_path(LOG_PATH . "/db.log");
|
|
check_path(LOG_PATH . "/db.err");
|
|
check_path(LOG_PATH . "/db.debug");
|
|
|
|
$err_lvl = 'NOTICE';
|
|
|
|
switch ($errno) {
|
|
case E_DEBUG:
|
|
$err_lvl = 'DEBUG';
|
|
break;
|
|
case E_WARNING:
|
|
$err_lvl = 'WARNING';
|
|
break;
|
|
case E_ERROR:
|
|
$err_lvl = 'FATAL ERROR';
|
|
break;
|
|
}
|
|
|
|
$dt = new DateTime();
|
|
|
|
if (is_null($errmsg)) {
|
|
$errmsg = $this->sql;
|
|
}
|
|
|
|
file_put_contents(realpath(LOG_PATH . '/db.log'), "{$dt->format(DATE_ISO8601)}\t" .
|
|
"$err_lvl\t" .
|
|
"Executing: $this->query_type\t" .
|
|
"SQL: {$errmsg}" . PHP_EOL, FILE_APPEND);
|
|
|
|
if ($errno == E_DEBUG && $this->result && LOG_LEVEL == E_DEBUG && is_a($this->result, 'mysqli_result')) {
|
|
file_put_contents(realpath(LOG_PATH . '/db.debug'), print_r($this->result, true), FILE_APPEND);
|
|
}
|
|
elseif ($errno == E_ERROR && $this->c->error) {
|
|
file_put_contents(realpath(LOG_PATH . '/db.err'), "{$dt->format(DATE_ISO8601)}\t" .
|
|
"{$this->c->error}" . PHP_EOL, FILE_APPEND);
|
|
error_log($this->c->error);
|
|
die($this->c->error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to populate the fields for the SQL
|
|
*
|
|
* @param array $fields [optional]
|
|
* Optional array of fields to string together to create a field list
|
|
*
|
|
* @return string
|
|
*/
|
|
public function fields($fields = null)
|
|
{
|
|
$str_fields = null;
|
|
|
|
if (is_array($fields) && count($fields)) {
|
|
foreach ($fields as $field) {
|
|
if ((strpos($field, '`') === false) &&
|
|
(strpos($field, '.') === false) &&
|
|
(strpos($field, '*') === false) &&
|
|
(stripos($field, ' as ') === false)) {
|
|
$str_fields .= "`$field`,";
|
|
}
|
|
else {
|
|
$str_fields .= "$field,";
|
|
}
|
|
}
|
|
$str_fields = substr($str_fields, 0, -1);
|
|
}
|
|
elseif (is_null($fields)) {
|
|
$str_fields = "*";
|
|
}
|
|
|
|
return $str_fields;
|
|
}
|
|
|
|
/**
|
|
* Function to create the where statement for the SQL
|
|
*
|
|
* @param array $where
|
|
* Two-dimensional array to use to build the where clause
|
|
*
|
|
* <code>
|
|
* array(<br />
|
|
* array(<br />
|
|
* 'field' => 'field_name',<br />
|
|
* 'op' => '=', // (common operations or IN, BETWEEN, LIKE, NOT_LIKE, IS, & IS_NOT constants)<br />
|
|
* 'value' => 'field_value',<br />
|
|
* 'sql_op' => 'AND', // NOT required for first element (common SQL operators AND, OR, NOR)<br />
|
|
* 'open-paren' => true, // optional to add a paren '(' BEFORE clause<br />
|
|
* 'close-paren' => true, // optional to add a paren ')' AFTER clause<br />
|
|
* 'low' => '1', // LOW value only used in BETWEEN clause<br />
|
|
* 'high' => '100', // HIGH value only used in BETWEEN clause<br />
|
|
* 'case_insensitive' => true // optional boolean to set the parameters to LOWER to do case insenstive comparison
|
|
* ),<br />
|
|
* array(<br />
|
|
* ...<br />
|
|
* ),<br />
|
|
* ...<br />
|
|
* )
|
|
* </code>
|
|
*
|
|
* @return string
|
|
*/
|
|
public function where($where)
|
|
{
|
|
$ret = " WHERE";
|
|
|
|
foreach ($where as $x => $w) {
|
|
if (!isset($w['field']) && isset($w['close-paren']) && $w['close-paren']) {
|
|
$ret .= ")";
|
|
continue;
|
|
}
|
|
elseif (!isset($w['field']) || ($x > 0 && !isset($w['sql_op']))) {
|
|
continue;
|
|
}
|
|
|
|
if ($x > 0) {
|
|
$ret .= " {$w['sql_op']}";
|
|
}
|
|
|
|
if (isset($w['open-paren']) && $w['open-paren']) {
|
|
$ret .= " (";
|
|
}
|
|
|
|
if ((strpos($w['field'], '`') === false) &&
|
|
(strpos($w['field'], '.') === false) &&
|
|
(strpos($w['field'], '*') === false) &&
|
|
(stripos($w['field'], ' as ') === false)) {
|
|
$field = "`{$w['field']}`";
|
|
}
|
|
else {
|
|
$field = $w['field'];
|
|
}
|
|
|
|
$not = null;
|
|
if (isset($w['op']) && in_array($w['op'], array(IS_NOT, NOT_LIKE, NOT_IN))) {
|
|
$not = ' NOT';
|
|
}
|
|
|
|
if (isset($w['op']) && ($w['op'] == LIKE || $w['op'] == NOT_LIKE)) {
|
|
$ret .= " {$field}{$not} LIKE {$w['value']}";
|
|
}
|
|
elseif (isset($w['op']) && ($w['op'] == IN || $w['op'] == NOT_IN) && is_string($w['value'])) {
|
|
$ret .= " {$field}{$not} IN " . (strpos($w['value'], '(') !== false ? $w['value'] : "({$w['value']})");
|
|
}
|
|
elseif (isset($w['op']) && ($w['op'] == IN || $w['op'] == NOT_IN) && is_array($w['value'])) {
|
|
$ret .= " {$field}{$not} IN (" . implode(",", array_map(array($this, '_escape'), $w['value'])) . ")";
|
|
}
|
|
elseif (isset($w['op']) && $w['op'] == BETWEEN) {
|
|
if (!isset($w['low']) && !isset($w['high'])) {
|
|
continue;
|
|
}
|
|
$ret .= " {$field} BETWEEN {$this->_escape($w['low'])} AND {$this->_escape($w['high'])}";
|
|
}
|
|
elseif (isset($w['op']) && ($w['op'] == IS || $w['op'] == IS_NOT)) {
|
|
$ret .= " {$field} IS{$not} {$this->_escape($w['value'])}";
|
|
}
|
|
else {
|
|
$op = "=";
|
|
if (isset($w['op'])) {
|
|
$op = $w['op'];
|
|
}
|
|
if (isset($w['case_insensitive']) && $w['case_insensitive']) {
|
|
$ret .= " LOWER({$field}) {$op} LOWER({$this->_escape($w['value'])})";
|
|
}
|
|
elseif (preg_match("/\(SELECT/", $w['value'])) {
|
|
$ret .= " {$field} {$op} {$w['value']}";
|
|
}
|
|
else {
|
|
$ret .= " {$field} {$op} {$this->_escape($w['value'])}";
|
|
}
|
|
}
|
|
|
|
if (isset($w['close-paren']) && $w['close-paren']) {
|
|
$ret .= ")";
|
|
}
|
|
}
|
|
if (strlen($ret) == 7) {
|
|
$ret = '';
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to parse the flags
|
|
*
|
|
* @param array $flags
|
|
* Two-dimensional array to added flags
|
|
*
|
|
* <code>
|
|
* array(
|
|
* 'table_joins' => array(
|
|
* "JOIN table2 t2 ON t2.id=t1.id"
|
|
* ),
|
|
* 'group' => 'field',
|
|
* 'having' => 'field',
|
|
* 'order' => 'field',
|
|
* 'start' => 0,
|
|
* 'limit' => 0
|
|
* )
|
|
* </code>
|
|
*
|
|
* @see db_helper::groups()
|
|
* @see db_helper::having()
|
|
* @see db_helper::order()
|
|
*
|
|
* @return string
|
|
*/
|
|
public function flags($flags)
|
|
{
|
|
$ret = '';
|
|
|
|
if (isset($flags['group'])) {
|
|
$ret .= $this->groups($flags['group']);
|
|
}
|
|
|
|
if (isset($flags['having']) && is_array($flags['having'])) {
|
|
$ret .= $this->having($flags['having']);
|
|
}
|
|
|
|
if (isset($flags['order'])) {
|
|
$ret .= $this->order($flags['order']);
|
|
}
|
|
|
|
if (isset($flags['limit']) && (is_string($flags['limit']) || is_numeric($flags['limit']))) {
|
|
$ret .= " LIMIT ";
|
|
if (isset($flags['start']) && (is_string($flags['start']) || is_numeric($flags['start']))) {
|
|
$ret .= "{$flags['start']},";
|
|
}
|
|
$ret .= "{$flags['limit']}";
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to parse SQL GROUP BY statements
|
|
*
|
|
* @param mixed $groups
|
|
*
|
|
* @return string
|
|
*/
|
|
private function groups($groups)
|
|
{
|
|
$ret = '';
|
|
if (is_array($groups)) {
|
|
$ret .= " GROUP BY";
|
|
|
|
foreach ($groups as $grp) {
|
|
$ret .= " $grp";
|
|
}
|
|
}
|
|
elseif (is_string($groups)) {
|
|
$ret .= " GROUP BY {$groups}";
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to parse SQL HAVING statements
|
|
*
|
|
* @param mixed $having
|
|
*
|
|
* return string
|
|
*/
|
|
private function having($having)
|
|
{
|
|
$ret = " HAVING";
|
|
$x = 0;
|
|
foreach ($having as $h) {
|
|
if (!isset($h['field']) || ($x > 0 && !isset($h['sql_op']))) {
|
|
continue;
|
|
}
|
|
|
|
if ($x > 0) {
|
|
$ret .= " {$h['sql_op']} ";
|
|
}
|
|
|
|
if ($h['op'] == LIKE) {
|
|
$ret .= " {$h['field']} LIKE {$h['value']}";
|
|
}
|
|
elseif ($h['op'] == IN && is_string($h['value'])) {
|
|
$ret .= " {$h['field']} IN {$h['value']}";
|
|
}
|
|
elseif ($h['op'] == IN && is_array($h['value'])) {
|
|
$ret .= " {$h['field']} IN ('" . implode("', '", $h['value']) . "')";
|
|
}
|
|
elseif ($h['op'] == BETWEEN) {
|
|
$ret .= " {$h['field']} BETWEEN {$this->_escape($h['low'])} AND {$this->_escape($h['high'])}";
|
|
}
|
|
elseif ($h['op'] == IS) {
|
|
$ret .= " {$h['field']} IS {$this->_escape($h['value'])}";
|
|
}
|
|
elseif ($h['op'] == IS_NOT) {
|
|
$ret .= " {$h['field']} IS NOT {$this->_escape($h['value'])}";
|
|
}
|
|
else {
|
|
$ret .= " {$h['field']} {$h['op']} {$this->_escape($h['value'])}";
|
|
}
|
|
|
|
$x++;
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to parse SQL ORDER BY statements
|
|
*
|
|
* @param mixed $order
|
|
*
|
|
* @return string
|
|
*/
|
|
private function order($order)
|
|
{
|
|
$ret = '';
|
|
if (is_array($order)) {
|
|
$ret .= " ORDER BY";
|
|
|
|
foreach ($order as $ord) {
|
|
$ret .= " {$ord['field']} {$ord['sort']},";
|
|
}
|
|
|
|
$ret = substr($ret, 0, -1);
|
|
}
|
|
elseif (is_string($order)) {
|
|
$ret .= " ORDER BY {$order}";
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public static function run()
|
|
{
|
|
$args = func_get_args();
|
|
$conn = null;
|
|
|
|
if (is_array($args) && count($args) < 2) {
|
|
return;
|
|
}
|
|
|
|
if (!is_a($args[0], "mysqli")) {
|
|
return;
|
|
}
|
|
else {
|
|
$conn = $args[0];
|
|
}
|
|
|
|
if (!is_string($args[1])) {
|
|
return;
|
|
}
|
|
else {
|
|
$sql = $args[1];
|
|
}
|
|
|
|
if (strpos($sql, "?") !== false) {
|
|
$x = 2;
|
|
while (strpos($sql, "?") !== false) {
|
|
$sql = str_replace_first("?", "'" . $conn->real_escape_string($args[$x]) . "'", $sql);
|
|
}
|
|
}
|
|
|
|
if (!$stmt = $conn->prepare($sql)) {
|
|
print $conn->error . PHP_EOL;
|
|
return;
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
print "Execution of prepared statement failed: (" . $stmt->errno . ") " . $stmt->error . PHP_EOL;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function
|
|
*
|
|
* @return void|mixed
|
|
*/
|
|
public static function selectrow_array()
|
|
{
|
|
$args = func_get_args();
|
|
$conn = null;
|
|
$ret = [];
|
|
|
|
if (is_array($args) && count($args) < 2) {
|
|
return;
|
|
}
|
|
|
|
if (!is_a($args[0], "mysqli")) {
|
|
return;
|
|
}
|
|
else {
|
|
$conn = $args[0];
|
|
}
|
|
|
|
if (!is_string($args[1])) {
|
|
return;
|
|
}
|
|
else {
|
|
$sql = $args[1];
|
|
}
|
|
|
|
if (strpos($sql, "?") !== false) {
|
|
$x = 2;
|
|
while (strpos($sql, "?") !== false) {
|
|
$sql = str_replace_first("?", "'" . $conn->real_escape_string($args[$x]) . "'", $sql);
|
|
}
|
|
}
|
|
|
|
if (!$stmt = $conn->prepare($sql)) {
|
|
print $conn->error . PHP_EOL;
|
|
return;
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
print "Execution of prepared statement failed: (" . $stmt->errno . ") " . $stmt->error . PHP_EOL;
|
|
return;
|
|
}
|
|
|
|
$meta = $stmt->result_metadata();
|
|
$fields = $fieldNames = [];
|
|
|
|
while ($field = $meta->fetch_field()) {
|
|
$fieldNames[] = $var = $field->name;
|
|
$$var = null;
|
|
$fields[$var] = &$$var;
|
|
}
|
|
|
|
$fieldCount = (is_array($fieldNames) ? count($fieldNames) : 0);
|
|
|
|
call_user_func_array(array($stmt, "bind_result"), $fields);
|
|
|
|
$i = 0;
|
|
while ($stmt->fetch()) {
|
|
for ($r = 0; $r < $fieldCount; $r++) {
|
|
$ret[$i][$fieldNames[$r]] = $fields[$fieldNames[$r]];
|
|
}
|
|
}
|
|
|
|
if (is_array($ret) && count($ret) == 1) {
|
|
return $ret[0];
|
|
}
|
|
else {
|
|
return $ret;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function mysql_escape_string()
|
|
{
|
|
$args = func_get_args();
|
|
$conn = null;
|
|
$sql = '';
|
|
|
|
if (is_array($args) && count($args) < 3) {
|
|
return;
|
|
}
|
|
|
|
if (!is_a($args[0], "mysqli")) {
|
|
return;
|
|
}
|
|
else {
|
|
$conn = $args[0];
|
|
}
|
|
|
|
if (!is_string($args[1])) {
|
|
return;
|
|
}
|
|
else {
|
|
$sql = $args[1];
|
|
}
|
|
|
|
if (strpos($sql, "?") !== false) {
|
|
$x = 2;
|
|
while (strpos($sql, "?") !== false) {
|
|
$sql = str_replace_first("?", "'" . $conn->real_escape_string($args[$x]) . "'", $sql);
|
|
}
|
|
}
|
|
|
|
return $sql;
|
|
}
|
|
|
|
public function is_constraint($con_id)
|
|
{
|
|
$res = $this->c->query("SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = '$con_id'");
|
|
|
|
if ($res->num_rows) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This file will contain all the variables and functions to operate a database
|
|
* and for the ST&E Manager to interact with
|
|
*
|
|
* @author Ryan Prather
|
|
*/
|
|
class db
|
|
{
|
|
|
|
/**
|
|
* Array of words to be removed
|
|
*/
|
|
private $DISALLOWED = array(
|
|
'the', 'be', 'to', 'of', 'and',
|
|
'a', 'in', 'that', 'have', 'I',
|
|
'it', 'for', 'not', 'on', 'with',
|
|
'he', 'as', 'you', 'do', 'at',
|
|
'this', 'but', 'his', 'by', 'from',
|
|
'they', 'we', 'say', 'her', 'she',
|
|
'or', 'an', 'will', 'my', 'one',
|
|
'all', 'would', 'there', 'their', 'what',
|
|
'so', 'up', 'out', 'if', 'about',
|
|
'who', 'get', 'which', 'go', 'me',
|
|
'when', 'make', 'can', 'like', 'time',
|
|
'no', 'just', 'him', 'know', 'take',
|
|
'people', 'into', 'year', 'your', 'good',
|
|
'some', 'could', 'them', 'see', 'other',
|
|
'than', 'then', 'now', 'look', 'only',
|
|
'come', 'its', 'over', 'think', 'also',
|
|
'back', 'after', 'use', 'two', 'how',
|
|
'our', 'work', 'first', 'well', 'way',
|
|
'even', 'new', 'want', 'because', 'any',
|
|
'these', 'give', 'day', 'most', 'us'
|
|
);
|
|
|
|
/**
|
|
* The database connection
|
|
*
|
|
* @var mysqli
|
|
* @access protected
|
|
*/
|
|
protected $conn = null;
|
|
|
|
/**
|
|
* A private database helper
|
|
*
|
|
* @var db_helper
|
|
* @access public
|
|
*/
|
|
public $help = null;
|
|
|
|
/**
|
|
* Constant for the first column where target finding statuses start
|
|
*
|
|
* @var integer
|
|
*/
|
|
const FIRST_ECHECKLIST_HOST_COL = 5;
|
|
|
|
/**
|
|
* Constructor function to instantiate a new DB object and connection
|
|
*
|
|
* @param bool $persistent [optional]
|
|
*/
|
|
public function __construct($persistent = false)
|
|
{
|
|
// attempt to create a new database connection
|
|
$host = ($persistent ? "p:" : "") . DB_SERVER;
|
|
if (class_exists('mysqli')) {
|
|
$pwd = self::decrypt_pwd();
|
|
$this->conn = new mysqli($host, 'web', $pwd, 'sagacity');
|
|
}
|
|
else {
|
|
die("Could not find the mysqli class");
|
|
}
|
|
// if there is a problem output that
|
|
if ($this->conn->connect_errno && $this->conn->connect_errno == 1045) {
|
|
die("Invalid database username and/or password");
|
|
}
|
|
elseif ($this->conn->connect_errno) {
|
|
error_log("Error connecting to " . DB_SERVER . " " . $this->conn->connect_error);
|
|
die("Error connecting to " . DB_SERVER);
|
|
}
|
|
|
|
// set the character set and default database
|
|
$this->conn->set_charset("utf8");
|
|
$this->conn->real_query("SET sql_mode=''");
|
|
|
|
$this->help = new db_helper($this->conn);
|
|
}
|
|
|
|
/**
|
|
* Function to decrypt the password
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function decrypt_pwd()
|
|
{
|
|
if (!file_exists(DOC_ROOT . "/" . PWD_FILE)) {
|
|
die("Cannot connect to the database because the password file does not exist");
|
|
}
|
|
|
|
$enc_pwd = file_get_contents(DOC_ROOT . "/" . PWD_FILE);
|
|
$pwd = my_decrypt($enc_pwd);
|
|
|
|
return $pwd;
|
|
}
|
|
|
|
/**
|
|
* Get the ID of the last command that was executed
|
|
*
|
|
* @return integer
|
|
* The integer of the last primary key id inserted into whatever table
|
|
*/
|
|
public function get_Last_Insert_ID()
|
|
{
|
|
return $this->conn->insert_id;
|
|
}
|
|
|
|
// {{{ ADVISORY CLASS FUNCTIONS
|
|
/**
|
|
* Function to get an advisory from the database
|
|
*
|
|
* @param string $advisory_id [optional]
|
|
* String with advisory ID to specifically find
|
|
*
|
|
* @return array:advisory|NULL
|
|
* Returns array of advisory objects or NULL if nothing is found in the database
|
|
*/
|
|
public function get_Advisory($advisory_id = null)
|
|
{
|
|
$ret = [];
|
|
|
|
if (!is_null($advisory_id)) {
|
|
$this->help->select("sagacity.advisories", null, array(
|
|
array(
|
|
'field' => 'advisory_id',
|
|
'op' => '=',
|
|
'value' => $advisory_id
|
|
)
|
|
));
|
|
}
|
|
else {
|
|
$this->help->select("sagacity.advisories", null, []);
|
|
}
|
|
|
|
if ($ref = $this->help->execute()) {
|
|
foreach ($ref as $row) {
|
|
$ret[] = new advisory($row['pdi_id'], $row['advisory_id'], $row['reference'], $row['type'], $row['url']);
|
|
}
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Update or insert an advisory
|
|
*
|
|
* @param array:advisory $advisories
|
|
* Array of advisory class objects to save/update to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Advisory($advisories)
|
|
{
|
|
$values = [];
|
|
$fields = [
|
|
'pdi_id',
|
|
'advisory_id',
|
|
'type',
|
|
'reference',
|
|
'url',
|
|
'title',
|
|
'impact'
|
|
];
|
|
foreach ($advisories as $adv) {
|
|
$values[] = [
|
|
$adv->get_PDI_ID(),
|
|
$adv->get_Advisory_ID(),
|
|
$adv->get_Type(),
|
|
$adv->get_Ref_Text(),
|
|
$adv->get_URL(),
|
|
$adv->get_Title(),
|
|
$adv->get_Impact()
|
|
];
|
|
}
|
|
|
|
$this->help->extended_replace("sagacity.advisories", $fields, $values);
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ CATEGORY CLASS FUNCTIONS
|
|
/**
|
|
* Get ST&E category data
|
|
*
|
|
* @param integer $int_Cat_ID [optional]
|
|
* Grab specific ste_cat from database (default NULL)
|
|
*
|
|
* @return array:ste_cat|NULL
|
|
* Returns an array of categories that are applicable to the specific ST&E or a specifically requested category
|
|
*/
|
|
public function get_Category($int_Cat_ID = null)
|
|
{
|
|
$where = [];
|
|
$ret = [];
|
|
|
|
if ($int_Cat_ID != null) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $int_Cat_ID
|
|
];
|
|
}
|
|
|
|
$this->help->select("ste_cat", null, $where);
|
|
$cats = $this->help->execute();
|
|
|
|
if (is_array($cats) && count($cats) && isset($cats['id'])) {
|
|
$cats = [0 => $cats];
|
|
}
|
|
|
|
if (is_array($cats) && count($cats)) {
|
|
foreach ($cats as $cat) {
|
|
$tmp = new ste_cat($cat['id'], $cat['ste_id'], $cat['name'], $cat['analysts']);
|
|
|
|
$this->help->select("ste_cat_sources", ['src_id'], [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $cat['id']
|
|
]
|
|
]);
|
|
$srcs = $this->help->execute();
|
|
if (is_array($srcs) && count($srcs) && isset($srcs['src_id'])) {
|
|
$srcs = [0 => $srcs];
|
|
}
|
|
|
|
if (is_array($srcs) && count($srcs)) {
|
|
foreach ($srcs as $src) {
|
|
$tmp->add_Source($this->get_Sources($src['src_id']));
|
|
}
|
|
}
|
|
|
|
$this->get_Cat_Count($tmp);
|
|
|
|
$ret[] = $tmp;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to automatically put targets in categories by operating systems<br />
|
|
* Skips generic OS's and targets that already assigned
|
|
*
|
|
* @param int $ste_id
|
|
*/
|
|
public function auto_Catorgize_Targets($ste_id)
|
|
{
|
|
$this->help->select("sagacity.target t", ['t.id', 't.os_string'], [
|
|
[
|
|
'field' => 't.ste_id',
|
|
'value' => $ste_id
|
|
],
|
|
[
|
|
'field' => 't.cat_id',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'AND'
|
|
],
|
|
[
|
|
'field' => 's.cpe',
|
|
'op' => '!=',
|
|
'value' => 'cpe:/o:generic:generic:-',
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
'JOIN sagacity.software s ON t.os_id=s.id'
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$id = 0;
|
|
$this->help->select("sagacity.ste_cat", ['id'], [
|
|
[
|
|
'field' => 'ste_id',
|
|
'value' => $ste_id
|
|
],
|
|
[
|
|
'field' => 'name',
|
|
'value' => trim($row['os_string']),
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
$tmp = $this->help->execute();
|
|
if (is_array($tmp) && count($tmp) && isset($tmp['id'])) {
|
|
$id = $tmp['id'];
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.ste_cat", [
|
|
'ste_id' => $ste_id,
|
|
'name' => trim($row['os_string'])
|
|
], true);
|
|
$id = $this->help->execute();
|
|
}
|
|
|
|
if ($id) {
|
|
$this->help->update("sagacity.target", ['cat_id' => $id], [
|
|
[
|
|
'field' => 'id',
|
|
'value' => $row['id']
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to save categories
|
|
*
|
|
* @param ste_cat $ste_cat_in
|
|
*
|
|
* @return mixed
|
|
* Returns FALSE if failed, otherwise the ID of the newly inserted category
|
|
*/
|
|
public function save_Category($ste_cat_in)
|
|
{
|
|
if (is_null($ste_cat_in->get_ID())) {
|
|
$this->help->insert("sagacity.ste_cat", array(
|
|
'ste_id' => $ste_cat_in->get_STE_ID(),
|
|
'name' => $ste_cat_in->get_Name(),
|
|
'analysts' => $ste_cat_in->get_Analyst()
|
|
));
|
|
|
|
if (!($cat_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$ste_cat_in->set_ID($cat_id);
|
|
}
|
|
else {
|
|
$this->help->update("sagacity.ste_cat", array(
|
|
'name' => $ste_cat_in->get_Name(),
|
|
'analysts' => $ste_cat_in->get_Analyst()
|
|
), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $ste_cat_in->get_ID()
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (is_array($ste_cat_in->get_Sources()) && count($ste_cat_in->get_Sources())) {
|
|
$this->help->delete("ste_cat_sources", null, [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $ste_cat_in->get_ID()
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$srcs = [];
|
|
foreach ($ste_cat_in->get_Sources() as $src) {
|
|
$srcs[] = [$ste_cat_in->get_ID(), $src->get_ID()];
|
|
}
|
|
$this->help->extended_insert("ste_cat_sources", ['cat_id', 'src_id'], $srcs);
|
|
$this->help->execute();
|
|
}
|
|
|
|
return $ste_cat_in->get_ID();
|
|
}
|
|
|
|
/**
|
|
* This function renames a category
|
|
*
|
|
* @param integer $intOldCat
|
|
* Category ID of the category to rename
|
|
* @param string $strNewCatName
|
|
* New name for the category
|
|
*
|
|
* @return boolean
|
|
* Return TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function rename_Cat($intOldCat, $strNewCatName)
|
|
{
|
|
$this->help->update("sagacity.ste_cat", array('name' => $strNewCatName), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $intOldCat
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function deletes a category and assigns the targets to "Unassigned"
|
|
*
|
|
* @param integer $intCat
|
|
* ID of the category to delete
|
|
*
|
|
* @return boolean
|
|
* Return TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Cat($intCat)
|
|
{
|
|
$this->help->update("sagacity.target", array('cat_id' => null), array(
|
|
array(
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("sagacity.ste_cat_sources", null, array(
|
|
array(
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("sagacity.category_interview", null, array(
|
|
array(
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("sagacity.ste_cat", null, array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function sets the analyst that is in charge of this category
|
|
*
|
|
* @param integer $intCat
|
|
* Category ID to update
|
|
* @param string $strAnalyst
|
|
* Name of the analyst
|
|
*
|
|
* @return boolean
|
|
* Return TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function assign_Analyst_To_Category($intCat, $strAnalyst)
|
|
{
|
|
$analysts = strtolower($strAnalyst) == 'none' ? null : $strAnalyst;
|
|
$this->help->update("sagacity.ste_cat", array('analysts' => $analysts), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
)
|
|
));
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function does the move of a tgt to a new category
|
|
*
|
|
* @param array:integer $arrTgts
|
|
* Array of integer ID for each target to move
|
|
* @param integer $intCat
|
|
* Category ID to reassign them to
|
|
*
|
|
* @return boolean
|
|
* Return TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function move_Tgt_To_Cat($arrTgts, $intCat)
|
|
{
|
|
$this->help->update("sagacity.target", array('cat_id' => $intCat), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => IN,
|
|
'value' => $arrTgts
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ CCE CLASS FUNCTIONS
|
|
/**
|
|
* Getter function for CCE
|
|
*
|
|
* @param string $cce_id
|
|
* CCE ID to query for
|
|
*
|
|
* @return array:cce
|
|
*/
|
|
public function get_CCE($cce_id = null)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if (!is_null($cce_id)) {
|
|
$where[] = array(
|
|
'field' => 'cce_id',
|
|
'op' => '=',
|
|
'value' => $cce_id
|
|
);
|
|
}
|
|
|
|
$this->help->select("sagacity.cce", array('pdi_id', 'cce_id'), $where);
|
|
|
|
$cces = $this->help->execute();
|
|
if (is_array($cces) && count($cces) && isset($cces['pdi_id'])) {
|
|
$cces = array(0 => $cces);
|
|
}
|
|
|
|
if (is_array($cces) && count($cces) && isset($cces[0])) {
|
|
foreach ($cces as $cce) {
|
|
$ret[] = new cce($cce['pdi_id'], $cce['cce_id']);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to save CCE's to database
|
|
*
|
|
* @param array:cce|cce $cces
|
|
* An array of CCE's that need to be saved
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if save was successful, otherwise FALSE
|
|
*/
|
|
public function save_CCE($cces)
|
|
{
|
|
$ret = true;
|
|
$fields = array('pdi_id', 'cce_id');
|
|
$params = [];
|
|
|
|
if (is_array($cces)) {
|
|
foreach ($cces as $cce) {
|
|
$params[] = [$cce->get_PDI_ID(), $cce->get_CCE_ID()];
|
|
}
|
|
|
|
$this->help->extended_replace("sagacity.cce", $fields, $params);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
$ret = false;
|
|
}
|
|
}
|
|
else {
|
|
$this->help->replace("sagacity.cce", array(
|
|
'pdi_id' => $cces->get_PDI_ID(),
|
|
'cce_id' => $cces->get_CCE_ID()
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
$ret = false;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ CCI CLASS FUNCTIONS
|
|
public function get_CCI($cci_id = null)
|
|
{
|
|
$ret = [];
|
|
|
|
$this->help->select("sagacity.cci");
|
|
|
|
if (!is_null($cci_id)) {
|
|
$this->help->select("sagacity.cci", null, array(
|
|
array(
|
|
'field' => 'cci_id',
|
|
'op' => '=',
|
|
'value' => $cci_id
|
|
)
|
|
));
|
|
}
|
|
|
|
$ccis = $this->help->execute();
|
|
|
|
if (is_array($ccis) && count($ccis)) {
|
|
foreach ($ccis as $cci_data) {
|
|
$cci = new cci();
|
|
$cci->cci_id = $cci_data['cci_id'];
|
|
$cci->definition = $cci_data['definition'];
|
|
$cci->type = $cci_data['type'];
|
|
$cci->param = $cci_data['param'];
|
|
$cci->note = $cci_data['note'];
|
|
|
|
$this->help->select("sagacity.cci_refs", null, array(
|
|
array(
|
|
'field' => 'cci_id',
|
|
'op' => '=',
|
|
'value' => $cci_data['cci_id']
|
|
)
|
|
));
|
|
$refs = $this->help->execute();
|
|
if (is_array($refs) && count($refs)) {
|
|
foreach ($refs as $ref_data) {
|
|
$ref = new cci_reference();
|
|
$ref->index = $ref_data['index'];
|
|
$ref->url = $ref_data['url'];
|
|
$ref->title = $ref_data['title'];
|
|
$ref->ver = $ref_data['ver'];
|
|
|
|
$cci->refs[] = $ref;
|
|
}
|
|
}
|
|
|
|
$ret[] = $cci;
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get eMASS CCI Map
|
|
* @author Matt Shuter
|
|
*
|
|
* @return array
|
|
* Array of CCI-eMASS control mappings
|
|
*/
|
|
public function get_EMASS_CCIs()
|
|
{
|
|
$this->help->select("rmf.emass_cci");
|
|
$ret = $this->help->execute();
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to save a CCI
|
|
*
|
|
* @param array:cci|cci $cci_in
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function save_CCI($cci_in)
|
|
{
|
|
if (is_array($cci_in)) {
|
|
$ccis = [];
|
|
foreach ($cci_in as $cci) {
|
|
$cci_id = preg_replace("/CCI\-[0]+/", "CCI-", $cci->cci_id);
|
|
$ccis[] = [
|
|
$cci_id,
|
|
$cci->control_id,
|
|
$cci->enh_id,
|
|
$cci->definition,
|
|
$cci->guidance,
|
|
$cci->procedure
|
|
];
|
|
}
|
|
$this->help->extended_insert('rmf.cci', array(
|
|
'id', 'control_id', 'enh_id', 'def', 'guidance', 'procedure'
|
|
), $ccis, true);
|
|
}
|
|
else {
|
|
$cci_id = preg_replace("/CCI\-[0]+/", "CCI-", $cci_in->cci_id);
|
|
$this->help->insert('rmf.cci', array(
|
|
'cci_id' => $cci_id,
|
|
'control_id' => $cci_in->control_id,
|
|
'enh_id' => $cci_in->enh_id,
|
|
'def' => $cci_in->definition,
|
|
'guidance' => $cci_in->guidance,
|
|
'procedure' => $cci_in->procedure
|
|
), true);
|
|
}
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to save an array of eMASS-CCI mappings
|
|
*
|
|
* @param array:cci $cci_in
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function save_EMASS_CCIs($ccis_in)
|
|
{
|
|
$ret = false;
|
|
$columns = array('id', 'control');
|
|
$this->help->extended_insert('rmf.emass_cci', $columns, $ccis_in, true);
|
|
|
|
if ($this->help->execute()) {
|
|
$ret = true;
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ CHECKLIST CLASS FUNCTIONS
|
|
/**
|
|
* Get a checklist
|
|
*
|
|
* @param mixed $Checklist_ID [optional]
|
|
* Checklist ID to query for (default NULL)
|
|
* @param boolean $ord_desc [optional]
|
|
* Decide if you want to order to return from newest release
|
|
*
|
|
* @return array:checklist
|
|
* Returns an array of checklists, or an empty array if none found
|
|
*/
|
|
public function get_Checklist($Checklist_ID = null, $ord_desc = false)
|
|
{
|
|
$ret = [];
|
|
|
|
if ($ord_desc) {
|
|
$this->help->select("sagacity.checklist", [
|
|
'id',
|
|
'checklist_id',
|
|
'name',
|
|
'description',
|
|
'date',
|
|
'file_name',
|
|
'ver',
|
|
"MAX(LPAD(`release`, 0, 2)) AS 'release'",
|
|
'type',
|
|
'icon'
|
|
]);
|
|
}
|
|
else {
|
|
$this->help->select("sagacity.checklist", null);
|
|
}
|
|
|
|
$where = [];
|
|
if (!is_null($Checklist_ID)) {
|
|
if (is_numeric($Checklist_ID)) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID
|
|
];
|
|
}
|
|
elseif (is_array($Checklist_ID)) {
|
|
if (isset($Checklist_ID['checklist_id'])) {
|
|
$where[] = [
|
|
'field' => 'checklist_id',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID['checklist_id']
|
|
];
|
|
}
|
|
|
|
if (isset($Checklist_ID['type'])) {
|
|
$where[] = [
|
|
'field' => 'type',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID['type'],
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (isset($Checklist_ID['version'])) {
|
|
$where[] = [
|
|
'field' => 'ver',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID['version'],
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (isset($Checklist_ID['release'])) {
|
|
$where[] = [
|
|
'field' => 'release',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID['release'],
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'checklist_id',
|
|
'op' => '=',
|
|
'value' => $Checklist_ID
|
|
];
|
|
}
|
|
}
|
|
|
|
if (is_array($where) && count($where)) {
|
|
$this->help->sql .= $this->help->where($where);
|
|
}
|
|
|
|
$flags = [];
|
|
if ($ord_desc) {
|
|
$flags = [
|
|
'group' => 'type',
|
|
'order' => [
|
|
['field' => 'name', 'sort' => 'asc'],
|
|
['field' => 'type', 'sort' => 'asc'],
|
|
['field' => 'ver', 'sort' => 'desc'],
|
|
['field' => 'LPAD(`release`,2,0)', 'sort' => 'desc']
|
|
]
|
|
];
|
|
}
|
|
else {
|
|
$flags = [
|
|
'order' => [
|
|
['field' => 'name', 'sort' => 'asc'],
|
|
['field' => 'type', 'sort' => 'asc'],
|
|
['field' => 'ver', 'sort' => 'asc'],
|
|
['field' => 'LPAD(`release`,2,0)', 'sort' => 'asc']
|
|
]
|
|
];
|
|
}
|
|
|
|
if (is_array($flags) && count($flags)) {
|
|
$this->help->sql .= $this->help->flags($flags);
|
|
}
|
|
|
|
$rows = $this->help->execute();
|
|
if (isset($rows['id'])) {
|
|
$rows = array(0 => $rows);
|
|
}
|
|
|
|
if (is_array($rows) && count($rows)) {
|
|
foreach ($rows as $row) {
|
|
$chk = new checklist(
|
|
$row['id'], $row['checklist_id'], $row['name'], $row['description'], $row['date'], $row['file_name'], $row['ver'], $row['release'], $row['type'], $row['icon']
|
|
);
|
|
/*
|
|
$this->help->select("sagacity.checklist_software_lookup", array('sw_id'), array(
|
|
array(
|
|
'field' => 'chk_id',
|
|
'op' => '=',
|
|
'value' => $row['id']
|
|
)
|
|
));
|
|
$sw_rows = $this->help->execute();
|
|
if (count($sw_rows)) {
|
|
if (isset($sw_rows['sw_id'])) {
|
|
$sw_rows = array(0 => $sw_rows);
|
|
}
|
|
|
|
foreach ($sw_rows as $row2) {
|
|
$chk->add_SW($this->get_Software($row2['sw_id']));
|
|
}
|
|
}
|
|
*/
|
|
$ret[] = $chk;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get the checklist based on the checklist filename
|
|
*
|
|
* @param string $fname
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function get_Checklist_By_File($fname)
|
|
{
|
|
$ret = [];
|
|
$this->help->select("sagacity.checklist", null, [
|
|
[
|
|
'field' => 'file_name',
|
|
'value' => $fname
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$chk = new checklist($row['id'], $row['checklist_id'], $row['name'], $row['description'], $row['date'], $row['file_name'], $row['ver'], $row['release'], $row['type'], $row['icon']);
|
|
/**/
|
|
$this->help->select("sagacity.checklist_software_lookup", ['sw_id'], [
|
|
[
|
|
'field' => 'chk_id',
|
|
'value' => $row['id']
|
|
]
|
|
]);
|
|
$sw_rows = $this->help->execute();
|
|
if (is_array($sw_rows) && count($sw_rows)) {
|
|
if (isset($sw_rows['sw_id'])) {
|
|
$sw_rows = [0 => $sw_rows];
|
|
}
|
|
|
|
foreach ($sw_rows as $row2) {
|
|
$chk->add_SW($this->get_Software($row2['sw_id']));
|
|
}
|
|
}
|
|
|
|
$ret[] = $chk;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve the most current checklist for a given software package
|
|
*
|
|
* @param software $software
|
|
* Software of which to look for checklists
|
|
*
|
|
* @return array:checklist
|
|
* Returns an array of checklists that this software ties to. Otherwise, an empty array
|
|
*/
|
|
public function get_Latest_Checklist_By_Software($software)
|
|
{
|
|
$ret = [];
|
|
$this->help->create_table("c", true, $this->help->select("sagacity.checklist", null, [], array(
|
|
'order' => '`ver` DESC, CONVERT(`release`, DECIMAL(4,2)) DESC'
|
|
)));
|
|
if (!$this->help->execute()) {
|
|
return $ret;
|
|
}
|
|
|
|
$this->help->select("c", array('c.id'), array(
|
|
array(
|
|
'field' => 'csl.sw_id',
|
|
'op' => '=',
|
|
'value' => $software->get_ID()
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"JOIN sagacity.checklist_software_lookup csl ON csl.chk_id=c.id"
|
|
),
|
|
'group' => 'c.name,c.type',
|
|
'order' => 'c.name'
|
|
));
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = array(0 => $rows);
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$chk = $this->get_Checklist($row['id']);
|
|
if (is_array($chk) && count($chk) && isset($chk[0])) {
|
|
$ret[] = $chk[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get a summary of checklist stats
|
|
*
|
|
* @param integer $cat_id
|
|
* Integer category ID to get the summary on
|
|
*
|
|
* @return NULL|array:targets,checklist,string
|
|
* Returns an associative array of target (id & name), checklists, and a summary that joins the two
|
|
*/
|
|
public function get_Checklist_Summary($cat_id)
|
|
{
|
|
$where = array(array(
|
|
'field' => 't.cat_id',
|
|
'op' => (is_null($cat_id) ? IS : '='),
|
|
'value' => $cat_id
|
|
));
|
|
$tgts = [];
|
|
$chklsts = [];
|
|
$summary = [];
|
|
|
|
$this->help->select("sagacity.target_checklist tc", null, $where, array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.target t ON t.id=tc.tgt_id"
|
|
),
|
|
'group' => 't.id'
|
|
));
|
|
|
|
$tgt_rows = $this->help->execute();
|
|
if (is_array($tgt_rows) && count($tgt_rows) && isset($tgt_rows['name'])) {
|
|
$tgt_rows = array(0 => $tgt_rows);
|
|
}
|
|
|
|
if (is_array($tgt_rows) && count($tgt_rows) && isset($tgt_rows[0])) {
|
|
foreach ($tgt_rows as $row) {
|
|
$tgts[$row['id']] = $row['name'];
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
$this->help->select("sagacity.target_checklist tc", array('c.id', 'c.name', 'c.type', 'c.ver', 'c.`release`'), $where, array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.checklist c ON tc.chk_id=c.id",
|
|
"LEFT JOIN sagacity.target t ON tc.tgt_id=t.id"
|
|
),
|
|
'group' => 'c.id',
|
|
'order' => 'c.name'
|
|
));
|
|
|
|
$chk_rows = $this->help->execute();
|
|
if (is_array($chk_rows) && count($chk_rows) && isset($chk_rows['id'])) {
|
|
$chk_rows = array(0 => $chk_rows);
|
|
}
|
|
|
|
if (is_array($chk_rows) && count($chk_rows) && isset($chk_rows[0])) {
|
|
foreach ($chk_rows as $row) {
|
|
$chklsts[$row['id']] = "{$row['name']} V{$row['ver']}R{$row['release']} (" . ($row['type'] == 'iavm' ? 'IAVM' : ucfirst($row['type'])) . ")";
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
$this->help->select("sagacity.findings f", array("COUNT(1) as 'cnt'", 'c.id', 'c.name', 'c.ver', 'c.`release`'), array(
|
|
array(
|
|
'field' => 't.cat_id',
|
|
'op' => (is_null($cat_id) ? IS : '='),
|
|
'value' => $cat_id
|
|
),
|
|
array(
|
|
'field' => 'c.name',
|
|
'op' => '=',
|
|
'value' => 'Orphan',
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.target t ON t.id=f.tgt_id",
|
|
"LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pcl.pdi_id=f.pdi_id",
|
|
"LEFT JOIN sagacity.checklist c ON pcl.checklist_id=c.id"
|
|
)
|
|
));
|
|
$chk_rows2 = $this->help->execute();
|
|
if (is_array($chk_rows2) && count($chk_rows2) && isset($chk_rows2['cnt'])) {
|
|
if ($chk_rows2['cnt'] > 0) {
|
|
$chklsts[$chk_rows2['id']] = "{$chk_rows2['name']} V{$chk_rows2['ver']}R{$chk_rows2['release']}";
|
|
}
|
|
}
|
|
|
|
foreach ($chklsts as $chk_key => $chk) {
|
|
foreach ($tgts as $host_key => $host) {
|
|
if ($chk != 'Orphan') {
|
|
$this->help->select_count("sagacity.target_checklist tc", [
|
|
[
|
|
'field' => 'tc.tgt_id',
|
|
'op' => '=',
|
|
'value' => $host_key
|
|
],
|
|
[
|
|
'field' => 'tc.chk_id',
|
|
'op' => '=',
|
|
'value' => $chk_key,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
}
|
|
else {
|
|
$this->help->select("sagacity.findings f", ["IF(COUNT(1) > 0, '1', '0')"], [
|
|
[
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $host_key
|
|
],
|
|
[
|
|
'field' => 'c.name',
|
|
'op' => '=',
|
|
'value' => 'Orphan',
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pcl.pdi_id=f.pdi_id",
|
|
"LEFT JOIN sagacity.checklist c ON c.id=pcl.checklist_id"
|
|
]
|
|
]);
|
|
}
|
|
|
|
$summary[$chk_key][$host_key] = $this->help->execute();
|
|
}
|
|
}
|
|
|
|
return ['tgts' => $tgts, 'checklists' => $chklsts, 'summary' => $summary];
|
|
}
|
|
|
|
/**
|
|
* Get all checklist & targets in a category
|
|
*
|
|
* @param integer $cat_id
|
|
* Category ID to pull the checklists from
|
|
*
|
|
* @return NULL|array:string checklist
|
|
*/
|
|
public function get_Category_Checklists($cat_id)
|
|
{
|
|
$chklsts = [];
|
|
|
|
$this->help->select("sagacity.target_checklist tc", array('tc.tgt_id', 'tc.chk_id'), array(
|
|
array(
|
|
'field' => 't.cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.target t ON tc.tgt_id = t.id",
|
|
"LEFT JOIN sagacity.checklist c ON tc.chk_id = c.id"
|
|
),
|
|
'order' => 'c.name'
|
|
));
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['tgt_id'])) {
|
|
$rows = array(0 => $rows);
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$chk = $this->get_Checklist($row['chk_id']);
|
|
if (is_array($chk) && count($chk) && isset($chk[0]) && is_a($chk[0], 'checklist')) {
|
|
$chk = $chk[0];
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
|
|
$tgts = isset($chklsts[$chk->get_ID()]['tgts']) ? $chklsts[$chk->get_ID()]['tgts'] : null;
|
|
$chklsts[$chk->get_ID()] = array(
|
|
'tgts' => $tgts . $row['tgt_id'] . ",",
|
|
'checklist' => $chk
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->help->select_count("sagacity.target t", array(
|
|
array(
|
|
'field' => 't.cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id
|
|
),
|
|
array(
|
|
'field' => 'pcl.checklist_id',
|
|
'op' => '=',
|
|
'value' => "(SELECT c.id FROM sagacity.checklist c WHERE c.name='Orphan')",
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.findings f ON t.id=f.tgt_id",
|
|
"LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pcl.pdi_id=f.pdi_id"
|
|
)
|
|
));
|
|
|
|
$count = $this->help->execute();
|
|
if ($count) {
|
|
$this->help->select("sagacity.target t", array("t.id AS 'tgt_id'", "pcl.checklist_id AS 'chk_id'"), array(
|
|
array(
|
|
'field' => 't.cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id
|
|
),
|
|
array(
|
|
'field' => 'pcl.checklist_id',
|
|
'op' => '=',
|
|
'value' => "(SELECT c.id FROM sagacity.checklist c WHERE c.name='Orphan')",
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.findings f ON t.id=f.tgt_id",
|
|
"LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pcl.pdi_id=f.pdi_id"
|
|
),
|
|
'group' => 't.id,pcl.checklist_id'
|
|
));
|
|
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['tgt_id'])) {
|
|
$rows2 = array(0 => $rows2);
|
|
}
|
|
|
|
if (is_array($rows2) && count($rows2) && isset($rows2[0])) {
|
|
foreach ($rows2 as $row2) {
|
|
$chk = $this->get_Checklist($row2['chk_id']);
|
|
if (is_array($chk) && count($chk) && isset($chk[0]) && is_a($chk[0], 'checklist')) {
|
|
$chk = $chk[0];
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
|
|
$tgts = isset($chklsts[$chk->get_ID()]['tgts']) ? $chklsts[$chk->get_ID()]['tgts'] : "";
|
|
$chklsts[$chk->get_ID()] = array(
|
|
'tgts' => $tgts . $row2['tgt_id'] . ",",
|
|
'checklist' => $chk
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $chklsts;
|
|
}
|
|
|
|
/**
|
|
* Get array of checklists for a target
|
|
*
|
|
* @param integer $tgt_id
|
|
* The target ID of the target we want checklists from
|
|
*
|
|
* @return array:checklist |NULL
|
|
* Returns an array of checklists that are assigned to the requested target
|
|
*/
|
|
public function get_Target_Checklists($tgt_id)
|
|
{
|
|
$this->help->select("sagacity.target_checklist tc", ['c.id', 'tc.class'], [
|
|
[
|
|
'field' => 'tc.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN sagacity.checklist c ON c.id=tc.chk_id"
|
|
],
|
|
'order' => 'c.name'
|
|
]);
|
|
$chk = [];
|
|
$chks = $this->help->execute();
|
|
|
|
if (isset($chks['id'])) {
|
|
$chks = [0 => $chks];
|
|
}
|
|
|
|
if (is_array($chks) && count($chks) && isset($chks[0])) {
|
|
foreach ($chks as $row) {
|
|
$checklist = $this->get_Checklist($row['id'])[0];
|
|
$checklist->set_Classification($row['class']);
|
|
|
|
$chk[] = $checklist;
|
|
}
|
|
}
|
|
|
|
// get the orphan checklist ID
|
|
$this->help->select("sagacity.checklist", ['id'], [
|
|
[
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => 'Orphan'
|
|
]
|
|
]);
|
|
$orphan = $this->help->execute();
|
|
|
|
// check to see if this target has findings from the Orphan checklist
|
|
$this->help->select_count("sagacity.pdi_checklist_lookup pcl", [
|
|
[
|
|
'field' => 'pcl.checklist_id',
|
|
'op' => '=',
|
|
'value' => $orphan['id']
|
|
],
|
|
[
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"RIGHT JOIN sagacity.findings f ON pcl.pdi_id=f.pdi_id"
|
|
]
|
|
]);
|
|
$cnt = $this->help->execute();
|
|
|
|
// add the orphan checklist if findings exist
|
|
if ($cnt) {
|
|
$chk[] = $this->get_Checklist($orphan['id'])[0];
|
|
}
|
|
|
|
return $chk;
|
|
}
|
|
|
|
/**
|
|
* Function for getting eChecklist data to export
|
|
*
|
|
* @param int $cat_id
|
|
* @param array $chk_host_list
|
|
* @param string $status
|
|
* @param int $category
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_Category_Findings($cat_id, $chk_host_list = [], $status = null, $category = null)
|
|
{
|
|
$ret = [];
|
|
$stigs = [];
|
|
$tgt_ids = [];
|
|
|
|
$where = [
|
|
[
|
|
'field' => 'gcf.cat_id',
|
|
'op' => (is_null($cat_id) ? IS : '='),
|
|
'value' => $cat_id
|
|
]
|
|
];
|
|
|
|
if (!is_null($status)) {
|
|
$where[] = [
|
|
'field' => 'gcf.status',
|
|
'op' => '=',
|
|
'value' => $status,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
];
|
|
|
|
if ($status == 'Not Reviewed') {
|
|
$where[] = [
|
|
'field' => 'gcf.status',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
else {
|
|
unset($where[1]['open-paren']);
|
|
}
|
|
}
|
|
|
|
if (!is_null($category)) {
|
|
$where[] = [
|
|
'field' => 'gcf.cat',
|
|
'op' => '=',
|
|
'value' => $category,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("sagacity.get_cat_findings gcf", null, $where);
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['tgt_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
if (is_null($row['chk_icon']) || $row['chk_icon'] == '') {
|
|
$worksheet_name = '(Unknown)';
|
|
}
|
|
else {
|
|
$worksheet_name = substr($row['chk_icon'], 0, -4);
|
|
}
|
|
|
|
if (!isset($ret[$worksheet_name])) {
|
|
$ret[$worksheet_name] = ['target_list' => [], 'checklists' => [], 'stigs' => []];
|
|
$where2 = [
|
|
[
|
|
'field' => 't.cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id
|
|
],
|
|
[
|
|
'field' => 'c.icon',
|
|
'op' => LIKE,
|
|
'value' => "'$worksheet_name%'",
|
|
'sql_op' => 'AND'
|
|
]
|
|
];
|
|
|
|
if (is_array($tgt_ids) && count($tgt_ids)) {
|
|
$where2[] = [
|
|
'field' => 't.id',
|
|
'op' => IN,
|
|
'value' => $tgt_ids,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("target t", ['t.class'], $where2, [
|
|
'table_joins' => [
|
|
"LEFT JOIN target_checklist tc ON tc.tgt_id = t.id",
|
|
"LEFT JOIN checklist c ON c.id=tc.chk_id"
|
|
],
|
|
'group' => 't.class',
|
|
'order' => "FIELD(t.class, 'S', 'FOUO', 'U')"
|
|
]);
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['class'])) {
|
|
$ret[$worksheet_name]['highest_class'] = $rows2['class'];
|
|
}
|
|
}
|
|
|
|
if (!in_array($row['chk_id'], $ret[$worksheet_name]['checklists'])) {
|
|
$ret[$worksheet_name]['checklists'][] = $row['chk_id'];
|
|
}
|
|
|
|
if (!isset($ret[$worksheet_name]['target_list'][$row['tgt_name']])) {
|
|
$ret[$worksheet_name]['target_list']["{$row['tgt_name']}"] = count($ret[$worksheet_name]['target_list']) + 6;
|
|
}
|
|
|
|
if (!isset($ret[$worksheet_name]['stigs'][$row['stig_id']])) {
|
|
if (!empty($row['finding_ia_controls'])) {
|
|
$ia = explode(' ', $row['finding_ia_controls']);
|
|
}
|
|
else {
|
|
$ia = explode(' ', $row['ia_controls']);
|
|
}
|
|
$echk = new echecklist($row['stig_id'], $row['vms_id'], (empty($row['finding_cat']) ? $row['cat'] : $row['finding_cat']), $ia, $row['short_title'], null, $row['notes'], $row['check_contents'], null);
|
|
$echk->set_PDI_ID($row['pdi_id']);
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']] = [
|
|
'echecklist' => $echk,
|
|
"{$row['tgt_name']}" => $row['finding_status'],
|
|
'chk_id' => $row['chk_id']
|
|
];
|
|
if (!in_array($row['stig_id'], $stigs)) {
|
|
$stigs[] = $row['stig_id'];
|
|
}
|
|
}
|
|
else {
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']][$row['tgt_name']] = $row['finding_status'];
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']]['echecklist']->append_Notes($row['notes'] . PHP_EOL);
|
|
}
|
|
|
|
if ($row['chk_type'] == 'manual') {
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']]['chk_id'] = $row['chk_id'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$where = [
|
|
[
|
|
'field' => 'gof.cat_id',
|
|
'op' => (is_null($cat_id) ? IS : '='),
|
|
'value' => $cat_id
|
|
]
|
|
];
|
|
|
|
if (is_array($stigs) && count($stigs) && isset($stigs[0]) && is_a($stigs[0], 'stig')) {
|
|
$where[] = [
|
|
'field' => 'gof.stig_id',
|
|
'op' => NOT_IN,
|
|
'value' => $stigs,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (!is_null($status)) {
|
|
$where[] = [
|
|
'field' => 'gof.status',
|
|
'op' => '=',
|
|
'value' => $status,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
];
|
|
|
|
if ($status == 'Not Reviewed') {
|
|
$where[] = [
|
|
'field' => 'gof.status',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
else {
|
|
unset($where[2]['open-paren']);
|
|
}
|
|
}
|
|
|
|
if (!is_null($category)) {
|
|
$where[] = [
|
|
'field' => 'gof.cat',
|
|
'op' => '=',
|
|
'value' => $category,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("sagacity.get_orphan_findings gof", null, $where);
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['tgt_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
$worksheet_name = "Orphan";
|
|
$class = ['U' => 1, 'FOUO' => 2, 'S' => 3];
|
|
foreach ($rows as $row) {
|
|
if (!isset($ret[$worksheet_name])) {
|
|
$ret[$worksheet_name] = ['target_list' => [], 'checklists' => [], 'stigs' => [], 'highest_class' => 'U'];
|
|
}
|
|
|
|
if (!in_array($row['chk_id'], $ret[$worksheet_name]['checklists'])) {
|
|
$ret[$worksheet_name]['checklists'][] = $row['chk_id'];
|
|
}
|
|
|
|
if (!isset($ret[$worksheet_name]['target_list'][$row['tgt_name']])) {
|
|
$ret[$worksheet_name]['target_list'][$row['tgt_name']] = (is_array($ret[$worksheet_name]['target_list']) ? count($ret[$worksheet_name]['target_list']) + 6 : 7);
|
|
|
|
$sql2 = "SELECT t.`class` " .
|
|
"FROM `sagacity`.`target` t " .
|
|
"WHERE t.`name` = '" . $this->conn->real_escape_string($row['tgt_name']) . "'";
|
|
if ($res2 = $this->conn->query($sql2)) {
|
|
$row2 = $res2->fetch_assoc();
|
|
if (isset($class[$row2['class']]) && isset($class[$ret[$worksheet_name]['highest_class']])) {
|
|
if ($class[$row2['class']] > $class[$ret[$worksheet_name]['highest_class']]) {
|
|
$ret[$worksheet_name]['highest_class'] = $row2['class'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($ret[$worksheet_name]['stigs'][$row['stig_id']])) {
|
|
if (!empty($row['finding_ia_controls'])) {
|
|
$ia = explode(" ", $row['finding_ia_controls']);
|
|
}
|
|
else {
|
|
$ia = explode(" ", $row['ia_controls']);
|
|
}
|
|
$echk = new echecklist($row['stig_id'], $row['vms_id'], (empty($row['finding_cat']) ? $row['cat'] : $row['finding_cat']), $ia, $row['short_title'], null, $row['notes'], $row['check_contents'], null);
|
|
$echk->set_PDI_ID($row['pdi_id']);
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']] = [
|
|
'echecklist' => $echk,
|
|
$row['tgt_name'] => $row['finding_status'],
|
|
'chk_id' => $row['chk_id']
|
|
];
|
|
}
|
|
else {
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']][$row['tgt_name']] = $row['finding_status'];
|
|
$ret[$worksheet_name]['stigs'][$row['stig_id']]['echecklist']->append_Notes($row['notes'] . "\r");
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Add a checklist to database
|
|
*
|
|
* @param checklist $checklist_in
|
|
* The checklist that we want to add to the database
|
|
*
|
|
* @return integer
|
|
* Returns the id of the checklist inserted, or 0 if failed
|
|
*/
|
|
public function save_Checklist($checklist_in)
|
|
{
|
|
if (empty($checklist_in->id)) {
|
|
$this->help->insert("sagacity.checklist", array(
|
|
'checklist_id' => $checklist_in->checklist_id,
|
|
'name' => $checklist_in->name,
|
|
'description' => $checklist_in->description,
|
|
'date' => $checklist_in->date,
|
|
'file_name' => $checklist_in->file_name,
|
|
'release' => $checklist_in->release,
|
|
'ver' => $checklist_in->ver,
|
|
'type' => $checklist_in->type,
|
|
'icon' => $checklist_in->icon
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
else {
|
|
$chk_id = $this->conn->insert_id;
|
|
}
|
|
|
|
if (is_array($checklist_in->sw) && count($checklist_in->sw)) {
|
|
$fields = [
|
|
'chk_id', 'sw_id'
|
|
];
|
|
$params = [];
|
|
|
|
foreach ($checklist_in->sw as $sw) {
|
|
if (is_a($sw, 'software') && $sw->get_ID()) {
|
|
$params[] = [$chk_id, $sw->get_ID()];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_insert('checklist_software_lookup', $fields, $params, true);
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->help->update('checklist', [
|
|
'checklist_id' => $checklist_in->checklist_id,
|
|
'name' => $checklist_in->name,
|
|
'description' => $checklist_in->description,
|
|
'date' => $checklist_in->date,
|
|
'file_name' => $checklist_in->file_name,
|
|
'release' => $checklist_in->release,
|
|
'ver' => $checklist_in->ver,
|
|
'type' => $checklist_in->type,
|
|
'icon' => $checklist_in->icon
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $checklist_in->id
|
|
]
|
|
]);
|
|
|
|
$chk_id = $checklist_in->id;
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
if (is_array($checklist_in->sw) && count($checklist_in->sw)) {
|
|
$this->help->delete("checklist_software_lookup", [
|
|
[
|
|
'field' => 'chk_id',
|
|
'op' => '=',
|
|
'value' => $checklist_in->id
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
$field = ['chk_id', 'sw_id'];
|
|
$params = [];
|
|
|
|
foreach ($checklist_in->sw as $sw) {
|
|
if ($sw->get_ID()) {
|
|
$params[] = [$chk_id, $sw->get_ID()];
|
|
}
|
|
}
|
|
|
|
if (is_array($params) && count($params)) {
|
|
$this->help->extended_insert("checklist_software_lookup", $field, $params, true);
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::sql_handler($this->help->sql);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $chk_id;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ CVE CLASS FUNCTIONS
|
|
/**
|
|
* Function to retrieve CVE object
|
|
*
|
|
* @param string $cve_id
|
|
* CVE to query from the database
|
|
*
|
|
* @return cve|NULL
|
|
* Returns CVE and associated references or null is nothing found
|
|
*/
|
|
public function get_CVE($cve_id)
|
|
{
|
|
$cve = null;
|
|
|
|
$this->help->select("sagacity.cve_db", array(
|
|
"cve_db.cve_id", "cve.pdi_id", "cve_db.seq", "cve_db.status",
|
|
"cve_db.phase", "cve_db.phase_date", "cve_db.desc"
|
|
), array(
|
|
array(
|
|
'field' => 'cve_db.cve_id',
|
|
'op' => '=',
|
|
'value' => $cve_id
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.cve ON cve.cve_id=cve_db.cve_id"
|
|
)
|
|
));
|
|
|
|
$row = $this->help->execute();
|
|
|
|
if (is_array($row) && count($row) && isset($row['cve_id'])) {
|
|
$cve_id = $row['cve_id'];
|
|
|
|
$cve = new cve($row['pdi_id'], $row['cve_id']);
|
|
$cve->set_Sequence($row['seq']);
|
|
$cve->set_Status($row['status']);
|
|
$cve->set_Phase($row['phase']);
|
|
$cve->set_Phase_Date($row['phase_date']);
|
|
$cve->set_Description($row['desc']);
|
|
|
|
$this->help->select("sagacity.iavm_to_cve itc", array("itc.noticeId"), array(
|
|
array(
|
|
'field' => "itc.cve_id",
|
|
'op' => '=',
|
|
'value' => $cve_id
|
|
)
|
|
));
|
|
|
|
$iavm_rows = $this->help->execute();
|
|
if (is_array($iavm_rows) && count($iavm_rows) && isset($iavm_rows['noticeId'])) {
|
|
$iavm_rows = array(0 => $iavm_rows);
|
|
}
|
|
|
|
if (is_array($iavm_rows) && count($iavm_rows) && isset($iavm_rows[0])) {
|
|
foreach ($iavm_rows as $iavm) {
|
|
$cve->add_IAVM($iavm['noticeId']);
|
|
}
|
|
}
|
|
|
|
$this->help->select("sagacity.cve_references", array('id', 'source', 'url', 'val'), array(
|
|
array(
|
|
'field' => 'cve_seq',
|
|
'op' => '=',
|
|
'value' => $cve_id
|
|
)
|
|
));
|
|
|
|
$ref_rows = $this->help->execute();
|
|
if (is_array($ref_rows) && count($ref_rows) && isset($ref_rows['id'])) {
|
|
$ref_rows = array(0 => $ref_rows);
|
|
}
|
|
|
|
if (is_array($ref_rows) && count($ref_rows) && isset($ref_rows[0])) {
|
|
foreach ($ref_rows as $ref) {
|
|
$cve->add_Reference(new cve_reference($ref['id'], $ref['source'], $ref['url'], $ref['val']));
|
|
}
|
|
}
|
|
}
|
|
|
|
return $cve;
|
|
}
|
|
|
|
/**
|
|
* Getter function to retrieve CVE's by their link to a PDI
|
|
*
|
|
* @param integer $pdi_id
|
|
* PDI ID that we want to find CVE's for
|
|
*
|
|
* @return NULL|array:cve
|
|
* Returns an array of CVEs for each one found that links to a PDI or NULL if none found
|
|
*/
|
|
public function get_CVEs_By_PDI($pdi_id)
|
|
{
|
|
$ret = [];
|
|
$sql = "SELECT " .
|
|
"cve_db.`cve_id`,cve.`pdi_id`,cve_db.`seq`,cve_db.`status`," .
|
|
"cve_db.`phase`,cve_db.`phase_date`,cve_db.`desc` " .
|
|
"FROM `sagacity`.`cve_db` " .
|
|
"LEFT JOIN `sagacity`.`cve` ON cve.`cve_id` = cve_db.`cve_id` " .
|
|
"WHERE cve.`pdi_id` = " . $this->conn->real_escape_string($pdi_id);
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if (!$res->num_rows) {
|
|
return null;
|
|
}
|
|
while ($row = $res->fetch_assoc()) {
|
|
$cve_id = $row['cve_id'];
|
|
|
|
$cve = new cve($row['pdi_id'], $row['cve_id']);
|
|
|
|
$cve->set_Sequence($row['seq']);
|
|
$cve->set_Status($row['status']);
|
|
$cve->set_Phase($row['phase']);
|
|
$cve->set_Phase_Date($row['phase_date']);
|
|
$cve->set_Description($row['desc']);
|
|
|
|
$sql = "SELECT itc.`noticeId` " .
|
|
"FROM `sagacity`.`iavm_to_cve` itc " .
|
|
"WHERE itc.`cve_id`='" . $this->conn->real_escape_string($cve_id) . "'";
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$cve->add_IAVM($row2['noticeId']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$sql = "SELECT `id`,`source`,`url`,`val` " .
|
|
"FROM `sagacity`.`cve_references` " .
|
|
"WHERE `cve_seq`='" . $this->conn->real_escape_string($cve_id) . "'";
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$cve->add_Reference(new cve_reference($row2['id'], $row2['source'], $row2['url'], $row2['val']));
|
|
}
|
|
|
|
$ret[] = $cve;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get a CVE from a external reference
|
|
*
|
|
* @param string $ext
|
|
* String of the external reference we are looking for
|
|
*
|
|
* @return cve|NULL
|
|
* Returns the CVE that references that external data point or NULL if none found
|
|
*/
|
|
public function get_CVE_From_External($ext)
|
|
{
|
|
$sql = "SELECT `cve_seq` " .
|
|
"FROM `sagacity`.`cve_references` " .
|
|
"WHERE `url` LIKE '%" . $this->conn->real_escape_string($ext) . "%' OR " .
|
|
"`val` LIKE '%" . $this->conn->real_escape_string($ext) . "%' " .
|
|
"GROUP BY `cve_seq` " .
|
|
"ORDER BY `cve_seq` DESC";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if ($res->num_rows) {
|
|
$row = $res->fetch_assoc();
|
|
$cve = $this->get_CVE($row['cve_seq']);
|
|
return $cve;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Update or insert a CVE
|
|
*
|
|
* @param array:cve $cves
|
|
* Array of CVEs to save to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_CVE($cves)
|
|
{
|
|
if (is_array($cves) && isset($cves[0]) && is_a($cves[0], 'cve')) {
|
|
foreach ($cves as $cve) {
|
|
$db_cve = $this->get_CVE($cve->get_CVE());
|
|
|
|
if (!is_null($db_cve) && is_a($db_cve, 'cve')) {
|
|
$this->help->update("sagacity.cve_db", array(
|
|
'status' => $cve->get_Status(),
|
|
'phase' => $cve->get_Phase(),
|
|
'phase_date' => $cve->get_Phase_Date(),
|
|
'desc' => $cve->get_Description()
|
|
), array(
|
|
array(
|
|
'field' => 'cve_id',
|
|
'op' => '=',
|
|
'value' => $cve->get_CVE()
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
if (!$db_cve->get_PDI_ID() && $cve->get_PDI_ID()) {
|
|
$this->help->insert("sagacity.cve", array(
|
|
'pdi_id' => $cve->get_PDI_ID(),
|
|
'cve_id' => $cve->get_CVE()
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$vals = [];
|
|
foreach ($cve->get_References() as $ref) {
|
|
if (!$db_cve->ref_Exists($ref->get_Value())) {
|
|
$vals[] = [
|
|
$cve->get_CVE(),
|
|
$ref->get_Source(),
|
|
$ref->get_URL(),
|
|
$ref->get_Value()
|
|
];
|
|
}
|
|
}
|
|
|
|
if (is_array($vals) && count($vals)) {
|
|
$this->help->extended_insert("cve_references", ['cve_seq', 'source', 'url', 'val'], $vals, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->help->insert("cve_db", [
|
|
'cve_id' => $cve->get_CVE(),
|
|
'seq' => $cve->get_Sequence(),
|
|
'status' => $cve->get_Status(),
|
|
'phase' => $cve->get_Phase(),
|
|
'phase_date' => $cve->get_Phase_Date(),
|
|
'desc' => $cve->get_Description()
|
|
], true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
if ($cve->get_PDI_ID()) {
|
|
$this->help->insert("sagacity.cve", [
|
|
'pdi_id' => $cve->get_PDI_ID(),
|
|
'cve_id' => $cve->get_CVE()
|
|
], true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (is_array($cve->get_References()) && count($cve->get_References())) {
|
|
$ref_vals = [];
|
|
foreach ($cve->get_References() as $ref) {
|
|
$ref_vals[] = [
|
|
$cve->get_CVE(),
|
|
$ref->get_Source(),
|
|
$ref->get_URL(),
|
|
$ref->get_Value()
|
|
];
|
|
}
|
|
|
|
if (is_array($ref_vals) && count($ref_vals)) {
|
|
$this->help->extended_insert("cve_references", ['cve_seq', 'source', 'url', 'val'], $ref_vals, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($cve->get_XML()) {
|
|
$this->help->insert("cve_web", [
|
|
'cve_id' => $cve->get_CVE(),
|
|
'xml' => $cve->get_XML()
|
|
], true);
|
|
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ ECHECKLIST CLASS FUNCTIONS
|
|
/**
|
|
* Get an eChecklist for a checklist and list of targets
|
|
*
|
|
* @param mixed $ref
|
|
* The reference to search for (can consist of any data that is referenced in an eChecklist line
|
|
* @param integer $chk_id
|
|
*
|
|
* @return NULL|echecklist
|
|
* Returns eChecklist for associated checklists and reference
|
|
*/
|
|
public function get_eChecklist($ref, $chk_id)
|
|
{
|
|
$ret = null;
|
|
$where = [];
|
|
|
|
if (is_a($ref, "stig")) {
|
|
$where[] = [
|
|
'field' => 's.stig_id',
|
|
'op' => '=',
|
|
'value' => $ref->get_ID()
|
|
];
|
|
}
|
|
elseif (is_a($ref, "golddisk")) {
|
|
$where[] = [
|
|
'field' => 'v.vms_id',
|
|
'op' => '=',
|
|
'value' => $ref->get_ID()
|
|
];
|
|
}
|
|
elseif (is_a($ref, "pdi")) {
|
|
$where[] = [
|
|
'field' => 'pdi.id',
|
|
'op' => '=',
|
|
'value' => $ref->get_ID()
|
|
];
|
|
}
|
|
else {
|
|
error_log("No reference to search for");
|
|
return $ret;
|
|
}
|
|
|
|
$this->help->select("pdi_catalog pdi", [
|
|
"pdi.id AS 'pdi_id'",
|
|
"s.stig_id",
|
|
"v.vms_id",
|
|
"pdi.short_title",
|
|
"IF(pdi.cat=1,'I',IF(pdi.cat=2,'II',IF(pdi.cat=3,'III',''))) as 'cat'"
|
|
], $where, [
|
|
'table_joins' => [
|
|
"LEFT JOIN stigs s ON s.pdi_id = pdi.id",
|
|
"LEFT JOIN golddisk v ON v.pdi_id = pdi.id"
|
|
],
|
|
'group' => 's.stig_id'
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret = new echecklist($row['stig_id'], $row['vms_id'], $row['cat'], null, $row['short_title'], null, null, null, null);
|
|
$ret->set_PDI_ID($row['pdi_id']);
|
|
|
|
$this->help->select("pdi_checklist_lookup pcl", ['pcl.check_contents'], [
|
|
[
|
|
'field' => 'pcl.checklist_id',
|
|
'op' => IN,
|
|
'value' => (is_array($chk_id) ? implode(",", $chk_id) : $chk_id)
|
|
],
|
|
[
|
|
'field' => 'pcl.pdi_id',
|
|
'op' => '=',
|
|
'value' => $row['pdi_id'],
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN sagacity.checklist c ON c.id = pcl.checklist_id"
|
|
],
|
|
'order' => "FIELD(c.`type`, 'manual', 'iavm', 'policy', 'benchmark')"
|
|
]);
|
|
|
|
$row2 = $this->help->execute();
|
|
if (is_array($row2) && count($row2) && isset($row2['check_contents'])) {
|
|
$ret->set_Check_Contents($row2['check_contents']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ FILTER CLASS FUNCTIONS
|
|
/**
|
|
* Getter function for search filters
|
|
*
|
|
* @param string $type
|
|
*
|
|
* @return array:string
|
|
*/
|
|
public function get_Filters($type, $name = null)
|
|
{
|
|
$ret = [];
|
|
$sql = "SELECT `type`, `name`, `criteria` " .
|
|
"FROM `sagacity`.`search_filters` " .
|
|
"WHERE `type` = '" . $this->conn->real_escape_string($type) . "'";
|
|
|
|
if (!is_null($name)) {
|
|
$sql .= " AND `name` = '" . $this->conn->real_escape_string($name) . "'";
|
|
}
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret[] = array(
|
|
'type' => $row['type'],
|
|
'name' => $row['name'],
|
|
'criteria' => $row['criteria']
|
|
);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Save function for a search filter
|
|
*
|
|
* @param string $type
|
|
* @param string $name
|
|
* @param string $criteria
|
|
*
|
|
* @return string
|
|
*/
|
|
public function save_Filter($type, $name, $criteria)
|
|
{
|
|
$this->help->insert("sagacity.search_filters", [
|
|
'name' => $name,
|
|
'type' => $type,
|
|
'criteria' => $criteria
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ FINDING CLASS FUNCTIONS
|
|
/**
|
|
* Get finding(s) for a specific target from the database
|
|
*
|
|
* @param target $tgt
|
|
* The target that we want findings for
|
|
* @param stig|golddisk|iavm|nessus $ref [optional]
|
|
* Get a finding associated with a specific PDI (default null)
|
|
* @param scan $scan [optional]
|
|
* Get findings associated with a specific scan (default null)
|
|
* @param boolean $orphan_only [optional]
|
|
* Only retrieve orphaned findings (default false)
|
|
* @param string $status [optional]
|
|
* Limit the retrieval to findings with this status (default null)
|
|
*
|
|
* @return array:finding|NULL
|
|
* Returns array of findings
|
|
*/
|
|
public function get_Finding($tgt, $ref = null, $scan = null, $orphan_only = false, $status = null)
|
|
{
|
|
$ret = null;
|
|
$where = [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
];
|
|
|
|
if (!is_null($scan)) {
|
|
$where[] = [
|
|
'field' => 'scan_id',
|
|
'op' => '=',
|
|
'value' => $scan->get_ID(),
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (!is_null($ref) && method_exists($ref, 'get_PDI_ID')) {
|
|
$where[] = [
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $ref->get_PDI_ID(),
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("sagacity.findings", null, $where);
|
|
|
|
if (!is_null($status)) {
|
|
$this->help->sql = "SELECT " .
|
|
"f.`id`, {$tgt->get_ID()} as 'tgt_id', pdi.`id` as 'pdi_id', f.`scan_id`, " .
|
|
"f.`notes`, f.`change_id`, f.`orig_src`, f.`finding_itr`, f.`cat`, " .
|
|
"IF(f.`findings_status_id` IS NOT NULL, " .
|
|
"f.`findings_status_id`, " .
|
|
"(SELECT fs.`id` " .
|
|
"FROM `sagacity`.`findings_status` fs " .
|
|
"WHERE fs.`status` = '{$this->conn->real_escape_string($status)}')" .
|
|
") as 'findings_status' " .
|
|
"FROM `sagacity`.`pdi_catalog` pdi " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` lookup ON lookup.`pdi_id` = pdi.`id` " .
|
|
"LEFT JOIN `sagacity`.`target_checklist` tc ON tc.`chk_id` = lookup.`checklist_id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pdi.`id` AND " .
|
|
"f.`tgt_id` = {$this->conn->real_escape_string($tgt->get_ID())} " .
|
|
"WHERE tc.`tgt_id` = {$tgt->get_ID()} AND " .
|
|
"(f.`findings_status_id` = (" .
|
|
"SELECT fs.`id` " .
|
|
"FROM `sagacity`.`findings_status` fs " .
|
|
"WHERE fs.`status` = '{$this->conn->real_escape_string($status)}'" .
|
|
") OR " .
|
|
"f.`findings_status_id` IS NULL) " .
|
|
"GROUP BY pdi.id";
|
|
}
|
|
|
|
if ($orphan_only) {
|
|
$this->help->select("sagacity.findings f", ['f.*'], [
|
|
[
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
],
|
|
[
|
|
'field' => 'c.name',
|
|
'op' => '=',
|
|
'value' => 'Orphan',
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN pdi_checklist_lookup pcl ON f.pdi_id=pcl.pdi_id",
|
|
"LEFT JOIN target_checklist tc ON tc.chk_id=pcl.checklist_id",
|
|
"LEFT JOIN checklist c ON pcl.checklist_id=c.id"
|
|
]
|
|
]);
|
|
}
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$find = new finding($row['id'], $row['tgt_id'], $row['pdi_id'], $row['scan_id'], $row['findings_status_id'], $row['notes'], $row['change_id'], $row['orig_src'], $row['finding_itr']);
|
|
$find->set_Category($row['cat']);
|
|
|
|
$this->help->select("finding_controls", ['ia_control'], [
|
|
[
|
|
'field' => 'finding_id',
|
|
'op' => '=',
|
|
'value' => $row['id']
|
|
]
|
|
]);
|
|
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['ia_control'])) {
|
|
$rows2 = [0 => $rows2];
|
|
}
|
|
if (is_array($rows2) && count($rows2) && isset($rows2[0])) {
|
|
foreach ($rows2 as $row2) {
|
|
$find->add_IA_Control($row2['ia_control']);
|
|
}
|
|
}
|
|
else {
|
|
$this->help->select("ia_controls", ["CONCAT(`type`, '-', `type_id`) AS 'ia_control'"], [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $row['pdi_id']
|
|
]
|
|
]);
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['ia_control'])) {
|
|
$rows2 = [0 => $rows2];
|
|
}
|
|
if (is_array($rows2) && count($rows2) && isset($rows2[0])) {
|
|
foreach ($rows2 as $row2) {
|
|
$find->add_IA_Control($row2['ia_control']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$ret[$find->get_PDI_ID()] = $find;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get the findings that are assigned to specific controls
|
|
*
|
|
* @param ste $ste
|
|
* @param proc_ia_controls $ia_ctrl
|
|
* @param string $status
|
|
* @return array:finding |NULL
|
|
*/
|
|
public function get_Findings_by_Control($ste, $ia_ctrl, $status = null)
|
|
{
|
|
if (!is_null($status)) {
|
|
if ($status == "Open") {
|
|
$status = " AND (fs.`status` = 'Open' OR fs.`status` = 'Exception')";
|
|
}
|
|
else {
|
|
$status = " AND fs.`status` = '" . $this->conn->real_escape_string($status) . "'";
|
|
}
|
|
}
|
|
|
|
$sql = "SELECT " .
|
|
"f.`id`, f.`tgt_id`, f.`pdi_id`, f.`scan_id`, f.`findings_status_id` as 'findings_status', " .
|
|
"f.`notes`, f.`change_id`, f.`orig_src`, f.`finding_itr`, f.`cat` " .
|
|
"FROM `sagacity`.`findings` f " .
|
|
"JOIN `sagacity`.`findings_status` fs ON f.`findings_status_id` = fs.`id` " .
|
|
"JOIN `sagacity`.`stigs` s ON s.`pdi_id` = f.`pdi_id` " .
|
|
"JOIN `sagacity`.`target` t ON t.`id` = f.`tgt_id` " .
|
|
"JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " .
|
|
"WHERE t.`ste_id` = " . $ste->get_ID() . " AND " .
|
|
"fc.`ia_control` = '" . $this->conn->real_escape_string($ia_ctrl->get_Control_ID()) . "'" .
|
|
(!is_null($status) ? $status : "") . " " .
|
|
"GROUP BY f.`pdi_id` " .
|
|
"ORDER BY f.`cat`, s.`stig_id`"
|
|
;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
$ret = [];
|
|
while ($row = $res->fetch_assoc()) {
|
|
$find = new finding($row['id'], $row['tgt_id'], $row['pdi_id'], $row['scan_id'], $row['findings_status'], $row['notes'], $row['change_id'], $row['orig_src'], $row['finding_itr']);
|
|
$find->set_Category($row['cat']);
|
|
|
|
$sql2 = "SELECT `ia_control` FROM `sagacity`.`finding_controls` WHERE `finding_id` = " . $row['id'];
|
|
|
|
if ($res2 = $this->conn->query($sql2)) {
|
|
if ($res2->num_rows) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$find->add_IA_Control($row2['ia_control']);
|
|
}
|
|
}
|
|
else {
|
|
$sql2 = "SELECT CONCAT(`type`, '-', `type_id`) AS 'ia_control' FROM `sagacity`.`ia_controls` WHERE `pdi_id` = " . $row['pdi_id'];
|
|
if ($res2 = $this->conn->query($sql2)) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$find->add_IA_Control($row2['ia_control']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$ret[] = $find;
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function to return the host name of the targets that have this finding
|
|
*
|
|
* @param ste $ste
|
|
* @param pdi $pdi
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_Affected_Hosts_by_PDI($ste, $pdi)
|
|
{
|
|
$sql = "SELECT (SELECT GROUP_CONCAT(DISTINCT t.`name` SEPARATOR ', ')) AS 'name' " .
|
|
"FROM `sagacity`.`findings` f " .
|
|
"JOIN `sagacity`.`target` t ON f.`tgt_id` = t.`id` " .
|
|
"WHERE t.`ste_id` = " . $ste->get_ID() . " AND " .
|
|
"f.`pdi_id` = " . $pdi->get_ID()
|
|
;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
return $res->fetch_assoc()['name'];
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Function to return stigs that are not in the systems MAC and Classification
|
|
*
|
|
* @param ste $ste
|
|
*
|
|
* @return array:stig
|
|
*/
|
|
public function get_Findings_Not_in_System($ste)
|
|
{
|
|
$ret = [];
|
|
$this->help->create_table("unaccounted_for_findings", [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'datatype' => 'int(11)',
|
|
'option' => 'UNIQUE NOT NULL'
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$sql = "INSERT IGNORE INTO `unaccounted_for_findings` (`pdi_id`) SELECT DISTINCT(f.`pdi_id`) " .
|
|
"FROM `findings` f JOIN `target` t ON t.`id` = f.`tgt_id` " .
|
|
"WHERE t.`ste_id` = " . $ste->get_ID();
|
|
$this->conn->real_query($sql);
|
|
|
|
$class = 'cl';
|
|
if ($ste->get_System()->get_Classification() == 'Public') {
|
|
$class = 'pub';
|
|
}
|
|
elseif ($ste->get_System()->get_Classification() == 'Sensitive') {
|
|
$class = 'sen';
|
|
}
|
|
|
|
$sql = "DELETE FROM `unaccounted_for_findings` WHERE `pdi_id` IN (SELECT ia.`pdi_id` " .
|
|
"FROM `proc_level_type` plt " .
|
|
"JOIN `ia_controls` ia ON CONCAT(ia.`type`, '-', ia.`type_id`) = plt.`proc_control` " .
|
|
"WHERE " .
|
|
"plt.`level` = " . $ste->get_System()->get_MAC() . " AND " .
|
|
"plt.`class` = '$class')";
|
|
$this->conn->real_query($sql);
|
|
|
|
$sql = "SELECT s.`stig_id` FROM `unaccounted_for_findings` uaf JOIN `stigs` s ON s.`pdi_id` = uaf.`pdi_id`";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$stig = $this->get_Stig($row['stig_id']);
|
|
if (is_array($stig) && count($stig) && isset($stig[0]) && is_a($stig[0], 'stig')) {
|
|
$stig = $stig[0];
|
|
}
|
|
if (!preg_match("/^\d{5}$/", $stig->get_ID())) {
|
|
$ret[] = $stig;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get count of all findings with the status passed in
|
|
*
|
|
* @param integer $cat_id
|
|
* The category we are searching
|
|
* @param string $status
|
|
* The status to look for
|
|
* @param integer $cat [optional]
|
|
* The CAT/severity level
|
|
* @param proc_ia_controls $ctrl [optional]
|
|
* A IA control to filter for
|
|
*
|
|
* @return integer
|
|
* Returns the number of findings in the category that have the passed in status, severity, and control
|
|
*/
|
|
public function get_Finding_Count_By_Status($cat_id, $status, $cat = null, $ctrl = null)
|
|
{
|
|
$joins = [
|
|
"JOIN target_checklist tc ON t.id = tc.tgt_id",
|
|
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id",
|
|
"LEFT JOIN findings f ON f.pdi_id = pcl.pdi_id AND t.id = f.tgt_id",
|
|
"LEFT JOIN findings_status fs ON fs.id = f.findings_status_id"
|
|
];
|
|
if (!is_null($ctrl)) {
|
|
$joins[] = "JOIN finding_controls fc ON fc.finding_id = f.id";
|
|
}
|
|
|
|
$where = [
|
|
[
|
|
'field' => 't.cat_id',
|
|
'value' => $cat_id
|
|
],
|
|
[
|
|
'field' => 'fs.status',
|
|
'value' => $status,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
]
|
|
];
|
|
|
|
if ($status == 'Not Reviewed') {
|
|
$where[] = [
|
|
'field' => 'fs.status',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
|
|
if (!is_null($cat) && is_numeric($cat)) {
|
|
$where[] = [
|
|
'field' => 'f.cat',
|
|
'value' => $cat,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
|
|
$where[] = [
|
|
'field' => 'fc.ia_control',
|
|
'value' => $ctrl->get_Control_ID(),
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$field = ($status == 'Not Reviewed' ? "COUNT(DISTINCT(pcl.pdi_id)) AS 'count'" : "COUNT(DISTINCT(f.id)) AS 'count'");
|
|
$this->help->select_count("target t", $where, ['table_joins' => $joins]);
|
|
$this->help->sql = str_replace("COUNT(1) AS 'count'", $field, $this->help->sql);
|
|
|
|
$cnt = $this->help->execute();
|
|
|
|
$joins = [
|
|
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = c.id",
|
|
"JOIN findings f ON f.pdi_id = pcl.pdi_id",
|
|
"LEFT JOIN findings_status fs ON f.findings_status_id = fs.id",
|
|
"JOIN target t ON t.id = f.tgt_id"
|
|
];
|
|
|
|
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
|
|
$joins[] = "JOIN finding_controls fc ON fc.finding_id = f.id";
|
|
}
|
|
|
|
$where = [
|
|
[
|
|
'field' => 't.cat_id',
|
|
'value' => $cat_id
|
|
],
|
|
[
|
|
'field' => 'c.name',
|
|
'value' => 'Orphan',
|
|
'sql_op' => 'AND'
|
|
],
|
|
[
|
|
'field' => 'fs.status',
|
|
'value' => $status,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
]
|
|
];
|
|
|
|
if ($status == 'Not Reviewed') {
|
|
$where[] = [
|
|
'field' => 'fs.status',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
else {
|
|
$where[] =[
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
|
|
if (!is_null($cat) && is_numeric($cat)) {
|
|
$where[] = [
|
|
'field' => 'f.cat',
|
|
'value' => $cat,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
|
|
$where[] = [
|
|
'field' => 'fc.ia_control',
|
|
'value' => $ctrl->get_Control_ID(),
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select_count("checklist c", $where, array('table_joins' => $joins));
|
|
$this->help->sql = str_replace("COUNT(1) AS 'count'", $field, $this->help->sql);
|
|
|
|
$cnt += $this->help->execute();
|
|
|
|
return $cnt;
|
|
}
|
|
|
|
/**
|
|
* Get count of all findings with the status passed in
|
|
*
|
|
* @param ste $ste
|
|
* The category we are searching
|
|
* @param string $status
|
|
* The status to look for
|
|
* @param integer $cat
|
|
* The CAT/severity level
|
|
* @param proc_ia_controls $ctrl
|
|
* A IA control to filter for
|
|
*
|
|
* @return integer
|
|
* Returns the number of findings with status
|
|
*/
|
|
public function get_STE_Finding_Count_By_Status($ste, $status, $cat = null, $ctrl = null)
|
|
{
|
|
$sql = "SELECT " .
|
|
($status == 'Not Reviewed' ? "(SELECT COUNT(DISTINCT(pcl.`pdi_id`))" : "(SELECT COUNT(DISTINCT(f.`id`))") .
|
|
"FROM `sagacity`.`target` t " .
|
|
"LEFT JOIN `sagacity`.`target_checklist` tc ON t.`id` = tc.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = tc.`chk_id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` AND t.`id` = f.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON fs.`id` = f.`findings_status_id` " .
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "") .
|
|
"WHERE t.`ste_id` = " . $this->conn->real_escape_string($ste->get_ID()) . " AND " .
|
|
"(fs.`status` = '" . $this->conn->real_escape_string($status) . "' " .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") " .
|
|
(!is_null($cat) ? "AND f.`cat` = $cat " : "") .
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' " : "") .
|
|
")" .
|
|
" + " .
|
|
($status == 'Not Reviewed' ? "(SELECT COUNT(DISTINCT(pcl.`pdi_id`))" : "(SELECT COUNT(DISTINCT(f.`id`))") .
|
|
"FROM `sagacity`.`checklist` c " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = c.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON f.`findings_status_id` = fs.`id` " .
|
|
"JOIN `sagacity`.`target` t ON t.`id` = f.`tgt_id` " .
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "") .
|
|
"WHERE t.`ste_id` = " . $this->conn->real_escape_string($ste->get_ID()) . " AND " .
|
|
"c.`name` = 'Orphan' AND " .
|
|
"(fs.`status` = '" . $this->conn->real_escape_string($status) . "' " .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") " .
|
|
(!is_null($cat) ? "AND f.`cat` = $cat " : "") .
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' " : "") .
|
|
") AS 'sum_count'";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
return $res->fetch_assoc()['sum_count'];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get count of all findings with the status passed in
|
|
*
|
|
* @param target $tgt
|
|
* The target we are searching
|
|
* @param string $status
|
|
* The status to look for
|
|
* @param integer $cat [optional]
|
|
* The CAT/severity level
|
|
* @param proc_ia_controls $ctrl [optional]
|
|
* A IA control to filter for
|
|
* @param array $chk_ids [optional]
|
|
* @param boolean $is_orphan [optional]
|
|
*
|
|
* @return integer
|
|
* Returns the number of findings with status 'False Positives'
|
|
*/
|
|
public function get_Host_Finding_Count_By_Status($tgt, $status, $cat = null, $ctrl = null, $chk_ids = null, $is_orphan = false)
|
|
{
|
|
if (!$is_orphan) {
|
|
$sql = "SELECT (SELECT COUNT(DISTINCT(pcl.`pdi_id`)) " .
|
|
"FROM `sagacity`.`target` t " .
|
|
"LEFT JOIN `sagacity`.`target_checklist` tc ON t.`id` = tc.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = tc.`chk_id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` AND t.`id` = f.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON fs.`id` = f.`findings_status_id` " .
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "") .
|
|
"WHERE t.`id` = " . $this->conn->real_escape_string($tgt->get_ID()) . " AND " .
|
|
"(fs.`status` = '" . $this->conn->real_escape_string($status) . "' " .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") " .
|
|
(!is_null($cat) ? "AND f.`cat` = $cat " : "") .
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' " : "") .
|
|
(!is_null($chk_ids) ? "AND pcl.`checklist_id` IN (" . implode(", ", $chk_ids) . ") " : "") .
|
|
")";
|
|
}
|
|
else {
|
|
$sql = "SELECT (SELECT COUNT(DISTINCT(pcl.`pdi_id`)) " .
|
|
"FROM `sagacity`.`checklist` c " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = c.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON f.`findings_status_id` = fs.`id` " .
|
|
"JOIN `sagacity`.`target` t ON t.`id` = f.`tgt_id` " .
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "") .
|
|
"WHERE t.`id` = " . $this->conn->real_escape_string($tgt->get_ID()) . " AND " .
|
|
"c.`name` = 'Orphan' AND " .
|
|
"(fs.`status` = '" . $this->conn->real_escape_string($status) . "' " .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") " .
|
|
(!is_null($cat) ? "AND f.`cat` = $cat " : "") .
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' " : "") .
|
|
")";
|
|
}
|
|
$sql .= " AS 'sum_count'";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
return $res->fetch_assoc()['sum_count'];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function for getting number of targets that have a finding in this control
|
|
*
|
|
* @param ia_control $ctrl
|
|
* @param ste $ste
|
|
* @param string $status
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_Control_Finding_Count($ctrl, $ste, $status, $cat = null)
|
|
{
|
|
$sql = "SELECT " .
|
|
"IFNULL((SELECT COUNT(1) " .
|
|
"FROM `target` t " .
|
|
"LEFT JOIN `target_checklist` tc ON t.`id` = tc.`tgt_id` " .
|
|
"LEFT JOIN `pdi_checklist_lookup` pcl ON pcl.`checklist_id` = tc.`chk_id` " .
|
|
"LEFT JOIN `findings` f ON f.`pdi_id` = pcl.`pdi_id` AND t.`id` = f.`tgt_id` " .
|
|
"LEFT JOIN `findings_status` fs ON fs.`id` = f.`findings_status_id` " .
|
|
"LEFT JOIN `finding_controls` fc ON fc.`finding_id` = f.`id` " .
|
|
"WHERE " .
|
|
"(fs.`status` = '$status' " .
|
|
($status == 'Open' ? " OR fs.`status` = 'Exception'" : "") .
|
|
($status == 'Not a Finding' ? " OR fs.`status` = 'Not Applicable'" : "") .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") AND " .
|
|
(!is_null($cat) ? "f.`cat` = $cat AND " : "") .
|
|
(!is_null($ctrl) ? "fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' AND " : "") .
|
|
"t.`ste_id` = $ste " .
|
|
"GROUP BY f.`pdi_id`" .
|
|
"), 0)" .
|
|
" + " .
|
|
"IFNULL((SELECT COUNT(1) " .
|
|
"FROM `checklist` c " .
|
|
"LEFT JOIN `pdi_checklist_lookup` pcl ON pcl.`checklist_id` = c.`id` " .
|
|
"LEFT JOIN `findings` f ON f.`pdi_id` = pcl.`pdi_id` " .
|
|
"LEFT JOIN `findings_status` fs ON f.`findings_status_id` = fs.`id` " .
|
|
"LEFT JOIN `target` t ON t.`id` = f.`tgt_id` " .
|
|
"LEFT JOIN `finding_controls` fc ON fc.`finding_id` = f.`id` " .
|
|
"WHERE " .
|
|
"c.`name` = 'Orphan' AND " .
|
|
"(fs.`status` = '$status' " .
|
|
($status == 'Open' ? " OR fs.`status` = 'Exception'" : "") .
|
|
($status == 'Not a Finding' ? " OR fs.`status` = 'Not Applicable'" : "") .
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "") .
|
|
") AND " .
|
|
(!is_null($cat) ? "f.`cat` = $cat AND " : "") .
|
|
(!is_null($ctrl) ? "fc.`ia_control` = '" . $ctrl->get_Control_ID() . "' AND " : "") .
|
|
"t.`ste_id` = $ste " .
|
|
"GROUP BY f.`pdi_id`" .
|
|
"), 0) AS 'sum_count'";
|
|
/*
|
|
$sql = "SELECT ".
|
|
"(SELECT COUNT(DISTINCT(f.`tgt_id`))".
|
|
"FROM `targets`.`target` t ".
|
|
"LEFT JOIN `targets`.`target_checklist` tc ON t.`id` = tc.`tgt_id` ".
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = tc.`chk_id` ".
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` AND t.`id` = f.`tgt_id` ".
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON fs.`id` = f.`findings_status_id` ".
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "").
|
|
"WHERE t.`ste_id` = ".$this->conn->real_escape_string($ste->get_ID())." AND ".
|
|
"(fs.`status` = '".$this->conn->real_escape_string($status)."' ".
|
|
($status == 'Open' ? " OR fs.`status` = 'Exception'" : "").
|
|
($status == 'Not a Finding' ? " OR fs.`status` = 'Not Applicable'" : "").
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "").
|
|
") ".
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '".$ctrl->get_Control_ID()."' " : "").
|
|
")".
|
|
|
|
" + ".
|
|
|
|
"(SELECT COUNT(DISTINCT(f.`tgt_id`))".
|
|
"FROM `sagacity`.`checklist` c ".
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = c.`id` ".
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` ".
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON f.`findings_status_id` = fs.`id` ".
|
|
"JOIN `targets`.`target` t ON t.`id` = f.`tgt_id` ".
|
|
(!is_null($ctrl) ? "JOIN `sagacity`.`finding_controls` fc ON fc.`finding_id` = f.`id` " : "").
|
|
"WHERE t.`ste_id` = ".$this->conn->real_escape_string($ste->get_ID())." AND ".
|
|
"c.`name` = 'Orphan' AND ".
|
|
"(fs.`status` = '".$this->conn->real_escape_string($status)."' ".
|
|
($status == 'Open' ? " OR fs.`status` = 'Exception'" : "").
|
|
($status == 'Not a Finding' ? " OR fs.`status` = 'Not Applicable'" : "").
|
|
($status == 'Not Reviewed' ? " OR fs.`status` IS NULL" : "").
|
|
") ".
|
|
(!is_null($ctrl) ? "AND fc.`ia_control` = '".$ctrl->get_Control_ID()."' " : "").
|
|
") AS 'sum_count'";
|
|
*/
|
|
if ($res = $this->conn->query($sql)) {
|
|
return $res->fetch_assoc()['sum_count'];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving the notes from a particular finding
|
|
*
|
|
* @param integer $pdi_id
|
|
* @param integer $tgt_id
|
|
*
|
|
* @return string|NULL
|
|
*/
|
|
public function get_Finding_Notes($pdi_id, $tgt_id)
|
|
{
|
|
$sql = "SELECT f.`notes` FROM `sagacity`.`findings` f " .
|
|
"WHERE f.`pdi_id` = " . $this->conn->real_escape_string($pdi_id) .
|
|
" AND f.`tgt_id` = " . $this->conn->real_escape_string($tgt_id);
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if ($res->num_rows) {
|
|
$row = $res->fetch_assoc();
|
|
return $row['notes'];
|
|
}
|
|
}
|
|
else {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function to determine how pervasive a finding is across all targets
|
|
*
|
|
* @TODO - FINISH
|
|
*
|
|
* @param ste $ste
|
|
* @param proc_ia_controls $ia_ctrl
|
|
* @param string $status
|
|
*/
|
|
public function get_Finding_Pervasivity_by_Control($ste, $ia_ctrl, $status = null)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Function to return all the possible finding statuses
|
|
*
|
|
* @return array:finding_status
|
|
*/
|
|
public function get_Finding_Statuses()
|
|
{
|
|
$sql = "SELECT `id`, `status` " .
|
|
"FROM `sagacity`.`findings_status`";
|
|
$ret = [];
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$status = new finding_status();
|
|
$status->id = $row['id'];
|
|
$status->status = $row['status'];
|
|
|
|
$ret[] = $status;
|
|
}
|
|
}
|
|
else {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to compare the findings from two different targets
|
|
*
|
|
* @param target $left_tgt
|
|
* @param target $right_tgt
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_Finding_Comparrison($left_tgt, $right_tgt)
|
|
{
|
|
$ret = [];
|
|
$left_sql = "SELECT " .
|
|
"s.`stig_id`, pcl.`check_contents`, " .
|
|
"tgt.`id` AS 'tgt_id', tgt.`name` AS 'tgt_name', " .
|
|
"IF(f.`cat` IS NULL, pdi.`cat`, f.`cat`) AS 'cat', f.`notes`, " .
|
|
"IF(f.`findings_status_id` IS NULL, 'Not Reviewed', fs.`status`) AS 'finding_status', " .
|
|
"(SELECT GROUP_CONCAT(fc.`ia_control` SEPARATOR ' ') " .
|
|
"FROM `sagacity`.`finding_controls` fc " .
|
|
"WHERE fc.`finding_id` = f.`id`) AS 'finding_ia_controls', " .
|
|
"(SELECT GROUP_CONCAT(DISTINCT CONCAT(ia.`type`, '-', ia.`type_id`) SEPARATOR ' ') " .
|
|
"FROM `sagacity`.`ia_controls` ia " .
|
|
"WHERE ia.`pdi_id` = pcl.`pdi_id`) AS 'ia_controls' " .
|
|
"FROM `sagacity`.`checklist` chk " .
|
|
"JOIN `sagacity`.`target_checklist` tc ON tc.`chk_id` = chk.`id` " .
|
|
"JOIN `sagacity`.`target` tgt ON tgt.`id` = tc.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = chk.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` AND f.`tgt_id` = tgt.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON fs.`id` = f.`findings_status_id` " .
|
|
"LEFT JOIN `sagacity`.`stigs` s ON s.`pdi_id` = pcl.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_catalog` pdi ON pdi.`id` = pcl.`pdi_id` " .
|
|
"WHERE tgt.`id` = " . $left_tgt->get_ID() . " " .
|
|
"GROUP BY s.`stig_id`, tgt.`name` " .
|
|
"ORDER BY s.`stig_id`, FIELD(chk.`type`, 'manual', 'iavm', 'policy', 'benchmark')";
|
|
$right_sql = "SELECT " .
|
|
"s.`stig_id`, pcl.`check_contents`, " .
|
|
"tgt.`id` AS 'tgt_id', tgt.`name` AS 'tgt_name', " .
|
|
"IF(f.`cat` IS NULL, pdi.`cat`, f.`cat`) AS 'cat', f.`notes`, " .
|
|
"IF(f.`findings_status_id` IS NULL, 'Not Reviewed', fs.`status`) AS 'finding_status', " .
|
|
"(SELECT GROUP_CONCAT(fc.`ia_control` SEPARATOR ' ') " .
|
|
"FROM `sagacity`.`finding_controls` fc " .
|
|
"WHERE fc.`finding_id` = f.`id`) AS 'finding_ia_controls', " .
|
|
"(SELECT GROUP_CONCAT(DISTINCT CONCAT(ia.`type`, '-', ia.`type_id`) SEPARATOR ' ') " .
|
|
"FROM `sagacity`.`ia_controls` ia " .
|
|
"WHERE ia.`pdi_id` = pcl.`pdi_id`) AS 'ia_controls' " .
|
|
"FROM `sagacity`.`checklist` chk " .
|
|
"JOIN `sagacity`.`target_checklist` tc ON tc.`chk_id` = chk.`id` " .
|
|
"JOIN `sagacity`.`target` tgt ON tgt.`id` = tc.`tgt_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` pcl ON pcl.`checklist_id` = chk.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings` f ON f.`pdi_id` = pcl.`pdi_id` AND f.`tgt_id` = tgt.`id` " .
|
|
"LEFT JOIN `sagacity`.`findings_status` fs ON fs.`id` = f.`findings_status_id` " .
|
|
"LEFT JOIN `sagacity`.`stigs` s ON s.`pdi_id` = pcl.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_catalog` pdi ON pdi.`id` = pcl.`pdi_id` " .
|
|
"WHERE tgt.`id` = " . $right_tgt->get_ID() . " " .
|
|
"GROUP BY s.`stig_id`, tgt.`name` " .
|
|
"ORDER BY s.`stig_id`, FIELD(chk.`type`, 'manual', 'iavm', 'policy', 'benchmark')";
|
|
|
|
if ($res = $this->conn->query($left_sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret['left'][$row['stig_id']] = array(
|
|
'stig_id' => $row['stig_id'],
|
|
'cat' => $row['cat'],
|
|
'ia_controls' => (!empty($row['finding_ia_controls']) ? $row['finding_ia_controls'] : $row['ia_controls']),
|
|
'status' => $row['finding_status'],
|
|
'notes' => $row['notes']
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($res = $this->conn->query($right_sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret['right'][$row['stig_id']] = array(
|
|
'stig_id' => $row['stig_id'],
|
|
'cat' => $row['cat'],
|
|
'ia_controls' => (!empty($row['finding_ia_controls']) ? $row['finding_ia_controls'] : $row['ia_controls']),
|
|
'status' => $row['finding_status'],
|
|
'notes' => $row['notes']
|
|
);
|
|
|
|
if (!isset($ret['left'][$row['stig_id']])) {
|
|
$ret['left'][$row['stig_id']] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// @TODO - modify to accept finding and array:finding
|
|
/**
|
|
* Add a finding
|
|
*
|
|
* @param scan $scan
|
|
* Scan that found this item
|
|
* @param array:target|target $tgts
|
|
* Array of targets or a single target that have this finding
|
|
* @param array|finding $finding_data
|
|
* Array of data associated with the finding<br />
|
|
* [0] => 'stig id'<br />
|
|
* [1] => 'vms id'<br />
|
|
* [2] => 'category level (I, II, III)'<br />
|
|
* [3] => 'ia controls (space delimited)'<br />
|
|
* [4] => 'short title'<br />
|
|
* [5...n] => 'target status'<br />
|
|
* [n+1] => 'notes'<br />
|
|
* [n+2] => 'check contents'<br />
|
|
* [n+3] => 'missing pdi'
|
|
*/
|
|
public function add_Finding($scan, $tgts, $finding_data)
|
|
{
|
|
global $cmd;
|
|
set_time_limit(0);
|
|
$host_count = 0;
|
|
$ref = null;
|
|
|
|
if (is_array($tgts)) {
|
|
$host_count = count($tgts);
|
|
}
|
|
else {
|
|
$host_count++;
|
|
}
|
|
|
|
if (preg_match('/\d\.\d+/', $finding_data[0])) {
|
|
$finding_data[0] = str_pad($finding_data[0], 5, "0");
|
|
}
|
|
$stig_id = $finding_data[0];
|
|
$vms_id = preg_replace("/V0+/i", "V-", $finding_data[1]);
|
|
$cat_lvl = substr_count($finding_data[2], 'I');
|
|
$ia_controls = $finding_data[3];
|
|
$short_title = $finding_data[4];
|
|
$notes = $finding_data[self::FIRST_ECHECKLIST_HOST_COL + $host_count];
|
|
|
|
if (preg_match('/SV\-.*_rule/', $stig_id)) {
|
|
$ref = $this->get_SV_Rule(null, $stig_id);
|
|
}
|
|
elseif (preg_match('/CVE\-\d{4}\-\d+/', $stig_id)) {
|
|
$ref = [0 => $this->get_CVE($stig_id)];
|
|
}
|
|
elseif (preg_match('/\d{4}\-[ABT]\-\d+/', $stig_id)) {
|
|
$ref = [0 => $this->get_IAVM($stig_id)];
|
|
}
|
|
|
|
if (is_null($ref) && $stig_id != 'No Reference') {
|
|
$ref = $this->get_Stig($stig_id);
|
|
}
|
|
|
|
if (is_null($ref) && $vms_id != 'No Reference') {
|
|
$ref = $this->get_GoldDisk($vms_id);
|
|
}
|
|
|
|
if (is_array($ref) && count($ref) && isset($ref[0])) {
|
|
$ref = $ref[0];
|
|
}
|
|
else {
|
|
// add a new checklist entry
|
|
$pdi = new pdi(null, $cat_lvl, 'NOW', $short_title, $short_title);
|
|
$pdi_id = $this->save_PDI($pdi);
|
|
|
|
$stig = new stig($pdi_id, $stig_id, $short_title);
|
|
$ref = $stig;
|
|
$this->add_Stig($stig);
|
|
|
|
$golddisk = new golddisk($pdi_id, $vms_id, $short_title);
|
|
if ($vms_id != 'No Reference') {
|
|
$this->save_GoldDisk($golddisk);
|
|
}
|
|
}
|
|
|
|
if (is_array($tgts)) {
|
|
$updated_finding = [];
|
|
$new_finding = [];
|
|
$x = 0;
|
|
foreach ($tgts as $tgt) {
|
|
switch (strtolower(str_replace('_', ' ', $finding_data[self::FIRST_ECHECKLIST_HOST_COL + $x]))) {
|
|
case 'not reviewed':
|
|
case 'not a finding':
|
|
case 'open':
|
|
case 'not applicable':
|
|
case 'no data':
|
|
case 'exception':
|
|
case 'false positive':
|
|
$status = $finding_data[self::FIRST_ECHECKLIST_HOST_COL + $x];
|
|
break;
|
|
default:
|
|
$status = 'Not Reviewed';
|
|
}
|
|
|
|
$current_finding = $this->get_Finding($tgt, $ref);
|
|
if (is_array($current_finding) && count($current_finding) > 0) {
|
|
$current_finding = $current_finding[0];
|
|
}
|
|
|
|
$current_status = '';
|
|
|
|
if ($current_finding != null) {
|
|
$current_status = $current_finding->get_Finding_Status_String();
|
|
//$current_source = $current_finding->get();
|
|
|
|
if ($current_status != $status) {
|
|
$current_notes = $current_finding->get_Notes();
|
|
if (!$current_notes) {
|
|
$current_finding->set_Notes($notes);
|
|
}
|
|
else {
|
|
if ($notes && stristr($current_notes, $notes) === false) {
|
|
$current_finding->prepend_Notes($current_notes);
|
|
}
|
|
}
|
|
|
|
if (($current_status == 'Open' || $status == 'Open') &&
|
|
($current_status == 'Not Applicable' || $current_status == 'Not a Finding' ||
|
|
$status == 'Not Applicable' || $status == 'Not a Finding')) {
|
|
$current_finding->set_Notes("OPEN CONFLICT: $current_status/$status\n$notes");
|
|
|
|
$current_finding->set_Change_ID(finding::TO_OPEN);
|
|
}
|
|
elseif (($current_status == 'Not a Finding' || $current_status == 'Not Applicable') &&
|
|
($status == 'Not a Finding' || $status == 'Not Applicable')) {
|
|
$current_finding->set_Notes("NF/NA CONFLICT: $current_status/$status\n$notes");
|
|
|
|
$current_finding->set_Change_ID(finding::TO_NF);
|
|
}
|
|
else {
|
|
$current_finding->set_Change_ID(finding::NC);
|
|
}
|
|
|
|
$new_status = $current_finding->get_Deconflicted_Status($status);
|
|
$new_status_id = $current_finding->get_Finding_Status_ID($new_status);
|
|
$current_finding->set_Finding_Status($new_status_id);
|
|
|
|
$current_finding->set_Original_Source($scan->get_Source()->get_Name());
|
|
$current_finding->set_Finding_Iteration($current_finding->get_Finding_Iteration() + 1);
|
|
$current_finding->set_Scan_ID($scan->get_ID());
|
|
$current_finding->set_Category($cat_lvl);
|
|
$current_finding->set_IA_Controls($ia_controls);
|
|
|
|
$updated_finding[] = $current_finding;
|
|
}
|
|
else {
|
|
$current_notes = $current_finding->get_Notes();
|
|
if (!$current_notes) {
|
|
$current_finding->set_Notes($notes);
|
|
}
|
|
else {
|
|
if ($notes && stristr($current_notes, $notes) === false) {
|
|
$current_finding->set_Notes($current_notes . PHP_EOL . $notes);
|
|
}
|
|
}
|
|
|
|
$current_finding->set_Change_ID(finding::NC);
|
|
$current_finding->set_Original_Source($scan->get_Source()->get_Name());
|
|
$current_finding->set_Finding_Iteration($current_finding->get_Finding_Iteration() + 1);
|
|
$current_finding->set_Scan_ID($scan->get_ID());
|
|
$current_finding->set_Category($cat_lvl);
|
|
$current_finding->set_IA_Controls($ia_controls);
|
|
|
|
$updated_finding[] = $current_finding;
|
|
}
|
|
}
|
|
else {
|
|
$new = new finding(null, $tgt->get_ID(), $ref->get_PDI_ID(), $scan->get_ID(), $status, $notes, 0, null, 1);
|
|
$new->set_Category($cat_lvl);
|
|
$new->set_IA_Controls($ia_controls);
|
|
|
|
$new_finding[] = $new;
|
|
}
|
|
|
|
if ($status == 'False Positive') {
|
|
$match = [];
|
|
if (preg_match("/\(FP\-([a-zA-Z \-]+)\)/i", $notes, $match)) {
|
|
$src = $match[1];
|
|
//$src = str_replace("_", " ", $match[1]);
|
|
$sql = "REPLACE INTO `false_positives` (`pdi_id`, `src_id`, `notes`) VALUES (" .
|
|
$this->conn->real_escape_string($ref->get_PDI_ID()) . ", " .
|
|
"(SELECT `id` FROM `sources` WHERE `name` = '" . $this->conn->real_escape_string($src) . "'), " .
|
|
"'Common FP for $src')";
|
|
|
|
if (!$this->conn->real_query($sql)) {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
if (isset($cmd['debug'])) {
|
|
Sagacity_Error::err_handler("Added " . $ref->get_PDI_ID() . " to FP list for $src");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($status == 'Exception') {
|
|
$ste = $this->get_STE($tgt->get_STE_ID())[0];
|
|
|
|
$sql = "REPLACE INTO `exceptions` (`pdi_id`, `sys_id`, `notes`) VALUES (" .
|
|
$this->conn->real_escape_string($ref->get_PDI_ID()) . ", " .
|
|
$this->conn->real_escape_string($ste->get_System()->get_ID()) . ", " .
|
|
"'')";
|
|
|
|
if (!$this->conn->real_query($sql)) {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
if (isset($cmd['debug'])) {
|
|
Sagacity_Error::err_handler("Added exception " . $ref->get_PDI_ID());
|
|
}
|
|
}
|
|
|
|
$x++;
|
|
}
|
|
|
|
$notes = (isset($current_finding) && is_array($current_finding) && count($current_finding) ? $current_finding->get_Notes() . " " . $notes : $notes);
|
|
|
|
if (isset($updated_finding) && is_array($updated_finding) && count($updated_finding) > 0) {
|
|
foreach ($updated_finding as $finding) {
|
|
$update_sql = "UPDATE `findings` SET " .
|
|
"`scan_id` = " . $this->conn->real_escape_string($finding->get_Scan_ID()) . ", " .
|
|
"`findings_status_id` = " . $this->conn->real_escape_string($finding->get_Finding_Status()) . ", " .
|
|
"`notes` = '" . $this->conn->real_escape_string($finding->get_Notes()) . "', " .
|
|
"`change_id` = " . $this->conn->real_escape_string($finding->get_Change_ID()) . ", " .
|
|
"`orig_src` = '" . $this->conn->real_escape_string($finding->get_Original_Source()) . "', " .
|
|
"`finding_itr` = " . $this->conn->real_escape_string($finding->get_Finding_Iteration()) . ", " .
|
|
"`cat` = " . $this->conn->real_escape_string($finding->get_Category()) .
|
|
" WHERE `id` = " . $this->conn->real_escape_string($finding->get_ID());
|
|
|
|
$this->conn->ping();
|
|
|
|
if (!$this->conn->real_query($update_sql)) {
|
|
Sagacity_Error::sql_handler($update_sql);
|
|
error_log($this->conn->error);
|
|
return false;
|
|
}
|
|
|
|
$this->conn->real_query("DELETE FROM `finding_controls` WHERE `finding_id` = " . $finding->get_ID());
|
|
|
|
$sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES ";
|
|
foreach ($finding->get_IA_Controls() as $ia) {
|
|
$sql2 .= "({$this->conn->real_escape_string($finding->get_ID())}, " .
|
|
"'{$this->conn->real_escape_string($ia)}'),";
|
|
}
|
|
$sql2 = substr($sql2, 0, -1);
|
|
if (strlen($sql2) > 74) {
|
|
$this->conn->real_query($sql2);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($new_finding) && count($new_finding) > 0) {
|
|
foreach ($new_finding as $finding) {
|
|
$insert_sql = "INSERT INTO `findings` (`tgt_id`, `pdi_id`, `scan_id`, `findings_status_id`, `cat`, `notes`) VALUES " .
|
|
"(" . $this->conn->real_escape_string($finding->get_Tgt_ID()) . ", " .
|
|
$this->conn->real_escape_string($finding->get_PDI_ID()) . ", " .
|
|
$this->conn->real_escape_string($finding->get_Scan_ID()) . ", " .
|
|
$this->conn->real_escape_string($finding->get_Finding_Status()) . ", " .
|
|
$this->conn->real_escape_string($finding->get_Category()) . ", " .
|
|
"'" . $this->conn->real_escape_string($finding->get_Notes()) . "')";
|
|
|
|
$this->conn->ping();
|
|
|
|
if (strlen($insert_sql) > 103) {
|
|
if (!$this->conn->real_query($insert_sql)) {
|
|
Sagacity_Error::sql_handler($insert_sql);
|
|
error_log($this->conn->error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$find_id = $this->conn->insert_id;
|
|
|
|
$sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES ";
|
|
foreach ($finding->get_IA_Controls() as $ia) {
|
|
$sql2 .= "({$this->conn->real_escape_string($find_id)}, " .
|
|
"'{$this->conn->real_escape_string($ia)}'),";
|
|
}
|
|
$sql2 = substr($sql2, 0, -1);
|
|
if (strlen($sql2) > 74) {
|
|
$this->conn->real_query($sql2);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else {
|
|
$updated_finding = null;
|
|
$new_finding = null;
|
|
switch (strtolower(str_replace('_', ' ', $finding_data[self::FIRST_ECHECKLIST_HOST_COL]))) {
|
|
case 'not reviewed':
|
|
case 'not a finding':
|
|
case 'open':
|
|
case 'not applicable':
|
|
case 'no data':
|
|
case 'exception':
|
|
case 'false positive':
|
|
$status = str_replace('_', ' ', $finding_data[self::FIRST_ECHECKLIST_HOST_COL]);
|
|
break;
|
|
default:
|
|
$status = 'Not Reviewed';
|
|
}
|
|
|
|
$current_finding = $this->get_Finding($tgts, $ref);
|
|
if (is_array($current_finding) && count($current_finding) > 0) {
|
|
$current_finding = $current_finding[0];
|
|
}
|
|
|
|
$current_status = '';
|
|
|
|
if (is_array($current_finding) && count($current_finding)) {
|
|
$current_status = $current_finding->get_Finding_Status_String();
|
|
//$current_source = $current_finding->get();
|
|
|
|
if ($current_status != $status) {
|
|
$current_notes = $current_finding->get_Notes();
|
|
if (!$current_notes) {
|
|
$current_finding->set_Notes($notes);
|
|
}
|
|
else {
|
|
if ($notes && stristr($current_notes, $notes) === false) {
|
|
$current_finding->set_Notes($current_notes . PHP_EOL . $notes);
|
|
}
|
|
}
|
|
|
|
if (($current_status == 'Open' || $status == 'Open') &&
|
|
($current_status == 'Not Applicable' || $current_status == 'Not a Finding' ||
|
|
$status == 'Not Applicable' || $status == 'Not a Finding')) {
|
|
$current_finding->set_Notes("OPEN CONFLICT: $current_status/$status\n$notes");
|
|
|
|
$current_finding->set_Change_ID(finding::TO_OPEN);
|
|
}
|
|
elseif (($current_status == 'Not a Finding' || $current_status == 'Not Applicable') &&
|
|
($status == 'Not a Finding' || $status == 'Not Applicable')) {
|
|
$current_finding->set_Notes("NF/NA CONFLICT: $current_status/$status\n$notes");
|
|
|
|
$current_finding->set_Change_ID(finding::TO_NF);
|
|
}
|
|
else {
|
|
$current_finding->set_Change_ID(finding::NC);
|
|
}
|
|
|
|
$new_status = $current_finding->get_Deconflicted_Status($status);
|
|
$new_status_id = $current_finding->get_Finding_Status_ID($new_status);
|
|
$current_finding->set_Finding_Status($new_status_id);
|
|
|
|
$current_finding->set_Original_Source($scan->get_Source()->get_Name());
|
|
$current_finding->set_Finding_Iteration($current_finding->get_Finding_Iteration() + 1);
|
|
$current_finding->set_Scan_ID($scan->get_ID());
|
|
|
|
$updated_finding = $current_finding;
|
|
}
|
|
else {
|
|
$current_notes = $current_finding->get_Notes();
|
|
if (!$current_notes) {
|
|
$current_finding->set_Notes($notes);
|
|
}
|
|
else {
|
|
if ($notes && stristr($current_notes, $notes) === false) {
|
|
$current_finding->set_Notes($current_notes . PHP_EOL . $notes);
|
|
}
|
|
}
|
|
|
|
$current_finding->set_Change_ID(finding::NC);
|
|
$current_finding->set_Original_Source($scan->get_Source()->get_Name());
|
|
$current_finding->set_Finding_Iteration($current_finding->get_Finding_Iteration() + 1);
|
|
$current_finding->set_Scan_ID($scan->get_ID());
|
|
|
|
$updated_finding = $current_finding;
|
|
}
|
|
}
|
|
else {
|
|
$new_finding = new finding(null, $tgts->get_ID(), $ref->get_PDI_ID(), $scan->get_ID(), $status, $notes, 0, null, 1);
|
|
|
|
$new_finding->set_Category($cat_lvl);
|
|
$new_finding->set_IA_Controls($ia_controls);
|
|
}
|
|
|
|
$notes = (isset($current_finding) && is_array($current_finding) && count($current_finding) ? $current_finding->get_Notes() . " " . $notes : $notes);
|
|
|
|
if (isset($updated_finding) && !is_null($updated_finding)) {
|
|
$update_sql = "UPDATE `findings` SET " .
|
|
"`scan_id` = " . $this->conn->real_escape_string($updated_finding->get_Scan_ID()) . ", " .
|
|
"`findings_status_id` = " . $this->conn->real_escape_string($updated_finding->get_Finding_Status()) . ", " .
|
|
"`notes` = '" . $this->conn->real_escape_string($updated_finding->get_Notes()) . "', " .
|
|
"`change_id` = " . $this->conn->real_escape_string($updated_finding->get_Change_ID()) . ", " .
|
|
"`orig_src` = '" . $this->conn->real_escape_string($updated_finding->get_Original_Source()) . "', " .
|
|
"`finding_itr` = " . $this->conn->real_escape_string($updated_finding->get_Finding_Iteration()) . ", " .
|
|
"`cat` = " . $this->conn->real_escape_string($updated_finding->get_Category()) .
|
|
" WHERE `id` = " . $this->conn->real_escape_string($updated_finding->get_ID());
|
|
|
|
$this->conn->ping();
|
|
|
|
if (!$this->conn->real_query($update_sql)) {
|
|
Sagacity_Error::sql_handler($update_sql);
|
|
error_log($this->conn->error);
|
|
return false;
|
|
}
|
|
|
|
$this->conn->real_query("DELETE FROM `sagacity`.`finding_controls` WHERE `finding_id` = " . $updated_finding->get_ID());
|
|
|
|
$sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES ";
|
|
|
|
foreach ($updated_finding->get_IA_Controls() as $ia) {
|
|
$sql2 .= "(" .
|
|
$this->conn->real_escape_string($updated_finding->get_ID()) . ", " .
|
|
"'" . $this->conn->real_escape_string($ia) . "'), ";
|
|
}
|
|
|
|
$sql2 = substr($sql2, 0, -1);
|
|
|
|
$this->conn->real_query($sql2);
|
|
}
|
|
|
|
if (isset($new_finding) && !is_null($new_finding)) {
|
|
$insert_sql = "INSERT INTO `sagacity`.`findings` (`tgt_id`, `pdi_id`, `scan_id`, `findings_status_id`, `notes`, `cat`) VALUES " .
|
|
"(" . $this->conn->real_escape_string($new_finding->get_Tgt_ID()) . ", " .
|
|
$this->conn->real_escape_string($new_finding->get_PDI_ID()) . ", " .
|
|
$this->conn->real_escape_string($new_finding->get_Scan_ID()) . ", " .
|
|
$this->conn->real_escape_string($new_finding->get_Finding_Status()) . ", " .
|
|
"'" . $this->conn->real_escape_string($new_finding->get_Notes()) . "', " .
|
|
$this->conn->real_escape_string($new_finding->get_Category()) . ")";
|
|
|
|
$this->conn->ping();
|
|
|
|
if (strlen($insert_sql) > 97) {
|
|
if (!$this->conn->real_query($insert_sql)) {
|
|
Sagacity_Error::sql_handler($insert_sql);
|
|
error_log($this->conn->error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$find_id = $this->conn->insert_id;
|
|
|
|
$sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES ";
|
|
foreach ($new_finding->get_IA_Controls() as $ia) {
|
|
$sql2 .= "(" .
|
|
$this->conn->real_escape_string($find_id) . ", " .
|
|
"'" . $this->conn->real_escape_string($ia) . "'), ";
|
|
}
|
|
|
|
$sql2 = substr($sql2, 0, -1);
|
|
|
|
$this->conn->real_query($sql2);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to add findings to the database
|
|
*
|
|
* @param array:finding $updated_findings
|
|
* Array of findings to update
|
|
* @param array:finding $added_findings
|
|
* Array of findings to add to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function add_Findings_By_Target($updated_findings, $added_findings)
|
|
{
|
|
$fields = ['pdi_id', 'tgt_id', 'scan_id', 'findings_status_id', 'notes', 'cat'];
|
|
$ins_arr = [];
|
|
|
|
if (is_array($added_findings) && count($added_findings) && is_a(current($added_findings), 'finding')) {
|
|
$scan_id = current($added_findings)->get_Scan_ID();
|
|
|
|
foreach ($added_findings as $finding) {
|
|
$ins_arr[] = [
|
|
$finding->get_PDI_ID(),
|
|
$finding->get_Tgt_ID(),
|
|
$finding->get_Scan_ID(),
|
|
$finding->get_Finding_Status(),
|
|
$finding->get_Notes(),
|
|
$finding->get_Category()
|
|
];
|
|
}
|
|
|
|
if (is_array($ins_arr) && count($ins_arr)) {
|
|
$this->help->extended_insert('findings', $fields, $ins_arr, true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
|
|
$this->help->sql = "INSERT IGNORE INTO `finding_controls` (`finding_id`, `ia_control`) " .
|
|
"(SELECT f.`id`, " .
|
|
"(SELECT CONCAT(ia.`type`, '-', ia.`type_id`) " .
|
|
"FROM `ia_controls` ia " .
|
|
"WHERE ia.`pdi_id` = f.`pdi_id`) " .
|
|
"FROM `findings` f " .
|
|
"WHERE f.`scan_id` = $scan_id)"
|
|
;
|
|
$this->help->query_type = db_helper::INSERT;
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
|
|
$this->help->delete("finding_controls", null, [
|
|
[
|
|
'field' => 'ia_control',
|
|
'op' => '=',
|
|
'value' => ''
|
|
],
|
|
[
|
|
'field' => 'ia_control',
|
|
'op' => '=',
|
|
'value' => '-',
|
|
'sql_op' => 'OR'
|
|
],
|
|
[
|
|
'field' => 'ia_control',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR'
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
}
|
|
|
|
if (is_array($updated_findings) && count($updated_findings) && is_a(current($updated_findings), 'finding')) {
|
|
$this->help->create_table("tmp_findings", true, [
|
|
[
|
|
'field' => 'id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'tgt_id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'pdi_id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'scan_id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'findings_status_id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'change_id',
|
|
'datatype' => 'int(11)'
|
|
],
|
|
[
|
|
'field' => 'finding_itr',
|
|
'datatype' => 'int(5)'
|
|
],
|
|
[
|
|
'field' => 'cat',
|
|
'datatype' => 'int(1)'
|
|
],
|
|
[
|
|
'field' => 'notes',
|
|
'datatype' => 'text'
|
|
],
|
|
[
|
|
'field' => 'orig_src',
|
|
'datatype' => 'varchar(10)'
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
$upd_arr = [];
|
|
$update_fields = ['id', 'tgt_id', 'pdi_id', 'scan_id', 'findings_status_id', 'change_id', 'finding_itr', 'cat', 'notes', 'orig_src'];
|
|
foreach ($updated_findings as $finding) {
|
|
$upd_arr[] = [
|
|
$finding->get_ID(),
|
|
$finding->get_Tgt_ID(),
|
|
$finding->get_PDI_ID(),
|
|
$finding->get_Scan_ID(),
|
|
$finding->get_Finding_Status(),
|
|
$finding->get_Change_ID(),
|
|
$finding->get_Finding_Iteration(),
|
|
$finding->get_Category(),
|
|
$finding->get_Notes(),
|
|
$finding->get_Original_Source()
|
|
];
|
|
}
|
|
|
|
if (is_array($upd_arr) && count($upd_arr)) {
|
|
$this->help->extended_insert("tmp_findings", $update_fields, $upd_arr, true);
|
|
$this->help->execute();
|
|
|
|
$this->help->extended_update('findings', 'tmp_findings', 'id', $update_fields);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to update a finding status and notes
|
|
*
|
|
* @param finding $find
|
|
* The finding to update
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function update_Finding($find)
|
|
{
|
|
if ($find->get_ID()) {
|
|
$this->help->update("sagacity.findings", array(
|
|
'findings_status_id' => $find->get_Finding_Status(),
|
|
'notes' => $find->get_Notes(),
|
|
'cat' => $find->get_Category()
|
|
), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $find->get_ID()
|
|
)
|
|
));
|
|
return $this->help->execute();
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.findings", array(
|
|
'tgt_id' => $find->get_Tgt_ID(),
|
|
'pdi_id' => $find->get_PDI_ID(),
|
|
'scan_id' => $find->get_Scan_ID(),
|
|
'findings_status_id' => $find->get_Finding_Status(),
|
|
'notes' => $find->get_Notes(),
|
|
'cat' => $find->get_Category()
|
|
), true);
|
|
if (!$find_id = $this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$ia_arr = [];
|
|
foreach ($find->get_IA_Controls() as $ia) {
|
|
$ia_arr[] = array(
|
|
$find_id,
|
|
$ia
|
|
);
|
|
}
|
|
|
|
$this->help->extended_insert("sagacity.finding_controls", array('finding_id', 'control_id'), $ia_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get count of open category I findings for a target
|
|
*
|
|
* @param integer $checklist_id
|
|
* Checklist ID to query for quantity
|
|
* @param target $tgt
|
|
* Target to query
|
|
*
|
|
* @return integer
|
|
* Returns the number of findings that are Cat I and with a status of 'Open' for a specific host
|
|
*/
|
|
public function get_Host_Open_Cat_1($checklist_id, $tgt)
|
|
{
|
|
$this->help->select_count("sagacity.pdi_catalog pdi", array(
|
|
array(
|
|
'field' => 'lu.checklist_id',
|
|
'op' => '=',
|
|
'value' => $checklist_id
|
|
),
|
|
array(
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID(),
|
|
'sql_op' => 'AND'
|
|
),
|
|
array(
|
|
'field' => 'fs.status',
|
|
'op' => '=',
|
|
'value' => 'Open',
|
|
'sql_op' => 'AND'
|
|
),
|
|
array(
|
|
'field' => 'pdi.cat',
|
|
'op' => '=',
|
|
'value' => 1,
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"JOIN sagacity.pdi_checklist_lookup lu ON lu.pdi_id=pdi.id",
|
|
"JOIN sagacity.findings f ON f.pdi_id=pdi.id",
|
|
"LEFT JOIN sagacity.stigs s ON s.pdi_id=pdi.id",
|
|
"LEFT JOIN sagacity.findings_status fs ON fs.id=f.findings_status_id"
|
|
)
|
|
));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Get count of not reviewed findings for a target
|
|
*
|
|
* @param integer $checklist_id
|
|
* Checklist ID to query for quantity
|
|
* @param target $tgt
|
|
* Target to query
|
|
*
|
|
* @return integer
|
|
* Returns the number of findings with a status of 'Not Reviewed' for a specific host
|
|
*/
|
|
public function get_Host_Not_Reviewed($checklist_id, $tgt)
|
|
{
|
|
$this->help->select_count("sagacity.pdi_catalog pdi", array(
|
|
array(
|
|
'field' => 'lu.checklist_id',
|
|
'op' => '=',
|
|
'value' => $checklist_id
|
|
),
|
|
array(
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID(),
|
|
'sql_op' => 'AND'
|
|
),
|
|
array(
|
|
'field' => 'fs.status',
|
|
'op' => '=',
|
|
'value' => 'Not Reviewed',
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"JOIN sagacity.pdi_checklist_lookup lu ON lu.pdi_id=pdi.id",
|
|
"JOIN sagacity.findings f ON f.pdi_id=pdi.id",
|
|
"LEFT JOIN sagacity.stigs s ON s.pdi_id=pdi.id",
|
|
"LEFT JOIN sagacity.findings_status fs ON fs.id=f.findings_status_id"
|
|
)
|
|
));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
// }}}
|
|
// {{{ GOLDDISK CLASS FUNCTIONS
|
|
/**
|
|
* Get GoldDisk data
|
|
*
|
|
* @param string $str_VMS_ID [optional]
|
|
* The VMS id of the golddisk object (default null)
|
|
*
|
|
* @return array:golddisk |NULL
|
|
* Returns an array of golddisk objects, or null if none found
|
|
*/
|
|
public function get_GoldDisk($str_VMS_ID = null)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if ($str_VMS_ID != null) {
|
|
$where[] = array(
|
|
'field' => 'vms_id',
|
|
'op' => '=',
|
|
'value' => $str_VMS_ID
|
|
);
|
|
}
|
|
|
|
$this->help->select("sagacity.golddisk", null, $where);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
|
|
$rows = array(0 => $rows);
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new golddisk($row['pdi_id'], $row['vms_id'], $row['short_title']);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving a VMS using the PDI
|
|
*
|
|
* @param integer $pdi_id
|
|
* The PDI ID of the golddisk to grab
|
|
*
|
|
* @return array:golddisk |NULL
|
|
* Returns an array of golddisk, or null if none found
|
|
*/
|
|
public function get_GoldDisk_By_PDI($pdi_id)
|
|
{
|
|
$ret = [];
|
|
$this->help->select("golddisk", null, [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new golddisk($row['pdi_id'], $row['vms_id'], $row['short_title']);
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to add GoldDisk to database
|
|
*
|
|
* @param golddisk $new_GoldDisk
|
|
* The golddisk object to add to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise false
|
|
*/
|
|
public function save_GoldDisk($new_GoldDisk)
|
|
{
|
|
$this->help->insert("sagacity.golddisk", array(
|
|
'pdi_id' => $new_GoldDisk->get_PDI_ID(),
|
|
'vms_id' => $new_GoldDisk->get_ID(),
|
|
'short_title' => $new_GoldDisk->get_Short_Title()
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ IA_CONTROL CLASS FUNCTIONS
|
|
/**
|
|
* Function to get IA control from DB
|
|
*
|
|
* @param ia_control $ia
|
|
* IA Control to retrieve from the database
|
|
*
|
|
* @return ia_control|NULL
|
|
* Returns IA_Control object, or null if none found
|
|
*/
|
|
public function get_IA_Controls($ia)
|
|
{
|
|
$sql = "SELECT `pdi_id`, `type`, `type_id` " .
|
|
"FROM `sagacity`.`ia_controls` " .
|
|
"WHERE " .
|
|
"`pdi_id` = " . $this->conn->real_escape_string($ia->get_PDI_ID()) . " AND " .
|
|
"`type` = '" . $this->conn->real_escape_string($ia->get_Type()) . "' AND " .
|
|
"`type_id` = " . $this->conn->real_escape_string($ia->get_Type_ID());
|
|
|
|
$res = $this->conn->query($sql);
|
|
|
|
if ($res->num_rows > 0) {
|
|
$row = $res->fetch_assoc();
|
|
|
|
return new ia_control($row['pdi_id'], $row['type'], $row['type_id']);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving all the IA controls by mac and classification
|
|
*
|
|
* @param system $sys
|
|
*
|
|
* @return array:ia_control
|
|
*/
|
|
public function get_IA_Controls_By_Mac_Class($sys)
|
|
{
|
|
$class = 'cl';
|
|
if ($sys->get_Classification() == 'Public') {
|
|
$class = 'pub';
|
|
}
|
|
elseif ($sys->get_Classification() == 'Sensitive') {
|
|
$class = 'sen';
|
|
}
|
|
$ret = [];
|
|
$sql = "SELECT `proc_control` " .
|
|
"FROM `sagacity`.`proc_level_type` " .
|
|
"WHERE " .
|
|
"`level` = " . $sys->get_MAC() . " AND " .
|
|
"`class` = '$class'";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret[] = new ia_control(null, explode('-', $row['proc_control'])[0], explode('-', $row['proc_control'])[1]);
|
|
}
|
|
}
|
|
else {
|
|
error_log($this->conn->error);
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving IA Controls by PDI
|
|
*
|
|
* @param integer $pdi_id
|
|
* PDI ID used to query
|
|
*
|
|
* @return array:ia_control |NULL
|
|
* Returns array of ia_controls associated with a specific PDI, or null if none found
|
|
*/
|
|
public function get_IA_Controls_By_PDI($pdi_id)
|
|
{
|
|
$sql = "SELECT " .
|
|
"`pdi_id`, `type`, `type_id` " .
|
|
"FROM `sagacity`.`ia_controls` " .
|
|
"WHERE `pdi_id` = " . $this->conn->real_escape_string($pdi_id);
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
$ret = [];
|
|
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret[] = new ia_control($row['pdi_id'], $row['type'], $row['type_id']);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function to get the icon that represents the IA control status
|
|
*
|
|
* @param ste $ste
|
|
* @param proc_ia_controls $ctrl
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_IA_Control_Icon($ste, $ctrl)
|
|
{
|
|
$cats = $this->get_STE_Cat_List($ste->get_ID());
|
|
$total = 0;
|
|
|
|
foreach ($cats as $cat) {
|
|
$total += $this->get_Finding_Count_By_Status($cat->get_ID(), "Open", null, $ctrl);
|
|
$total += $this->get_Finding_Count_By_Status($cat->get_ID(), "Exception", null, $ctrl);
|
|
}
|
|
|
|
if ($total) {
|
|
return "error.png";
|
|
}
|
|
|
|
if (false) {
|
|
$ctrl = new proc_ia_controls();
|
|
}
|
|
if (empty($ctrl->finding->vul_desc)) {
|
|
return "exclamation.png";
|
|
}
|
|
elseif (empty($ctrl->finding->mitigations)) {
|
|
return "exclamation.png";
|
|
}
|
|
|
|
return "Under_construction.svg";
|
|
}
|
|
|
|
/**
|
|
* Update an IA control
|
|
*
|
|
* @param ia_control|array:ia_control $ia_Controls
|
|
* Array of IA Controls to update
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_IA_Control($ia_Controls)
|
|
{
|
|
$params = [];
|
|
|
|
if (is_array($ia_Controls) && count($ia_Controls) && isset($ia_Controls[0]) && is_a($ia_Controls[0], 'ia_control')) {
|
|
foreach ($ia_Controls as $ia) {
|
|
$params[] = array(
|
|
$ia->get_PDI_ID(),
|
|
$ia->get_Type(),
|
|
$ia->get_Type_ID()
|
|
);
|
|
}
|
|
}
|
|
elseif (is_a($ia_Controls, 'ia_control')) {
|
|
$params[] = array(
|
|
$ia_Controls->get_PDI_ID(),
|
|
$ia_Controls->get_Type(),
|
|
$ia_Controls->get_Type_ID()
|
|
);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
$this->help->extended_replace("sagacity.ia_controls", array('pdi_id', 'type', 'type_id'), $params);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ IAVM CLASS FUNCTIONS
|
|
/**
|
|
* Function for retrieving an IAVM
|
|
*
|
|
* @param integer|string $iavm_ID
|
|
* The IAVM ID to look for
|
|
*
|
|
* @return iavm|NULL
|
|
* Returns IAVM object, otherwise null if none found
|
|
*/
|
|
public function get_IAVM($iavm_ID)
|
|
{
|
|
$sql = "SELECT " .
|
|
"iavm.`noticeId`, iavm.`pdi_id`, iavm.`xmlUrl`, iavm.`htmlUrl`, iavm.`iavmNoticeNumber`, iavm.`title`, " .
|
|
"iavm.`type`, iavm.`state`, iavm.`lastUpdated`, iavm.`releaseDate`, iavm.`supersedes`, " .
|
|
"iavm.`executiveSummary`, iavm.`fixAction`, iavm.`note`, iavm.`vulnAppsSysAndCntrmsrs`, " .
|
|
"iavm.`stigFindingSeverity`, iavm.`knownExploits`, iavm.`file_name` " .
|
|
"FROM `sagacity`.`iavm_notices` iavm";
|
|
|
|
if (is_numeric($iavm_ID)) {
|
|
$sql .= " WHERE iavm.`noticeId` = " . $this->conn->real_escape_string($iavm_ID);
|
|
}
|
|
else {
|
|
$sql .= " WHERE iavm.`iavmNoticeNumber` = '" . $this->conn->real_escape_string($iavm_ID) . "'";
|
|
}
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if (!$res->num_rows) {
|
|
return null;
|
|
}
|
|
$notice_row = $res->fetch_assoc();
|
|
$noticeId = $notice_row['noticeId'];
|
|
|
|
$iavm = new iavm($notice_row['noticeId'], $notice_row['pdi_id'], $notice_row['xmlUrl'], $notice_row['htmlUrl'], $notice_row['iavmNoticeNumber'], $notice_row['title'], $notice_row['type'], $notice_row['state'], $notice_row['lastUpdated'], $notice_row['releaseDate'], $notice_row['supersedes'], $notice_row['executiveSummary'], $notice_row['fixAction'], $notice_row['note'], $notice_row['vulnAppsSysAndCntrmsrs'], $notice_row['stigFindingSeverity'], $notice_row['knownExploits']);
|
|
|
|
$sql = "SELECT `cve_id` FROM `sagacity`.`iavm_to_cve` WHERE `noticeId` = " . $notice_row['noticeId'];
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$iavm->add_CVE($row2['cve_id']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$sql = "SELECT `id`, `title`, `url` FROM `sagacity`.`iavm_references` " .
|
|
"WHERE `iavm_notice_id` = " . $this->conn->real_escape_string($noticeId);
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
while ($ref_row = $res2->fetch_assoc()) {
|
|
$iavm->add_Reference(new iavm_reference($ref_row['id'], $ref_row['title'], $ref_row['url']));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
$sql = "SELECT `id`, `details` FROM `sagacity`.`iavm_tech_overview` " .
|
|
"WHERE `iavm_notice_id` = " . $this->conn->real_escape_string($noticeId);
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
$to_row = $res2->fetch_assoc();
|
|
$to = new iavm_tech_overview($to_row['id'], $to_row['details']);
|
|
$iavm->set_Tech_Overview($to);
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
$sql = "SELECT `id`, `type`, `title`, `url` FROM sagacity.iavm_patches " .
|
|
"WHERE `iavm_notice_id` = " . $this->conn->real_escape_string($noticeId);
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
while ($patch_row = $res2->fetch_assoc()) {
|
|
$iavm->add_Patch(new iavm_patch($patch_row['id'], $patch_row['type'], $patch_row['title'], $patch_row['url']));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
$sql = "SELECT `header`, `body` FROM `sagacity`.`iavm_mitigations` " .
|
|
"WHERE `iavm_notice_id` = " . $this->conn->real_escape_string($noticeId);
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
$mit_row = $res2->fetch_assoc();
|
|
|
|
$iavm->set_Mitigation(new iavm_mitigation($mit_row['header'], $mit_row['body']));
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
$sql = "SELECT `bid` FROM `sagacity`.`iavm_bids` " .
|
|
"WHERE `iavm_notice_id` = " . $this->conn->real_escape_string($noticeId);
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
if ($res2->num_rows) {
|
|
while ($bid_row = $res2->fetch_assoc()) {
|
|
$iavm->add_Bid(new iavm_bid($bid_row['bid']));
|
|
}
|
|
}
|
|
}
|
|
|
|
return $iavm;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get IAVM from external data (reference or patch)
|
|
*
|
|
* @param string $ext
|
|
* The external data to search for
|
|
*
|
|
* @return iavm|NULL
|
|
* Returns an iavm object if any are found, otherwise NULL
|
|
*/
|
|
public function get_IAVM_From_External($ext)
|
|
{
|
|
$sql = "SELECT `iavm_notice_id` FROM `sagacity`.`iavm_references` " .
|
|
"WHERE `title` LIKE '%" . $this->conn->real_escape_string($ext) . "%' OR " .
|
|
"`url` LIKE '%" . $this->conn->real_escape_string($ext) . "%' " .
|
|
"GROUP BY `iavm_notice_id` " .
|
|
"ORDER BY `iavm_notice_id` DESC";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if ($res->num_rows) {
|
|
$row = $res->fetch_assoc();
|
|
$iavm = $this->get_IAVM($row['iavm_notice_id']);
|
|
return $iavm;
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
$sql = "SELECT `iavm_notice_id` FROM `sagacity`.`iavm_patches` " .
|
|
"WHERE `title` LIKE '%" . $this->conn->real_escape_string($ext) . "%' OR " .
|
|
"`url` LIKE '%" . $this->conn->real_escape_string($ext) . "%' " .
|
|
"GROUP BY `iavm_notice_id` " .
|
|
"ORDER BY `iavm_notice_id` DESC";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
if ($res->num_rows) {
|
|
$row = $res->fetch_assoc();
|
|
$iavm = $this->get_IAVM($row['iavm_notice_id']);
|
|
return $iavm;
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM BIDs
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_Bids($iavm)
|
|
{
|
|
$params = [];
|
|
if (is_array($iavm->get_Bids()) && count($iavm->get_Bids())) {
|
|
foreach ($iavm->get_Bids() as $bid) {
|
|
$params[] = [$iavm->get_Notice_ID(), $bid];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_replace('iavm_bids', ['iavm_notice_id', 'bid'], $params);
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM mitigations
|
|
*
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_Mitigation($iavm)
|
|
{
|
|
if ($iavm->get_Mitigation()) {
|
|
$this->help->replace("iavm_mitiagations", [
|
|
'iavm_notice_id' => $iavm->get_Notice_ID(),
|
|
'header' => $iavm->get_Mitigation()->get_Header(),
|
|
'body' => $iavm->get_Mitigation()->get_Text()
|
|
]);
|
|
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM patches
|
|
*
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_Patches($iavm)
|
|
{
|
|
$params = [];
|
|
if (is_array($iavm->get_Patches()) && count($iavm->get_Patches())) {
|
|
foreach ($iavm->get_Patches() as $patch) {
|
|
$params[] = [$iavm->get_Notice_ID(), $patch->get_Type(), $patch->get_Title(), $patch->get_URL()];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_replace("iavm_patches", ['iavm_notice_id', 'type', 'title', 'url'], $params);
|
|
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM references
|
|
*
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_References($iavm)
|
|
{
|
|
$params = [];
|
|
if (is_array($iavm->get_References()) && count($iavm->get_References())) {
|
|
foreach ($iavm->get_References() as $ref) {
|
|
$params[] = [$iavm->get_Notice_ID(), $ref->get_Title(), $ref->get_URL()];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_replace("iavm_references", ['iavm_notice_id', 'title', 'url'], $params);
|
|
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM tech overview data
|
|
*
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_Tech_Overview($iavm)
|
|
{
|
|
if ($iavm->get_Tech_Overview()) {
|
|
$this->help->replace("iavm_tech_overview", [
|
|
'iavm_notice_id' => $iavm->get_Notice_ID(),
|
|
'details' => $iavm->get_Tech_Overview()->get_Details()
|
|
]);
|
|
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to save IAVM-to-CVE references
|
|
*
|
|
* @param iavm $iavm
|
|
*/
|
|
public function save_Iavm_Cves($iavm)
|
|
{
|
|
$params = [];
|
|
if (is_array($iavm->get_CVE()) && count($iavm->get_CVE())) {
|
|
foreach ($iavm->get_CVE() as $cve) {
|
|
$params[] = [$iavm->get_Notice_ID(), $cve];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_replace("iavm_to_cve", ['noticeId', 'cve_id'], $params);
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to save IAVMs
|
|
*
|
|
* @param iavm $iavm_in
|
|
* The IAVM to save
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_IAVM($iavm_in)
|
|
{
|
|
// check to see if the IAVM already exists
|
|
$db_iavm = $this->get_IAVM($iavm_in->get_Notice_ID());
|
|
|
|
if (is_null($db_iavm)) {
|
|
$this->help->insert('iavm_notices', [
|
|
'noticeId' => $iavm_in->get_Notice_ID(),
|
|
'pdi_id' => $iavm_in->get_PDI_ID(),
|
|
'xmlUrl' => $iavm_in->get_XML_URL(),
|
|
'htmlUrl' => $iavm_in->get_HTML_URL(),
|
|
'iavmNoticeNumber' => $iavm_in->get_Notice_Number(),
|
|
'title' => $iavm_in->get_Title(),
|
|
'type' => $iavm_in->get_Type(),
|
|
'state' => $iavm_in->get_State(),
|
|
'lastUpdate' => $iavm_in->get_Last_Updated_Date(),
|
|
'releaseDate' => $iavm_in->get_Release_Date_Date(),
|
|
'supersedes' => $iavm_in->get_Supersedes(),
|
|
'executiveSummary' => $iavm_in->get_Executive_Summary(),
|
|
'fixAction' => $iavm_in->get_Fix_Action(),
|
|
'note' => $iavm_in->get_Notes(),
|
|
'vulnAppsSysAndCntrmsrs' => $iavm_in->get_Vuln_Apps(),
|
|
'stigFindingSeverity' => $iavm_in->get_Stig_Severity(),
|
|
'knownExploits' => $iavm_in->get_Known_Exploits()
|
|
]);
|
|
}
|
|
else {
|
|
$this->help->update("iavm_notices", [
|
|
'type' => $iavm_in->get_Type(),
|
|
'state' => $iavm_in->get_State(),
|
|
'lastUpdated' => $iavm_in->get_Last_Updated_Date(),
|
|
'supersedes' => $iavm_in->get_Supersedes(),
|
|
'executiveSummary' => $iavm_in->get_Executive_Summary(),
|
|
'fixAction' => $iavm_in->get_Fix_Action(),
|
|
'knownExploits' => $iavm_in->get_Known_Exploits(),
|
|
'note' => $iavm_in->get_Notes(),
|
|
'vulnAppsSysAndCntrmsrs' => $iavm_in->get_Vuln_Apps()
|
|
], [
|
|
[
|
|
'field' => 'noticeId',
|
|
'op' => '=',
|
|
'value' => $iavm_in->get_Notice_ID()
|
|
]
|
|
]);
|
|
}
|
|
|
|
if ($this->help->execute()) {
|
|
$this->save_Iavm_Bids($iavm_in);
|
|
$this->save_Iavm_Mitigation($iavm_in);
|
|
$this->save_Iavm_Patches($iavm_in);
|
|
$this->save_Iavm_References($iavm_in);
|
|
$this->save_Iavm_Tech_Overview($iavm_in);
|
|
$this->save_Iavm_Cves($iavm_in);
|
|
}
|
|
}
|
|
|
|
// }}}
|
|
// {{{ INTERFACES CLASS FUNCTIONS
|
|
/**
|
|
* Get all interfaces for a target
|
|
*
|
|
* @param integer $tgtID
|
|
* Target ID to get interface information for
|
|
*
|
|
* @return array:interfaces|NULL
|
|
* Returns array of interfaces (with ports), or NULL if none found
|
|
*/
|
|
public function get_Interfaces($tgtID)
|
|
{
|
|
$ret = [];
|
|
if (!$tgtID) {
|
|
return [];
|
|
}
|
|
|
|
$this->help->select("sagacity.interfaces", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgtID
|
|
],
|
|
[
|
|
'field' => 'ipv4',
|
|
'op' => '!=',
|
|
'value' => '',
|
|
'sql_op' => 'AND'
|
|
],
|
|
[
|
|
'field' => 'ipv4',
|
|
'op' => IS_NOT,
|
|
'value' => null,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$int = new interfaces($row['id'], $row['tgt_id'], $row['name'], $row['ipv4'], $row['ipv6'], $row['hostname'], $row['fqdn'], $row['description']);
|
|
$int->set_MAC($row['mac']);
|
|
|
|
$this->help->select("sagacity.get_ports", null, [
|
|
[
|
|
'field' => 'int_id',
|
|
'op' => '=',
|
|
'value' => $row['id']
|
|
]
|
|
]);
|
|
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['id'])) {
|
|
$rows2 = [0 => $rows2];
|
|
}
|
|
|
|
if (is_array($rows2) && count($rows2) && isset($rows2[0])) {
|
|
foreach ($rows2 as $p) {
|
|
if ($p['proto'] == 'tcp') {
|
|
$port = new tcp_ports($p['id'], $p['port'], $p['name'], $p['banner'], $p['notes']);
|
|
$int->add_TCP_Ports($port);
|
|
}
|
|
else {
|
|
$port = new udp_ports($p['id'], $p['port'], $p['name'], $p['banner'], $p['notes']);
|
|
$int->add_UDP_Ports($port);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($row['ipv6']) {
|
|
$ret[$row['ipv6']] = $int;
|
|
}
|
|
else {
|
|
$ret[$row['ipv4']] = $int;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get an interface object using the IP address
|
|
*
|
|
* @param integer $tgt_id
|
|
* @param string $ip
|
|
*
|
|
* @return NULL|interfaces
|
|
*/
|
|
public function get_Interface_By_IP($tgt_id, $ip)
|
|
{
|
|
$this->help->select("sagacity.interfaces", null, array(
|
|
array(
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
),
|
|
array(
|
|
'field' => 'ipv4',
|
|
'op' => '=',
|
|
'value' => $ip,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
),
|
|
array(
|
|
'field' => 'ipv6',
|
|
'op' => '=',
|
|
'value' => $ip,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
)
|
|
));
|
|
|
|
$row = $this->help->execute();
|
|
if (is_null($row)) {
|
|
return null;
|
|
}
|
|
$int = new interfaces($row['id'], $row['tgt_id'], $row['name'], $row['ipv4'], $row['ipv6'], $row['hostname'], $row['fqdn'], $row['description']);
|
|
|
|
$this->help->select("sagacity.ports_proto_services pps", array('pps.id', 'pps.port', 'pps.proto',
|
|
"IF(ppsl.name != pps.IANA_Name, ppsl.name, pps.IANA_Name) AS 'name'",
|
|
"IF(ppsl.banner != pps.banner, ppsl.banner, pps.banner) AS 'banner'",
|
|
"IF(ppsl.notes != pps.notes, ppsl.notes, pps.notes) AS 'notes'"
|
|
), array(
|
|
array(
|
|
'field' => 'ppsl.int_id',
|
|
'op' => '=',
|
|
'value' => $row['id']
|
|
),
|
|
array(
|
|
'field' => 'pps.id',
|
|
'op' => IN,
|
|
'value' => "(SELECT pps_id FROM sagacity.pps_list WHERE int_id={$row['id']})",
|
|
'sql_op' => 'AND'
|
|
)
|
|
), array(
|
|
'table_joins' => array(
|
|
"LEFT JOIN sagacity.pps_list ppsl ON ppsl.pps_id=pps.id"
|
|
)
|
|
));
|
|
|
|
$rows2 = $this->help->execute();
|
|
if (is_array($rows2) && count($rows2) && isset($rows2['id'])) {
|
|
$rows2 = array(0 => $rows2);
|
|
}
|
|
|
|
if (is_array($rows2) && count($rows2) && isset($rows2[0])) {
|
|
foreach ($rows2 as $port) {
|
|
$class = "{$port['proto']}_ports";
|
|
$method = "add_" . strtoupper($port['proto']) . "_Ports";
|
|
$port = new $class($port['id'], $port['port'], $port['name'], $port['banner'], $port['notes']);
|
|
$int->$method($port);
|
|
}
|
|
}
|
|
|
|
return $int;
|
|
}
|
|
|
|
/**
|
|
* Return the last ID of the last interface in the database
|
|
*
|
|
* @return integer
|
|
* Returns the ID of the last interface that was inserted
|
|
*/
|
|
public function get_Last_Interface_ID()
|
|
{
|
|
$this->help->select("sagacity.interfaces", array('id'), [], array(
|
|
'order' => 'id DESC',
|
|
'limit' => 1
|
|
));
|
|
|
|
$row = $this->help->execute();
|
|
if (isset($row['id']) && $row['id'])
|
|
return $row['id'];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Save an interface
|
|
*
|
|
* @param array|interfaces $req
|
|
* Associative array of data to insert into database
|
|
* @param string $action [optional]
|
|
* String representing the action to be taken ('insert','update', defaulted to 'insert')
|
|
* @param integer $tgt_id [optional]
|
|
* Integer that the interface info is going to be save to (defaulted to 0)
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Interface($req, $action = 'insert')
|
|
{
|
|
if ($action == 'insert') {
|
|
if (is_array($req)) {
|
|
$first = array_shift($req);
|
|
if (!is_a($first, 'interfaces')) {
|
|
return false;
|
|
}
|
|
$req[$first->get_IPv4()] = $first;
|
|
foreach ($req as $int) {
|
|
$this->help->insert("sagacity.interfaces", array(
|
|
'tgt_id' => $int->get_TGT_ID(),
|
|
'ipv4' => $int->get_IPv4(),
|
|
'ipv6' => $int->get_IPv6(),
|
|
'hostname' => $int->get_Hostname(),
|
|
'fqdn' => $int->get_FQDN(),
|
|
'description' => $int->get_Description(),
|
|
'mac' => $int->get_MAC()
|
|
), true);
|
|
|
|
if (!($int_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$int->set_ID($int_id);
|
|
$ports = [];
|
|
|
|
if (is_array($int->get_TCP_Ports()) && count($int->get_TCP_Ports())) {
|
|
foreach ($int->get_TCP_Ports() as $tcp) {
|
|
$ports[] = array(
|
|
$int->get_ID(),
|
|
$tcp->get_ID(),
|
|
$tcp->get_Banner(),
|
|
$tcp->get_Notes()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (is_array($int->get_UDP_Ports()) && count($int->get_UDP_Ports())) {
|
|
foreach ($int->get_UDP_Ports() as $udp) {
|
|
$ports[] = array(
|
|
$int->get_ID(),
|
|
$udp->get_ID(),
|
|
$udp->get_Banner(),
|
|
$udp->get_Notes()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (count($ports)) {
|
|
$this->help->extended_insert("pps_list", array('int_id', 'pps_id', 'banner', 'notes'), $ports, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elseif (is_a($req, 'interfaces')) {
|
|
$this->help->insert("interfaces", array(
|
|
'tgt_id' => $req->get_TGT_ID(),
|
|
'ipv4' => $req->get_IPv4(),
|
|
'ipv6' => $req->get_IPv6(),
|
|
'hostname' => $req->get_Hostname(),
|
|
'fqdn' => $req->get_FQDN(),
|
|
'description' => $req->get_Description(),
|
|
'mac' => $req->get_MAC()
|
|
), true);
|
|
|
|
if (!($int_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$req->set_ID($int_id);
|
|
$ports = [];
|
|
|
|
if (is_array($req->get_TCP_Ports()) && count($req->get_TCP_Ports())) {
|
|
foreach ($req->get_TCP_Ports() as $tcp) {
|
|
$ports[] = array(
|
|
$int->get_ID(),
|
|
$tcp->get_ID(),
|
|
$tcp->get_Banner(),
|
|
$tcp->get_Notes()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (is_array($req->get_UDP_Ports()) && count($req->get_UDP_Ports())) {
|
|
foreach ($req->get_UDP_Ports() as $udp) {
|
|
$ports[] = array(
|
|
$int->get_ID(),
|
|
$udp->get_ID(),
|
|
$udp->get_Banner(),
|
|
$udp->get_Notes()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (count($ports)) {
|
|
$this->help->extended_insert("sagacity.pps_list", array('int_id', 'pps_id', 'banner', 'notes'), $ports, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->help->insert("interfaces", array(
|
|
'tgt_id' => $req['tgt_id'],
|
|
'ipv4' => $req['ipv4'],
|
|
'hostname' => (isset($req['hostname']) ? $req['hostname'] : $req['ipv4']),
|
|
'fadn' => (isset($req['fqdn']) ? $req['fqdn'] : $req['fqdn'])
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (isset($req['ip']) && $req['ip'] != null) {
|
|
foreach ($req['ip'] as $int_id => $val) {
|
|
if (isset($req['new'][$int_id])) {
|
|
$this->help->insert("sagacity.interfaces", [
|
|
'tgt_id' => $req['tgt'],
|
|
'ipv4' => $req['ip'][$int_id],
|
|
'hostname' => $req['hostname'][$int_id],
|
|
'fqdn' => $req['fqdn'][$int_id],
|
|
'name' => $req['name'][$int_id],
|
|
'description' => $req['description'][$int_id],
|
|
], true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
elseif ($val != 'DELETE') {
|
|
$this->help->update("sagacity.interfaces", [
|
|
'name' => $req['name'][$int_id],
|
|
'ipv4' => $val,
|
|
'hostname' => $req['hostname'][$int_id],
|
|
'fqdn' => $req['fqdn'][$int_id],
|
|
'description' => $req['description'][$int_id]
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $int_id
|
|
]
|
|
]);
|
|
|
|
if ($this->help->execute()) {
|
|
$tcp_ports = isset($req['tcp_port'][$int_id]) ? $req['tcp_port'][$int_id] : [];
|
|
$udp_ports = isset($req['udp_port'][$int_id]) ? $req['udp_port'][$int_id] : [];
|
|
|
|
$ports = [];
|
|
|
|
if (is_array($tcp_ports) && count($tcp_ports) > 0) {
|
|
foreach ($tcp_ports as $port_id => $val2) {
|
|
$ports[] = [
|
|
$int_id,
|
|
$port_id,
|
|
$req['iana_name'][$int_id][$port_id],
|
|
$req['banner'][$int_id][$port_id],
|
|
$req['notes'][$int_id][$port_id]
|
|
];
|
|
}
|
|
}
|
|
|
|
if (is_array($udp_ports) && count($udp_ports) > 0) {
|
|
foreach ($udp_ports as $int_id => $val2) {
|
|
$ports[] = [
|
|
$int_id,
|
|
$port_id,
|
|
$req['iana_name'][$int_id][$port_id],
|
|
$req['banner'][$int_id][$port_id],
|
|
$req['notes'][$int_id][$port_id]
|
|
];
|
|
}
|
|
}
|
|
|
|
if (count($ports)) {
|
|
$this->help->extended_insert("pps_list", ['int_id', 'pps_id', 'name', 'banner', 'notes'], $ports, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
$this->help->delete("sagacity.pps_list", null, array(
|
|
array(
|
|
'field' => 'int_id',
|
|
'op' => '=',
|
|
'value' => $int_id
|
|
)
|
|
));
|
|
$this->help->execute();
|
|
$this->help->delete("sagacity.interfaces", null, array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $int_id
|
|
)
|
|
));
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to delete an target interface from the database
|
|
*
|
|
* @param int $id
|
|
* The ID of the interface to be deleted
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if interface successfully deleted, otherwise FALSE
|
|
*/
|
|
public function delete_Interface($id)
|
|
{
|
|
// delete all associated ports
|
|
$this->help->delete("sagacity.pps_list", null, [
|
|
[
|
|
'field' => 'int_id',
|
|
'op' => '=',
|
|
'value' => $id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
// delete the interface itself
|
|
$this->help->delete("sagacity.interfaces", null, [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// {{{ Ports
|
|
/**
|
|
* Save the port to the database
|
|
*
|
|
* @param interfaces $int
|
|
* Interface to tie the ports to
|
|
* @param array:tcp_ports|array:udp_ports $ports
|
|
* Array of tcp and udp ports that are to be saved
|
|
* @param string $action [optional]
|
|
* Whether or not the ports are to be updated or inserted (defaulted 'insert')
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Ports($int, $ports, $action = 'insert')
|
|
{
|
|
$ret = true;
|
|
$ins_sql = 'REPLACE INTO `sagacity`.`pps_list` (`int_id`,`pps_id`,`name`,`banner`,`notes`) VALUES ';
|
|
if ($action == 'insert') {
|
|
foreach ($ports as $port) {
|
|
$ins_sql .= "(" . $int->get_ID() . ", " .
|
|
"(SELECT `id` FROM `sagacity`.`ports_proto_services` WHERE `port` = '" . $port->get_Port() . "'" .
|
|
" AND `proto` = '" . (is_a($port, 'tcp_ports') ? 'tcp' : 'udp') . "' " .
|
|
" AND `notes` NOT LIKE '%historic%' LIMIT 1), " .
|
|
"'" . $this->conn->real_escape_string($port->get_IANA_Name()) . "', " .
|
|
"'" . $this->conn->real_escape_string($port->get_Banner()) . "', " .
|
|
"'" . $this->conn->real_escape_string($port->get_Notes()) . "'), ";
|
|
}
|
|
|
|
$ins_sql = substr($ins_sql, 0, -1);
|
|
|
|
if (strlen($ins_sql) > 84) {
|
|
if (!$this->conn->real_query($ins_sql)) {
|
|
Sagacity_Error::sql_handler($ins_sql);
|
|
error_log($this->conn->error);
|
|
$ret = false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ TCP_PORTS CLASS FUNCTIONS
|
|
/**
|
|
* Get TCP port data
|
|
*
|
|
* @param integer $port_number [optional]
|
|
* Port number to retrieve from database
|
|
*
|
|
* @return array:tcp_ports|NULL
|
|
* Returns array of tcp ports, or null if none found
|
|
*/
|
|
public function get_TCP_Ports($port_number = null)
|
|
{
|
|
$ret = [];
|
|
$where = [
|
|
[
|
|
'field' => 'proto',
|
|
'op' => '=',
|
|
'value' => 'tcp'
|
|
]
|
|
];
|
|
|
|
if (!is_null($port_number)) {
|
|
$where[] = [
|
|
'field' => 'port',
|
|
'op' => '=',
|
|
'value' => $port_number,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("ports_proto_services", ['id', 'port', 'iana_Name', 'banner', 'notes'], $where);
|
|
|
|
$rows = $this->help->execute();
|
|
if (isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new tcp_ports($row['id'], $row['port'], $row['iana_Name'], $row['banner'], $row['notes']);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ UDP_PORTS CLASS FUNCTIONS
|
|
/**
|
|
* Get UDP port data
|
|
*
|
|
* @param integer $port_number
|
|
* Port number to retrieve from database
|
|
*
|
|
* @return array:udp_ports|NULL
|
|
* Returns array of udp ports, or null if none found
|
|
*/
|
|
public function get_UDP_Ports($port_number = null)
|
|
{
|
|
$ret = [];
|
|
$where = [
|
|
[
|
|
'field' => 'proto',
|
|
'op' => '=',
|
|
'value' => 'udp'
|
|
]
|
|
];
|
|
|
|
if (!is_null($port_number)) {
|
|
$where[] = [
|
|
'field' => 'port',
|
|
'op' => '=',
|
|
'value' => $port_number,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("ports_proto_services", ['id', 'port', 'iana_Name', 'banner', 'notes'], $where);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new udp_ports($row['id'], $row['port'], $row['iana_Name'], $row['banner'], $row['notes']);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ NESSUS CLASS FUNCTIONS
|
|
/**
|
|
* Function to retrieve a nessus object
|
|
*
|
|
* @param string $nessus_id
|
|
* Nessus ID of the object you want
|
|
*
|
|
* @return nessus|NULL
|
|
* Returns nessus object and associated references, or null if none found
|
|
*/
|
|
public function get_Nessus($nessus_id)
|
|
{
|
|
$this->help->select("nessus_plugins np", null, [
|
|
[
|
|
'field' => 'np.plugin_id',
|
|
'op' => '=',
|
|
'value' => $nessus_id
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN sagacity.nessus n ON n.nessus_id = np.plugin_id"
|
|
]
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
|
|
if (is_array($row) && count($row) && isset($row['plugin_id'])) {
|
|
$nessus = new nessus($row['pdi_id'], $row['plugin_id']);
|
|
|
|
$nessus->set_Name($row['name']);
|
|
$nessus->set_Copyright($row['copyright']);
|
|
$nessus->set_Version($row['version']);
|
|
$nessus->set_FileDate($row['file_date']);
|
|
$nessus->set_FileName($row['file_name']);
|
|
|
|
$this->help->select("sagacity.nessus_meta", null, [
|
|
[
|
|
'field' => 'plugin_id',
|
|
'op' => '=',
|
|
'value' => $row['plugin_id']
|
|
]
|
|
]);
|
|
|
|
if ($rows = $this->help->execute()) {
|
|
if (is_array($rows) && count($rows)) {
|
|
foreach ($rows as $row) {
|
|
$nessus->add_Reference($row['type'], $row['val']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $nessus;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Update Nessus data
|
|
*
|
|
* @param array:nessus|nessus $nessus
|
|
* Nessus object to update
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Nessus($nessus)
|
|
{
|
|
$nessus_arr = [];
|
|
$meta_arr = [];
|
|
$plugins_arr = [];
|
|
$update_arr = [];
|
|
|
|
$nessus_fields = array('pdi_id', 'nessus_id');
|
|
$meta_fields = array('plugin_id', 'type', 'val');
|
|
$plugins_fields = array('plugin_id', 'name', 'copyright', 'version', 'file_name', 'file_date');
|
|
|
|
$this->help->create_table("tmp_nessus", true, array(
|
|
array(
|
|
'field' => 'plugin_id',
|
|
'datatype' => 'int(11)',
|
|
'options' => 'primary key'
|
|
),
|
|
array(
|
|
'field' => 'name',
|
|
'datatype' => 'varchar(255)'
|
|
),
|
|
array(
|
|
'field' => 'copyright',
|
|
'datatype' => 'varchar(255)'
|
|
),
|
|
array(
|
|
'field' => 'version',
|
|
'datatype' => 'varchar(45)'
|
|
),
|
|
array(
|
|
'field' => 'file_name',
|
|
'datatype' => 'varchar(100)'
|
|
),
|
|
array(
|
|
'field' => 'file_date',
|
|
'datatype' => 'int(11)'
|
|
)
|
|
));
|
|
$this->help->execute();
|
|
|
|
if (is_a($nessus, 'nessus')) {
|
|
$nessus = array(0 => $nessus);
|
|
}
|
|
|
|
if (is_array($nessus)) {
|
|
$refs = [];
|
|
foreach ($nessus as $plug) {
|
|
$db_nessus = $this->get_Nessus($plug->get_Nessus_ID());
|
|
|
|
if (is_null($db_nessus)) {
|
|
if (!$plug->get_PDI_ID()) {
|
|
$pdi = new pdi(null, $plug->get_Category(), $plug->get_FileDate_Date());
|
|
$pdi->set_Short_Title($plug->get_Name());
|
|
$pdi->set_Group_Title($plug->get_Name());
|
|
$pdi->set_Description($plug->get_Description());
|
|
$pdi->set_ID($this->save_PDI($pdi));
|
|
$plug->set_PDI_ID($pdi->get_ID());
|
|
|
|
$stig = new stig($plug->get_PDI_ID(), $plug->get_Nessus_ID(), $plug->get_Name());
|
|
$this->add_Stig($stig);
|
|
}
|
|
|
|
$plugins_arr[] = [
|
|
$plug->get_Nessus_ID(),
|
|
$plug->get_Name(),
|
|
$plug->get_Copyright(),
|
|
$plug->get_Version(),
|
|
$plug->get_FileName(),
|
|
$plug->get_FileDate()
|
|
];
|
|
|
|
$refs = $plug->get_Reference();
|
|
}
|
|
else {
|
|
$update_arr[] = [
|
|
$plug->get_Nessus_ID(),
|
|
$plug->get_Name(),
|
|
$plug->get_Copyright(),
|
|
$plug->get_Version(),
|
|
$plug->get_FileName(),
|
|
$plug->get_FileDate()
|
|
];
|
|
|
|
$refs = $plug->compare_References($db_nessus);
|
|
}
|
|
|
|
$nessus_arr[] = [$plug->get_PDI_ID(), $plug->get_Nessus_ID()];
|
|
|
|
if (is_array($refs) && count($refs)) {
|
|
foreach ($refs as $type => $ref) {
|
|
foreach ($ref as $val) {
|
|
$meta_arr[] = array($plug->get_Nessus_ID(), $type, $val);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_array($plugins_arr) && count($plugins_arr)) {
|
|
$this->help->extended_insert("nessus_plugins", $plugins_fields, $plugins_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
|
|
if (is_array($update_arr) && count($update_arr)) {
|
|
$this->help->extended_insert("tmp_nessus", $plugins_fields, $update_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
$this->help->extended_update("nessus_plugins", "tmp_nessus", "plugin_id", $plugins_fields);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
|
|
if (is_array($nessus_arr) && count($nessus_arr)) {
|
|
$this->help->extended_insert("nessus", $nessus_fields, $nessus_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
|
|
if (is_array($meta_arr) && count($meta_arr)) {
|
|
$this->help->extended_insert("nessus_meta", $meta_fields, $meta_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ OVAL CLASS FUNCTIONS
|
|
/**
|
|
* Getter function for oval
|
|
*
|
|
* @param string $oval_id
|
|
* Oval ID to retrieve from database
|
|
*
|
|
* @return oval|NULL
|
|
* Returns oval object, or null if none found
|
|
*/
|
|
public function get_Oval($oval_id)
|
|
{
|
|
$oval = null;
|
|
$sql = "SELECT " .
|
|
"`pdi_id`, `oval_id`, `title`, `desc`, `platform`, `ext_def`, `ext_def_op` " .
|
|
"FROM sagacity.oval " .
|
|
"WHERE `oval_id` = '" . $this->conn->real_escape_string($oval_id) . "'";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
$row = $res->fetch_assoc();
|
|
|
|
$oval = new oval($row['pdi_id'], $row['oval_id'], $row['title'], $row['desc'], $row['platform'], $row['ext_def'], $row['ext_def_op']);
|
|
|
|
$sql = "SELECT" .
|
|
"`oval_id`, `source`, `url`, `ref_id` " .
|
|
"FROM sagacity.oval_ref " .
|
|
"WHERE `oval_id` = '" . $this->conn->real_escape_string($row['oval_id']) . "'";
|
|
|
|
if ($res2 = $this->conn->query($sql)) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$ref = new oval_ref($row2['oval_id'], $row2['source'], $row2['url'], $row2['ref_id']);
|
|
|
|
$oval->add_Reference($ref);
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return $oval;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function to create a OVAL xml file to import into SCC
|
|
*
|
|
* @param string $os
|
|
* Operating system version to query
|
|
*
|
|
* @return string
|
|
* Returns string representing XML
|
|
*/
|
|
public function get_OS_Oval($os)
|
|
{
|
|
$xmlns = "xmlns = 'http://oval.mitre.org/XMLSchema/oval-definitions-5#windows'";
|
|
// ------------------------------ Start <registry_test> -----------------------------
|
|
// create temporary db table to combine all OVAL checks marked 'M' and not 'M'
|
|
$tmp_sql = "CREATE TEMPORARY TABLE `tmp_oval` SELECT " .
|
|
"pdi.`id`, o.`oval_id`, s.`stig_id`, vms.`vms_id`, pdi.`check_contents`, pdi.`short_title` " .
|
|
"FROM `pdi_catalog` AS pdi " .
|
|
"LEFT JOIN `oval` AS o ON pdi.`id` = o.`pdi_id` " .
|
|
"LEFT JOIN `stigs` AS s ON pdi.`id` = s.`pdi_id` " .
|
|
"LEFT JOIN `golddisk` AS vms ON pdi.`id` = vms.`pdi_id` " .
|
|
"LEFT JOIN `pdi_checklist_lookup` AS lookup ON pdi.`id` = lookup.`pdi_id` " .
|
|
"LEFT JOIN `checklist` AS c ON lookup.`checklist_id` = c.`id` " .
|
|
"LEFT JOIN `software` AS sft ON sft.`id` = c.`sw_id` " .
|
|
"WHERE " .
|
|
"o.`oval_id` = 'M' AND " .
|
|
"pdi.`check_contents` LIKE '%Registry Hive%' AND " .
|
|
"sft.`man` = 'MS' AND " .
|
|
"sft.`name` = 'Windows' AND " .
|
|
"sft.`ver` = '$os' " .
|
|
"GROUP BY `stig_id`";
|
|
|
|
$this->conn->real_query($tmp_sql);
|
|
|
|
// delete rows in temporary table from other checklist that cannot designated as manual
|
|
$del_sql = "DELETE FROM tmp_oval " .
|
|
"WHERE `id` IN (" .
|
|
"SELECT pdi.`id` " .
|
|
"FROM `pdi_catalog` AS pdi " .
|
|
"LEFT JOIN `oval` AS o ON pdi.`id` = o.`pdi_id` " .
|
|
"LEFT JOIN `stigs` AS s ON pdi.`id` = s.`pdi_id` " .
|
|
"LEFT JOIN `golddisk` AS vms ON pdi.`id` = vms.`pdi_id` " .
|
|
"LEFT JOIN `pdi_checklist_lookup` AS lookup ON pdi.`id` = lookup.`pdi_id` " .
|
|
"LEFT JOIN `checklist` AS c ON lookup.`checklist_id` = c.`id` " .
|
|
"LEFT JOIN `software` AS sft ON sft.`id` = c.`sw_id` " .
|
|
"WHERE " .
|
|
"o.`oval_id` != 'M' AND " .
|
|
"pdi.`check_contents` REGEXP 'Registry Hive' AND " .
|
|
"sft.`man` = 'MS' AND " .
|
|
"sft.`name` = 'Windows' AND " .
|
|
"sft.`ver` = '$os' " .
|
|
"GROUP BY pdi.`id`)";
|
|
|
|
$this->conn->real_query($del_sql);
|
|
|
|
$sql = "SELECT " .
|
|
"`id`, `oval_id`, `stig_id`, `vms_id`, `check_contents`, `short_title` " .
|
|
"FROM `tmp_oval`";
|
|
|
|
if ($sth = $this->conn->prepare($sql)) {
|
|
if ($sth->execute()) {
|
|
$pdi_id = 0;
|
|
$oval_id = '';
|
|
$stig_id = '';
|
|
$vms_id = '';
|
|
$check_contents = '';
|
|
$short_title = '';
|
|
$x = 0;
|
|
$sth->bind_result($pdi_id, $oval_id, $stig_id, $vms_id, $check_contents, $short_title);
|
|
// oval_file xml validation check
|
|
$root = '<?xml version="1.0" encoding="UTF-8"?><oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:windows-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#windows" xmlns:independent-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#windows http://oval.mitre.org/language/download/schema/version5.3/ovaldefinition/complete/windows-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent http://oval.mitre.org/language/download/schema/version5.3/ovaldefinition/complete/independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 http://oval.mitre.org/language/download/schema/version5.3/ovaldefinition/complete/oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-common-5 http://oval.mitre.org/language/download/schema/version5.3/ovaldefinition/complete/oval-common-schema.xsd">';
|
|
// declaring string variables and setting values to empty
|
|
$def = '';
|
|
$tst = '';
|
|
$obj = '';
|
|
$ste = '';
|
|
// generator node in xml format
|
|
$date = new DateTime(); // insert date and time when file completed
|
|
$gen = "<generator><oval:product_name>DISA FSO</oval:product_name><oval:schema_version>5.3</oval:schema_version><oval:timestamp>" .
|
|
$date->format(DATE_W3C) . "</oval:timestamp></generator>";
|
|
|
|
while ($sth->fetch()) {
|
|
$x++;
|
|
$match = [];
|
|
preg_match('/Registry Hive: +(\S*)/', $check_contents, $match);
|
|
$hive = $match[1];
|
|
|
|
preg_match('/(Subkey|Path|Registry Path): +(\\\)?(.*)/', $check_contents, $match);
|
|
$path = is_array($match) && count($match) > 3 ? $match[3] : "STIG ID: $stig_id" . PHP_EOL;
|
|
|
|
preg_match('/Value Name: +(\S*)/', $check_contents, $match);
|
|
$name = is_array($match) && count($match) > 1 ? $match[1] : '';
|
|
|
|
if (is_array($match) && count($match) == 2) {
|
|
$c_operator = 'AND';
|
|
$c_count = 1;
|
|
}
|
|
|
|
preg_match('/Type: +(\S*)/', $check_contents, $match);
|
|
$type = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL;
|
|
|
|
preg_match('/Value: +(\S*)/', $check_contents, $match);
|
|
$value = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL;
|
|
|
|
if (strpos($type, "PDI ID: " . $pdi_id) !== false) {
|
|
// print "$pdi_id, $vms_id this VMS item cannot be automated".PHP_EOL.PHP_EOL;
|
|
continue;
|
|
}
|
|
|
|
// variables set for various xml nodes
|
|
$def_id = 'oval:smc.gpea.windows:def:' . $pdi_id;
|
|
$tst_id = 'oval:smc.gpea.windows:tst:' . $pdi_id . "00";
|
|
$ste_id = 'oval:smc.gpea.windows:ste:' . $pdi_id . "00";
|
|
$obj_id = 'oval:smc.gpea.windows:obj:' . $pdi_id . "00";
|
|
$var_id = 'oval:smc.gpea.windows:var:' . $pdi_id . "00";
|
|
$def_class = 'compliance';
|
|
$m_family = 'windows';
|
|
$aft_platform = 'Microsoft Windows ' . $os;
|
|
$tst_chk_existence = ($c_count == 1 ? "all_exist" : '');
|
|
|
|
// definitions node in xml format
|
|
$def .= "<definition id='$def_id' version='1' class='$def_class'>" . "<metadata>" .
|
|
"<title>$short_title</title>" . "<affected family='$m_family'>" .
|
|
"<platform>$aft_platform</platform>" . "</affected>" .
|
|
"<reference source='' ref_url='' ref_id='' />" .
|
|
"<description>$short_title</description>" . "</metadata>" .
|
|
"<criteria operator='$c_operator'>";
|
|
|
|
if ($c_count == 1) {
|
|
$def .= "<criterion test_ref='oval:smc.gpea.windows:tst:" . $pdi_id . "00' comment='" .
|
|
$hive . "\\" . $path . "!" . $name . " value equals variable' />" . PHP_EOL;
|
|
}
|
|
|
|
$def .= "</criteria></definition>";
|
|
|
|
$tst .= "<registry_test $xmlns id='$tst_id' version='1' check_existence='$tst_chk_existence' check='all' comment='comment'>" .
|
|
"<object object_ref='$obj_id' />" . "<state state_ref='$ste_id' />" .
|
|
"</registry_test>";
|
|
|
|
if (substr($path, -1) != "\\") {
|
|
$path .= "\\";
|
|
}
|
|
|
|
$obj .= "<registry_object $xmlns id='$obj_id' version='1' comment='comment'>" .
|
|
"<hive datatype='string'>" . strtoupper($hive) . "</hive>" .
|
|
"<key datatype='string'>$path</key>" . "<name datatype='string'>$name</name>" .
|
|
"</registry_object>";
|
|
|
|
$ste .= "<registry_state $xmlns id='$ste_id' version='1' comment='comment'>" . "<type>" .
|
|
strtolower($type) . "</type>" . "<value datatype='" .
|
|
(strpos(strtolower($type), 'sz') ? 'string' : 'int') .
|
|
"' operation='equals'>$value</value>" . "</registry_state>";
|
|
}
|
|
$sth->close();
|
|
}
|
|
}
|
|
// ------------------------------ End <registry_test> -----------------------------
|
|
// ------------------------------ Start <auditeventpolicysubcategories_test> -----------------------------
|
|
$tmp_sql = "CREATE TEMPORARY TABLE `tmp_oval` SELECT " .
|
|
"pdi.`id`,o.`oval_id`,s.`stig_id`,vms.`vms_id`,pdi.`check_contents`,pdi.`short_title` " .
|
|
"FROM `sagacity`.`pdi_catalog` AS pdi " .
|
|
"LEFT JOIN `sagacity`.`oval` AS o ON pdi.`id`=o.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`stigs` AS s ON pdi.`id`=s.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`golddisk` AS vms ON pdi.`id`=vms.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` AS lookup ON pdi.`id`=lookup.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`checklist` AS c ON lookup.`checklist_id`=c.`id` " .
|
|
"LEFT JOIN `sagacity`.`software` AS sft ON sft.`id`=c.`sw_id` " .
|
|
"WHERE " .
|
|
"o.`oval_id`='M' AND " .
|
|
"pdi.`check_contents` LIKE '%AuditPol%' AND " .
|
|
"sft.`man`='MS' AND " .
|
|
"sft.`name`='Windows' AND " .
|
|
"sft.`ver`='$os' " .
|
|
"GROUP BY `stig_id`";
|
|
$this->conn->real_query($tmp_sql);
|
|
|
|
$del_sql = "DELETE FROM tmp_oval " .
|
|
"WHERE `id` IN (" .
|
|
"SELECT pdi.`id` " .
|
|
"FROM `sagacity`.`pdi_catalog` AS pdi " .
|
|
"LEFT JOIN `sagacity`.`oval` AS o ON pdi.`id`=o.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`stigs` AS s ON pdi.`id`=s.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`golddisk` AS vms ON pdi.`id`=vms.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`pdi_checklist_lookup` AS lookup ON pdi.`id`=lookup.`pdi_id` " .
|
|
"LEFT JOIN `sagacity`.`checklist` AS c ON lookup.`checklist_id`=c.`id` " .
|
|
"LEFT JOIN `sagacity`.`software` AS sft ON sft.`id`=c.`sw_id` " .
|
|
"WHERE " .
|
|
"o.`oval_id`!='M' AND " .
|
|
"pdi.`check_contents` REGEXP 'AuditPol' AND " .
|
|
"sft.`man`='MS' AND " .
|
|
"sft.`name`='Windows' AND " .
|
|
"sft.`ver`='$os' " .
|
|
"GROUP BY pdi.`id`)";
|
|
$this->conn->real_query($del_sql);
|
|
|
|
$sql = "SELECT " .
|
|
"`id`,`oval_id`,`stig_id`,`vms_id`,`check_contents`,`short_title` " .
|
|
"FROM `tmp_oval`";
|
|
|
|
if ($sth = $this->conn->prepare($sql)) {
|
|
if ($sth->execute()) {
|
|
$pdi_id = 0;
|
|
$oval_id = '';
|
|
$stig_id = '';
|
|
$vms_id = '';
|
|
$check_contents = '';
|
|
$short_title = '';
|
|
$x = 0;
|
|
$sth->bind_result($pdi_id, $oval_id, $stig_id, $vms_id, $check_contents, $short_title);
|
|
|
|
$sth->store_result();
|
|
|
|
if ($sth->num_rows > 0) {
|
|
$obj .= "<auditeventpolicysubcategories_object $xmlns id='oval:smc.gpea.windows:obj:1' version='1' comment='Audit Event Policy Subcategories' />";
|
|
}
|
|
|
|
while ($sth->fetch()) {
|
|
$tst_id = "oval:smc.gpea.windows:tst:" . $pdi_id . "00";
|
|
$ste_id = "oval:smc.gpea.windows:ste:" . $pdi_id . "00";
|
|
|
|
$arrow_idx = strpos($check_contents, '->') + 3;
|
|
$dash_idx = strpos($check_contents, ' - ');
|
|
|
|
$subcat = substr($check_contents, $arrow_idx, $dash_idx - $arrow_idx);
|
|
$tag = str_replace(' ', '_', strtolower($subcat));
|
|
|
|
$audit = substr($check_contents, $dash_idx + 3);
|
|
|
|
$ste .= "<auditeventpolicysubcategories_state $xmlns id='$ste_id' version='1' comment='comment'>" .
|
|
"<$tag datatype='string'>" .
|
|
($audit == 'Failure' ? 'AUDIT_FAILURE' : 'AUDIT_SUCCESS') . "</$tag>" .
|
|
"</auditeventpolicysubcategories_state>";
|
|
|
|
$tst .= "<auditeventpolicysubcategories_test $xmlns id='$tst_id' version='1' check_existence='at_least_one_exists' check='all' comment='comment'>" .
|
|
"<object object_ref='oval:smc.gpea.windows:obj:1' />" .
|
|
"<state state_ref='$ste_id' />" . "</auditeventpolicysubcategories_test>";
|
|
}
|
|
}
|
|
else {
|
|
error_log($sth->error);
|
|
}
|
|
}
|
|
else {
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
// ------------------------------ End <auditeventpolicysubcategories_test> -----------------------------
|
|
// ------------------------------ Start <passwordpolicy_test> -----------------------------
|
|
// ------------------------------ End <passwordpolicy_test> -----------------------------
|
|
|
|
$xml_string = $root .
|
|
"$gen<definitions>$def</definitions><tests>$tst</tests><objects>$obj</objects><states>$ste</states></oval_definitions>";
|
|
|
|
return $xml_string;
|
|
}
|
|
|
|
/**
|
|
* Function to get oval constant data from database
|
|
*
|
|
* @param string $oval_id
|
|
* Oval ID to get constant data for
|
|
*
|
|
* @return array
|
|
* Returns array of constant ID and value
|
|
*/
|
|
public function get_Oval_Const($oval_id)
|
|
{
|
|
$sql = "SELECT `const_id`,`value` FROM `sagacity`.`ov_convert` WHERE `var_id`=" . $oval_id;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
$vals = [];
|
|
while ($row = $res->fetch_assoc()) {
|
|
$vals[] = $row['value'];
|
|
}
|
|
|
|
return array(
|
|
'const_id' => $row['const_id'],
|
|
'values' => $vals
|
|
);
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to add an Oval
|
|
*
|
|
* @param oval $oval
|
|
* Oval to add to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function add_Oval($oval)
|
|
{
|
|
$this->help->insert("sagacity.oval", array(
|
|
'pdi_id' => $oval->get_PDI_ID(),
|
|
'oval_id' => $oval->get_Oval_ID(),
|
|
'title' => $oval->get_Title(),
|
|
'desc' => $oval->get_Description(),
|
|
'platform' => $oval->get_Platform(),
|
|
'ext_def' => $oval->get_External_Definition(),
|
|
'ext_def_op' => $oval->get_External_Definition_Operator()
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to save oval data
|
|
*
|
|
* @param oval $oval_in
|
|
* Oval to update database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Oval($oval_in)
|
|
{
|
|
$this->help->replace("sagacity.oval", array(
|
|
'pdi_id' => $oval_in->get_PDI_ID(),
|
|
'oval_id' => $oval_in->get_Oval_ID(),
|
|
'title' => $oval_in->get_Title(),
|
|
'desc' => $oval_in->get_Description(),
|
|
'platform' => $oval_in->get_Platform(),
|
|
'ext_def' => $oval_in->get_External_Definition(),
|
|
'ext_def_op' => $oval_in->get_External_Definition_Operator()
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ PDI_CATALOG CLASS FUNCTIONS
|
|
/**
|
|
* Function to retrieve a PDI from the database
|
|
*
|
|
* @param integer $pdi_id
|
|
* PDI ID to get from database
|
|
* @param integer $chk_id
|
|
* Checklist ID to filter on
|
|
*
|
|
* @return pdi|NULL
|
|
* Returns PDI object, or null if none found
|
|
*/
|
|
public function get_PDI($pdi_id, $chk_id = null)
|
|
{
|
|
$pdi = null;
|
|
$this->help->select("sagacity.pdi_catalog p", null, [
|
|
[
|
|
'field' => 'p.id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
]
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
|
|
if (is_array($row) && count($row) && isset($row['id'])) {
|
|
$pdi = new pdi($row['id'], $row['cat'], $row['update']);
|
|
$pdi->set_Short_Title($row['short_title']);
|
|
$pdi->set_Check_Contents($row['check_contents']);
|
|
|
|
if (!is_null($chk_id)) {
|
|
$this->help->select("sagacity.pdi_checklist_lookup", null, [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
],
|
|
[
|
|
'field' => 'checklist_id',
|
|
'op' => '=',
|
|
'value' => $chk_id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
if (is_array($row) && count($row) && isset($row['pdi_id'])) {
|
|
$pdi->set_Short_Title($row['short_title']);
|
|
$pdi->set_Group_Title($row['group_title']);
|
|
$pdi->set_Check_Contents($row['check_contents']);
|
|
$pdi->set_Fix_Text($row['fix_text']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $pdi;
|
|
}
|
|
|
|
/**
|
|
* Function to get pdi catalog item from database
|
|
*
|
|
* @param integer $pdi_id
|
|
* Get PDI Catalog entry from database using this ID
|
|
*
|
|
* @return array|NULL
|
|
* Returns associative array with record, or null if none found
|
|
*/
|
|
public function get_PDI_Catalog($pdi_id)
|
|
{
|
|
$this->help->select("sagacity.pdi", null, array(
|
|
array(
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
)
|
|
));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to attempt to match text
|
|
*
|
|
* @param pdi $pdi
|
|
* PDI to match in database
|
|
* @param nessus $nessus
|
|
* Nessus to match in database
|
|
* @param cve $cve
|
|
* CVE to match in database
|
|
* @param iavm $iavm
|
|
* IAVM to match in database
|
|
*
|
|
* @return array|NULL
|
|
* Returns array of possible matches, or null if none found
|
|
*/
|
|
public function get_Matching_PDIs($pdi, $nessus, $cve, $iavm)
|
|
{
|
|
/*
|
|
$string = '';
|
|
|
|
if (!is_null($nessus)) {
|
|
$string = $nessus->get_Name() . ' ' . $nessus->get_Description() . ' ' . $nessus->get_Summary();
|
|
}
|
|
elseif (!is_null($cve)) {
|
|
$string = $cve->get_Description();
|
|
}
|
|
elseif (!is_null($iavm)) {
|
|
$string = $iavm->get_Title() . ' ' . $iavm->get_Executive_Summary();
|
|
}
|
|
|
|
foreach ($this->DISALLOWED as $word) {
|
|
$string = preg_replace("/\s" . $word . "\s/i", " ", $string);
|
|
}
|
|
|
|
$sql = "SELECT " .
|
|
"MATCH(pdi.`short_title`,pdi.`description`,pdi.`check_content`) " .
|
|
"AGAINST('" . $this->conn->real_escape_string($string) . "' IN NATURAL LANGUAGE MODE) AS 'score'," .
|
|
"pdi.`id`,pdi.`short_title`,pdi.`description`,pdi.`check_content` " .
|
|
"FROM `sagacity`.`pdi_catalog` pdi " .
|
|
"GROUP BY pdi.`id`,`score` " .
|
|
"HAVING `score` > 10 " .
|
|
"ORDER BY `score` DESC " .
|
|
"LIMIT 0, 5";
|
|
|
|
$ret = [];
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret[] = array(
|
|
'score' => number_format($row['score'], 3),
|
|
'pdi_id' => $row['id'],
|
|
'title' => $row['short_title'],
|
|
'check_content' => $row['check_content'],
|
|
'desc' => $row['description']
|
|
);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
*/
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function to try and find a PDI
|
|
*
|
|
* @param array $data_in
|
|
* An array of a type and value to search for. This will primarily be intended for types that don't have a readily available link to a PDI (nessus, retina, CVE, IAVM, etc).
|
|
*
|
|
* @return integer
|
|
* Returns the PDI id of the matching entry, or 0 if none found
|
|
*/
|
|
public function find_PDI($data_in)
|
|
{
|
|
if ($data_in['type'] == 'nessus') {
|
|
$nessus = $this->get_Nessus($data_in['value']);
|
|
|
|
if (is_null($nessus)) {
|
|
return 0;
|
|
}
|
|
|
|
if ($nessus->get_PDI_ID()) {
|
|
return $nessus->get_PDI_ID();
|
|
}
|
|
else {
|
|
$cves = $nessus->get_Reference_By_Type('cve');
|
|
foreach ($cves as $cve_num) {
|
|
$cve = $this->get_CVE($cve_num);
|
|
if ($cve->get_PDI_ID()) {
|
|
return $cve->get_PDI_ID();
|
|
}
|
|
|
|
$sql = "SELECT `noticeId` FROM `sagacity`.`iavm_to_cve` WHERE `cve_id`='" . $this->conn->real_escape_string($cve_num) . "'";
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$iavm = $this->get_IAVM($row['noticeId']);
|
|
|
|
if (!is_null($iavm)) {
|
|
return $iavm->get_PDI_ID();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
}
|
|
|
|
$bids = $nessus->get_Reference_By_Type('bid');
|
|
foreach ($bids as $bid_num) {
|
|
$sql = "SELECT iavm.`pdi_id` " .
|
|
"FROM `sagacity`.`nessus_refs` nr " .
|
|
"JOIN `sagacity`.`iavm_bids` ib ON ib.`bid`=nr.`val` " .
|
|
"JOIN `sagacity`.`iavm_notices` iavm ON iavm.`noticeId`=ib.`iavm_notice_id` " .
|
|
"WHERE " .
|
|
"nr.`type`='bid' AND " .
|
|
"nr.`val`=" . $this->conn->real_escape_string($bid_num) . " AND " .
|
|
"nr.`plugin_id`=" . $this->conn->real_escape_string($nessus->get_Nessus_ID());
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
return $row['pdi_id'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Function to save an existing PDI
|
|
*
|
|
* @param pdi $pdi_in
|
|
* The PDI to save or update
|
|
* @param checklist $checklist [optional]
|
|
* The checklist to link new PDIs to (if null links to Orphan checklist)
|
|
*
|
|
* @return boolean|int
|
|
* Returns ID of PDI or FALSE if failed to save.
|
|
*/
|
|
public function save_PDI($pdi_in, $checklist = null)
|
|
{
|
|
$pdi_id = null;
|
|
|
|
if ($pdi_in->get_ID()) {
|
|
$this->help->update('sagacity.pdi_catalog', [
|
|
'cat' => $pdi_in->get_Category_Level(),
|
|
'update' => $pdi_in->get_Last_Update(),
|
|
'short_title' => $pdi_in->get_Short_Title(),
|
|
'check_contents' => $pdi_in->get_Check_Contents()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $pdi_in->get_ID()
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$pdi_id = $pdi_in->get_ID();
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.pdi_catalog", [
|
|
"cat" => $pdi_in->get_Category_Level(),
|
|
'update' => $pdi_in->get_Last_Update(),
|
|
'short_title' => $pdi_in->get_Short_Title(),
|
|
'check_contents' => $pdi_in->get_Check_Contents()
|
|
]);
|
|
|
|
if (!($pdi_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$pdi_in->set_ID($pdi_id);
|
|
}
|
|
|
|
if (is_null($checklist)) {
|
|
$checklist = $this->get_Checklist('Orphan');
|
|
}
|
|
|
|
if (is_array($checklist) && isset($checklist[0]) && is_a($checklist[0], 'checklist')) {
|
|
$this->help->insert('sagacity.pdi_checklist_lookup', [
|
|
'pdi_id' => $pdi_id,
|
|
'checklist_id' => $checklist[0]->get_ID(),
|
|
'check_contents' => $pdi_in->get_Check_Contents(),
|
|
'group_title' => $pdi_in->get_Group_Title(),
|
|
'short_title' => $pdi_in->get_Short_Title(),
|
|
'fix_text' => $pdi_in->get_Fix_Text()
|
|
], true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
elseif (is_a($checklist, 'checklist')) {
|
|
$this->help->insert("sagacity.pdi_checklist_lookup", array(
|
|
'pdi_id' => $pdi_id,
|
|
'checklist_id' => $checklist->get_ID(),
|
|
'check_contents' => $pdi_in->get_Check_Contents(),
|
|
'group_title' => $pdi_in->get_Group_Title(),
|
|
'short_title' => $pdi_in->get_Short_Title(),
|
|
'fix_text' => $pdi_in->get_Fix_Text()
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::err_handler("Cannon link PDI ID $pdi_id with a checklist", E_WARNING);
|
|
}
|
|
|
|
return $pdi_id;
|
|
}
|
|
|
|
/**
|
|
* Function to save the check contents to a specific PDI and checklist
|
|
*
|
|
* @param pdi $pdi_in
|
|
* The PDI (containing the check contents)
|
|
* @param checklist $checklist_in
|
|
* The checklist
|
|
* @param string $check_contents_in [optional]
|
|
* The check contents to save (will use check contents in $pdi_in if this is null)
|
|
* @param string $fix_text_in [optional]
|
|
* The fix text to save
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Check_Contents($pdi_in, $checklist_in, $check_contents_in = null, $fix_text_in = null)
|
|
{
|
|
$this->help->replace("sagacity.pdi_checklist_lookup", array(
|
|
'pdi_id' => $pdi_in->get_ID(),
|
|
'checklist_id' => $checklist_in->get_ID(),
|
|
'group_title' => $pdi_in->get_Group_Title(),
|
|
'short_title' => $pdi_in->get_Short_Title(),
|
|
'check_contents' => (!is_null($check_contents_in) ? $check_contents_in : $pdi_in->get_Check_Contents()),
|
|
'fix_text' => (!is_null($fix_text_in) ? $fix_text_in : $pdi_in->get_Fix_Text())
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ PROC_IA_CONTROLS CLASS FUNCTIONS
|
|
/**
|
|
* Function to get all procedural IA controls for specified system
|
|
*
|
|
* @param ste $ste_in
|
|
* ST&E to query the database for
|
|
* @param string $control_id [optional]
|
|
* Control ID to query (default null)
|
|
*
|
|
* @return array:proc_ia_controls
|
|
* Return array of proc_ia_controls and associated sub controls, or empty array if none found
|
|
*/
|
|
public function get_Proc_IA_Controls($ste_in, $control_id = null)
|
|
{
|
|
$ret = [];
|
|
$sys = $this->get_System($ste_in->get_System()->get_ID())[0];
|
|
switch ($sys->get_Classification()) {
|
|
case 'Public':
|
|
$class = 'pub';
|
|
break;
|
|
case 'Sensitive':
|
|
$class = 'sen';
|
|
break;
|
|
case 'Classified':
|
|
$class = 'cl';
|
|
break;
|
|
default:
|
|
$class = '';
|
|
}
|
|
|
|
$sql = "SELECT " .
|
|
"pia.`control_id`,pia.`name`,pia.`subject_area`,pia.`description`," .
|
|
"pia.`threat_vul_cm`,pia.`gen_imp_guide`,pia.`guide_resource`,pia.`impact` " .
|
|
"FROM `sagacity`.`proc_ia_controls` pia " .
|
|
"LEFT JOIN `sagacity`.`proc_level_type` plt ON plt.`proc_control`=pia.`control_id` " .
|
|
"WHERE plt.`type`='diacap' AND " .
|
|
"plt.`level`=" . $sys->get_MAC() . " AND " .
|
|
"plt.`class`='$class'";
|
|
|
|
if (!is_null($control_id)) {
|
|
$sql .= " AND pia.`control_id`='" . $this->conn->real_escape_string($control_id) . "'";
|
|
}
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ia = new proc_ia_controls($row['control_id'], $row['name'], $row['subject_area'], $row['description'], $row['threat_vul_cm'], $row['gen_imp_guide'], $row['guide_resource'], $row['impact']);
|
|
|
|
$sql2 = "SELECT `ste_id`,`control_id`,`vul_desc`,`mitigations`,`references`,`risk_analysis`,`notes`,`done` " .
|
|
"FROM `sagacity`.`control_findings` " .
|
|
"WHERE `ste_id`=" . $ste_in->get_ID() . " AND " .
|
|
"`control_id`='" . $row['control_id'] . "'";
|
|
if ($res2 = $this->conn->query($sql2)) {
|
|
if ($res2->num_rows > 0) {
|
|
$row2 = $res2->fetch_assoc();
|
|
|
|
$ia->finding->control_id = $row2['control_id'];
|
|
$ia->finding->ste_id = $row2['ste_id'];
|
|
$ia->finding->vul_desc = $row2['vul_desc'];
|
|
$ia->finding->mitigations = $row2['mitigations'];
|
|
$ia->finding->reference = $row2['references'];
|
|
$ia->finding->notes = $row2['notes'];
|
|
$ia->finding->risk_analysis = $row2['risk_analysis'];
|
|
$ia->finding->done = $row2['done'];
|
|
}
|
|
}
|
|
|
|
$sql2 = "SELECT " .
|
|
"`sub_control_id`,`name`,`objective`," .
|
|
"`prep`,`script`,`exp_result` " .
|
|
"FROM `sagacity`.`proc_ia_sub_controls` " .
|
|
"WHERE `parent_control_id`='" . $row['control_id'] . "'";
|
|
|
|
if ($res2 = $this->conn->query($sql2)) {
|
|
while ($row2 = $res2->fetch_assoc()) {
|
|
$ia_sub = new proc_sub_ia_controls($row2['sub_control_id'], $row2['name'], $row2['objective'], $row2['prep'], $row2['script'], $row2['exp_result']);
|
|
|
|
$sql3 = "SELECT " .
|
|
"`ste_id`,`proc_id`,`status`,`test_results`," .
|
|
"`mitigations`,`milestones`,`ref`,`notes` " .
|
|
"FROM `sagacity`.`proc_findings` " .
|
|
"WHERE `ste_id`=" . $ste_in->get_ID() . " AND " .
|
|
"`proc_id`='" . $row2['sub_control_id'] . "'";
|
|
|
|
if ($res3 = $this->conn->query($sql3)) {
|
|
if ($res3->num_rows > 0) {
|
|
$row3 = $res3->fetch_assoc();
|
|
|
|
$ia_sub->finding->control_id = $row3['proc_id'];
|
|
$ia_sub->finding->ste_id = $row3['ste_id'];
|
|
$ia_sub->finding->test_result = $row3['test_results'];
|
|
$ia_sub->finding->mitigation = $row3['mitigations'];
|
|
$ia_sub->finding->milestone = $row3['milestones'];
|
|
$ia_sub->finding->reference = $row3['ref'];
|
|
$ia_sub->finding->notes = $row3['notes'];
|
|
$ia_sub->finding->status = $row3['status'];
|
|
}
|
|
else {
|
|
$ia_sub->finding->status = 'Not Reviewed';
|
|
}
|
|
}
|
|
|
|
$ia->add_Sub($ia_sub);
|
|
}
|
|
}
|
|
|
|
$ret[] = $ia;
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ INTERVIEW QUESTION CLASS FUNCTIONS
|
|
/**
|
|
* Function to return the categories
|
|
*
|
|
* @return array:string
|
|
*/
|
|
public function get_Question_Categories()
|
|
{
|
|
$ret = [];
|
|
$this->help->select("interview_questions", ['cat'], [], ['group' => 'cat']);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = $row['cat'];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get the questions
|
|
*
|
|
* @param integer $cat_in
|
|
* @param string $type_in
|
|
*/
|
|
public function get_Questions($cat_in, $type_in = null)
|
|
{
|
|
$ret = [];
|
|
$sql = "SELECT " .
|
|
"iq.`id`,iq.`key`,iq.`cat`,iq.`question`," .
|
|
"(SELECT ci.`answer` " .
|
|
"FROM `category_interview` ci " .
|
|
"WHERE ci.`ques_id`=iq.`id` AND ci.`cat_id`=" . $this->conn->real_escape_string($cat_in) . ") AS 'answer' " .
|
|
"FROM `interview_questions` iq " .
|
|
"WHERE iq.`cat`='" . $this->conn->real_escape_string($type_in) . "'";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ques = new question();
|
|
$ques->id = $row['id'];
|
|
$ques->cat = $row['cat'];
|
|
$ques->key = $row['key'];
|
|
$ques->question = $row['question'];
|
|
$ques->answer = $row['answer'];
|
|
|
|
$ret[] = $ques;
|
|
}
|
|
}
|
|
else {
|
|
print $sql . "<br />";
|
|
print $this->conn->error;
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to return the interview questions with their answers
|
|
*
|
|
* @param int $cat_id_in
|
|
*
|
|
* @return array:question
|
|
*/
|
|
public function get_Interview_Answers($cat_id_in)
|
|
{
|
|
$ret = [];
|
|
$this->help->select("interview_questions iq", ['iq.id', 'iq.key', 'iq.question', 'ci.answer'], [
|
|
[
|
|
'field' => 'ci.cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id_in
|
|
]
|
|
], [
|
|
'table_joins' => "LEFT JOIN category_interview ci ON iq.id = ci.ques_id"
|
|
]);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ques = new question();
|
|
|
|
$ques->id = $row['id'];
|
|
$ques->key = $row['key'];
|
|
$ques->question = $row['question'];
|
|
$ques->answer = ($row['answer'] ? true : false);
|
|
|
|
$ret[] = $ques;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to reset the interview answers
|
|
*
|
|
* @param string $type_in
|
|
* @param int $cat_in
|
|
*/
|
|
public function set_Questions($type_in, $cat_in)
|
|
{
|
|
$this->help->delete("category_interview", null, [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_in
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$this->help->sql = "INSERT IGNORE INTO `category_interview` (`cat_id`,`ques_id`)" .
|
|
" SELECT " . $this->conn->real_escape_string($cat_in) . ",`id`" .
|
|
" FROM `interview_questions`" .
|
|
" WHERE `cat`='" . $this->conn->real_escape_string($type_in) . "'";
|
|
$this->help->query_type = db_helper::INSERT;
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to set the answer for an interview question
|
|
*
|
|
* @param int $cat_id_in
|
|
* @param question $question
|
|
* @return boolean
|
|
*/
|
|
public function set_QA($cat_id_in, $question)
|
|
{
|
|
$this->help->update("category_interview", ['answer' => ($question->answer)], [
|
|
[
|
|
'field' => 'ques_id',
|
|
'op' => '=',
|
|
'value' => $question->id
|
|
],
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $cat_id_in,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ RETINA CLASS FUNCTIONS
|
|
/**
|
|
* Update retina data
|
|
*
|
|
* @param retina $retina_In
|
|
* Retina object to save to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Retina($retina_In)
|
|
{
|
|
$sql = "REPLACE INTO `sagacity`.`retina` (`pdi_id`,`retina_id`) VALUES (" .
|
|
$this->conn->real_escape_string($retina_In->get_PDI_ID()) . "," .
|
|
$this->conn->real_escape_string($retina_In->get_Retina_ID()) . ")";
|
|
|
|
if (!$this->conn->real_query($sql)) {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ RMF_CONTROL CLASS FUNCTIONS
|
|
/**
|
|
* Function to get all the RMF controls that apply to a certain baseline impact<br />
|
|
* Used for tailoring later
|
|
*
|
|
* @param string $baseline
|
|
*
|
|
* @return array:rmf_control
|
|
*/
|
|
public function get_RMF_Control_By_Baseline($baseline)
|
|
{
|
|
$ret = [];
|
|
if (!in_array($baseline, array("low", "moderate", "high"))) {
|
|
return [];
|
|
}
|
|
|
|
$sql = "SELECT " .
|
|
"f.`abbr`,f.`name` AS 'family_name' " .
|
|
"c.`control_id`,c.`name` AS 'control_name',c.`pri`,c.`statement`,c.`guidance` " .
|
|
"cb.`impact_level` " .
|
|
"FROM `rmf`.`controls` c " .
|
|
"JOIN `rmf`.`control_baseline` cb ON cb.`control_id`=c.`control_id` " .
|
|
"JOIN `rmf`.`family` f ON f.`abbr`=c.`family_id` " .
|
|
"WHERE cb.`impact_level`='" . $this->conn->real_escape_string($baseline) . "'"
|
|
;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$family = new rmf_family();
|
|
$family->set_Abbr($row['abbr']);
|
|
$family->set_Name($row['family_name']);
|
|
|
|
$rmf = new rmf_control();
|
|
$rmf->family = $family;
|
|
$rmf->set_Control_ID($row['control_id']);
|
|
$rmf->set_Name($row['control_name']);
|
|
$rmf->set_Priority($row['pri']);
|
|
$rmf->set_Statement($row['statement']);
|
|
$rmf->set_Guidance($row['guidance']);
|
|
$rmf->set_Baseline($baseline, true);
|
|
|
|
$this->get_RMF_Related_Controls($rmf);
|
|
$this->get_RMF_Enhanced_Controls($rmf, $baseline);
|
|
|
|
$ret[] = $rmf;
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get all the related controls
|
|
*
|
|
* @param rmf_control $rmf
|
|
*/
|
|
public function get_RMF_Related_Controls(rmf_control &$rmf)
|
|
{
|
|
$sql = "SELECT rc.`related_control_id` " .
|
|
"FROM `rmf`.`related_controls rc " .
|
|
"WHERE rc.`control_id`='" . $this->conn->real_escape_string($rmf->get_Control_ID()) . "'"
|
|
;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$rmf->add_Related_Control($row['related_control_id']);
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to get all the enhanced controls
|
|
*
|
|
* @param rmf_control $rmf
|
|
* @param string $baseline
|
|
*/
|
|
public function get_RMF_Enhanced_Controls(rmf_control &$rmf, $baseline = null)
|
|
{
|
|
$sql = "SELECT " .
|
|
"ce.`enh_id`,ce.`name`,ce.`desc`,ce.`guidance` " .
|
|
"FROM `rmf`.`control_enh` ce " .
|
|
"JOIN `rmf`.`enhancement_baseline eb ON eb.`control_id`=ce.`control_id` AND " .
|
|
"eb.`enh_id`=ce.`enh_id` " .
|
|
"WHERE ce.`control_id`='" . $this->conn->real_escape_string($rmf->get_Control_ID()) . "' AND " .
|
|
"eb.`impact`='" . (is_null($baseline) ? $rmf->get_Worst_Baseline() : $baseline) . "'"
|
|
;
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$enh = new rmf_control_enhancements();
|
|
$enh->set_Enhanced_ID($row['enh_id']);
|
|
$enh->set_Guidance($row['guidance']);
|
|
$enh->set_Name($row['name']);
|
|
$enh->set_Statement($row['desc']);
|
|
|
|
$rmf->add_Enhanced_Control($enh);
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SCAN CLASS FUNCTIONS
|
|
/**
|
|
* Get ScanData for Results page
|
|
*
|
|
* @param integer $intSTE
|
|
* ST&E ID to grab scans for
|
|
* @param integer|string $Scan_ID [optional]
|
|
* Scan ID or file name to grab (defaulted null)
|
|
*
|
|
* @return array:scan|NULL
|
|
* Returns array of scans associated with the ST&E, or null if none found
|
|
*/
|
|
public function get_ScanData($intSTE, $Scan_ID = null, $status_in = null, $type_in = null)
|
|
{
|
|
$ret = [];
|
|
$where = [
|
|
[
|
|
'field' => 's.ste_id',
|
|
'value' => $intSTE
|
|
]
|
|
];
|
|
|
|
if (!is_null($Scan_ID)) {
|
|
if (is_numeric($Scan_ID)) {
|
|
$where[] = [
|
|
'field' => 's.id',
|
|
'value' => $Scan_ID,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 's.file_name',
|
|
'value' => $Scan_ID,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!is_null($status_in)) {
|
|
$where[] = [
|
|
'field' => 's.status',
|
|
'value' => $status_in,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
if (!is_null($type_in)) {
|
|
$where[] = [
|
|
'field' => 'src.name',
|
|
'value' => $type_in,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("scans s", ['s.*'], $where, [
|
|
'table_joins' => [
|
|
"JOIN sources src ON src.id=s.src_id"
|
|
],
|
|
'order' => 's.file_name'
|
|
]);
|
|
|
|
$scan_rows = $this->help->execute();
|
|
if (isset($scan_rows['id'])) {
|
|
$scan_rows = [0 => $scan_rows];
|
|
}
|
|
if (is_array($scan_rows) && count($scan_rows)) {
|
|
foreach ($scan_rows as $row) {
|
|
$src = $this->get_Sources($row['src_id']);
|
|
if (is_array($src) && count($src) && isset($src[0]) && is_a($src[0], 'source')) {
|
|
$src = $src[0];
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
|
|
$ste = $this->get_STE($intSTE);
|
|
if (is_array($ste) && count($ste) && isset($ste[0]) && is_a($ste[0], 'ste')) {
|
|
$ste = $ste[0];
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
|
|
$scan = new scan($row['id'], $src, $ste, $row['itr'], $row['file_name'], $row['file_date']);
|
|
$scan->set_Notes($row['notes']);
|
|
$scan->set_PID($row['pid']);
|
|
$scan->set_Start_Time($row['start_time']);
|
|
$scan->set_Last_Update($row['last_update']);
|
|
$scan->set_Status($row['status']);
|
|
$scan->set_Percentage_Complete($row['perc_comp']);
|
|
$scan->set_Last_Host($row['last_host']);
|
|
$scan->set_Total_Host_Count($row['host_count']);
|
|
|
|
$this->help->select("host_list hl", ['hl.tgt_id', 't.name', 'hl.finding_count', 'hl.scanner_error', 'hl.notes'], [
|
|
[
|
|
'field' => 'hl.scan_id',
|
|
'value' => $row['id']
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN target t ON t.id=hl.tgt_id"
|
|
]
|
|
]);
|
|
$hl_rows = $this->help->execute();
|
|
if (is_array($hl_rows) && count($hl_rows) && isset($hl_rows['tgt_id'])) {
|
|
$hl_rows = [0 => $hl_rows];
|
|
}
|
|
if (is_array($hl_rows) && count($hl_rows) && isset($hl_rows[0])) {
|
|
foreach ($hl_rows as $row) {
|
|
$tgt = new target($row['name']);
|
|
$tgt->set_ID($row['tgt_id']);
|
|
$tgt->set_STE_ID($intSTE);
|
|
$tgt->interfaces = $this->get_Interfaces($tgt->get_ID());
|
|
if ((bool) $row['scanner_error']) {
|
|
$scan->setScanError((bool) $row['scanner_error']);
|
|
}
|
|
|
|
$hl = new host_list();
|
|
$hl->setTargetId($tgt->get_ID());
|
|
$hl->setTargetName($tgt->get_Name());
|
|
$hl->setTargetIp($tgt->getIP());
|
|
$hl->setFindingCount($row['finding_count']);
|
|
$hl->setScanError((bool) $row['scanner_error']);
|
|
$hl->setScanNotes($row['notes']);
|
|
|
|
$scan->add_Target_to_Host_List($hl);
|
|
}
|
|
}
|
|
|
|
$ret[] = $scan;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Save scan data
|
|
*
|
|
* @param scan $new_Scan
|
|
* New scan to save to database
|
|
*
|
|
* @return integer
|
|
* Returns ID of new scan, or 0 if fail
|
|
*/
|
|
public function save_Scan($new_Scan)
|
|
{
|
|
if (!is_a($new_Scan, "scan")) {
|
|
return;
|
|
}
|
|
if (!is_a($new_Scan->get_Source(), 'source')) {
|
|
throw(new Exception("Wrong source type " . print_r($new_Scan->get_Source(), true)));
|
|
}
|
|
if ($new_Scan->get_ID()) {
|
|
$this->help->update("scans", [
|
|
'src_id' => $new_Scan->get_Source()->get_ID(),
|
|
'itr' => $new_Scan->get_Itr(),
|
|
'file_date' => $new_Scan->get_File_DateTime(),
|
|
'pid' => $new_Scan->get_PID(),
|
|
'start_time' => $new_Scan->get_Start_Time(),
|
|
'last_update' => $new_Scan->get_Last_Update(),
|
|
'status' => $new_Scan->get_Status(),
|
|
'perc_comp' => $new_Scan->get_Percentage_Complete(),
|
|
'last_host' => $new_Scan->get_Last_Host(),
|
|
'host_count' => $new_Scan->get_Total_Host_Count(),
|
|
'notes' => $new_Scan->get_Notes()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'value' => $new_Scan->get_ID()
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
$this->update_Scan_Host_List($new_Scan, $new_Scan->get_Host_List());
|
|
}
|
|
else {
|
|
$this->help->insert("scans", [
|
|
'src_id' => $new_Scan->get_Source()->get_ID(),
|
|
'ste_id' => $new_Scan->get_STE()->get_ID(),
|
|
'itr' => $new_Scan->get_Itr(),
|
|
'file_name' => $new_Scan->get_File_Name(),
|
|
'file_date' => $new_Scan->get_File_DateTime(),
|
|
'pid' => $new_Scan->get_PID(),
|
|
'start_time' => $new_Scan->get_Start_Time(),
|
|
'last_update' => $new_Scan->get_Last_Update(),
|
|
'status' => $new_Scan->get_Status(),
|
|
'perc_comp' => $new_Scan->get_Percentage_Complete(),
|
|
'last_host' => $new_Scan->get_Last_Host(),
|
|
'host_count' => $new_Scan->get_Total_Host_Count(),
|
|
'notes' => $new_Scan->get_Notes()
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
$new_Scan->set_ID($this->conn->insert_id);
|
|
|
|
$this->update_Scan_Host_List($new_Scan, $new_Scan->get_Host_List());
|
|
}
|
|
return $new_Scan->get_ID();
|
|
}
|
|
|
|
/**
|
|
* Delete a scan (associated finding data and optionally targets)
|
|
*
|
|
* @param integer $ste_id
|
|
* ST&E ID where the scan exists
|
|
* @param integer $scan_id
|
|
* Scan to delete from database
|
|
* @param boolean $del_tgts
|
|
* Boolean to decide if we are deleting targets as well
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Scan($ste_id, $scan_id, $del_tgts = false)
|
|
{
|
|
$scan = $this->get_ScanData($ste_id, $scan_id);
|
|
|
|
if (is_array($scan) && count($scan) && isset($scan[0]) && is_a($scan[0], 'scan')) {
|
|
$scan = $scan[0];
|
|
}
|
|
elseif (!is_a($scan, 'scan')) {
|
|
Sagacity_Error::err_handler("Failed to find Scan ($scan_id)", E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("finding_controls fc", ['fc.*'], [
|
|
[
|
|
'field' => 'f.scan_id',
|
|
'op' => '=',
|
|
'value' => $scan_id
|
|
]
|
|
], [
|
|
"JOIN findings f ON f.id=fc.finding_id"
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("findings", null, [
|
|
[
|
|
'field' => 'scan_id',
|
|
'op' => '=',
|
|
'value' => $scan_id
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("host_list", null, [
|
|
[
|
|
'field' => 'scan_id',
|
|
'op' => '=',
|
|
'value' => $scan_id
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("scans", null, [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $scan_id
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
if ($del_tgts) {
|
|
/**
|
|
* @var host_list $host
|
|
*/
|
|
foreach ($scan->get_Host_List() as $host) {
|
|
$this->delete_Target($host->getTargetId());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Updates the host_list field for a particular scan
|
|
*
|
|
* @param scan $scan
|
|
* Scan to update
|
|
* @param array $host_list [optional]
|
|
* Formatted host list to update (default null)
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSEs
|
|
*/
|
|
public function update_Scan_Host_List($scan, $host_list = null)
|
|
{
|
|
$this->help->delete("host_list", null, [
|
|
[
|
|
'field' => 'scan_id',
|
|
'value' => $scan->get_ID()
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
$params = [];
|
|
if (is_null($host_list)) {
|
|
foreach ($scan->get_Host_List() as $host) {
|
|
$params[] = [
|
|
$scan->get_ID(),
|
|
$host->getTargetId(),
|
|
$host->getFindingCount(),
|
|
$host->getScanError(),
|
|
$host->getScanNotes()
|
|
];
|
|
}
|
|
}
|
|
else {
|
|
foreach ($host_list as $host) {
|
|
if (!is_a($host, 'host_list')) {
|
|
break;
|
|
}
|
|
$params[] = [
|
|
$scan->get_ID(),
|
|
$host->getTargetId(),
|
|
$host->getFindingCount(),
|
|
$host->getScanError(),
|
|
$host->getScanNotes()
|
|
];
|
|
}
|
|
}
|
|
|
|
if (count($params)) {
|
|
$this->help->extended_insert("host_list", ['scan_id', 'tgt_id', 'finding_count', 'scanner_error', 'notes'], $params);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the scan source data
|
|
*
|
|
* @param integer|string $srcID
|
|
* Source ID or name to grab from database
|
|
*
|
|
* @return source|NULL
|
|
* Returns source, or null if none found
|
|
*/
|
|
public function get_Sources($srcID = null)
|
|
{
|
|
$where = [];
|
|
$ret = null;
|
|
|
|
if (!is_null($srcID)) {
|
|
if (is_numeric($srcID)) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $srcID
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => $srcID,
|
|
'case_insensitive' => true
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("sagacity.sources", null, $where, ['order' => 'name']);
|
|
$src_rows = $this->help->execute();
|
|
|
|
if (is_array($src_rows) && isset($src_rows['id'])) {
|
|
$src_rows = [0 => $src_rows];
|
|
}
|
|
|
|
if (is_array($src_rows) && count($src_rows) && isset($src_rows[0])) {
|
|
foreach ($src_rows as $row) {
|
|
$src = new source($row['id'], $row['name']);
|
|
$src->set_Icon($row['icon']);
|
|
|
|
$ret[] = $src;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get the expected sources for a category
|
|
*
|
|
* @param ste_cat $cat
|
|
*
|
|
* @return array:source|array
|
|
*/
|
|
public function get_Expected_Category_Sources($cat)
|
|
{
|
|
if (is_array($cat) && count($cat)) {
|
|
$cat = $cat[0];
|
|
}
|
|
if (!is_a($cat, "ste_cat")) {
|
|
return [];
|
|
}
|
|
$ret = [];
|
|
$this->help->select("sagacity.sources s", ['s.id', 's.name', 's.icon'], [
|
|
[
|
|
'field' => 'cat.id',
|
|
'op' => '=',
|
|
'value' => $cat->get_ID()
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN sagacity.ste_cat_sources src ON s.id=src.src_id",
|
|
"JOIN sagacity.ste_cat cat ON cat.id=src.cat_id"
|
|
]
|
|
]);
|
|
|
|
$src_arr = $this->help->execute();
|
|
if (is_array($src_arr) && count($src_arr) && isset($src_arr['id'])) {
|
|
$src_arr = [0 => $src_arr];
|
|
}
|
|
|
|
if (is_array($src_arr) && count($src_arr) && isset($src_arr[0])) {
|
|
foreach ($src_arr as $row) {
|
|
$src = new source($row['id'], $row['name']);
|
|
$icon = null;
|
|
if ($row['icon']) {
|
|
$icon = str_replace(" ", "-", substr($row['icon'], 0, -4)) . "-missing.png";
|
|
}
|
|
$src->set_Icon($icon);
|
|
$ret[$src->get_ID()]['src'] = $src;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Find the sources that have contained this target
|
|
*
|
|
* @param target $tgt
|
|
* @param array $exp_scan_srcs
|
|
*
|
|
* @return array:sources
|
|
*/
|
|
public function get_Target_Scan_Sources($tgt, &$exp_scan_srcs = null)
|
|
{
|
|
$ret = [];
|
|
$this->help->select("sources src", ["src.id", "src.name", "src.icon", "SUM(hl.finding_count) AS 'finding_count'", "hl.scanner_error", "hl.notes"], [
|
|
[
|
|
'field' => 'hl.tgt_id',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN scans s ON s.src_id=src.id",
|
|
"LEFT JOIN host_list hl ON hl.scan_id=s.id"
|
|
],
|
|
'group' => 'src.name,src.id'
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
if (is_null($exp_scan_srcs)) {
|
|
foreach ($rows as $row) {
|
|
$ret[$row['id']]['src'] = new source($row['id'], $row['name']);
|
|
$ret[$row['id']]['src']->set_Icon($row['icon']);
|
|
$ret[$row['id']]['count'] = $row['finding_count'];
|
|
$ret[$row['id']]['scan_error'] = (boolean) $row['scanner_error'];
|
|
$ret[$row['id']]['notes'] = $row['notes'];
|
|
}
|
|
}
|
|
else {
|
|
foreach ($rows as $row) {
|
|
if (isset($exp_scan_srcs[$row['id']])) {
|
|
$exp_scan_srcs[$row['id']]['src']->set_Icon($row['icon']);
|
|
$exp_scan_srcs[$row['id']]['count'] = $row['finding_count'];
|
|
$exp_scan_srcs[$row['id']]['scan_error'] = (boolean) $row['scanner_error'];
|
|
$exp_scan_srcs[$row['id']]['notes'] = $row['notes'];
|
|
}
|
|
else {
|
|
$exp_scan_srcs[$row['id']]['src'] = new source($row['id'], $row['name']);
|
|
$exp_scan_srcs[$row['id']]['src']->set_Icon($row['icon']);
|
|
$exp_scan_srcs[$row['id']]['count'] = $row['finding_count'];
|
|
$exp_scan_srcs[$row['id']]['scan_error'] = (boolean) $row['scanner_error'];
|
|
$exp_scan_srcs[$row['id']]['notes'] = $row['notes'];
|
|
}
|
|
}
|
|
|
|
return $exp_scan_srcs;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SCRIPT FUNCTIONS
|
|
/**
|
|
* Function to get a catalog script
|
|
*
|
|
* @param string $file_name_in [optional]
|
|
* Look for a specific catalog/STIG file that is processing
|
|
*
|
|
* @return array:catalog_script|NULL
|
|
*/
|
|
public function get_Catalog_Script($file_name_in = null)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if (!is_null($file_name_in)) {
|
|
$where[] = [
|
|
'field' => 'file_name',
|
|
'op' => '=',
|
|
'value' => $file_name_in
|
|
];
|
|
}
|
|
|
|
$this->help->select("sagacity.catalog_scripts", null, $where, [
|
|
'order' => "FIELD(`status`, 'ERROR','RUNNING','IN QUEUE','COMPLETE'),`file_name`"
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['file_name'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows)) {
|
|
foreach ($rows as $row) {
|
|
$script = new catalog_script();
|
|
|
|
$script->file_name = $row['file_name'];
|
|
$script->pid = $row['pid'];
|
|
$script->start_time = new DateTime($row['start_time']);
|
|
$script->last_update = new DateTime($row['last_update']);
|
|
$script->status = $row['status'];
|
|
$script->perc_comp = $row['perc_comp'];
|
|
$script->stig_count = $row['stig_count'];
|
|
|
|
$ret[] = $script;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to get script count
|
|
*
|
|
* @param string $status [optional]
|
|
* Return only the count for a script that is in a certain status (defaulted null)
|
|
*
|
|
* @return integer
|
|
* Returns the number of script that are in the database or count in a specific status
|
|
*/
|
|
public function get_Catalog_Script_Count($status = null)
|
|
{
|
|
$where = [];
|
|
if (!is_null($status)) {
|
|
$where[] = [
|
|
'field' => 'status',
|
|
'op' => '=',
|
|
'value' => $status
|
|
];
|
|
|
|
if ($status == 'RUNNING') {
|
|
$where[] = [
|
|
'field' => 'perc_comp',
|
|
'op' => '<',
|
|
'value' => 100,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
];
|
|
$where[] = [
|
|
'field' => 'perc_comp',
|
|
'op' => IS,
|
|
'value' => null,
|
|
'sql_op' => 'OR',
|
|
'close-paren' => true
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select_count("sagacity.catalog_scripts", $where);
|
|
|
|
if ($count = $this->help->execute()) {
|
|
return $count;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Function to add new catalog parsing script
|
|
*
|
|
* @param string $file_name_in
|
|
* The catalog/STIG file that is processing
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function add_Catalog_Script($file_name_in)
|
|
{
|
|
$this->help->insert("sagacity.catalog_scripts", ['file_name' => $file_name_in], true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to update catalog script execution
|
|
*
|
|
* @param string $file
|
|
* Script to update
|
|
* @param array $field
|
|
* Array with the name and value of the column to update
|
|
* 'name' => 'pid',
|
|
* 'value' => 1234
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function update_Catalog_Script($file, $field)
|
|
{
|
|
$where = array(
|
|
array(
|
|
'field' => 'file_name',
|
|
'op' => '=',
|
|
'value' => $file
|
|
)
|
|
);
|
|
|
|
if ($field['name'] == 'perc_comp' && $field['value'] == 100 && isset($field['complete'])) {
|
|
$this->help->update("sagacity.catalog_scripts", array(
|
|
$field['name'] => $field['value'],
|
|
'status' => 'COMPLETE',
|
|
'last_update' => 'NOW()'
|
|
), $where);
|
|
}
|
|
elseif ($field['name'] == 'pid') {
|
|
$this->help->update("sagacity.catalog_scripts", array(
|
|
$field['name'] => $field['value'],
|
|
'status' => 'RUNNING',
|
|
'start_time' => 'NOW()',
|
|
'last_update' => 'NOW()'
|
|
), $where);
|
|
}
|
|
else {
|
|
$this->help->update('sagacity.catalog_scripts', array(
|
|
$field['name'] => $field['value'],
|
|
'last_update' => 'NOW()'
|
|
), $where);
|
|
}
|
|
|
|
if (!$this->help->execute()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to get the number of scripts that are currently running
|
|
*
|
|
* @param integer $ste
|
|
* ST&E to evaluate
|
|
*
|
|
* @return integer
|
|
* Returns the count of scripts that are running
|
|
*/
|
|
public function get_Running_Script_Count($ste)
|
|
{
|
|
$this->help->select_count("scans", [
|
|
[
|
|
'field' => 'status',
|
|
'op' => '=',
|
|
'value' => 'RUNNING'
|
|
],
|
|
[
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $ste,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Getter function to retrieve the status of a result script
|
|
*
|
|
* @param int $ste_id
|
|
* @param string $file
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_Running_Script_Status($ste_id, $file)
|
|
{
|
|
$this->help->select("sagacity.scans", ['status', 'perc_comp'], [
|
|
[
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $ste_id
|
|
],
|
|
[
|
|
'field' => 'file_name',
|
|
'op' => '=',
|
|
'value' => $file,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Add a new script to the database
|
|
*
|
|
* @param string $file
|
|
* Result file name
|
|
* @param integer $ste_id
|
|
* The STE ID that the script is being added to
|
|
* @param string $type
|
|
* The result type
|
|
*
|
|
* @return boolean
|
|
* Return TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function add_Running_Script($file, $ste_id, $type, $location)
|
|
{
|
|
$existing_scan = $this->get_ScanData($ste_id, $file);
|
|
|
|
if (is_array($existing_scan) && count($existing_scan) && isset($existing_scan[0]) && is_a($existing_scan[0], 'scan')) {
|
|
$scan = $existing_scan[0];
|
|
|
|
$this->help->update("scans", [
|
|
'start_time' => 'NOW()',
|
|
'last_update' => 'NOW()',
|
|
'perc_comp' => 0.0
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $scan->get_ID()
|
|
]
|
|
]);
|
|
}
|
|
else {
|
|
$type = str_replace("_", " ", $type);
|
|
$src = $this->get_Sources($type);
|
|
|
|
if (is_array($src) && count($src) && is_a($src[0], 'source')) {
|
|
$src = $src[0];
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
$fd = date("Y-m-d", filemtime(TMP . "/" . $file));
|
|
|
|
$this->help->insert("sagacity.scans", [
|
|
'ste_id' => $ste_id,
|
|
'src_id' => $src->get_ID(),
|
|
'file_name' => $file,
|
|
'file_date' => $fd,
|
|
'start_time' => 'NOW()',
|
|
'last_update' => 'NOW()',
|
|
'status' => 'IN QUEUE',
|
|
'perc_comp' => 0.0,
|
|
'location' => $location
|
|
], true);
|
|
}
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to update a running script entry to add the process ID
|
|
*
|
|
* @param string $file
|
|
* The result file to update
|
|
* @param array $field
|
|
* Associative array (name,value) to know what field to update
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function update_Running_Scan($file, $field)
|
|
{
|
|
$where = [
|
|
[
|
|
'field' => 'file_name',
|
|
'op' => '=',
|
|
'value' => $file
|
|
]
|
|
];
|
|
|
|
if ($field['name'] == 'perc_comp' && $field['value'] == 100 && isset($field['complete'])) {
|
|
$this->help->update("sagacity.scans", [
|
|
$field['name'] => $field['value'],
|
|
'status' => 'COMPLETE',
|
|
'last_update' => 'NOW()'
|
|
], $where);
|
|
}
|
|
elseif ($field['name'] == 'pid') {
|
|
$this->help->update("sagacity.scans", [
|
|
$field['name'] => $field['value'],
|
|
'status' => 'RUNNING',
|
|
'start_time' => 'NOW()',
|
|
'last_update' => 'NOW()',
|
|
'host_count' => 0
|
|
], $where);
|
|
}
|
|
elseif ($field['name'] == 'last_host') {
|
|
$this->help->update("sagacity.scans s", [
|
|
"s.{$field['name']}" => $field['value'],
|
|
's.last_update' => 'NOW()',
|
|
's.hosts_comp' => "s.`hosts_comp`+1"
|
|
], $where);
|
|
}
|
|
else {
|
|
$this->help->update("sagacity.scans", [
|
|
$field['name'] => $field['value'],
|
|
'last_update' => 'NOW()'
|
|
], $where);
|
|
}
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SITE CLASS FUNCTIONS
|
|
/**
|
|
* Get site data
|
|
*
|
|
* @param integer $siteID [optional]
|
|
* Site ID to get from database
|
|
*
|
|
* @return array:site
|
|
* Returns array of sites, or empty array if none found
|
|
*/
|
|
public function get_Site($siteID = null)
|
|
{
|
|
$where = [];
|
|
$sites = [];
|
|
|
|
if (!is_null($siteID)) {
|
|
if (is_numeric($siteID)) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $siteID
|
|
];
|
|
}
|
|
else {
|
|
$where = [
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => $siteID
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("sites", null, $where, ['order' => 'name']);
|
|
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$sites[] = new site($row['id'], $row['name'], $row['address'], $row['city'], $row['state'], $row['zip'], $row['country'], $row['poc_name'], $row['poc_email'], $row['poc_phone']);
|
|
}
|
|
}
|
|
|
|
return $sites;
|
|
}
|
|
|
|
/**
|
|
* Get a site for an ST&E
|
|
*
|
|
* @param integer $intSTE
|
|
* ID of the STE to isolate
|
|
*
|
|
* @return site|NULL
|
|
* Returns array of sites associated with a specific ST&E, or null if none found
|
|
*/
|
|
public function get_Site_By_STE_ID($intSTE)
|
|
{
|
|
$this->help->select("sites s", ['s.*'], [
|
|
[
|
|
'field' => 'ste.id',
|
|
'op' => '=',
|
|
'value' => $intSTE
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN ste ON ste.site_id = s.id"
|
|
]
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
if (is_array($row) && count($row) && isset($row['id'])) {
|
|
$site = new site($row['id'], $row['name'], $row['address'], $row['city'], $row['state'], $row['zip'], $row['country'], $row['poc_name'], $row['poc_email'], $row['poc_phone']);
|
|
|
|
return $site;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Update or insert a site
|
|
*
|
|
* @param site $site_In
|
|
* Site to save to the database
|
|
*
|
|
* @return boolean|NULL
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Site(site $site_In)
|
|
{
|
|
if ($site_In->get_Id()) {
|
|
$this->help->update("sites", [
|
|
'name' => $site_In->get_Name(),
|
|
'address' => $site_In->get_Address(),
|
|
'city' => $site_In->get_City(),
|
|
'state' => $site_In->get_State(),
|
|
'zip' => $site_In->get_Zip(),
|
|
'country' => $site_In->get_Country(),
|
|
'poc_name' => $site_In->get_POC_Name(),
|
|
'poc_email' => $site_In->get_POC_Email(),
|
|
'poc_phone' => $site_In->get_POC_Phone()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $site_In->get_Id()
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return $site_In->get_Id();
|
|
}
|
|
else {
|
|
$this->help->insert("sites", [
|
|
'name' => $site_In->get_Name(),
|
|
'address' => $site_In->get_Address(),
|
|
'city' => $site_In->get_City(),
|
|
'state' => $site_In->get_State(),
|
|
'zip' => $site_In->get_Zip(),
|
|
'country' => $site_In->get_Country(),
|
|
'poc_name' => $site_In->get_POC_Name(),
|
|
'poc_email' => $site_In->get_POC_Email(),
|
|
'poc_phone' => $site_In->get_POC_Phone()
|
|
], true);
|
|
|
|
if (!($site_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return $site_id;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SOFTWARE CLASS FUNCTIONS
|
|
/**
|
|
* Get software data
|
|
*
|
|
* @param integer|string|software $software_In
|
|
* Specific ID, array of software objects, or associative array to use (default null)
|
|
* @param boolean $exact_match [optional]
|
|
* Perform an exact match on a CPE (default false)
|
|
*
|
|
* @return array:software
|
|
* Returns array of matching software, or empty array if none found
|
|
*/
|
|
public function get_Software($software_In, $exact_match = false)
|
|
{
|
|
$ret = [];
|
|
$cpe = null;
|
|
$sw = null;
|
|
$query = false;
|
|
|
|
if (is_array($software_In)) {
|
|
if (isset($software_In[0]) && is_a($software_In[0], 'software')) {
|
|
$cpe = $software_In[0]->get_CPE();
|
|
}
|
|
elseif (isset($software_In[0]) && isset($software_In[0]['man'])) {
|
|
$software_In = $software_In[0];
|
|
|
|
$type = (isset($software_In['type']) && $software_In['type'] ? "o" : "a");
|
|
$ver = (isset($software_In['ver']) && $software_In['ver'] ? $software_In['ver'] : "-");
|
|
$cpe = strtolower(
|
|
str_replace(
|
|
array(" ", "(", ")"), array("_", "%28", "%29"), "cpe:/{$type}:{$software_In['man']}:{$software_In['name']}:{$ver}"
|
|
)
|
|
);
|
|
}
|
|
|
|
if ($cpe) {
|
|
$this->help->select("sagacity.software", null, array(
|
|
array(
|
|
'field' => 'cpe',
|
|
'op' => LIKE,
|
|
'value' => "'%$cpe%'"
|
|
)
|
|
));
|
|
$query = true;
|
|
}
|
|
}
|
|
elseif (is_numeric($software_In)) {
|
|
$this->help->select("sagacity.software", null, array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $software_In
|
|
)
|
|
));
|
|
$query = true;
|
|
}
|
|
elseif (is_string($software_In)) {
|
|
$op = $exact_match ? '=' : LIKE;
|
|
$field = 'cpe';
|
|
if (strpos($software_In, "cpe:2.3") !== false) {
|
|
$field = 'cpe23';
|
|
}
|
|
|
|
$exclude_r2 = null;
|
|
if (preg_match("/windows_server_20[\d]+/", $software_In)) {
|
|
if (!preg_match("/r2/", $software_In)) {
|
|
$exclude_r2 = array(
|
|
'field' => $field,
|
|
'op' => NOT_LIKE,
|
|
'value' => "'%r2%'",
|
|
'sql_op' => 'AND'
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->help->select("software", null, [
|
|
[
|
|
'field' => $field,
|
|
'op' => $op,
|
|
'value' => ($op == LIKE ? "'$software_In%'" : $software_In)
|
|
], $exclude_r2], ['order' => 'cpe']
|
|
);
|
|
$query = true;
|
|
}
|
|
elseif (is_a($software_In, 'software')) {
|
|
$os = ($software_In->is_OS() ? "/o" : "/a");
|
|
$man = str_replace(" ", "_", strtolower($software_In->get_Man()));
|
|
$name = str_replace(" ", "_", strtolower($software_In->get_Name()));
|
|
$ver = str_replace(" ", "_", strtolower($software_In->get_Version()));
|
|
$value = "'cpe:{$os}:{$man}:{$name}:{$ver}:%'";
|
|
$field = 'cpe';
|
|
|
|
if (!is_null($software_In->get_CPE23())) {
|
|
$os = substr($os, 1);
|
|
$value = "'cpe:2.3:{$os}:{$man}:{$name}:{$ver}:%'";
|
|
$field = 'cpe23';
|
|
}
|
|
|
|
$this->help->select("software", null, [
|
|
[
|
|
'field' => $field,
|
|
'op' => LIKE,
|
|
'value' => $value
|
|
]
|
|
], ['order' => 'cpe']
|
|
);
|
|
$query = true;
|
|
}
|
|
|
|
if ($query) {
|
|
$rows = $this->help->execute();
|
|
if (isset($rows['cpe'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$sw = new software($row['cpe'], $row['cpe23']);
|
|
$sw->set_ID($row['id']);
|
|
$sw->set_SW_String($row['sw_string']);
|
|
$sw->set_Shortened_SW_String($row['short_sw_string']);
|
|
|
|
$ret[] = $sw;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve a software item by using the CPE or CPE v2.3
|
|
*
|
|
* @param string $cpe_in
|
|
* CPE to search for
|
|
*
|
|
* @return software|NULL
|
|
* Returns software object if found, otherwise null
|
|
*/
|
|
public function get_Software_By_CPE($cpe_in)
|
|
{
|
|
$field = "cpe";
|
|
if (strpos($cpe_in, "cpe:2.3") !== false) {
|
|
$field = "cpe23";
|
|
}
|
|
|
|
$this->help->select("software", null, [
|
|
[
|
|
'field' => $field,
|
|
'op' => '=',
|
|
'value' => $cpe_in
|
|
]
|
|
]);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$sw = new software($row['cpe'], $row['cpe23']);
|
|
$sw->set_ID($row['id']);
|
|
$sw->set_SW_String($row['sw_string']);
|
|
|
|
return $sw;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get the IDs of the CPEs passed in
|
|
*
|
|
* @param array:string $cpes
|
|
*/
|
|
public function get_Software_Ids(array $cpes = [])
|
|
{
|
|
$ret = [];
|
|
$this->help->select("software", ['id'], [
|
|
[
|
|
'field' => 'cpe',
|
|
'op' => IN,
|
|
'value' => $cpes
|
|
]
|
|
]);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = $row['id'];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// @TODO - Finish
|
|
/**
|
|
* Get a list of all software items
|
|
*
|
|
* @param boolean $isOS
|
|
* Boolean to isolate the operating systems
|
|
* @param integer $os_ID
|
|
* ID of a specific software, used to select an element in the drop-down
|
|
*
|
|
* @return string
|
|
* Returns a string with the drop-down option tags
|
|
*/
|
|
public function get_Software_List($isOS, $os_ID = null)
|
|
{
|
|
$ret = '<option value=0> -- Please Select An Option -- </option>';
|
|
$sql = "SELECT `id`,`cpe`,`cpe23`,`sw_string` " .
|
|
"FROM `sagacity`.`software`";
|
|
|
|
if (!is_null($os_ID)) {
|
|
$sql .= " WHERE `id`=" . $os_ID;
|
|
}
|
|
elseif ($isOS) {
|
|
$sql .= " WHERE `cpe23` LIKE '%:o:%'";
|
|
}
|
|
elseif (!$isOS) {
|
|
$sql .= " WHERE `cpe23` LIKE '%:a:%'";
|
|
}
|
|
|
|
// set up query to split cpe string then group by man and name
|
|
//$sql .= " GROUP BY ";
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$sw = new software($row['cpe'], $row['cpe23']);
|
|
|
|
$ret .= "<option value='" . $row['id'] . "'";
|
|
if ($os_ID == $row['id']) {
|
|
$ret .= " selected ";
|
|
}
|
|
$ret .= ">" . $sw->man . " " . $sw->name . " " . $sw->ver . (!empty($sw->sp) ? "(" . $sw->sp . ")" : "") . "</option>";
|
|
}
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get array of software that a target has installed
|
|
*
|
|
* @param integer $tgt_id
|
|
* Target ID to query for
|
|
*
|
|
* @return array:software|NULL
|
|
* Returns array of software that are assigned to associated target, or null if none found
|
|
*/
|
|
public function get_Target_Software($tgt_id)
|
|
{
|
|
$this->help->select("software s", ['s.*'], [
|
|
[
|
|
'field' => 'ts.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN sagacity.target_software ts ON ts.sft_id=s.id"
|
|
]
|
|
]);
|
|
|
|
$sw_arr = $this->help->execute();
|
|
$sft = [];
|
|
|
|
if (is_array($sw_arr) && count($sw_arr)) {
|
|
if (isset($sw_arr['cpe'])) {
|
|
$sw_arr = [0 => $sw_arr];
|
|
}
|
|
|
|
foreach ($sw_arr as $row) {
|
|
$sw = new software($row['cpe'], $row['cpe23']);
|
|
$sw->set_ID($row['id']);
|
|
$sw->set_SW_String($row['sw_string']);
|
|
$sw->set_Shortened_SW_String($row['short_sw_string']);
|
|
|
|
$sft[] = $sw;
|
|
}
|
|
}
|
|
|
|
return $sft;
|
|
}
|
|
|
|
/**
|
|
* Update existing software or add new
|
|
*
|
|
* @param software $sw_in
|
|
* The software to save
|
|
*
|
|
* @return integer
|
|
* Returns the ID of the software that was just inserted or updated if successful, otherwise it returns 0
|
|
*/
|
|
public function save_Software($sw_in)
|
|
{
|
|
if (!is_null($sw_in->get_ID())) {
|
|
$this->help->update("sagacity.software", array(
|
|
'cpe' => $sw_in->get_CPE(),
|
|
'cpe23' => $sw_in->get_CPE23(),
|
|
'sw_string' => $sw_in->get_SW_String(),
|
|
'short_sw_string' => $sw_in->get_Shortened_SW_String()
|
|
), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $sw_in->get_ID()
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return 0;
|
|
}
|
|
|
|
return $sw_in->get_ID();
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.software", array(
|
|
'cpe' => $sw_in->get_CPE(),
|
|
'cpe23' => $sw_in->get_CPE23(),
|
|
'sw_string' => $sw_in->get_SW_String(),
|
|
'short_sw_string' => $sw_in->get_Shortened_SW_String()
|
|
), true);
|
|
|
|
if (!($sw_id = $this->help->execute())) {
|
|
$this->help->debug(E_WARNING);
|
|
return 0;
|
|
}
|
|
|
|
return $sw_id;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve an array of all the software detection regex's
|
|
*
|
|
* @param string $type
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_Regex_Array($type)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if ($type != 'os') {
|
|
$where[] = [
|
|
'field' => 'type',
|
|
'op' => '=',
|
|
'value' => $type
|
|
];
|
|
$where[] = [
|
|
'field' => 'type',
|
|
'op' => '=',
|
|
'value' => 'multiple',
|
|
'sql_op' => 'OR'
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'type',
|
|
'op' => LIKE,
|
|
'value' => "'%os'"
|
|
];
|
|
}
|
|
|
|
$this->help->select("sagacity.sw_man_match", null, $where);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$tmp = [
|
|
'id' => $row['id'],
|
|
'man' => $row['man'],
|
|
'rgx' => $row['rgx'],
|
|
'name' => []
|
|
];
|
|
|
|
$this->help->select("sagacity.sw_name_match", null, [
|
|
[
|
|
'field' => 'man_id',
|
|
'op' => '=',
|
|
'value' => $row['id']
|
|
]
|
|
]);
|
|
$name_rows = $this->help->execute();
|
|
|
|
if (is_array($name_rows) && count($name_rows) && isset($name_rows['id'])) {
|
|
$name_rows = [0 => $name_rows];
|
|
}
|
|
|
|
if (is_array($name_rows) && count($name_rows) && isset($name_rows[0])) {
|
|
foreach ($name_rows as $row2) {
|
|
$tmp['name'][$row2['id']] = array(
|
|
'name' => $row2['name'],
|
|
'man_override' => $row2['man_override'],
|
|
'rgx' => $row2['rgx'],
|
|
'name_match' => $row2['name_match'],
|
|
'ver_match' => $row2['ver_match'],
|
|
'ver' => $row2['ver'],
|
|
'update_match' => $row2['update_match'],
|
|
'is_os' => ($row2['is_os'] ? true : false),
|
|
'multiple' => ($row2['multiple'] ? true : false)
|
|
);
|
|
}
|
|
}
|
|
|
|
$ret[] = $tmp;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ STE CLASS FUNCTIONS
|
|
/**
|
|
* Get ST&E data
|
|
*
|
|
* @param integer $steID
|
|
* ST&E ID to isolate
|
|
*
|
|
* @return array:ste|NULL
|
|
* Returns array of ste objects, or null if none found
|
|
*/
|
|
public function get_STE($steID = null)
|
|
{
|
|
$where = [];
|
|
$ret = null;
|
|
|
|
if ($steID != null) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $steID
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'primary',
|
|
'op' => '=',
|
|
'value' => 0
|
|
];
|
|
}
|
|
|
|
$this->help->select("ste", null, $where, ['order' => 'eval_start DESC']);
|
|
$ste_rows = $this->help->execute();
|
|
|
|
if (isset($ste_rows['id'])) {
|
|
$ste_rows = [0 => $ste_rows];
|
|
}
|
|
|
|
if (is_array($ste_rows) && count($ste_rows) && isset($ste_rows[0])) {
|
|
foreach ($ste_rows as $row) {
|
|
$sys = $this->get_System($row['system_id']);
|
|
if (is_array($sys) && count($sys) && isset($sys[0]) && is_a($sys[0], 'system')) {
|
|
$sys = $sys[0];
|
|
}
|
|
else {
|
|
Sagacity_Error::err_handler("Unable to find system for ST&E ID {$row['id']}", E_ERROR);
|
|
}
|
|
$site = $this->get_Site($row['site_id']);
|
|
if (is_array($site) && count($site) && isset($site[0]) && is_a($site[0], 'site')) {
|
|
$site = $site[0];
|
|
}
|
|
else {
|
|
Sagacity_Error:err_handler("Unable to find site for ST&E ID {$row['id']}", E_ERROR);
|
|
}
|
|
|
|
$ste = new ste($row['id'], $sys, $site, $row['eval_start'], $row['eval_end'], $row['multiple'], $row['primary']);
|
|
$ste->set_Assumptions($row['assumptions']);
|
|
$ste->set_Conclusions($row['conclusion']);
|
|
$ste->set_Constraints($row['constraints']);
|
|
$ste->set_Deviations($row['deviations']);
|
|
$ste->set_Recommendations($row['recommendations']);
|
|
$ste->set_Residual_Risk($row['residual_risk']);
|
|
$ste->set_Scope($row['scope']);
|
|
$ste->set_Status($row['risk_status']);
|
|
$ste->set_AO($row['ao']);
|
|
|
|
$this->help->select("people p", ['st.pos', 'p.*'], [
|
|
[
|
|
'field' => 'st.ste_id',
|
|
'op' => '=',
|
|
'value' => $ste->get_ID()
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN ste_team st ON st.people_id=p.id"
|
|
]
|
|
]);
|
|
$people_rows = $this->help->execute();
|
|
if (is_array($people_rows) && isset($people_rows['id'])) {
|
|
$people_rows = [0 => $people_rows];
|
|
}
|
|
|
|
if (is_array($people_rows) && count($people_rows) && isset($people_rows[0])) {
|
|
foreach ($people_rows as $row2) {
|
|
$people = new people();
|
|
$people->id = $row2['id'];
|
|
$people->org = $row2['org'];
|
|
$people->name = $row2['name'];
|
|
$people->phone = $row2['phone'];
|
|
$people->position = $row2['pos'];
|
|
|
|
$ste->add_STE_Team_Member($people);
|
|
}
|
|
}
|
|
|
|
$ret[] = $ste;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get the subsystems for a particular site
|
|
*
|
|
* @param ste $ste_in
|
|
* ST&E to get subsystems for
|
|
*
|
|
* @return array:ste
|
|
* Returns the subsystem ST&E, or empty array if none found
|
|
*/
|
|
public function get_Subsystems($ste_in)
|
|
{
|
|
$this->help->select("sagacity.ste", null, array(
|
|
array(
|
|
'field' => 'primary',
|
|
'op' => '=',
|
|
'value' => $ste_in->get_ID()
|
|
)
|
|
));
|
|
$ret = [];
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = array(0 => $rows);
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new ste($row['id'], $row['system_id'], $row['site_id'], $row['eval_start'], $row['eval_end'], $row['multiple'], $row['primary']);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* This function returns ST&E list and creates options for a select box
|
|
* Will organize into optgroup tags if subsystems are found
|
|
*
|
|
* @param boolean $select_first [optional]
|
|
* Force the selection of the first element in the drop-down
|
|
*
|
|
* @return string|NULL
|
|
* Returns a string of option tag elements, or null if none found
|
|
*/
|
|
public function get_STE_List($select_first = false)
|
|
{
|
|
$ret = '<option value="0"' . ($select_first ? ' selected' : '') . '> -- Please Select An Option -- </option>';
|
|
$stes = $this->get_STE();
|
|
|
|
if (is_array($stes) && count($stes) && isset($stes['id'])) {
|
|
$stes = [0 => $stes];
|
|
}
|
|
|
|
if (is_array($stes) && count($stes) && isset($stes[0])) {
|
|
foreach ($stes as $ste) {
|
|
$start_str = $ste->get_Eval_Start_Date()->format('d M Y');
|
|
|
|
$subs = $this->get_Subsystems($ste);
|
|
|
|
if (is_array($subs) && count($subs) > 0) {
|
|
$ret .= "<optgroup label='{$ste->get_System()->get_Name()} {$ste->get_Site()->get_Name()}'>" .
|
|
"<option value='{$ste->get_ID()}'";
|
|
|
|
if ((isset($_REQUEST['ste']) && $_REQUEST['ste'] == $ste->get_ID()) || (isset($_COOKIE['ste']) && $_COOKIE['ste'] == $ste->get_ID())) {
|
|
if (!$select_first) {
|
|
$ret .= " selected ";
|
|
}
|
|
}
|
|
|
|
$ret .= ">{$ste->get_System()->get_Name()}, {$ste->get_Site()->get_Name()}, {$start_str} ({$ste->get_ID()})</option>";
|
|
|
|
foreach ($subs as $sub) {
|
|
$ret .= "<option value='{$sub->get_ID()}'";
|
|
|
|
if ((isset($_REQUEST['ste']) && $_REQUEST['ste'] == $sub->get_ID()) || (isset($_COOKIE['ste']) && $_COOKIE['ste'] == $sub->get_ID())) {
|
|
if (!$select_first) {
|
|
$ret .= " selected ";
|
|
}
|
|
}
|
|
|
|
$ret .= ">{$sub->get_System()->get_Name()}, {$sub->get_Site()->get_Name()}, {$start_str} ({$sub->get_ID()})</option>";
|
|
}
|
|
|
|
$ret .= "</optgroup>";
|
|
}
|
|
else {
|
|
$ret .= "<option value='{$ste->get_ID()}'";
|
|
|
|
if ((isset($_REQUEST['ste']) && $_REQUEST['ste'] == $ste->get_ID()) || (isset($_COOKIE['ste']) && $_COOKIE['ste'] == $ste->get_ID())) {
|
|
if (!$select_first) {
|
|
$ret .= " selected ";
|
|
}
|
|
}
|
|
|
|
$ret .= ">{$ste->get_System()->get_Name()}, {$ste->get_Site()->get_Name()}, {$start_str} ({$ste->get_ID()})</option>";
|
|
}
|
|
}
|
|
}
|
|
|
|
// return the string of <option> tags
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* This function returns an array of ste_cat objects that are within the specified ST&E
|
|
*
|
|
* @param integer $intSTE
|
|
* ST&E id to grab the categories for
|
|
* @param mixed $intCatID [optional]
|
|
* ID or name of the specific Category you want to retrieve
|
|
*
|
|
* @return array:ste_cat
|
|
* Returns array of ste_cat objects that match criteria
|
|
*/
|
|
public function get_STE_Cat_List($intSTE, $intCatID = null)
|
|
{
|
|
$ret = [];
|
|
$where = [
|
|
[
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $intSTE
|
|
]
|
|
];
|
|
|
|
if (!is_null($intCatID) && is_numeric($intCatID)) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $intCatID,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
elseif (!is_null($intCatID) && is_string($intCatID)) {
|
|
$where[] = [
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => $intCatID,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
|
|
$this->help->select("ste_cat", null, $where, ['order' => 'name']);
|
|
$cats = $this->help->execute();
|
|
|
|
if (is_array($cats) && count($cats) && isset($cats['id'])) {
|
|
$cats = [0 => $cats];
|
|
}
|
|
|
|
if (is_array($cats) && count($cats) && isset($cats[0])) {
|
|
foreach ($cats as $cat) {
|
|
$tmp = new ste_cat($cat['id'], $cat['ste_id'], $cat['name'], $cat['analysts']);
|
|
|
|
$this->help->select("ste_cat_sources", null, [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $cat['id']
|
|
]
|
|
]);
|
|
$srcs = $this->help->execute();
|
|
if (is_array($srcs) && count($srcs) && isset($srcs['cat_id'])) {
|
|
$srcs = [0 => $srcs];
|
|
}
|
|
if (is_array($srcs) && count($srcs) && isset($srcs[0])) {
|
|
foreach ($srcs as $src) {
|
|
$tmp->add_Source($this->get_Sources($src['src_id']));
|
|
}
|
|
}
|
|
|
|
$this->get_Cat_Count($tmp);
|
|
|
|
$ret[] = $tmp;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Method to retrieve the category count data from the database for a specific category
|
|
*
|
|
* @param ste_cat $cat
|
|
*/
|
|
public function get_Cat_Count(ste_cat &$cat)
|
|
{
|
|
$where = [];
|
|
if($cat->get_ID()) {
|
|
$where[] = [
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $cat->get_ID()
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $cat->get_STE_ID()
|
|
];
|
|
}
|
|
$this->help->select("target", ['cat_1', 'cat_2', 'cat_3', 'closed', 'not_applicable', 'not_reviewed'], $where);
|
|
|
|
$rows = $this->help->execute();
|
|
if(is_array($rows) && count($rows) && isset($rows['cat_1'])) {
|
|
$cat->open += $rows['cat_1'] + $rows['cat_2'] + $rows['cat_3'];
|
|
$cat->na += $rows['not_applicable'];
|
|
$cat->nf += $rows['closed'];
|
|
$cat->nr += $rows['not_reviewed'];
|
|
}
|
|
elseif(is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach($rows as $r) {
|
|
$cat->open += $r['cat_1'] + $r['cat_2'] + $r['cat_3'];
|
|
$cat->na += $r['not_applicable'];
|
|
$cat->nf += $r['closed'];
|
|
$cat->nr += $r['not_reviewed'];
|
|
}
|
|
}
|
|
|
|
$cat->total = $cat->open + $cat->na + $cat->nf + $cat->nr;
|
|
|
|
$this->help->select_count("target", $where);
|
|
$cat->tgt_count = $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to get categories assigned to a ST&E
|
|
*
|
|
* @param integer $intSTE
|
|
* The ST&E ID to grab categories for
|
|
* @param string $strName
|
|
* The specific name the look for
|
|
*
|
|
* @return array:ste_cat |NULL
|
|
* Returns array of ste_cat for all categories in that ST&E, or null if none found
|
|
*/
|
|
public function get_STE_Category_List($intSTE, $strName = null)
|
|
{
|
|
$sql = "SELECT `id`,`ste_id`,`name`,`analysts` " .
|
|
"FROM `sagacity`.`ste_cat` " .
|
|
"WHERE `ste_id`=$intSTE ";
|
|
|
|
if (!is_null($strName)) {
|
|
$sql .= "AND `name`='" . $this->conn->real_escape_string($strName) . "' ";
|
|
}
|
|
|
|
$sql .= "ORDER BY `name`";
|
|
$ret = [];
|
|
|
|
if ($res = $this->conn->query($sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$ret[] = new ste_cat($row['id'], $row['ste_id'], $row['name'], $row['analysts']);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
else {
|
|
Sagacity_Error::sql_handler($sql);
|
|
error_log($this->conn->error);
|
|
}
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Update or insert an ST&E
|
|
*
|
|
* @param ste $ste_In
|
|
* ST&E to save to the database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_STE($ste_In)
|
|
{
|
|
if (!isset($_REQUEST['action'])) {
|
|
$this->help->insert("ste", [
|
|
'system_id' => $ste_In->get_System()->get_ID(),
|
|
'site_id' => $ste_In->get_Site()->get_ID(),
|
|
'eval_start' => $ste_In->get_Eval_Start_Date(),
|
|
'eval_end' => $ste_In->get_Eval_End_Date(),
|
|
'scope' => $ste_In->get_Scope(),
|
|
'assumptions' => $ste_In->get_Assumptions(),
|
|
'constraints' => $ste_In->get_Constratints(),
|
|
'deviations' => $ste_In->get_Deviations(),
|
|
'recommendations' => $ste_In->get_Recommendations(),
|
|
'residual_risk' => $ste_In->get_Residual_Risk(),
|
|
'conclusion' => $ste_In->get_Conclusions(),
|
|
'ao' => $ste_In->get_AO()
|
|
]);
|
|
|
|
$id = $this->help->execute();
|
|
|
|
if (!$id) {
|
|
return false;
|
|
}
|
|
|
|
return $id;
|
|
}
|
|
elseif ($_REQUEST['action'] == 'save-ste' && !$ste_In->get_ID()) {
|
|
$multiple = isset($_REQUEST['add_subsystems']) ? '1' : '0';
|
|
|
|
$this->help->insert("ste", [
|
|
'system_id' => $ste_In->get_System()->get_ID(),
|
|
'site_id' => $ste_In->get_Site()->get_ID(),
|
|
'eval_start' => $ste_In->get_Eval_Start_Date(),
|
|
'eval_end' => $ste_In->get_Eval_End_Date(),
|
|
'scope' => $ste_In->get_Scope(),
|
|
'assumptions' => $ste_In->get_Assumptions(),
|
|
'constraints' => $ste_In->get_Constraints(),
|
|
'deviations' => $ste_In->get_Deviations(),
|
|
'recommendations' => $ste_In->get_Recommendations(),
|
|
'residual_risk' => $ste_In->get_Residual_Risk(),
|
|
'conclusion' => $ste_In->get_Conclusions(),
|
|
'ao' => $ste_In->get_AO(),
|
|
'multiple' => $multiple,
|
|
'primary' => 0
|
|
]);
|
|
|
|
$ste_id = $this->help->execute();
|
|
|
|
if ($ste_id) {
|
|
$this->conn->real_query("INSERT INTO `ste_cat` (`ste_id`,`name`) " .
|
|
"SELECT $ste_id,`name` FROM `category`");
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
if (isset($_REQUEST['add_subsystems'])) {
|
|
$ins = [];
|
|
|
|
foreach ($_REQUEST['subsystems'] as $subs) {
|
|
$ins[] = [
|
|
$subs,
|
|
$ste_In->get_Site()->get_ID(),
|
|
$ste_In->get_Eval_Start_Date(),
|
|
$ste_In->get_Eval_End_Date(),
|
|
0,
|
|
$ste_id
|
|
];
|
|
|
|
$this->help->extended_insert("ste", ['system_id', 'site_id', 'eval_start', 'eval_end', 'multiple', 'primary'], $ins);
|
|
$sec_ste_id = $this->help->execute();
|
|
|
|
if ($sec_ste_id) {
|
|
$this->conn->real_query(
|
|
"INSERT INTO `ste_cat` (`ste_id`,`name`) SELECT $sec_ste_id, `name` FROM `category`");
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
elseif ($_REQUEST['action'] == 'save-ste' && $ste_In->get_ID()) {
|
|
$this->help->update("ste", [
|
|
'system_id' => $ste_In->get_System()->get_ID(),
|
|
'site_id' => $ste_In->get_Site()->get_ID(),
|
|
'eval_start' => $ste_In->get_Eval_Start_Date(),
|
|
'eval_end' => $ste_In->get_Eval_End_Date(),
|
|
'multiple' => (isset($_REQUEST['add_subsystems']) ? '1' : '0'),
|
|
'scope' => $ste_In->get_Scope(),
|
|
'assumptions' => $ste_In->get_Assumptions(),
|
|
'constraints' => $ste_In->get_Constraints(),
|
|
'deviations' => $ste_In->get_Deviations(),
|
|
'recommendations' => $ste_In->get_Recommendations(),
|
|
'residual_risk' => $ste_In->get_Residual_Risk(),
|
|
'conclusion' => $ste_In->get_Conclusions(),
|
|
'ao' => $ste_In->get_AO(),
|
|
'primary' => 0
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $ste_In->get_ID()
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
return false;
|
|
}
|
|
|
|
$this->help->update("ste", ['primary' => '0'], [
|
|
[
|
|
'field' => 'primary',
|
|
'op' => '=',
|
|
'value' => $ste_In->get_ID()
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
if (isset($_REQUEST['add_subsystems'])) {
|
|
foreach ($_REQUEST['subsystems'] as $subs) {
|
|
$ids = explode('_', $subs);
|
|
$this->help->update("ste", [
|
|
'system_id' => $ids[0],
|
|
'site_id' => $ste_In->get_Site()->get_ID(),
|
|
'eval_start' => $ste_In->get_Eval_Start_Date(),
|
|
'eval_end' => $ste_In->get_Eval_End_Date(),
|
|
'multiple' => '0',
|
|
'primary' => $ste_In->get_ID()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $ids[1]
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ STIG CLASS FUNCTIONS
|
|
/**
|
|
* Get STIG data
|
|
*
|
|
* @param string $str_Stig_ID [optional]
|
|
* STIG ID to get from database (default null)
|
|
* @param boolean $like [optional]
|
|
* To perform a like comparison (default false)
|
|
*
|
|
* @return array:stig |NULL
|
|
* Returns array of stigs, or null if none found
|
|
*/
|
|
public function get_Stig($str_Stig_ID = null, $like = false)
|
|
{
|
|
$where = [];
|
|
$ret = [];
|
|
|
|
if (!is_null($str_Stig_ID)) {
|
|
if (preg_match("/^\d\.\d{1,2}$/", $str_Stig_ID)) {
|
|
if (strlen($str_Stig_ID) == 3) {
|
|
$str_Stig_ID .= "00";
|
|
}
|
|
elseif (strlen($str_Stig_ID) == 4) {
|
|
$str_Stig_ID .= "0";
|
|
}
|
|
}
|
|
|
|
if ($like) {
|
|
$where[] = [
|
|
'field' => 'stig_id',
|
|
'op' => LIKE,
|
|
'value' => "'%$str_Stig_ID%'"
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'stig_id',
|
|
'op' => '=',
|
|
'value' => $str_Stig_ID
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("stigs", null, $where);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['stig_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$stig = new stig($row['pdi_id'], $row['stig_id'], $row['description']);
|
|
$stig->set_Function($row['tweak_data']);
|
|
$ret[] = $stig;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving the STIG by the PDI
|
|
*
|
|
* @param integer $pdi_id
|
|
* PDI ID of the stig we want to isolate
|
|
*
|
|
* @return stig|NULL
|
|
* Returns stigs, or null if none found
|
|
*/
|
|
public function get_STIG_By_PDI($pdi_id)
|
|
{
|
|
$stig = null;
|
|
|
|
$this->help->select("stigs", null, [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['stig_id'])) {
|
|
$stig = new stig($rows['pdi_id'], $rows['stig_id'], $rows['description']);
|
|
}
|
|
|
|
return $stig;
|
|
}
|
|
|
|
/**
|
|
* Function to return possible stig functions
|
|
*
|
|
* @param stig $stig
|
|
* @param target $tgt
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_STIG_Function($stig, $tgt)
|
|
{
|
|
$ret = null;
|
|
$chk_arr = [];
|
|
foreach ($tgt->checklists as $chk) {
|
|
$chk_arr[] = $chk->get_ID();
|
|
}
|
|
|
|
$this->help->select("pdi_checklist_lookup", ['tweak_data'], [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $stig->get_PDI_ID()
|
|
],
|
|
[
|
|
'field' => 'checklist_id',
|
|
'op' => IN,
|
|
'op' => $chk_arr,
|
|
'sql_op' => 'AND'
|
|
],
|
|
[
|
|
'field' => 'tweak_data',
|
|
'op' => IS_NOT,
|
|
'value' => null,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['tweak_data'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret = $row['tweak_data'];
|
|
}
|
|
}
|
|
else {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to add STIG to database
|
|
*
|
|
* @param stig $new_Stig
|
|
* STIG to add to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function add_Stig($new_Stig)
|
|
{
|
|
$this->help->insert("sagacity.stigs", array(
|
|
'pdi_id' => $new_Stig->get_PDI_ID(),
|
|
'stig_id' => $new_Stig->get_ID(),
|
|
'description' => $new_Stig->get_Description()
|
|
), true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SV_RULE CLASS FUNCTIONS
|
|
/**
|
|
* Function to get SV Rule data
|
|
*
|
|
* @param integer $pdi_id [optional]
|
|
* PDI ID (defaulted null)
|
|
* @param string $sv_rule_id [optional]
|
|
* SV Rule to get from database (defaulted null)
|
|
*
|
|
* @return array:sv_rule|NULL
|
|
* Returns SV Rule, or null if none found
|
|
*/
|
|
public function get_SV_Rule($pdi_id = null, $sv_rule_id = null)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if (!is_null($pdi_id) && !is_null($sv_rule_id)) {
|
|
$where = [
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
],
|
|
[
|
|
'field' => 'sv_rule',
|
|
'op' => '=',
|
|
'value' => $sv_rule_id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
];
|
|
}
|
|
elseif (!is_null($sv_rule_id)) {
|
|
$where[] = [
|
|
'field' => 'sv_rule',
|
|
'op' => '=',
|
|
'value' => $sv_rule_id
|
|
];
|
|
}
|
|
elseif (!is_null($pdi_id)) {
|
|
$where[] = [
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pdi_id
|
|
];
|
|
}
|
|
|
|
$this->help->select("sv_rule", null, $where);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = new sv_rule($row['pdi_id'], $row['sv_rule']);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Update an SV Rule
|
|
*
|
|
* @param sv_rule $sv_Rule
|
|
* Array of SV Rules to save to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_SV_Rule($sv_Rule = null)
|
|
{
|
|
$params = [];
|
|
|
|
if (is_array($sv_Rule) && count($sv_Rule) && isset($sv_Rule[0]) && is_a($sv_Rule[0], 'sv_rule')) {
|
|
foreach ($sv_Rule as $rule) {
|
|
$params[] = [
|
|
$rule->get_PDI_ID(),
|
|
$rule->get_SV_Rule()
|
|
];
|
|
}
|
|
}
|
|
elseif (is_a($sv_Rule, 'sv_rule')) {
|
|
$params[] = [
|
|
$sv_Rule->get_PDI_ID(),
|
|
$sv_Rule->get_SV_Rule()
|
|
];
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
$this->help->extended_replace("sagacity.sv_rule", array('pdi_id', 'sv_rule'), $params);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
//{{{ SYSTEM CLASS FUNCTIONS
|
|
/**
|
|
* Get system data
|
|
*
|
|
* @param integer $systemID [optional]
|
|
* System ID to get from database (default null)
|
|
*
|
|
* @return array:system|NULL
|
|
* Returns array of systems, or null if none found
|
|
*/
|
|
public function get_System($systemID = null)
|
|
{
|
|
$ret = [];
|
|
$where = [];
|
|
|
|
if (!is_null($systemID)) {
|
|
if (is_numeric($systemID)) {
|
|
$where[] = [
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $systemID
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => $systemID
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("sagacity.system", null, $where, ['order' => 'name']);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$sys = new system($row['id'], $row['name'], $row['mac'], $row['classification']);
|
|
|
|
$sys->set_Description($row['description']);
|
|
$sys->set_Mitigations($row['mitigations']);
|
|
$sys->set_Executive_Summary($row['executive_summary']);
|
|
$sys->set_Abbreviation($row['abbr']);
|
|
switch ($row['acred_type']) {
|
|
case 'diacap':
|
|
$sys->set_Accreditation_Type(accrediation_types::DIACAP);
|
|
break;
|
|
case 'rmf':
|
|
$sys->set_Accreditation_Type(accrediation_types::RMF);
|
|
break;
|
|
case 'pci':
|
|
$sys->set_Accreditation_Type(accrediation_types::PCI);
|
|
break;
|
|
case 'nispom':
|
|
$sys->set_Accreditation_Type(accrediation_types::NISPOM);
|
|
break;
|
|
case 'sox':
|
|
$sys->set_Accreditation_Type(accrediation_types::SOX);
|
|
break;
|
|
case 'hipaa':
|
|
$sys->set_Accreditation_Type(accrediation_types::HIPAA);
|
|
break;
|
|
case 'cobit':
|
|
$sys->set_Accreditation_Type(accrediation_types::COBIT);
|
|
}
|
|
|
|
$ret[] = $sys;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get the system for a ST&E
|
|
*
|
|
* @param integer $intSTE
|
|
* ST&E ID to query for
|
|
*
|
|
* @return system|NULL
|
|
* Returns array of systems, or null if none found
|
|
*/
|
|
public function get_System_By_STE_ID($intSTE)
|
|
{
|
|
$ret = null;
|
|
$this->help->select("system s", ['s.*'], [
|
|
[
|
|
'field' => 'ste.id',
|
|
'op' => '=',
|
|
'value' => $intSTE
|
|
]
|
|
], [
|
|
'table_joins' => ["LEFT JOIN ste ON ste.system_id = s.id"]
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
if (is_array($row) && count($row) && isset($row['id'])) {
|
|
$ret = new system($row['id'], $row['name'], $row['mac'], $row['classification']);
|
|
|
|
$ret->set_Description($row['description']);
|
|
$ret->set_Mitigations($row['mitigations']);
|
|
$ret->set_Executive_Summary($row['executive_summary']);
|
|
$ret->set_Abbreviation($row['abbr']);
|
|
switch ($row['acred_type']) {
|
|
case 'diacap':
|
|
$ret->set_Accreditation_Type(accrediation_types::DIACAP);
|
|
break;
|
|
case 'rmf':
|
|
$ret->set_Accreditation_Type(accrediation_types::RMF);
|
|
break;
|
|
case 'pci':
|
|
$ret->set_Accreditation_Type(accrediation_types::PCI);
|
|
break;
|
|
case 'nispom':
|
|
$ret->set_Accreditation_Type(accrediation_types::NISPOM);
|
|
break;
|
|
case 'sox':
|
|
$ret->set_Accreditation_Type(accrediation_types::SOX);
|
|
break;
|
|
case 'hipaa':
|
|
$ret->set_Accreditation_Type(accrediation_types::HIPAA);
|
|
break;
|
|
case 'cobit':
|
|
$ret->set_Accreditation_Type(accrediation_types::COBIT);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Update or insert a system
|
|
*
|
|
* @param system $system_In
|
|
* System to save to database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_System($system_In)
|
|
{
|
|
$acred_type = '';
|
|
switch ($system_In->get_Accreditation_Type()) {
|
|
case accrediation_types::DIACAP:
|
|
$acred_type = 'diacap';
|
|
break;
|
|
case accrediation_types::RMF:
|
|
$acred_type = 'rmf';
|
|
break;
|
|
case accrediation_types::PCI:
|
|
$acred_type = 'pci';
|
|
break;
|
|
case accrediation_types::NISPOM:
|
|
$acred_type = 'nispom';
|
|
break;
|
|
case accrediation_types::SOX:
|
|
$acred_type = 'sox';
|
|
break;
|
|
case accrediation_types::HIPAA:
|
|
$acred_type = 'hipaa';
|
|
break;
|
|
case accrediation_types::COBIT:
|
|
$acred_type = 'cobit';
|
|
}
|
|
|
|
if ($system_In->get_ID()) {
|
|
$this->help->update("sagacity.system", array(
|
|
'name' => $system_In->get_Name(),
|
|
'mac' => $system_In->get_MAC(),
|
|
'classification' => $system_In->get_Classification(),
|
|
'description' => $system_In->get_Description(),
|
|
'mitigations' => $system_In->get_Mitigations(),
|
|
'abbr' => $system_In->get_Abbreviation(),
|
|
'executive_summary' => $system_In->get_Executive_Summary(),
|
|
'acred_type' => $acred_type
|
|
), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $system_In->get_ID()
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return $system_In->get_ID();
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.system", array(
|
|
'name' => $system_In->get_Name(),
|
|
'mac' => $system_In->get_MAC(),
|
|
'classification' => $system_In->get_Classification(),
|
|
'description' => $system_In->get_Description(),
|
|
'mitigations' => $system_In->get_Mitigations(),
|
|
'abbr' => $system_In->get_Abbreviation(),
|
|
'executive_summary' => $system_In->get_Executive_Summary(),
|
|
'acred_type' => $acred_type
|
|
), true);
|
|
|
|
if (!($sys_id = $this->help->execute())) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return $sys_id;
|
|
}
|
|
}
|
|
|
|
// }}}
|
|
// {{{ TARGET CLASS FUNCTIONS
|
|
/**
|
|
* Check for the presents of a target
|
|
*
|
|
* @param integer $ste_id
|
|
* STE ID
|
|
* @param string $tgt_in
|
|
* Target to look for (can be IPv4, IPv6, ID, name, hostname, or FQDN)
|
|
*
|
|
* @return integer
|
|
* Returns the ID of the target if found, otherwise 0
|
|
*/
|
|
public function check_Target($ste_id, $tgt_in)
|
|
{
|
|
if (preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $tgt_in)) {
|
|
$this->help->select("target t", ['t.id'], [
|
|
[
|
|
'field' => 'i.ipv4',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'open-paren' => true
|
|
],
|
|
[
|
|
'field' => 't.name',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'close-paren' => true,
|
|
'sql_op' => 'OR'
|
|
],
|
|
[
|
|
'field' => 't.ste_id',
|
|
'op' => '=',
|
|
'value' => $ste_id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN interfaces i ON i.tgt_id=t.id"
|
|
],
|
|
'group' => 't.id',
|
|
'limit' => 1
|
|
]);
|
|
}
|
|
elseif (preg_match("/\:/", $tgt_in)) {
|
|
$this->help->select("target t", ['t.id'], [
|
|
[
|
|
'field' => 'i.ipv6',
|
|
'op' => '=',
|
|
'value' => $tgt_in
|
|
],
|
|
[
|
|
'field' => 't.ste_id',
|
|
'op' => '=',
|
|
'value' => $ste_id,
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN interfaces i ON i.tgt_id=t.id"
|
|
]
|
|
]);
|
|
}
|
|
else {
|
|
$this->help->select("target t", ['t.id'], [
|
|
[
|
|
'field' => 't.ste_id',
|
|
'op' => '=',
|
|
'value' => $ste_id
|
|
],
|
|
[
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'sql_op' => 'AND',
|
|
'open-paren' => true
|
|
],
|
|
[
|
|
'field' => 't.name',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'sql_op' => 'OR',
|
|
'case_insensitive' => true
|
|
],
|
|
[
|
|
'field' => 'i.hostname',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'sql_op' => 'OR',
|
|
'case_insensitive' => true
|
|
],
|
|
[
|
|
'field' => 'i.fqdn',
|
|
'op' => '=',
|
|
'value' => $tgt_in,
|
|
'sql_op' => 'OR',
|
|
'case_insensitive' => true,
|
|
'close-paren' => true
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN interfaces i ON i.tgt_id=t.id"
|
|
],
|
|
'group' => 't.id'
|
|
]);
|
|
}
|
|
|
|
$tgt = $this->help->execute();
|
|
if (is_array($tgt) && count($tgt) && isset($tgt['id'])) {
|
|
return $tgt['id'];
|
|
}
|
|
elseif (is_array($tgt) && count($tgt) > 1) {
|
|
Sagacity_Error::err_handler("Return more than one target " . print_r($tgt, true), E_WARNING);
|
|
}
|
|
/*
|
|
if () {
|
|
print_r($tgt);
|
|
if (isset($tgt['id'])) {
|
|
return $tgt['id'];
|
|
}
|
|
}
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get a target by name or ID or all targets in an ST&E
|
|
*
|
|
* @param integer $int_STE_ID
|
|
* ST&E ID to get targets from
|
|
* @param integer|string $TGT [optional]
|
|
* Target to specific grab (can be integer ID or name)
|
|
*
|
|
* @return array:target
|
|
* Returns array of targets
|
|
*/
|
|
public function get_Target_Details($int_STE_ID, $TGT = null)
|
|
{
|
|
$ret = [];
|
|
$where = [[
|
|
'field' => 't.ste_id',
|
|
'op' => '=',
|
|
'value' => $int_STE_ID
|
|
]];
|
|
|
|
if (!is_null($TGT)) {
|
|
if (is_numeric($TGT)) {
|
|
$where[] = [
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $TGT,
|
|
'sql_op' => 'AND'
|
|
];
|
|
}
|
|
else {
|
|
$where[] = [
|
|
'field' => 't.name',
|
|
'op' => '=',
|
|
'value' => $TGT,
|
|
'sql_op' => 'AND',
|
|
'case_insensitive' => true
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("target t", null, $where);
|
|
$tgts = $this->help->execute();
|
|
|
|
if (isset($tgts['name'])) {
|
|
$tgts = [0 => $tgts];
|
|
}
|
|
|
|
if (is_array($tgts) && count($tgts)) {
|
|
foreach ($tgts as $row) {
|
|
$tgt = new target($row['name']);
|
|
$tgt->set_ID($row['id']);
|
|
$tgt->set_STE_ID($row['ste_id']);
|
|
$tgt->set_Cat_ID($row['cat_id']);
|
|
$tgt->set_OS_ID($row['os_id']);
|
|
$tgt->set_Auto_Status_ID($row['auto_status_id']);
|
|
$tgt->set_Man_Status_ID($row['man_status_id']);
|
|
$tgt->set_Data_Status_ID($row['data_status_id']);
|
|
$tgt->set_FP_Cat1_Status_ID($row['fp_cat1_status_id']);
|
|
$tgt->set_Location($row['location']);
|
|
$tgt->set_Source($row['source']);
|
|
$tgt->set_Notes($row['notes']);
|
|
$tgt->set_Missing_Patches($row['missing_patches']);
|
|
$tgt->set_OS_String($row['os_string']);
|
|
$tgt->set_PP_Flag($row['pp_flag']);
|
|
$tgt->set_PP_Suspended($row['pp_off']);
|
|
$tgt->setCat1Count($row['cat_1']);
|
|
$tgt->setCat2Count($row['cat_2']);
|
|
$tgt->setCat3Count($row['cat_3']);
|
|
$tgt->setNotAFindingCount($row['closed']);
|
|
$tgt->setNotApplicableCount($row['not_applicable']);
|
|
$tgt->setNotReviewedCount($row['not_reviewed']);
|
|
$tgt->classification = $row['class'];
|
|
$tgt->software = $this->get_Target_Software($row['id']);
|
|
$tgt->checklists = $this->get_Target_Checklists($row['id']);
|
|
|
|
$interfaces = $this->get_Interfaces($row['id']);
|
|
if (is_array($interfaces)) {
|
|
foreach ($interfaces as $int) {
|
|
if ($int->get_IPv4()) {
|
|
$tgt->interfaces["{$int->get_IPv4()}"] = $int;
|
|
}
|
|
else {
|
|
$tgt->interfaces["{$int->get_IPv6()}"] = $int;
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->get_Target_MetaData($tgt);
|
|
|
|
$ret[] = $tgt;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get the target's meta data
|
|
*
|
|
* @param target $tgt
|
|
* Target to retrieve the meta data for
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function get_Target_MetaData(&$tgt)
|
|
{
|
|
if (!is_a($tgt, 'target')) {
|
|
return;
|
|
}
|
|
|
|
$this->help->select("target t", ['t.id', 'nm.*', 'sm.*', 'um.*'], [
|
|
[
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN target_net_meta nm ON nm.tgt_id=t.id",
|
|
"LEFT JOIN target_sys_meta sm ON sm.tgt_id=t.id",
|
|
"LEFT JOIN target_user_meta um ON um.tgt_id=t.id"
|
|
],
|
|
'group' => 't.id'
|
|
]);
|
|
|
|
$row = $this->help->execute();
|
|
|
|
if (is_array($row) && count($row) && isset($row[0])) {
|
|
$row = $row[0];
|
|
}
|
|
|
|
if (is_array($row) && count($row) && isset($row['netstat_connections'])) {
|
|
$tgt->set_Netstat_Connections($row['netstat_connections']);
|
|
$tgt->set_Shares($row['shares']);
|
|
$tgt->set_Routes($row['routes']);
|
|
$tgt->set_Firewall_Config($row['firewall_config']);
|
|
$tgt->set_Autorun($row['autorun']);
|
|
$tgt->set_Mounted($row['mounted']);
|
|
$tgt->set_Process_List($row['process_list']);
|
|
$tgt->set_Services($row['services']);
|
|
$tgt->set_Last_Boot($row['last_boot']);
|
|
$tgt->set_Remote_Registry($row['remote_registry']);
|
|
$tgt->set_Copyright($row['copyrighted']);
|
|
$tgt->set_VM(($row['is_vm'] ? true : false));
|
|
$tgt->set_System($row['system']);
|
|
$tgt->set_BIOS($row['bios']);
|
|
$tgt->set_WMI_PID($row['wmi_listening_pid']);
|
|
$tgt->set_Login($row['login']);
|
|
$tgt->set_User_List($row['user_list']);
|
|
$tgt->set_Last_Login($row['last_login']);
|
|
$tgt->set_Disabled_Accts($row['disabled_accts']);
|
|
$tgt->set_Stag_Pwds($row['stag_pwds']);
|
|
$tgt->set_Never_Logged_In($row['never_logged_in']);
|
|
$tgt->set_Pwds_Never_Expire($row['pwd_never_expires']);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get all targets in a particular group/category
|
|
*
|
|
* @param integer $intCat
|
|
* Category to get targets from
|
|
*
|
|
* @return array:target|NULL
|
|
* Returns array of targets for selected category
|
|
*/
|
|
public function get_Target_By_Category($intCat)
|
|
{
|
|
$ret = [];
|
|
$cat = $this->get_Category($intCat);
|
|
if (is_array($cat) && count($cat)) {
|
|
$cat = $cat[0];
|
|
}
|
|
$this->help->select("target", ['id'], [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => (is_null($intCat) ? IS : '='),
|
|
'value' => $intCat
|
|
]
|
|
], [
|
|
'order' => 'name'
|
|
]);
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = $this->get_Target_Details($cat->get_STE_ID(), $row['id'])[0];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to return all targets that are not assigned to a category
|
|
*
|
|
* @param int $intSTE
|
|
*
|
|
* @return array:target |NULL
|
|
*/
|
|
public function get_Unassigned_Targets($intSTE)
|
|
{
|
|
$this->help->select("target", ['id'], [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => IS,
|
|
'value' => null
|
|
],
|
|
[
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $intSTE,
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'order' => 'name'
|
|
]);
|
|
$ret = [];
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[] = $this->get_Target_Details($intSTE, $row['id'])[0];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get the count of all targets in an ST&E
|
|
*
|
|
* @param integer $intCat
|
|
* Category to look in
|
|
*
|
|
* @return integer
|
|
* Returns count of targets in specific category
|
|
*/
|
|
public function get_STE_Cat_TGT_Count($intCat)
|
|
{
|
|
$this->help->select_count("target", [
|
|
[
|
|
'field' => 'cat_id',
|
|
'op' => '=',
|
|
'value' => $intCat
|
|
]
|
|
]);
|
|
|
|
$count = $this->help->execute();
|
|
|
|
if (is_numeric($count)) {
|
|
return $count;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve list of targets from 2 ST&E's
|
|
*
|
|
* @param ste $left_ste
|
|
* The left or primary ST&E to compare
|
|
* @param ste $right_ste
|
|
* The right or secondary ST&E to compare
|
|
*
|
|
* @return array:target
|
|
* Returns an array of targets that are similar for both or null if it exists in one, but not the other
|
|
*/
|
|
public function get_Target_Comparison($left_ste, $right_ste)
|
|
{
|
|
$left_missing_sql = "SELECT `id` FROM `sagacity`.`target` WHERE `ste_id`=" . $left_ste->get_ID() . " ORDER BY `name`";
|
|
$right_missing_sql = "SELECT `id` FROM `sagacity`.`target` WHERE `ste_id`=" . $right_ste->get_ID() . " ORDER BY `name`";
|
|
$ret = array('left' => [], 'right' => []);
|
|
|
|
if ($res = $this->conn->query($left_missing_sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$tgt = $this->get_Target_Details($left_ste->get_ID(), $row['id'])[0];
|
|
$ret['left'][$tgt->get_Name()] = $tgt;
|
|
}
|
|
}
|
|
|
|
if ($res = $this->conn->query($right_missing_sql)) {
|
|
while ($row = $res->fetch_assoc()) {
|
|
$tgt = $this->get_Target_Details($right_ste->get_ID(), $row['id'])[0];
|
|
$ret['right'][$tgt->get_Name()] = $tgt;
|
|
|
|
if (!isset($ret['left'][$tgt->get_Name()])) {
|
|
$ret['left'][$tgt->get_Name()] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Function to perform post processing on nessus scan data
|
|
*
|
|
* @param integer $id [optional]
|
|
* Specific target ID to process (default null), if null will look for all targets that need the post-processing run
|
|
* @param integer $os_id [optional]
|
|
* OS ID of the target (only used when passing in a specific target)
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function post_Processing($id = null)
|
|
{
|
|
if (is_null($id)) {
|
|
$this->help->select("target", ['id', 'os_id'], [
|
|
[
|
|
'field' => 'pp_flag',
|
|
'op' => '=',
|
|
'value' => 1
|
|
],
|
|
[
|
|
'field' => 'pp_off',
|
|
'op' => '=',
|
|
'value' => 0,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
$tgts = $this->help->execute();
|
|
|
|
if(is_array($tgts) && count($tgts) && isset($tgts['id'])) {
|
|
$tgts = [0 => $tgts];
|
|
}
|
|
|
|
if (is_array($tgts) && count($tgts) && isset($tgts[0])) {
|
|
foreach ($tgts as $tgt) {
|
|
$this->help->query_type = db_helper::INSERT;
|
|
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
|
|
"SELECT {$tgt['id']},c.`id` FROM (" .
|
|
"SELECT chk.*,s.`id` AS 'real_sw' " .
|
|
"FROM `checklist` chk " .
|
|
"JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk.`id` " .
|
|
"JOIN `software` s ON csl.`sw_id`=s.`id` " .
|
|
"WHERE " .
|
|
"chk.`type` = 'manual' AND " .
|
|
"s.`cpe` NOT LIKE '%generic:generic%' AND " .
|
|
"s.`cpe` NOT LIKE '%apache:http\_server%' AND " .
|
|
"s.`cpe` NOT LIKE '%oracle:jre%' " .
|
|
"ORDER BY chk.`ver` DESC,CONVERT(chk.`release`, DECIMAL(4,2)) DESC" .
|
|
") c " .
|
|
"JOIN `target_software` ts ON ts.`sft_id`=c.`real_sw` " .
|
|
"WHERE ts.`tgt_id`={$tgt['id']} " .
|
|
"GROUP BY c.`name`,c.`type`";
|
|
$this->help->execute();
|
|
|
|
$os = $this->get_Software($tgt['os_id']);
|
|
if (is_array($os) && count($os) && isset($os[0]) && is_a($os[0], 'software')) {
|
|
$os = $os[0];
|
|
}
|
|
|
|
// to apply JRE STIGs to correct software
|
|
$sw = "Unix";
|
|
if (strtolower($os->man) == 'microsoft' && (strtolower($os->name) == 'windows xp' || (strtolower($os->name) == 'windows-nt' && strtolower($os->ver) == 'xp'))) {
|
|
$sw = "WinXP";
|
|
}
|
|
elseif (strtolower($os->man) == 'microsoft' && strtolower($os->name) == 'windows 7') {
|
|
$sw = "Win7";
|
|
}
|
|
$this->help->query_type = db_helper::INSERT;
|
|
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
|
|
"SELECT '{$tgt['id']}',c.`id` FROM (" .
|
|
"SELECT chk.*,s.`id` as 'real_sw' " .
|
|
"FROM `checklist` chk " .
|
|
"JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk.`id` " .
|
|
"JOIN `software` s ON s.`id`=csl.`sw_id` " .
|
|
"WHERE s.`cpe` LIKE '%oracle:jre%' AND " .
|
|
"chk.`checklist_id` LIKE 'JRE%{$sw}%' " .
|
|
"ORDER BY chk.`ver` DESC,CONVERT(chk.`release`, DECIMAL(4,2)) DESC" .
|
|
") c " .
|
|
"JOIN `target_software` ts ON ts.`sft_id`=c.`real_sw` " .
|
|
"WHERE ts.`tgt_id`={$tgt['id']} " .
|
|
"GROUP BY c.`name`,c.`type`"
|
|
;
|
|
$this->help->execute();
|
|
|
|
// specific checklist assignment for Apache
|
|
$sw = "Unix";
|
|
if (strtolower($os->man) == 'microsoft') {
|
|
$sw = "Windows";
|
|
}
|
|
$this->help->query_type = db_helper::INSERT;
|
|
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
|
|
"SELECT '{$tgt['id']}',c.`id` FROM (" .
|
|
"SELECT chk.*,s.`id` AS 'real_sw' " .
|
|
"FROM `checklist` chk " .
|
|
"JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk.`id` " .
|
|
"JOIN `software` s ON s.`id`=csl.`sw_id` " .
|
|
"WHERE s.`cpe` LIKE '%apache:http\_server%' AND " .
|
|
"chk.`checklist_id` LIKE 'Apache%{$sw}%' " .
|
|
"ORDER BY chk.`ver` DESC,CONVERT(chk.`release`,DECIMAL(4,2)) DESC" .
|
|
") c " .
|
|
"JOIN `target_software` ts ON ts.`sft_id`=c.`real_sw` " .
|
|
"WHERE ts.`tgt_id`={$tgt['id']} " .
|
|
"GROUP BY c.`name`,c.`type`"
|
|
;
|
|
$this->help->execute();
|
|
|
|
$this->help->query_type = db_helper::INSERT;
|
|
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
|
|
"SELECT '{$tgt['id']}',c.`id` FROM (" .
|
|
"SELECT chk.*,csl.`sw_id` AS 'real_sw' FROM `checklist` chk " .
|
|
"JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk.`id` " .
|
|
"JOIN `software` s ON csl.`sw_id`=s.`id` " .
|
|
"WHERE s.`cpe` NOT LIKE '%generic:generic%' " .
|
|
"ORDER BY chk.`ver` DESC,CONVERT(chk.`release`, DECIMAL(4,2)) DESC" .
|
|
") c " .
|
|
"LEFT JOIN `target` t ON c.`real_sw`=t.`os_id` " .
|
|
"WHERE t.`id`={$tgt['id']} " .
|
|
"GROUP BY c.`name`,c.`type`";
|
|
$this->help->execute();
|
|
|
|
$this->help->update("target", ['pp_flag' => 0], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $tgt['id']
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$this->help->query_type = db_helper::INSERT;
|
|
$this->help->sql = "INSERT IGNORE INTO `findings` (`tgt_id`,`pdi_id`,`findings_status_id`) " .
|
|
"SELECT {$tgt['id']},pcl.pdi_id,'1' " .
|
|
"FROM target_checklist tc " .
|
|
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " .
|
|
"WHERE tc.tgt_id = {$tgt['id']}";
|
|
$this->help->execute();
|
|
|
|
$this->update_Target_Counts($tgt['id']);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->help->select("checklist c", ['c.*', "s.id AS 'sw_id'"], [
|
|
[
|
|
'field' => 's.cpe',
|
|
'op' => NOT_LIKE,
|
|
'value' => "'%generic:generic%'"
|
|
],
|
|
[
|
|
'field' => 's.cpe',
|
|
'op' => NOT_LIKE,
|
|
'value' => "'%apache:http\_server%'",
|
|
'sql_op' => 'AND'
|
|
],
|
|
[
|
|
'field' => 's.cpe',
|
|
'op' => NOT_LIKE,
|
|
'value' => "'%oracle:jre%'",
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN checklist_software_lookup csl ON csl.chk_id=c.id",
|
|
"JOIN software s ON csl.sw_id=s.id"
|
|
],
|
|
'order' => 'c.ver DESC,CONVERT(c.`release`, DECIMAL(4,2)) DESC'
|
|
]);
|
|
$this->help->create_table("c", true);
|
|
$this->help->execute();
|
|
|
|
$this->help->select("c", ["c.id"], [
|
|
[
|
|
'field' => 'ts.tgt_id',
|
|
'op' => '=',
|
|
'value' => $id
|
|
],
|
|
[
|
|
'field' => 't.pp_off',
|
|
'op' => '=',
|
|
'value' => '0',
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN target_software ts ON ts.sft_id=c.sw_id",
|
|
"JOIN target t ON t.id=ts.tgt_id"
|
|
],
|
|
'group' => 'c.name,c.type'
|
|
]);
|
|
|
|
$tc_arr = [];
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$tc_arr[] = [
|
|
$id,
|
|
$row['id']
|
|
];
|
|
}
|
|
}
|
|
|
|
if (count($tc_arr)) {
|
|
$this->help->extended_insert("target_checklist", ['tgt_id', 'chk_id'], $tc_arr, true);
|
|
$this->help->execute();
|
|
}
|
|
|
|
$this->help->drop("sagacity", "c", true);
|
|
$this->help->select("checklist c", ['c.*', "s.id AS 'sw_id'"], [
|
|
[
|
|
'field' => 's.cpe',
|
|
'op' => NOT_LIKE,
|
|
'value' => "'%generic:generic%'"
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN checklist_software_lookup csl ON csl.chk_id=c.id",
|
|
"JOIN software s ON csl.sw_id=s.id"
|
|
],
|
|
'order' => 'c.ver DESC,CONVERT(c.`release`, DECIMAL(4,2)) DESC'
|
|
]);
|
|
$this->help->create_table("c", true);
|
|
$this->help->execute();
|
|
|
|
$this->help->select("c", ["c.id"], [
|
|
[
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $id
|
|
],
|
|
[
|
|
'field' => 't.pp_off',
|
|
'op' => '=',
|
|
'value' => '0',
|
|
'sql_op' => 'AND'
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN target t ON c.sw_id=t.os_id"
|
|
],
|
|
'group' => 'c.name,c.type'
|
|
]);
|
|
|
|
$tc_arr = [];
|
|
|
|
$rows = $this->help->execute();
|
|
if (is_array($rows) && count($rows) && isset($rows['id'])) {
|
|
$rows = [0 => $rows];
|
|
}
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$tc_arr[] = [
|
|
$id,
|
|
$row['id']
|
|
];
|
|
}
|
|
}
|
|
|
|
if (count($tc_arr)) {
|
|
$this->help->extended_insert("target_checklist", ['tgt_id', 'chk_id'], $tc_arr, true);
|
|
$this->help->execute();
|
|
}
|
|
|
|
$this->help->update("target", ["pp_flag" => 0], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $id
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$this->help->sql = "INSERT IGNORE INTO findings (tgt_id,pdi_id,findings_status_id) " .
|
|
"SELECT {$id},pcl.pdi_id,1 " .
|
|
"FROM target_checklist tc " .
|
|
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " .
|
|
"WHERE tc.tgt_id = {$id}";
|
|
$this->help->execute();
|
|
|
|
$this->update_Target_Counts($id);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to update the target finding counts
|
|
*
|
|
* @param int $tgt_id
|
|
*/
|
|
public function update_Target_Counts($tgt_id)
|
|
{
|
|
$nf = 0;
|
|
$nr = 0;
|
|
$na = 0;
|
|
$cat_1 = 0;
|
|
$cat_2 = 0;
|
|
$cat_3 = 0;
|
|
|
|
$this->help->select('target t', ["COUNT(DISTINCT(pcl.pdi_id)) AS 'pdi_count'"], [
|
|
[
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"LEFT JOIN target_checklist tc ON tc.tgt_id = t.id",
|
|
"LEFT JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id",
|
|
"LEFT JOIN findings f ON f.pdi_id = pcl.pdi_id AND f.tgt_id = t.id"
|
|
],
|
|
'group' => 't.id'
|
|
]);
|
|
$row = $this->help->execute();
|
|
if (is_array($row) && count($row) && isset($row['pdi_count'])) {
|
|
$nr = $row['pdi_count'];
|
|
}
|
|
|
|
$this->help->select("target t", [
|
|
"IF(ISNULL(fs.status), 'Not Reviewed', fs.status) AS 'status'",
|
|
"f.cat AS 'severity'",
|
|
"COUNT(DISTINCT f.pdi_id) AS 'finding_count'"
|
|
], [
|
|
[
|
|
'field' => 't.id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
], [
|
|
'table_joins' => [
|
|
"JOIN target_checklist tc ON tc.tgt_id = t.id",
|
|
"JOIN pdi_checklist_lookup pcl ON tc.chk_id = pcl.checklist_id",
|
|
"LEFT JOIN findings f ON f.tgt_id = t.id AND f.pdi_id = pcl.pdi_id",
|
|
"LEFT JOIN findings_status fs ON f.findings_status_id = fs.id"
|
|
],
|
|
'group' => "t.id,`severity`,f.findings_status_id"
|
|
]);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows['status'])) {
|
|
$nr -= $rows['finding_count'];
|
|
switch ($rows['status']) {
|
|
case 'Not a Finding':
|
|
case 'False Positive':
|
|
$nf += $rows['finding_count'];
|
|
break;
|
|
case 'Not Applicable':
|
|
$na += $rows['finding_count'];
|
|
break;
|
|
case 'Not Reviewed':
|
|
$nr += $rows['finding_count'];
|
|
break;
|
|
case 'Open':
|
|
case 'Exception':
|
|
${'cat_' . $rows['severity']} += $rows['finding_count'];
|
|
}
|
|
}
|
|
elseif (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$nr -= $row['finding_count'];
|
|
switch ($row['status']) {
|
|
case 'Not a Finding':
|
|
case 'False Positive':
|
|
$nf += $row['finding_count'];
|
|
break;
|
|
case 'Not Applicable':
|
|
$na += $row['finding_count'];
|
|
break;
|
|
case 'Not Reviewed':
|
|
case 'No Data':
|
|
$nr += $row['finding_count'];
|
|
break;
|
|
case 'Open':
|
|
case 'Exception':
|
|
${'cat_' . $row['severity']} += $row['finding_count'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->help->update("target", [
|
|
'cat_1' => $cat_1,
|
|
'cat_2' => $cat_2,
|
|
'cat_3' => $cat_3,
|
|
'closed' => $nf,
|
|
'not_reviewed' => $nr,
|
|
'not_applicable' => $na
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Update or insert a target
|
|
*
|
|
* @param target $tgt
|
|
* The target to save
|
|
* @param boolean $pp
|
|
*
|
|
* @return integer
|
|
* Returns ID of newly added target, or 0 if fail
|
|
*/
|
|
public function save_Target($tgt, $pp = null)
|
|
{
|
|
if (!is_a($tgt, 'target')) {
|
|
Sagacity_Error::err_handler("Invalid type in db::save_Target()", E_ERROR);
|
|
}
|
|
|
|
if (!in_array($tgt->classification, ['U', 'S', 'FOUO'])) {
|
|
$sys = $this->get_System_By_STE_ID($tgt->get_STE_ID());
|
|
if (is_a($sys, 'system')) {
|
|
switch ($sys->get_Classification()) {
|
|
case 'Sensitive':
|
|
$tgt->classification = "FOUO";
|
|
break;
|
|
case 'Classified':
|
|
$tgt->classification = "S";
|
|
break;
|
|
default:
|
|
$tgt->classification = "U";
|
|
}
|
|
}
|
|
else {
|
|
$tgt->classification = "U";
|
|
}
|
|
}
|
|
|
|
if (!$tgt->get_ID()) {
|
|
$this->help->insert("target", [
|
|
'ste_id' => $tgt->get_STE_ID(),
|
|
'name' => $tgt->get_Name(),
|
|
'cat_id' => $tgt->get_Cat_ID(),
|
|
'os_id' => $tgt->get_OS_ID(),
|
|
'os_string' => $tgt->get_OS_String(),
|
|
'location' => $tgt->get_Location(),
|
|
'auto_status_id' => $tgt->get_Auto_Status_ID(),
|
|
'man_status_id' => $tgt->get_Man_Status_ID(),
|
|
'data_status_id' => $tgt->get_Data_Status_ID(),
|
|
'fp_cat1_status_id' => $tgt->get_FP_Cat1_Status_ID(),
|
|
'pp_off' => $tgt->is_PP_Suspended(),
|
|
'class' => $tgt->classification,
|
|
'notes' => $tgt->get_Notes()
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
Sagacity_Error::err_handler("Failed to insert target {$tgt->get_Name()}", E_WARNING);
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
|
|
$this->help->select("target", ['id'], [
|
|
[
|
|
'field' => 'ste_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_STE_ID(),
|
|
],
|
|
[
|
|
'field' => 'name',
|
|
'op' => '=',
|
|
'value' => $tgt->get_Name(),
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
$tmp = $this->help->execute();
|
|
if (is_array($tmp) && count($tmp) && isset($tmp['id'])) {
|
|
$tgt->set_ID($tmp['id']);
|
|
}
|
|
else {
|
|
Sagacity_Error::err_handler("Failure retrieving the target that was just saved {$tgt->get_Name()}", E_ERROR);
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* @todo get current target and check for OS ID > 2
|
|
*/
|
|
$exist_tgt = $this->get_Target_Details($tgt->get_STE_ID(), $tgt->get_ID());
|
|
if (is_array($exist_tgt) && count($exist_tgt) && isset($exist_tgt[0]) && is_a($exist_tgt[0], 'target')) {
|
|
$exist_tgt = $exist_tgt[0];
|
|
if ($exist_tgt->get_OS_ID() <= 2 && $tgt->get_OS_ID() <= 2) {
|
|
$os_id = $exist_tgt->get_OS_ID();
|
|
$os_string = $exist_tgt->get_OS_String();
|
|
}
|
|
elseif ($exist_tgt->get_OS_ID() > 2 && $tgt->get_OS_ID() <= 2) {
|
|
$os_id = $exist_tgt->get_OS_ID();
|
|
$os_string = $exist_tgt->get_OS_String();
|
|
}
|
|
elseif ($exist_tgt->get_OS_ID() <= 2 && $tgt->get_OS_ID() > 2) {
|
|
$os_id = $tgt->get_OS_ID();
|
|
$os_string = $tgt->get_OS_String();
|
|
}
|
|
else {
|
|
$os_id = $tgt->get_OS_ID();
|
|
$os_string = $tgt->get_OS_String();
|
|
}
|
|
}
|
|
else {
|
|
$os_id = $tgt->get_OS_ID();
|
|
$os_string = $tgt->get_OS_String();
|
|
}
|
|
|
|
$this->help->update("target", [
|
|
'name' => $tgt->get_Name(),
|
|
'os_id' => $os_id,
|
|
'os_string' => $os_string,
|
|
'cat_id' => $tgt->get_Cat_ID(),
|
|
'location' => $tgt->get_Location(),
|
|
'auto_status_id' => $tgt->get_Auto_Status_ID(),
|
|
'man_status_id' => $tgt->get_Man_Status_ID(),
|
|
'data_status_id' => $tgt->get_Data_Status_ID(),
|
|
'fp_cat1_status_id' => $tgt->get_FP_Cat1_Status_ID(),
|
|
'missing_patches' => $tgt->get_Missing_Patches(),
|
|
'class' => $tgt->classification,
|
|
'pp_flag' => $tgt->is_PP_Flag_Set(),
|
|
'pp_off' => $tgt->is_PP_Suspended(),
|
|
'notes' => $tgt->get_Notes()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (is_array($tgt->interfaces) && count($tgt->interfaces)) {
|
|
$this->save_Target_Interfaces($tgt);
|
|
}
|
|
|
|
if (is_array($tgt->software) && count($tgt->software)) {
|
|
$this->save_Target_Software($tgt);
|
|
}
|
|
else {
|
|
$this->delete_Target_Software($tgt);
|
|
}
|
|
|
|
if (is_array($tgt->checklists) && count($tgt->checklists)) {
|
|
$this->save_Target_Checklists($tgt);
|
|
}
|
|
else {
|
|
$this->delete_Target_Checklists($tgt);
|
|
}
|
|
|
|
if ($pp === null) {
|
|
if (!$tgt->is_PP_Suspended()) {
|
|
$this->post_Processing($tgt->get_ID());
|
|
}
|
|
else {
|
|
$this->update_Target_Counts($tgt->get_ID());
|
|
}
|
|
}
|
|
else {
|
|
if ($pp === true) {
|
|
$this->post_Processing($tgt->get_ID());
|
|
}
|
|
else {
|
|
$this->update_Target_Counts($tgt->get_ID());
|
|
}
|
|
}
|
|
|
|
$this->help->replace("target_net_meta", [
|
|
'tgt_id' => $tgt->get_ID(),
|
|
'netstat_connections' => $tgt->get_Netstat_Connections(),
|
|
'shares' => $tgt->get_Shares(),
|
|
'routes' => $tgt->get_Routes(),
|
|
'firewall_config' => $tgt->get_Firewall_Config()
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
|
|
$this->help->replace("target_sys_meta", [
|
|
'tgt_id' => $tgt->get_ID(),
|
|
'mounted' => $tgt->get_Mounted(),
|
|
'process_list' => $tgt->get_Process_List(),
|
|
'autorun' => $tgt->get_Autorun(),
|
|
'services' => $tgt->get_Services(),
|
|
'last_boot' => (is_a($tgt->get_Last_Boot(), 'DateTime') ? $tgt->get_Last_Boot() : null),
|
|
'remote_registry' => $tgt->get_Remote_Registry(),
|
|
'copyrighted' => $tgt->get_Copyright(),
|
|
'is_vm' => $tgt->is_VM(),
|
|
'system' => $tgt->get_System(),
|
|
'bios' => $tgt->get_BIOS(),
|
|
'wmi_listening_pid' => $tgt->get_WMI_PID()
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
|
|
$this->help->replace("target_user_meta", [
|
|
'tgt_id' => $tgt->get_ID(),
|
|
'login' => $tgt->get_Login(),
|
|
'user_list' => $tgt->get_User_List(),
|
|
'last_login' => $tgt->get_Last_Login(),
|
|
'disabled_accts' => $tgt->get_Disabled_Accts(),
|
|
'stag_pwds' => $tgt->get_Stag_Pwds(),
|
|
'never_logged_in' => $tgt->get_Never_Logged_In(),
|
|
'pwd_never_expires' => $tgt->get_Pwds_Never_Expire()
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
|
|
return $tgt->get_ID();
|
|
}
|
|
|
|
/**
|
|
* Function to save the checklists that are assigned to a target
|
|
*
|
|
* @param target $tgt
|
|
* Target
|
|
* @param array:checklist $checklists [optional]
|
|
* Array of checklists to assign to target (if null, uses $tgt->checklists value)
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Target_Checklists($tgt, $checklists = null)
|
|
{
|
|
$this->help->delete("target_checklist", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$chk_arr = [];
|
|
if (is_array($checklists) && count($checklists) && isset($checklists[0]) && is_a($checklists[0], 'checklist')) {
|
|
foreach ($checklists as $chk) {
|
|
$chk_arr[] = [$tgt->get_ID(), $chk->get_ID()];
|
|
}
|
|
}
|
|
else {
|
|
foreach ($tgt->checklists as $chk) {
|
|
$chk_arr[] = [$tgt->get_ID(), $chk->get_ID()];
|
|
}
|
|
}
|
|
|
|
if (count($chk_arr)) {
|
|
$this->help->extended_insert("target_checklist", ['tgt_id', 'chk_id'], $chk_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to save the software installed on the target
|
|
*
|
|
* @param target $tgt
|
|
* The target that the software is installed on
|
|
* @param array:software $software [optional]
|
|
* Array of software that are installed on the target (if null uses the $tgt->software)
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function save_Target_Software($tgt, $software = null)
|
|
{
|
|
$this->help->delete("target_software", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt->get_ID()
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
$sw_arr = [];
|
|
if (is_array($software) && count($software) && isset($software[0]) && is_a($software[0], 'software')) {
|
|
foreach ($software as $sw) {
|
|
$sw_arr[] = [$tgt->get_ID(), $sw->get_ID(), $sw->get_Shortened_SW_String()];
|
|
}
|
|
}
|
|
else {
|
|
foreach ($tgt->software as $sw) {
|
|
$sw_arr[] = [$tgt->get_ID(), $sw->get_ID(), $sw->get_Shortened_SW_String()];
|
|
}
|
|
}
|
|
|
|
if (count($sw_arr)) {
|
|
$this->help->extended_insert("target_software", ['tgt_id', 'sft_id', 'sw_string'], $sw_arr, true);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to save the interfaces of a target
|
|
*
|
|
* @param target $tgt
|
|
*/
|
|
public function save_Target_Interfaces($tgt)
|
|
{
|
|
if (!is_array($tgt->interfaces) || !count($tgt->interfaces)) {
|
|
return;
|
|
}
|
|
|
|
foreach ($tgt->interfaces as $int) {
|
|
if ($int->get_ID()) {
|
|
$this->help->update("sagacity.interfaces", array(
|
|
'name' => $int->get_Name(),
|
|
'ipv4' => $int->get_IPv4(),
|
|
'ipv6' => $int->get_IPv6(),
|
|
'hostname' => $int->get_Hostname(),
|
|
'fqdn' => $int->get_FQDN(),
|
|
'description' => $int->get_Description()
|
|
), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $int->get_ID()
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
else {
|
|
$this->help->insert("interfaces", [
|
|
'tgt_id' => $tgt->get_ID(),
|
|
'name' => $int->get_Name(),
|
|
'ipv4' => $int->get_IPv4(),
|
|
'ipv6' => $int->get_IPv6(),
|
|
'hostname' => $int->get_Hostname(),
|
|
'fqdn' => $int->get_FQDN(),
|
|
'description' => $int->get_Description()
|
|
]);
|
|
|
|
if (!($int_id = $this->help->execute())) {
|
|
$this->help->debug(E_WARNING);
|
|
continue;
|
|
}
|
|
|
|
$int->set_ID($int_id);
|
|
}
|
|
|
|
$ports = [];
|
|
if (is_array($int->get_TCP_Ports()) && count($int->get_TCP_Ports())) {
|
|
foreach ($int->get_TCP_Ports() as $port_num => $tcp) {
|
|
$port_num = ($tcp->get_ID() ? $tcp->get_ID() : "(SELECT `id` FROM `sagacity`.`ports_proto_services` WHERE `port`=$port_num AND `proto`='tcp' AND `notes` NOT LIKE '%historic%' LIMIT 1)");
|
|
$ports[] = [
|
|
$int->get_ID(),
|
|
$port_num,
|
|
$tcp->get_IANA_Name(),
|
|
$tcp->get_Banner(),
|
|
$tcp->get_Notes()
|
|
];
|
|
}
|
|
}
|
|
|
|
if (is_array($int->get_UDP_Ports()) && count($int->get_UDP_Ports())) {
|
|
foreach ($int->get_UDP_Ports() as $port_num => $udp) {
|
|
$port_num = ($udp->get_ID() ? $udp->get_ID() : "(SELECT `id` FROM `sagacity`.`ports_proto_services` WHERE `port`=$port_num AND `proto`='udp' AND `notes` NOT LIKE '%historic%' LIMIT 1)");
|
|
$ports[] = array(
|
|
$int->get_ID(),
|
|
$port_num,
|
|
$udp->get_IANA_Name(),
|
|
$udp->get_Banner(),
|
|
$udp->get_Notes()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (count($ports)) {
|
|
$this->help->extended_insert("sagacity.pps_list", array(
|
|
'int_id', 'pps_id', 'name', 'banner', 'notes'
|
|
), $ports, true);
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to merge the secondary target into the primary target data
|
|
*
|
|
* @param int $ste_id
|
|
* ID of the ST&E both targets are in
|
|
* @param int $pri_tgt_id
|
|
* ID of the primary target
|
|
* @param int $sec_tgt_id
|
|
* ID of the secondary target (will be deleted after complete)
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function merge_Target($ste_id, $pri_tgt_id, $sec_tgt_id)
|
|
{
|
|
// update the primary target checklists to add any that are in the secondary that are not already in the primary
|
|
$this->help->select("sagacity.target_checklist", ['chk_id'], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $pri_tgt_id
|
|
]
|
|
]);
|
|
$tcs = $this->help->execute();
|
|
if (is_array($tcs) && count($tcs) && isset($tcs['chk_id'])) {
|
|
$tcs = [0 => $tcs];
|
|
}
|
|
$pri_tcs = [];
|
|
if (is_array($tcs) && count($tcs)) {
|
|
foreach ($tcs as $tc) {
|
|
if (isset($tc['chk_id']) && is_numeric($tc['chk_id'])) {
|
|
$pri_tcs[] = $tc['chk_id'];
|
|
}
|
|
}
|
|
}
|
|
if (count($pri_tcs)) {
|
|
$this->help->update("sagacity.target_checklist", ['tgt_id' => $pri_tgt_id], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
],
|
|
[
|
|
'field' => 'chk_id',
|
|
'op' => NOT_IN,
|
|
'value' => $pri_tcs,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// update the primary target software to add any that are in the secondary that are not already in the primary
|
|
$this->help->select("sagacity.target_software", ['sft_id'], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $pri_tgt_id
|
|
]
|
|
]);
|
|
$tss = $this->help->execute();
|
|
if (is_array($tss) && count($tss) && isset($tss['sft_id'])) {
|
|
$tss = [0 => $tss];
|
|
}
|
|
$pri_tss = [];
|
|
if (is_array($tss) && count($tss)) {
|
|
foreach ($tss as $ts) {
|
|
if (isset($ts['sft_id']) && is_numeric($ts['sft_id'])) {
|
|
$pri_tss[] = $ts['sft_id'];
|
|
}
|
|
}
|
|
}
|
|
if (count($pri_tss)) {
|
|
$this->help->update("sagacity.target_software", ['tgt_id' => $pri_tgt_id], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
],
|
|
[
|
|
'field' => 'sft_id',
|
|
'op' => NOT_IN,
|
|
'value' => $pri_tss,
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_WARNING);
|
|
}
|
|
}
|
|
|
|
// delete any remaining checklists from the secondary
|
|
$this->delete_Target_Checklists($sec_tgt_id);
|
|
|
|
// delete any remaining software from the secondary
|
|
$this->delete_Target_Software($sec_tgt_id);
|
|
|
|
// need to clear this up...
|
|
// check on PDI, and status, deconflict different statuses
|
|
$pri_tgt = $this->get_Target_Details($ste_id, $pri_tgt_id)[0];
|
|
$sec_tgt = $this->get_Target_Details($ste_id, $sec_tgt_id)[0];
|
|
$sec_findings = $this->get_Finding($sec_tgt);
|
|
foreach ($sec_findings as $key => $find) {
|
|
$stig = $this->get_STIG_By_PDI($find->get_PDI_ID());
|
|
$pri_find = $this->get_Finding($pri_tgt, $stig);
|
|
|
|
if (is_array($pri_find) && count($pri_find)) {
|
|
$pri_find = $pri_find[0];
|
|
if ($pri_find->get_Finding_Status() != $find->get_Finding_Status()) {
|
|
$pri_find->set_Finding_Status_By_String($pri_find->get_Deconflicted_Status($find->get_Finding_Status_String()));
|
|
$pri_find->prepend_Notes("Merge target-different status");
|
|
}
|
|
|
|
if ($find->get_Notes()) {
|
|
$pri_find->append_Notes($find->get_Notes(), true);
|
|
}
|
|
|
|
$this->help->update("sagacity.findings", [
|
|
'findings_status_id' => $pri_find->get_Finding_Status(),
|
|
'notes' => $pri_find->get_Notes()
|
|
], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $pri_find->get_ID()
|
|
]
|
|
]);
|
|
}
|
|
else {
|
|
$sec_findings[$key]->set_Tgt_ID($pri_tgt_id);
|
|
$pri_find = $sec_findings[$key];
|
|
|
|
$this->help->update("sagacity.findings", [
|
|
'tgt_id' => $pri_find->get_Tgt_ID()
|
|
], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
],
|
|
[
|
|
'field' => 'pdi_id',
|
|
'op' => '=',
|
|
'value' => $pri_find->get_PDI_ID(),
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
}
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
}
|
|
}
|
|
|
|
$this->delete_Target_Findings($sec_tgt_id);
|
|
|
|
// update host_list
|
|
$this->help->select("sagacity.host_list", ['scan_id'], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $pri_tgt_id
|
|
]
|
|
]);
|
|
$scan_ids = $this->help->execute();
|
|
if (is_array($scan_ids) && count($scan_ids) && isset($scan_ids['scan_id'])) {
|
|
$scan_ids = array(0 => $scan_ids);
|
|
}
|
|
|
|
if (is_array($scan_ids) && count($scan_ids) && isset($scan_ids[0])) {
|
|
foreach ($scan_ids as $scan) {
|
|
$this->help->select_count("sagacity.host_list", [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
],
|
|
[
|
|
'field' => 'scan_id',
|
|
'op' => '=',
|
|
'value' => $scan['scan_id'],
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
|
|
if ($this->help->execute()) {
|
|
$this->help->delete("sagacity.host_list", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
],
|
|
[
|
|
'field' => 'scan_id',
|
|
'op' => '=',
|
|
'value' => $scan['scan_id'],
|
|
'sql_op' => 'AND'
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
}
|
|
$this->help->update("sagacity.host_list", ['tgt_id' => $pri_tgt_id], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $sec_tgt_id
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
|
|
// reassign the secondary pps to the primary
|
|
$sec_int = $this->get_Interfaces($sec_tgt_id);
|
|
|
|
foreach ($sec_int as $int) {
|
|
if ($int->get_IPv6()) {
|
|
$pri_int = $this->get_Interface_By_IP($pri_tgt_id, $int->get_IPv6());
|
|
}
|
|
else {
|
|
$pri_int = $this->get_Interface_By_IP($pri_tgt_id, $int->get_IPv4());
|
|
}
|
|
|
|
if (is_null($pri_int)) {
|
|
// add the interface by updating the tgt_id pointer
|
|
$this->help->update('sagacity.interfaces', ['tgt_id' => $pri_tgt_id], [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $int->get_ID()
|
|
]
|
|
]);
|
|
$this->help->execute();
|
|
}
|
|
else {
|
|
// loop through tcp/udp port list to see if we need to update those
|
|
foreach ($int->get_TCP_Ports() as $tcp) {
|
|
if (!$pri_int->get_TCP_Port_By_Port_Number($tcp->get_Port())) {
|
|
$this->help->update("sagacity.pps_list", array('int_id' => $pri_int->get_ID()), array(
|
|
array(
|
|
'field' => 'int_id',
|
|
'op' => '=',
|
|
'value' => $int->get_ID()
|
|
),
|
|
array(
|
|
'field' => 'pps_id',
|
|
'op' => '=',
|
|
'value' => $tcp->get_ID(),
|
|
'sql_op' => 'AND'
|
|
)
|
|
));
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
|
|
foreach ($int->get_UDP_Ports() as $udp) {
|
|
if (!$pri_int->get_UDP_Port_By_Port_Number($udp->get_Port())) {
|
|
$this->help->update("sagacity.pps_list", array('int_id' => $pri_int->get_ID()), array(
|
|
array(
|
|
'field' => 'int_id',
|
|
'op' => '=',
|
|
'value' => $int->get_ID()
|
|
),
|
|
array(
|
|
'field' => 'pps_id',
|
|
'op' => '=',
|
|
'value' => $udp->get_ID(),
|
|
'sql_op' => 'AND'
|
|
)
|
|
));
|
|
$this->help->execute();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->delete_Target($sec_tgt_id);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to delete all checklists assigned to a target
|
|
*
|
|
* @param target|int $tgt
|
|
* Target to delete all checklists from
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Target_Checklists($tgt)
|
|
{
|
|
if (is_a($tgt, "target")) {
|
|
$tgt_id = $tgt->get_ID();
|
|
}
|
|
elseif (is_numeric($tgt)) {
|
|
$tgt_id = $tgt;
|
|
}
|
|
else {
|
|
error_log("Invalid type");
|
|
return false;
|
|
}
|
|
$this->help->delete("sagacity.target_checklist", null, array(
|
|
array(
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to delete all software assigned to a target
|
|
*
|
|
* @param target|int $tgt
|
|
* Target to delete all software from
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Target_Software($tgt)
|
|
{
|
|
if (is_a($tgt, 'target')) {
|
|
$tgt_id = $tgt->get_ID();
|
|
}
|
|
elseif (is_numeric($tgt)) {
|
|
$tgt_id = $tgt;
|
|
}
|
|
else {
|
|
error_log("Invalid Type");
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("sagacity.target_software", null, array(
|
|
array(
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete a target and associated data from the database
|
|
*
|
|
* @param integer $tgt_id
|
|
* Target ID to delete from database
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Target($tgt_id)
|
|
{
|
|
$this->delete_Target_Checklists($tgt_id);
|
|
|
|
$this->delete_Target_Software($tgt_id);
|
|
|
|
$this->help->delete("finding_controls fc", ['fc.*'], [
|
|
[
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
], ["JOIN sagacity.findings f ON f.id=fc.finding_id"]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("findings", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("host_list", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->select("interfaces", ['id'], [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
$int_ids = $this->help->execute();
|
|
if (is_array($int_ids) && count($int_ids) > 1) {
|
|
$tmp = [];
|
|
foreach ($int_ids as $id) {
|
|
$tmp[] = $id['id'];
|
|
}
|
|
$int_ids = $tmp;
|
|
}
|
|
if (is_array($int_ids) && count($int_ids)) {
|
|
$this->help->delete("pps_list", null, [
|
|
[
|
|
'field' => 'int_id',
|
|
'op' => IN,
|
|
'value' => $int_ids
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
$this->help->delete("interfaces", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("target_net_meta", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("target_sys_meta", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("target_user_meta", null, [
|
|
[
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
$this->help->delete("target", null, [
|
|
[
|
|
'field' => 'id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
]
|
|
]);
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to delete all findings for a specific target
|
|
*
|
|
* @param target|int $tgt
|
|
* ID of the target to delete the findings for
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function delete_Target_Findings($tgt)
|
|
{
|
|
if (is_a($tgt, 'target')) {
|
|
$tgt_id = $tgt->get_ID();
|
|
}
|
|
elseif (is_numeric($tgt)) {
|
|
$tgt_id = $tgt;
|
|
}
|
|
else {
|
|
error_log("Invalid type");
|
|
return false;
|
|
}
|
|
|
|
$this->help->delete("sagacity.finding_controls fc", array("fc.*"), array(
|
|
array(
|
|
'field' => 'f.tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
)), array(
|
|
"JOIN sagacity.findings f ON f.id=fc.finding_id"
|
|
)
|
|
);
|
|
if (!$this->help->execute()) {
|
|
error_log("Error deleting finding controls");
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
$this->help->delete("sagacity.findings", null, array(
|
|
array(
|
|
'field' => 'tgt_id',
|
|
'op' => '=',
|
|
'value' => $tgt_id
|
|
)
|
|
));
|
|
if (!$this->help->execute()) {
|
|
error_log("Error deleting findings from findings table");
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}}
|
|
// {{{ SETTINGS FUNCTIONS
|
|
/**
|
|
* Function to get a setting from the database
|
|
*
|
|
* @param string|array:string $key [optional]
|
|
* If a string is passed, will return the meta_value value for the setting with that meta_key.
|
|
* If an array is passed, will return the key/value pair matching for each item matching e.g.
|
|
* [
|
|
* 'meta_key' => 'meta_value',
|
|
* 'meta_key2' => 'meta_value2',
|
|
* 'meta_key3' => 'meta_value3',
|
|
* ...
|
|
* ]
|
|
* @param mixed $default [optional]
|
|
* Returns this value if the key is not found in the database (defaulted to null)
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function get_Settings($key = null, $default = null)
|
|
{
|
|
$where = [];
|
|
if (is_array($key) && count($key)) {
|
|
$where[] = [
|
|
'field' => 'meta_key',
|
|
'op' => IN,
|
|
'value' => $key
|
|
];
|
|
}
|
|
elseif (is_string($key) && strlen($key)) {
|
|
$where[] = [
|
|
'field' => 'meta_key',
|
|
'op' => '=',
|
|
'value' => $key
|
|
];
|
|
}
|
|
|
|
$this->help->select("settings", ['meta_key', 'meta_value'], $where);
|
|
$rows = $this->help->execute();
|
|
|
|
if (is_array($rows) && count($rows) && isset($rows[0])) {
|
|
$ret = [];
|
|
foreach ($rows as $row) {
|
|
$ret[$row['meta_key']] = $row['meta_value'];
|
|
}
|
|
return $ret;
|
|
}
|
|
elseif (isset($rows['meta_value'])) {
|
|
return $rows['meta_value'];
|
|
}
|
|
else {
|
|
return $default;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to set a setting in the database
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
*/
|
|
public function set_Setting($key, $value)
|
|
{
|
|
$ret = false;
|
|
$this->help->select_count("sagacity.settings", [
|
|
[
|
|
'field' => 'meta_key',
|
|
'op' => '=',
|
|
'value' => $key
|
|
]
|
|
]);
|
|
if ($this->help->execute()) {
|
|
$this->help->update("sagacity.settings", ['meta_value' => $value], [
|
|
[
|
|
'field' => 'meta_key',
|
|
'op' => '=',
|
|
'value' => $key
|
|
]
|
|
]);
|
|
$ret = (boolean) $this->help->execute();
|
|
}
|
|
else {
|
|
$this->help->insert("sagacity.settings", ['meta_key' => $key, 'meta_value' => $value]);
|
|
$ret = (boolean) $this->help->execute();
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Method to update settings values using name => value pairs
|
|
*
|
|
* @param array $settings
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function set_Setting_Array($settings = [])
|
|
{
|
|
if (is_array($settings) && count($settings)) {
|
|
foreach ($settings as $key => $val) {
|
|
$this->help->update('settings', ['meta_value' => $val], [
|
|
[
|
|
'field' => 'meta_key',
|
|
'value' => $key
|
|
]
|
|
]);
|
|
|
|
if (!$this->help->execute()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// }}} END META
|
|
// {{{ VARIOUS FUNCTIONS
|
|
/**
|
|
* This function returns an array of all the task statuses
|
|
*
|
|
* @return array:string|NULL
|
|
* Array of all task statuses, or null if none found
|
|
*/
|
|
public function get_Task_Statuses()
|
|
{
|
|
$ret = [];
|
|
$this->help->select("task_status");
|
|
|
|
$rows = $this->help->execute();
|
|
|
|
if (!is_null($rows) && is_array($rows) && count($rows) && isset($rows[0])) {
|
|
foreach ($rows as $row) {
|
|
$ret[$row['id']] = $row['status'];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* This function updates the task status for a target
|
|
*
|
|
* @param string $strStatus
|
|
* Status to update
|
|
* @param array:integer $arrTgts
|
|
* Array of target ids to update
|
|
* @param int $intStatus
|
|
* New status id
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function update_Task_Status($strStatus, $arrTgts, $intStatus)
|
|
{
|
|
$field = null;
|
|
switch ($strStatus) {
|
|
case 'update_auto':
|
|
$field = "auto_status_id";
|
|
break;
|
|
case 'update_manual':
|
|
$field = "man_status_id";
|
|
break;
|
|
case 'update_data':
|
|
$field = "data_status_id";
|
|
break;
|
|
case 'update_fp_cat1':
|
|
$field = "fp_cat1_status_id";
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
$this->help->update("sagacity.target", array($field => $intStatus), array(
|
|
array(
|
|
'field' => 'id',
|
|
'op' => IN,
|
|
'value' => $arrTgts
|
|
)
|
|
));
|
|
|
|
if (!$this->help->execute()) {
|
|
$this->help->debug(E_ERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve all helps
|
|
*
|
|
* @return array:string|NULL
|
|
* Returns array of strings with section and title data, or null if none found
|
|
*/
|
|
public function get_All_Helps()
|
|
{
|
|
$this->help->select("sagacity.help", array('section', 'title'), [], array('order' => 'section'));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve a help topic or function
|
|
*
|
|
* @param string $type
|
|
* Grab a specific help
|
|
*
|
|
* @return array:string|NULL
|
|
* Return array with help information, or null if none found
|
|
*/
|
|
public function get_Help($type)
|
|
{
|
|
$where = [];
|
|
|
|
if (preg_match('/(\d|[A-D]\.?)+$/', $type)) {
|
|
$where[] = [
|
|
'field' => 'section',
|
|
'op' => '=',
|
|
'value' => $type
|
|
];
|
|
}
|
|
else {
|
|
if ($type != 'all') {
|
|
$where[] = [
|
|
'field' => 'topic',
|
|
'op' => '=',
|
|
'value' => $type
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->help->select("help", ['section', 'topic', 'title', 'content'], $where);
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to save the help as entered in the help_editor.php
|
|
*
|
|
* @param string $topic
|
|
* Topic of the help
|
|
* @param string $section
|
|
* Section of the help
|
|
* @param string $title
|
|
* Title
|
|
* @param string $content
|
|
* The HTML content
|
|
*
|
|
* @return boolean
|
|
* Returns TRUE if successful, otherwise FALSE
|
|
*/
|
|
public function save_Help($topic, $section, $title, $content)
|
|
{
|
|
$this->help->replace("help", array(
|
|
'section' => $section,
|
|
'topic' => $topic,
|
|
'title' => $title,
|
|
'content' => $content
|
|
));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function for deleting help data
|
|
*
|
|
* @param string $section
|
|
*
|
|
* @return int
|
|
*/
|
|
public function delete_Help($section)
|
|
{
|
|
$this->help->delete("help", null, array(
|
|
array(
|
|
'field' => 'section',
|
|
'op' => '=',
|
|
'value' => $section
|
|
)
|
|
));
|
|
|
|
return $this->help->execute();
|
|
}
|
|
|
|
/**
|
|
* Function to check to see if the handler for the database is connected and reconnect if there is an error
|
|
*/
|
|
public function is_Connected()
|
|
{
|
|
if (!mysqli_ping($this->conn)) {
|
|
//here is the major trick, you have to close the connection (even though its not currently working) for it to recreate properly.
|
|
$this->conn->close();
|
|
$this->conn = new mysqli(DB_SERVER, 'web', self::decrypt_pwd(), 'sagacity');
|
|
}
|
|
}
|
|
// }}}
|
|
}
|