#!/bin/bash

#########################################################
# Prep a RamNode OpenVZ Deb system for production use	#
#########################################################
# By Christopher A. Wadge, Jul 11, 2014			#
#							#
# http://files.tuxhelp.org/scripts/ramnode-bootstrap.sh	#
#							#
# Licensed under the GPL version 3. A copy of the GPL	#
# version 3 is included with this script.  If the file, #
# COPYING, is not included, you can find the GPL 	#
# version 3 at the following URL online:		#
#							#
# http://www.gnu.org/licenses/gpl-3.0.html		#
#########################################################


## VARIABLES ##
# The following are pre-determined variables that are not handled interactively.
#####

#
# Which version of Debian we are expecting
#
DEBIAN_VERSION="7"
#
# Boilerplate package list for installation, space-separated
#
STANDARD_PKGS="apt-utils bc curl less htop screen tmux bsdutils dnsutils pbzip2 pigz zip vim ufw fail2ban openssh-client openssh-server sudo tzdata"
#
# Pre-installed packages to be purged, space-seperated
#
PURGE_PKGS="`dpkg --get-selections | grep i386 | awk '{print $1}'` sendmail sendmail-base sendmail-bin sendmail-cf sendmail-doc apache2 apache2-doc apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common bind9 bind9-host bind9utils libbind9-80 libwbclient0 libcups2 rpcbind samba samba-common cifs-utils fetchmail"
#
# TCP port the SSH daemon should ride by default (leave blank for random)
#
SSH_PORT=""
#
# Primary IP address of the system
#
IP_ADDRESS="`hostname --ip-address`"
#
# The host's shortname
#
HOSTNAME_SHORT="`hostname -s`"
#
# The host's FQDN
#
HOSTNAME_FULL="`hostname -f`"
#
# GPG server we should be pulling our public keys from
#
GPG_KEYSERVER="keys.gnupg.net"
#
# Which keys we should be pulling down
#
GPG_KEYS="79AF54A9 DC242980 CBCB082A1BB943DB 1C4CBDCDCD2EFD2A E9C74FEEA2098A6E"
#
# Path for archived configuration files
#
BACKUP_PATH="/var/backups/oldconfigs/"
#
# Default system groups for new admin user, comma-seperated
#
ADMIN_SYS_GROUPS="sshlogin,sudo"


## ASSETS ##
# Config files, etc. we can provide within the script rather than calling externals.
#####

# /etc/sysctl.conf
File_sysctl_conf ()
{
cat <<- _EOF_
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additonal system variables
# See sysctl.conf (5) for information.
#
# There is a limited set which we can modify in an OpenVZ container.
#
kernel.printk = 3 4 1 3
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.secure_redirects = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.disable_ipv6 = 0
net.core.somaxconn = 65535
_EOF_
}

# /etc/apt/sources.list
File_apt_sources_list ()
{
cat <<- _EOF_
###########################
## Official Debian Repos ##
###########################
deb http://mirrors.kernel.org/debian/ wheezy main non-free contrib
deb http://security.debian.org/ wheezy/updates main contrib non-free
deb http://mirrors.kernel.org/debian/ wheezy-updates main contrib non-free
deb http://mirrors.kernel.org/debian/ wheezy-backports main contrib non-free

###########################
##    3rd-Party Repos    ##
###########################
deb http://ftp.osuosl.org/pub/mariadb/repo/5.5/debian wheezy main
deb http://repo.percona.com/apt wheezy main
deb http://mirror.tuxhelp.org/debian/ squeeze main
#deb http://apt.sparkz.no/debian/ squeeze main
#deb http://packages.dotdeb.org wheezy all
_EOF_
}

