Joining Unix-like systems to an Active Directory

Initially, I wanted a Solaris box to join an Active Directory. As I had some difficulties with Solaris, I tried CentOS Linux for reference. Finally, I came up with this howto, which covers not only Solaris and CentOS, but also the FreeBSD and NetBSD.
The scenario is quite simple. I setup a Windows Server 2008 R2 with SP1. This machine is the domain controller for an AD called test.intra and its related NetBIOS domain called TEST. I named that machine dc1.test.intra and gave it the IP address 192.168.0.25. For Internet access, I have a default gateway sitting at 192.168.0.1. All the Unix boxes get an address in the 192.168.0.0/24 range as well. The following table gives an overview:

hostnameip addressoperating system
dc1.test.intra192.168.0.25Windows 2008 R2
centos.test.intra192.168.0.26CentOS 5.6
solaris2.test.intra192.168.0.28Solaris 10 09/10
freebsd.test.intra192.168.0.29FreeBSD 8.2
netbsd.test.intra192.168.0.31NetBSD 5.1

All machines are running inside an ESXi host with VMware tools installed where available. I installed each operating system as its 64-bit version (x86_64 or amd64).

CentOS

First of all, you have to install the samba3x-winbind package:

$ yum install samba3x-winbind
Move /etc/samba/smb.conf to /etc/samba/smb.conf.orig and create a new /etc/samba/smb.conf:
[global]
	workgroup = TEST
	realm = TEST.INTRA
	security = ads
	template shell = /bin/bash
	winbind use default domain = true
	winbind offline logon = false
	load printers = no
	server string = Linux box
	dns proxy = no
	winbind enum groups = yes
	winbind enum users = yes
	winbind expand groups = 5
	password server = dc1.test.intra
Then, call authconfig --updateall --enablewinbind --enablewinbindauth --enablewinbindusedefaultdomain once. This will update your smb.conf, /etc/nsswitch.conf, and PAM configuration, namly /etc/pam.d/system-auth-ac. It will start winbindd, too. Your /etc/resolv.conf should point to the domain controller:
nameserver 192.168.0.25
domain test.intra
To join the Active Directory, you have to shutdown winbindd and do a net join:
$ service winbindd stop
$ net join -U administrator
Type in the administrator's password and start winbindd again:
$ service winbindd start
To have winbindd started at system boot, use chkconfig:
$ chkconfig winbindd on
If you want the home directory to be created on the fly when a new domain user logs in, then add the following line to the end of /etc/pam.d/system-auth-ac manually:
session     required      pam_winbind.so mkhomedir
You can now login into your CentOS box as arbitrary domain user.

FreeBSD

Unfortunately, the binary package of Samba comes without Active Directory support. Thus you have to compile it from the ports:

$ cd /usr/ports/net/samba35
$ make config install clean
In the options dialog, enable support for LDAP, ADS, and WinBIND. For your own sake, disable CUPS support. Wipe out /usr/local/etc/smb.conf and create a new one:
[global]
	workgroup = TEST
	realm = TEST.INTRA
	security = ads
	idmap uid = 16777216-33554431
	idmap gid = 16777216-33554431
	template shell = /usr/local/bin/bash
	winbind use default domain = true
	winbind offline logon = false
	load printers = no
	server string = FreeBSD box
	dns proxy = no
	winbind enum groups = yes
	winbind enum users = yes
	winbind expand groups = 5
	password server = dc1.test.intra
Similar to CentOS, adjust your /etc/resolv.conf:
nameserver 192.168.0.25
domain test.intra
You have also to modify /etc/nsswitch.conf. Replace
group: compat
passwd: compat
with
group: files winbind
passwd: files winbind
To start winbindd during system boot, add the following to your /etc/rc.conf:
winbindd_enable=YES
Now join the FreeBSD machine to the Active Directory by executing:
$ net join -U Administrator
PAM configuration is awkward. First, you have to modify /etc/pam.d/sshd. At the bottom of the auth block, replace
auth            required        pam_unix.so             no_warn try_first_pass
with
auth            sufficient      pam_unix.so             no_warn try_first_pass
auth            required        /usr/local/lib/pam_winbind.so use_first_pass
Add
session         required        /usr/local/lib/pam_winbind.so mkhomedir
at the end of the session block. Similar to the auth block, you have to replace
password        required        pam_unix.so             no_warn try_first_pass
with
password        sufficient      pam_unix.so             no_warn try_first_pass
password        required        /usr/local/lib/pam_winbind.so use_first_pass
Either reboot the FreeBSD box or start winbindd manually:
$ /usr/local/etc/rc.d/samba start
Ensure that you can still login as root and as domain user through ssh. If this works, then apply the above changes of /etc/pam.d/sshd also to /etc/pam.d/system.

