<?php
/*******************************************************************************
** Basic Analysis and Security Engine (BASE)
** Copyright (C) 2004 BASE Project Team
** Copyright (C) 2000 Carnegie Mellon University
**
** (see the file 'base_main.php' for license details)
**
** Project Lead: Kevin Johnson <kjohnson@secureideas.net>
** Built upon work by Roman Danyliw <rdd@cert.org>, <roman@danyliw.com>
**
** Purpose: routines to manipulate shared state (session information)
********************************************************************************
** Authors:
********************************************************************************
** Kevin Johnson <kjohnson@secureideas.net
**
********************************************************************************
*/
/** The below check is to make sure that the conf file has been loaded before this one....
 **  This should prevent someone from accessing the page directly. -- Kevin
 **/
defined( '_BASE_INC' ) or die( 'Accessing this file directly is not allowed.' );

include_once("$BASE_path/includes/base_state_common.inc.php");
include_once("$BASE_path/includes/base_state_citems.inc.php");

class CriteriaState
{
  var $clear_criteria_name;
  var $clear_criteria_element;
  var $clear_url;
  var $clear_url_params;

  var $criteria;

  function CriteriaState($url, $params = "")
  {
     $this->clear_url = $url;
     $this->clear_url_params = $params;

     /* XXX-SEC */
     GLOBAL $db;

     $this->criteria['sig'] = new SignatureCriteria(&$db, &$this, "sig");
     $this->criteria['sig_class'] = new SignatureClassificationCriteria(&$db, &$this, "sig_class");
     $this->criteria['sig_priority'] = new SignaturePriorityCriteria(&$db, &$this, "sig_priority");
     $this->criteria['ag'] = new AlertGroupCriteria(&$db, &$this, "ag");
     $this->criteria['sensor'] = new SensorCriteria(&$db, &$this, "sensor");
     $this->criteria['time'] = new TimeCriteria(&$db, &$this, "time", TIME_CFCNT);
     $this->criteria['ip_addr'] = new IPAddressCriteria(&$db, &$this, "ip_addr", IPADDR_CFCNT);
     $this->criteria['layer4'] = new Layer4Criteria(&$db, &$this, "layer4");
     $this->criteria['ip_field'] = new IPFieldCriteria(&$db, &$this, "ip_field", PROTO_CFCNT);
     $this->criteria['tcp_port'] = new TCPPortCriteria(&$db, &$this, "tcp_port", PROTO_CFCNT);
     $this->criteria['tcp_flags'] = new TCPFlagsCriteria(&$db, &$this, "tcp_flags");
     $this->criteria['tcp_field'] = new TCPFieldCriteria(&$db, &$this, "tcp_field", PROTO_CFCNT);
     $this->criteria['udp_port'] = new UDPPortCriteria(&$db, &$this, "udp_port", PROTO_CFCNT);
     $this->criteria['udp_field'] = new UDPFieldCriteria(&$db, &$this, "udp_field", PROTO_CFCNT);
     $this->criteria['icmp_field'] = new ICMPFieldCriteria(&$db, &$this, "icmp_field", PROTO_CFCNT);
     $this->criteria['rawip_field'] = new TCPFieldCriteria(&$db, &$this, "rawip_field", PROTO_CFCNT);
     $this->criteria['data'] = new DataCriteria(&$db, &$this, "data", PAYLOAD_CFCNT);

     /* 
      * For new criteria, add a call to the appropriate constructor here, and implement
      * the appropriate class in base_stat_citems.inc.
      */
  }

  function InitState()
  {
     RegisterGlobalState();
  
     $valid_criteria_list = array_keys($this->criteria);

     foreach ( $valid_criteria_list as $cname )
         $this->criteria[$cname]->Init();
  }