# /etc/vim/vimrc
File_vimrc ()
{
cat <<- _EOF_
" All system-wide defaults are set in \$VIMRUNTIME/debian.vim (usually just
" /usr/share/vim/vimcurrent/debian.vim) and sourced by the call to :runtime
" you can find below.  If you wish to change any of those settings, you should
" do it in this file (/etc/vim/vimrc), since debian.vim will be overwritten
" everytime an upgrade of the vim packages is performed.  It is recommended to
" make changes after sourcing debian.vim since it alters the value of the
" 'compatible' option.

" This line should not be removed as it ensures that various options are
" properly set to work with the Vim-related packages available in Debian.
runtime! debian.vim

" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'.  Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible

" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
syntax on

" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
"set background=dark

" Uncomment the following to have Vim jump to the last position when
" reopening a file
if has("autocmd")
  au BufReadPost * if line("'\\"") > 1 && line("'\\"") <= line("$") | exe "normal! g'\\"" | endif
endif

" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
"if has("autocmd")
"  filetype plugin indent on
"endif

" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd		" Show (partial) command in status line.
"set showmatch		" Show matching brackets.
"set ignorecase		" Do case insensitive matching
"set smartcase		" Do smart case matching
"set incsearch		" Incremental search
"set autowrite		" Automatically save before commands like :next and :make
"set hidden             " Hide buffers when they are abandoned
"set mouse=a		" Enable mouse usage (all modes)

" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif

_EOF_
}

# /usr/local/sbin/apt-up
File_apt_up ()
{
cat <<- _EOF_
#!/bin/sh
echo " ________________________________ "
echo "/ Checking for updated files...  \ "
echo "\________________________________/ "
aptitude update
echo " ________________________________ "
echo "/ Updating files if necessary... \ "
echo "\________________________________/ "
aptitude full-upgrade
echo " ________________________________ "
echo "/           Finished.            \ "
echo "\________________________________/ "
_EOF_
}

# /etc/issue.net
File_issue_net ()
{
cat <<- _EOF_
***********************************************************************
****       Unauthorized access to this device is prohibited.       ****
**** Use of this system is limited to authorized individuals only. ****
****                  All activity is monitored.                   ****
***********************************************************************
_EOF_
}

# /etc/default/ufw
File_UFW_ufw ()
{
cat <<- _EOF_
# /etc/default/ufw
#

# Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback
# accepted). You will need to 'disable' and then 'enable' the firewall for
# the changes to take affect.
IPV6=yes

# Set the default input policy to ACCEPT, ACCEPT_NO_TRACK, DROP, or REJECT.
# ACCEPT enables connection tracking for NEW inbound packets on the INPUT
# chain, whereas ACCEPT_NO_TRACK does not use connection tracking. Please note
# that if you change this you will most likely want to adjust your rules.
DEFAULT_INPUT_POLICY="DROP"

# Set the default output policy to ACCEPT, ACCEPT_NO_TRACK, DROP, or REJECT.
# ACCEPT enables connection tracking for NEW outbound packets on the OUTPUT
# chain, whereas ACCEPT_NO_TRACK does not use connection tracking. Please note
# that if you change this you will most likely want to adjust your rules.
DEFAULT_OUTPUT_POLICY="ACCEPT"

# Set the default forward policy to ACCEPT, DROP or REJECT.  Please note that
# if you change this you will most likely want to adjust your rules
DEFAULT_FORWARD_POLICY="DROP"

# Set the default application policy to ACCEPT, DROP, REJECT or SKIP. Please
# note that setting this to ACCEPT may be a security risk. See 'man ufw' for
# details
DEFAULT_APPLICATION_POLICY="SKIP"

# By default, ufw only touches its own chains. Set this to 'yes' to have ufw
# manage the built-in chains too. Warning: setting this to 'yes' will break
# non-ufw managed firewall rules
MANAGE_BUILTINS=no

#
# IPT backend
#
# only enable if using iptables backend
IPT_SYSCTL=/etc/ufw/sysctl.conf

# Extra connection tracking modules to load. Complete list can be found in
# net/netfilter/Kconfig of your kernel source. Some common modules:
# nf_conntrack_irc, nf_nat_irc: DCC (Direct Client to Client) support
# nf_conntrack_netbios_ns: NetBIOS (samba) client support
# nf_conntrack_pptp, nf_nat_pptp: PPTP over stateful firewall/NAT
# nf_conntrack_ftp, nf_nat_ftp: active FTP support
# nf_conntrack_tftp, nf_nat_tftp: TFTP support (server side)
#IPT_MODULES="nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns"
_EOF_
}

# /etc/ufw/after.rules
File_UFW_after_rules ()
{
cat <<- _EOF_
#
# rules.input-after
#
# Rules that should be run after the ufw command line added rules. Custom
# rules should be added to one of these chains:
#   ufw-after-input
#   ufw-after-output
#   ufw-after-forward
#

# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-after-input - [0:0]
:ufw-after-output - [0:0]
:ufw-after-forward - [0:0]
# End required lines

# don't log noisy services by default
-A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input

# don't log noisy broadcast
#-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input

# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
_EOF_
}

# /etc/ufw/before.rules
File_UFW_before_rules ()
{
cat <<- _EOF_
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
#   ufw-before-input
#   ufw-before-output
#   ufw-before-forward
#

# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
# End required lines


# allow all on loopback
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-output -o lo -j ACCEPT

# quickly process packets for which we already have a connection
-A ufw-before-input -m state --state RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m state --state RELATED,ESTABLISHED -j ACCEPT

# drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m state --state INVALID -j ufw-logging-deny
-A ufw-before-input -m state --state INVALID -j DROP

# ok icmp codes
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-input -p icmp --icmp-type source-quench -j ACCEPT
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT

# allow dhcp client to work
-A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT

#
# ufw-not-local
#
#-A ufw-before-input -j ufw-not-local

# if LOCAL, RETURN
#-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN

# if MULTICAST, RETURN
#-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN

# if BROADCAST, RETURN
#-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN

# all other non-local packets are dropped
#-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
#-A ufw-not-local -j DROP

# allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
# is uncommented)
#-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT

# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
# is uncommented)
#-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT

# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
_EOF_
}

# /etc/ufw/ufw.conf
File_UFW_ufw_conf ()
{
cat <<- _EOF_
# /etc/ufw/ufw.conf
#

# Set to yes to start on boot. If setting this remotely, be sure to add a rule
# to allow your remote connection before starting ufw. Eg: 'ufw allow 22/tcp'
ENABLED=yes

# Please use the 'ufw' command to set the loglevel. Eg: 'ufw logging medium'.
# See 'man ufw' for details.
LOGLEVEL=low
_EOF_
}

# /lib/ufw/user.rules
File_UFW_user_rules ()
{
cat <<- _EOF_
*filter
:ufw-user-input - [0:0]
:ufw-user-output - [0:0]
:ufw-user-forward - [0:0]
:ufw-before-logging-input - [0:0]
:ufw-before-logging-output - [0:0]
:ufw-before-logging-forward - [0:0]
:ufw-user-logging-input - [0:0]
:ufw-user-logging-output - [0:0]
:ufw-user-logging-forward - [0:0]
:ufw-after-logging-input - [0:0]
:ufw-after-logging-output - [0:0]
:ufw-after-logging-forward - [0:0]
:ufw-logging-deny - [0:0]
:ufw-logging-allow - [0:0]
:ufw-user-limit - [0:0]
:ufw-user-limit-accept - [0:0]
### RULES ###

### tuple ### allow tcp $SSH_PORT 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp --dport $SSH_PORT -j ACCEPT

### END RULES ###

### LOGGING ###
-A ufw-after-logging-input -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-A ufw-after-logging-forward -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-I ufw-logging-deny -m state --state INVALID -j RETURN -m limit --limit 3/min --limit-burst 10
-A ufw-logging-deny -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-A ufw-logging-allow -j LOG --log-prefix "[UFW ALLOW] " -m limit --limit 3/min --limit-burst 10
### END LOGGING ###

### RATE LIMITING ###
-A ufw-user-limit -m limit --limit 3/minute -j LOG --log-prefix "[UFW LIMIT BLOCK] "
-A ufw-user-limit -j REJECT
-A ufw-user-limit-accept -j ACCEPT
### END RATE LIMITING ###
COMMIT
_EOF_
}

# /lib/ufw/user6.rules
File_UFW_user6_rules ()
{
cat <<- _EOF_
*filter
:ufw6-user-input - [0:0]
:ufw6-user-output - [0:0]
:ufw6-user-forward - [0:0]
:ufw6-before-logging-input - [0:0]
:ufw6-before-logging-output - [0:0]
:ufw6-before-logging-forward - [0:0]
:ufw6-user-logging-input - [0:0]
:ufw6-user-logging-output - [0:0]
:ufw6-user-logging-forward - [0:0]
:ufw6-after-logging-input - [0:0]
:ufw6-after-logging-output - [0:0]
:ufw6-after-logging-forward - [0:0]
:ufw6-logging-deny - [0:0]
:ufw6-logging-allow - [0:0]
### RULES ###

### tuple ### allow tcp $SSH_PORT ::/0 any ::/0 in
-A ufw6-user-input -p tcp --dport $SSH_PORT -j ACCEPT

### END RULES ###

### LOGGING ###
-A ufw6-after-logging-input -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-A ufw6-after-logging-forward -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-I ufw6-logging-deny -m state --state INVALID -j RETURN -m limit --limit 3/min --limit-burst 10
-A ufw6-logging-deny -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10
-A ufw6-logging-allow -j LOG --log-prefix "[UFW ALLOW] " -m limit --limit 3/min --limit-burst 10
### END LOGGING ###
COMMIT
_EOF_
}

# /etc/fail2ban/jail.conf
File_jail_conf ()
{
cat <<- _EOF_

# Fail2Ban configuration file.
#
# This file was composed for Debian systems from the original one
#  provided now under /usr/share/doc/fail2ban/examples/jail.conf
#  for additional examples.
#
# To avoid merges during upgrades DO NOT MODIFY THIS FILE
# and rather provide your changes in /etc/fail2ban/jail.local
#
# Author: Yaroslav O. Halchenko <debian@onerussian.com>
#
# \$Revision$
#

# The DEFAULT allows a global definition of the options. They can be overridden
# in each jail afterwards.

[DEFAULT]

# "ignoreip" can be an IP address, a CIDR mask or a DNS host
ignoreip = 127.0.0.1/8
bantime  = 600
maxretry = 3

# "backend" specifies the backend used to get files modification. Available
# options are "gamin", "polling" and "auto".
# yoh: For some reason Debian shipped python-gamin didn't work as expected
#      This issue left ToDo, so polling is default backend for now
backend = auto

#
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
destemail = root@localhost

#
# ACTIONS
#

# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
banaction = iptables-multiport

# email action. Since 0.8.1 upstream fail2ban uses sendmail
# MTA for the mailing. Change mta configuration parameter to mail
# if you want to revert to conventional 'mail'.
mta = sendmail

# Default protocol
protocol = tcp

# Specify chain where jumps would need to be added in iptables-* actions
chain = INPUT

#
# Action shortcuts. To be used to define action parameter

# The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]

# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
              %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]

# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
               %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]

