#!/bin/bash # # .---. . . # | | | # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-' # ' ' --' --' -' - -' ' ' -' -' -' ' - --' # # Freedom in the Cloud # # Administrator control panel for the Freedombone system # # License # ======= # # Copyright (C) 2015 Bob Mottram # # 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 . COMPLETION_FILE=$HOME/freedombone-completed.txt SELECTED_USERNAME= SIP_CONFIG_FILE=/etc/sipwitch.conf ADMIN_USER= UPGRADE_SCRIPT_NAME="freedombone-upgrade" function any_key { echo ' ' read -n1 -r -p "Press any key to continue..." key } function check_for_updates { if [ ! -f /etc/cron.weekly/$UPGRADE_SCRIPT_NAME ]; then dialog --title "Check for updates" \ --msgbox "Upgrade script was not found" 6 40 return fi clear ./etc/cron.weekly/$UPGRADE_SCRIPT_NAME any_key } function add_user { data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Add new user" \ --form "\n" 8 40 3 \ "Username:" 1 1 "" 1 11 16 15 \ "ssh public key (optional):" 2 1 "" 3 1 40 10000 \ 2> $data sel=$? case $sel in 1) return;; 255) return;; esac new_user_username=$(cat $data | sed -n 1p) new_user_ssh_public_key=$(cat $data | sed -n 2p) if [ ${#new_user_username} -lt 2 ]; then dialog --title "New username" \ --msgbox "No username was given" 6 40 return fi if [[ "$new_user_username" == *" "* ]]; then dialog --title "Invalid username" \ --msgbox "The username should not contain any spaces" 6 40 return fi if [ ${#new_user_ssh_public_key} -lt 20 ]; then clear freedombone-adduser "$new_user_username" any_key else if [[ "$new_user_ssh_public_key" == "ssh-"* ]]; then clear freedombone-adduser "$new_user_username" "$new_user_ssh_public_key" any_key else dialog --title "ssh public key" \ --msgbox "This does not look like an ssh public key" 6 40 fi fi } function show_sip_extensions { if [ ! -f $SIP_CONFIG_FILE ]; then return; fi clear echo "SIP phone extensions:" echo " " while read ext; do if [[ $ext == *"user id"* ]]; then echo -n " " echo -n $(echo "$ext" | awk -F '"' '{print $2}' | awk -F '"' '{print $1}') echo -n " " fi if [[ $ext == *"extension"* ]]; then echo $(echo "$ext" | awk -F '>' '{print $2}' | awk -F '<' '{print $1}') fi done < $SIP_CONFIG_FILE any_key } function select_user { SELECTED_USERNAME= data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title "Select a user" \ --backtitle "Freedombone Control Panel" \ --dselect "/home/" 14 40 2> $data sel=$? case $sel in 0) SELECTED_USERNAME=$(cat $data | awk -F '/' '{print $3}');; 1) return;; 255) return;; esac if [ ${#SELECTED_USERNAME} -lt 2 ]; then SELECTED_USERNAME= fi if [ ! -d /home/$SELECTED_USERNAME/Maildir ]; then dialog --title "User directory check" \ --msgbox "This does not look like a user directory" 6 40 SELECTED_USERNAME= fi } function delete_user { select_user if [ ! $SELECTED_USERNAME ]; then return fi if grep -Fxq "Admin user:$SELECTED_USERNAME" $COMPLETION_FILE; then dialog --title "Administrator user" \ --msgbox "You can't delete the administrator user" 6 40 return fi clear freedombone-rmuser $SELECTED_USERNAME any_key } function configure_remote_backups { if ! grep -Fxq "Admin user:$SELECTED_USERNAME" $COMPLETION_FILE; then dialog --title "Administrator user" \ --msgbox "No Administrator user found. Check $COMPLETION_FILE" 6 40 return fi if [ ${#ADMIN} -lt 2 ]; then dialog --title "Administrator user" \ --msgbox "Username not found" 6 40 return fi if [ ! -d /home/$ADMIN_USER ]; then dialog --title "Administrator user" \ --msgbox "Home directory not found" 6 40 return fi freedombone-remote -u $ADMIN_USER } function change_password { select_user if [ ! $SELECTED_USERNAME ]; then return fi clear echo "Change password for $SELECTED_USERNAME" echo "" su -c "passwd" - $SELECTED_USERNAME any_key } function change_ssh_public_key { select_user if [ ! $SELECTED_USERNAME ]; then return fi if grep -Fxq "Admin user:$SELECTED_USERNAME" $COMPLETION_FILE; then dialog --title "Change ssh public key" \ --backtitle "Freedombone Control Panel" \ --defaultno \ --yesno "\nThis is the administrator user.\n\nAre you sure you want to change the ssh public key for the administrator?" 10 60 sel=$? case $sel in 1) return;; 255) return;; esac fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title "Change ssh public key for $SELECTED_USERNAME" \ --backtitle "Freedombone Control Panel" \ --inputbox "Paste the ssh public key below" 8 60 2>$data sel=$? case $sel in 0) SSH_PUBLIC_KEY=$(<$data) if [ "$SSH_PUBLIC_KEY" ]; then if [ ${#SSH_PUBLIC_KEY} -gt 5 ]; then if [ -f "$SSH_PUBLIC_KEY" ]; then if [ ! -d /home/$SELECTED_USERNAME/.ssh ]; then mkdir /home/$SELECTED_USERNAME/.ssh fi cp $SSH_PUBLIC_KEY \ /home/$SELECTED_USERNAME/.ssh/authorized_keys chown -R $SELECTED_USERNAME:$SELECTED_USERNAME \ /home/$SELECTED_USERNAME/.ssh dialog --title "Change ssh public key" \ --msgbox "ssh public key was installed" 6 40 else if [[ "$SSH_PUBLIC_KEY" == "ssh-"* ]]; then if [ ! -d /home/$SELECTED_USERNAME/.ssh ]; then mkdir /home/$SELECTED_USERNAME/.ssh fi echo "$SSH_PUBLIC_KEY" > \ /home/$SELECTED_USERNAME/.ssh/authorized_keys chown -R $SELECTED_USERNAME:$SELECTED_USERNAME \ /home/$SELECTED_USERNAME/.ssh dialog --title "Change ssh public key" \ --msgbox "ssh public key was installed" 6 40 fi fi fi fi ;; esac } function add_to_mailing_list { select_user if [ ! $SELECTED_USERNAME ]; then return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Subscribe $SELECTED_USERNAME to a mailing list" \ --form "\n" 8 68 4 \ "List folder name:" 1 1 "" 1 35 26 25 \ "Name between [] on subject line:" 2 1 "" 2 35 26 25 \ "List email address:" 3 1 "" 3 35 26 25 \ 2> $data sel=$? case $sel in 1) return;; 255) return;; esac LIST_NAME=$(cat $data | sed -n 1p) LIST_SUBJECT=$(cat $data | sed -n 2p) LIST_EMAIL=$(cat $data | sed -n 3p) if [ ${#LIST_NAME} -lt 2 ]; then dialog --title "Add mailing list" \ --msgbox "No mailing list name was given" 6 40 return fi if [ ${#LIST_SUBJECT} -lt 2 ]; then dialog --title "Add mailing list" \ --msgbox "No mailing list subject was given" 6 40 return fi if [ ${#LIST_EMAIL} -lt 2 ]; then dialog --title "Add mailing list" \ --msgbox "No mailing list email address was given" 6 40 return fi if [[ "$LIST_EMAIL" != *"@"* || "$LIST_EMAIL" != *"."* ]]; then dialog --title "Add mailing list" \ --msgbox "Unrecognised email address" 6 40 return fi freedombone-addlist -u $SELECTED_USERNAME -l "$LIST_NAME" \ -s "$LIST_SUBJECT" -e "$LIST_EMAIL" dialog --title "Add mailing list" \ --msgbox "$LIST_NAME list was added" 6 40 } function email_rule { select_user if [ ! $SELECTED_USERNAME ]; then return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Email rule for user $SELECTED_USERNAME" \ --form "\n" 8 65 3 \ "When email arrives from address:" 1 1 "" 1 35 24 28 \ "Move to folder:" 2 1 "" 2 35 24 28 \ 2> $data sel=$? case $sel in 1) return;; 255) return;; esac RULE_EMAIL=$(cat $data | sed -n 1p) RULE_FOLDER=$(cat $data | sed -n 2p) if [ ${#RULE_EMAIL} -lt 2 ]; then dialog --title "Add email rule" \ --msgbox "No email address was given" 6 40 return fi if [ ${#RULE_FOLDER} -lt 2 ]; then dialog --title "Add email rule" \ --msgbox "No folder name was given" 6 40 return fi if [[ "$RULE_EMAIL" != *"@"* || "$RULE_EMAIL" != *"."* ]]; then dialog --title "Add email rule" \ --msgbox "Unrecognised email address" 6 40 return fi freedombone-addemail -u $SELECTED_USERNAME -e "$RULE_EMAIL" \ -g "$RULE_FOLDER" dialog --title "Add email rule" \ --msgbox "Email rule for $RULE_EMAIL was added" 6 40 } function block_unblock_email { select_user if [ ! $SELECTED_USERNAME ]; then return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Block/Unblock email going to $SELECTED_USERNAME" \ --form "\n" 8 65 3 \ "When email arrives from address:" 1 1 "" 1 35 24 28 \ "Block it:" 2 1 "yes" 2 35 4 4 \ 2> $data sel=$? case $sel in 1) return;; 255) return;; esac BLOCK_EMAIL=$(cat $data | sed -n 1p) BLOCK=$(cat $data | sed -n 2p) if [ ${#BLOCK_EMAIL} -lt 2 ]; then dialog --title "Block/Unblock an email" \ --msgbox "No email address was given" 6 40 return fi if [[ "$BLOCK_EMAIL" != *"@"* || "$BLOCK_EMAIL" != *"."* ]]; then dialog --title "Block/Unblock an email" \ --msgbox "Unrecognised email address" 6 40 return fi if [[ $BLOCK == "y"* || $BLOCK == "Y"* ]]; then freedombone-ignore -u $SELECTED_USERNAME -e "$BLOCK_EMAIL" dialog --title "Block an email" \ --msgbox "Email from $BLOCK_EMAIL to $SELECTED_USERNAME blocked" 6 40 else freedombone-unignore -u $SELECTED_USERNAME -e "$BLOCK_EMAIL" dialog --title "Unblock an email" \ --msgbox "Email from $BLOCK_EMAIL to $SELECTED_USERNAME unblocked" 6 40 fi } function block_unblock_subject { select_user if [ ! $SELECTED_USERNAME ]; then return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Block/Unblock email going to $SELECTED_USERNAME" \ --form "\n" 8 70 3 \ "When email arrives with subject text:" 1 1 "" 1 40 24 28 \ "Block it:" 2 1 "yes" 2 40 4 4 \ 2> $data sel=$? case $sel in 1) return;; 255) return;; esac BLOCK_SUBJECT=$(cat $data | sed -n 1p) BLOCK=$(cat $data | sed -n 2p) if [ ${#BLOCK_SUBJECT} -lt 2 ]; then dialog --title "Block/Unblock an email" \ --msgbox "No subject was given" 6 40 return fi if [[ $BLOCK == "y"* || $BLOCK == "Y"* ]]; then freedombone-ignore -u $SELECTED_USERNAME -t "$BLOCK_SUBJECT" dialog --title "Block an email" \ --msgbox "Email with subject $BLOCK_SUBJECT to $SELECTED_USERNAME blocked" 6 40 else freedombone-unignore -u $SELECTED_USERNAME -t "$BLOCK_SUBJECT" dialog --title "Unblock an email" \ --msgbox "Email with subject $BLOCK_SUBJECT to $SELECTED_USERNAME unblocked" 6 40 fi } function create_keydrive_master { select_user if [ ! $SELECTED_USERNAME ]; then return fi dialog --title "USB Master Keydrive" \ --msgbox "Plug in a LUKS encrypted USB drive" 6 40 clear freedombone-keydrive -u $SELECTED_USERNAME --master 'yes' any_key } function create_keydrive_fragment { select_user if [ ! $SELECTED_USERNAME ]; then return fi dialog --title "USB Fragment Keydrive" \ --msgbox "Plug in a LUKS encrypted USB drive" 6 40 clear freedombone-keydrive -u $SELECTED_USERNAME any_key } function backup_data { dialog --title "Backup data to USB" \ --msgbox "Plug in a LUKS encrypted USB drive" 6 40 clear echo ' ' echo 'Enter the passphrase for your LUKS encrypted backup drive:' backup any_key } function restore_data { dialog --title "Restore data from USB" \ --msgbox "Plug in your backup USB drive" 6 40 clear echo ' ' echo 'Enter the passphrase for your LUKS encrypted backup drive:' restore any_key } function restore_data_remote { if [ ! $ADMIN_USER ]; then dialog --title "Restore data from remote server" \ --msgbox "Unknown admin user" 6 40 return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title "Restore from remote server" \ --backtitle "Freedombone Control Panel" \ --inputbox "Enter the domain name of the server from which you wish to restore" 8 60 2>$data sel=$? case $sel in 0) friend_server_domain_name=$(<$data) if [ ${#friend_server_domain_name} -lt 2 ]; then return fi if [[ $friend_server_domain_name != *"."* ]]; then dialog --title "Remote server domain name" \ --msgbox "Invalid domain name" 6 40 return fi restorefromfriend $friend_server_domain_name any_key ;; esac } function logging_on_off { logging="no" dialog --title "Logging" \ --backtitle "Freedombone Control Panel" \ --yesno "\nDo you want to turn logging on?" 7 60 sel=$? case $sel in 0) logging="yes";; 255) return;; esac clear echo '' echo 'This may take a few seconds. Please wait...' if [[ $logging == "no" ]]; then freedombone-logging off else freedombone-logging on fi } function restore_gpg_key { select_user if [ ! $SELECTED_USERNAME ]; then return fi dialog --title "Restore GPG key for user $SELECTED_USERNAME" \ --msgbox "Plug in your USB keydrive" 6 40 clear freedombone-recoverkey -u $SELECTED_USERNAME any_key } function security_settings { freedombone-sec any_key } function reset_tripwire { clear echo 'Resetting the Tripwire...' echo ' ' echo ' ' | reset-tripwire any_key } function hubzilla_renew_cert { dialog --title "Renew SSL certificate" \ --backtitle "Freedombone Control Panel" \ --yesno "\nThis will renew a letsencrypt certificate. Select 'yes' to continue" 16 60 sel=$? case $sel in 1) return;; 255) return;; esac HUBZILLA_DOMAIN_NAME=$(cat $COMPLETION_FILE | grep "Hubzilla domain" | awk -F ':' '{print $2}') if [ ! -d /var/www/$HUBZILLA_DOMAIN_NAME/htdocs ]; then dialog --title "Renew SSL certificate" \ --msgbox "Hubzilla install directory not found" 6 40 return fi freedombone-renew-cert -h $HUBZILLA_DOMAIN_NAME -p 'letsencrypt' if [ ! "$?" = "0" ]; then any_key else dialog --title "Renew SSL certificate" \ --msgbox "Hubzilla certificate has been renewed" 6 40 fi } function hubzilla_restore { dialog --title "Restore hubzilla from USB backup" \ --backtitle "Freedombone Control Panel" \ --yesno "\nInsert your USB backup drive and select 'yes' to continue" 16 60 sel=$? case $sel in 1) return;; 255) return;; esac clear echo 'Enter your backup drive password:' restorehubzilla } function hubzilla_channel_directory_server { if ! grep -q "Hubzilla domain" $COMPLETION_FILE; then dialog --title "Hubzilla channel directory server" \ --msgbox "Hubzilla is not installed on this system" 6 40 return fi HUBZILLA_DOMAIN_NAME=$(cat $COMPLETION_FILE | grep "Hubzilla domain" | awk -F ':' '{print $2}') if [ ! -d /var/www/$HUBZILLA_DOMAIN_NAME/htdocs ]; then dialog --title "Hubzilla channel directory server" \ --msgbox "Hubzilla install directory not found" 6 40 return fi data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title "Hubzilla channel directory server" \ --backtitle "Freedombone Control Panel" \ --inputbox "When you click on 'channel directory' this is where Hubzilla will obtain its list from" 8 60 2>$data sel=$? case $sel in 0) hubzilla_domain_server=$(<$data) if [[ $hubzilla_domain_server != *"."* ]]; then return fi if [[ $hubzilla_domain_server != "https"* ]]; then dialog --title "Hubzilla channel directory server" \ --msgbox "Invalid domain - include the https://" 6 40 return fi ./var/www/$HUBZILLA_DOMAIN_NAME/htdocs/util/config system directory_server $hubzilla_domain_server dialog --title "Hubzilla channel directory server" \ --msgbox "Domain channel directory server changed to $hubzilla_domain_server" 6 40 ;; esac } function format_drive { drive= data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Format a USB drive (LUKS encrypted)" \ --radiolist "Choose a drive:" 12 70 5 \ 1 "sda (Beaglebone Black)" off \ 2 "sdb" off \ 3 "sdc" off \ 4 "sdd" off \ 5 "Back to Backup and Restore menu" on 2> $data sel=$? case $sel in 1) return;; 255) return;; esac case $(cat $data) in 1) drive='sda';; 2) drive='sdb';; 3) drive='sdc';; 4) drive='sdd';; 5) return;; esac dialog --title "Format USB drive" \ --backtitle "Freedombone Control Panel" \ --defaultno \ --yesno "\nPlease confirm that you wish to format drive\n\n ${drive}\n\nAll current data on the drive will be lost, and you will be prompted to give a password used to encrypt the drive.\n\nDANGER: If you screw up here and format the wrong drive it's your own fault!" 16 60 sel=$? case $sel in 1) return;; 255) return;; esac clear freedombone-format $drive any_key } function shut_down_system { dialog --title "Power off the system" \ --backtitle "Freedombone Control Panel" \ --defaultno \ --yesno "\nPlease confirm that you wish to power off the system.\n\nWARNING: to power on again you will need to have physical access to the hardware." 10 60 sel=$? case $sel in 1) return;; 255) return;; esac shutdown now } function restart_system { dialog --title "Restart the system" \ --backtitle "Freedombone Control Panel" \ --defaultno \ --yesno "\nPlease confirm that you wish to restart the system.\n\nWARNING: If you are using full disk encryption then you will need physical access to the hardware to type in the password" 10 60 sel=$? case $sel in 1) return;; 255) return;; esac reboot } function menu_backup_restore { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Backup and Restore" \ --radiolist "Choose an operation:" 17 70 10 \ 1 "Backup data to USB drive" off \ 2 "Restore GPG key from USB keydrive" off \ 3 "Restore data from USB drive" off \ 4 "Restore Hubzilla data from USB drive" off \ 5 "Configure remote backups" off \ 6 "Restore from remote backup" off \ 7 "Backup GPG key to USB (master keydrive)" off \ 8 "Backup GPG key to USB (fragment keydrive)" off \ 9 "Format a USB drive (LUKS encrypted)" off \ 10 "Back to main menu" on 2> $data sel=$? case $sel in 1) break;; 255) break;; esac case $(cat $data) in 1) backup_data;; 2) restore_gpg_key;; 3) restore_data;; 4) hubzilla_restore;; 5) configure_remote_backups;; 6) restore_data_remote;; 7) create_keydrive_master;; 8) create_keydrive_fragment;; 9) format_drive;; 10) break;; esac done } function menu_email { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Email Filtering Rules" \ --radiolist "Choose an operation:" 12 70 5 \ 1 "Add a user to a mailing list" off \ 2 "Add an email rule" off \ 3 "Block/Unblock an email address" off \ 4 "Block/Unblock email with subject text" off \ 5 "Back to main menu" on 2> $data sel=$? case $sel in 1) break;; 255) break;; esac case $(cat $data) in 1) add_to_mailing_list;; 2) email_rule;; 3) block_unblock_email;; 4) block_unblock_subject;; 5) break;; esac done } function menu_users { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Manage Users" \ --radiolist "Choose an operation:" 12 70 5 \ 1 "Add a user" off \ 2 "Delete a user" off \ 3 "Change user password" off \ 4 "Change user ssh public key" off \ 5 "Back to main menu" on 2> $data sel=$? case $sel in 1) break;; 255) break;; esac case $(cat $data) in 1) add_user;; 2) delete_user;; 3) change_password;; 4) change_ssh_public_key;; 5) break;; esac done } function menu_hubzilla { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Hubzilla" \ --radiolist "Choose an operation:" 13 70 4 \ 1 "Restore from usb backup" off \ 2 "Set channel directory server" off \ 3 "Renew SSL certificate" off \ 4 "Back to main menu" on 2> $data sel=$? case $sel in 1) break;; 255) break;; esac case $(cat $data) in 1) hubzilla_restore;; 2) hubzilla_channel_directory_server;; 3) hubzilla_renew_cert;; 4) break;; esac done } function menu_top_level { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle "Freedombone Control Panel" \ --title "Control Panel" \ --radiolist "Choose an operation:" 19 70 12 \ 1 "Backup and Restore" off \ 2 "Show SIP Phone Extensions" off \ 3 "Reset Tripwire" off \ 4 "Logging on/off" off \ 5 "Manage Users" off \ 6 "Email Filtering Rules" off \ 7 "Security Settings" off \ 8 "Hubzilla" off \ 9 "Check for updates" off \ 10 "Power off the system" off \ 11 "Restart the system" off \ 12 "Exit" on 2> $data sel=$? case $sel in 1) exit 1;; 255) exit 1;; esac case $(cat $data) in 1) menu_backup_restore;; 2) show_sip_extensions;; 3) reset_tripwire;; 4) logging_on_off;; 5) menu_users;; 6) menu_email;; 7) security_settings;; 8) menu_hubzilla;; 9) check_for_updates;; 10) shut_down_system;; 11) restart_system;; 12) break;; esac done } if [ ! -f $COMPLETION_FILE ]; then echo 'This command should only be run on an installed Freedombone system' exit 1 fi ADMIN_USER=$(cat $COMPLETION_FILE | grep "Admin user" | awk -F ':' '{print $2}') menu_top_level clear cat /etc/motd exit 0