|
#!/bin/bash |
|
# SnapServ Server StackScript (S5) |
|
# |
|
# Copyright (c) 2013 Pascal Mathis <dev@snapserv.net> |
|
|
|
### |
|
# Flags and includes |
|
### |
|
set -o nounset |
|
set -o errexit |
|
export FANCYTTY=1 |
|
. /lib/lsb/init-functions |
|
|
|
### |
|
# Configuration |
|
### |
|
CONFIG_FILE="/root/config.sh" |
|
LOG_FILE='/root/s5.log' |
|
|
|
### |
|
# Config file paths |
|
### |
|
readonly CNF_HOSTNAME='/etc/hostname' |
|
readonly CNF_HOSTS='/etc/hosts' |
|
readonly CNF_INTERFACES='/etc/network/interfaces' |
|
readonly CNF_DNS_RESOLV='/etc/resolv.conf' |
|
readonly CNF_GAI='/etc/gai.conf' |
|
readonly CNF_SOFTWARE_REPOSITORIES='/etc/apt/sources.list' |
|
readonly CNF_NTP='/etc/ntp.conf' |
|
readonly CNF_OPENSSH_SERVER='/etc/ssh/sshd_config' |
|
readonly CNF_DUO_UNIX='/etc/duo/login_duo.conf' |
|
readonly CNF_MAILNAME='/etc/mailname' |
|
readonly CNF_APTICRON='/etc/apticron/apticron.conf' |
|
|
|
### |
|
# Download URLs |
|
### |
|
readonly URL_PAM_SSH_AGENT_AUTH='http://garr.dl.sourceforge.net/project/pamsshagentauth/pam_ssh_agent_auth/v0.9.5/pam_ssh_agent_auth-0.9.5.tar.bz2' |
|
readonly URL_DUO_UNIX='https://dl.duosecurity.com/duo_unix-latest.tar.gz' |
|
|
|
### |
|
# Error codes |
|
### |
|
readonly ERR_NO_CONFIG_FILE=0 |
|
readonly ERR_MISSING_CONFIG_KEY=1 |
|
readonly ERR_MUST_RUN_AS_ROOT=2 |
|
readonly ERR_USER_DOES_NOT_EXIST=3 |
|
readonly ERR_INVALID_CONFIG_FILE=4 |
|
readonly ERR_MISSING_PAM_SECURITY_FOLDER=5 |
|
|
|
### |
|
# Helper functions |
|
### |
|
require_config() { |
|
local CONFIG_KEY |
|
CONFIG_KEY=${1} |
|
|
|
if [[ -z ${!CONFIG_KEY:-} ]]; then |
|
step_echo "Missing configuration key: ${CONFIG_KEY}" |
|
exit ${ERR_MISSING_CONFIG_KEY} |
|
fi |
|
} |
|
|
|
begin_step() { |
|
local SECTION_NAME |
|
local STEP_DESCRIPTION |
|
SECTION_NAME=${1} |
|
STEP_DESCRIPTION=${2} |
|
|
|
log_action_begin_msg "[${SECTION_NAME}] ${STEP_DESCRIPTION}" |
|
echo "--------------- [${SECTION_NAME}] ${STEP_DESCRIPTION} ---------------" >>${LOG_FILE} |
|
trap step_trap ERR EXIT |
|
} |
|
|
|
end_step() { |
|
trap - ERR EXIT |
|
log_action_end_msg 0 |
|
} |
|
|
|
step_echo() { |
|
echo "${@}" |
|
} |
|
|
|
# We need to declare 'ERROR_CODE' here, because the local statement |
|
# already resets the $? variable. |
|
ERROR_CODE=0 |
|
step_trap() { |
|
ERROR_CODE=${?} |
|
trap - ERR EXIT |
|
log_action_end_msg ${ERROR_CODE} |
|
} |
|
|
|
### |
|
# Clear logfile |
|
### |
|
echo -n '' >${LOG_FILE} |
|
|
|
### |
|
# Check for configuration file and load if available |
|
### |
|
if [[ ! -z ${CONFIG_FILE:-} ]] && [[ -f ${CONFIG_FILE} ]]; then |
|
# Check permissions of configuration file |
|
FILE_OWNER=$(stat -c '%u' ${CONFIG_FILE}) |
|
FILE_CHMOD=$(stat -c '%a' ${CONFIG_FILE}) |
|
if [[ ${FILE_CHMOD} != '600' ]] || [[ ${FILE_OWNER} != '0' ]]; then |
|
echo "For security reasons, the configuration file needs to belong to root with chmod 600." 1>&2 |
|
exit ${ERR_INVALID_CONFIG_FILE} |
|
else |
|
. ${CONFIG_FILE} |
|
fi |
|
else |
|
echo "Configuration file '${CONFIG_FILE}' was not found." 1>&2 |
|
exit ${ERR_NO_CONFIG_FILE} |
|
fi |
|
|
|
### |
|
# Check if script runs as root |
|
### |
|
if [[ $EUID -ne 0 ]]; then |
|
echo "This script must be run as root." 1>&2 |
|
exit ${ERR_MUST_RUN_AS_ROOT} |
|
fi |
|
|
|
### |
|
# [Network] Configure hostname and hosts file |
|
### |
|
if [[ ! -z ${S5_HOST_CONFIGURE:-} ]] && ${S5_HOST_CONFIGURE}; then |
|
begin_step 'Network' 'Configuring host' |
|
|
|
require_config 'S5_HOST_NAME' |
|
require_config 'S5_HOST_FQDN' |
|
require_config 'S5_PREFER_IPV4_OVER_IPV6' |
|
|
|
# Change hostname |
|
echo "${S5_HOST_FQDN}" >${CNF_HOSTNAME} |
|
hostname "${S5_HOST_FQDN}" |
|
|
|
# Adjust hosts file |
|
HOST_IP_ADDRESS=$(hostname -I) |
|
cat >${CNF_HOSTS} <<-EOL |
|
127.0.0.1 localhost |
|
::1 localhost ip6-localhost ip6-loopback |
|
ff02::1 ip6-allnodes |
|
ff02::2 ip6-allrouters |
|
|
|
${HOST_IP_ADDRESS} ${S5_HOST_FQDN} ${S5_HOST_NAME} |
|
EOL |
|
|
|
# Change precedence of getaddrinfo() |
|
if ${S5_PREFER_IPV4_OVER_IPV6}; then |
|
sed -i -e 's/^#precedence ::ffff:0:0\/96 100/precedence ::ffff:0:0\/96 100/' ${CNF_GAI} |
|
else |
|
sed -i -e 's/^precedence ::ffff:0:0\/96 100/#precedence ::ffff:0:0\/96 100/' ${CNF_GAI} |
|
fi |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [Network] DNS resolvers |
|
### |
|
if [[ ! -z ${S5_DNS_CONFIGURE:-} ]] && ${S5_DNS_CONFIGURE}; then |
|
begin_step 'Network' 'Configuring DNS resolvers' |
|
|
|
require_config 'S5_DNS_SEARCH_DOMAINS' |
|
require_config 'S5_DNS_SERVERS_IPV4' |
|
require_config 'S5_DNS_SERVERS_IPV6' |
|
|
|
# Strip existing DNS resolvers from interfaces-config |
|
sed -i -e '/^dns-nameservers/ d' ${CNF_INTERFACES} |
|
|
|
# Write new configuration file |
|
echo -n '' >${CNF_DNS_RESOLV} |
|
for SEARCH_DOMAIN in "${S5_DNS_SEARCH_DOMAINS[@]}"; do |
|
echo "search ${SEARCH_DOMAIN}" >>${CNF_DNS_RESOLV} |
|
done |
|
for SERVER_IPV4 in "${S5_DNS_SERVERS_IPV4[@]}"; do |
|
echo "nameserver ${SERVER_IPV4}" >>${CNF_DNS_RESOLV} |
|
done |
|
for SERVER_IPV6 in "${S5_DNS_SERVERS_IPV6[@]}"; do |
|
echo "nameserver ${SERVER_IPV6}" >>${CNF_DNS_RESOLV} |
|
done |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [Software] Update repositoriers |
|
### |
|
if [[ ! -z ${S5_SOFTWARE_CONFIGURE:-} ]] && ${S5_SOFTWARE_CONFIGURE}; then |
|
begin_step 'Software' 'Updating repositories and installed packages' |
|
|
|
# Modify repositories |
|
echo -n '' >${CNF_SOFTWARE_REPOSITORIES} |
|
for REPOSITORY in "${S5_SOFTWARE_REPOSITORIES[@]}"; do |
|
echo "${REPOSITORY}" >>${CNF_SOFTWARE_REPOSITORIES} |
|
done |
|
|
|
# Update package lists and installed packaes |
|
apt-get -q -y update 2>&1 &>>${LOG_FILE} |
|
apt-get -q -y upgrade 2>&1 &>>${LOG_FILE} |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [NTP] Install and configure NTPd |
|
### |
|
if [[ ! -z ${S5_NTP_CONFIGURE:-} ]] && ${S5_NTP_CONFIGURE}; then |
|
begin_step 'Software' 'Installing and configuring NTP daemon' |
|
|
|
require_config 'S5_NTP_SERVERS' |
|
|
|
# Install ntp daemon from software repositories |
|
apt-get -q -y install ntp &>>${LOG_FILE} |
|
|
|
# Write first part of configuration |
|
cat >${CNF_NTP} <<-EOL |
|
driftfile /var/lib/ntp/ntp.drift |
|
|
|
statistics loopstats peerstats clockstats |
|
filegen loopstats file loopstats type day enable |
|
filegen peerstats file peerstats type day enable |
|
filegen clockstats file clockstats type day enable |
|
|
|
EOL |
|
|
|
# Write NTP servers into NTP configuration |
|
for NTP_SERVER in "${S5_NTP_SERVERS[@]}"; do |
|
echo "server ${NTP_SERVER}" >>${CNF_NTP} |
|
done |
|
|
|
# Write second part of configuration |
|
cat >>${CNF_NTP} <<-EOL |
|
|
|
restrict -4 default kod notrap nomodify nopeer noquery |
|
restrict -6 default kod notrap nomodify nopeer noquery |
|
restrict 127.0.0.1 |
|
restrict ::1 |
|
EOL |
|
|
|
# Restart NTP daemon |
|
service ntp restart >>${LOG_FILE} |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [User] Lock root account, create new account and assign SSH keys |
|
### |
|
if [[ ! -z ${S5_USER_CONFIGURE:-} ]] && ${S5_USER_CONFIGURE}; then |
|
begin_step 'User' 'Setting up initial user configuration' |
|
|
|
require_config 'S5_USER_NAME' |
|
require_config 'S5_USER_GROUP' |
|
require_config 'S5_USER_HOME_DIR' |
|
require_config 'S5_USER_SSH_KEY' |
|
require_config 'S5_USER_OVERWRITE_EXISTING_SSH_KEYS' |
|
require_config 'S5_USER_LOCK_ROOT_ACCOUNT' |
|
|
|
# Create user if nonexistant |
|
if ! id -u ${S5_USER_NAME} &>/dev/null; then |
|
groupadd ${S5_USER_GROUP} >>${LOG_FILE} |
|
useradd -g ${S5_USER_GROUP} -m -d ${S5_USER_HOME_DIR} -s /bin/bash ${S5_USER_NAME} >>${LOG_FILE} |
|
usermod --lock ${S5_USER_NAME} >>${LOG_FILE} |
|
passwd --delete ${S5_USER_NAME} >>${LOG_FILE} |
|
else |
|
echo "User ${S5_USER_NAME} already exists and therefore won't be created." >>${LOG_FILE} |
|
fi |
|
|
|
# Copy SSH keys into new user |
|
if [[ ! -f "${S5_USER_HOME_DIR}/.ssh/authorized_keys" ]] || ${S5_USER_OVERWRITE_EXISTING_SSH_KEYS}; then |
|
mkdir -p "${S5_USER_HOME_DIR}/.ssh" |
|
touch "${S5_USER_HOME_DIR}/.ssh/authorized_keys" |
|
chown -R "${S5_USER_NAME}:${S5_USER_GROUP}" "${S5_USER_HOME_DIR}/.ssh/" |
|
chmod 700 "${S5_USER_HOME_DIR}/.ssh/" |
|
chmod 600 "${S5_USER_HOME_DIR}/.ssh/authorized_keys" |
|
echo "${S5_USER_SSH_KEY}" >"${S5_USER_HOME_DIR}/.ssh/authorized_keys" |
|
else |
|
echo "SSH keys for user ${S5_USER_NAME} already exist. For safety reasons, they won't be overwritten unless specified with 'S5_USER_OVERWRITE_EXISTING_SSH_KEYS'." >>${LOG_FILE} |
|
fi |
|
|
|
# Lock root account completely |
|
if ${S5_USER_LOCK_ROOT_ACCOUNT}; then |
|
usermod --lock root >>${LOG_FILE} |
|
passwd --delete root >>${LOG_FILE} |
|
fi |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [SSH] Install and confiĝure OpenSSH server |
|
### |
|
if [[ ! -z ${S5_SSH_CONFIGURE:-} ]] && ${S5_SSH_CONFIGURE}; then |
|
begin_step 'Software' 'Installing and configuring OpenSSH server' |
|
|
|
require_config 'S5_SSH_PORT_NUMBER' |
|
require_config 'S5_SSH_PERMIT_TUNNEL' |
|
require_config 'S5_SSH_ALLOW_TCP_FORWARDING' |
|
require_config 'S5_SSH_X11_FORWARDING' |
|
|
|
# Install OpenSSH server from software repositories |
|
apt-get -q -y install openssh-server &>>${LOG_FILE} |
|
|
|
# Configure OpenSSH server |
|
cat >${CNF_OPENSSH_SERVER} <<-EOL |
|
# Generic options |
|
Port ${S5_SSH_PORT_NUMBER} |
|
Protocol 2 |
|
HostKey /etc/ssh/ssh_host_rsa_key |
|
HostKey /etc/ssh/ssh_host_dsa_key |
|
HostKey /etc/ssh/ssh_host_ecdsa_key |
|
UsePrivilegeSeparation yes |
|
PrintMotd no |
|
PrintLastLog yes |
|
Subsystem sftp /usr/lib/openssh/sftp-server |
|
|
|
# Logging options |
|
SyslogFacility AUTH |
|
LogLevel INFO |
|
|
|
# Security options |
|
KeyRegenerationInterval 300 |
|
ServerKeyBits 4096 |
|
LoginGraceTime 120 |
|
StrictModes yes |
|
|
|
PermitRootLogin no |
|
PermitEmptyPasswords no |
|
PasswordAuthentication no |
|
IgnoreRhosts yes |
|
RhostsRSAAuthentication no |
|
HostbasedAuthentication no |
|
KerberosAuthentication no |
|
|
|
AllowUsers ${S5_USER_NAME} |
|
|
|
# Tunnel policies |
|
EOL |
|
|
|
# Add custom configuration |
|
if ${S5_SSH_X11_FORWARDING}; then |
|
echo 'X11Forwarding yes' >>${CNF_OPENSSH_SERVER} |
|
else |
|
echo 'X11Forwarding no' >> ${CNF_OPENSSH_SERVER} |
|
fi |
|
if ${S5_SSH_ALLOW_TCP_FORWARDING}; then |
|
echo 'AllowTcpForwarding yes' >>${CNF_OPENSSH_SERVER} |
|
else |
|
echo 'AllowTcpForwarding no' >> ${CNF_OPENSSH_SERVER} |
|
fi |
|
if ${S5_SSH_PERMIT_TUNNEL}; then |
|
echo 'PermitTunnel yes' >>${CNF_OPENSSH_SERVER} |
|
else |
|
echo 'PermitTunnel no' >> ${CNF_OPENSSH_SERVER} |
|
fi |
|
|
|
# Regenerate server keys |
|
rm /etc/ssh/ssh_host_* |
|
dpkg-reconfigure openssh-server &>>${LOG_FILE} |
|
|
|
# Restart OpenSSH daemon |
|
service ssh restart >>${LOG_FILE} |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [sudo] Setup sudo |
|
### |
|
if [[ ! -z ${S5_SUDO_CONFIGURE:-} ]] && ${S5_SUDO_CONFIGURE}; then |
|
begin_step 'Software' 'Installing and configuring sudo' |
|
|
|
# Install sudo and required build dependencies from software repositories |
|
apt-get -q -y install sudo &>>${LOG_FILE} |
|
apt-get -q -y install build-essential libpam-dev libssl-dev &>>${LOG_FILE} |
|
|
|
# Update sudoers file |
|
cat >/tmp/sudoers.new <<-EOL |
|
Defaults env_reset |
|
Defaults mail_badpass |
|
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
|
Defaults env_keep+=SSH_AUTH_SOCK |
|
Defaults passwd_tries=1 |
|
|
|
# User privilege specification |
|
root ALL=(ALL:ALL) ALL |
|
|
|
# Allow members of group sudo to execute any command |
|
%sudo ALL=(ALL:ALL) ALL |
|
EOL |
|
EDITOR='cp /tmp/sudoers.new' visudo |
|
|
|
# Add user account to sudo group |
|
usermod -a -G sudo ${S5_USER_NAME} |
|
|
|
# Compile, make and install pam_ssh_agent_auth |
|
pushd /usr/local/src >>${LOG_FILE} |
|
wget --quiet -O 'pam_ssh_agent_auth.tar.bz2' ${URL_PAM_SSH_AGENT_AUTH} >>${LOG_FILE} |
|
tar xf 'pam_ssh_agent_auth.tar.bz2' >>${LOG_FILE} |
|
pushd /usr/local/src/pam_ssh_agent_auth* >>${LOG_FILE} |
|
./configure 2>&1 >>${LOG_FILE} |
|
make 2>&1 &>>${LOG_FILE} |
|
make install 2>&1 &>>${LOG_FILE} |
|
|
|
if [[ -d '/lib/x86_64-linux-gnu/security' ]]; then |
|
PAM_SECURITY_FOLDER='/lib/x86_64-linux-gnu/security' |
|
elif [[ -d '/lib/i386-linux-gnu/security' ]]; then |
|
PAM_SECURITY_FOLDER='/lib/i386-linux-gnu/security' |
|
elif [[ -d '/lib/i686-linux-gnu/security' ]]; then |
|
PAM_SECURITY_FOLDER='/lib/i686-linux-gnu/security' |
|
else |
|
echo "Could not find PAM security library folder." 2>&1 |
|
exit ${ERR_MISSING_PAM_SECURITY_FOLDER} |
|
fi |
|
|
|
rm -f "${PAM_SECURITY_FOLDER}/pam_ssh_agent_auth.so" |
|
ln -s /usr/local/libexec/pam_ssh_agent_auth.so ${PAM_SECURITY_FOLDER} |
|
popd >>${LOG_FILE} |
|
popd >>${LOG_FILE} |
|
|
|
# Adjust sudo pam configuration |
|
cat >/etc/pam.d/sudo <<-EOL |
|
#%PAM-1.0 |
|
# @include common-auth |
|
auth sufficient pam_ssh_agent_auth.so file=%h/.ssh/authorized_keys |
|
auth required pam_deny.so |
|
|
|
@include common-account |
|
@include common-session-noninteractive |
|
EOL |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [bash] Setup bash aliases |
|
### |
|
if [[ ! -z ${S5_BASH_CONFIGURE:-} ]] && ${S5_BASH_CONFIGURE}; then |
|
begin_step 'Software' 'Configuring bash aliases' |
|
|
|
require_config 'S5_BASH_ALIASES' |
|
require_config 'S5_BASH_AFFECTED_USERS' |
|
|
|
for AFFECTED_USER in "${S5_BASH_AFFECTED_USERS[@]}"; do |
|
# Check if user exists |
|
if ! id -u ${AFFECTED_USER} &>/dev/null; then |
|
echo "User ${AFFECTED_USER} does not exist." 2>&1 |
|
exit ${ERR_USER_DOES_NOT_EXIST} |
|
fi |
|
|
|
HOMEDIR=$(eval "echo ~${AFFECTED_USER}") |
|
echo "${S5_BASH_ALIASES}" >"${HOMEDIR}/.bash_aliases" |
|
done |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [DuoUnix] Setup two-factor authentication |
|
### |
|
if [[ ! -z ${S5_DUO_UNIX_CONFIGURE:-} ]] && ${S5_DUO_UNIX_CONFIGURE}; then |
|
begin_step 'Security' 'Setting up DuoUnix two-factor authentication' |
|
|
|
require_config 'S5_DUO_UNIX_IKEY' |
|
require_config 'S5_DUO_UNIX_SKEY' |
|
require_config 'S5_DUO_UNIX_HOST' |
|
|
|
# Compile, make and install duo_unix |
|
pushd /usr/local/src >>${LOG_FILE} |
|
wget --quiet -O 'duo_unix.tar.gz' ${URL_DUO_UNIX} >>${LOG_FILE} |
|
tar xf 'duo_unix.tar.gz' >>${LOG_FILE} |
|
pushd /usr/local/src/duo_unix* >>${LOG_FILE} |
|
./configure --prefix=/usr 2>&1 >>${LOG_FILE} |
|
make 2>&1 &>>${LOG_FILE} |
|
make install 2>&1 &>>${LOG_FILE} |
|
popd >>${LOG_FILE} |
|
popd >>${LOG_FILE} |
|
|
|
# Configure DuoUnix |
|
cat >${CNF_DUO_UNIX} <<-EOL |
|
[duo] |
|
ikey = ${S5_DUO_UNIX_IKEY} |
|
skey = ${S5_DUO_UNIX_SKEY} |
|
host = ${S5_DUO_UNIX_HOST} |
|
pushinfo = yes |
|
autopush = no |
|
prompts = 1 |
|
motd = no |
|
EOL |
|
|
|
# Write DuoUnix wrapper script |
|
cat >/usr/local/bin/duoauth <<-'EOL' |
|
#!/bin/bash |
|
# Immediately kill connection if user tries to abort this script |
|
trap jail INT |
|
jail() { |
|
kill -9 ${PPID} |
|
exit 1 |
|
} |
|
|
|
# Handle connection based on subsystem |
|
if [ -z "${SSH_ORIGINAL_COMMAND}" ]; then |
|
# SSH connection without any subsystem |
|
/usr/sbin/login_duo "${SHELL} -l" |
|
exit 0 |
|
else |
|
# SSH connection with specified subsystem e.g. SFTP, rsync... |
|
if [[ -r /etc/duo/subsystem.whitelist ]] && grep -Fxq "${SSH_ORIGINAL_COMMAND}" /etc/duo/subsystem.whitelist; then |
|
${SHELL} -c '${SSH_ORIGINAL_COMMAND}' |
|
exit 0 |
|
else |
|
/usr/sbin/login_duo "${SHELL} -c '${SSH_ORIGINAL_COMMAND}'" |
|
exit 0 |
|
fi |
|
fi |
|
|
|
# Default action is to deny connection |
|
kill -9 ${PPID} |
|
exit 1 |
|
EOL |
|
chmod 755 /usr/local/bin/duoauth |
|
|
|
# Create subsystem whitelist |
|
if ${S5_DUO_UNIX_WHITELIST_SFTP}; then |
|
cat >/etc/duo/subsystem.whitelist <<-EOL |
|
/usr/lib/openssh/sftp-server |
|
EOL |
|
else |
|
echo -n '' >/etc/duo/subsystem.whitelist |
|
fi |
|
chmod 644 /etc/duo/subsystem.whitelist |
|
|
|
# Inject DuoUnix into SSH configuration |
|
if [[ ! -z ${S5_SSH_CONFIGURE:-} ]] && ${S5_SSH_CONFIGURE}; then |
|
cat >>${CNF_OPENSSH_SERVER} <<-EOL |
|
|
|
# DuoUnix integration |
|
ForceCommand /usr/local/bin/duoauth |
|
EOL |
|
service ssh restart >>${LOG_FILE} |
|
fi |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [DynMOTD] Dynamic message of the day |
|
### |
|
if [[ ! -z ${S5_DYN_MOTD_CONFIGURE:-} ]] && ${S5_DYN_MOTD_CONFIGURE}; then |
|
begin_step 'Software' 'Setting up dynamic message of the day' |
|
|
|
require_config 'S5_DYN_MOTD_BANNER' |
|
|
|
# Write DynMOTD script |
|
cat >/etc/profile.d/dynmotd.sh <<-'EOL' |
|
#!/bin/bash |
|
HOSTNAME=$(hostname -f) |
|
IP_ADDRESS=$(hostname -I | tr -d ' ') |
|
KERNEL_VERSION=$(uname -r) |
|
UPTIME=$(uptime | sed -n 's/.*up \([^,]*\), \([0-9:]*\), .*/\1 \2 hours/p') |
|
if [[ ! -n ${UPTIME} ]]; then |
|
UPTIME=$(uptime | sed -n 's/.*up \([^,]*\), .*/\1 hours/p') |
|
fi |
|
UPTIME=$(echo "${UPTIME}" | sed 's/^ *//g') |
|
CPU_MODEL=$(grep -m 1 'model name' /proc/cpuinfo | cut -d: -f2 | sed 's/^ *//g' | sed -n 's/ \+/ /gp') |
|
PROCESS_COUNT=$(ps aux | tail -n +2 | wc -l) |
|
LOAD=$(cat /proc/loadavg | cut -d ' ' -f 1,2,3) |
|
MEM_TOTAL=$(free -t -m | grep "Total" | awk '{print $2}') |
|
MEM_USED=$(free -t -m | grep "Total" | awk '{print $3}') |
|
|
|
USERNAME=$(whoami) |
|
PRIMARY_GROUP=$(id -gn) |
|
USER_SESSION_COUNT=$(who | grep ${USERNAME} | wc -l) |
|
|
|
if [[ $(id -Gn) == *sudo* ]]; then |
|
USERTYPE='Administrator' |
|
else |
|
USERTYPE='User' |
|
fi |
|
|
|
BANNER=$(cat /etc/motd-banner 2>/dev/null) |
|
MAINTENANCE_INFO=$(cat /etc/motd-maintenance 2>/dev/null) |
|
if [[ ! -n ${MAINTENANCE_INFO} ]]; then |
|
MAINTENANCE_INFO='Nothing to report.' |
|
fi |
|
|
|
echo -e "\033[1;32m${BANNER} |
|
|
|
\033[0;35m++++++++++++++++++++: \033[0;37mSystem Data\033[0;35m :++++++++++++++++++++++ |
|
\033[0;35m+ \033[0;37mHostname \033[0;35m= \033[1;32m${HOSTNAME} |
|
\033[0;35m+ \033[0;37mAddress \033[0;35m= \033[1;32m${IP_ADDRESS} |
|
\033[0;35m+ \033[0;37mKernel \033[0;35m= \033[1;32m${KERNEL_VERSION} |
|
\033[0;35m+ \033[0;37mUptime \033[0;35m= \033[1;32m${UPTIME} |
|
\033[0;35m+ \033[0;37mProcesses \033[0;35m= \033[1;32m${PROCESS_COUNT} running processes |
|
\033[0;35m+ \033[0;37mAvg. Load \033[0;35m= \033[1;32m${LOAD} |
|
\033[0;35m+ \033[0;37mCPU \033[0;35m= \033[1;32m${CPU_MODEL} |
|
\033[0;35m+ \033[0;37mMemory \033[0;35m= \033[1;32m${MEM_USED} MiB of ${MEM_TOTAL} MiB |
|
\033[0;35m+++++++++++++++++++++: \033[0;37mUser Data\033[0;35m :+++++++++++++++++++++++ |
|
\033[0;35m+ \033[0;37mType \033[0;35m= \033[1;32m${USERTYPE} |
|
\033[0;35m+ \033[0;37mUsername \033[0;35m= \033[1;32m${USERNAME} |
|
\033[0;35m+ \033[0;37mGroup \033[0;35m= \033[1;32m${PRIMARY_GROUP} (primary) |
|
\033[0;35m+ \033[0;37mSessions \033[0;35m= \033[1;32m${USER_SESSION_COUNT} sessions active |
|
\033[0;35m++++++++++++++: \033[0;37mMaintenance Information\033[0;35m :++++++++++++++++ |
|
\033[0;35m+ \033[0;37m${MAINTENANCE_INFO} |
|
\033[0;35m+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
\033[0m" |
|
EOL |
|
chmod 644 /etc/profile.d/dynmotd.sh |
|
|
|
# Create banner and maintenance info files |
|
cat >/etc/motd-banner <<-EOL |
|
${S5_DYN_MOTD_BANNER} |
|
EOL |
|
touch /etc/motd-maintenance |
|
chmod 644 /etc/motd-banner |
|
chmod 644 /etc/motd-maintenance |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [Mail] Install and configure exim4 in send-only mode |
|
### |
|
if [[ ! -z ${S5_MAIL_CONFIGURE:-} ]] && ${S5_MAIL_CONFIGURE}; then |
|
begin_step 'Mail' 'Installing and configuring send-only mail server' |
|
|
|
require_config 'S5_HOST_NAME' |
|
require_config 'S5_HOST_FQDN' |
|
require_config 'S5_MAIL_POSTMASTER_ADDRESSES' |
|
|
|
# Purge existing exim4 installation |
|
apt-get -q -y purge exim4-config &>>${LOG_FILE} |
|
|
|
# Automate exim4 installation (non-interactive) |
|
echo -n "${S5_HOST_FQDN}" >${CNF_MAILNAME} |
|
debconf-set-selections <<-EOL |
|
exim4-config exim4/mailname string ${S5_HOST_FQDN} |
|
exim4-config exim4/dc_localdelivery select Maildir format in home directory |
|
exim4-config exim4/dc_local_interfaces string 127.0.0.1 ; ::1 |
|
exim4-config exim4/dc_minimaldns boolean false |
|
exim4-config exim4/dc_other_hostnames string ${S5_HOST_FQDN}; ${S5_HOST_NAME}; localhost.localdomain; localhost |
|
exim4-config exim4/dc_eximconfig_configtype select internet site; mail is sent and received directly using SMTP |
|
exim4-config exim4/no_config boolean true |
|
exim4-config exim4/dc_postmaster string ${S5_MAIL_POSTMASTER_ADDRESSES[@]} |
|
exim4-config exim4/use_split_config boolean false |
|
exim4-config exim4/dc_relay_nets string |
|
exim4-config exim4/dc_relay_domains string |
|
EOL |
|
|
|
# Install exim4 from software repositories |
|
apt-get -q -y install exim4 &>>${LOG_FILE} |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# [Software] Install and configure apticron |
|
### |
|
if [[ ! -z ${S5_APTICRON_CONFIGURE:-} ]] && ${S5_APTICRON_CONFIGURE}; then |
|
begin_step 'Software' 'Installing and configuring apticron' |
|
|
|
require_config 'S5_APTICRON_ALERT_MAIL' |
|
|
|
# Install apticron from software repositories |
|
apt-get -q -y install apticron &>>${LOG_FILE} |
|
|
|
# Configure apticron |
|
cat >${CNF_APTICRON} <<-EOL |
|
EMAIL="${S5_APTICRON_ALERT_MAIL}" |
|
IPADDRESSNUM="1" |
|
EOL |
|
|
|
end_step |
|
fi |
|
|
|
### |
|
# S5 has finished |
|
### |
|
log_success_msg 'SnapServ Server StackScript (S5) was successfully executed.' |
|
log_warning_msg 'It seems like S5 has finished. Please reboot this host to apply all changes.' |
|
exit 0 |