# Choose default action.  To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g.  action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
action = %(action_)s

#
# JAILS
#

# Next jails corresponds to the standard configuration in Fail2ban 0.6 which
# was shipped in Debian. Enable any defined here jail by including
#
# [SECTION_NAME]
# enabled = true

#
# in /etc/fail2ban/jail.local.
#
# Optionally you may override any other parameter (e.g. banaction,
# action, port, logpath, etc) in that section within jail.local

[ssh]

enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 6

[dropbear]

enabled  = false
port     = ssh
filter   = sshd
logpath  = /var/log/dropbear
maxretry = 6

# Generic filter for pam. Has to be used with action which bans all ports
# such as iptables-allports, shorewall
[pam-generic]

enabled  = false
# pam-generic filter can be customized to monitor specific subset of 'tty's
filter   = pam-generic
# port actually must be irrelevant but lets leave it all for some possible uses
port     = all
banaction = iptables-allports
port     = anyport
logpath  = /var/log/auth.log
maxretry = 6

[xinetd-fail]

enabled   = false
filter    = xinetd-fail
port      = all
banaction = iptables-multiport-log
logpath   = /var/log/daemon.log
maxretry  = 2


[ssh-ddos]

enabled  = true
port     = ssh
filter   = sshd-ddos
logpath  = /var/log/auth.log
maxretry = 6

