Linux Active Directory Integration

Recently I undertook the very daunting task of integrating a Red Hat Enterprise Linux 5 server in a Windows Server 2003 RC2 Active Directory environment.

As enterprise networks go, single sign-on between operating systems from all walks of life is sort-of a holy grail of achievement, and with good reason, it was by no means obvious or easy to make it happen! But with some determination, lots of Google searching, trial and error, and a desk to bang your head against, it is ultimately possible.

In Linux-land, those nifty GUI tools for doing this sort of thing are completely worthless. On the Windows side Microsoft isn't exactly the biggest help either. The web and various man pages are your only friends. I spent the better part of two weeks searching the web, reading documentation, ant attempting to follow in the footsteps of those that came before me.

You see, I wanted to make AD login happen on a Linux server, but I did not want to become an expert in Kerberos, LDAP, Windows Active Directory, or networking in general. Unfortunately, you're much better off if you are an expert. Linux does not forgive the weak or the naive. And AD login on Linux doesn't look like it will ever be as easy as integrating a Windows client on a Windows domain. That is to say, set your domain, enter the Administrator password, and you're good to go. No, no, no, that's far too easy. OK, enough whining, let's get on with it.

Here are the goals I set out with:

  • I want to have file shares that Windows clients can log into without having to login. Their credentials should be passed automatically via Active Directory, as is the case when a Windows client accesses a share on a Windows server.
  • Network users should be able to log into a Linux client using their Windows Active Directory login.
  • Windows Active Directory users and security groups should be exposed in Linux automatically. Linux chown and chgrp operations should work on domain users and groups the same way that they work with native Linux users and groups.
  • Linux attributes like GID, UID, etc, as assigned to domain users should be the same from server to server.

That's the synopsis, currently my integration of Linux in a Windows AD environment fulfills all of those requirements but the last, and with some further research and experimentation, I believe I can fulfill all of those requirements. Now a word of warning.

DISCLAIMER: I am not an Active Directory expert. Neither am I an expert on the various technologies that Linux uses to perform authentication. There may be flaws in my configurations. I MAY NOT BE ABLE TO ASSIST YOU WITH YOUR PARTICULAR CONFIGURATION. I CANNOT GUARANTEE SECURITY. PROCEED AT YOUR OWN RISK.

The following configuration is specific to my company's particular implementation of a Windows Server 2003 (RC2) domain running Active Directory. Your results may vary, God help you in your quest.

So, without further delay, here are the configuration instructions.

In order to configure Linux for AD authentication, you must configure PAM (Pluggable Authentication Modules), nsswitch (Name Service Switch), LDAP, Kerberos, Samba, and Winbind. I present two different methods of AD authentication simultaneously, that is to say authentication via LDAP, and authentication via Winbind. These instructions are based on personal experience with the help of the following online resources/blogs.

Again, my configuration is specific to Red Hat Enterprise Linux 5, certain bits may need to be tweaked for your particular distribution of Linux.

Configure LDAP, /etc/ldap.conf

First up is LDAP. Make the following configuration changes to /etc/ldap.conf

01.bind_policy soft
04.base dc=example,dc=com
06.binddn adquery@EXAMPLE.COM
07.bindpw adquerypassword
08.scope sub
09.ssl no
10.referrals no
11.nss_base_passwd dc=example,dc=com?sub
12.nss_base_shadow dc=example,dc=com?sub
13.nss_base_group dc=example,dc=com?sub?&(objectCategory=group)(gidnumber=*)
14.nss_map_objectclass posixAccount user
15.nss_map_objectclass shadowAccount user
16.nss_map_objectclass posixGroup group
17.nss_map_attribute gecos cn
18.nss_map_attribute homeDirectory unixHomeDirectory
19.nss_map_attribute uniqueMember member

In the LDAP configuration, the configuration is set for a domain called The domain controller has the host name The domain controller is located at the IP address

If your domain is called, and your domain controller is you'd change the configuration like so where only the domain is referenced:dc=something,dc=example,dc=com

Active Directory also does not allow anonymous queries. Each query made must be associated with a valid domain user. Therefore, you must create a new user in Active Directory for this purpose. In the example configuration, this user is adquery@EXAMPLE.COM, and the user's password is adquerypassword. This user should have no privileges, in fact you should make this user a member of Domain Guests.