  function ReadState()
  {
     RegisterGlobalState();

     /* 
      * If the BACK button was clicked, shuffle the appropriate
      * criteria variables from the $back_list (history) array into
      * the current session ($HTTP_SESSION_VARS)
      */
     if ( ($GLOBALS['maintain_history'] == 1) &&
          (ImportHTTPVar("back", VAR_DIGIT) == 1) )
     {
        PopHistory();
     }

     /* 
      * Import, update and sanitize all persistant criteria variables 
      */
     $valid_criteria_list = array_keys($this->criteria);
     foreach ( $valid_criteria_list as $cname )
     {
        $this->criteria[$cname]->Import();
        $this->criteria[$cname]->Sanitize();
     }

     /* 
      * Check whether criteria elements need to be cleared 
      */
     $this->clear_criteria_name = ImportHTTPVar("clear_criteria", "", 
                                                array_keys($this->criteria));
     $this->clear_criteria_element = ImportHTTPVar("clear_criteria_element", "", 
                                                   array_keys($this->criteria));

     if ( $this->clear_criteria_name != "" )
        $this->ClearCriteriaStateElement($this->clear_criteria_name,
                                         $this->clear_criteria_element);

     /*
      * Save the current criteria into $back_list (history)
      */
     if ( $GLOBALS['maintain_history'] == 1 )
        PushHistory();
  }

  function GetBackLink()
  {
    return PrintBackButton();
  }

  function GetClearCriteriaString($name, $element = "")
  {
    return '&nbsp;&nbsp;<A HREF="'.$this->clear_url.'?clear_criteria='.$name.
           '&clear_criteria_element='.$element.$this->clear_url_params.'">...clear...</A>';
  }

  function ClearCriteriaStateElement($name, $element)
  {
    $valid_criteria_list = array_keys($this->criteria);

    if ( in_array($name, $valid_criteria_list) )
    {
       ErrorMessage(_REMOVE." '$name' "._FROMCRIT);
  
       $this->criteria[$name]->Init();     
    }
    else
      ErrorMessage(_ERRCRITELEM);
  }
}

/* ***********************************************************************
 * Function: PopHistory()
 *
 * @doc Remove and restore the last entry of the history list (i.e., 
 *      hit the back button in the browser)
 *     
 * @see PushHistory PrintBackButton
 *
 ************************************************************************/
function PopHistory()
{
   GLOBAL $HTTP_SESSION_VARS;

   if ( $HTTP_SESSION_VARS['back_list_cnt'] >= 0 )
   {
      /* Remove the state of the page from which the back button was
       * just hit
       */
      unset($HTTP_SESSION_VARS['back_list'][$HTTP_SESSION_VARS['back_list_cnt']]);

      /* 
       * save a copy of the $back_list because session_destroy()/session_decode() will 
       * overwrite it. 
       */
      $save_back_list = $HTTP_SESSION_VARS['back_list'];
      $save_back_list_cnt = $HTTP_SESSION_VARS['back_list_cnt']-1;

      /* Restore the session 
       *   - destroy all variables in the current session
       *   - restore proper back_list history entry into the current variables (session)
       *       - but, first delete the currently restored entry and 
       *              decremement the history stack
       *   - push saved back_list back into session
       */
      session_unset();

      if ( $GLOBALS['debug_mode'] > 2 )
         ErrorMessage("Popping a History Entry from #".$save_back_list_cnt);

      session_decode($save_back_list[$save_back_list_cnt]["session"]);
      unset($save_back_list[$save_back_list_cnt]);
      --$save_back_list_cnt;

      $HTTP_SESSION_VARS['back_list'] = $save_back_list;
      $HTTP_SESSION_VARS['back_list_cnt'] = $save_back_list_cnt;
   }
}

/* ***********************************************************************
 * Function: PushHistory()
 *
 * @doc Save the current criteria into the history list ($back_list, 
 *      $back_list_cnt) in order to support the BASE back button.
 *     
 * @see PopHistory PrintBackButton
 *
 ************************************************************************/