#
# HTTP servers
#

[apache]

enabled  = false
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache*/*error.log
maxretry = 6

# default action is now multiport, so apache-multiport jail was left
# for compatibility with previous (<0.7.6-2) releases
[apache-multiport]

enabled   = false
port      = http,https
filter    = apache-auth
logpath   = /var/log/apache*/*error.log
maxretry  = 6

[apache-noscript]

enabled  = false
port     = http,https
filter   = apache-noscript
logpath  = /var/log/apache*/*error.log
maxretry = 6

[apache-overflows]

enabled  = false
port     = http,https
filter   = apache-overflows
logpath  = /var/log/apache*/*error.log
maxretry = 2

#
# FTP servers
#

[vsftpd]

enabled  = false
port     = ftp,ftp-data,ftps,ftps-data
filter   = vsftpd
logpath  = /var/log/vsftpd.log
# or overwrite it in jails.local to be
# logpath = /var/log/auth.log
# if you want to rely on PAM failed login attempts
# vsftpd's failregex should match both of those formats
maxretry = 6


[proftpd]

enabled  = false
port     = ftp,ftp-data,ftps,ftps-data
filter   = proftpd
logpath  = /var/log/proftpd/proftpd.log
maxretry = 6


[pure-ftpd]

enabled  = false
port     = ftp,ftp-data,ftps,ftps-data
filter   = pure-ftpd
logpath  = /var/log/auth.log
maxretry = 6