NetBSD

You have to compile Samba from pkgsrc as the binary package doesn't include nss_winbind.so. If you haven't downloaded pkrsrc so far, then do it now (this may last several minutes):

$ cd /usr
$ cvs -q -z3 -d anoncvs@anoncvs.NetBSD.org:/cvsroot checkout -P pkgsrc
Afterwards, you can update your copy of pkgsrc whenever you like:
$ cd /usr/pkgsrc
$ cvs update -dP
To build Samba with nss_winbind.so and pam_winbind.so on NetBSD, you have to apply my patch samba-3.5.10.nss_winbind.netbsd.patch. At first, extract Samba and apply all patches provided by pkgsrc:
$ cd /usr/pkgsrc/net/samba35
$ make patch
$ cd work/samba-3.5.10
Now download my patch from above, save it (in your home directory, for instance), and apply it:
patch -p1 <~/samba-3.5.10.nss_winbind.netbsd.patch
cd ../..
Building samba takes some time:
$ make
$ make install
However, you have to install nss_winbind.so manually:
$ cp -iv work/samba-3.5.10/nsswitch/nss_winbind.so /usr/lib/nss_winbind.so.0
Reclaim some disk space by cleaning up the working directories:
$ make clean clean-depends
Save the original smb.conf installed by pkgsrc:
$ mv -iv /usr/pkg/etc/samba/smb.conf /usr/pkg/etc/samba/smb.conf.orig
Create a fresh /usr/pkg/etc/samba/smb.conf:
[global]
	workgroup = TEST
	realm = TEST.INTRA
	security = ads
	idmap uid = 16777216-33554431
	idmap gid = 16777216-33554431
	template shell = /usr/pkg/bin/bash
	winbind use default domain = true
	winbind offline logon = false
	load printers = no
	server string = NetBSD box
	dns proxy = no
	winbind enum groups = yes
	winbind enum users = yes
	winbind expand groups = 5
	password server = dc1.test.intra
Make sure that /etc/resolv.conf points to dc1.test.intra:
nameserver 192.168.0.25
domain test.intra
Install winbindd's rc-script:
$ cp -iv /usr/pkg/share/examples/rc.d/winbindd /etc/rc.d/winbindd
$ chmod 0755 /etc/rc.d/winbindd
In /etc/rc.conf, enable winbindd at boot time:
winbindd=YES
Now your NetBSD box is ready to join the Active Directory:
$ net join -U administrator
Start winbindd:
$ /etc/rc.d/winbindd start
In /etc/nsswitch.conf, replace the following lines:
group:          compat
passwd:         compat
Replace them with these:
group:          files winbind
passwd:         files winbind
Edit /etc/pam.d/sshd. Replace the following entries:
auth            required        pam_unix.so     no_warn try_first_pass
...
account         required        pam_unix.so
...
password        required        pam_unix.so     no_warn try_first_pass
Replace them with these:
auth            sufficient      pam_unix.so     no_warn try_first_pass
auth            required        /usr/pkg/lib/security/pam_winbind.so try_first_pass
...
account         sufficient      pam_unix.so
account         required        /usr/pkg/lib/security/pam_winbind.so
...
password        sufficient      pam_unix.so     no_warn try_first_pass
password        required        /usr/pkg/lib/security/pam_winbind.so try_first_pass
Now login as an AD user through ssh. If this works, modify /etc/pam.d/system accordingly.

Solaris

As Solaris 10 ships with Samba 3.0.x which is too old, you have to fetch Samba 3.4.x and all of its dependencies from Sunfreeware. You'll need the source code of Samba, too. Download all files to a temporary directory like /var/tmp. Unzip all binary packages and install them, eg.:

