Raspberry Pi running Active Directory, using Samba on FreeBSD.

Active Directory Service with Samba

Setting up Samba and Active Directory

We're building an Active Directory server from Samba running on FreeBSD, free server software on a free operating system. We have already set up the needed DNS infrastructure on an existing BIND master (or primary) DNS server, installed FreeBSD on a Raspberry Pi, and set that up as a BIND slave DNS server for those same zones. Now we're ready to do the Samba work! Jump back to the start for an overview of the project.

Recall that Active Directory is simply Microsoft's bundle of DNS, LDAP (more or less), and Kerberos (kind of). I had thought that Active Directory meant an enormously complicated collection of Microsoft-specific services, all of which communicate through arcane Microsoft-specific protocols. Not really.

Samba setup

In an earlier step we installed Samba on our FreeBSD system. Now it's time to configure it. But first, let's see if any Samba processes are running, or if any old database files are lying around to cause confusion. The egrep process may notice itself, as here. That doesn't matter, just make sure there aren't any of the ones we're looking for:

Cleaning up

# ps axuww | egrep 'PID|samba|smbd|nmbd|winbindd'
USER     PID %CPU %MEM   VSZ   RSS TT  STAT STARTED     TIME COMMAND
root     755  0.0  0.5  6424  2280  0  S+   16:30    0:00.08 egrep PID|samba|smbd|nmbd|winbind
# smbd -b | grep /
   Built using: /nxb-bin/usr/bin/cc
   SRCDIR:      /wrkdirs/usr/ports/net/samba43/work/samba-4.3.13/source3
   BUILDDIR:    /wrkdirs/usr/ports/net/samba43/work/samba-4.3.13/source3
   SBINDIR: /usr/local/sbin
   BINDIR: /usr/local/bin
   CONFIGFILE: /usr/local/etc/smb4.conf
   LOGFILEBASE: /var/log/samba4
   LMHOSTSFILE: /usr/local/etc/lmhosts
   LIBDIR: /usr/local/lib
   MODULESDIR: /usr/local/lib/shared-modules
   LOCKDIR: /var/db/samba4
   STATEDIR: /var/db/samba4
   CACHEDIR: /var/db/samba4
   PIDDIR: /var/run/samba4
   SMB_PASSWD_FILE: /var/db/samba4/private/smbpasswd
   PRIVATE_DIR: /var/db/samba4/private 

You may need to clean up some things:

# pkill samba smbd nmbd winbindd
# rm -rf /usr/local/etc/smb4.conf \
	/usr/local/etc/lmhosts \
	/var/db/samba4/*

Provisioning a domain

Make sure that you are certain about the DNS domain and Kerberos realm name, as you cannot change those. You would have to delete the definitions and start over with the correct names.

Here is one way to do the provisioning. You can also do it interactively, passing only the --use-rfc2307 option. Include RFC 2307 support, as this allows you to store Unix attributes like UID, home directory, etc., in Active Directory. Be patient, as this takes several minutes to run, especially on a single-CPU Raspberry Pi.

# samba-tool domain provision --use-rfc2307 \
	 --realm=CORP.EXAMPLE.COM --domain=CORP \
	 --server-role=dc --dns-backend=BIND9_DLZ
Looking up IPv4 addresses
Looking up IPv6 addresses
Setting up share.ldb
Setting up secrets.ldb
Setting up the registry
Setting up the privileges database
Setting up idmap db
Setting up SAM db
Setting up sam.ldb partitions and settings
Setting up sam.ldb rootDSE
Pre-loading the Samba 4 and AD schema
Adding DomainDN: DC=corp,DC=example,DC=com
Adding configuration container
Setting up sam.ldb schema
Setting up sam.ldb configuration data
Setting up display specifiers
Modifying display specifiers
Adding users container
Modifying users container
Adding computers container
Modifying computers container
Setting up sam.ldb data
Setting up well known security principals
Setting up sam.ldb users and groups
Setting up self join
Adding DNS accounts
Creating CN=MicrosoftDNS,CN=System,DC=corp,DC=example,DC=com
Creating DomainDnsZones and ForestDnsZones partitions
Populating DomainDnsZones and ForestDnsZones partitions
See /var/db/samba4/private/named.conf for an example configuration include file for BIND
and /var/db/samba4/private/named.txt for further documentation required for secure DNS updates
Setting up sam.ldb rootDSE marking as synchronized
Fixing provision GUIDs
A Kerberos configuration suitable for Samba 4 has been generated at /var/db/samba4/private/krb5.conf
Setting up fake yp server settings
Once the above files are installed, your Samba4 server will be ready to use
Admin password:		+Dyg<oqzjG~H$p%NI
Server Role:		active directory domain controller
Hostname:		freebsd
NetBIOS Domain:		CORP
DNS Domain:		corp.example.com
DOMAIN SID:		S-1-5-21-1556128061-1363490377-3170584331

Record the automatically generated administrator password and the domain SID.

You probably want to change the password expiration. Otherwise you will be suddenly inconvenienced in 42 days.

# samba-tool user setexpiry --noexpiry Administrator
Expiry for user 'Administrator' disabled.

You may want to reset the password. If you do this without waiting for a day, change the minimum password age to zero:

# samba-tool domain passwordsettings show
Password informations for domain 'DC=corp,DC=example,DC=com'

Password complexity: on
Store plaintext passwords: off
Password history length: 24
Minimum password length: 7
Minimum password age (days): 1
Maximum password age (days): 42
Account lockout duration (mins): 30
Account lockout threshold (attempts): 0
Reset account lockout after (mins): 30

# samba-tool domain passwordsettings set --min-pwd-age 0
Minimum password age changed!
All changes applied successfully!

# samba-tool user password --user=administrator
Password for [CORP\administrator]:+Dyg<oqzjG~H$p%NI
New Password:new-password-here
Retype Password:new-password-here 
Changed password OK

Remaining manual steps

Verify that /var/db/samba4/private/named.conf was automatically configured by uncommenting the appropriate dlz_bind9_*.so shared library.

Then, if it hasn't already been done automatically, add a line at the end of /usr/local/etc/namedb/named.conf:

include "/var/db/samba4/private/named.conf"; 

I need to make a symbolic link to the new Kerberos configuration file:

# ln -s /var/db/samba4/private/krb5.conf /etc/krb5.conf

Now let's see if Samba starts cleanly:

# /usr/local/etc/rc.d/samba_server onestart
Performing sanity check on Samba configuration: OK
Starting samba.
[2017/02/18 11:55:02.721769,  0] ../lib/util/debug.c:947(reopen_logs_internal)
  Unable to open new log file '/var/log/samba4/log.samba': No such file or directory
[2017/02/18 11:55:02.758508,  0] ../source4/smbd/server.c:371(binary_smbd_main)
  samba version 4.3.13 started.
  Copyright Andrew Tridgell and the Samba Team 1992-2015
# /usr/local/etc/rc.d/samba_server onestop
Stopping samba.
Waiting for PIDS: 1063 

It fails because /var/log is mounted on RAM on the Raspberry Pi. Logs disappear at every boot, along with the expected subdirectory. I have configured syslog to start, but then to send everything over the network to a log collector instead of saving it to disk. Samba, however, wants to save a copy locally. So, I added one line to the end of the [global] stanza in /usr/local/etc/smb4.conf. I also removed the dnsupdate from the end of the list of server services.

[global]
	workgroup = CORP
	realm =  CORP.EXAMPLE.COM
	netbios name = FREEBSD
	server role = active directory domain controller
	server services = s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc
	idmap_ldb:use rfc2307 = yes
	log file = /var/log/samba.%m
		
[netlogon]
	path = /var/db/samba4/sysvol/corp.example.com/scripts
	read only = No

[sysvol]
	path = /var/db/samba4/sysvol
	read only = No 

Now let's try it again:

# /usr/local/etc/rc.d/samba_server onestart
Performing sanity check on Samba configuration: OK
Starting samba.
[... wait a minute for everything to come up ...]
# /usr/local/etc/rc.d/samba_server onestatus
samba is running as pid 564.
# pstree
-+= 00001 root /sbin/init --
 |--= 00347 root /sbin/devd
 |--= 00493 root /usr/sbin/syslogd -s
 |--= 00505 bind /usr/local/sbin/named -u bind -c /usr/local/etc/namedb/named.conf
 |--= 00553 root /usr/sbin/ntpd -g -c /etc/ntp.conf -p /var/run/ntpd.pid -f /var/db/ntpd.drift
 |-+= 00564 root /usr/local/sbin/samba --daemon --configfile=/usr/local/etc/smb4.conf
 | |-+- 00690 root samba: task[s3fs_parent] (samba)
 | | \-+= 00692 root /usr/local/sbin/smbd -D --option=server role check:inhibit=yes --foreground
 | |   |--- 00707 root /usr/local/sbin/smbd -D --option=server role check:inhibit=yes --foreground
 | |   |--- 00710 root /usr/local/sbin/smbd -D --option=server role check:inhibit=yes --foreground
 | |   \--- 01642 root /usr/local/sbin/smbd -D --option=server role check:inhibit=yes --foreground
 | |--- 00691 root samba: task[dcesrv] (samba)
 | |--- 00693 root samba: task[nbtd] (samba)
 | |--- 00694 root samba: task wrepl server_id[694] (samba)
 | |--- 00695 root samba: task[ldapsrv] (samba)
 | |--- 00696 root samba: task[cldapd] (samba)
 | |--- 00697 root samba: task[kdc] (samba)
 | |--- 00698 root samba: task[dreplsrv] (samba)
 | |-+- 00699 root samba: task[winbindd_parent] (samba)
 | | \-+= 00703 root /usr/local/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
 | |   |--- 00709 root /usr/local/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
 | |   |--- 01164 root /usr/local/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
 | |   \--- 01165 root /usr/local/sbin/winbindd -D --option=server role check:inhibit=yes --foreground
 | |--- 00700 root samba: task[ntp_signd] (samba)
 | |--- 00701 root samba: task[kccsrv] (samba)
 | \--- 00702 root samba: task[dnsupdate] (samba)
 |-+= 00634 root /usr/sbin/sshd
 | \-+= 01647 root sshd: cromwell [priv] (sshd)
 |   \-+- 01649 cromwell sshd: cromwell@pts/0 (sshd)
 |     \-+= 01650 cromwell -tcsh (tcsh)
 |       \-+= 01688 cromwell pstree
 |         \--- 01689 cromwell ps -axwwo user,pid,ppid,pgid,command
 |--= 00689 root /usr/libexec/getty 3wire.115200 ttyu0
 |--= 00685 root /usr/libexec/getty Pc ttyv0
 |--= 00686 root /usr/libexec/getty Pc ttyv1
 |--= 00687 root /usr/libexec/getty Pc ttyv2
 \--= 00688 root /usr/libexec/getty Pc ttyv3

I also looked in the syslog output on the log collector, there were no new error messages about missing log directories. Locally I have multiple Samba log files, all of them ephemeral ones on the RAM-based /var/log file system. But all the content is going to the log collector and being saved there.

# ls -l /var/log/log* /var/log/samba*
total 20
drwxrwxr-x  2 root  operator   512 Feb 18 11:42 .snap
-rw-r--r--  1 root  wheel      266 Feb 18 12:27 log.wb-CORP
-rw-r--r--  1 root  wheel      133 Feb 18 12:27 log.winbindd-idmap
-rw-r--r--  1 root  wheel     3639 Feb 18 12:27 samba.%m
-rw-r--r--  1 root  wheel      154 Feb 18 12:27 samba.smbd
-rw-r--r--  1 root  wheel      342 Feb 18 12:27 samba.winbindd 

All this seems good, so I added this line to /etc/rc.conf:

samba_server_enable="YES" 

Now let's reboot and make sure that everything comes up.

Checking the network services

DNS

This is good, it's listening on IPv4 and IPv6 on all interfaces.

# lsof -i tcp:53 -o -i udp:53
COMMAND PID USER   FD   TYPE     DEVICE OFFSET NODE NAME
named   508 bind   21u  IPv6 0xc321f650    0t0  TCP localhost:domain (LISTEN)
named   508 bind   22u  IPv4 0xc321f328    0t0  TCP localhost:domain (LISTEN)
named   508 bind   23u  IPv4 0xc321f000    0t0  TCP freebsd.example.com:domain (LISTEN)
named   508 bind   24u  IPv6 0xc321eca0    0t0  TCP [fe80:2::ba27:ebff:fe41:b9ae]:domain (LISTEN)
named   508 bind   25u  IPv6 0xc321e978    0t0  TCP freebsd.example.com:domain (LISTEN)
named   508 bind  512u  IPv6 0xc31373e8    0t0  UDP localhost:domain
named   508 bind  513u  IPv4 0xc31373d4    0t0  UDP localhost:domain
named   508 bind  514u  IPv4 0xc31373c0    0t0  UDP freebsd.example.com:domain
named   508 bind  515u  IPv6 0xc31373ac    0t0  UDP [fe80:2::ba27:ebff:fe41:b9ae]:domain
named   508 bind  516u  IPv6 0xc3137398    0t0  UDP freebsd.example.com:domain

Microsoft SMB/CIFS services

Three samba processes are providing five network services. Check /etc/services to figure out which is which.

# egrep -w '135|136|137|138|139|445' /etc/services
loc-srv         135/tcp    epmap        #Location Service
loc-srv         135/udp    epmap        #Location Service
profile         136/tcp    #PROFILE Naming System
profile         136/udp    #PROFILE Naming System
netbios-ns      137/tcp    #NETBIOS Name Service
netbios-ns      137/udp    #NETBIOS Name Service
netbios-dgm     138/tcp    #NETBIOS Datagram Service
netbios-dgm     138/udp    #NETBIOS Datagram Service
netbios-ssn     139/tcp    #NETBIOS Session Service
netbios-ssn     139/udp    #NETBIOS Session Service
microsoft-ds    445/tcp
microsoft-ds    445/udp
# lsof -i tcp:135-139 -o -i udp:135-139 -o -i tcp:445 -o -i udp:445
COMMAND  PID USER   FD   TYPE     DEVICE OFFSET NODE NAME
samba    691 root   41u  IPv6 0xc321d328    0t0  TCP *:loc-srv (LISTEN)
samba    691 root   42u  IPv4 0xc321d000    0t0  TCP *:loc-srv (LISTEN)
smbd     692 root   44u  IPv6 0xc321f978    0t0  TCP *:microsoft-ds (LISTEN)
smbd     692 root   45u  IPv6 0xc3480978    0t0  TCP *:netbios-ssn (LISTEN)
smbd     692 root   46u  IPv4 0xc3480650    0t0  TCP *:microsoft-ds (LISTEN)
smbd     692 root   47u  IPv4 0xc3480328    0t0  TCP *:netbios-ssn (LISTEN)
samba    693 root   24u  IPv4 0xc31372e4    0t0  UDP *:netbios-ns
samba    693 root   27u  IPv4 0xc31372d0    0t0  UDP *:netbios-dgm
samba    693 root   29u  IPv4 0xc31372bc    0t0  UDP 10.1.1.255:netbios-ns
samba    693 root   30u  IPv4 0xc31372a8    0t0  UDP freebsd.corp.example.com:netbios-ns
samba    693 root   31u  IPv4 0xc3137294    0t0  UDP 10.1.1.255:netbios-dgm
samba    693 root   32u  IPv4 0xc3137280    0t0  UDP freebsd.corp.example.com:netbios-dg

LDAP, LDAP/S

LDAP is needed for the directory service. We need both LDAP and Kerberos for Windows clients to move beyond old-style NetBIOS/LANMAN operation.

# lsof -i tcp:389 -o -i udp:389 -o -i tcp:636 -o -i udp:636
COMMAND PID USER   FD   TYPE     DEVICE OFFSET NODE NAME
samba   695 root   24u  IPv6 0xc3381328    0t0  TCP *:ldap (LISTEN)
samba   695 root   29u  IPv6 0xc3381000    0t0  TCP *:ldaps (LISTEN)
samba   695 root   33u  IPv4 0xc3380650    0t0  TCP *:ldap (LISTEN)
samba   695 root   34u  IPv4 0xc3380328    0t0  TCP *:ldaps (LISTEN)
samba   696 root   24u  IPv6 0xc313726c    0t0  UDP *:ldap
samba   696 root   30u  IPv4 0xc3137258    0t0  UDP *:ldap
samba   696 root   32u  IPv6 0xc3137244    0t0  UDP freebsd.corp.example.com:ldap
samba   696 root   33u  IPv4 0xc3137230    0t0  UDP freebsd.corp.example.com:ldap

Kerberos

Finally, Kerberos authenticates users and issues service tickets.

# lsof -i tcp:88 -o -i udp:88 -o -i tcp:464 -o -i udp:464
COMMAND PID USER   FD   TYPE     DEVICE OFFSET NODE NAME
samba   697 root   24u  IPv6 0xc3382000    0t0  TCP *:kerberos-sec (LISTEN)
samba   697 root   31u  IPv6 0xc313721c    0t0  UDP *:kerberos-sec
samba   697 root   33u  IPv6 0xc3381ca0    0t0  TCP *:kpasswd5 (LISTEN)
samba   697 root   34u  IPv6 0xc3137208    0t0  UDP *:kpasswd5
samba   697 root   35u  IPv4 0xc3381978    0t0  TCP *:kerberos-sec (LISTEN)
samba   697 root   36u  IPv4 0xc31371f4    0t0  UDP *:kerberos-sec
samba   697 root   37u  IPv4 0xc3381650    0t0  TCP *:kpasswd5 (LISTEN)
samba   697 root   38u  IPv4 0xc31371e0    0t0  UDP *:kpasswd5
samba   697 root   39u  IPv6 0xc31371cc    0t0  UDP freebsd.corp.example.com:kerberos-sec
samba   697 root   40u  IPv6 0xc31371b8    0t0  UDP freebsd.corp.example.com:kpasswd5
samba   697 root   41u  IPv4 0xc31371a4    0t0  UDP freebsd.corp.example.com:kerberos-sec
samba   697 root   42u  IPv4 0xc3137190    0t0  UDP freebsd.corp.example.com:kpasswd5

Testing

Let's see if we can get a list of the shares from another system:

$ smbclient -L //freebsd -U administrator
Enter administrator's password: ************
Domain=[CORP] OS=[Windows 6.1] Server=[Samba 4.3.13]

	Sharename       Type      Comment
	---------       ----      -------
	netlogon        Disk      
	sysvol          Disk
	IPC$            IPC       IPC Service (Samba 4.3.13)
Domain=[CORP] OS=[Windows 6.1] Server=[Samba 4.3.13]

	Server               Comment
	---------            -------

	Workgroup            Master
	---------            -------

The netlogon and sysvol shares must exist on a domain controller. They were created automatically during the provisioning. Let's test the sysvol share:

$ smbclient //freebsd/sysvol -U administrator -c 'dir'
Enter administrator's password: ************
Domain=[CORP] OS=[Windows 6.1] Server=[Samba 4.3.13]
  .                                   D        0  Fri Feb 17 10:40:28 2024
  ..                                  D        0  Fri Feb 17 13:57:46 2024
  corp.example.com                    D        0  Fri Feb 17 10:40:28 2024

                    30162908 blocks of size 1024. 25800308 blocks available

Let's see if we can get information about the AD server. I should be able to do that from the AD server itself and from another system, so long as its Samba configuration file /etc/samba/smb.conf is set up reasonably. Its [global] stanza should have a realm = REALM_NAME line.

$ net ads info
LDAP server: 10.1.1.235
LDAP server name: freebsd.corp.example.com
Realm: CORP.EXAMPLE.COM
Bind Path: dc=CORP,dc=EXAMPLE,dc=COM
LDAP port: 389
Server time: Wed, 15 Mar 2017 14:16:53 EST
KDC server: 10.1.1.235
Server time offset: 0

Can I get Kerberos credentials from a command prompt on the AD server?

$ klist
klist: No ticket file: /tmp/krb5cc_1000
$ kinit administrator@CORP.EXAMPLE.COM
administrator@CORP.EXAMPLE.COM's Password: ************
$ klist
Credentials cache: FILE:/tmp/krb5cc_1000
        Principal: administrator@CORP.EXAMPLE.COM

  Issued                Expires               Principal
Feb 17 16:43:02 2024  Feb 18 00:43:01 2024  krbtgt/CORP.EXAMPLE.COM@CORP.EXAMPLE.COM
$ klist -v
Credentials cache: FILE:/tmp/krb5cc_1000
        Principal: administrator@CORP.EXAMPLE.COM
   Cache version: 4

Server: krbtgt/CORP.EXAMPLE.COM@CORP.EXAMPLE.COM
Client: administrator@CORP.EXAMPLE.COM
Ticket etype: aes256-cts-hmac-sha1-96, kvno 1
Ticket length: 985
Auth time:  Feb 17 16:43:02 2024
End time:   Feb 18 00:43:01 2024
Ticket flags: pre-authent, initial, forwardable
Addresses: addressless

The above is on the AD server, so klist is from the Heimdal Kerberos implementation. I'll do this from another system where klist is from the MIT implementation. Unfortunately, the two implementations have different syntax.

$ klist
klist: No credentials cache found (filename: /tmp/krb5cc_1000)
$ kinit administrator@CORP.EXAMPLE.COM
administrator@CORP.EXAMPLE.COM's Password: ************
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: administrator@CORP.EXAMPLE.COM

Valid starting     Expires            Service principal
03/16/17 14:48:35  03/17/17 00:48:35  krbtgt/CORP.EXAMPLE.COM@CORP.EXAMPLE.COM
        renew until 03/17/17 14:48:33
$ klist -ef
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: administrator@CORP.EXAMPLE.COM

Valid starting     Expires            Service principal
03/16/17 14:48:35  03/17/17 00:48:35  krbtgt/CORP.EXAMPLE.COM@CORP.EXAMPLE.COM
	renew until 03/17/17 14:48:33, Flags: RIA
	Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96
The MIT Kerberos Administrator's How-To Guide MIT Kerberos Documentation BIND9_DLZ Back End Troubleshooting Red Hat Enterprise Linux Windows Integration Guide

It's working!

If it didn't there is troubleshooting information at samba.org.

The MIT How-To Guide starts with a very good overview of Kerberos. MIT has further Kerberos documentation if you need it. The Heimdal project has some good documentation about their implementation, although you won't be interacting with it directly.

Now we need to create users and groups

We need to define users and groups in the LDAP directory tree and Kerberos database. All of our testing has used Administrator, the only user defined so far. You use samba-tool to define AD groups and users. We will manage the Kerberos cryptography requirements with ktutil.

Yes, for standalone Kerberos you would use kadmin to manage the Kerberos database in /var/heimdal/heimdal.db, a Berkeley Btree database file.

However, Samba manages its own Kerberos database under /var/db/samba4/private/. You do all interaction with the Samba database, both the LDAP directory and the Kerberos database, using the samba-tool command. The exception to this is the use of ktutil to interact with the Kerberos keytab. You will see that in the next step.

The next page takes us through a practical deployment.

Raspberry Pi running FreeBSD.

An Active Directory server based on Samba running on FreeBSD on a Raspberry Pi.