FreeRADIUS AD authentication

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

Source: http://community.spiceworks.com/how_to/show/445-integrate-linux-with-active-directory-using-samba-winbind-and-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.

Name (required)
E-mail (required - never shown publicly)
Webpage URL
Comment:
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Trackback responses to this post

About me

Nonoo
I'm Nonoo. This is my blog about music, sounds, filmmaking, amateur radio, computers, programming, electronics and other things I'm obsessed with. ... »

Twitter

Listening now

My favorite artists