[wuftpd]

enabled  = false
port     = ftp,ftp-data,ftps,ftps-data
filter   = wuftpd
logpath  = /var/log/auth.log
maxretry = 6


#
# Mail servers
#

[postfix]

enabled  = false
port     = smtp,ssmtp
filter   = postfix
logpath  = /var/log/mail.log


[couriersmtp]

enabled  = false
port     = smtp,ssmtp
filter   = couriersmtp
logpath  = /var/log/mail.log


#
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
# all relevant ports get banned
#

[courierauth]

enabled  = false
port     = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter   = courierlogin
logpath  = /var/log/mail.log


[sasl]

enabled  = false
port     = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter   = sasl
# You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize.
logpath  = /var/log/mail.log

[dovecot]

enabled = false
port    = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter  = dovecot
logpath = /var/log/mail.log

# DNS Servers


# These jails block attacks against named (bind9). By default, logging is off
# with bind9 installation. You will need something like this:
#
# logging {
#     channel security_file {
#         file "/var/log/named/security.log" versions 3 size 30m;
#         severity dynamic;
#         print-time yes;
#     };
#     category security {
#         security_file;
#     };
# };
#
# in your named.conf to provide proper logging

# !!! WARNING !!!
#   Since UDP is connection-less protocol, spoofing of IP and imitation
#   of illegal actions is way too simple.  Thus enabling of this filter
#   might provide an easy way for implementing a DoS against a chosen
#   victim. See
#    http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html
#   Please DO NOT USE this jail unless you know what you are doing.
#[named-refused-udp]
#
#enabled  = false
#port     = domain,953
#protocol = udp
#filter   = named-refused
#logpath  = /var/log/named/security.log

[named-refused-tcp]

enabled  = false
port     = domain,953
protocol = tcp
filter   = named-refused
logpath  = /var/log/named/security.log


_EOF_
}

# /etc/security/limits.conf
File_limits_conf ()
{
cat <<- _EOF_
# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain>        <type>  <item>  <value>
#
#Where:
#<domain> can be:
#        - an user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#        - NOTE: group and wildcard limits are not applied to root.
#          To apply a limit to the root user, <domain> must be
#          the literal username root.
#
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open files
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit (KB)
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to values: [-20, 19]
#        - rtprio - max realtime priority
#        - chroot - change root to directory (Debian-specific)
#
#<domain>      <type>  <item>         <value>
#

#*               soft    core            0
#root            hard    core            100000
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#ftp             -       chroot          /ftp
#@student        -       maxlogins       4

*               soft    core            0
*               hard    core            0
*               soft    nofile          819200
*               hard    nofile          819200
root            soft    nproc           unlimited
root            soft    nofile          unlimited

# End of file
_EOF_
}

