#!/bin/bash
# ----------------------------------------------------------------------------- 
# @brief: update the kernel options in the samhain configuration
#         file, after a new kernel has been compiled
# @author: marc heisterkamp <marzheister@web.de>
# ----------------------------------------------------------------------------- 

SAMHAIN_CFG="/etc/samhainrc"

BLUE="[34;01m"
CYAN="[36;01m"
GREEN="[32;01m"
DARK_GREEN="[32m"
RED="[31;01m"
PURPLE="[35;01m"
WHITE="[37;01m"
DARK_GRAY="[30;01m"
LIGHT_GRAY="[37m"
YELLOW="[33;01m"
BROWN="[33m"
OFF="[0m"


SYSTEM_MAP=""
new_cfg=''
scriptname="$0"

# global variables for system adresses (extracted from System.map)
SYS_CALL=''
SYS_CALL_TABLE=''
PROC_ROOT=''
PROC_ROOT_IOPS=''
PROC_ROOT_LOOKUP=''

# Make sure the user has root permissions
if [ $UID -ne 0 ] ; then
  echo "You must be root to run this script. Exiting."
  exit 1
fi


#------------------------------------------------------------------------------
# usage 
#------------------------------------------------------------------------------
function print_usage() {

  cat >&2 <<EOHELP

  update the samhainrc configuration file with new kernel system addresses
  (i.e: after kernel compilation) by extracting these from the new System.map 
  file

  SYNOPSIS
     $scriptname [ ${GREEN}--help${OFF} ]
                           [ ${GREEN}--nocolor${OFF} ]
                           [ ${GREEN}--print-only${OFF} ] <System.map>
                           [ ${GREEN}--update${OFF} ]     <System.map>

  OPTIONS
     ${GREEN}-h${OFF} ${GREEN}--help${OFF}
        Show help. 

     ${GREEN}--nocolor${OFF}
        Disable color hilighting for non ANSI-compatible terms.

     ${GREEN}-p${OFF} ${GREEN}--print-only${OFF} <System.map>
        Print the extracted system adresses and do not write them to the 
        samhain configuration file. 

     ${GREEN}-u${OFF} ${GREEN}--update${OFF} <System.map>
        Update the samhainrc configuration file with new kernel system
        addresses from the given System.map file 

EOHELP
 exit 0
}


#------------------------------------------------------------------------------
# parses the command line options 
# param in: all parameters given to the script 
#------------------------------------------------------------------------------
function parse_cmd_line() {

  # parse the command-line
  while [ -n "$1" ]; do
    case "$1" in
      --help|-h) 
        print_usage
        ;;
      --nocolor|-n)
        unset DARK_GREEN GREEN RED BROWN LIGHT_GRAY WHITE OFF 
        ;;
      --print-only|-p)
        shift
        SYSTEM_MAP="$1"
        get_system_addresses
        print_system_addresses
        break
        ;;
      --update|-u)
        shift
        SYSTEM_MAP="$1"
        get_system_addresses
        print_system_addresses
        replace_system_addresses
        ;;
      -*)
        echo "$scriptname: unknown option $1. Exiting" >&2
        exit 1
        ;;
    esac
    shift
  done
}


