Introduction (802.1x dual authentication)
This post describes a solution that I have hacked together to get our Linux laptops (RHEL6, RHEL7, Fedora) to connect to an Aruba wireless network which requires that wireless clients must perform both "Computer authentication" and "User authentication" before they are allowed full access. Both the client machine and the user are part of a kerberos realm (eg Active Directory). In this example, the wireless network's SSID will be "LINUK-WLAN".
It's straightforward to configure Windows clients to authenticate in this way, but the mechanism is not yet supported in Linux. There is a Red Hat bugzilla RFE to add support for this: https://bugzilla.redhat.com/show_bug.cgi?id=1129811
Stage 1/
- The client machine performs "Computer authentication" to the controller using WPA2-Enterprise and PEAP.
- The username is the kerberos principal name for the machine account, eg "host/dhu.linuk.local"
This is the fully qualified hostname prefixed with "host/" - The password is the machine password, which is a random 32 digit string
(In AD, machine passwords are never forcibly expired but by default the client attempts to reset it's own password every 30 days.)
- The username is the kerberos principal name for the machine account, eg "host/dhu.linuk.local"
- If the machine authenticates correctly, then the wireless controller adds it to a table of machines that have passed the first stage of authentication.
At this point the wireless controller normally allows some limited access to the network, this may include access to DNS, LDAP etc.
Stage 2/
- The client now re-authenticates to the same network, this time using WPA2-Enterprise and PEAP.
- The username is the user principal name, eg "LINUK\jbloggs"
- The password is the user's password
- If this authentication is successful, AND the client has successfully passed machine authentication, then the machine is granted full access to the network.
How does Windows do this?
Stage 1 "Computer authentication" is carried out before user logon.
If you go to the wireless network properties -> Security tab -> and choose "Adanced Settings" you should see an option to select "User or computer authentication".The system should now perform Computer authentication the user has logged on.
Stage 2 "User authenticaton" is carried out when a user logs into the machine.
If you go to the wireless network properties -> Security tab -> Choose "PEAP" and click "Settings" -> Choose "EAP-MSCHAP v2" and click "Configure"
You'll see there is a tickbox for "Automatically use my Windows logon name and password".
How can we do it on Linux?
In our case, the machines are joined to Active Directory using Dell's Quest Authentication Services software. In the section below we use some of the quest utilities to gather useful information.
For client machines that are joined to their authentication realms with other software (such as sssd), I imagine that alternative commands could be used. However time constraints have stopped me looking into this.
For stage 1:
- We can figure out the client's principal name by looking at:
/opt/quest/bin/vastool ktutil list
- We can't find out the current machine password, but we can reset it and print the newly generated one to stdout.
To do this join the corporate network and run:/opt/quest/bin/vastool -q -u host/ passwd -r -o
- We can try to find out our user name and domain with something like:
/opt/quest/bin/vastool list user $(whoami) | cut -f1 -d:
- The password is our user's normal password
How can we automate this a little better on Linux?
- Configure stage 1 (computer auth) to happen automatically on boot
- When the machine password is updated, capture the new password and update the wireless config
- Have a script to automatically configure the a user profile which can perform user auth.
I have written a script to set this up. Here's a high-level description of what it does:
- Hooks into the Quest password change script so that changes to the machine password are captured
- Enables wpa_supplicant to start on boot
- Configures wpa_supplicant to authenticate to our network with the machine name and password
- Creates a NetworkManager profile for the user which connects with their own username to perform the second authentication
- The user must then keep their own password up to date in the NetworkManager profile
A bit more detail about the scripts/files in our solution
For ease of deployment, the files are the same across all OS platforms. However the scripts themselves are platform aware and operate differently depending on the OS version.
I'll include copies of the scripts below in case they are of use to anyone. It's extremely unlikely that these scripts will work in another environment without some significant customisation. I've anonymised the scripts, and invented the imaginary domain "linuk.local".
First, here's a brief outline of the files required:
- /usr/local/bin/linukwlan-setup
This is the script run by the user to configure their laptop for LINUK-WLAN. It does the user configuration, such as creating the NetworkManager profile. It also runs /usr/local/sbin/linukwlan-machine-setup using sudo.
- /usr/local/sbin/linukwlan-machine-setup
This file is pushed with our custom rsync script.
This script is run as root using sudo as part of /usr/local/bin/linukwlan-setup. It carries out the configuration of the system files. This includes configuring wpa_supplicant, and checking that our machine password change hooks are in place.
- /etc/opt/quest/vas/vas.conf
This file is not edited by us directly. However group policy configures the following parameter "password-change-script" so that machine password changes are captured and piped to: /usr/local/sbin/update-machine-password
- /usr/local/sbin/update-machine-password
This file is pushed with our custom rsync script.
It receives the monthly machine password changes from vas (Quest), writes them out to a file and then passes the change on to any other interested parties (eg samba).
- /etc/opt/quest/vas/admachinepassword
This file contains a copy of the machine password (this is the file written out by /usr/mlocal/sbin/update-machine-password above)
- /etc/sudoers.d/03linukwlan
This file is pushed with our custom rsync script. It allows regular users to run /usr/local/sbin/ionwlan-machine-setup with root privileges.
- /etc/wpa_supplicant/wpa_supplicant.conf
This file is written out by the /usr/local/sbin/linukwlan-machine-setup script. It contains the configuration for wpa_supplicant so that it can perform computer authorisation. This file is also updated by /usr/local/sbin/update-machine-password every time the machine password changes.
- /etc/sysconfig/wpa_supplicant
This file is written out by the /usr/local/sbin/linukwlan-machine-setup script. The INTERFACES line needs to be modified to include your wireless interface. Remember to also ensure that the wpa_supplicant service is set to run on boot.
Copies of the scripts/files
/etc/sudoers.d/03linukwlan
/usr/local/sbin/update-machine-password
/usr/local/sbin/linukwlan-machine-setup
/usr/local/bin/linukwlan-setup
/etc/wpa_supplicant/wpa_supplicant.conf
/etc/sysconfig/wpa_supplicant
##########################################################
# linuk sudoers include file #
# #
# These options are required for the LINUK-WLAN setup #
# script to work. #
# #
##########################################################
# Create an alias for LINUK-WLAN commands
Cmnd_Alias LINUKWLAN=/usr/local/sbin/linukwlan-machine-setup
# Do not require a TTY
Defaults!LINUKWLAN !requiretty
# Don't require a password for these commands
%lingroup ALL=NOPASSWD:LINUKWLAN
/usr/local/sbin/update-machine-password
#!/bin/bash
#
SAMBASCRIPT=/opt/quest/libexec/vas-set-samba-password
WPACONF=/etc/wpa_supplicant/wpa_supplicant.conf
MPASSFILE=/etc/opt/quest/vas/admachinepassword
function log { logger -s -p user.info -t update-machine-password $@; }
function loge { logger -s -p user.warning -t update-machine-password $@; }
umask 007 # u=rwx,g=,o=
while read STDIN; do
MPASS="$STDIN"
# Annoyingly, tee doesn't write out the file if the pipe fails
# (ie if the Quest samba script doesn't exist)
if [[ -x $SAMBASCRIPT ]]; then
echo $STDIN | tee $MPASSFILE | $SAMBASCRIPT
else
echo $STDIN > $MPASSFILE
fi
done
# Check PW
log "Received new machine password"
if [[ ${#MPASS} -ne 32 ]]; then
loge "Error: New machine password is not correct length"
exit 1
fi
# Figure out name
SPNS=$(/opt/quest/bin/vastool ktutil list | egrep -o "host/$(hostname)\.[a-z]{3,}\.local" | sort | uniq)
NUMSPNS=$(echo "$SPNS" | grep -c '^')
if [[ $NUMSPNS -eq 1 ]]; then
MNAME="$SPNS"
log "Using machine name: $MNAME"
elif [[ $NUMSPNS -gt 1 ]]; then
loge "Error: Found multiple conflicting machine names"
else
loge "Error: Could not find machine name"
fi
# Does conf file exist?
if ! [[ -f $WPACONF ]]; then
loge "Error: File $WPACONF does not exist"
# Does conf file look correct?
elif ! grep -q 'ssid="LINUK-WLAN"' $WPACONF || ! egrep -q 'identity="host/.*.linuk.local"' $WPACONF || ! grep -q 'password=".*"' $WPACONF; then
loge "Error: File $WPACONF hasn't yet been set up by linukwlan-setup (or the expected format has been corrupted)"
# Carry out update
else
MPASSSAFE=$(echo $MPASS | sed -e 's/[\/&]/\\&/g')
MNAMESAFE=$(echo $MNAME | sed -e 's/[\/&]/\\&/g')
if sed -i -e "s/identity=\".*\"/identity=\"${MNAMESAFE}\"/" -e "s/password=\".*\"/password=\"${MPASSSAFE}\"/" $WPACONF; then
log "Updated machine name and password in $WPACONF"
else
loge "Error: Failed to update machine name or password in $WPACONF"
fi
fi
/usr/local/sbin/linukwlan-machine-setup
#!/bin/bash
#
#
MACHINEPWSCRIPT=/usr/local/sbin/update-machine-password
MACHINEPWFILE=/etc/opt/quest/vas/admachinepassword
VASCONF=/etc/opt/quest/vas/vas.conf
WPACONF=/etc/wpa_supplicant/wpa_supplicant.conf
WPASYSCONF=/etc/sysconfig/wpa_supplicant
DEFAULTIF=wlan0
IFOVERRIDEFILE=/usr/mlocal/etc/linukwlan-interface
OFF="\033[0m"; GREEN="\033[0;32m"; RED="\033[0;31m"; ORANGE="\033[0;33m"; BOLD="\033[1m"
#Check okay
function co {
echo -e "[ ${GREEN}OK${OFF} ] $@"
}
#Check fail
function cf {
echo -e "[${RED}FAIL${OFF}] $@"
if ! [ $CHECKONLY ]; then
echo -e "\nPlease contact IT support and include the output of this script. Contact details:\n"
exit 1
fi
}
#Check warn
function cw {
echo -e "[${ORANGE}WARN${OFF}] $@"
}
#Check info
function ci {
echo -e "[....] $@"
}
# Check command line arguments
if [[ "$1" == "-mp" ]]; then
if /opt/quest/bin/vastool -q -u host/ passwd -r -o | /usr/local/sbin/update-machine-password; then
co "Machine password updated. Try re-running the linukwlan-setup script."
exit 0
else
cf "There was a problem updating the machine password file."
fi
elif [[ "$1" == "-c" ]]; then
# We are in check only mode
CHECKONLY=YES
else
:
fi
# Check for pcre/pcre-tools (we use pcregrep)
if grep -q "release 6" /etc/redhat-release; then
PACKAGE=pcre
else
PACKAGE=pcre-tools
fi
if rpm -q $PACKAGE &>/dev/null; then
co "$PACKAGE package is installed"
else
cf "This script requires the $PACKAGE package to be installed"
fi
# Check vas.conf is configured for machine pw script
# This configuration should be pushed by group policy
if egrep -q "^\s+password-change-script = $MACHINEPWSCRIPT" $VASCONF; then
co "Machine password change hook in config file $VASCONF looks okay"
else
cf "Machine password change hooks in config file $VASCONF look incorrect. Is the machine in the right AD container? Has group policy been applied?"
fi
# Check machine pw script is present
# This should be pushed in the /usr/local tree
if [[ -x $MACHINEPWSCRIPT ]]; then
co "File $MACHINEPWSCRIPT exists"
else
cf "File $MACHINEPWSCRIPT does not exist"
fi
# Figure out our hostname
if [[ $(/opt/quest/bin/vastool ktutil list | pcregrep -o 'host/[\w\-\_]+\.[\w\.\-\_]+' | uniq | wc -l) -eq 1 ]]; then
MACHINENAME=$(/opt/quest/bin/vastool ktutil list | pcregrep -o 'host/[\w\-\_]+\.[\w\.\-\_]+' | uniq)
co "The name of our machine account is: $MACHINENAME"
else
cf "We failed to establish the name of our machine account"
fi
# Check that the machine password file exists, has been updated within 90 days, and looks valid
if [[ -f $MACHINEPWFILE ]]; then
co "Machine password file exists"
else
cf "Machine password file does not exist. You could try to fix this by connecting to the LINUK network, waiting a few minutes, then running \"linukwlan-setup -mp\""
fi
if [[ $(find $MACHINEPWFILE -mtime -30) ]]; then
co "Machine password file < 30 days old"
else
cw "Machine password file > 30 days old. This may not be a problem. You could try to fix this by connecting to the LINUK network, waiting a few minutes, then running \"linukwlan-setup -mp\""
fi
MACHINEPW=$(cat $MACHINEPWFILE)
if [[ ${#MACHINEPW} -eq 32 ]]; then
co "The machine password looks like the correct format"
else
cf "The machine password is not in a valid format"
fi
# Check wpa_supplicant is configured with our network
if [[ $(egrep -c "^\s?network" $WPACONF) -gt 1 ]]; then
# Mutiple configs
cf "There are multiple network configurations in $WPACONF"
elif [[ $(egrep -c "^\s?network" $WPACONF) -eq 1 ]]; then
# One config
if pcregrep -qM 'network={[\n\s]*ssid="LINUK-WLAN"[\n\s]*scan_ssid=1[\n\s]*key_mgmt=WPA-EAP[\n\s]*eap=PEAP[\n\s]*identity="host/[\w\.]*"[\n\s]*password=".{32}"[\n\s]*phase2="auth=MSCHAPV2"[\n\s]*}' $WPACONF; then
co "There's a network configuration for LINUK-WLAN in $WPACONF with valid syntax"
elif egrep -q 'ssid="LINUK-WLAN"' $WPACONF; then
cw "There's a configuration for LINUK-WLAN in $WPACONF, but it might not be valid"
fi
# Check that parameters are correct
if fgrep -q "identity=\"${MACHINENAME}\"" $WPACONF && fgrep -q "password=\"${MACHINEPW}\"" $WPACONF; then
co "Machine name and password are up to date in $WPACONF"
else
cw "Machine name and/or password are out of date in ${WPACONF}"
if ! [[ $CHECKONLY ]]; then
ci "Attempting to update machine name and password in $WPACONF"
MACHINEPWSAFE=$(echo $MACHINEPW | sed -e 's/[\/&]/\\&/g')
MACHINENAMESAFE=$(echo $MACHINENAME | sed -e 's/[\/&]/\\&/g')
sed -i -e "s/identity=\".*\"/identity=\"${MACHINENAMESAFE}\"/" -e "s/password=\".*\"/password=\"${MACHINEPWSAFE}\"/" $WPACONF
if fgrep -q "identity=\"${MACHINENAME}\"" $WPACONF && fgrep -q "password=\"${MACHINEPW}\"" $WPACONF; then
co "Successfully updated machine name and password in $WPACONF"
else
cf "Failed to update machine name and password in $WPACONF"
fi
fi
fi
else
# No config
if ! [[ $CHECKONLY ]]; then
# Let's try to configure
ci "Attempting to configure LINUK-WLAN network in $WPACONF"
echo "
# Network added by $0 at $(date)
network={
ssid=\"LINUK-WLAN\"
scan_ssid=1
key_mgmt=WPA-EAP
eap=PEAP
identity=\"$MACHINENAME\"
password=\"$MACHINEPW\"
phase2=\"auth=MSCHAPV2\"
}" >> $WPACONF
# Check our new config took correctly
if pcregrep -qM 'network={[\n\s]*ssid="LINUK-WLAN"[\n\s]*scan_ssid=1[\n\s]*key_mgmt=WPA-EAP[\n\s]*eap=PEAP[\n\s]*identity="host/[\w\.]*"[\n\s]*password=".{32}"[\n\s]*phase2="auth=MSCHAPV2"[\n\s]*}' $WPACONF; then
co "Successfully configured LINUK-WLAN network in $WPACONF"
else
cf "Failed to configure LINUK-WLAN network in $WPACONF"
fi
else
cf "There is no network configuration for LINUK-WLAN in $WPACONF"
fi
fi
# Find our wireless interface, and check that it's configured in wpa_supplicant
# Check if there's a manually configured interface
MANIF=$(cat $IFOVERRIDEFILE 2>/dev/null)
if echo $MANIF | egrep -q "^\w+$"; then
IF=$MANIF
co "We're manually configured to use interface: $IF \n This is configured in $IFOVERRIDEFILE"
else
# There's no manual config, try to figure out the wireless interface
IFSOAB=$(/sbin/ifconfig -a | sed -n "s/^\(wl\w*\).*/\1/p")
NUMIFS=$(echo $IFSOAB | grep -v "^$" | grep -c ^)
if [[ $NUMIFS -eq 1 ]]; then
IF=$IFSOAB
co "Found a wireless interface: $IF"
elif [[ $NUMIFS -eq 0 ]]; then
cw "Could not find a wireless interface.\n If it's a non-standard name then you should configure it in $IFOVERRIDEFILE"
SKIPWIRELESS=1
elif [[ $NUMIFS -gt 1 ]]; then
IF=$(echo "$IFSOAB" | head -n1)
cw "Warning, found multiple wireless interfaces! Using first interface: $IF \n You can override this in $IFOVERRIDEFILE"
else
cf "Something has gone spectacularly badly wrong here"
fi
fi
if ! [ $SKIPWIRELESS ]; then
# Check the interface exists
if /sbin/ifconfig $IF &>/dev/null; then
co "Wireless interface $IF exists"
else
cf "Wireless interface $IF does not exist"
fi
# Check wpa_supplicant is configured for our interface
if egrep -q "^INTERFACES=\"\-i ?$IF\"" $WPASYSCONF; then
co "Wireless interface \"$IF\" is configured in $WPASYSCONF"
elif ! [[ $CHECKONLY ]]; then
ci "Attempting to configure $WPASYSCONF with wireless interface: $IF"
sed -i "s/^INTERFACES=\"\"/INTERFACES=\"-i$IF\"/" $WPASYSCONF
if egrep -q "^INTERFACES=\"\-i ?$IF\"" $WPASYSCONF; then
co "Wireless interface $IF is now configured in $WPASYSCONF"
else
cf "Failed to configure $WPASYSCONF with wireless interface: $IF"
fi
else
cf "Wireless interface $IF is not configured in $WPASYSCONF"
fi
# Is interface up?
if /sbin/ifconfig | egrep -q "^$IF"; then
co "Wireless interface $IF is up"
else
cw "Wireless interface $IF is down. Is the wireless switch off?"
fi
fi
# Check wpa_supplicant is enabled
if grep -q "release 6" /etc/redhat-release; then
#RHEL6 (chkconfig)
if /sbin/chkconfig --list wpa_supplicant | grep -q "5:on"; then
co "wpa_supplicant service is enabled for start at runlevel 5"
else
#ci "Attempting to enable wpa_supplicant service at runlevel 5"
if chkconfig wpa_supplicant on &>/dev/null && chkconfig --list wpa_supplicant | grep -q "5:on"; then
co "Successfully enabled wpa_supplicant service for start at runlevel 5"
else
cf "Failed to enable wpa_supplicant service for start at runlevel 5"
fi
fi
else
#Other OS (systemctl)
if systemctl is-enabled wpa_supplicant &>/dev/null; then
co "wpa_supplicant service is enabled at system boot"
else
if systemctl enable wpa_supplicant.service &>/dev/null && systemctl is-enabled wpa_supplicant &>/dev/null; then
co "Successfully enabled wpa_supplicant for start at system boot"
else
cf "Failed to enable wpa_supplicant service for start at system boot"
fi
fi
fi
# Crude check to see if we've authenticated
if grep -q "EAP-MSCHAPV2: Authentication succeeded" /var/log/wpa_supplicant.log; then
co "Looks like we've probably already performed machine auth"
else
cw "Doesn't look like we've performed machine auth. A reboot is required!"
exit 2
fi
exit 0
/usr/local/bin/linukwlan-setup
#!/bin/bash
#
# Usage:
#
# linukwlan-setup Normal mode. This will attempt to set up the system and user
# profile for connection to LINUK-WLAN
#
# linukwlan-setup -c Check-only mode. This will report problems with the setup, but
# not fix them.
#
# linukwlan-setup -r Remove/repair mode. This will remove any existing NetworkManager
# profiles for LINUK-WLAN and recreate them. It will also carry out
# the system setup
#
# linukwlan-setup -mp Machine password mode. This will attempt to reset the machine
# password in AD, then exit.
#
#
MACHINESCRIPT=/usr/local/sbin/linukwlan-machine-setup
OFF="\033[0m"; GREEN="\033[0;32m"; RED="\033[0;31m"; ORANGE="\033[0;33m"; BOLD="\033[1m"
#Check okay
function co {
echo -e "[ ${GREEN}OK${OFF} ] $@"
}
#Check fail
function cf {
echo -e "[${RED}FAIL${OFF}] $@"
if ! [ $CHECKONLY ]; then
echo -e "\nPlease contact IT support and include the output of this script. Contact details: blah blah\n"
exit 1
fi
}
#Check warn
function cw {
echo -e "[${ORANGE}WARN${OFF}] $@"
}
#Check info
function ci {
echo -e "[....] $@"
}
# Process command line arguments
while [ $# -gt 0 ]; do
case $1 in
"-c" | "--check") CHECKONLY=YES; echo Check only mode; shift 1 ;;
"-r" | "--removify") REMOVIFY=OHYES; echo Removify mode; shift 1 ;;
"-d" | "--debug") DEBUG=HELLYES; echo Debug mode; shift 1 ;;
"-mp" | "--machine-password") echo Fix machine password mode; sudo $MACHINESCRIPT -mp; exit 0 ;;
*) echo -e "Unrecognised argument $1"; exit 1 ;;
esac
done
# Don't be running as rooty toot
if [[ $UID -ne 0 ]]; then
co "Currently running as normal user"
else
cf "You must run this script as yourself, not root"
fi
echo -e "\n${BOLD}LINUK-WLAN setup (machine config)${OFF}"
# OS Check
if egrep -q "Fedora release 2[12]|Red Hat Enterprise Linux Workstation release 7" /etc/redhat-release; then
co "Operating system supported"
# NetworkManager profiles are stored directly by NM"
elif egrep -q "Red Hat Enterprise Linux Workstation release 6|CentOS Linux release 6" /etc/redhat-release; then
co "Operating system supported"
GCONFMODE=yes
# NetworkManager profiles are stored in gconf"
else
cf "Operating system not supported"
fi
# Check that the machine script is present
# This should be distributed in /usr/local
if [[ -f $MACHINESCRIPT ]]; then
co "File $MACHINESCRIPT exists"
else
cf "File $MACHINESCRIPT does not exist\n Has /usr/local been synced to the laptop correctly?"
fi
# Check that we can run with sudo
# There should be an entry in sudoers (files pushed by group policy)
if sudo -l | grep $MACHINESCRIPT &>/dev/null; then
co "We can run $MACHINESCRIPT using sudo"
else
cf "We can't run $MACHINESCRIPT using sudo\nHave group policies been applied? Is the machine in the correct AD container?"
fi
# Run the machine setup check
if sudo $MACHINESCRIPT ${CHECKONLY+-c}; then
co "$MACHINESCRIPT completed successfully"
elif [[ $? -eq 2 ]]; then
REBOOT=needed
co "$MACHINESCRIPT completed successfully"
else
exit 1
fi
echo -e "\n${BOLD}LINUK-WLAN setup (user config)${OFF}"
# Figure out what username to use (required for checking and creating profiles)
# We also need to know what domain they're in, but we're probably off the LAN.
# To find out we can try to use Quest's user cache...
DOMAINUSER=$(/opt/quest/bin/vastool list users | sed -ne 's/\([A-Z]\+\\'$(whoami)'\):.*/\1/p')
if ! egrep -q '^[A-Z]*\\'$(whoami)'$' <<<$DOMAINUSER; then
cf "ERROR: Could not find the user \"$(whoami)\" in the Quest user cache.
Is this machine joined to Quest?
Are you running the script as your own user?"
else
co "Found user \"$(whoami)\" in the Quest user cache."
fi
# Check that we will be able to configure the profiles
if [ $GCONFMODE ]; then
ci "On this OS, NetworkManager profiles are stored in gconf"
# Basic sanity check that we can see our gconf tree
if gconftool-2 --dir-exists /system; then
co "We can see /system in gconf"
else
cf "We can't see /system in gconf"
fi
else
ci "On this OS, NetworkManager profiles are stored directly (no gconf)"
# polkit only allows local (not SSH) users to modify NM connections
# You can change this by creating a custom polkit rule.
if [ "$SSH_CLIENT" ]; then
cw "Looks like you're logged in through SSH, so polkit will not allow you to modify the NM config."
else
co "You are logged into the console, so you will be able to modify the NM config."
fi
fi
# Function to check for existing profiles
function check_profiles {
COUNT=0
if ! [ $GCONFMODE ]; then
while read CONN; do
CONNDUMP=$(nmcli conn show "$CONN")
# Count profiles for SSID LINUK-WLAN
if check_param2 "802-11-wireless.ssid:\s*LINUK-WLAN"; then
((COUNT++))
fi
done <<<"$(nmcli --fields NAME conn show | grep -v NAME)"
else
for CONN in $(gconftool-2 --all-dirs /system/networking/connections | xargs); do
if gconftool-2 -R $CONN | grep -q "ssid = \[76,73,78,85,75,45,87,76,65,78\]"; then
((COUNT++))
fi
done
fi
if [[ $COUNT -gt 1 ]]; then
cw "We found $COUNT existing profiles for SSID \"LINUK-WLAN\""
return 2
elif [[ $COUNT -eq 1 ]]; then
co "We found $COUNT existing profile for SSID \"LINUK-WLAN\""
return 1
else
co "We found $COUNT existing profiles for SSID \"LINUK-WLAN\""
return 0
fi
}
# Internal helper function for checking gconf values
function check_param {
[[ $3 ]] && GREPFLAG="-E" || GREPFLAG="-F"
if ! gconftool-2 --get "$1" 2>/dev/null | grep $GREPFLAG -q "$2"; then
((ERRORCOUNT++))
[[ $DEBUG ]] && echo -e "-- DEBUG -----\ngconftool-2 --get \"$1\" = $(gconftool-2 --get "$1")\nFailed to match against grep $GREPFLAG \"$2\"\n--------------"
return 1
else
return 0
fi
}
# Internal helper function for checking NetworkManager config
function check_param2 {
[[ "$2" == "-i" ]] && GREPFLAG="-i"
if ! echo $CONNDUMP | egrep $GREPFLAG -q "$1"; then
((ERRORCOUNT++))
[[ $DEBUG ]] && echo -e "check_param2: $CONN failed to match \"egrep $GREPFLAG -q \"$1\"\""
return 1
else
return 0
fi
}
# Function to attempt removal of all profiles
function remove_all_profiles {
COUNT=0
if ! [ $GCONFMODE ]; then
while read CONN; do
CONNDUMP=$(nmcli conn show "$CONN")
# Only remove profiles for SSID LINUK-WLAN
if check_param2 "802-11-wireless.ssid:\s*LINUK-WLAN"; then
if nmcli conn delete "$CONN"; then
((COUNT++))
else
cw "Failed to remove profile: $CONN"
fi
fi
done <<<"$(nmcli --fields NAME conn show | grep -v NAME)"
else
for CONN in $(gconftool-2 --all-dirs /system/networking/connections | xargs); do
if check_param "$CONN/802-11-wireless/ssid" "[76,73,78,85,75,45,87,76,65,78]"; then
ci "Removing profile $CONN ($(gconftool-2 --get "$CONN/connection/id"))"
UUID=$(gconftool-2 --get "$CONN/connection/uuid")
gconftool-2 --unset "/apps/nm-applet/ignore-ca-cert/$UUID"
if ! gconftool-2 --recursive-unset "$CONN"; then
cw "Failed to remove profile: $CONN"
else
((COUNT++))
fi
fi
done
fi
ci "$COUNT profile(s) removed"
}
# Function to perform detailed check of existing profiles
function check_profiles_detailed {
if ! [ $GCONFMODE ]; then
while read CONN; do
CONNDUMP=$(nmcli conn show "$CONN")
# Only check profiles for SSID LINUK-WLAN
if check_param2 "802-11-wireless.ssid:\s*LINUK-WLAN"; then
ci "Checking profile: $CONN"
ERRORCOUNT=0
check_param2 "connection.type:\s*802-11-wireless"
check_param2 "connection.interface-name:\s*--"
check_param2 "802-11-wireless.mode:\s*infrastructure"
check_param2 "802-11-wireless-security.key-mgmt:\s*wpa-eap"
check_param2 "802-1x.eap:\s*peap"
SAFEDOMAINUSER=${DOMAINUSER/\\/\\\\} # Replace single backslash with double backslash for use in the impending regex
check_param2 "802-1x.identity:\s*"${SAFEDOMAINUSER-nobody}"" "-i"
check_param2 "802-1x.phase2-auth:\s*mschapv2"
if [[ $ERRORCOUNT -eq 0 ]]; then
co "Profile \"$CONN\" looks correct!\n Nevertheless, if you wish to remove all existing LINUK-WLAN profiles and\n create a new one from scratch then run this script with the \"-r\" flag."
else
[[ $DEBUG ]] && echo "To view profile, try: "
cf "Profile \"$CONN\" looks incorrect!\n You could try removing all existing LINUK-WLAN profiles and creating one from scratch.\n To do this, run this script with the \"-r\" flag."
fi
fi
done <<<"$(nmcli --fields NAME conn show | grep -v NAME)"
else
# Loop through all NM connections
for CONN in $(gconftool-2 --all-dirs /system/networking/connections | xargs); do
# Only check profiles for SSID LINUK-WLAN
if check_param "$CONN/802-11-wireless/ssid" "[73,79,78,45,87,76,65,78]"; then
ci "Checking: $CONN ($(gconftool-2 --get "$CONN/connection/id"))"
ERRORCOUNT=0
check_param "$CONN/802-11-wireless-security/name" "802-11-wireless-security"
check_param "$CONN/802-11-wireless-security/key-mgmt" "wpa-eap"
check_param "$CONN/802-11-wireless-security/group" "[tkip,ccmp]"
check_param "$CONN/802-1x/name" "802-1x"
check_param "$CONN/802-1x/phase2-auth" "mschapv2"
check_param "$CONN/802-1x/eap" "[peap]"
check_param "$CONN/802-1x/identity" "${DOMAINUSER-nobody}"
check_param "$CONN/connection/type" "802-11-wireless"
check_param "$CONN/connection/name" "connection"
check_param "$CONN/connection/uuid" "[a-z0-9\-]{32}" "-E"
check_param "$CONN/connection/id" "LINUK-WLAN (User auth)"
check_param "$CONN/802-11-wireless/name" "802-11-wireless"
check_param "$CONN/802-11-wireless/mode" "infrastructure"
check_param "$CONN/802-11-wireless/ssid" "[76,73,78,85,75,45,87,76,65,78]"
check_param "$CONN/802-11-wireless/security" "802-11-wireless-security"
PARAMCOUNT=$(gconftool-2 -R $CONN | egrep -v "seen-bssids|timestamp" | wc -l)
if [[ $PARAMCOUNT -eq 19 ]] && [[ $ERRORCOUNT -eq 0 ]]; then
co "Profile looks correct!\n Nevertheless, if you wish to remove all existing LINUK-WLAN profiles and\n create a new one from scratch then run this script with the \"-r\" flag."
else
[[ $DEBUG ]] && echo "To view profile, try: gconftool-2 -R $CONN"
cf "Profile looks incorrect! ($PARAMCOUNT/$ERRORCOUNT)\n We could try removing all existing LINUK-WLAN profiles and creating one from scratch.\n To do this, run this script with the \"-r\" flag."
fi
fi
done
fi
}
# Function to create a new profile from scratch
function create_new_profile {
ci "Creating a new NM profile for SSID \"LINUK-WLAN\""
if ! [ $GCONFMODE ]; then
# In RHEL7 we can add the connection directly using NM (which is quite nice actually)
if nmcli connection add con-name "LINUK-WLAN (User auth)" type 802-11-wireless ifname '*' ssid LINUK-WLAN mode infrastructure && nmcli connection modify "LINUK-WLAN (User auth)" 802-1x.eap peap 802-1x.identity "${DOMAINUSER-nobody}" 802-1x.phase2-auth mschapv2 802-1x.password-flags 1 802-11-wireless-security.key-mgmt wpa-eap connection.permissions "user:$(whoami)" ; then
co "Profile was added successfully"
else
cf "There was a problem adding the new profile"
fi
else
# In RHEL6 we can't add the connection using NM, so we have to edit gconf directly.
# Figure out the path we should use for our new profile
EXISTING_PROFILES=$(gconftool-2 --all-dirs /system/networking/connections)
# Check for existing profiles
if [[ -z $EXISTING_PROFILES ]]; then
NEW_PROFILE=1
else
LAST_PROFILE=$(echo "$EXISTING_PROFILES" | cut -f5 -d"/" | sort -n | tail -n1)
if [[ $LAST_PROFILE =~ ^[0-9]+$ ]]; then
NEW_PROFILE=$(( LAST_PROFILE + 1 ))
else
echo "ERROR: Couldn't figure out path for new profile creation."
exit 1
fi
fi
# Generate our UUID
RAN=$(cat /dev/urandom | tr -dc 'a-f0-9' | head -c 32)
UUID=${RAN:0:8}-${RAN:8:4}-${RAN:12:4}-${RAN:16:4}-${RAN:20:12}
if gconftool-2 -R /system/networking | grep -q $UUID; then
echo "ERROR: If you're reading this then God is playing tricks on you"
exit 1
fi
#Create new location
BASE_LOCATION=/system/networking/connections/$NEW_PROFILE
#gconf commands
COMMANDBLOCK=$(cat <<'END_HEREDOC'
gconftool-2 --set "$BASE_LOCATION/802-11-wireless-security/name" --type string "802-11-wireless-security"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless-security/key-mgmt" --type string "wpa-eap"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless-security/group" --type list --list-type string "[tkip,ccmp]"
gconftool-2 --set "$BASE_LOCATION/802-1x/name" --type string "802-1x"
gconftool-2 --set "$BASE_LOCATION/802-1x/phase2-auth" --type string "mschapv2"
gconftool-2 --set "$BASE_LOCATION/802-1x/eap" --type list --list-type string "[peap]"
gconftool-2 --set "$BASE_LOCATION/802-1x/identity" --type string "$DOMAINUSER"
gconftool-2 --set "$BASE_LOCATION/connection/type" --type string "802-11-wireless"
gconftool-2 --set "$BASE_LOCATION/connection/name" --type string "connection"
gconftool-2 --set "$BASE_LOCATION/connection/uuid" --type string "$UUID"
gconftool-2 --set "$BASE_LOCATION/connection/id" --type string "LINUK-WLAN (User auth)"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless/name" --type string "802-11-wireless"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless/mode" --type string "infrastructure"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless/ssid" --type list --list-type int "[76,73,78,85,75,45,87,76,65,78]"
gconftool-2 --set "$BASE_LOCATION/802-11-wireless/security" --type string "802-11-wireless-security"
gconftool-2 --set "/apps/nm-applet/ignore-ca-cert/$UUID" --type bool true
END_HEREDOC
)
STATUSVAR=0
# Execute commands
echo "$COMMANDBLOCK" | while read line; do
newline=$(echo "$line" | sed -e 's/"/\\"/g' | sed -e 's/[()]/\\&/g' )
[[ $DEBUG ]] && eval echo "$newline"
eval "$line"
STATUSVAR+=$?
done
# Check exit codes
if [[ $STATUSVAR -ne 0 ]]; then
cw "WARNING: Some gconf commands did not complete successfully!"
else
co "Profile creation seems to have been successful"
fi
fi
}
if [ $CHECKONLY ]; then
# Check (read-only) mode
check_profiles
check_profiles_detailed
echo -e "\nWe are running in check-only mode, so no changes were made\n"
else
# Profile check/remove/create logic
if check_profiles; then
create_new_profile
else
if [[ $REMOVIFY ]]; then
ci "The -r flag was supplied, so we will attempt to remove existing profiles"
remove_all_profiles
if check_profiles; then
create_new_profile
else
cf "Couldn't remove all config for SSID \"LINUK-WLAN\""
fi
else
check_profiles_detailed
fi
fi
fi
echo -e "\n - Try selecting the \"LINUK-WLAN (User auth)\" profile in NetworkManager\n - You will need to enter your network password in the authentication settings window for the connection\n - If this is the first time you've run this script, you may need to ${BOLD}reboot${OFF} before connecting"
[[ $REBOOT ]] && echo -e "\n${BOLD}* Please reboot now to perform machine authentication *${OFF}"
/etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
# Network added by /usr/local/sbin/linukwlan-machine-setup at Thu Oct 22 16:34:10 BST 2015
network={
ssid="LINUK-WLAN"
scan_ssid=1
key_mgmt=WPA-EAP
eap=PEAP
identity="host/dhu.linuk.local"
password="abcdefghijklmnopqrstuvwxyzABCDEF"
phase2="auth=MSCHAPV2"
}
/etc/sysconfig/wpa_supplicant
# Use the flag "-i" before each of your interfaces, like so:
# INTERFACES="-ieth1 -iwlan0"
INTERFACES="-iwlan0"
# Use the flag "-D" before each driver, like so:
# DRIVERS="-Dwext"
DRIVERS=""
# Other arguments
# -u Enable the D-Bus interface (required for use with NetworkManager)
# -f Log to /var/log/wpa_supplicant.log
# -P Write pid file to /var/run/wpa_supplicant.pid
# required to return proper codes by init scripts (e.g. double "start" action)
# -B to daemonize that has to be used together with -P is already in wpa_supplicant.init.d
OTHER_ARGS="-u -f /var/log/wpa_supplicant.log -P /var/run/wpa_supplicant.pid"