#!/bin/sh
#
# Setup freeRADIUS 3 for both EAP-TTLS/PAP and PEAP/MS-CHAPv2 authentication.
#
# Wolfgang Schweer <wschweer@arcor.de>
# First edited: 2020-12-25
# Last edited:  2021-01-11

set -e

DIRNAME="/etc/freeradius/3.0/certs"

# Warn if freeRADIUS has already been configured.
if [ -f $DIRNAME/ca.der ]; then
echo "-------------------------------------------------------------------------"
	echo ""
	echo "The freeRADIUS server seems to have been configured already, exiting."
	echo ""
	echo "If 100% sure freeRADIUS should be configured from scratch again, run:"
	echo ""
	echo "rm -rf /etc/freeradius"
	echo "apt purge freeradius* -yq"
	echo "apt install freeradius freeradius-krb5 -yq"
	echo "Then run this tool again."
	echo ""
echo "-------------------------------------------------------------------------"
	exit 0
fi

# Check execute permission.
if [ ! -d $DIRNAME ] && [ $(id -u) -gt 0 ]; then
	echo "Please run $0 as root or use sudo, exiting."
	exit 0
fi

# Check if required packages are installed.
if [ ! -d $DIRNAME ] ; then
	echo "---------------------------------------------------------------------------------------"
	echo ""
	echo "Make sure the winbind, freeradius and freeradius-krb5 packages are installed, i.e. run:"
	echo "apt update && apt install winbind freeradius freeradius-krb5 -qy"
	echo ""
	echo "---------------------------------------------------------------------------------------"
	exit 0
fi

# Only run on a main server (kdadmin.local and /etc/debian-edu/www are required).
if test -r /etc/debian-edu/config ; then
	. /etc/debian-edu/config
fi
if ! echo "$PROFILE" | grep -q Main-Server ; then
	echo "It only makes sense to run $0 on a main server, exiting."
	exit 0
fi

cd $DIRNAME

# Kerberos principal and keytab setup-
if [ ! -f /etc/krb5.keytab.radius ] ; then
	kadmin.local ank -randkey radius/tjener.intern@INTERN
	kadmin.local ktadd -k /etc/krb5.keytab.radius radius/tjener.intern@INTERN
	chown freerad:freerad /etc/krb5.keytab.radius
fi

# Configure freeRADIUS EAP-TTLS/PAP and PEAP/MS-CHAPv2 authentication.
echo "" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "#--------------------- Debian Edu specific example -------------------------" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "# Uncomment the next two lines to only allow LDAP group 'teachers'." >> /etc/freeradius/3.0/mods-config/files/authorize
echo "#DEFAULT	Group != \"teachers\", Auth-Type := Reject" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "#		Reply-Message = \"Accessing wireless network is not allowed.\"" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "#---------------------------------------------------------------------------" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "# Please don't add anything below the next line!" >> /etc/freeradius/3.0/mods-config/files/authorize
echo "DEFAULT Auth-Type = Kerberos" >> /etc/freeradius/3.0/mods-config/files/authorize

sed -i '/copy_request/ s/no/yes/' /etc/freeradius/3.0/mods-available/eap
sed -i '/use_tunneled/ s/no/yes/' /etc/freeradius/3.0/mods-available/eap

sed -i '/keytab/ s#${localstatedir}/lib/radiusd/keytab#/etc/krb5.keytab.radius#' /etc/freeradius/3.0/mods-available/krb5
sed -i '/service/ s#name_of_principle#radius/tjener.intern#' /etc/freeradius/3.0/mods-available/krb5

sed -i '/request-nt-key/ s#/path/to/ntlm_auth#/usr/bin/ntlm_auth#' /etc/freeradius/3.0/mods-available/mschap
sed -i '/request-nt-key/ s/#/ /' /etc/freeradius/3.0/mods-available/mschap
sed -i '/request-nt-key/ s#nt-key#nt-key --allow-mschapv2#' /etc/freeradius/3.0/mods-available/mschap

sed -i '/pam/  a\
        \
        #\
        # Kerberos Authentication\
        Auth-Type Kerberos {\
                    krb5\
        }' /etc/freeradius/3.0/sites-available/default

sed -i '/pam/  a\
        \
        #\
        # Kerberos Authentication\
        Auth-Type Kerberos {\
                    krb5\
        }' /etc/freeradius/3.0/sites-available/inner-tunnel

# Enable Kerberos module.
cd /etc/freeradius/3.0/mods-enabled

if [ ! -f krb5 ] ; then
	ln -s ../mods-available/krb5 krb5
fi

cd -

# Allow the freerad user to read the Winbind reply and the certificate key file.
/sbin/usermod -a -G winbindd_priv freerad
/sbin/usermod -a -G ssl-cert freerad

service freeradius stop

# Generate freeRADIUS specific CA and server certificates and make them available.
PASSWORD="$(pwgen -1 16)"

update-ini-file ca.cnf           req input_password "${PASSWORD}"
update-ini-file client.cnf       req input_password "${PASSWORD}"
update-ini-file inner-server.cnf req input_password "${PASSWORD}"
update-ini-file server.cnf       req input_password "${PASSWORD}"