#------------------------------------------------------------------------------
# extract system adresses from given System.map file and save to global
# variables 
#------------------------------------------------------------------------------
function get_system_addresses() { 

  if [ -z "$SYSTEM_MAP" ] ; then
    echo
    echo "No System.map specified. Exiting" >&2
    echo
    exit 1
  fi

  if [ ! -f "$SYSTEM_MAP" ] ; then
    echo
    echo "Could not find System.map: $SYSTEM_MAP. Exiting" >&2
    echo
    exit 1
  fi

  # 1. this is the address of system_call (grep system_call System.map) 
  #    KernelSystemCall = 0xc0106cf8
  SYS_CALL="0x`grep system_call $SYSTEM_MAP | cut -d' ' -f1`"

  # 2. this is the address of sys_call_table (grep ' sys_call_table' System.map) 
  #    KernelSyscallTable = 0xc01efb98
  SYS_CALL_TABLE="0x`grep sys_call_table $SYSTEM_MAP | cut -d' ' -f1`"

  # 3. this is the address of proc_root (grep ' proc_root$' System.map) 
  #    KernelProcRoot = 0xc01efb98
  PROC_ROOT="0x`grep ' proc_root$' $SYSTEM_MAP | cut -d' ' -f1`"

  # 4. this is the address of proc_root_inode_operations 
  #    (grep proc_root_inode_operations System.map) 
  #    KernelProcRootIops = 0xc01efb98
  PROC_ROOT_IOPS="0x`grep proc_root_inode_operations $SYSTEM_MAP | cut -d' ' -f1`"

  # 5. this is the address of proc_root_lookup
  #    (grep proc_root_lookup System.map) 
  #    KernelProcRootLookup = 0xc01efb98
  PROC_ROOT_LOOKUP="0x`grep proc_root_lookup $SYSTEM_MAP | cut -d' ' -f1`"
}


#------------------------------------------------------------------------------
# extract system adresses from given System.map file and save to global
# variables 
#------------------------------------------------------------------------------
function replace_system_addresses() { 

  if [ -z "$SAMHAIN_CFG" ] ; then
    echo "Could not find your samhainrc config file: $SAMHAIN_CFG. Exiting" >&2
    exit 1
  fi

  echo
  echo "Replacing current kernel system addresses in: $SAMHAIN_CFG"

  # 1. replace current 'KernelSystemCall' setting
  new_cfg=`sed -e "s/^\(KernelSystemCall[[:blank:]]*=\)[[:blank:]]*\(.*\)/\1 ${SYS_CALL}/" $SAMHAIN_CFG` 

  # 2. replace current 'KernelSyscallTable' setting
  new_cfg=`echo "$new_cfg" | sed -e "s/^\(KernelSyscallTable[[:blank:]]*=\)[[:blank:]]*\(.*\)/\1 ${SYS_CALL_TABLE}/"` 

  # 3. replace current 'KernelProcRoot' setting
  new_cfg=`echo "$new_cfg" | sed -e "s/^\(KernelProcRoot[[:blank:]]*=\)[[:blank:]]*\(.*\)/\1 ${PROC_ROOT}/"` 

  # 4. replace current 'KernelProcRootIops' setting
  new_cfg=`echo "$new_cfg" | sed -e "s/^\(KernelProcRootIops[[:blank:]]*=\)[[:blank:]]*\(.*\)/\1 ${PROC_ROOT_IOPS}/"` 

  # 5. replace current 'KernelSystemCall' setting
  new_cfg=`echo "$new_cfg" | sed -e "s/^\(KernelProcRootLookup[[:blank:]]*=\)[[:blank:]]*\(.*\)/\1 ${PROC_ROOT_LOOKUP}/"` 

  echo "Backup old samhainrc $SAMHAIN_CFG to $SAMHAIN_CFG.bak"

  # backup old samhainrc config file 
  mv "$SAMHAIN_CFG" "$SAMHAIN_CFG.bak"

  # write new samhainrc config file 
  echo "$new_cfg" > "$SAMHAIN_CFG"

  echo "Successfully updated kernel system addresses."
  echo
}


#------------------------------------------------------------------------------
# print samhain required system adresses 
#------------------------------------------------------------------------------
function print_system_addresses() {

  echo 
  echo "your kernel system addresses from: `basename $SYSTEM_MAP`"
  echo 
  echo "  KernelSystemCall     = $SYS_CALL"
  echo "  KernelSyscallTable   = $SYS_CALL_TABLE"
  echo "  KernelProcRoot       = $PROC_ROOT"
  echo "  KernelProcRootIops   = $PROC_ROOT_IOPS"
  echo "  KernelProcRootLookup = $PROC_ROOT_LOOKUP"
  echo 

}

if [ $# -eq 0 ] ; then
  print_usage
fi

parse_cmd_line $*

exit 0