# /etc/ssh/sshd_config
File_sshd_config ()
{
cat <<- _EOF_
# Package generated configuration file
# See the sshd_config(5) manpage for details

# What ports, IPs and protocols we listen for
Port $SSH_PORT
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 2048

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin no
StrictModes yes

RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile	%h/.ssh/authorized_keys

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
#PasswordAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,chacha20-poly1305@openssh.com
MACs hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1,umac-64@openssh.com,hmac-ripemd160

X11Forwarding no
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no
UseDNS no
AllowGroups sshlogin

MaxStartups 128:33:1024
Banner /etc/issue.net

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

Subsystem sftp /usr/lib/openssh/sftp-server

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
_EOF_
}

## FUNCTIONS ##
# Use a function for each sub-task for max flexibility.
#####

Error_Handler ()
{

	echo "[FATAL] Script aborted while $CURRENT_STEP."
	echo
	exit 1
}

Sanity_Check ()
{
	CURRENT_STEP="performing sanity check"
	if [ `whoami` != root ]; then
		echo "[ERROR] Script must be run as root."
		WE_ARE_SANE=false
	fi
	if [ ! -f /etc/debian_version ]; then
		echo "[ERROR] Is this really a Debian host?"
		WE_ARE_SANE=false
		elif [ ! `grep $DEBIAN_VERSION. /etc/debian_version` ]; then
			echo "[WARNING] Debian version doesn't match ($DEBIAN_VERSION.x)"
			read -p "==> Continue anyway? [Y/n] " REPLY
			case "$REPLY" in
				n|N|No|NO|nO) exit 1 ;;
				*) ;;
			esac
	fi
	if [ "$WE_ARE_SANE" = "false" ]; then
		Error_Handler
	fi
}
Stop_Cruft_Services ()
{
	CURRENT_STEP="stopping superfluous services"
	CRUFT_SERVICES="apache2 bind9 samba sendmail"
	for Cruft_Service in $CRUFT_SERVICES ; do
		/usr/sbin/service $Cruft_Service stop || /usr/sbin/service $Cruft_Service stop || echo "[WARNING] Unable to stop $Cruft_Service service)"
	done
}

Create_Backup_Dir ()
{
	CURRENT_STEP="creating backup directory"
	if [ ! -d "${BACKUP_PATH}" ]; then
		mkdir -p "${BACKUP_PATH}" || Error_Handler
	fi
	CURRENT_STEP="setting perms on backup directory"
	chown root:root "${BACKUP_PATH}" || Error_Handler
	chmod 750 "${BACKUP_PATH}" || Error_Handler
}

Generate_Random_Port ()
{
	if [ -z $SSH_PORT ]; then
		SSH_PORT="`/usr/bin/shuf -i 10000-65000 -n 1`"
	fi
}

Add_Source_List ()
{
	CURRENT_STEP="archiving old '/etc/apt/sources.list'"
	cp -a /etc/apt/sources.list "${BACKUP_PATH}" || Error_Handler
	CURRENT_STEP="applying new '/etc/apt/sources.list'"
	File_apt_sources_list > /etc/apt/sources.list || Error_Handler
}

Get_GPG_Keys ()
{
	CURRENT_STEP="installing GPG keys"
	apt-key adv --recv-keys --keyserver "${GPG_KEYSERVER}" "${GPG_KEYS}" || Error_Handler
}

Install_Aptitude ()
{
	CURRENT_STEP="updating package lists"
	apt-get update || Error_Handler
	CURRENT_STEP="installing aptitude"
	apt-get install -y aptitude || Error_Handler
}

Purge_Cruft ()
{
	CURRENT_STEP="purging cruft packages"
	aptitude purge -y ${PURGE_PKGS} || aptitude purge -y ${PURGE_PKGS} || aptitude purge -y ${PURGE_PKGS} || Error_Handler
}

Update_System ()
{
	CURRENT_STEP="updating package lists"
	aptitude update || Error_Handler
	CURRENT_STEP="updating system packages"
	aptitude full-upgrade -y || aptitude full-upgrade -y || aptitude full-upgrade -y || Error_Handler
}

