#!/bin/bash

# Copyright 2014-2020 Security Onion Solutions, LLC

#    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/>.

cd "$(dirname "$0")" || exit 255
source ./so-functions
source ./so-common-functions
source ./so-whiptail
source ./so-variables

# Parse command line arguments
setup_type=$1
automation=$2

while [[ $# -gt 0 ]]; do
	arg="$1"
	shift
	case "$arg" in
		"--turbo="* ) 
			export TURBO="http://${arg#*=}";;
		"--proxy="* ) 
			export {http,https,ftp,rsync,all}_proxy="${arg#*=}";;
		"--allow-role="* )
			export ALLOW_ROLE="${arg#*=}";;
		"--allow-cidr="* )
			export ALLOW_CIDR="${arg#*=}";;
		"--skip-reboot" )
			export SKIP_REBOOT=1;;
		* )
			if [[ "$arg" == "--"* ]]; then
				echo "Invalid option"
			fi
	esac
done

# Begin Installation pre-processing
echo "---- Starting setup at $(date -u) ----" >> $setup_log 2>&1

automated=no
function progress() {
	if [ $automated == no ]; then
		whiptail --title "Security Onion Install" --gauge 'Please wait while installing' 6 60 0
	else
		cat >> $setup_log 2>&1
	fi
}

if [[ -f automation/$automation && $(basename $automation) == $automation ]]; then
	echo "Preselecting variable values based on automated setup: $automation" >> $setup_log 2>&1
	source automation/$automation
	automated=yes

	echo "Checking network configuration" >> $setup_log 2>&1
	ip a >> $setup_log 2>&1

	attempt=1
	attempts=60
	ip a | grep "$MNIC:" | grep "state UP" >> $setup_log 2>&1
	while [ $? -ne 0 ]; do
		ip a >> $setup_log 2>&1
		if [ $attempt -gt $attempts ]; then
			echo "Network unavailable - setup cannot continue" >> $setup_log 2>&1
			exit 1
		fi
		echo "Waiting for network to come up (attempt $attempt of $attempts)" >> $setup_log 2>&1
		attempt=$((attempt + 1))
		sleep 10;
		ip a | grep "$MNIC:" | grep "state UP" >> $setup_log 2>&1
	done
	echo "Network is up on $MNIC" >> $setup_log 2>&1
fi

case "$setup_type" in
	iso | network) # Accepted values
		echo "Beginning Security Onion $setup_type install" >> $setup_log 2>&1
		;;
	*)
		echo "Invalid install type, must be 'iso' or 'network'" | tee $setup_log
		exit 1
		;;
esac

# Allow execution of SO tools during setup
export PATH=$PATH:../salt/common/tools/sbin

got_root

detect_os

if [ "$OS" == ubuntu ]; then
	update-alternatives --set newt-palette /etc/newt/palette.original >> $setup_log 2>&1
fi

setterm -blank 0

if [ "$setup_type" == 'iso' ] || (whiptail_you_sure); then
	true
else
	echo "User cancelled setup." | tee $setup_log
	whiptail_cancel
fi

whiptail_install_type

if [ "$install_type" = 'EVAL' ]; then
	is_node=true
	is_master=true
	is_sensor=true
	is_eval=true
elif [ "$install_type" = 'STANDALONE' ]; then
	is_master=true
	is_distmaster=true
	is_node=true
	is_sensor=true
elif [ "$install_type" = 'MASTERSEARCH' ]; then
	is_master=true
	is_distmaster=true
	is_node=true
elif [ "$install_type" = 'MASTER' ]; then
	is_master=true
	is_distmaster=true
elif [ "$install_type" = 'SENSOR' ]; then
	is_sensor=true
	is_minion=true
	STRELKA=1
elif [[ "$install_type" =~ ^('SEARCHNODE'|'HOTNODE'|'WARMNODE')$ ]]; then
	is_node=true
	is_minion=true
elif [ "$install_type" = 'HEAVYNODE' ]; then
	is_node=true
	is_minion=true
	is_sensor=true
elif [ "$install_type" = 'FLEET' ]; then
	is_minion=true
	OSQUERY=1
elif [ "$install_type" = 'HELIXSENSOR' ]; then
	is_helix=true
fi

if [[ $is_eval ]]; then
	check_requirements "eval"
elif [[ $is_distmaster || $is_minion ]]; then
	check_requirements "dist"
elif [[ $is_sensor && ! $is_eval ]]; then
	check_requirements "dist" "sensor"
fi

whiptail_patch_schedule