update-ini-file ca.cnf           req output_password "${PASSWORD}"
update-ini-file client.cnf       req output_password "${PASSWORD}"
update-ini-file inner-server.cnf req output_password "${PASSWORD}"
update-ini-file server.cnf       req output_password "${PASSWORD}"

update-ini-file ca.cnf           certificate_authority countryName NO
update-ini-file client.cnf       client countryName NO
update-ini-file inner-server.cnf server countryName NO
update-ini-file server.cnf       server countryName NO

update-ini-file ca.cnf           certificate_authority organizationName "Debian Edu"
update-ini-file client.cnf       client organizationName "Debian Edu"
update-ini-file inner-server.cnf server organizationName "Debian Edu"
update-ini-file server.cnf       server organizationName "Debian Edu"

update-ini-file xpextensions     xpclient_ext crlDistributionPoints URI:http://www.intern/intern_ca.crl
update-ini-file xpextensions     xpserver_ext crlDistributionPoints URI:http://www.intern/intern_ca.crl
update-ini-file ca.cnf           CA_default   crlDistributionPoints URI:http://www.intern/intern_ca.crl
update-ini-file ca.cnf           v3_ca        crlDistributionPoints URI:http://www.intern/intern_ca.crl

update-ini-file ca.cnf           certificate_authority emailAddress postmaster@postoffice.intern
update-ini-file inner-server.cnf server emailAddress postmaster@postoffice.intern
update-ini-file server.cnf       server emailAddress postmaster@postoffice.intern

update-ini-file client.cnf       client commonName   user@postoffice.intern
update-ini-file client.cnf       client emailAddress user@postoffice.intern

update-ini-file ca.cnf           certificate_authority commonName '"Debian Edu freeRADIUS Certificate Authority"'
update-ini-file server.cnf       server commonName freeradius.intern

update-ini-file server.cnf       alt_names DNS.1 freeradius.intern

update-ini-file ca.cnf           CA_default default_days 3650
update-ini-file client.cnf       CA_default default_days 3650
update-ini-file inner-server.cnf CA_default default_days 3650
update-ini-file server.cnf       CA_default default_days 3650

update-ini-file inner-server.cnf server commonName '"Debian Edu freeRADIUS Inner Server Certificate"'

grep -q '^[[:blank:]]*subjectAltName[[:blank:]=]' xpextensions || cat >>xpextensions <<'EOF'

subjectAltName = @alt_names

#  This should be a host name of the RADIUS server.
#  Note that the host name is exchanged in EAP *before*
#  the user machine has network access.  So the host name
#  here doesn't really have to match anything in DNS.
[alt_names]
DNS.1 = freeradius.intern

# NAIRealm from RFC 7585
otherName.0 = 1.3.6.1.5.5.7.8.8;FORMAT:UTF8,UTF8:*.intern
EOF

sed -i \
    -e "/^[[:blank:]]*private_key_password[[:blank:]=]/s#=.*#= $PASSWORD#g" \
    -e '/^[[:blank:]]*certificate_file[[:blank:]=]/s#=.*#= /etc/ssl/certs/freeradius-server.crt#g' \
    -e '/^[[:blank:]]*private_key_file[[:blank:]=]/s#=.*#= /etc/ssl/private/freeradius-server.key#g' \
    -e '/^[[:blank:]]*ca_file[[:blank:]=]/s#=.*#= /etc/ssl/certs/freeradius-ca.crt#g' \
    ../mods-available/eap

sh ./bootstrap

chmod 644 dh server.crt server.pem ca.pem ca.der
chmod 640 server.key
cp ca.pem /etc/ssl/certs/freeradius-ca.crt
cp server.crt /etc/ssl/certs/freeradius-server.crt
cp server.key /etc/ssl/private/freeradius-server.key
chown root:ssl-cert /etc/ssl/private/freeradius-server.key

if [ -d /etc/debian-edu/www/ ] ; then
	cp ca.der /etc/debian-edu/www/freeradius-ca.der
	cp ca.pem /etc/debian-edu/www/freeradius-ca.pem
	cp ca.pem /etc/debian-edu/www/freeradius-ca.crt
fi

# Cleanup the certs dir.
make clean

# Start the configured freeRADIUS service and give some feedback.
service freeradius start

echo "------------------------------------------------------------------------------------"
echo "The freeRADIUS server has been configured."
echo ""
echo "Both CRT and DER encoded freeRADIUS CA certificates are available for download:"
echo "https://www.intern/freeradius-ca.pem (for end user devices running Linux)."
echo "https://www.intern/freeradius-ca.crt (Linux, Android and Windows)."
echo "https://www.intern/freeradius-ca.der (macOS, iOS, iPadOS and Windows)."
echo ""
echo "For simple site-specific configuration adjustments, see"
echo "/etc/freeradius/3.0/users        [allow/deny wireless using LDAP groups]"
echo "/etc/freeradius/3.0/huntgroups   [combine access points (APs) into dedicated groups]"
echo "/etc/freeradius/3.0/clients.conf [enable/disable APs via shared secret]"
echo ""
echo "------------------------------------------------------------------------------------"