$ gzip -d samba-3.4.2-sol10-x86-local.gz
$ pkgadd -d samba-3.4.2-sol10-x86-local
After this, unpack the source code of Samba and prepare it for compiliation:
$ gzip -cd samba-3.4.2.tar.gz | tar -xf -
$ cd samba-3.4.2/source3
$ ./configure --enable-nss-wrapper --with-pam
Edit the newly created Makefile. Replace the line:
SHLD=${CC} ${CFLAGS}
with:
SHLD=${CC} ${CFLAGS} -L/usr/local/lib -lintl
Add the following statement at the end of include/config.h:
#define HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG 1
Now you are ready to build the modules:
$ make pam_modules nss_modules
You have to install both modules manually:
$ mv -iv /usr/lib/security/pam_winbind.so.1 /usr/lib/security/pam_winbind.so.1.orig
$ cp -iv bin/pam_winbind.so /usr/lib/security/pam_winbind.so.1
$ ln -s pam_winbind.so.1 /usr/lib/security/pam_winbind.so
$ mv -iv /usr/lib/nss_winbind.so.1 /usr/lib/nss_winbind.so.1.orig
$ cp -iv ../nsswitch/libnss_winbind.so /lib/nss_winbind.so.1
$ ln -s ../../lib/nss_winbind.so.1 /usr/lib/nss_winbind.so.1
Next, you should update the dynamic linker search path:
$ crle -u -l /lib:/usr/lib:/usr/local/lib:/usr/local/samba/lib
Make sure that /etc/resolv.conf is well setup:
domain test.intra
nameserver 192.168.0.25
Your /usr/local/samba/lib/smb.conf should look like this:
[global]
	workgroup = TEST
	realm = TEST.INTRA
	security = ads
	idmap uid = 16777216-33554431
	idmap gid = 16777216-33554431
	template shell = /usr/bin/bash
	winbind use default domain = true
	winbind offline logon = false
	load printers = no
	server string = Solaris box
	dns proxy = no
	winbind enum groups = yes
	winbind enum users = yes
	winbind expand groups = 5
	password server = dc1.test.intra
	template homedir = /export/home/%U
Now, join your Solaris box to the Active Directory:
$ net join -U Administrator
For now, start winbindd manually:
$ /usr/local/samba/sbin/winbindd
To list all users and groups in your Active Directory, use wbinfo -u or wbinfo -g, respectively. Ensure that /etc/nsswitch.conf contains correct settings:
passwd:     files winbind
group:      files winbind
hosts:      files dns
ipnodes:    files dns
I used /etc/nsswitch.files as a template and added winbind and dns where appropriate. Also, I copied /etc/pam.conf-winbind to /etc/pam.conf and added
other   auth sufficient         pam_winbind.so use_first_pass
right after
other   auth requisite          pam_authtok_get.so.1
I commented out
other   password required       pam_winbind.so
If you can login as an AD user through ssh, then modify the login entries in the same way. To start winbindd during system boot, you have to create a new service bundle. Copy /var/svc/manifest/network/winbind.xml to /var/tmp/winbind-local.xml and adjust any filepathes to point to /usr/local/samba instead of /usr/sfw. You might download a ready to use winbind-local.xml and import it into svc:
$ svcadm disable winbind
$ svccfg import /var/tmp/winbind-local.xml
$ svcadm enable winbind-local

OpenBSD

OpenBSD 4.9 does neither have a nsswitch subsystem nor a PAM subsystem.

DragonFly BSD

DragonFly BSD 2.10.1 does not have a pluggable nsswitch subsystem, which is required to redirect libc password function calls to winbindd.

OpenIndiana

Although OpenIndiana Build 148 comes with Samba 3.5.4, I was not able to join the Active Directory:

root@openindiana:~# net join -U administrator
Enter administrator's password:
Failed to join domain: failed to lookup DC info for domain 'TEST.INTRA' over rpc: Logon failure
ADS join did not work, falling back to RPC...
Enter administrator's password:
Could not connect to server DC1
The username or password was not correct.
Connection failed: NT_STATUS_LOGON_FAILURE
Of course I double checked the password...

Further thoughts

As winbind automatically maps Windows user SIDs to Unix UIDs and GIDs, it is an ideal solution for joining just one Unix box to an Active Directory. It's also suitable if you want to join multiple Unix boxes, probably with differing UIDs/GIDs. If each user need to have the same UID and GID on all boxes, then you should put idmap.tdb under the control of CTDB. CTDB is a cluster database developed by the Samba team. It has to be installed on a cluster filesystem which is not available on every operating system. On the other hand, you could replace winbind by pam_kerberos, nss_ldap, and UNIX Interoperability Components. pam_kerberos authenticates your users against an Active Directory. UNIX Interoperability Components are a schema extension of Active Directory. They provide additional fields and entries for Unix GIDs, UIDs, etc. nss_ldap can be configured to use these fields so that each AD user will get the same IDs on all boxes.
To automatically mount a user's home directory from a Windows fileserver, have a look at pam_mount. In contrast, a user's home directory can be created on the fly by enabling pam_winbind's parameter mkhomedir. Of course, your Unix box might also serve your users' homedirs so that there is no need to mount them from another server.