function PushHistory()
{
   GLOBAL $HTTP_SERVER_VARS, $HTTP_SESSION_VARS, $HTTP_POST_VARS;

   if ( $GLOBALS['debug_mode'] > 1 )
   {
      ErrorMessage("Saving state (into ".$HTTP_SESSION_VARS['back_list_cnt'].")");
   }

   /* save the current session without the $back_list into the history 
    *   - make a temporary copy of the $back_list
    *   - NULL-out the $back_list in $HTTP_SESSION_VARS (so that 
    *       the current session is serialized without these variables)
    *   - serialize the current session
    *   - fix-up the QUERY_STRING
    *       - make a new QUERY_STRING that includes the temporary QueryState variables
    *       - remove &back=1 from any QUERY_STRING
    *   - add the current session into the $back_list (history)
    */
   $tmp_back_list = $HTTP_SESSION_VARS['back_list'];
   $tmp_back_list_cnt = $HTTP_SESSION_VARS['back_list_cnt'];

   $HTTP_SESSION_VARS['back_list'] = NULL;
   $HTTP_SESSION_VARS['back_list_cnt'] = -1;

   $full_session = session_encode();
   $HTTP_SESSION_VARS['back_list'] = $tmp_back_list;
   $HTTP_SESSION_VARS['back_list_cnt'] = $tmp_back_list_cnt;

   $query_string = $HTTP_SERVER_VARS["QUERY_STRING"];
   if ( isset($HTTP_POST_VARS['caller']) ) $query_string .= "&caller=".$HTTP_POST_VARS['caller'];
   if ( isset($HTTP_POST_VARS['num_result_rows']) ) $query_string .= "&num_result_rows=".$HTTP_POST_VARS['num_result_rows'];
   if ( isset($HTTP_POST_VARS['sort_order']) ) $query_string .= "&sort_order=".$HTTP_POST_VARS['sort_order'];
   if ( isset($HTTP_POST_VARS['current_view']) ) $query_string .= "&current_view=".$HTTP_POST_VARS['current_view'];
   if ( isset($HTTP_POST_VARS['submit']) ) $query_string .= "&submit=".$HTTP_POST_VARS['submit'];

   $query_string = ereg_replace("back=1&", "", $query_string);

   ++$HTTP_SESSION_VARS['back_list_cnt'];
   $HTTP_SESSION_VARS['back_list'][$HTTP_SESSION_VARS['back_list_cnt']] =  
          array ("PHP_SELF"     => $HTTP_SERVER_VARS["PHP_SELF"],
                 "QUERY_STRING" => $query_string, 
                 "session"      => $full_session );

  if ( $GLOBALS['debug_mode'] > 1 )
  {
      ErrorMessage("Insert session into slot #".$HTTP_SESSION_VARS['back_list_cnt']);

      echo "Back List (Cnt = ".$HTTP_SESSION_VARS['back_list_cnt'].") <PRE>";
      print_r($HTTP_SESSION_VARS['back_list']);
      echo "</PRE>";
  }
}

/* ***********************************************************************
 * Function: PrintBackButton()
 *
 * @doc Returns a string with the URL of the previously viewed
 *      page.  Clicking this link is equivalent to using the browser
 *      back-button, but all the associated BASE meta-information 
 *      propogates correctly.
 *     
 * @see PushHistory PopHistory
 *
 ************************************************************************/
function PrintBackButton()
{
   GLOBAL $HTTP_SESSION_VARS;

   if ( $GLOBALS['maintain_history'] == 0 )
      return "<FONT>Back</FONT>";

   $criteria_num = $HTTP_SESSION_VARS['back_list_cnt'] - 1;
  
   if ( isset($HTTP_SESSION_VARS['back_list'][$criteria_num]["PHP_SELF"]) )

     return "<FONT><A HREF=\"".$HTTP_SESSION_VARS['back_list'][$criteria_num]["PHP_SELF"].
            "?back=1&".
            $HTTP_SESSION_VARS['back_list'][$criteria_num]["QUERY_STRING"]."\">Back</A></FONT>";
   else
     return "<FONT>Back</FONT>";
}
?>
