#!/bin/sh
#
# The BSD License (http://www.opensource.org/licenses/bsd-license.php) 
# specifies the terms and conditions of use for checksec.sh:
#
# Copyright (c) 2009-2011, Tobias Klein.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions 
# are met:
# 
# * Redistributions of source code must retain the above copyright 
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright 
#   notice, this list of conditions and the following disclaimer in 
#   the documentation and/or other materials provided with the 
#   distribution.
# * Neither the name of Tobias Klein nor the name of trapkit.de may be 
#   used to endorse or promote products derived from this software 
#   without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
# DAMAGE.
#
# Name    : checksec.sh
# Version : 1.5
# Author  : Tobias Klein
# Date    : November 2011
# Download: http://www.trapkit.de/tools/checksec.html
# Changes : http://www.trapkit.de/tools/checksec_changes.txt
#
# Description:
#
# Modern Linux distributions offer some mitigation techniques to make it 
# harder to exploit software vulnerabilities reliably. Mitigations such 
# as RELRO, NoExecute (NX), Stack Canaries, Address Space Layout 
# Randomization (ASLR) and Position Independent Executables (PIE) have 
# made reliably exploiting any vulnerabilities that do exist far more 
# challenging. The checksec.sh script is designed to test what *standard* 
# Linux OS and PaX (http://pax.grsecurity.net/) security features are being 
# used.
#
# As of version 1.3 the script also lists the status of various Linux kernel 
# protection mechanisms.
#
# Credits:
#
# Thanks to Brad Spengler (grsecurity.net) for the PaX support.
# Thanks to Jon Oberheide (jon.oberheide.org) for the kernel support.
# Thanks to Ollie Whitehouse (Research In Motion) for rpath/runpath support.
# 
# Others that contributed to checksec.sh (in no particular order):
#
# Simon Ruderich, Denis Scherbakov, Stefan Kuttler, Radoslaw Madej,
# Anthony G. Basile, Martin Vaeth and Brian Davis. 
#

# global vars
have_readelf=1
verbose=false

# FORTIFY_SOURCE vars
FS_end=_chk
FS_cnt_total=0
FS_cnt_checked=0
FS_cnt_unchecked=0
FS_chk_func_libc=0
FS_functions=0
FS_libc=0
 
# version information
version() {
  echo "checksec v1.5, Tobias Klein, www.trapkit.de, November 2011"
  echo 
}

# help
help() {
  echo "Usage: checksec [OPTION]"
  echo
  echo "Options:"
  echo
  echo "  --file <executable-file>"
  echo "  --dir <directory> [-v]"
  echo "  --proc <process name>"
  echo "  --proc-all"
  echo "  --proc-libs <process ID>"
  echo "  --kernel"
  echo "  --fortify-file <executable-file>"
  echo "  --fortify-proc <process ID>"
  echo "  --version"
  echo "  --help"
  echo
  echo "For more information, see:"
  echo "  http://www.trapkit.de/tools/checksec.html"
  echo
}

# check if command exists
command_exists () {
  type $1  > /dev/null 2>&1;
}

# check if directory exists
dir_exists () {
  if [ -d $1 ] ; then
    return 0
  else
    return 1
  fi
}

# check user privileges
root_privs () {
  if [ $(/usr/bin/id -u) -eq 0 ] ; then
    return 0
  else
    return 1
  fi
}

# check if input is numeric
isNumeric () {
  echo "$@" | grep -q -v "[^0-9]"
}

# check if input is a string
isString () {
  echo "$@" | grep -q -v "[^A-Za-z]"
}

# check file(s)
filecheck() {
  # check for RELRO support
  if readelf -l $1 2>/dev/null | grep -q 'GNU_RELRO'; then
    if readelf -d $1 2>/dev/null | grep -q 'BIND_NOW'; then
      echo -n -e 'Full RELRO      '
    else
      echo -n -e 'Partial RELRO   '
    fi
  else
    echo -n -e 'No RELRO        '
  fi

  # check for stack canary support
  if readelf -s $1 2>/dev/null | grep -q '__stack_chk_fail'; then
    echo -n -e 'Canary found      '
  else
    echo -n -e 'No canary found   '
  fi

  # check for NX support
  if readelf -W -l $1 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then
    echo -n -e 'NX disabled   '
  else
    echo -n -e 'NX enabled    '
  fi 

  # check for PIE support
  if readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then
    echo -n -e 'No PIE          '
  elif readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
    if readelf -d $1 2>/dev/null | grep -q '(DEBUG)'; then
      echo -n -e 'PIE enabled     '
    else   
      echo -n -e 'DSO             '
    fi
  else
    echo -n -e 'Not an ELF file   '
  fi 

  # check for rpath / run path
  if readelf -d $1 2>/dev/null | grep -q 'rpath'; then
   echo -n -e 'RPATH      '
  else
   echo -n -e 'No RPATH   '
  fi

  if readelf -d $1 2>/dev/null | grep -q 'runpath'; then
   echo -n -e 'RUNPATH      '
  else
   echo -n -e 'No RUNPATH   '
  fi
}

