Wednesday 28 October 2015

802.1x dual authentication on Red Hat Linux



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.)
  • 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 the simplest case, it's possible to get fully authenticated by manually inserting the appropriate usernames and passwords into NetworkManager.
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
    
For stage 2:
  • 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?


Ideally Network Manager would be aware of the system's machine password and would carry out Computer Authentication automatically. It would also be nice if it could automatically pick up the login user's username and password for use in wireless authentication.  However, in the absence of this functionality we want try to achieve the following:
  • 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 found that in our case the simplest way to perform the computer authentication was to use wpa_supplicant rather than NetworkManager.  The details of the network are inserted to the wpa_supplicant config file, and when the service starts it attempts to authenticate to the network.  Doing it this way means that the system does not pick up an IP address when it completes authentication.  It only does this once it completes user authentication with NetworkManager.  This was ideal for us, but it could be a disadvantage if you're looking to make use of IP connectivity at the computer auth stage, for example access to the kerberos realm to allow users to log in to the machine.

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


We use Quest group policies to push files and settings to our Linux machines.  There is a group policy object that contains the configuration relating to this setup, which is linked to our laptop container in AD.  Additional files are pushed to the clients through a custom script which copies in useful files every night with rsync.

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 file is pushed with our custom rsync script.
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
 ##########################################################  
 # 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"