#!/bin/bash

if [ $(/usr/bin/id -u) != 0 ]; then echo "only root can do that"; exit 2; fi

#
# Copyright 2015-2016 Senderek Web Security, Ireland. All rights reserved.
#                <https://senderek.ie>
#
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

#
# Author:       Ralf Senderek <innovation@senderek.ie>
#
# license:      GNU General Public License version 3 or higher
# description:  Activates the cryptobone daemon during the boot process 
# processname:  cryptoboned 
# config:       none
# date:         22 July 2016
#

### BEGIN INIT INFO
# Provides:          cryptoboned
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Activates the cryptobone daemon during the boot process
### END INIT INFO

# chkconfig:         2345  90 60

if [ -f /lib/lsb/init-functions ]
then
    . /lib/lsb/init-functions
fi 
KEYS="/usr/lib/cryptobone/keys"
REAL="none"
SOCK="/usr/lib/cryptobone/secrets.sock"

##########################################################################

start() {

     if ! df | grep /usr/lib/cryptobone/keys 2> /dev/null > /dev/null
     then
           # we're booting 
           
	   # load the SELinux policy for the daemon
           semodule -i /usr/lib/cryptobone/selinux/cryptobone.pp
           semodule -e cryptobone

           SWITCH=/usr/lib/cryptobone/bootswitch
           if [ ! -f $SWITCH ] 
           then
               touch $SWITCH
           fi
           chattr -i $SWITCH
           chmod 600 $SWITCH
	   chmod 700 $KEYS
          
	   if [ ! -L /usr/lib/cryptobone/masterkey ]
	   then
                # initialize database and create a master key and local key
		/usr/lib/cryptobone/createmasterkey
		# now there is $KEYS/random and both file systems (boot.fs and permanent.fs)
	   fi
	   /bin/rm /usr/lib/cryptobone/UPLOADED 2> /dev/null
	   # record evidence that we're really booting
           typeset -i BOOTTIME=$(cat /proc/stat | grep btime | cut -f2 -d" ")
           typeset -i NOW=$(date +%s)
	   typeset -i DIFF=$NOW-$BOOTTIME
	   echo $DIFF > $SWITCH
           DIR=$(echo -n $(cat $KEYS/random) $(stat -c "directory %i" $KEYS) | sha256sum | cut -c-64)
	   FILE=$(echo -n $DIR $(stat -c "file %i"  $KEYS/random) | sha256sum | cut -c-64)

           # establish the boot file system
	   L=$(losetup -f)
	   losetup $L $KEYS/boot.fs
           cat $KEYS/$DIR/$FILE | cryptsetup create cryptobone $L
	   if mount /dev/mapper/cryptobone $KEYS
	   then
	        # start the daemon
		rm -f /usr/lib/cryptobone/ssh.sock
	        /usr/lib/cryptobone/cryptoboned 
	        ssh-agent -s -a /usr/lib/cryptobone/ssh.sock
		export SSH_AUTH_SOCK=/usr/lib/cryptobone/ssh.sock 2>/dev/null > /dev/null


                OVERWRITE=$(echo "get-element EXTERN.OVERWRITE"  | socat - UNIX-connect:$SOCK 2> /dev/null)
                if [ x$OVERWRITE = "xyes" ]
		then
                     rm -f $KEYS/real.key $KEYS/cbb
		fi

		if  [ ! -r $KEYS/real.key ]
		then
                     # check if external keys are stored in the encrypted database
                     REALKEY=$(echo "get-element EXTERN.real.key"  | socat - UNIX-connect:$SOCK 2> /dev/null)
                     if [ x$REALKEY != "x" ]
		     then
                          echo $REALKEY > $KEYS/real.key
			  chmod 600 $KEYS/real.key
	                  REALKEY="000000000000000000000000000000000000000000"
	                  unset REALKEY
		     fi
                fi

		if  [ ! -r $KEYS/cbb ]
                then
                     SSHKEY=$(echo "get-element EXTERN.cbb"  | socat - UNIX-connect:$SOCK 2> /dev/null)
                     if [ x$SSHKEY != "x" ]
		     then
                          echo "$SSHKEY" | base64 -d  > $KEYS/cbb
			  chmod 600 $KEYS/cbb
	                  SSHKEY=$(/bin/dd if=/dev/zero bs=1K count=4 2>/dev/null)
	                  unset SSHKEY
		     fi
		fi
		
                echo -n "replace EXTERN.OVERWRITE no"  | socat - UNIX-connect:$SOCK 2> /dev/null
		
		if [ -f $KEYS/cbb ]
		then
		     ssh-add $KEYS/cbb
		     REAL=$(cat /usr/lib/cryptobone/keys/real.key) 2> /dev/null
		fi
	   fi    
           
           # remove the boot file system
	   umount /dev/mapper/cryptobone
	   cryptsetup remove cryptobone
	   losetup -d $L
    
           # mount the permanent file system
	   L=$(losetup -f)
	   losetup $L $KEYS/permanent.fs
           mount $L $KEYS
	   chmod 700 $KEYS

           echo 9999 > $SWITCH
           chattr +i $SWITCH

    	   if [ ! -L /usr/lib/cryptobone/ALLINONE ]
	   then
	        # we're using a real Crypto Bone
	        if [ -f /usr/lib/cryptobone/cbb.config ]
	        then
	             chmod 600 /usr/lib/cryptobone/cbb.config
	             . /usr/lib/cryptobone/cbb.config
                     # wait for BONEIP to come up
		     typeset -i count=0
		     while [ $count -lt 20 ]
                     do
		         /bin/sleep 2
			 count=$count+1
                         /bin/ping -w1 -c1 ${BONEIP} 2>/dev/null > /dev/null
			 if [ $? -eq 0 ]
			 then
                             count=21
			 fi
                     done

                     /bin/ping -w1 -c1 ${BONEIP} 2>/dev/null > /dev/null
		     if [ $? -eq 0 ]
	             then
                          # upload the master key to the real crypto bone
		          echo $(/usr/lib/cryptobone/getlocalsecret) SYSTEM UPLOAD $(echo $REAL) | /usr/bin/ssh -l cryptobone  ${BONEIP} /cbb/cbcontrol
	                  REAL="000000000000000000000000000000000000000000"
	                  unset REAL

		          count=0
		          while [ $count -lt 3 ]
                          do
		               /bin/sleep 2
			       count=$count+1
                               /bin/ping -w1 -c1 ${BONEIP} 2>/dev/null > /dev/null
	                  
			       RES=$(echo $(/usr/lib/cryptobone/getlocalsecret) STATUS | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol)
  	                       if [ "${RES}x" = "activex" ]
	                       then 
		                    touch /usr/lib/cryptobone/UPLOADED
				    count=11
	                       fi
			  done     
	             fi
	        fi
     	   fi
	   REAL="000000000000000000000000000000000000000000"
	   unset REAL
     fi
}


##########################################################################
stop() {
     if [ -d /dev/shm/RAM ]
     then
         /usr/lib/cryptobone/bin/savemessages
     fi
     killall cryptoboned
}


##########################################################################
case "$1" in
  start)
	start
	;;
  stop) 
	stop
	;;
  restart)
        echo "deliberately not implemented"
	;;
  status)
        echo "deliberately not implemented"
	;;
  force-reload)
        echo "deliberately not implemented"
        ;;
  *)
	echo "Usage: /usr/lib/cryptobone/init.d/cryptoboned {start|stop}"
	exit 1
esac

exit 0
