= Samba 4 AD on ZFS =
== Introduction ==
This Wiki page covers installing and configuring Samba 4 as an Active Directory server on a ZFS system.
It was developed based on FreeBSD 11 (amd64) installed mid July 2017.

This install was an upgrade of an older FreeBSD system running Samba 3.6 using the 'classicupgrade' script using BIND for DNS and the Samba 4.5 port.

The example domain is 'example.org' - change to match your network.

== ToDo ==
The following is still not done
 * Work out why Samba 4.6 is broken (the upgrade script failed, I didn't investigate)
 * Check samba48 port which probably doesn't need the sysvol hack
 * Shadow copy support (this looks like it will require some small code changes - see https://bugzilla.samba.org/show_bug.cgi?id=11658)
 * Authenticating users via PAM (was deemed not useful enough for the hassle).
 * DHCP updating DNS (not enough DHCP used to be bothered).

== Installation ==
{{{#!highlight hs
cd /usr/ports/net/samba45
sudo make install
# Select BIND911 during the samba45 config phase
# Select GSSAPI_HEIMDAL during the bind911 config phase
}}}

== Configuration ==

=== Enable NFSv4 ACLs in your ZFS volume ===
{{{#!highlight sh 
sudo zfs set aclmode=passthrough zroot
sudo zfs set aclinherit=passthrough zroot
}}}

=== Setup UFS system volume ===
Samba's upgrade script is not smart enough (yet) to enable zfsacl automatically so it's simpler to have a POSIX ACL enabled UFS file system as sysvol.
{{{#!highlight sh 
sudo zfs create -V 2G zroot/samba4sysvol
sudo newfs /dev/zvol/zroot/samba4sysvol

# Add to /etc/fstab
sudo sh -c 'cat >>/etc/fstab' <<EOF
/dev/zvol/zroot/samba4sysvol /var/db/samba4/sysvol ufs       rw,acls 0       2
EOF

sudo mkdir -p /var/db/samba4/sysvol
sudo mount /var/db/samba4/sysvol
}}}

=== Copy old data ===
{{{#!highlight sh
sudo -i
mkdir -p /usr/local/samba.PDC/dbdir
cd /usr/local/samba.PDC
scp root@oldserver:/usr/local/etc/smb.conf smb.PDC.conf
scp root@oldserver:/usr/local/etc/samba/smbpasswd dbdir
scp root@oldserver:/usr/local/etc/samba/secrets.tdb dbdir/
scp root@oldserver:/usr/local/etc/samba/schannel_store.tdb dbdir/
scp root@oldserver:/usr/local/etc/samba/passdb.tdb dbdir/
scp root@oldserver:/var/spool/samba/locks/gencache_notrans.tdb dbdir/
scp root@oldserver:/var/spool/samba/locks/group_mapping.tdb dbdir/
scp root@oldserver:/var/spool/samba/locks/account_policy.tdb dbdir/
}}}

=== Run upgrade script ===
This was done iteratively - I ran the upgrade script and removed entries from the old smbpasswd file that it objected to.
{{{#!highlight sh
vi dbdir/smbpasswd
# Remove all cruft (old entries, conflicts, etc that the upgrade script complains about)
sudo samba-tool domain classicupgrade --dbdir=/usr/local/samba.PDC/dbdir/ --realm=example.org --dns-backend=BIND9_DLZ /usr/local/samba.PDC/smb.PDC.conf
}}}

=== Configure BIND ===
Generate an RNDC key by running..
{{{
rndc-confgen -a -k rndc-key -c tmp
}}}

Note the contents of "tmp" and combine with /usr/local/etc/named.conf as below..
{{{
options {
	// All file and path names are relative to the chroot directory,
	// if any, and should be fully qualified.
	directory	"/usr/local/etc/namedb/working";
	pid-file	"/var/run/named/pid";
	dump-file	"/var/dump/named_dump.db";
	statistics-file	"/var/stats/named.stats";

// These zones are already covered by the empty zones listed below.
// If you remove the related empty zones below, comment these lines out.
	disable-empty-zone "255.255.255.255.IN-ADDR.ARPA";
	disable-empty-zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA";
	disable-empty-zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA";

	forwarders {
		8.8.8.8;
		4.4.4.4;
	};

	empty-zones-enable yes;
	disable-empty-zone "example.org";
	disable-empty-zone "3.2.1.in-addr.arpa";

	tkey-gssapi-keytab "/var/db/samba4/private/dns.keytab";
};

zone "." {
        type slave;
        file "/usr/local/etc/namedb/slave/named.root";
        masters {
                192.0.32.132;           // lax.xfr.dns.icann.org
                2620:0:2d0:202::132;    // lax.xfr.dns.icann.org
                192.0.47.132;           // iad.xfr.dns.icann.org
                2620:0:2830:202::132;   // iad.xfr.dns.icann.org
        };
        notify no;
};

// IPv4 ARPA
zone "arpa" {
        type slave;
        file "/usr/local/etc/namedb/slave/arpa.root";
        masters {
                192.0.32.132;           // lax.xfr.dns.icann.org
                2620:0:2d0:202::132;    // lax.xfr.dns.icann.org
                192.0.47.132;           // iad.xfr.dns.icann.org
                2620:0:2830:202::132;   // iad.xfr.dns.icann.org
        };
        notify no;
};

// IPv6 ARPA
zone "ip6.arpa" {
        type slave;
        file "/usr/local/etc/namedb/slave/ip6.arpa.root";
        masters {
                192.0.32.132;           // lax.xfr.dns.icann.org
                2620:0:2d0:202::132;    // lax.xfr.dns.icann.org
                192.0.47.132;           // iad.xfr.dns.icann.org
                2620:0:2830:202::132;   // iad.xfr.dns.icann.org
        };
        notify no;
};

// RFCs 1912, 5735 and 6303 (and BCP 32 for localhost)
zone "localhost"	{ type master; file "/usr/local/etc/namedb/master/localhost-forward.db"; };
zone "127.in-addr.arpa"	{ type master; file "/usr/local/etc/namedb/master/localhost-reverse.db"; };

key "rndc-key" {
	algorithm hmac-md5;
	secret "XXXXXX";
};

controls {
	inet 127.0.0.1 port 953
		allow { 127.0.0.1; } keys { "rndc-key"; };
};
include "/var/db/samba4/private/named.conf";
}}}
Where "XXXXXX" is the key material.
Also update the non-empty zones to match your domain and IP range.

Create "/usr/local/etc/namedb/rndc.conf"

{{{
key "rndc-key" {
        algorithm hmac-md5;
        secret "XXXXXX";
};

options {
        default-key "rndc-key";
        default-server 127.0.0.1;
        default-port 953;
};
}}}
Where "XXXXXX" is the key material.

This file should be owned root:wheel with permissions 0640.

Check "/var/db/samba4/private/named.conf" and make sure only the "dlz_bind9_11.so" line is uncommented.

=== Configure Samba ===
The following configuration will create a 'users' share and a 'public' share.

{{{
# Global parameters
[global]
        log level = all:2
        netbios name = EXAMPLEHOST
        realm = EXAMPLE.ORG
        workgroup = EXAMPLE
        server role = active directory domain controller
        server services = -dns
        idmap_ldb:use rfc2307 = yes

[netlogon]
        path = /var/db/samba4/sysvol/example.org/scripts
        read only = No

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

[users]
        comment = User home directories
        path = /usr/home
        read only = no
        vfs objects = zfsacl

[public]
        comment = Public
        path = /public
        read only = no
        public = yes
        vfs objects = zfsacl
}}}

Note that AD mode is incompatible with the home directories feature, the 'users' share above is the canonical (Windows) way to do this.

=== Configure Kerberos ===
Copy the Kerberos configuration and key tab created by the classicupgrade script
{{{#!highligh sh
sudo cp -p /var/db/samba4/private/krb5.conf /etc/
sudo cp -p /var/db/samba4/private/secrets.keytab /etc/krb5.keytab
}}}

Modify "/etc/krb5.conf" so it looks like so
{{{
[libdefaults]
        default_realm = EXAMPLE.ORG
        dns_lookup_realm = false
        dns_lookup_kdc = true
        default_ccache_name = /tmp/krb5cc_%{uid}

[domain_realm]
        .example.org = EXAMPLE.ORG
}}}

=== Configure NSS ===
Modify "/etc/nsswitch.conf" to comment out group, group_compat, passed and passwd_compat and replace with
{{{
group: files winbind
passwd: files winbind
}}}

=== Configure /etc/hosts ===
Add an entry to "/etc/hosts" which matches the hostname to to the IP, e.g.
{{{
1.2.3.4  examplehost example host.example.org
}}}

=== Configure rc.conf ===
Add this to /etc/rc.conf to start bind & Samba at boot
{{{
samba_server_enable="YES"
named_enable="YES"
}}}

=== Start daemons ===
Reboot or run the following to start BIND and Samba
{{{
sudo service samba_server start
sudo service named start
}}}

== Testing ==
You should now be able to use "getent" to query Samba, eg..
{{{
[examplehost 14:38] ~ >getent group Domain\ Users
EXAMPLE\domain users:x:20
[examplehost 14:38] ~ >getent group Domain\ Admins
EXAMPLE\domain admins:x:0
}}}

== Permissions ==
In order for Windows to be able to manage permissions someone has to be given the right to change permissions. This can be done like so
{{{
sudo setfacl -m g:Domain\ Admins:cC:fd:allow /public /usr/home
}}}

== Useful Commands ==
=== DNS ===
As Samba is now managing DNS you need to get it to add/remove records. This can be done with the Windows management tools or using samba-tool, e.g.
{{{
# Get a Kerberos ticket as an admin user
kinit

# List all zones
samba-tool dns zonelist examplehost -k yes

# List all forward records
samba-tool dns query examplehost -k yes example.org @ ALL

# Create reverse zone (not done by default)
samba-tool dns zonecreate examplehost -k yes 1.2.3.in-addr.arpa

# Add A record for testpc -> 1.2.3.10
samba-tool dns add examplehost -k yes example.org testpc A 1.2.3.10
samba-tool dns add examplehost -k yes 3.2.1.in-addr.arpa 10 CNAME testpc.example.org.

# Delete above records
samba-tool dns delete examplehost -k yes example.org testpc A 1.2.3.10
samba-tool dns delete examplehost -k yes 3.2.1.in-addr.arpa 10 CNAME testpc.example.org.
}}}

=== Set permissions ===
Grant group "Domain Users" all permissions on /somedir and contents
{{{
sudo find /somedir -type f -print0 | sudo xargs -0 setfacl -m g:Domain\ Users:full_set::allow
sudo find /somedir -type d -print0 | sudo xargs -0 setfacl -m g:Domain\ Users:full_set:fd:allow
}}}
Or for everybody (probably not wise, since it's like chmod 777/666)
{{{
sudo find /somedir -type f -print0 | sudo xargs -0 setfacl -m @everybody:full_set::allow
sudo find /somedir -type d -print0 | sudo xargs -0 setfacl -m @everybody:full_set:fd:allow
}}}

=== Limited privilege users ===
Create a "dhcpuser" who is a member of "!DnsAdmins" which could be used to from a DHCP server to updated DNS
{{{
samba-tool user create dhcpduser --description="Unprivileged user for TSIG-GSSAPI DNS updates via ISC DHCP server" --random-password
samba-tool user setexpiry dhcpduser --noexpiry
samba-tool group addmembers DnsAdmins dhcpduser
samba-tool domain exportkeytab --principal=dhcpduser@example.org dhcpduser.keytab
sudo cp dhcpduser.keytab /usr/local/etc/dhcpduser.keytab
}}}
Note that I have only done limited testing here. This is based on an !ArchLinux Wiki page https://wiki.archlinux.org/index.php/Samba/Active_Directory_domain_controller and the package https://aur.archlinux.org/packages/samba-dhcpd-update/

=== Edit user profile information ===
{{{
sudo ldbedit -H /var/db/samba4/private/sam.ldb 'sAMAccountName=testuser'
}}}

=== Time synchronisation ===
When a Windows PC is joined to a domain the 'Internet Time' tab will disappear and it will instead only synchronise to the DC. For this to work NTPd needs to be configured to sign messages (with Samba's help).

Edit /etc/ntp.conf and add/modify the following..
{{{
ntpsigndsocket /var/run/samba4/ntp_signd/
restrict -4 default kod notrap nomodify nopeer noquery mssntp
restrict -6 default kod notrap nomodify nopeer noquery mssntp
}}}

And restart NTPd (eg '''sudo service ntpd restart''')

Time synchronisation on a client Windows PC can be checked by running the following..
{{{
w32tm /stripchart /computer:time.windows.com /dataonly
}}}
Which will give output like so
{{{
C:\Users\darius>w32tm /stripchart /computer:time.windows.com /dataonly
Tracking time.windows.com [52.163.118.68:123].
The current time is 10/01/2018 9:49:52 AM.
09:49:52, +00.0064586s
09:49:55, -00.0050746s
09:49:57, -00.0034439s
09:49:59, -00.0038588s
09:50:01, +00.1017965s
09:50:04, -00.0029371s
09:50:06, -00.0055241s
09:50:08, -00.0004811s
09:50:10, -00.0039628s
^C
}}}

----
CategoryHowTo CategoryZfs