# check process(es)
proccheck() {
  # check for RELRO support
  if readelf -l $1/exe 2>/dev/null | grep -q 'Program Headers'; then
    if readelf -l $1/exe 2>/dev/null | grep -q 'GNU_RELRO'; then
      if readelf -d $1/exe 2>/dev/null | grep -q 'BIND_NOW'; then
        echo -n -e 'gFull RELRO        '
      else
        echo -n -e 'gPartial RELRO     '
      fi
    else
      echo -n -e 'gNo RELRO          '
    fi
  else
    echo -n -e 'gPermission denied (please run as root)\n'
    exit 1
  fi

  # check for stack canary support
  if readelf -s $1/exe 2>/dev/null | grep -q 'Symbol table'; then
    if readelf -s $1/exe 2>/dev/null | grep -q '__stack_chk_fail'; then
      echo -n -e 'gCanary found           '
    else
      echo -n -e 'gNo canary found        '
    fi
  else
    if [ "$1" != "1" ] ; then
      echo -n -e 'gPermission denied      '
    else
      echo -n -e 'gNo symbol table found  '
    fi
  fi

  # first check for PaX support
  if cat $1/status 2> /dev/null | grep -q 'PaX:'; then
    pageexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b6) )
    segmexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b10) )
    mprotect=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b8) )
    randmmap=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b9) )
    if [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "R" ]] ; then
      echo -n -e 'gPaX enabled   '
    elif [[ "$pageexec" = "p" && "$segmexec" = "s" && "$randmmap" = "R" ]] ; then
      echo -n -e 'gPaX ASLR only '
    elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "R" ]] ; then
      echo -n -e 'gPaX mprot off '
    elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "r" ]] ; then
      echo -n -e 'gPaX ASLR off  '
    elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "r" ]] ; then
      echo -n -e 'gPaX NX only   '
    else
      echo -n -e 'gPaX disabled  '
    fi
  # fallback check for NX support
  elif readelf -W -l $1/exe 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then
    echo -n -e 'gNX disabled   '
  else
    echo -n -e 'gNX enabled    '
  fi 

  # check for PIE support
  if readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then
    echo -n -e 'gNo PIE                  '
  elif readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
    if readelf -d $1/exe 2>/dev/null | grep -q '(DEBUG)'; then
      echo -n -e 'gPIE enabled             '
    else   
      echo -n -e 'gDynamic Shared Object   '
    fi
  else
    echo -n -e 'gNot an ELF file         '
  fi
}