Install_Standard_Packages ()
{
	CURRENT_STEP="installing standard packages"
	aptitude install -t wheezy-backports -y ${STANDARD_PKGS} || Error_Handler
}

Add_System_Groups ()
{
	for Current_Group in `echo "${ADMIN_SYS_GROUPS}" | sed -n 1'p' | tr ',' '\n' | while read Group; do echo $Group ; done` ; do 
		if [ "`grep -c $Current_Group /etc/group`" -eq "0" ] ; then
			CURRENT_STEP="adding system group '$Current_Group'"
			groupadd -r $Current_Group || Error_Handler
		fi
	done
}

Admin_User_SetVars ()
{
clear
echo "==========================" 
echo "   New admin user setup	"
echo "=========================="
echo
echo -n "Enter new username: "
echo
read -p "==> " Admin_User
	if [ -z ${Admin_User} ] ; then
		echo
		echo '[INFO] This field is mandatory!'
		echo
		read -p 'Press [Enter] key to continue...' PAUSE
		Admin_User_SetVars
		elif [ "`grep -c ${Admin_User} /etc/passwd`" -ge "1" ] ; then
		echo
		echo '[INFO] User already exists!'
		echo
		read -p "==> Change its password? [N/y] " REPLY
		case "$REPLY" in
			y|Y|yes|YES|Yes) passwd ${Admin_User} ;;
			*) ;;
		esac
	fi
echo
echo -n "Enter ${Admin_User}'s full name (optional): "
read -p "==> " Admin_User_name
echo
echo -n "Enter ${Admin_User}'s phone number (optional): "
read -p "==> " Admin_User_phone
echo
echo -n "Enter ${Admin_User}'s email (optional): "
read -p "==> " Admin_User_email
echo
}

Admin_User_CheckVars ()
{
clear
echo "=== You've chosen the following options for your new user:  ==="
echo "Admin's Username : ${Admin_User}"
echo "Full Name        : ${Admin_User_name}"
echo "Phone Number     : ${Admin_User_phone}"
echo "Email            : ${Admin_User_email}"
echo "==============================================================="
echo
read -p "==> Is this OK? [N/y] " REPLY
case "$REPLY" in
y|Y|yes|YES|Yes) echo "" ;;
*) clear ; Admin_User_SetVars ; Admin_User_CheckVars ;;
esac
}

Admin_User_Verify ()
{
	if [ "`grep -c ${Admin_User} /etc/passwd`" -eq "0" ] ; then
		echo "[WARNING] The admin user wasn't added; this step is mandatory."
		read -p "==> Try again? [Y/n] " REPLY
		case "$REPLY" in
			n|N|No|NO|nO) Error_Handler ;;
			*) Add_Admin_User ;;
		esac
	elif [ "`getent shadow | grep '^[^:]*:.\?:' | cut -d: -f1 | grep -c ${Admin_User}`" -ge "1" ] ; then
		echo "[WARNING] The user '${Admin_User}' exists, but has no password!"
		read -p "==> Set one now? [Y/n] " REPLY
		case "$REPLY" in
			n|N|No|NO|nO) Error_Handler ;;
			*) passwd ${Admin_User} ; Admin_User_Verify ;;
		esac
	fi
}

Add_Admin_User ()
{
	CURRENT_STEP="adding new admin user"
        Admin_User_SetVars
        Admin_User_CheckVars
	if [ "`grep -c ${Admin_User} /etc/passwd`" -eq "0" ] ; then
		adduser --gecos "${Admin_User_name},,${Admin_User_phone},${Admin_User_email}" ${Admin_User}
	fi
	Admin_User_Verify
	CURRENT_STEP="adding '${Admin_User}' to '${ADMIN_SYS_GROUPS}'"
        usermod -a -G ${ADMIN_SYS_GROUPS} ${Admin_User} || Error_Handler
}

Lock_Root ()
{
	if [ ${Admin_User} != root ] ; then 
		passwd -lq root || echo "[WARNING] Unable to lock built-in root account!"
	fi
}

