#!/usr/bin/bash if [ $(/usr/bin/id -u) != 0 ]; then echo "only root can do that"; exit 2; fi # use the check only under Fedora, it fails under Ubuntu if [ -L /etc/fedora-release ] then . /usr/lib/cryptobone/check fi ############################################################################## # This file is part of the CRYPTO BONE # File : cbcontrol # Version : 2.0 (ALL-IN-ONE) # License : BSD-3-Clause # Date : 24 May 2025 # Contact : Please send enquiries and bug-reports to innovation@senderek.ie # # Copyright (c) 2015-2025 # Ralf Senderek, Ireland. All rights reserved. (https://senderek.ie) # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Ralf Senderek. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. ############################################################################## # This script is the cornerstone of the Cryptobone software. It is run by the root user # to access the database of secrets via the UNIX-socket and perform certain tasks # that are requested by the GUI cryptobone2. # The GUI (running under the ordinary user UID) sends commands to this script # via the sudo mechanism and cbcontrol executes these special commands using either # the cryptobone daemon on the same machine (ALL-IN-ONE mode) or sends the commands # to an external device (the cryptoboneexternd daemon) via a dedicated ssh tunnel # (EXTERNAL mode). # # The Cryptobone software separates the user's GUI from the working of the "engine" # that takes care of encrypted message transport (via safewebdrop scripts) and decryption # of incoming webdrop messages and attachment files using and updating AES keys that are # provided by the cryptobone daemon and stored in the database by the daemon. # All cleartext files (messages and attachments) reside inside a ramdisk that can be # used by the root user only. The GUI needs to send the appropriate commands via sudo # to this script to have the task completed with access to the ramdisk that is inaccessible # to everyone except root. # # There are certain commands that are executed by cbcontrol directly (such as switching from # ALL-IN-ONE mode to EXTERNAL mode and back, that need no secrets to be used. # Other commands (like sending messages and attachments) need the current AES secret key for the # intended recipient and either get these secrets via the UNIX-socket from the daemon, # that has the secrets in memory or transfer decrypted information from the ramdisk into the GUI. # A special case are attachment files (ie a PDF) that need to be read by helper programs under # the user's UID. That means the GUI may request a copy of the attachment file being stored # in the user's home directory to be of any use. In case of sending or receiving attachments # with an external device, an upload or download of the file must be performed via the ssh tunnel # by this script. # # A special command is COPY_EXTERNAL_SECRETS which is used for a special purpose when the # external device is used to host the database of secrets (and does all the other heavy lifting) # in EXTERNAL mode. # Because some secrets which have been generated by the external device must be transferred into the # local client machine's database (the external master key and the ssh private key for instance), # this scripts copies those secrets into its own database first and on the next boot, the script # that starts the cryptobone daemon puts these secrets into the boot.fs, so that the external # master key can be uploaded to the external device during the boot process. . /usr/lib/cryptobone/cbcontrol.functions #-------------------------------------------------------------# if [ ! -d /dev/shm/RAM ] then /usr/lib/cryptobone/rc.local fi date +%s > /dev/shm/RAM/GUI 2> /dev/null if [ x$1 = "xUSEALLINONE" ] then ln -s /usr/lib/cryptobone/version /usr/lib/cryptobone/ALLINONE /usr/bin/cp /usr/lib/cryptobone/allinone.header /usr/lib/cryptobone/safewebdrop.header ###exit 0 fi if [ x$1 = "xUSECRYPTOBONE" ] then /bin/rm -f /usr/lib/cryptobone/ALLINONE /usr/bin/cp /usr/lib/cryptobone/extern.header /usr/lib/cryptobone/safewebdrop.header ###exit 0 fi if [ x$1 = "xBONEIP" ] then if [ x$2 != "x" ] ; then echo "BONEIP=$2" > /usr/lib/cryptobone/cbb.config exit 0 fi fi if [ x$1 = "xGETALLINONE" ] then if [ -L /usr/lib/cryptobone/ALLINONE ] then # ALLINONE mode echo -n "ALLINONE " if [ -f /usr/lib/cryptobone/database ]; then echo -n "active" else echo -n "nodatabase" fi else # EXTERNAL DEVICE mode echo -n "EXTERNAL " # did we copy the external secrets already? SSHKEY=$(echo "get-element EXTERN.cbb" | socat - UNIX-connect:/usr/lib/cryptobone/secrets.sock 2> /dev/null) if [ x$SSHKEY = "x" ]; then echo -n "unfinished" exit 0 fi # do we have a IP address? if [ -f /usr/lib/cryptobone/cbb.config ] then . /usr/lib/cryptobone/cbb.config # ist the external device responding to ping? if ! ping -c1 -w1 ${BONEIP} 2>/dev/null >/dev/null; then echo -n "offline : " else # External device is reachable # is the external device already active ? if [ -f /usr/lib/cryptobone/UPLOADED ] ; then echo -n "active : " else echo -n "waiting : " fi fi echo -n ${BONEIP} else echo -n "0.0.0.0" fi SSHKEY=$(echo "get-element EXTERN.cbb" | socat - UNIX-connect:/usr/lib/cryptobone/secrets.sock 2> /dev/null) if [ x$SSHKEY = "x" ]; then echo -n "unfinished" fi fi exit 0 fi if [ x$1 = "xDELETE" ]; then if [ x$2 = "xCONFIG" ]; then /bin/rm /usr/lib/cryptobone/cbb.config echo -n "success" exit 0 fi fi if [ x$1 = "xCOPY_EXTERNAL_SECRETS" ] then if [ x$2 != "x" ] then DIR=$2 if [ -f $DIR/master.key ] then # there are keys on the SD card echo -n "replace EXTERN.OVERWRITE yes" | socat -t15 - UNIX-connect:$SOCK 2> /dev/null /bin/cp $DIR/local.key /usr/lib/cryptobone/keys/EXTERN.local.key 2>/dev/null /bin/chown root /usr/lib/cryptobone/keys/EXTERN.local.key 2>/dev/null /bin/chmod 600 /usr/lib/cryptobone/keys/EXTERN.local.key 2>/dev/null if [ -f /usr/lib/cryptobone/keys/EXTERN.local.key ]; then /usr/bin/sha256sum /usr/lib/cryptobone/keys/EXTERN.local.key | /usr/bin/cut -c-64 > /usr/lib/cryptobone/keys/EXTERN.local.key.sha256 /bin/chmod 600 /usr/lib/cryptobone/keys/EXTERN.local.key.sha256 else echo -n "failed" exit 2 fi # write 2 secrets directly to database LINE=$(/bin/cat $DIR/master.key | cut -c-40) echo -n "replace EXTERN.real.key $LINE" | socat -t15 - UNIX-connect:$SOCK 2> /dev/null RES=$(echo "get-element EXTERN.real.key" | socat -t15 - UNIX-connect:$SOCK 2> /dev/null) if [ x$RES != "x$LINE" ] then echo -n "failed" exit 2 fi # base64 encode cbb after it is decrypted to form one line /usr/bin/ssh-keygen -p -P $(/bin/cat $DIR/local.key) -N "" -f $DIR/cbb 2> /dev/null > /dev/null LINE=$(/bin/cat $DIR/cbb | base64 | tr -d "\n" ) echo "replace EXTERN.cbb $LINE" | socat -t15 - UNIX-connect:$SOCK 2> /dev/null RES=$(echo "get-element EXTERN.cbb" | socat -t15 - UNIX-connect:$SOCK 2> /dev/null) if [ x$RES != "x$LINE" ] then echo -n "failed" exit 2 fi # reaching this point, all secrets have been transferred correctly. echo -n "success" exit 0 fi fi echo -n "nokeys" exit 1 fi if [ -L /usr/lib/cryptobone/ALLINONE ] then # process all commands for the ALLINONE mode if [ "x$1" = "xEXIT" ] then echo "Bye for now." exit 0 fi # check if querying local.key works, compare with sha256 hashvalue # exit "failed", if local.key cannot be accessed (directly or via a second device) if [ ! -f /usr/lib/cryptobone/keys/local.key.sha256 ] then /usr/lib/cryptobone/rc.local fi TESTHASH=$(/bin/cat /usr/lib/cryptobone/keys/local.key.sha256 2>/dev/null | cut -c-64) HASH=$(/usr/lib/cryptobone/getlocalsecret | sha256sum | cut -c-64) if [ x$HASH != x$TESTHASH ] then echo "failed: local authentication" exit 1 fi if [ $# -ge 1 ] then case $1 in ATTACHMENT) case $2 in LIST) attachmentlist ;; COPY) copy_attachment "$3" ;; DELETE) delete_attachment "$3" ;; esac ;; EXTERNAL) case $2 in STATUS) check_external ;; esac ;; FETCH) /usr/lib/cryptobone/systemd.fetch ;; KEY) case $2 in CONTACT) contact_registered "$3" ;; NEWSECRETS) get_new_secrets ;; RECIPIENTLIST) recipient_list ;; #RESET) reset_key_for_email "$3" # ;; USE) register_new_key "$3" "$4" ;; *) echo "unknown KEY command" ;; esac ;; MESSAGE) case $2 in COPY) copy_message "$3" ;; esac ;; #NETWORK) case $2 in # only for external device # STATUS) case $3 in # CONNECT) /usr/bin/sudo /sbin/ifconfig 2>&1 # ;; # FIREWALL) /usr/bin/sudo /usr/lib/cryptobone/firewall status # ;; # PING) /bin/ping -c1 -w1 $(cat /usr/lib/cryptobone/pinghost) # ;; # esac # esac # ;; ###POWEROFF) echo "going down" ### /usr/lib/cryptobone/bin/cbb-poweroff 2>/dev/null ### ;; READ) case $2 in DESTROY) destroy_message $3 ;; MESSAGELIST) get_message_list ;; WEBDROPLIST) get_webdrop_list ;; MESSAGE) read_message $3 ;; WEBDROP) read_webdrop $3 ;; esac ;; RESET) echo "reset the masterkey" ;; SETUP) case $2 in WID) get_wid ;; WEBDROP) show_safewebdrop_setup ;; WEBDROPSECRET) setup_safewebdropsecret "$3" ;; WEBDROPSERVER) setup_safewebdropserver "$3" ;; WEBDROPUSER) setup_safewebdropuser "$3" ;; CLEARREG) setup_clear_safewebdrop_registration ;; REGISTER) setup_register_safewebdrop ;; REGISTRATION) setup_get_safewebdrop_registration ;; esac ;; SHOW) echo "forbidden"; ;; STATUS) if echo "get-element cryptobone" | socat -t15 - UNIX-connect:$SOCK > /dev/null then echo "active" else echo "waiting" fi ;; SYSTEM) case $2 in SUSPEND) cryptobonesuspend ;; RESUME) cryptoboneresume ;; POWEROFF) clear_RAM ;; RESTART) /usr/lib/cryptobone/rc.local ;; esac ;; WEBDROP) safewebdrop_message "$2" "$3" "$4" ;; *) echo "failed" ;; esac exit 0 fi echo "failed" exit 1 else # real Crypto Bone # send all commands via ssh tunnel to $BONEIP using cryptobone's ssh key export SSH_AUTH_SOCK=/usr/lib/cryptobone/ssh.sock if [ -f /usr/lib/cryptobone/cbb.config ] then /bin/chmod 600 /usr/lib/cryptobone/cbb.config . /usr/lib/cryptobone/cbb.config 2> /dev/null else BONEIP="none" echo "BONEIP MISSING" exit 0 fi # check if external device is active or not if [ ! -f /usr/lib/cryptobone/UPLOADED ]; then # ist the external device responding to ping? if ping -c1 -w1 ${BONEIP} 2>/dev/null >/dev/null; then echo "master key not uploaded" else echo "offline" exit 0 fi RES=$(echo $(/usr/lib/cryptobone/getlocalsecret) STATUS | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol) if [[ $RES = "active" ]] ; then touch /usr/lib/cryptobone/UPLOADED fi if [[ $RES = "waiting" ]] ; then # the external database cannot be accessed echo "master key not available" /usr/bin/rm -f /usr/lib/cryptobone/UPLOADED 2>/dev/null exit 0 fi fi if [ -f /usr/lib/cryptobone/UPLOADED ]; then # external device is active # if sending attachments with an external crypto bone, then upload the attachment before the # WEBDROP command safewebdrop_message "$2" "$3" "$4" is handed over to the external device if [ $1 = "WEBDROP" ] ; then if [ $4 != "none" ]; then echo $(/usr/lib/cryptobone/getlocalsecret) ATTACH $(/usr/bin/cat $4 | base64 --wrap 0) | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol fi fi # if downloading messages from the external crypto bone, exit after writing the result to the user's homedir. if [ $1 = "MESSAGE" ] ; then if [ $2 == "COPY" ]; then # find the user's home directory USER=$(cat /etc/sudoers.d/cbcontrol | tail -1 | cut -f1 -d " ") if [ ! -d /home/${USER}/.safewebdrop ] ; then /usr/bin/mkdir /home/${USER}/.safewebdrop 2> /dev/null chmod 700 /home/${USER}/.safewebdrop chown ${USER} /home/${USER}/.safewebdrop fi # TODO check if $3 exists. Change name or overwrite $3.b64 TEMP=/home/${USER}/.safewebdrop/$3.b64 DEST=/home/${USER}/.safewebdrop/$3 echo $(/usr/lib/cryptobone/getlocalsecret) MESSAGE COPY $3 | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol > ${TEMP} if [ $? -eq 0 ] ; then /usr/bin/base64 -d ${TEMP} > ${DEST} if [ $? -eq 0 ] ; then /usr/bin/rm -f ${TEMP} echo "message $1 SAVED" fi fi chown ${USER} /home/${USER}/.safewebdrop/* chmod 600 /home/${USER}/.safewebdrop/* exit 0 fi fi # if downloading attachments from the external crypto bone, exit after writing the result to the user's homedir. if [ $1 = "ATTACHMENT" ] ; then if [ $2 == "COPY" ]; then # find the user's home directory USER=$(cat /etc/sudoers.d/cbcontrol | tail -1 | cut -f1 -d " ") if [ ! -d /home/${USER}/.safewebdrop ] ; then /usr/bin/mkdir /home/${USER}/.safewebdrop 2> /dev/null chmod 700 /home/${USER}/.safewebdrop chown ${USER} /home/${USER}/.safewebdrop fi TEMP=/home/${USER}/.safewebdrop/$3.b64 DEST=/home/${USER}/.safewebdrop/$3 echo $(/usr/lib/cryptobone/getlocalsecret) ATTACHMENT COPY $3 | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol > ${TEMP} if [ $? -eq 0 ] ; then /usr/bin/base64 -d ${TEMP} > ${DEST} if [ $? -eq 0 ] ; then /usr/bin/rm -f ${TEMP} echo "$1 SAVED" fi fi chown ${USER} /home/${USER}/.safewebdrop/* chmod 600 /home/${USER}/.safewebdrop/* exit 0 fi fi # send the commands directly to the EXTERNAL Crypto Bone echo $(/usr/lib/cryptobone/getlocalsecret) $1 $2 $3 $4 | /usr/bin/ssh -l cryptobone ${BONEIP} /cbb/cbcontrol if [ $1 = "POWEROFF" ] then # shutdown of an active system has finished, record shutdown here. /bin/rm /usr/lib/cryptobone/UPLOADED 2> /dev/null fi else # external device is not yet active or unreachable if [ $BONEIP != "none" ] then # we have cbb.config, the external crypto bone may be reachable if ping -c1 -w1 ${BONEIP} 2>/dev/null >/dev/null then echo "master key not available" else echo "offline" fi exit 0 else # we don't have any configuration yet # external crypto bone is not reachable echo "no IP address" exit 0 fi fi fi #########################################################