# check mapped libraries
libcheck() {
  libs=( $(awk '{ print $6 }' /proc/$1/maps | grep '/' | sort -u | xargs file | grep ELF | awk '{ print $1 }' | sed 's/:/ /') )
 
  printf "\n* Loaded libraries (file information, # of mapped files: ${#libs[@]}):\n\n"
  
  for element in $(seq 0 $((${#libs[@]} - 1)))
  do
    echo "  ${libs[$element]}:"
    echo -n "    "
    filecheck ${libs[$element]}
    printf "\n\n"
  done
}

# check for system-wide ASLR support
aslrcheck() {
  # PaX ASLR support
  if !(cat /proc/1/status 2> /dev/null | grep -q 'Name:') ; then
    echo -n -e ':g insufficient privileges for PaX ASLR checks\n'
    echo -n -e '  Fallback to standard Linux ASLR check'
  fi
  
  if cat /proc/1/status 2> /dev/null | grep -q 'PaX:'; then
    printf ": "
    if cat /proc/1/status 2> /dev/null | grep 'PaX:' | grep -q 'R'; then
      echo -n -e 'gPaX ASLR enabled\n\n'
    else
      echo -n -e 'gPaX ASLR disabled\n\n'
    fi
  else
    # standard Linux 'kernel.randomize_va_space' ASLR support
    # (see the kernel file 'Documentation/sysctl/kernel.txt' for a detailed description)
    printf " (kernel.randomize_va_space): "
    if /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 1'; then
      echo -n -e 'gOn (Setting: 1)\n\n'
      printf "  Description - Make the addresses of mmap base, stack and VDSO page randomized.\n"
      printf "  This, among other things, implies that shared libraries will be loaded to \n"
      printf "  random addresses. Also for PIE-linked binaries, the location of code start\n"
      printf "  is randomized. Heap addresses are *not* randomized.\n\n"
    elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 2'; then
      echo -n -e 'gOn (Setting: 2)\n\n'
      printf "  Description - Make the addresses of mmap base, heap, stack and VDSO page randomized.\n"
      printf "  This, among other things, implies that shared libraries will be loaded to random \n"
      printf "  addresses. Also for PIE-linked binaries, the location of code start is randomized.\n\n"
    elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 0'; then
      echo -n -e 'gOff (Setting: 0)\n'
    else
      echo -n -e 'gNot supported\n'
    fi
    printf "  See the kernel file 'Documentation/sysctl/kernel.txt' for more details.\n\n"
  fi 
}

# check cpu nx flag
nxcheck() {
  if grep -q nx /proc/cpuinfo; then
    echo -n -e 'gYes\n\n'
  else
    echo -n -e 'gNo\n\n'
  fi
}

# check for kernel protection mechanisms
kernelcheck() {
  printf "  Description - List the status of kernel protection mechanisms. Rather than\n"
  printf "  inspect kernel mechanisms that may aid in the prevention of exploitation of\n"
  printf "  userspace processes, this option lists the status of kernel configuration\n"
  printf "  options that harden the kernel itself against attack.\n\n"
  printf "  Kernel config: "
 
  if [ -f /proc/config.gz ] ; then
    kconfig="zcat /proc/config.gz"
    printf "g/proc/config.gz\n\n"
  elif [ -f /boot/config-`uname -r` ] ; then
    kconfig="cat /boot/config-`uname -r`"
    printf "g/boot/config-`uname -r`\n\n"
    printf "  Warning: The config on disk may not represent running kernel config!\n\n";
  elif [ -f "${KBUILD_OUTPUT:-/usr/src/linux}"/.config ] ; then
    kconfig="cat ${KBUILD_OUTPUT:-/usr/src/linux}/.config"
    printf "g%s\n\n" "${KBUILD_OUTPUT:-/usr/src/linux}/.config"
    printf "  Warning: The config on disk may not represent running kernel config!\n\n";
  else
    printf "gNOT FOUND\n\n"
    exit 0
  fi

  printf "  GCC stack protector support:            "
  if $kconfig | grep -qi 'CONFIG_CC_STACKPROTECTOR=y'; then
    printf "gEnabled\n"
  else
    printf "gDisabled\n"
  fi

  printf "  Strict user copy checks:                "
  if $kconfig | grep -qi 'CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y'; then
    printf "gEnabled\n"
  else
    printf "gDisabled\n"
  fi

  printf "  Enforce read-only kernel data:          "
  if $kconfig | grep -qi 'CONFIG_DEBUG_RODATA=y'; then
    printf "gEnabled\n"
  else
    printf "gDisabled\n"
  fi
  printf "  Restrict /dev/mem access:               "
  if $kconfig | grep -qi 'CONFIG_STRICT_DEVMEM=y'; then
    printf "gEnabled\n"
  else
    printf "gDisabled\n"
  fi

  printf "  Restrict /dev/kmem access:              "
  if $kconfig | grep -qi 'CONFIG_DEVKMEM=y'; then
    printf "gDisabled\n"
  else
    printf "gEnabled\n"
  fi

  printf "\n"
  printf "* grsecurity / PaX: "

  if $kconfig | grep -qi 'CONFIG_GRKERNSEC=y'; then
    if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIGH=y'; then
      printf "gHigh GRKERNSEC\n\n"
    elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_MEDIUM=y'; then
      printf "gMedium GRKERNSEC\n\n"
    elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_LOW=y'; then
      printf "gLow GRKERNSEC\n\n"
    else
      printf "gCustom GRKERNSEC\n\n"
    fi

    printf "  Non-executable kernel pages:            "
    if $kconfig | grep -qi 'CONFIG_PAX_KERNEXEC=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Prevent userspace pointer deref:        "
    if $kconfig | grep -qi 'CONFIG_PAX_MEMORY_UDEREF=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Prevent kobject refcount overflow:      "
    if $kconfig | grep -qi 'CONFIG_PAX_REFCOUNT=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Bounds check heap object copies:        "
    if $kconfig | grep -qi 'CONFIG_PAX_USERCOPY=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Disable writing to kmem/mem/port:       "
    if $kconfig | grep -qi 'CONFIG_GRKERNSEC_KMEM=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Disable privileged I/O:                 "
    if $kconfig | grep -qi 'CONFIG_GRKERNSEC_IO=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Harden module auto-loading:             "
    if $kconfig | grep -qi 'CONFIG_GRKERNSEC_MODHARDEN=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi

    printf "  Hide kernel symbols:                    "
    if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIDESYM=y'; then
      printf "gEnabled\n"
    else
      printf "gDisabled\n"
    fi
  else
    printf "gNo GRKERNSEC\n\n"
    printf "  The grsecurity / PaX patchset is available here:\n"
    printf "    http://grsecurity.net/\n"
  fi

  printf "\n"
  printf "* Kernel Heap Hardening: "

  if $kconfig | grep -qi 'CONFIG_KERNHEAP=y'; then
    if $kconfig | grep -qi 'CONFIG_KERNHEAP_FULLPOISON=y'; then
      printf "gFull KERNHEAP\n\n"
    else
      printf "gPartial KERNHEAP\n\n"
    fi
  else
    printf "gNo KERNHEAP\n\n"
    printf "  The KERNHEAP hardening patchset is available here:\n"
    printf "    https://www.subreption.com/kernheap/\n\n"
  fi
}

# --- FORTIFY_SOURCE subfunctions (start) ---

# is FORTIFY_SOURCE supported by libc?
FS_libc_check() {
  printf "* FORTIFY_SOURCE support available (libc)    : "

  if [ "${#FS_chk_func_libc[@]}" != "0" ] ; then
    printf "gYes\n"
  else
    printf "gNo\n"
    exit 1
  fi
}

# was the binary compiled with FORTIFY_SOURCE?
FS_binary_check() {
  printf "* Binary compiled with FORTIFY_SOURCE support: "

  for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1)))
  do
    if [[ ${FS_functions[$FS_elem_functions]} =~ _chk ]] ; then
      printf "gYes\n"
      return
    fi
  done
  printf "gNo\n"
  exit 1
}

FS_comparison() {
  echo
  printf " ------ EXECUTABLE-FILE ------- . -------- LIBC --------\n"
  printf " FORTIFY-able library functions | Checked function names\n"
  printf " -------------------------------------------------------\n"

  for FS_elem_libc in $(seq 0 $((${#FS_chk_func_libc[@]} - 1)))
  do
    for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1)))
    do
      FS_tmp_func=${FS_functions[$FS_elem_functions]}
      FS_tmp_libc=${FS_chk_func_libc[$FS_elem_libc]}

      if [[ $FS_tmp_func =~ ^$FS_tmp_libc$ ]] ; then
        printf " g%-30s | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end
        let FS_cnt_total++
        let FS_cnt_unchecked++
      elif [[ $FS_tmp_func =~ ^$FS_tmp_libc(_chk) ]] ; then
        printf " g%-30s | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end
        let FS_cnt_total++
        let FS_cnt_checked++
      fi

    done
  done
}

FS_summary() {
  echo
  printf "SUMMARY:\n\n"
  printf "* Number of checked functions in libc                : ${#FS_chk_func_libc[@]}\n"
  printf "* Total number of library functions in the executable: ${#FS_functions[@]}\n"
  printf "* Number of FORTIFY-able functions in the executable : %s\n" $FS_cnt_total
  printf "* Number of checked functions in the executable      : g%s\n" $FS_cnt_checked
  printf "* Number of unchecked functions in the executable    : g%s\n" $FS_cnt_unchecked
  echo
}

# --- FORTIFY_SOURCE subfunctions (end) ---

if !(command_exists readelf) ; then
  printf "gWarning: 'readelf' not found! It's required for most checks.\n\n"
  have_readelf=0
fi

# parse command-line arguments
case "$1" in

 --version)
  version
  exit 0
  ;;

 --help)
  help
  exit 0
  ;;

 --dir)
  if [ "$3" = "-v" ] ; then
    verbose=true
  fi
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid directory.\n\n"
    exit 1
  fi
  # remove trailing slashes
  tempdir=`echo $2 | sed -e "s/\/*$//"`
  if [ ! -d $tempdir ] ; then
    printf "gError: The directory '$tempdir' does not exist.\n\n"
    exit 1
  fi
  cd $tempdir
  printf "RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE\n"
  for N in [A-Za-z]*; do
    if [ "$N" != "[A-Za-z]*" ]; then
      # read permissions?
      if [ ! -r $N ]; then
        printf "gError: No read permissions for '$tempdir/$N' (run as root).\n"
      else
        # ELF executable?
        out=`file $N`
        if [[ ! $out =~ ELF ]] ; then
           if [ "$verbose" = "true" ] ; then
             printf "g*** Not an ELF file: $tempdir/"
             file $N
             printf ""
           fi
        else 
          filecheck $N
          if [ `find $tempdir/$N \( -perm -004000 -o -perm -002000 \) -type f -print` ]; then
            printf "%s%s" $2 $N
          else
            printf "%s%s" $tempdir/ $N
          fi
          echo
        fi
      fi
    fi
  done
  exit 0
  ;;
 
 --file)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid file.\n\n"
   exit 1
  fi
  # does the file exist?
  if [ ! -e $2 ] ; then
    printf "gError: The file '$2' does not exist.\n\n"
    exit 1
  fi
  # read permissions?
  if [ ! -r $2 ] ; then
    printf "gError: No read permissions for '$2' (run as root).\n\n"
    exit 1
  fi
  # ELF executable?
  out=`file $2`
  if [[ ! $out =~ ELF ]] ; then
    printf "gError: Not an ELF file: "
    file $2
    printf "\n"
    exit 1
  fi
  printf "RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE\n"
  filecheck $2
  if [ `find $2 \( -perm -004000 -o -perm -002000 \) -type f -print` ] ; then
    printf "%s%s" $2 $N
  else
    printf "%s" $2
  fi
  echo
  exit 0
  ;;

 --proc-all)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  cd /proc
  printf "* System-wide ASLR"
  aslrcheck
  printf "* Does the CPU support NX: "
  nxcheck 
  printf "         COMMAND    PID RELRO             STACK CANARY           NX/PaX        PIE\n"
  for N in [1-9]*; do
    if [ $N != $$ ] && readlink -q $N/exe > /dev/null; then
      printf "%16s" `head -1 $N/status | cut -b 7-`
      printf "%7d " $N
      proccheck $N
      echo
    fi
  done
  if [ ! -e /usr/bin/id ] ; then
    printf "\ngNote: If you are running 'checksec.sh' as an unprivileged user, you\n"
    printf "      will not see all processes. Please run the script as root.\n\n"
  else 
    if !(root_privs) ; then
      printf "\ngNote: You are running 'checksec.sh' as an unprivileged user.\n" 
      printf "      Too see all processes, please run the script as root.\n\n"
    fi
  fi
  exit 0
  ;;

 --proc)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid process name.\n\n"
    exit 1
  fi
  if !(isString "$2") ; then
     printf "gError: Please provide a valid process name.\n\n"
     exit 1
  fi
  cd /proc
  printf "* System-wide ASLR"
  aslrcheck
  printf "* Does the CPU support NX: "
  nxcheck
  printf "         COMMAND    PID RELRO             STACK CANARY           NX/PaX        PIE\n"
  for N in `ps -Ao pid,comm | grep $2 | cut -b1-6`; do
    if [ -d $N ] ; then
      printf "%16s" `head -1 $N/status | cut -b 7-`
      printf "%7d " $N
      # read permissions?
      if [ ! -r $N/exe ] ; then
        if !(root_privs) ; then
          printf "gNo read permissions for '/proc/$N/exe' (run as root).\n\n"
          exit 1
        fi
        if [ ! `readlink $N/exe` ] ; then
          printf "gPermission denied. Requested process ID belongs to a kernel thread.\n\n"
          exit 1
        fi
        exit 1
      fi
      proccheck $N
      echo
    fi
  done
  exit 0
  ;;

 --proc-libs)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid process ID.\n\n"
    exit 1
  fi
  if !(isNumeric "$2") ; then
     printf "gError: Please provide a valid process ID.\n\n"
     exit 1
  fi
  cd /proc
  printf "* System-wide ASLR"
  aslrcheck
  printf "* Does the CPU support NX: "
  nxcheck
  printf "* Process information:\n\n"
  printf "         COMMAND    PID RELRO             STACK CANARY           NX/PaX        PIE\n"
  N=$2
  if [ -d $N ] ; then
    printf "%16s" `head -1 $N/status | cut -b 7-`
    printf "%7d " $N
    # read permissions?
    if [ ! -r $N/exe ] ; then
      if !(root_privs) ; then
        printf "gNo read permissions for '/proc/$N/exe' (run as root).\n\n"
        exit 1
      fi
      if [ ! `readlink $N/exe` ] ; then
        printf "gPermission denied. Requested process ID belongs to a kernel thread.\n\n"
        exit 1
      fi
      exit 1
    fi
    proccheck $N
    echo
    libcheck $N
  fi
  exit 0
  ;;

 --kernel)
  cd /proc
  printf "* Kernel protection information:\n\n"
  kernelcheck
  exit 0
  ;;

 --fortify-file)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid file.\n\n"
   exit 1
  fi
  # does the file exist?
  if [ ! -e $2 ] ; then
    printf "gError: The file '$2' does not exist.\n\n"
    exit 1
  fi
  # read permissions?
  if [ ! -r $2 ] ; then
    printf "gError: No read permissions for '$2' (run as root).\n\n"
    exit 1
  fi
  # ELF executable?
  out=`file $2`
  if [[ ! $out =~ ELF ]] ; then
    printf "gError: Not an ELF file: "
    file $2
    printf "\n"
    exit 1
  fi
  if [ -e /lib/libc.so.6 ] ; then
    FS_libc=/lib/libc.so.6
  elif [ -e /lib64/libc.so.6 ] ; then
    FS_libc=/lib64/libc.so.6
  elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then
    FS_libc=/lib/i386-linux-gnu/libc.so.6
  elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then
    FS_libc=/lib/x86_64-linux-gnu/libc.so.6
  else
    printf "gError: libc not found.\n\n"
    exit 1
  fi

  FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') )
  FS_functions=( $(readelf -s $2 | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') )

  FS_libc_check
  FS_binary_check
  FS_comparison
  FS_summary

  exit 0
  ;;

 --fortify-proc)
  if [ $have_readelf -eq 0 ] ; then
    exit 1
  fi
  if [ -z "$2" ] ; then
    printf "gError: Please provide a valid process ID.\n\n"
    exit 1
  fi
  if !(isNumeric "$2") ; then
     printf "gError: Please provide a valid process ID.\n\n"
     exit 1
  fi
  cd /proc
  N=$2
  if [ -d $N ] ; then
    # read permissions?
    if [ ! -r $N/exe ] ; then
      if !(root_privs) ; then
        printf "gNo read permissions for '/proc/$N/exe' (run as root).\n\n"
        exit 1
      fi
      if [ ! `readlink $N/exe` ] ; then
        printf "gPermission denied. Requested process ID belongs to a kernel thread.\n\n"
        exit 1
      fi
      exit 1
    fi
    if [ -e /lib/libc.so.6 ] ; then
      FS_libc=/lib/libc.so.6
    elif [ -e /lib64/libc.so.6 ] ; then
      FS_libc=/lib64/libc.so.6
    elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then
      FS_libc=/lib/i386-linux-gnu/libc.so.6
    elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then
      FS_libc=/lib/x86_64-linux-gnu/libc.so.6
    else
      printf "gError: libc not found.\n\n"
      exit 1
    fi
    printf "* Process name (PID)                         : %s (%d)\n" `head -1 $N/status | cut -b 7-` $N
    FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') )
    FS_functions=( $(readelf -s $2/exe | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') )

    FS_libc_check
    FS_binary_check
    FS_comparison
    FS_summary
  fi
  exit 0
  ;;

 *)
  if [ "$#" != "0" ] ; then
    printf "gError: Unknown option '$1'.\n\n"
  fi
  help
  exit 1
  ;;
esac