Set_Base_Configs ()
{
	#
	# Trivial configs -- warn on failure
	#
	cp -a /etc/issue.net "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/issue.net'"
	File_issue_net > /etc/issue.net || echo "[WARNING] Unable to apply new '/etc/issue.net'"
	cp -a /etc/vim/vimrc "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/vim/vimrc'"
	File_vimrc > /etc/vim/vimrc || echo "[WARNING] Unable to archive old '/etc/vim/vimrc'"
	#
	# Important configs -- abort on failure
	#
        CURRENT_STEP="applying new '/etc/ssh/sshd_config'"
	cp -a /etc/ssh/sshd_config "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/ssh/sshd_config'"
	File_sshd_config > /etc/ssh/sshd_config || Error_Handler
	CURRENT_STEP="applying new '/etc/security/limits.conf'"
	cp -a /etc/security/limits.conf "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/security/limits.conf'"
	File_limits_conf > /etc/security/limits.conf || Error_Handler
	CURRENT_STEP="applying new '/etc/sysctl.conf'"
	cp -a /etc/sysctl.conf "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/sysctl.conf'"
	File_sysctl_conf > /etc/sysctl.conf && sysctl -p -q || Error_Handler
	CURRENT_STEP="applying new '/etc/fail2ban/jail.conf'"
        cp -a /etc/fail2ban/jail.conf "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/fail2ban/jail.conf'"
        File_jail_conf > /etc/fail2ban/jail.conf || Error_Handler
	CURRENT_STEP="adding update script '/usr/local/sbin/apt-up'"
	File_apt_up > /usr/local/sbin/apt-up || echo "[WARNING] Unable to create '/usr/local/sbin/apt-up'"
	chmod 755 /usr/local/sbin/apt-up || echo "[WARNING] Unable to set privileges for '/usr/local/sbin/apt-up'"
	#
	# If using UFW firewall, add OpenVZ-friendly configs
	#
	if [ "`dpkg -l | grep -c ufw`" -ge "1" ] ; then
		CURRENT_STEP="applying UFW firewall configuration"
		cp -a /etc/default/ufw "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/default/ufw'"
		File_UFW_ufw > /etc/default/ufw || Error_Handler
		cp -a /etc/ufw/after.rules "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/ufw/after.rules'"
		File_UFW_after_rules > /etc/ufw/after.rules || Error_Handler
		cp -a /etc/ufw/before.rules "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/ufw/before.rules'"
		File_UFW_before_rules > /etc/ufw/before.rules || Error_Handler
		cp -a /etc/ufw/ufw.conf "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/etc/ufw/ufw.conf'"
		File_UFW_ufw_conf > /etc/ufw/ufw.conf || Error_Handler
		cp -a /lib/ufw/user.rules "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/lib/ufw/user.rules'"
		File_UFW_user_rules > /lib/ufw/user.rules || Error_Handler
                cp -a /lib/ufw/user6.rules "${BACKUP_PATH}" || echo "[WARNING] Unable to archive old '/lib/ufw/user6.rules'"
                File_UFW_user6_rules > /lib/ufw/user6.rules || Error_Handler
	fi
}

Generate_SSH_Stanza ()
{
	echo "[INFO] You can place the following stanza in your ~/.ssh/config:"
	echo
cat <<- _EOF_
Host $HOSTNAME_SHORT $HOSTNAME_FULL
    HostName $IP_ADDRESS
    Port $SSH_PORT
    User $Admin_User
    Compression yes
_EOF_
	echo
}

Reboot_Check ()
{
	echo "[INFO] Some changes require a reboot..."
	read -p "==> Do this now? [Y/n] " REPLY
	case "$REPLY" in
		n|N|No|NO|nO) exit 0 ;;
		*) sync ; reboot ;;
	esac
}

## EXECUTION ##
# Here we call our functions
#####

Sanity_Check
Stop_Cruft_Services
Create_Backup_Dir
Generate_Random_Port
Add_Source_List
Get_GPG_Keys
Install_Aptitude
Purge_Cruft
Update_System
Install_Standard_Packages
Add_System_Groups
Add_Admin_User
Set_Base_Configs
Lock_Root
echo
echo "[SUCCESS] System configuration complete."
echo
Generate_SSH_Stanza
Reboot_Check