Here’s how to set up RADIUS authentication using FreeRADIUS and an Active Directory server. For example, this can be used for authenticating Wifi WPA Enterprise clients (when you connect to a WPA Enterprise Wifi network, you have to give your username and password, not only a password like when connecting to a WPA Personal network).
Setting up Kerberos
Put these to /etc/krb5.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [libdefaults] ticket_lifetime = 600 default_realm = YOURDOMAIN.LOCAL default_tkt_enctypes = des3-hmac-sha1 des-cbc-crc default_tgs_enctypes = des3-hmac-sha1 des-cbc-crc [realms] YOURDOMAIN.LOCAL = { kdc = IPOFADSERVER default_domain = YOURDOMAIN.LOCAL } [domain_realm] .yourdomain = YOURDOMAIN.LOCAL yourdomain = YOURDOMAIN.LOCAL [kdc] profile = /etc/krb5kdc/kdc.conf [logging] kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmin.log default = FILE:/var/log/krb5lib.log |
Replace YOURDOMAIN.LOCAL with your domain name, and IPOFADSERVER with the IP address of the AD server.
To test the Kerberos, you can use kinit:
1 2 | kinit user@YOURDOMAIN.LOCAL klist |
Replace user with your username, and YOURDOMAIN.LOCAL with your domain name. If klist lists your ticket, then it works ok.
Compiling Samba
The current supplied version of Samba in Debian doesn’t come with AD support, so we have to compile it from source.
1 2 3 4 | #!/bin/bash ./configure --with-ads make sudo make install |
Setting up Samba
Source: http://deployingradius.com/documents/configuration/active_directory.html
As Samba was compiled from source, the smb.conf is in /usr/local/samba/etc/. It’s contents should be the following:
1 2 3 4 5 6 7 8 9 | [global] workgroup = YOURWORKGROUPNAME security = ads password server = PASSWORDSERVERIP realm = YOURDOMAIN.local printcap name = /dev/null load printers = no printing = bsd |
Replace YOURWORKGROUPNAME with your workgroup’s name, PASSWORDSERVERIP with the AD’s IP address, and YOURDOMAIN.local with your domain. You’ll need to start winbindd with Samba, so edit the init script /etc/init.d/samba:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | #!/bin/sh ### BEGIN INIT INFO # Provides: samba # Required-Start: $network $local_fs $remote_fs # Required-Stop: $network $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Should-Start: slapd cups # Should-Stop: slapd cups # Short-Description: start Samba daemons (nmbd and smbd) ### END INIT INFO # Defaults RUN_MODE="daemons" JOINUSER="aradius" JOINUSERPASS="" # Reads config file (will override defaults above) [ -r /etc/default/samba ] && . /etc/default/samba PIDDIR=/usr/local/samba/var/run NMBDPID=$PIDDIR/nmbd.pid SMBDPID=$PIDDIR/smbd.pid WINBINDDPID=$PIDDIR/winbindd.pid # clear conflicting settings from the environment unset TMPDIR # See if the daemons are there test -x /usr/local/samba/sbin/nmbd -a -x /usr/local/samba/sbin/smbd || exit 0 . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting Samba daemons" # Make sure we have our PIDDIR, even if it's on a tmpfs install -o root -g root -m 755 -d $PIDDIR if [ -n `which testparm` ] then NMBD_DISABLED=`testparm -s --parameter-name='disable netbios' 2>/dev/null` fi if [ "$NMBD_DISABLED" != 'Yes' ]; then log_progress_msg "nmbd" if ! start-stop-daemon --start --quiet --oknodo --exec /usr/local/samba/sbin/nmbd -- -D then log_end_msg 1 exit 1 fi fi if [ -n `which testparm` ] then WINBINDD_DISABLED=`testparm -s --parameter-name='disable winbindd' 2>/dev/null` fi if [ "$WINBINDD_DISABLED" != 'Yes' ]; then log_progress_msg "winbindd" echo $JOINUSERPASS | /usr/local/samba/bin/net ads join -U $JOINUSER if ! start-stop-daemon --start --quiet --oknodo --exec /usr/local/samba/sbin/winbindd -- -D then log_end_msg 1 exit 1 fi fi if [ "$RUN_MODE" != "inetd" ]; then log_progress_msg "smbd" if ! start-stop-daemon --start --quiet --oknodo --exec /usr/local/samba/sbin/smbd -- -D; then log_end_msg 1 exit 1 fi fi log_end_msg 0 ;; stop) log_daemon_msg "Stopping Samba daemons" log_progress_msg "nmbd" start-stop-daemon --stop --quiet --pidfile $NMBDPID # Wait a little and remove stale PID file sleep 1 if [ -f $NMBDPID ] && ! ps h `cat $NMBDPID` > /dev/null then # Stale PID file (nmbd was succesfully stopped), # remove it (should be removed by nmbd itself IMHO.) rm -f $NMBDPID fi log_progress_msg "winbindd" start-stop-daemon --stop --quiet --pidfile $WINBINDDPID # Wait a little and remove stale PID file sleep 1 if [ -f $WINBINDDPID ] && ! ps h `cat $WINBINDDPID` > /dev/null then # Stale PID file (nmbd was succesfully stopped), # remove it (should be removed by nmbd itself IMHO.) rm -f $WINBINDDPID fi echo $JOINUSERPASS | /usr/local/samba/bin/net ads leave -U $JOINUSER if [ "$RUN_MODE" != "inetd" ]; then log_progress_msg "smbd" start-stop-daemon --stop --quiet --pidfile $SMBDPID # Wait a little and remove stale PID file sleep 1 if [ -f $SMBDPID ] && ! ps h `cat $SMBDPID` > /dev/null then # Stale PID file (nmbd was succesfully stopped), # remove it (should be removed by smbd itself IMHO.) rm -f $SMBDPID fi fi log_end_msg 0 ;; reload) if [ "$RUN_MODE" != "inetd" ]; then log_daemon_msg "Reloading /usr/local/samba/etc/samba/smb.conf" "smbd only" start-stop-daemon --stop --quiet --signal HUP --pidfile $SMBDPID log_end_msg 0 fi ;; restart|force-reload) $0 stop sleep 1 $0 start ;; status) status="0" NMBD_DISABLED=`testparm -s --parameter-name='disable netbios' 2>/dev/null` if [ "$NMBD_DISABLED" != "Yes" ]; then status_of_proc -p $NMBDPID /usr/local/samba/sbin/nmbd nmbd || status=$? fi if [ "$WINBINDD_DISABLED" != "Yes" ]; then status_of_proc -p $WINBINDDPID /usr/local/samba/sbin/winbindd winbindd || status=$? fi if [ "$RUN_MODE" != "inetd" ]; then status_of_proc -p $SMBDPID /usr/local/samba/sbin/smbd smbd || status=$? fi if [ "$NMBD_DISABLED" = "Yes" -a "$RUN_MODE" = "inetd" ]; then status="4" fi exit $status ;; *) echo "Usage: /etc/init.d/samba {start|stop|reload|restart|force-reload|status}" exit 1 ;; esac exit 0 |
Note the JOINUSER and JOINUSERPASS variables, which should be set to a valid user who can get a Kerberos ticket. I also wrote a simple shell script called testjoin, which periodically tests the connection to the AD and restarts Samba and Freeradius if needed. Place it in /usr/local/bin/testjoin:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash while [ 1 ]; do echo a | /usr/local/samba/bin/net ads testjoin result=$? if [ $result -ne 0 ]; then service samba restart sleep 5 service freeradius restart fi sleep 300 done |
Here’s it’s init script, place it in /etc/init.d/testjoin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #!/bin/sh ### BEGIN INIT INFO # Provides: testjoin # Required-Start: $network $remote_fs $syslog # Required-Stop: $network $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: testjoin ### END INIT INFO PATH=/sbin:/bin:/usr/sbin:/usr/bin . /lib/lsb/init-functions DAEMON=/usr/local/bin/testjoin PIDFILE=/var/run/testjoin.pid test -x $DAEMON || exit 5 case $1 in start) log_daemon_msg "Starting testjoin" start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON -m -b log_end_msg $? ;; stop) log_daemon_msg "Stopping testjoin" start-stop-daemon --stop --quiet --pidfile $PIDFILE log_end_msg $? rm -f $PIDFILE ;; restart|force-reload) $0 stop && sleep 2 && $0 start ;; try-restart) if $0 status >/dev/null; then $0 restart else exit 0 fi ;; reload) exit 3 ;; status) status_of_proc $DAEMON "testjoin" ;; *) echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}" exit 2 ;; esac |
Install it using update-rc.d testjoin defaults, and start it with service testjoin start.
logrotate.d config for Samba
Put it in /etc/logrotate.d/samba:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /usr/local/samba/var/log.smbd { weekly missingok rotate 7 postrotate /etc/init.d/samba reload > /dev/null endscript compress notifempty } /usr/local/samba/var/log.nmbd { weekly missingok rotate 7 postrotate [ ! -f /usr/local/samba/var/run/nmbd.pid ] || kill -HUP `cat /usr/local/samba/var/run/nmbd.pid` endscript compress notifempty } /usr/local/samba/var/log.winbindd* /usr/local/samba/var/log.wb-* { weekly missingok rotate 7 postrotate [ ! -f /usr/local/samba/var/run/winbindd.pid ] || kill -HUP `cat /usr/local/samba/var/run/winbindd.pid` endscript compress notifempty } |
Testing ntlm_auth
Edit /etc/hosts so that your host name and FQDN point to 127.0.0.1:
1 | 127.0.0.1 localhost radius1 radius1.YOURDOMAIN.local |
Start Samba with /etc/init.d/samba start, and test ntlm_auth with:
1 | /usr/local/samba/bin/ntlm_auth --request-nt-key --domain=YOURDOMAIN.LOCAL --username=user --password=pass |
If the authentication was successful, it will display NT_STATUS_OK: Success (0x0). If something is not working, you should check Samba’s logs. If you want to manually join or leave the domain, you can use /usr/local/samba/bin/net join -U user, and /usr/local/samba/bin/net leave.
Setting up FreeRADIUS
Edit /etc/freeradius/modules/mschap:
1 | ntlm_auth = "/usr/local/samba/bin/ntlm_auth --request-nt-key --username=%{mschap:User-Name:-None} --domain=%{%{mschap:NT-Domain}:-YOURDOMAIN.LOCAL} --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00}" --require-membership-of=GROUPID" |
Replace YOURDOMAIN.LOCAL with your domain name, and GROUPID with the group ID of the AD group which the user must be the member of to authenticate. The –require-membership-of parameter is optional.
Edit /etc/freeradius/radiusd.conf and set the following:
1 2 | user = root group = root |
This is necessary as winbindd is running as root, and FreeRADIUS must run as root to be able to use ntlm_auth.
Add this to the end of /etc/freeradius/clients.conf:
1 2 3 | client 192.168.0.0/16 { secret = secret } |
Replace the given IP and subnet mask with the IP range where authentication requests come from. Change the secret as well.
Change the default_eap_type to mschapv2 in /etc/freeradius/eap.conf (there are two lines where you have will find a default_eap_type setting). If you are using your RADIUS to authenticate WPA Enterprise clients, you won’t be able to use PAP as the clients’s won’t give clean text passwords, only password hashes. You can only verify authenticity with ntlm_auth using the hash.
Certificates
Empty the /etc/freeradius/certs directory, and create the random and dh files:
1 2 | dd if=/dev/urandom of=/etc/freeradius/certs/random count=10 openssl dhparam -out /etc/freeradius/certs/dh 1024 |
If you don’t want to create self signed certificates for every client, then you should buy a simple SSL cert from a cheap provider like GlobeSSL. They will send you 3 files:
- a private key, which should be placed in /etc/freeradius/certs/server.key
- a server certificate, put it in /etc/freeradius/certs/yourhostname.crt
- a root CA/GlobeSSL certificate bundle, you don’t need this on the server.
Now edit /etc/freeradius/eap.conf and set the following:
1 2 3 | private_key_password = private_key_file = ${certdir}/server.key certificate_file = ${certdir}/yourhostname.crt |
Restart FreeRADIUS with service freeradius restart (or start it in debugging mode with freeradius -X), and test authentication with radtest (run it on a machine which has an IP address in the range defined in clients.conf):
1 | radtest -t mschap user pass radiusserverip 0 radiussecret |
If you want to test a full EAP authentication (simulating a WPA Enterprise client), you can use eapol_test. See this tutorial. Test both PEAP and EAP-TTLS using MSCHAPv2.
A note on intermediate CA signed certificates
If you are using RADIUS for authenticating WPA Enterprise clients, some problems may occur with server certificates signed by an intermediate CA (like the certs which can be bought from GlobeSSL). For example, if a Windows client has no internet access and tries to connect to the Wifi network for the first time, it will reject the server’s cert, because it can’t verify it’s authenticity using OCSP (see this note). If it has internet access during connecting (for example, the Ethernet cable is plugged in), it will be able to verify the certificate chain, and add the server’s certificate to it’s cert database. You can also add root and intermediate CA certs to Windows clients manually. Rename the bundle file to something.crt and then double click on it.
On Ubuntu, you have to manually select the certificate bundle file when connecting to the Wifi network. The bundle file should contain the root CA and the intermediate CA certificates. A bundle file can be obtained from the SSL provider (for example, here’s GlobeSSL’s bundle file).
If you can get a certificate which is signed by a root CA directly, and that root CA is known by your clients’ operating systems, then you won’t have problems. However, these certs are very expensive, and more and more root CAs started to sign only intermediate CAs, so they are hard to get as well.
Trackback responses to this post
About me
I'm Nonoo. This is my blog about music, sounds, filmmaking, amateur radio, computers, programming, electronics and other things I'm obsessed with.
... »
Trackback URL
No comments yet.