The remainder of the file has to do with mapping Microsoft's Services for Unix (SFU) snapin to Linux user attributes. My configuration ultimately does not utilize SFU at all, though it could with some experimentation.

The configurations I present allow two different ways of authenticating a domain user, via LDAP and Kerberos, or via Winbind. The former configuration does not allow Linux SMB shares to mount on Windows clients, while the latter does, at least in this particular Windows AD domain.

Configure NSSwitch, /etc/nsswitch.conf

01.# An example Name Service Switch config file. This file should be
02.# sorted with the most-used services at the beginning.
04.# The entry '[NOTFOUND=return]' means that the search for an
05.# entry should stop if the search in the previous entry turned
06.# up nothing. Note that if the search failed due to some other reason
07.# (like no NIS server responding) then the search continues with the
08.# next entry.
10.# Legal entries are:
12.#       nisplus or nis+         Use NIS+ (NIS version 3)
13.#       nis or yp               Use NIS (NIS version 2), also called YP
14.#       dns                     Use DNS (Domain Name Service)
15.#       files                   Use the local files
16.#       db                      Use the local database (.db) files
17.#       compat                  Use NIS on compat mode
18.#       hesiod                  Use Hesiod for user lookups
19.#       [NOTFOUND=return]       Stop searching if not found so far
22.# To use db, put the "db" in front of "files" for entries you want to be
23.# looked up first in the databases
25.# Example:
26.#passwd:    db files nisplus nis
27.#shadow:    db files nisplus nis
28.#group:     db files nisplus nis
30.passwd:     files winbind
31.shadow:     files      files winbind
34.#hosts:     db files nisplus nis dns
35.hosts:  files dns wins
37.# Example - obey only what nisplus tells us...
38.#services:    nisplus [NOTFOUND=return] files
39.#networks:    nisplus [NOTFOUND=return] files
40.#protocols:   nisplus [NOTFOUND=return] files
41.#rpc:         nisplus [NOTFOUND=return] files
42.#ethers:      nisplus [NOTFOUND=return] files
43.#netmasks:    nisplus [NOTFOUND=return] files
45.bootparams: files
47.ethers:     files
48.netmasks:   files
49.networks:   files
50.protocols:  files
51.rpc:        files   files
54.netgroup:   files
56.publickey:  nisplus
58.automount:  files
59.aliases:    files nisplus

In the preceding block you see the standard nsswitch.conf file that's shipping with Red Hat (and presumably Fedora and CentOS). This is the only important modification to make:

1.passwd:     files winbind
2.shadow:     files      files winbind

You're telling Linux to look at winbind as a source of authentication information, in addition to the Linux files/etc/passwd and /etc/group.

I could use the following configuration for LDAP, instead of Winbind. If only AD authentication is required (but no file shares), that would be the way to go. If going that method, you'll need that Microsoft Services for Unix snapin to be installed, and you'll have to configure the UID, GID, Home Directory, and Login Shell attributes for each domain user logging into Linux.

1.passwd:     files ldap
2.shadow:     files      files ldap

Configure PAM, /etc/pam.d/system-auth-ac

02.# This file is auto-generated.
03.# User changes will be destroyed the next time authconfig is run.
04.#auth     required   /lib/security/$ISA/
05.#auth     sufficient /lib/security/$ISA/ likeauth nullok
06.#auth     sufficient /lib/security/$ISA/
07.#auth     required   /lib/security/$ISA/
09.auth sufficient /lib/security/$ISA/
10.auth sufficient /lib/security/$ISA/ nullok_secure use_first_pass
11.auth required   /lib/security/$ISA/
13.#account  sufficient /lib/security/$ISA/
14.#account  sufficient /lib/security/$ISA/
15.#account  sufficient /lib/security/$ISA/ uid < 100 quiet
16.#account  required   /lib/security/$ISA/
18.account sufficient /lib/security/$ISA/
19.account required   /lib/security/$ISA/
21.password requisite  /lib/security/$ISA/ retry=3
22.password sufficient /lib/security/$ISA/ nullok use_authtok md5 shadow
23.password required   /lib/security/$ISA/
25.session  required   /lib/security/$ISA/ skel=/etc/skel umask=0077
26.session  required   /lib/security/$ISA/
27.session  required   /lib/security/$ISA/