case "$setup_type" in
	'iso')
		whiptail_set_hostname
		whiptail_management_nic
		whiptail_dhcp_or_static

		if [ "$address_type" != 'DHCP' ]; then
			whiptail_management_interface_ip
			whiptail_management_interface_mask
			whiptail_management_interface_gateway
			whiptail_management_interface_dns
			whiptail_management_interface_dns_search
		fi

		collect_adminuser_inputs
		;;
	'network')
		whiptail_network_notice
		whiptail_set_hostname
		whiptail_management_nic
		;;
esac

short_name=$(echo "$HOSTNAME" | awk -F. '{print $1}')

MINION_ID=$(echo "${short_name}_${install_type}" | tr '[:upper:]' '[:lower:]')
export MINION_ID

echo "MINION_ID = $MINION_ID" >> $setup_log 2>&1

minion_type=$(get_minion_type)

# Set any variables needed
set_default_log_size >> $setup_log 2>&1

if [[ $is_helix ]]; then
	RULESETUP=ETOPEN
	NSMSETUP=BASIC
	HNSENSOR=inherit
	MASTERUPDATES=0
fi

if [[ $is_helix || ( $is_master && $is_node ) ]]; then
	RULESETUP=ETOPEN
	NSMSETUP=BASIC
fi

if [[ $is_master && $is_node ]]; then
	LSPIPELINEWORKERS=1
	LSPIPELINEBATCH=125
	LSINPUTTHREADS=1
	LSINPUTBATCHCOUNT=125
	NIDS=Suricata
	BROVERSION=ZEEK
fi

if [[ $is_node ]]; then
	CURCLOSEDAYS=30
fi

# Start user prompts
if [[ $is_helix || $is_sensor ]]; then
	whiptail_bond_nics
	calculate_useable_cores
fi

if [[ $is_helix ||  $is_master ]]; then
	whiptail_homenet_master
fi

if [[ $is_helix || $is_master || $is_node ]]; then
	set_base_heapsizes
fi

if [[ $is_master && ! $is_eval ]]; then
	whiptail_master_adv
	whiptail_bro_version
	whiptail_nids
	whiptail_rule_setup

	if [ "$RULESETUP" != 'ETOPEN' ]; then
		whiptail_oinkcode
	fi

	if [ "$MASTERADV" = 'ADVANCED' ] && [ "$BROVERSION" != 'SURICATA' ]; then
		whiptail_master_adv_service_brologs
	fi
fi

if [[ $is_master ]]; then
	whiptail_components_adv_warning
	whiptail_enable_components
	collect_webuser_inputs
	get_redirect
fi

if [[ $is_distmaster || ( $is_sensor || $is_node ) && ! $is_eval ]]; then
	whiptail_master_updates
	if [[ $setup_type == 'network' && $MASTERUPDATES == 1 ]]; then
		whiptail_master_updates_warning
	fi
fi

if [[ $is_minion ]]; then
	whiptail_management_server
fi

if [[ $is_distmaster ]]; then
	collect_soremote_inputs
fi

if [[ $is_sensor && ! $is_eval ]]; then
	whiptail_homenet_sensor
	whiptail_sensor_config
	if [ $NSMSETUP == 'ADVANCED' ]; then
		whiptail_bro_pins
		whiptail_suricata_pins
		whiptail_bond_nics_mtu
	else
		whiptail_basic_bro
		whiptail_basic_suri
	fi
fi

if [[ $is_node && ! $is_eval ]]; then
	whiptail_node_advanced
	if [ "$NODESETUP" == 'NODEADVANCED' ]; then
		whiptail_node_es_heap
		whiptail_node_ls_heap
		whiptail_node_ls_pipeline_worker
		whiptail_node_ls_pipline_batchsize
		whiptail_node_ls_input_threads
		whiptail_node_ls_input_batch_count
		whiptail_cur_close_days
		whiptail_log_size_limit
	else
		NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE
		NODE_LS_HEAP_SIZE=$LS_HEAP_SIZE
		LSPIPELINEWORKERS=$num_cpu_cores
		LSPIPELINEBATCH=125
		LSINPUTTHREADS=1
		LSINPUTBATCHCOUNT=125
	fi
fi

whiptail_make_changes

if [[ -n "$TURBO" ]]; then
	use_turbo_proxy
fi

if [[ "$setup_type" == 'iso' ]]; then
	# Init networking so rest of install works
	set_hostname_iso
	set_management_interface

	add_admin_user
	disable_onion_user
fi

set_hostname >> $setup_log 2>&1
set_version >> $setup_log 2>&1
clear_master >> $setup_log 2>&1

if [[ $is_master ]]; then
	generate_passwords >> $setup_log 2>&1
	secrets_pillar >> $setup_log 2>&1
	add_socore_user_master >> $setup_log 2>&1
fi

if [[ $is_master && ! $is_eval ]]; then
	add_soremote_user_master >> $setup_log 2>&1