PAM is configured to use winbind for authentication in this example, if going the LDAP route, remove the "auth" and "account" blocks, and uncomment the corresponding "auth" and "account" lines containing references to krb5.

Configure Hosts, /etc/hosts

1.# Do not remove the following line, or various programs
2.# that require network functionality will fail.       NETBIOS.EXAMPLE.COM NETBIOS localhost    DC.EXAMPLE.COM DC

In the hosts configuration, you're doing two things. One, you're setting the Fully-Qualified Domain Name (FQDN) of the server or workstation, and two, you're hard-coding a DNS entry for the location of the domain controller. For good measure.

Configure Kerberos, /etc/krb5.conf

02.default = FILE:/var/log/krb5libs.log
03.kdc = FILE:/var/log/krb5kdc.log
04.admin_server = FILE:/var/log/kadmind.log
07.default_realm = EXAMPLE.COM
08.dns_lookup_realm = true
09.dns_lookup_kdc = true
13.kdc =
14.admin_server =
15.default_domain =
18.[domain_realm] = EXAMPLE.COM = EXAMPLE.COM
23.profile = /var/kerberos/krb5kdc/kdc.conf
26.pam = {
27.debug = false
28.ticket_lifetime = 36000
29.renew_lifetime = 36000
30.forwardable = true
31.krb4_convert = false

WARNING: The case of the domain names in krb5.conf is important. You will fail if this is not configured correctly.

At this point, you should be able to do a kerberos authentication. At the command line, cross your fingers and type the following:

1.# kinit user@EXAMPLE.COM

The above command obtains a new kerberos ticket. You do not have to be joined to the domain to obtain a kerberos ticket. Joining to the domain is necessary for mutual authentication, and is required for Linux SMB shares. Again, the case is important. The domain must be typed in all uppercase, or this command will fail. See if you have obtained a kerberos ticket by running the following command:

1.# klist

You should see a valid kerberos ticket.

Don't forget that the clock of the Linux client must be within the range allowed by the Windows server. Typically this is a skew of plus or minus five minutes. The best way to handle this is to set your clock to automatically synchronize to an NTP server, such as

Configure Samba and Winbind, /etc/samba/smb.conf

If they are running, stop the smb and winbind services.

1.# /sbin/service smb stop
2.# /sbin/service winbind stop

Now, configure /etc/samba/smb.conf.

02.workgroup = EXAMPLE
03.realm = EXAMPLE.COM
04.netbios name = NETBIOS
05.server string = = ads
07.use kerberos keytab = true
08.hosts allow = 192.168. 127. 10.
09.load printers = no
10.log file = /var/log/samba/%m.log
11.client use spnego = yes
12.max log size = 50
13.log level = 1
14.password server = DC.EXAMPLE.COM
15.idmap uid = 10000 - 20000
16.idmap gid = 10000 - 20000
17.winbind enum users = yes
18.winbind enum groups = yes
19.winbind cache time = 10
20.winbind nested groups = yes
21.;winbind nss info = template sfu
22.winbind use default domain = no
23.wins server =
24.template homedir = /home/%U
25.template shell = /bin/bash
26.;idmap backend = idmap_ad
27.dns proxy = no
28.domain master = no
29.preferred master = no
32.comment     = www on NETBIOS
33.path        = /home/www
34.valid users = @EXAMPLEweb
35.force user  = www
36.force group = EXAMPLEweb
37.public      = no
38.writable    = yes
39.printable   = no

Although I haven't tested it yet, I believe it is possible to use both winbind and Windows Services for Unix to generate Unix account attributes, UID, GID, login shell, and home directory. man smb.conf leads me to believe this is possible, but more tinkering is required. Additionally, smb.conf can be configured to store the winbind-generated attributes in an LDAP container, which is useful for synchronizing these attributes among multiple Linux clients.

Test the samba configuration.

1.# testparm /etc/samba/smb.conf

With regards to share definitions, group membership can be tested as criteria

1.valid users = @EXAMPLEweb

The above says that anyone in the group EXAMPLEweb is allowed access to the share.

Spaces in group names must be accounted for specially, just enclose the name in quotes.

1.valid users = @"EXAMPLEgroup name"

Now make sure that winbind and samba are set to start at boot, and that samba starts before winbind. Do this from the webmin console or the services console.

Now, start Winbind and Samba services, samba sbould be started first.

1.# /sbin/service smb start
2.# /sbin/service winbind start

Join the Windows Domain

Obtain a kerberos ticket for the domain Administrator

1.# kinit Administrator@EXAMPLE.COM

Verify that you have a ticket.

1.# klist

Join the workstation to the domain.

1.# net ads join

Alternatively, you can also join using the following command, which supersedes the need to pull a kerberos ticket for the domain Administrator.

1.# net ads join -U Administrator

As I explained previously in the configuration for LDAP, Windows Server 2003 does not allow anonymous queries, so you'll have to assign winbind a domain user, again this domain user does not need any privileges, in fact it's better if it is a member of domain guests.

1.# wbinfo --set-auth-user adquery%adquerypassword

The modulus separates the username and password, for a more complex password that may have characters that have special meaning in the BASH terminal, enclose the password in single (or double) quotes.

1.# wbinfo --set-auth-user adquery%'adquerypassword'

In Active Directory, the user lookup should be a member of Domain Guests. Verify that you have set the user with the following

1.# wbinfo --get-auth-user

The above should print the username and password.

Verify that you are joined by testing the join

1.# wbinfo -t
2.# net ads testjoin

Now, test that you have domain users and groups available.

1.# wbinfo -u

The above should print every domain user as EXAMPLEuser.

1.# wbinfo -g

The above should print every domain group as EXAMPLEgroup.

Test that you have merged domain users and local users with the following.

1.# getent passwd

The same for groups

1.# getent group

Domain users should be appended to the results of each of those commands.

Test a login with a domain user account.

1.# ssh -l EXAMPLEuser localhost

If the above is successful, you should see "Directory created for user", and have a login by SSH.

Operations like chown and chgrp should now work with domain users. At the command line, and in most other operations, any user or group name containing spaces must be enclosed in quotations. Additionally, the backslash character must be escaped like you see above in the SSH login.


If you are not able to login via a domain user, or if getent passwd / getent group does not return domain users, it may be necessary to clear the winbind cache.

1.# /sbin/service smb stop
2.# /sbin/service winbind stop

Delete the winbind cache.

1.# rm -f /var/cache/samba/winbindd_idmap.tdb
2.# /sbin/service smb start
3.# /sbin/service winbind start

For debugging, change the log level in smb.conf to 10, and look for the log for the client you are attempting to connect with in /var/log/samba. Logs are kept by netbios name and IP address.

Before attempting to connect to a Linux SMB share from a Window client, it may be necessary to logout and login on the client. It may also be necessary to wait a little time for propagation.

You may also find that the testparm /etc/samba/smb.conf command complains about the winbind separator. It's supposed to be a backslash by default. If this is a problem for you, you may want to change the separator to a plus sign instead. That change might look like this:

1.winbind enum users = yes
2.winbind enum groups = yes
3.winbind cache time = 10
4.winbind nested groups = yes
5.winbind separator = +

Other Useful Commands

1.# net ads changetrustpw

The above changes the machine's kerberos password, and updates the samba-maintained Kerberos keytab. This hangs when I do it, so CTRL + C to cancel out of it.

Once done, you have logout and login to any machines you're using to test.

Test the join.

1.# net ads testjoin

Leave the domain.

1.# net ads leave

Print out the workgroup of the kerberos realm.

1.# net ads workgroup

Print out the workgroup of the kerberos realm.

Cleanup, before logging off the server run the following command:

1.# kdestroy

This will remove any active kerberos tickets, including any obtained for the domain Administrator.

The domain Administrator can be given root access to the Linux server by editing the /etc/sudoers file.

1.# visudo -f /etc/sudoers

Make the following modification around the "root" line.

1.root    ALL=(ALL)       ALL
2.%Domain_Admins All=(ALL)ALL

I have not yet tested granting the domain administrator root privileges via sudo, so I'm not certain if that works.

To give Domain Admins sudo rights the line you need to add to /etc/sudoers is:

%Domain Admins ALL=(ALL) ALL