fi

set_main_ip >> $setup_log 2>&1

if [[ $is_minion ]]; then
	set_updates >> $setup_log 2>&1
	copy_ssh_key >> $setup_log 2>&1
fi

# Begin install
{
	# Set initial percentage to 0
	export percentage=0

        if [[ $is_minion ]]; then
                set_progress_str 1 'Configuring firewall'
                set_initial_firewall_policy >> $setup_log 2>&1
        fi

	set_progress_str 2 'Updating packages'
	update_packages >> $setup_log 2>&1

	if [[ $is_sensor || $is_helix ]]; then
		set_progress_str 3 'Creating bond interface'
		create_sensor_bond >> $setup_log 2>&1
		
		set_progress_str 4 'Generating sensor pillar'
		sensor_pillar >> $setup_log 2>&1
	fi

	set_progress_str 5 'Installing Salt and dependencies'
	saltify 2>> $setup_log

	set_progress_str 7 'Installing Docker and dependencies'
	docker_install >> $setup_log 2>&1
	
	set_progress_str 8 'Generating patch pillar'
	patch_pillar >> $setup_log 2>&1

	set_progress_str 9 'Initializing Salt minion'
	configure_minion "$minion_type" >> $setup_log 2>&1


	if [[ $is_master || $is_helix ]]; then
		set_progress_str 10 'Configuring Salt master'
		create_local_directories >> $setup_log 2>&1
		addtotab_generate_templates >> $setup_log 2>&1
		copy_master_config >> $setup_log 2>&1
		setup_salt_master_dirs >> $setup_log 2>&1
		firewall_generate_templates >> $setup_log 2>&1
		
		set_progress_str 11 'Updating sudoers file for soremote user'
		update_sudoers >> $setup_log 2>&1
		
		set_progress_str 12 'Generating master static pillar'
		master_static >> $setup_log 2>&1
		
		set_progress_str 13 'Generating master pillar'
		master_pillar >> $setup_log 2>&1
	fi


	set_progress_str 16 'Running first Salt checkin'
	salt_firstcheckin >> $setup_log 2>&1

	if [[ $is_helix ]]; then
		set_progress_str 17 'Generating the FireEye pillar'
		fireeye_pillar >> $setup_log 2>&1
	fi
	
	if [[ $is_node ]]; then
		set_progress_str 18 'Setting node type'
		set_node_type >> $setup_log 2>&1

		set_progress_str 19 'Generating search node pillar'
		node_pillar >> $setup_log 2>&1
	fi

	if [[ $is_minion ]]; then
		set_progress_str 20 'Accepting Salt key on master'
		accept_salt_key_remote >> $setup_log 2>&1
	fi

	if [[ $is_master ]]; then
		set_progress_str 20 'Accepting Salt key'
		salt-key -ya "$MINION_ID" >> $setup_log 2>&1
	fi

	set_progress_str 21 'Copying minion pillars to master'
	copy_minion_tmp_files >> $setup_log 2>&1

	set_progress_str 22 'Generating CA and checking in'
	salt_checkin >> $setup_log 2>&1

	if [[ $is_master || $is_helix ]]; then
		set_progress_str 25 'Configuring firewall'
		set_initial_firewall_policy >> $setup_log 2>&1
		
		if [[ "$setup_type" == 'iso' ]]; then
			set_progress_str 26 'Copying containers from iso'
		else
			set_progress_str 26 'Downloading containers from the internet'
		fi

		salt-call state.apply -l info registry >> $setup_log 2>&1
		docker_seed_registry  2>> "$setup_log" # ~ 60% when finished
		
		set_progress_str 60 "$(print_salt_state_apply 'master')"
		salt-call state.apply -l info master >> $setup_log 2>&1

		set_progress_str 61 "$(print_salt_state_apply 'idstools')"
		salt-call state.apply -l info idstools >> $setup_log 2>&1

		set_progress_str 61 "$(print_salt_state_apply 'suricata.master')"
		salt-call state.apply -l info suricata.master >> $setup_log 2>&1

	fi

	set_progress_str 62 "$(print_salt_state_apply 'firewall')"
	salt-call state.apply -l info firewall >> $setup_log 2>&1

	if [ $OS = 'centos' ]; then
		set_progress_str 63 'Installing Yum utilities'
		salt-call state.apply -l info yum.packages >> $setup_log 2>&1
	fi

	set_progress_str 63 "$(print_salt_state_apply 'common')"
	salt-call state.apply -l info common >> $setup_log 2>&1

	set_progress_str 64 "$(print_salt_state_apply 'nginx')"
	salt-call state.apply -l info nginx >> $setup_log 2>&1

	if [[ $is_master || $is_node ]]; then
		set_progress_str 64 "$(print_salt_state_apply 'elasticsearch')"
		salt-call state.apply -l info elasticsearch >> $setup_log 2>&1
	fi

	if [[ $is_sensor ]]; then
		set_progress_str 65 "$(print_salt_state_apply 'pcap')"
		salt-call state.apply -l info pcap >> $setup_log 2>&1

		set_progress_str 66 "$(print_salt_state_apply 'suricata')"
		salt-call state.apply -l info suricata >> $setup_log 2>&1

		set_progress_str 67 "$(print_salt_state_apply 'zeek')"
		salt-call state.apply -l info zeek >> $setup_log 2>&1
	fi

	if [[ $is_node ]]; then
		set_progress_str 68 "$(print_salt_state_apply 'curator')"
		salt-call state.apply -l info curator >> $setup_log 2>&1
	fi

	if [[ $is_master ]]; then
		set_progress_str 69 "$(print_salt_state_apply 'soc')"
		salt-call state.apply -l info soc >> $setup_log 2>&1

		set_progress_str 70 "$(print_salt_state_apply 'kibana')"
		salt-call state.apply -l info kibana >> $setup_log 2>&1

		set_progress_str 71 "$(print_salt_state_apply 'elastalert')"
		salt-call state.apply -l info elastalert >> $setup_log 2>&1

		set_progress_str 72 "$(print_salt_state_apply 'soctopus')"
		salt-call state.apply -l info soctopus >> $setup_log 2>&1
	fi
	
	if [[ "$OSQUERY" = 1 ]]; then
		set_progress_str 73 "$(print_salt_state_apply 'fleet')"
		salt-call state.apply -l info fleet >> $setup_log 2>&1

		set_progress_str 74 "$(print_salt_state_apply 'redis')"
		salt-call state.apply -l info redis >> $setup_log 2>&1
	fi

	if [[ "$WAZUH" = 1 ]]; then
		set_progress_str 75 "$(print_salt_state_apply 'wazuh')"
		salt-call state.apply -l info wazuh >> $setup_log 2>&1
	fi

	if [[ "$THEHIVE" = 1 ]]; then
		set_progress_str 76 "$(print_salt_state_apply 'hive')"
		salt-call state.apply -l info hive >> $setup_log 2>&1
	fi

	if [[ "$STRELKA" = 1 ]]; then
		set_progress_str 77 "$(print_salt_state_apply 'strelka')"
		salt-call state.apply -l info strelka >> $setup_log 2>&1
	fi

	if [[ "$PLAYBOOK" = 1 ]]; then
		set_progress_str 78 "$(print_salt_state_apply 'playbook')"
		salt-call state.apply -l info playbook >> $setup_log 2>&1
	fi

	if [[ "$NAVIGATOR" = 1 ]]; then
		set_progress_str 78 "$(print_salt_state_apply 'navigator')"
		salt-call state.apply -l info navigator >> $setup_log 2>&1
	fi

	if [[ $is_master || $is_helix ]]; then		
		set_progress_str 81 "$(print_salt_state_apply 'utility')"
		salt-call state.apply -l info utility >> $setup_log 2>&1
	fi

	if [[ ( $is_helix || $is_master || $is_node ) && ! $is_eval ]]; then
		set_progress_str 82 "$(print_salt_state_apply 'logstash')"
		salt-call state.apply -l info logstash >> $setup_log 2>&1

		set_progress_str 83 "$(print_salt_state_apply 'filebeat')"
		salt-call state.apply -l info filebeat >> $setup_log 2>&1
	fi

	set_progress_str 85 'Applying finishing touches'
	filter_unused_nics >> $setup_log 2>&1
	network_setup >> $setup_log 2>&1

	if [[ $is_master ]]; then
		set_progress_str 87 'Adding user to SOC'
		add_web_user >> $setup_log 2>&1
	fi

	set_progress_str 90 'Enabling checkin at boot'
	checkin_at_boot >> $setup_log 2>&1

	set_progress_str 95 'Verifying setup'
	salt-call -l info  state.highstate >> $setup_log 2>&1

} | progress

success=$(tail -10 $setup_log | grep Failed | awk '{ print $2}')
if [[ "$success" = 0 ]]; then
	whiptail_setup_complete
	if [[ -n $ALLOW_ROLE && -n $ALLOW_CIDR ]]; then 
		export IP=$ALLOW_CIDR
		so-allow -$ALLOW_ROLE >> $setup_log 2>&1
	fi
	if [[ $THEHIVE == 1 ]]; then
		check_hive_init
	fi
else
	whiptail_setup_failed
fi

if [[ -z $SKIP_REBOOT ]]; then
	shutdown -r now
fi
