Difference between revisions of "Samba/Active Directory domain controller"

From ArchWiki
Jump to navigation Jump to search
m (Creating a new directory: typo)
 
(59 intermediate revisions by 12 users not shown)
Line 1: Line 1:
 
[[Category:Network sharing]]
 
[[Category:Network sharing]]
[[ru:Samba 4 Active Directory domain controller]]
+
[[ja:Samba/Active Directory ドメインコントローラ]]
 +
[[ru:Samba/Active Directory domain controller]]
 
{{Related articles start}}
 
{{Related articles start}}
 
{{Related|Active Directory Integration}}
 
{{Related|Active Directory Integration}}
{{Related|OpenChange server}}
 
 
{{Related|Samba}}
 
{{Related|Samba}}
{{Related|Samba/Tips and tricks}}
+
{{Related|SOGo}}
{{Related|Samba Domain Controller}}
 
 
{{Related articles end}}
 
{{Related articles end}}
  
This article explains how to setup a new Active Directory Domain Controller. It is assumed that all configuration files are in their unmodified, post-installation state. This article was written and tested on a fresh installation, with no modifications other than setting up a staic IPv4 network connection, assigning a hostname, and adding openssh and vim (which should have no effect on the Samba configuration). Finally, most of the commands below will require elevated privileges. Despite conventional wisdom, it may be easier to run these short few commands from a root session as opposed to obtaining rights on an as needed basis.
+
This article explains how to setup an Active Directory domain controller using [[Samba]]. It is assumed that all configuration files are in their unmodified, post-installation state. This article was written and tested on a fresh installation, with no modifications other than setting up a static IPv4 network connection, and adding openssh and vim (which should have no effect on the Samba configuration). Finally, most of the commands below will require elevated privileges. Despite conventional wisdom, it may be easier to run these short few commands from a root session as opposed to obtaining rights on an as needed basis.
  
 
==Installation==
 
==Installation==
  
A fully functional samba 4 DC requires several programs beyond those included with the Samba distribution. [[Install]] the {{Pkg|bind-tools}}, {{Pkg|krb5}}, {{Pkg|ntp}}, {{Pkg|openldap}}, and {{Pkg|samba}} packages.
+
{{Note|Make sure you can access the machines in your network via their hostname. See [[Network configuration#Local network hostname resolution]] for more information.}}
  
Additionally, Samba contains its own fully functional DNS server, but many administrators prefer to use the ISC BIND package. If you need to maintain DNS zones for external domains, you are strongly encouraged to use {{Pkg|bind}}. If you need to share printers, you will also need {{Pkg|cups}}. If needed, install the {{Pkg|bind}} and/or {{Pkg|cups}} packages.
+
A fully functional samba domain controller requires several programs beyond those included with the Samba distribution. [[Install]] the {{Pkg|bind-tools}}, {{Pkg|krb5}}, {{Pkg|ntp}}, {{Pkg|openresolv}} and {{Pkg|samba}} packages.
  
==Provisioning==
+
Samba contains its own fully functional DNS server, but if you need to maintain DNS zones for external domains, you are strongly encouraged to use [[BIND]] instead. If you need to share printers, you will also need [[CUPS]]. If needed, install the {{Pkg|bind}} and/or {{Pkg|cups}} packages.
  
The first step to creating an Active Directory domain is provisioning. If this is the first domain controller in a new domain (as this guide assumes), this involves setting up the internal LDAP, Kerberos, and DNS servers and performing all of the basic configuration needed for the directory. If you have set up a directory server before, you are undoubtedly aware of the potential for errors in making these individual components work together as a single unit. The difficulty in doing so is the very reason that the Samba developers chose not to use the MIT or Heimdal Kerberos server or OpenLDAP server, instead opting for internal versions of these programs. The server packages above were installed only for the client utilities. Provisioning is quite a bit easier with Samba 4. Just issue the following command:
+
== Creating a new directory ==
  
# samba-tool domain provision --use-rfc2307 --use-xattrs=yes --interactive
+
===Provisioning===
  
===Argument explanations===
+
The first step to creating an Active Directory domain is provisioning. This involves setting up the internal [[LDAP]], [[Kerberos]], and DNS servers and performing all of the basic configuration needed for the directory. If you have set up a directory server before, you are undoubtedly aware of the potential for errors in making these individual components work together as a single unit. The difficulty in doing so is the very reason that the Samba developers chose to provide internal versions of these programs. The server packages above were installed only for the client utilities. Provisioning is quite a bit easier with Samba. Just issue the following command:
 +
 
 +
# samba-tool domain provision --use-rfc2307 --interactive
 +
 
 +
====Argument explanations====
 
;--use-rfc2307
 
;--use-rfc2307
:this argument adds POSIX attributes (UID/GID) to the AD Schema. This will be necessary if you intend to authenticate Linux, BSD, or OS X clients (including the local machine) in addition to Microsoft Windows.
+
:this argument adds POSIX attributes (UID/GID) to the AD Schema. This will be necessary if you intend to authenticate Linux, BSD, or macOS clients (including the local machine) in addition to Microsoft Windows.
 
 
;--use-xattrs=yes
 
:this argument enables the use of unix extended attributes (ACLs) for files hosted on this server. If you intend not have file shares on the domain controller, you can omit this switch (but this is not recommended). You should also ensure that any filesystems that will host Samba shares are mounted with support for ACLs.
 
  
 
;--interactive
 
;--interactive
 
:this parameter forces the provision script to run interactively. Alternately, you can review the help for the provision step by running {{ic|samba-tool domain provision --help}}.
 
:this parameter forces the provision script to run interactively. Alternately, you can review the help for the provision step by running {{ic|samba-tool domain provision --help}}.
  
===Interactive provision explanations===
+
====Interactive provision explanations====
 
;Realm
 
;Realm
 
:'''INTERNAL.DOMAIN.COM''' - This should be the same as the DNS domain in all caps. It is common to use an internal-only sub-domain to separate your internal domain from your external DNS domains, but it is not required.
 
:'''INTERNAL.DOMAIN.COM''' - This should be the same as the DNS domain in all caps. It is common to use an internal-only sub-domain to separate your internal domain from your external DNS domains, but it is not required.
Line 49: Line 49:
 
:'''xxxxxxxx''' - You must select a ''strong'' password for the administrator account. The minimum requirements are one upper case letter, one number, and at least eight characters. If you attempt to use a password that does not meet the complexity requirements, provisioning will fail.
 
:'''xxxxxxxx''' - You must select a ''strong'' password for the administrator account. The minimum requirements are one upper case letter, one number, and at least eight characters. If you attempt to use a password that does not meet the complexity requirements, provisioning will fail.
  
==Configuring daemons==
+
===Configuring daemons===
 +
 
 +
====NTPD====
 +
 
 +
Create a suitable NTP configuration for your network time server. See [[Network Time Protocol daemon]] for explanations of, and additional configuration options.
  
===NTPD===
+
Modify the {{ic|/etc/ntp.conf}} file with the following contents:
  
Create a suitable NTP configuration for your network time server. See [[Ntpd]] for explanations of, and additional configuration options.
+
{{hc|/etc/ntp.conf|<nowiki>
Create a backup copy of the default file:
+
# Please consider joining the pool:
 +
#
 +
#    http://www.pool.ntp.org/join.html
 +
#
 +
# For additional information see:
 +
# - https://wiki.archlinux.org/index.php/Network_Time_Protocol_daemon
 +
# - http://support.ntp.org/bin/view/Support/GettingStarted
 +
# - the ntp.conf man page
  
# mv /etc/ntp.conf{,.default}
+
# Associate to Arch's NTP pool
 +
server 0.arch.pool.ntp.org
 +
server 1.arch.pool.ntp.org
 +
server 2.arch.pool.ntp.org
 +
server 3.arch.pool.ntp.org
  
Create the {{ic|/etc/ntp.conf}} file with the following contents:
+
# Restrictions
 +
restrict default kod limited nomodify notrap nopeer mssntp
 +
restrict 127.0.0.1
 +
restrict ::1
 +
restrict 0.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 +
restrict 1.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 +
restrict 2.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 +
restrict 3.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
  
# Begin /etc/ntp.conf
+
# Location of drift file
+
driftfile /var/lib/ntp/ntpd.drift
# Associate to the public NTP pool servers
 
server 0.pool.ntp.org
 
server 1.pool.ntp.org
 
server 2.pool.ntp.org
 
 
# Location of drift file
 
driftfile /var/lib/ntp/ntpd.drift
 
 
# Location of the log file
 
logfile /var/log/ntpd
 
 
# Location of the update directory
 
ntpsigndsocket /var/lib/samba/ntp_signd/
 
 
# Restrictions
 
restrict default kod limited nomodify notrap nopeer mssntp
 
restrict 127.0.0.1
 
restrict ::1
 
restrict 0.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 
restrict 1.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 
restrict 2.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
 
 
# End /etc/ntp.conf
 
  
 +
# Location of the update directory
 +
ntpsigndsocket /var/lib/samba/ntp_signd/
 +
</nowiki>}}
  
 
Create the state directory and set permissions:
 
Create the state directory and set permissions:
Line 93: Line 95:
 
  # chmod 0750 /var/lib/samba/ntp_signd
 
  # chmod 0750 /var/lib/samba/ntp_signd
  
Enable and start the {{ic|ntpd}} service.
+
Enable and start the {{ic|ntpd.service}} unit.
 +
 
 +
====BIND====
  
===BIND===
+
If you elected to use the '''BIND9_DLZ''' DNS backend, [[Install]] the {{Pkg|bind}} package and create the following BIND configuration. See [[BIND]] for explanations of, and additional configuration options. Be sure to replace the '''x''' characters with suitable values:
  
If you elected to use the '''BIND9_DLZ''' DNS backend, create the following BIND configuration. See [[BIND]] for explanations of, and additional configuration options. Be sure to replace the '''x''' characters with suitable values:
+
Create the {{ic|/etc/named.conf}} file:
First, create a backup of the default configuration file:
 
  
# mv /etc/named.conf{,.default}
+
{{hc|/etc/named.conf|<nowiki>
 +
options {
 +
    directory "/var/named";
 +
    pid-file "/run/named/named.pid";
  
Create the {{ic|/etc/named.conf}} file:
+
    // Uncomment these to enable IPv6 connections support
 +
    // IPv4 will still work:
 +
    //  listen-on-v6 { any; };
 +
    // Add this for no IPv4:
 +
    //  listen-on { none; };
 +
 
 +
    auth-nxdomain yes;
 +
    datasize default;
 +
    empty-zones-enable no;
 +
    tkey-gssapi-keytab "/var/lib/samba/private/dns.keytab";
 +
    forwarders { </nowiki>'''xxx.xxx.xxx.xxx'''; '''xxx.xxx.xxx.xxx''';<nowiki> };
 +
 
 +
    //  Add any subnets or hosts you want to allow to use this DNS server (use "; " delimiter)
 +
    allow-query    { </nowiki>'''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8;<nowiki> };
 +
 
 +
    //  Add any subnets or hosts you want to allow to use recursive queries
 +
    allow-recursion { </nowiki>'''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8;<nowiki> };
 +
 
 +
    //  Add any subnets or hosts you want to allow dynamic updates from
 +
    allow-update    { </nowiki>'''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8;<nowiki> };
 +
 
 +
    allow-transfer { none; };
 +
    version none;
 +
    hostname none;
 +
    server-id none;
 +
};
 +
 
 +
zone "localhost" IN {
 +
    type master;
 +
    file "localhost.zone";
 +
};
 +
 
 +
zone "0.0.127.in-addr.arpa" IN {
 +
    type master;
 +
    file "127.0.0.zone";
 +
};
 +
 
 +
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" {
 +
    type master;
 +
    file "localhost.ip6.zone";
 +
};
 +
 
 +
zone "255.in-addr.arpa" IN {
 +
    type master;
 +
    file "empty.zone";
 +
};
 +
 
 +
zone "0.in-addr.arpa" IN {
 +
    type master;
 +
    file "empty0.zone";
 +
};
 +
 
 +
zone "." IN {
 +
    type hint;
 +
    file "root.hint";
 +
};
 +
 
 +
//Load AD integrated zones
 +
dlz "AD DNS Zones" {
 +
    database "dlopen /usr/lib/samba/bind9/dlz_bind9_10.so";
 +
};
  
//Begin /etc/named.conf
+
//zone "example.org" IN {
+
//    type slave;
// Global options
+
//    file "example.zone";
options {
+
//    masters {
    auth-nxdomain yes;
+
//       192.168.1.100;
    datasize default;
+
//   };
    directory "/var/named";
+
//   allow-query { any; };
    empty-zones-enable no;
+
//    allow-transfer { any; };
    pid-file "/run/named/named.pid";
+
//};
    tkey-gssapi-keytab "/var/lib/samba/private/dns.keytab";
+
//
    forwarders { '''xxx.xxx.xxx.xxx'''; '''xxx.xxx.xxx.xxx'''; };
+
logging {
//  Uncomment the next line to enable IPv6
 
//    listen-on-v6 { any; };
 
//  Add this for no IPv4:
 
//    listen-on { none; };
 
    notify no;
 
//  Add any subnets or hosts you want to allow to use this DNS server (use "; " delimiter)
 
    allow-query    { '''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8; };
 
//  Add any subnets or hosts you want to allow to use recursive queries
 
    allow-recursion { '''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8; };
 
// Add any subnets or hosts you want to allow dynamic updates from
 
    allow-update   { '''xxx.xxx.xxx.xxx/xx'''; 127.0.0.0/8; };
 
    version none;
 
    hostname none;
 
    server-id none;
 
};
 
 
//Root servers (required zone for recursive queries)
 
zone "." IN {
 
    type hint;
 
    file "root.hint";
 
};
 
 
//Required localhost forward-/reverse zones
 
zone "localhost" IN {
 
    type master;
 
    file "localhost.zone";
 
// allow-transfer { any; };
 
};
 
zone "0.0.127.in-addr.arpa" IN {
 
    type master;
 
    file "127.0.0.zone";
 
// allow-transfer { any; };
 
};
 
// Uncomment the following zone for IPv6 support
 
//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" IN {
 
//    type master;
 
//    file "localhost.ip6.zone";
 
//    allow-transfer { any; };
 
//};
 
 
//Load AD integrated zones
 
dlz "AD DNS Zones" {
 
    database "dlopen /usr/lib/samba/bind9/dlz_bind9_10.so";
 
};
 
 
//Log settings
 
logging {
 
 
     channel xfer-log {
 
     channel xfer-log {
 
         file "/var/log/named.log";
 
         file "/var/log/named.log";
        print-category yes;
+
            print-category yes;
        print-severity yes;
+
            print-severity yes;
        print-time yes;
+
            severity info;
        severity info;
+
        };
    };
+
        category xfer-in { xfer-log; };
    category xfer-in { xfer-log; };
+
        category xfer-out { xfer-log; };
    category xfer-out { xfer-log; };
+
        category notify { xfer-log; };
    category notify { xfer-log; };
+
};
};
+
</nowiki>}}
 
//End /etc/named.conf
 
  
 
Set permissions:
 
Set permissions:
Line 184: Line 201:
 
  # chmod 664 /var/log/named.log
 
  # chmod 664 /var/log/named.log
  
Enable and start the {{ic|named}} service.
+
<!-- Remove and adjust above configuration file for new version when this is fixed in arch -->
 +
Fix for recent versions of bind:
 +
 
 +
# copy /var/named/empty.zone /var/named/empty0.zone
 +
# chown root:named /var/named/empty0.zone
 +
 
 +
Enable and start the {{ic|named.service}} unit.
  
 
Good values for forwarders are your ISP's DNS servers. Google (8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, and 2001:4860:4860::8844) and OpenDNS (208.67.222.222, 208.67.220.220, 2620:0:ccc::2 and 2620:0:ccd::2) provide suitable public DNS servers free of charge. Appropriate values for subnets are specific to your network.
 
Good values for forwarders are your ISP's DNS servers. Google (8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, and 2001:4860:4860::8844) and OpenDNS (208.67.222.222, 208.67.220.220, 2620:0:ccc::2 and 2620:0:ccd::2) provide suitable public DNS servers free of charge. Appropriate values for subnets are specific to your network.
  
===Kerberos client utilities===
+
====Kerberos client utilities====
  
The provisioning step above created a perfectly valid krb5.conf file for use with a Samba 4 DC. Install it with the following commands:
+
The provisioning step above created a perfectly valid krb5.conf file for use with a Samba domain controller. Install it with the following commands:
  
 
  # mv /etc/krb5.conf{,.default}
 
  # mv /etc/krb5.conf{,.default}
 
  # cp /var/lib/samba/private/krb5.conf /etc
 
  # cp /var/lib/samba/private/krb5.conf /etc
  
===DNS===
+
====DNS====
  
You will need to begin using the local DNS server now. If your interface configuration files use resolvconf, reconfigure them appropriately. Create the {{ic|/etc/resolv.conf.tail}} (do not forget to substitute '''internal.domain.tld''' with your internal domain):
+
You will need to begin using the local DNS server now. Reconfigure resolvconf to use only localhost for DNS lookups. Create the {{ic|/etc/resolv.conf.tail}} (do not forget to substitute '''internal.domain.tld''' with your internal domain):
  
 
  # Samba configuration
 
  # Samba configuration
Line 205: Line 228:
 
  nameserver 127.0.0.1
 
  nameserver 127.0.0.1
  
Set permissions and regenerate the new {{ic|/etc/resolv.conf}} file
+
Set permissions and regenerate the new {{ic|/etc/resolv.conf}} file:
  
 
  # chmod 644 /etc/resolv.conf.tail
 
  # chmod 644 /etc/resolv.conf.tail
 
  # resolvconf -u
 
  # resolvconf -u
  
===Samba===
+
====Samba====
  
Enable and start the {{ic|samba}} service. If you intend to use the LDB utilities, you will also need create the {{ic|/etc/profile.d/sambaldb.sh}} file to set '''LDB_MODULES_PATH''':
+
Enable and start the {{ic|samba.service}} unit. If you intend to use the LDB utilities, you will also need create the {{ic|/etc/profile.d/sambaldb.sh}} file to set '''LDB_MODULES_PATH''':
  
 
  export LDB_MODULES_PATH="${LDB_MODULES_PATH}:/usr/lib/samba/ldb"
 
  export LDB_MODULES_PATH="${LDB_MODULES_PATH}:/usr/lib/samba/ldb"
Line 220: Line 243:
 
  # . /etc/profile.d/sambaldb.sh
 
  # . /etc/profile.d/sambaldb.sh
  
==Testing the installation==
+
===Testing the installation===
  
===DNS===
+
====DNS====
  
 
First, verify that DNS is working as expected. Execute the following commands substituting appropriate values for '''internal.domain.com''' and '''server''':
 
First, verify that DNS is working as expected. Execute the following commands substituting appropriate values for '''internal.domain.com''' and '''server''':
Line 236: Line 259:
 
server.internal.domain.com has address xxx.xxx.xxx.xxx}}
 
server.internal.domain.com has address xxx.xxx.xxx.xxx}}
  
===NT authentication===
+
====NT authentication====
  
 
Next, verify that password authentication is working as expected:
 
Next, verify that password authentication is working as expected:
Line 250: Line 273:
 
50332 blocks of size 2097152. 47185 blocks available}}
 
50332 blocks of size 2097152. 47185 blocks available}}
  
===Kerberos===
+
====Kerberos====
  
 
Now verify that the KDC is working as expected. Be sure to replace '''INTERNAL.DOMAIN.COM''' and use upper case letters:
 
Now verify that the KDC is working as expected. Be sure to replace '''INTERNAL.DOMAIN.COM''' and use upper case letters:
Line 279: Line 302:
 
The output should be the same as when testing password authentication above.
 
The output should be the same as when testing password authentication above.
  
==Additional configuration ==
+
===Additional configuration ===
  
=== DNS ===
+
==== DNS ====
  
 
You will also need to create a reverse lookup zone for each subnet in your environment in DNS. It is important that this is kept in Samba's DNS as opposed to BIND to allow for dynamic updates by cleints. For each subnet, create a reverse lookup zone with the following commands. Replace '''server'''.'''internal'''.'''domain'''.'''tld''' and '''xxx'''.'''xxx'''.'''xxx''' with appropriate values. For '''xxx'''.'''xxx'''.'''xxx''', use the first three octets of the subnet in reverse order (for example: 192.168.0.0/24 becomes 0.168.192):
 
You will also need to create a reverse lookup zone for each subnet in your environment in DNS. It is important that this is kept in Samba's DNS as opposed to BIND to allow for dynamic updates by cleints. For each subnet, create a reverse lookup zone with the following commands. Replace '''server'''.'''internal'''.'''domain'''.'''tld''' and '''xxx'''.'''xxx'''.'''xxx''' with appropriate values. For '''xxx'''.'''xxx'''.'''xxx''', use the first three octets of the subnet in reverse order (for example: 192.168.0.0/24 becomes 0.168.192):
  
  # samba-tool dns zonecreate '''server'''.'''internal'''.'''domain'''.'''tld''' '''xxx'''.'''xxx'''.'''xxx'''.in-addr.arpa
+
  # samba-tool dns zonecreate '''server'''.'''internal'''.'''domain'''.'''tld''' '''xxx'''.'''xxx'''.'''xxx'''.in-addr.arpa -U Administrator
  
 
Now, add a record for you server (if your server is multi-homed, add for each subnet) again substituting appropriate values as above. '''zzz''' will be replaced by the fourth octet of the IP for the server:
 
Now, add a record for you server (if your server is multi-homed, add for each subnet) again substituting appropriate values as above. '''zzz''' will be replaced by the fourth octet of the IP for the server:
  
  # samba-tool dns add '''server'''.'''internal'''.'''domain'''.'''tld''' '''xxx'''.'''xxx'''.'''xxx'''.in-addr.arpa '''zzz''' PTR '''server'''.'''internal'''.'''domain'''.'''tld'''
+
  # samba-tool dns add '''server'''.'''internal'''.'''domain'''.'''tld''' '''xxx'''.'''xxx'''.'''xxx'''.in-addr.arpa '''zzz''' PTR '''server'''.'''internal'''.'''domain'''.'''tld''' -U Administrator
  
 
Restart the {{ic|samba}} service. If using BIND for DNS, restart the {{ic|named}} service as well.
 
Restart the {{ic|samba}} service. If using BIND for DNS, restart the {{ic|named}} service as well.
Line 301: Line 324:
 
  xxx.xxx.xxx.xxx.in-addr.arpa domain name pointer server.internal.domain.tld.
 
  xxx.xxx.xxx.xxx.in-addr.arpa domain name pointer server.internal.domain.tld.
  
===SSL===
+
====TLS====
  
By defualt, SSL support is not enabled, however, a default certificate was created when the DC was brought up. To use the default keys, append the following lines to the "'''[global]'''" section of the {{ic|/etc/samba/smb.conf}} file:
+
TLS support is not enabled by default, however, a default certificate was created when the DC was brought up. With the release of Samba 4.3.8 and 4.2.2, unsecured LDAP binds are disabled by default, and you must configure TLS to use Samba as an authentication source (without reducing the security of your Samba installation). To use the default keys, append the following lines to the "'''[global]'''" section of the {{ic|/etc/samba/smb.conf}} file:
  
 
         tls enabled  = yes
 
         tls enabled  = yes
Line 310: Line 333:
 
         tls cafile  = tls/ca.pem
 
         tls cafile  = tls/ca.pem
  
If a trusted certificate is needed, create a signing key and a certificate request with the following commands (make certain that the Common Name matches the FQDN of the server and do not enter a password):
+
If a trusted certificate is needed, create a signing key and a certificate request (see [[OpenSSL]] for detailed instructions). Get the request signed by your chosen certificate authority, and put into this directory. If your certificate authority also needs an intermediate certificate, concatenate the certs (server cert first, then intermediate) and leave '''tls cafile''' blank.
  
# cd /var/lib/samba/private/tls
+
Restart {{ic|samba}} for the changes to take effect.
# openssl genrsa -out '''NETBIOS'''_KEY.pem 2048
 
# openssl req -new -key '''NETBIOS'''_KEY.pem -out '''NETBIOS'''_CSR.pem
 
  
Get the CSR signed by your chosen certificate authority, name appropriately ('''NETBIOS'''_CERT.pem for this example), and put into this directory. If your certifiacte authority also needs an intermedia certificate, put it there as well and use the '''tls cafile''' parmeter (else leave '''tls cafile''' blank).
+
== Adding a second domain controller to an existing domain ==
  
Restart {{ic|samba}} for the changes to take effect.
+
TBA...
 +
 
 +
== Tips and tricks ==
  
===DHCP===
+
===DHCP with dynamic DNS updates ===
  
It should be noted that using this method will affect functionality of windows clients, as they will still attempt to update DNS on their own and will be denied permission to do so as the record will be owned by the dhcp user. You should create a GPO to overcome this, but unfortunately, Samba 4 does not yet have a command line utility to modify GPOs, so you will need a Windows PC with the RSAT tools installed. Simply create a dedicated GPO with the Group Policy Editor, apply only to OUs that contain workstations (so that servers can still update using 'ipconfig /registerdns') and configure the following settings:
+
It should be noted that using this method will affect functionality of windows clients, as they will still attempt to update DNS on their own. When this occurs, the machine will be denied permission to do so as the record will be owned by the dhcp user rather than the machine account. While this is essentially harmless, it will generate warnings in the system log of the offending machine. You should create a GPO to overcome this, but unfortunately, Samba does not yet have a command line utility to modify GPOs. You will need a Windows PC with the RSAT tools installed. Simply create a dedicated GPO with the Group Policy Editor, and apply only to OUs that contain workstations (so that servers can still update using 'ipconfig /registerdns') and configure the following settings:
  
 
{{bc|1=Computer Configuration
 
{{bc|1=Computer Configuration
Line 332: Line 355:
 
           Register PTR Records = Disabled}}
 
           Register PTR Records = Disabled}}
  
[[Install]] the {{Pkg|dhcp}} package.
+
[[Install]] the {{Pkg|dhcp}} package and the {{AUR|samba-dhcpd-update}} package.
  
 
Create an unprivileged user in AD for performing the updates. When prompted for password, use a secure password. 63 random, mixed case, alpha-numeric characters is sufficient. Optionally samba-tool also takes a random argument:
 
Create an unprivileged user in AD for performing the updates. When prompted for password, use a secure password. 63 random, mixed case, alpha-numeric characters is sufficient. Optionally samba-tool also takes a random argument:
Line 342: Line 365:
 
  # samba-tool user setexpiry dhcp --noexpiry
 
  # samba-tool user setexpiry dhcp --noexpiry
  
Give the user privelges to administer DNS:
+
Give the user privileges to administer DNS:
 
  # samba-tool group addmembers DnsAdmins dhcp
 
  # samba-tool group addmembers DnsAdmins dhcp
  
Line 352: Line 375:
 
  # chmod 400 /etc/dhcpd/dhcpd.keytab
 
  # chmod 400 /etc/dhcpd/dhcpd.keytab
  
Now that the user is created, add create the {{ic|/usr/local/sbin/samba-dnsupdate.sh}} script to perform the updates:
+
Modify the {{ic|dhcpd-update-samba-dns.conf}} file with the following commands (substituting correct values for '''server''', '''internal'''.'''domain'''.'''tld''', and '''INTERNAL'''.'''DOMAIN'''.'''TLD'''):
 +
 
 +
{{hc|/etc/dhcpd/dhcpd-update-samba-dns.conf|<nowiki>
 +
# Variables
 +
KRB5CC="/run/dhcpd4.krb5cc"
 +
KEYTAB="/etc/dhcpd/dhcpd.keytab"
 +
DOMAIN=</nowiki>"'''internal'''.'''domain'''.'''tld'''"<nowiki>
 +
REALM=</nowiki>"'''INTERNAL'''.'''DOMAIN'''.'''TLD'''"<nowiki>
 +
PRINCIPAL="dhcp@${REALM}"
 +
NAMESERVER="</nowiki>'''server'''<nowiki>.${DOMAIN}"
 +
ZONE="${DOMAIN}"
 +
</nowiki>}}
  
#!/bin/bash
+
Configure the dhcpd server following the [[dhcpd]] article and add the following to all subnet declarations in the {{ic|/etc/dhcpd.conf}} file that provide DHCP service:
# Begin samba-dnsupdate.sh
 
# Author: DJ Lucas <dj_AT_linuxfromscratch_DOT_org>
 
# kerberos_creds() courtesy of Sergey Urushkin
 
<nowiki># http://www.kuron-germany.de/michael/blog/wp-content/uploads/2012/03/dhcpdns-sergey2.txt</nowiki>
 
 
# DHCP server should be authoritative for its own records, sleep for 5 seconds
 
# to allow unconfigured Windows hosts to create their own DNS records
 
# In order to use this script you should disable dynamic updates by hosts that
 
# will receive addresses from this DHCP server. Instructions are found here:
 
<nowiki># https://wiki.archlinux.org/index.php/Samba_4_Active_Directory_Domain_Controller#DHCP</nowiki>
 
sleep 5
 
 
checkvalues()
 
{
 
        [ -z "${2}" ] && echo "Error: argument '${1}' requires a parameter." && exit 1
 
 
        case ${2} in
 
 
                -*)
 
                        echo "Error: Invalid parameter '${2}' passed to ${1}."
 
                        exit 1
 
                ;;
 
 
                *)
 
                        return 0
 
                ;;
 
        esac
 
}
 
 
showhelp()
 
{
 
echo -e "\n"`basename ${0}` "uses samba-tool to update DNS records in Samba 4's DNS"
 
echo "server when using INTERNAL DNS or BIND9 DLZ plugin."
 
echo ""
 
echo "    Command line options (and variables):"
 
echo ""
 
echo "      -a | --action      Action for this script to perform"
 
echo "                        ACTION={add|delete}"
 
echo "      -c | --krb5cc      Path of the krb5 credential cache (optional)"
 
echo "                        Default: KRB5CC=/run/dhcpd.krb5cc"
 
echo "      -d | --domain      The DNS domain/zone to be updated"
 
echo "                        DOMAIN={domain.tld}"
 
echo "      -h | --help        Show this help message and exit"
 
echo "      -H | --hostname    Hostname of the record to be updated"
 
echo "                        HNAME={hostname}"
 
echo "      -i | --ip          IP address of the host to be updated"
 
echo "                        IP={0.0.0.0}"
 
echo "      -k | --keytab      Krb5 keytab to be used for authorization (optional)"
 
echo "                        Default: KEYTAB=/etc/dhcp/dhcpd.keytab"
 
echo "      -m | --mitkrb5    Use MIT krb5 client utilities"
 
echo "                        MITKRB5={YES|NO}"
 
echo "      -n | --nameserver  DNS server to be updated (must use FQDN, not IP)"
 
echo "                        NAMESERVER={server.internal.domain.tld}"
 
echo "      -p | --principal  Principal used for DNS updates"
 
echo "                        PRINCIPAL={user@domain.tld}"
 
echo "      -r | --realm      Authentication realm"
 
echo "                        REALM={DOMAIN.TLD}"
 
echo "      -z | --zone        Then name of the zone to be updated in AD.
 
echo "                        ZONE={zonename}
 
echo ""
 
echo "Example: $(basename $0) -d domain.tld -i 192.168.0.x -n 192.168.0.x \\"
 
echo "            -r DOMAIN.TLD -p user@domain.tld -H HOSTNAME -m"
 
echo ""
 
}
 
 
# Process arguments
 
[ -z "$1" ] && showhelp && exit 1
 
while [ -n "$1" ]; do
 
        case $1 in
 
 
                -a | --action)
 
                        checkvalues ${1} ${2}
 
                        ACTION=${2}
 
                        shift 2
 
                ;;
 
 
                -c | --krb5cc)
 
                        checkvalues ${1} ${2}
 
                        KRB5CC=${2}
 
                        shift 2
 
                ;;
 
 
                -d | --domain)
 
                        checkvalues ${1} ${2}
 
                        DOMAIN=${2}
 
                        shift 2
 
                ;;
 
 
                -h | --help)
 
                        showhelp
 
                        exit 0
 
                ;;
 
 
                -H | --hostname)
 
                        checkvalues ${1} ${2}
 
                        HNAME=${2%%.*}
 
                        shift 2
 
                ;;
 
 
                -i | --ip)
 
                        checkvalues ${1} ${2}
 
                        IP=${2}
 
                        shift 2
 
                ;;
 
 
                -k | --keytab)
 
                        checkvalues ${1} ${2}
 
                        KEYTAB=${2}
 
                        shift 2
 
                ;;
 
 
                -m | --mitkrb5)
 
                        KRB5MIT=YES
 
                        shift 1
 
                ;;
 
 
                -n | --nameserver)
 
                        checkvalues ${1} ${2}
 
                        NAMESERVER=${2}
 
                        shift 2
 
                ;;
 
 
                -p | --principal)
 
                        checkvalues ${1} ${2}
 
                        PRINCIPAL=${2}
 
                        shift 2
 
                ;;
 
 
                -r | --realm)
 
                        checkvalues ${1} ${2}
 
                        REALM=${2}
 
                        shift 2
 
                ;;
 
 
                -z | --zone)
 
                        checkvalues ${1} ${2}
 
                        ZONE=${2}
 
                        shift 2
 
                ;;
 
 
                *)
 
                        echo "Error!!! Unknown command line opion!"
 
                        echo "Try" `basename $0` "--help."
 
                        exit 1
 
                ;;
 
        esac
 
done
 
 
# Sanity checking
 
[ -z "$ACTION" ] && echo "Error: action not set." && exit 2
 
case "$ACTION" in
 
        add | Add | ADD)
 
                ACTION=ADD
 
        ;;
 
        del | delete | Delete | DEL | DELETE)
 
                ACTION=DEL
 
        ;;
 
        *)
 
                echo "Error: invalid action \"$ACTION\"." && exit 3
 
        ;;
 
esac
 
[ -z "$KRB5CC" ] && KRB5CC=/run/dhcpd.krb5cc
 
[ -z "$DOMAIN" ] && echo "Error: invalid domain." && exit 4
 
[ -z "$HNAME" ] && [ "$ACTION" == "ADD" ] && \
 
      echo "Error: hostname not set." && exit 5
 
[ -z "$IP" ] && echo "Error: IP address not set." && exit 6
 
[ -z "$KEYTAB" ] && KEYTAB=/etc/dhcp/dhcpd.keytab
 
[ -z "$NAMESERVER" ] && echo "Error: nameservers not set." && exit 7
 
[ -z "$PRINCIPAL" ] && echo "Error: principal not set." && exit 8
 
[ -z "$REALM" ] && echo "Error: realm not set." && exit 9
 
[ -z "$ZONE" ] && echo "Error: zone not set." && exit 10
 
 
# Disassemble IP for reverse lookups
 
OCT1=$(echo $IP | cut -d . -f 1)
 
OCT2=$(echo $IP | cut -d . -f 2)
 
OCT3=$(echo $IP | cut -d . -f 3)
 
OCT4=$(echo $IP | cut -d . -f 4)
 
RZONE="$OCT3.$OCT2.$OCT1.in-addr.arpa"
 
 
kerberos_creds() {
 
export KRB5_KTNAME="$KEYTAB"
 
export KRB5CCNAME="$KRB5CC"
 
 
if [ "$KRB5MIT" = "YES" ]; then
 
    KLISTARG="-s"
 
else
 
    KLISTARG="-t"
 
fi
 
 
klist $KLISTARG || kinit -k -t "$KEYTAB" -c "$KRB5CC" "$PRINCIPAL" || { logger -s -p daemon.error -t dhcpd kinit for dynamic DNS failed; exit 11; }
 
}
 
 
 
add_host(){
 
    logger -s -p daemon.info -t dhcpd Adding A record for host $HNAME with IP $IP to zone $ZONE on server $NAMESERVER
 
    samba-tool dns add $NAMESERVER $ZONE $HNAME A $IP -k yes
 
}
 
 
 
delete_host(){
 
    logger -s -p daemon.info -t dhcpd Removing A record for host $HNAME with IP $IP from zone $ZONE on server $NAMESERVER
 
    samba-tool dns delete $NAMESERVER $ZONE $HNAME A $IP -k yes
 
}
 
 
 
update_host(){
 
    logger -s -p daemon.info -t dhcpd Removing A record for host $HNAME with IP $CURIP from zone $ZONE on server $NAMESERVER
 
    samba-tool dns delete $NAMESERVER $ZONE $HNAME A $CURIP -k yes
 
    add_host
 
}
 
 
 
add_ptr(){
 
    logger -s -p daemon.info -t dhcpd Adding PTR record $OCT4 with hostname $HNAME to zone $RZONE on server $NAMESERVER
 
    samba-tool dns add $NAMESERVER $RZONE $OCT4 PTR $HNAME.$DOMAIN -k yes
 
}
 
 
 
delete_ptr(){
 
    logger -s -p daemon.info -t dhcpd Removing PTR record $OCT4 with hostname $HNAME from zone $RZONE on server $NAMESERVER
 
    samba-tool dns delete $NAMESERVER $RZONE $OCT4 PTR $HNAME.$DOMAIN -k yes
 
}
 
 
 
update_ptr(){
 
    logger -s -p daemon.info -t dhcpd Removing PTR record $OCT4 with hostname $CURHNAME from zone $RZONE on server $NAMESERVER
 
    samba-tool dns delete $NAMESERVER $RZONE $OCT4 PTR $CURHNAME -k yes
 
    add_ptr
 
}
 
 
 
case "$ACTION" in
 
    ADD)
 
        kerberos_creds
 
        host -t A $HNAME.$DOMAIN > /dev/null
 
        if [ "${?}" == 0 ]; then
 
          CURIP=$(host -t A $HNAME.$DOMAIN | cut -d " " -f 4 )
 
          if <nowiki>[[</nowiki> "$CURIP" != "$IP" <nowiki>]]</nowiki>; then
 
              update_host
 
          fi
 
        else
 
            add_host
 
        fi
 
       
 
        host -t PTR $IP > /dev/null
 
        if [ "${?}" == 0 ]; then
 
            CURHNAME=$(host -t PTR $IP | cut -d " " -f 5 | rev | cut -c 2- | rev)
 
            if <nowiki>[[</nowiki> "$CURHNAME" != "$HNAME.$DOMAIN" <nowiki>]]</nowiki>; then
 
              update_ptr
 
            fi
 
        else
 
            add_ptr
 
        fi
 
    ;;
 
 
    DEL)
 
        kerberos_creds
 
        host -t A $HNAME.$DOMAIN > /dev/null
 
        if [ "${?}" == 0 ]; then
 
            delete_host
 
        fi
 
 
        host -t PTR $IP > /dev/null
 
        if [ "${?}" == 0 ]; then
 
            delete_ptr
 
        fi
 
    ;;
 
 
    *)
 
        echo "Error: Invalid action '$ACTION'!" && exit 12
 
    ;;
 
 
esac
 
 
# End samba-dnsupdate.sh
 
  
 +
{{bc|<nowiki>
 +
  on commit {
 +
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 +
    set ClientName = pick-first-value(option host-name, host-decl-name);
 +
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "add", ClientIP, ClientName);
 +
  }
  
The dhcpd service will need to use a fast exiting wrapper script to avoid locking issues and delays. Create the {{ic|/etc/dhcpd/update.sh}} script with the following commands (substituting correct values for '''server''', '''internal'''.'''domain'''.'''tld''', and '''INTERNAL'''.'''DOMAIN'''.'''TLD'''):
+
  on release {
 +
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 +
    set ClientName = pick-first-value(option host-name, host-decl-name);
 +
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
 +
  }
  
#!/bin/bash
+
    on expiry {
# Begin /etc/dhcpd/update.sh
+
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
+
    set ClientName = pick-first-value(option host-name, host-decl-name);
# Variables
+
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
KRB5CC="/run/dhcpd4.krb5cc"
+
</nowiki>}}
KEYTAB="/etc/dhcpd/dhcpd.keytab"
 
DOMAIN="'''internal'''.'''domain'''.'''tld'''"
 
REALM="'''INTERNAL'''.'''DOMAIN'''.'''TLD'''"
 
PRINCIPAL="dhcp@${REALM}"
 
NAMESERVER="'''server'''.${DOMAIN}"
 
ZONE="${DOMAIN}"
 
 
ACTION=$1
 
IP=$2
 
HNAME=$3
 
 
export KRB5CC KEYTAB DOMAIN REALM PRINCIPAL NAMESERVER ZONE ACTION IP HNAME
 
 
/usr/local/sbin/samba-dnsupdate.sh -m &
 
 
# End /etc/dhcpd/update.sh
 
  
Configure the dhcpd server following the [[dhcpd]] article and add the following to all subnet declarations in the {{ic|/etc/dhcpd.conf}} file that provide DHCP service:
+
Here is a complete example {{ic|/etc/dhcpd.conf}} file for reference:
  
  on commit {
+
{{hc|/etc/dhcpd.conf|<nowiki>
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "add", ClientIP, ClientName);
 
  }
 
 
  on release {
 
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "delete", ClientIP, ClientName);
 
  }
 
 
    on expiry {
 
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "delete", ClientIP, ClientName);
 
  
Here is a complete example {{ic|/etc/dhcpd.conf}} file for reference:
+
subnet </nowiki>'''192.168.1.0''' netmask '''255.255.255.0'''<nowiki> {
 +
  range </nowiki>'''192.168.1.100''' '''192.168.1.199'''<nowiki>;
 +
  option subnet-mask </nowiki>'''255.255.255.0'''<nowiki>;
 +
  option routers </nowiki>'''192.168.1.254'''<nowiki>;
 +
  option domain-name "</nowiki>'''internal.domain.tld'''<nowiki>";
 +
  option domain-name-servers </nowiki>'''192.168.1.1'''<nowiki>;
 +
  option broadcast-address </nowiki>'''192.168.1.255'''<nowiki>;
 +
  default-lease-time 28800;
 +
  max-lease-time 43200;
 +
  authoritative;
  
# Begin /etc/dhcpd.conf
+
  on commit {
+
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
# No DHCP service in the DMZ.
+
    set ClientName = pick-first-value(option host-name, host-decl-name);
subnet 192.168.2.0 netmask 255.255.255.0 {
+
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "add", ClientIP, ClientName);
}
+
  }
 
# Internal subnet
 
subnet 192.168.1.0 netmask 255.255.255.0 {
 
  range 192.168.1.100 192.168.1.199;
 
  option subnet-mask 255.255.255.0;
 
  option routers 192.168.1.254;
 
  option domain-name "internal.domain.tld";
 
  option domain-name-servers 192.168.1.1;
 
  option broadcast-address 192.168.1.255;
 
  default-lease-time 28800;
 
  max-lease-time 43200;
 
  authoritative;
 
 
  on commit {
 
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "add", ClientIP, ClientName);
 
  }
 
 
  on release {
 
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "delete", ClientIP, ClientName);
 
  }
 
 
    on expiry {
 
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 
    set ClientName = pick-first-value(option host-name, host-decl-name);
 
    execute("/etc/dhcpd/update.sh", "delete", ClientIP, ClientName);
 
  }
 
}
 
 
# End /etc/dhcpd.conf
 
  
Set permissions:
+
  on release {
 +
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 +
    set ClientName = pick-first-value(option host-name, host-decl-name);
 +
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
 +
  }
  
# chmod 750 /usr/local/sbin/samba-dnsupdate.sh
+
    on expiry {
# chmod 750 /etc/dhcpd/update.sh
+
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
 +
    set ClientName = pick-first-value(option host-name, host-decl-name);
 +
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
 +
  }
 +
}
 +
</nowiki>}}
  
 
Finally, enable and start (or restart) the {{ic|dhcpd4}} service.
 
Finally, enable and start (or restart) the {{ic|dhcpd4}} service.
  
==What to do next==
+
=== Transferring users from one directory to another ===
 +
 
 +
Unfortunately, there is no built-in utility to export users from one directory to another. This is one way, albeit exceptionally ugly, to get the user specific fields out of your existing SAM and into a suitable LDIF format for ldbmodify:
 +
 
 +
ldbsearch -H /var/lib/samba/private/sam.ldb \
 +
    -s sub -b cn=Users,dc='''internal''',dc='''domain''',dc='''tld''' '(objectClass=user)' | \
 +
    grep -e "^\# record" -e "^accountExpires:" -e "^c:" -e "^cn:" -e "^co:" -e "^codePage:" \
 +
          -e "^comment:" -e "^company:" -e "^countryCode:" -e "^department:" \
 +
          -e "^description:" -e "^displayName" -e "^displayNamePrintable:" \
 +
          -e "^distinguishedName" -e "^division:" -e "^dn:" -e "^employeeID:" \
 +
          -e "^facsimileTelephoneNumber:" -e "^generationQualifier:" \
 +
          -e "^givenName" -e "^homeDirectory:" -e "^homeDrive:" -e "^homePhone:" \
 +
          -e "^homePostalAddress:" -e "^info:" -e "^initials:" \
 +
          -e "^internationalISDNNumber:" -e "^ipPhone:" -e "^l:" -e "^mail:" \
 +
          -e "^manager:" -e "^middleName:" -e "^mobile:" -e "^name:" -e "^o:" \
 +
          -e "^objectClass" -e "^otherFacsimileTelephoneNumber:" \
 +
          -e "^otherHomePhone:" -e "^otherIpPhone:" -e "^otherMailbox:" \
 +
          -e "^otherMobile:" -e "^otherPager:" -e "^otherTelephone:" -e "^pager:" \
 +
          -e "^personalTitle:" -e "^physicalDeliveryOfficeName:" -e "^postalAddress:" \
 +
          -e "^postalCode:" -e "^postOfficeBox:" -e "^proxyAddresses\: SMTP" \
 +
          -e "^proxyAddresses: smtp" -e "^referredDeliveryMethod:" \
 +
          -e "^primaryInternationalISDNNumber:" -e "^primaryTelexNumber:" \
 +
          -e "^profilePath:" -e "^registeredAddress:" -e "^sAMAccountName:" \
 +
          -e "^scriptPath:" -e "^sn:" -e "^st:" -e "^street:" -e "^streetAddress:" \
 +
          -e "^telephoneNumber:" -e "^teletexTerminalIdentifier:" \
 +
          -e "^telexNumber:" -e "^title:" -e "^userAccountControl:" -e "^userPrincipalName:"\
 +
          -e "^url:" -e "^userSharedFolder:" -e "^userSharedFolderOther:" -e "^wWWHomePage:" | \
 +
    sed '/^dn:.*/ a\changetype: add' | sed '/^# record/ i\\n' > user-export.ldif
 +
 
 +
Explanation: Run an ldbsearch in the users container only, using sub-tree search for objectclass=user. If you need the whole directory, you can modify the search base to use the root or some other OU. The output from ldbsearch is then piped into a really long grep command that returns only appropriate attributes to keep in the new directory. This is obviously subjective, and probably should be tailored to your specific use case. Finally, we use sed to insert the changetype line (needed to tell ldbmodify that we are adding a user), and prefix with a blank line (to make it easier to read) for each exported object.
 +
 
 +
{{Note|You will need to modify the output file and remove any objects that you don't want transferred. The output file will contain objects (service users, built-ins, etc.) that can break your new directory if you fail to remove them! It will also contain the old domain in both the "dn" and "distinguishedName" attributies that must be changed before import.}}
 +
 
 +
To import, after editing the file and transferring to the new server, simply run the following command on your new samba domain controller:
 +
 
 +
ldbmodify -H /var/lib/samba/private/sam.ldb user-export.ldif
  
If you have made it this far without any unexpected output from the tests above, you are good to go. Congrats! Here are some related topics to extend your new AD server:
+
=== Password Complexity  ===
  
[[Active Directory Integration]] - This article explains how to attach Linux clients to an Active Directory domain.
+
By default, Samba requires strong passwords. To disable the complexity check, issue the following command:
  
[[OpenChange server]] - The OpenChange project provides a Microsoft Exchange compatible mail server using only open source software.
+
{{bc|# samba-tool domain passwordsettings set --complexity&#61;off}}

Latest revision as of 20:25, 12 July 2018

This article explains how to setup an Active Directory domain controller using Samba. It is assumed that all configuration files are in their unmodified, post-installation state. This article was written and tested on a fresh installation, with no modifications other than setting up a static IPv4 network connection, and adding openssh and vim (which should have no effect on the Samba configuration). Finally, most of the commands below will require elevated privileges. Despite conventional wisdom, it may be easier to run these short few commands from a root session as opposed to obtaining rights on an as needed basis.

Installation

Note: Make sure you can access the machines in your network via their hostname. See Network configuration#Local network hostname resolution for more information.

A fully functional samba domain controller requires several programs beyond those included with the Samba distribution. Install the bind-tools, krb5, ntp, openresolv and samba packages.

Samba contains its own fully functional DNS server, but if you need to maintain DNS zones for external domains, you are strongly encouraged to use BIND instead. If you need to share printers, you will also need CUPS. If needed, install the bind and/or cups packages.

Creating a new directory

Provisioning

The first step to creating an Active Directory domain is provisioning. This involves setting up the internal LDAP, Kerberos, and DNS servers and performing all of the basic configuration needed for the directory. If you have set up a directory server before, you are undoubtedly aware of the potential for errors in making these individual components work together as a single unit. The difficulty in doing so is the very reason that the Samba developers chose to provide internal versions of these programs. The server packages above were installed only for the client utilities. Provisioning is quite a bit easier with Samba. Just issue the following command:

# samba-tool domain provision --use-rfc2307 --interactive

Argument explanations

--use-rfc2307
this argument adds POSIX attributes (UID/GID) to the AD Schema. This will be necessary if you intend to authenticate Linux, BSD, or macOS clients (including the local machine) in addition to Microsoft Windows.
--interactive
this parameter forces the provision script to run interactively. Alternately, you can review the help for the provision step by running samba-tool domain provision --help.

Interactive provision explanations

Realm
INTERNAL.DOMAIN.COM - This should be the same as the DNS domain in all caps. It is common to use an internal-only sub-domain to separate your internal domain from your external DNS domains, but it is not required.
Domain
INTERNAL - This will be the NetBIOS domain name, usually the leftmost DNS sub-domain but can be anything you like. For example, the name INTERNAL would not be very descriptive. Perhaps company name or initials would be appropriate. This should be entered in all caps, and should have a 15 character maximum length for compatibility with older clients.
Server Role
dc - This article assumes that your are installing the first DC in a new domain. If you select anything different, the rest of this article will likely be useless to you.
DNS Backend
BIND9_DLZ or SAMBA_INTERNAL - This is down to personal preference of the server admin. Again, if you are hosting DNS for external domains, you are strongly encouraged to use the BIND9_DLZ backend so that flat zone files can continue to be used and existing transfer rules can co-exist with the internal DNS server. If unsure, use the SAMBA_INTERNAL backend.
Administrator password
xxxxxxxx - You must select a strong password for the administrator account. The minimum requirements are one upper case letter, one number, and at least eight characters. If you attempt to use a password that does not meet the complexity requirements, provisioning will fail.

Configuring daemons

NTPD

Create a suitable NTP configuration for your network time server. See Network Time Protocol daemon for explanations of, and additional configuration options.

Modify the /etc/ntp.conf file with the following contents:

/etc/ntp.conf
# Please consider joining the pool:
#
#     http://www.pool.ntp.org/join.html
#
# For additional information see:
# - https://wiki.archlinux.org/index.php/Network_Time_Protocol_daemon
# - http://support.ntp.org/bin/view/Support/GettingStarted
# - the ntp.conf man page

# Associate to Arch's NTP pool
server 0.arch.pool.ntp.org
server 1.arch.pool.ntp.org
server 2.arch.pool.ntp.org
server 3.arch.pool.ntp.org

# Restrictions
restrict default kod limited nomodify notrap nopeer mssntp
restrict 127.0.0.1
restrict ::1
restrict 0.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
restrict 1.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
restrict 2.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery
restrict 3.arch.pool.ntp.org mask 255.255.255.255 nomodify notrap nopeer noquery

# Location of drift file
driftfile /var/lib/ntp/ntpd.drift

# Location of the update directory
ntpsigndsocket /var/lib/samba/ntp_signd/

Create the state directory and set permissions:

# install -d /var/lib/samba/ntp_signd
# chown root:ntp /var/lib/samba/ntp_signd
# chmod 0750 /var/lib/samba/ntp_signd

Enable and start the ntpd.service unit.

BIND

If you elected to use the BIND9_DLZ DNS backend, Install the bind package and create the following BIND configuration. See BIND for explanations of, and additional configuration options. Be sure to replace the x characters with suitable values:

Create the /etc/named.conf file:

/etc/named.conf
options {
    directory "/var/named";
    pid-file "/run/named/named.pid";

    // Uncomment these to enable IPv6 connections support
    // IPv4 will still work:
    //  listen-on-v6 { any; };
    // Add this for no IPv4:
    //  listen-on { none; };

    auth-nxdomain yes;
    datasize default;
    empty-zones-enable no;
    tkey-gssapi-keytab "/var/lib/samba/private/dns.keytab";
    forwarders { xxx.xxx.xxx.xxx; xxx.xxx.xxx.xxx; };

    //  Add any subnets or hosts you want to allow to use this DNS server (use "; " delimiter)
    allow-query     { xxx.xxx.xxx.xxx/xx; 127.0.0.0/8; };

    //  Add any subnets or hosts you want to allow to use recursive queries
    allow-recursion { xxx.xxx.xxx.xxx/xx; 127.0.0.0/8; };

    //  Add any subnets or hosts you want to allow dynamic updates from
    allow-update    { xxx.xxx.xxx.xxx/xx; 127.0.0.0/8; };

    allow-transfer { none; };
    version none;
    hostname none;
    server-id none;
};

zone "localhost" IN {
    type master;
    file "localhost.zone";
};

zone "0.0.127.in-addr.arpa" IN {
    type master;
    file "127.0.0.zone";
};

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" {
    type master;
    file "localhost.ip6.zone";
};

zone "255.in-addr.arpa" IN {
    type master;
    file "empty.zone";
};

zone "0.in-addr.arpa" IN {
    type master;
    file "empty0.zone";
};

zone "." IN {
    type hint;
    file "root.hint";
};

//Load AD integrated zones
dlz "AD DNS Zones" {
    database "dlopen /usr/lib/samba/bind9/dlz_bind9_10.so";
};

//zone "example.org" IN {
//    type slave;
//    file "example.zone";
//    masters {
//        192.168.1.100;
//    };
//    allow-query { any; };
//    allow-transfer { any; };
//};
//
logging {
    channel xfer-log {
        file "/var/log/named.log";
            print-category yes;
            print-severity yes;
            severity info;
        };
        category xfer-in { xfer-log; };
        category xfer-out { xfer-log; };
        category notify { xfer-log; };
};

Set permissions:

# chgrp named /var/lib/samba/private/dns.keytab
# chmod g+r /var/lib/samba/private/dns.keytab
# touch /var/log/named.log
# chown root:named /var/log/named.log
# chmod 664 /var/log/named.log

Fix for recent versions of bind:

# copy /var/named/empty.zone /var/named/empty0.zone
# chown root:named /var/named/empty0.zone

Enable and start the named.service unit.

Good values for forwarders are your ISP's DNS servers. Google (8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, and 2001:4860:4860::8844) and OpenDNS (208.67.222.222, 208.67.220.220, 2620:0:ccc::2 and 2620:0:ccd::2) provide suitable public DNS servers free of charge. Appropriate values for subnets are specific to your network.

Kerberos client utilities

The provisioning step above created a perfectly valid krb5.conf file for use with a Samba domain controller. Install it with the following commands:

# mv /etc/krb5.conf{,.default}
# cp /var/lib/samba/private/krb5.conf /etc

DNS

You will need to begin using the local DNS server now. Reconfigure resolvconf to use only localhost for DNS lookups. Create the /etc/resolv.conf.tail (do not forget to substitute internal.domain.tld with your internal domain):

# Samba configuration
search internal.domain.tld
# If using IPv6, uncomment the following line
#nameserver ::1
nameserver 127.0.0.1

Set permissions and regenerate the new /etc/resolv.conf file:

# chmod 644 /etc/resolv.conf.tail
# resolvconf -u

Samba

Enable and start the samba.service unit. If you intend to use the LDB utilities, you will also need create the /etc/profile.d/sambaldb.sh file to set LDB_MODULES_PATH:

export LDB_MODULES_PATH="${LDB_MODULES_PATH}:/usr/lib/samba/ldb"

Set permissions on the file and source it:

# chmod 0755 /etc/profile.d/sambaldb.sh
# . /etc/profile.d/sambaldb.sh

Testing the installation

DNS

First, verify that DNS is working as expected. Execute the following commands substituting appropriate values for internal.domain.com and server:

# host -t SRV _ldap._tcp.internal.domain.com.
# host -t SRV _kerberos._udp.internal.domain.com.
# host -t A server.internal.domain.com.

You should receive output similar to the following:

_ldap._tcp.internal.domain.com has SRV record 0 100 389 server.internal.domain.com.
_kerberos._udp.internal.domain.com has SRV record 0 100 88 server.internal.domain.com.
server.internal.domain.com has address xxx.xxx.xxx.xxx

NT authentication

Next, verify that password authentication is working as expected:

# smbclient //localhost/netlogon -U Administrator -c 'ls'

You will be prompted for a password (the one you selected earlier), and will get a directory listing like the following:

Domain=[INTERNAL] OS=[Unix] Server=[Samba 4.1.2]
  .                                   D        0  Wed Nov 27 23:59:07 2013
  ..                                  D        0  Wed Nov 27 23:59:12 2013

		50332 blocks of size 2097152. 47185 blocks available

Kerberos

Now verify that the KDC is working as expected. Be sure to replace INTERNAL.DOMAIN.COM and use upper case letters:

# kinit administrator@INTERNAL.DOMAIN.COM

You should be prompted for a password and get output similar to the following:

Warning: Your password will expire in 41 days on Wed 08 Jan 2014 11:59:11 PM CST

Verify that you actually got a ticket:

# klist

You should get output similar to below:

Ticket cache: FILE:/tmp/krb5cc_0
Default principal: administrator@INTERNAL.DOMAIN.COM

Valid starting       Expires              Service principal
11/28/2013 00:22:17  11/28/2013 10:22:17  krbtgt/INTERNAL.DOMAIN.COM@INTERNAL.DOMAIN.COM
	renew until 11/29/2013 00:22:14

As a final test, use smbclient with your recently acquired ticket. Replace server with the correct server name:

# smbclient //server/netlogon -k -c 'ls'

The output should be the same as when testing password authentication above.

Additional configuration

DNS

You will also need to create a reverse lookup zone for each subnet in your environment in DNS. It is important that this is kept in Samba's DNS as opposed to BIND to allow for dynamic updates by cleints. For each subnet, create a reverse lookup zone with the following commands. Replace server.internal.domain.tld and xxx.xxx.xxx with appropriate values. For xxx.xxx.xxx, use the first three octets of the subnet in reverse order (for example: 192.168.0.0/24 becomes 0.168.192):

# samba-tool dns zonecreate server.internal.domain.tld xxx.xxx.xxx.in-addr.arpa -U Administrator

Now, add a record for you server (if your server is multi-homed, add for each subnet) again substituting appropriate values as above. zzz will be replaced by the fourth octet of the IP for the server:

# samba-tool dns add server.internal.domain.tld xxx.xxx.xxx.in-addr.arpa zzz PTR server.internal.domain.tld -U Administrator

Restart the samba service. If using BIND for DNS, restart the named service as well.

Finally, test the lookup. Replace xxx.xxx.xxx.xxx with the IP of your server:

# host -t PTR xxx.xxx.xxx.xxx

You should get output similar to the following:

xxx.xxx.xxx.xxx.in-addr.arpa domain name pointer server.internal.domain.tld.

TLS

TLS support is not enabled by default, however, a default certificate was created when the DC was brought up. With the release of Samba 4.3.8 and 4.2.2, unsecured LDAP binds are disabled by default, and you must configure TLS to use Samba as an authentication source (without reducing the security of your Samba installation). To use the default keys, append the following lines to the "[global]" section of the /etc/samba/smb.conf file:

        tls enabled  = yes
        tls keyfile  = tls/key.pem
        tls certfile = tls/cert.pem
        tls cafile   = tls/ca.pem

If a trusted certificate is needed, create a signing key and a certificate request (see OpenSSL for detailed instructions). Get the request signed by your chosen certificate authority, and put into this directory. If your certificate authority also needs an intermediate certificate, concatenate the certs (server cert first, then intermediate) and leave tls cafile blank.

Restart samba for the changes to take effect.

Adding a second domain controller to an existing domain

TBA...

Tips and tricks

DHCP with dynamic DNS updates

It should be noted that using this method will affect functionality of windows clients, as they will still attempt to update DNS on their own. When this occurs, the machine will be denied permission to do so as the record will be owned by the dhcp user rather than the machine account. While this is essentially harmless, it will generate warnings in the system log of the offending machine. You should create a GPO to overcome this, but unfortunately, Samba does not yet have a command line utility to modify GPOs. You will need a Windows PC with the RSAT tools installed. Simply create a dedicated GPO with the Group Policy Editor, and apply only to OUs that contain workstations (so that servers can still update using 'ipconfig /registerdns') and configure the following settings:

Computer Configuration
  Policies
    Administrative Templates
      Network
        DNS Client
          Dynamic Update = Disabled
          Register PTR Records = Disabled

Install the dhcp package and the samba-dhcpd-updateAUR package.

Create an unprivileged user in AD for performing the updates. When prompted for password, use a secure password. 63 random, mixed case, alpha-numeric characters is sufficient. Optionally samba-tool also takes a random argument:

# samba-tool user create dhcp --description="Unprivileged user for DNS updates via DHCP server"

Since this is a service account, disabling password expiration on the user account is recommended, but not required:

# samba-tool user setexpiry dhcp --noexpiry

Give the user privileges to administer DNS:

# samba-tool group addmembers DnsAdmins dhcp

Export the users credentials to a private keytab:

# samba-tool domain exportkeytab --principal=dhcp@INTERNAL.DOMAIN.TLD dhcpd.keytab
# install -vdm 755 /etc/dhcpd
# mv dhcpd.keytab /etc/dhcpd
# chown root:root /etc/dhcpd/dhcpd.keytab
# chmod 400 /etc/dhcpd/dhcpd.keytab

Modify the dhcpd-update-samba-dns.conf file with the following commands (substituting correct values for server, internal.domain.tld, and INTERNAL.DOMAIN.TLD):

/etc/dhcpd/dhcpd-update-samba-dns.conf
# Variables
KRB5CC="/run/dhcpd4.krb5cc"
KEYTAB="/etc/dhcpd/dhcpd.keytab"
DOMAIN="internal.domain.tld"
REALM="INTERNAL.DOMAIN.TLD"
PRINCIPAL="dhcp@${REALM}"
NAMESERVER="server.${DOMAIN}"
ZONE="${DOMAIN}"

Configure the dhcpd server following the dhcpd article and add the following to all subnet declarations in the /etc/dhcpd.conf file that provide DHCP service:

  on commit {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "add", ClientIP, ClientName);
  }

  on release {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
  }

    on expiry {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);

Here is a complete example /etc/dhcpd.conf file for reference:

/etc/dhcpd.conf

subnet 192.168.1.0 netmask 255.255.255.0 {
  range 192.168.1.100 192.168.1.199;
  option subnet-mask 255.255.255.0;
  option routers 192.168.1.254;
  option domain-name "internal.domain.tld";
  option domain-name-servers 192.168.1.1;
  option broadcast-address 192.168.1.255;
  default-lease-time 28800;
  max-lease-time 43200;
  authoritative;

  on commit {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "add", ClientIP, ClientName);
  }

  on release {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
  }

    on expiry {
    set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
    set ClientName = pick-first-value(option host-name, host-decl-name);
    execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
  }
}

Finally, enable and start (or restart) the dhcpd4 service.

Transferring users from one directory to another

Unfortunately, there is no built-in utility to export users from one directory to another. This is one way, albeit exceptionally ugly, to get the user specific fields out of your existing SAM and into a suitable LDIF format for ldbmodify:

ldbsearch -H /var/lib/samba/private/sam.ldb \
    -s sub -b cn=Users,dc=internal,dc=domain,dc=tld '(objectClass=user)' | \
    grep -e "^\# record" -e "^accountExpires:" -e "^c:" -e "^cn:" -e "^co:" -e "^codePage:" \
         -e "^comment:" -e "^company:" -e "^countryCode:" -e "^department:" \
         -e "^description:" -e "^displayName" -e "^displayNamePrintable:" \
         -e "^distinguishedName" -e "^division:" -e "^dn:" -e "^employeeID:" \
         -e "^facsimileTelephoneNumber:" -e "^generationQualifier:" \
         -e "^givenName" -e "^homeDirectory:" -e "^homeDrive:" -e "^homePhone:" \
         -e "^homePostalAddress:" -e "^info:" -e "^initials:" \
         -e "^internationalISDNNumber:" -e "^ipPhone:" -e "^l:" -e "^mail:" \
         -e "^manager:" -e "^middleName:" -e "^mobile:" -e "^name:" -e "^o:" \
         -e "^objectClass" -e "^otherFacsimileTelephoneNumber:" \
         -e "^otherHomePhone:" -e "^otherIpPhone:" -e "^otherMailbox:" \
         -e "^otherMobile:" -e "^otherPager:" -e "^otherTelephone:" -e "^pager:" \
         -e "^personalTitle:" -e "^physicalDeliveryOfficeName:" -e "^postalAddress:" \
         -e "^postalCode:" -e "^postOfficeBox:" -e "^proxyAddresses\: SMTP" \
         -e "^proxyAddresses: smtp" -e "^referredDeliveryMethod:" \
         -e "^primaryInternationalISDNNumber:" -e "^primaryTelexNumber:" \
         -e "^profilePath:" -e "^registeredAddress:" -e "^sAMAccountName:" \
         -e "^scriptPath:" -e "^sn:" -e "^st:" -e "^street:" -e "^streetAddress:" \
         -e "^telephoneNumber:" -e "^teletexTerminalIdentifier:" \
         -e "^telexNumber:" -e "^title:" -e "^userAccountControl:" -e "^userPrincipalName:"\
         -e "^url:" -e "^userSharedFolder:" -e "^userSharedFolderOther:" -e "^wWWHomePage:" | \
    sed '/^dn:.*/ a\changetype: add' | sed '/^# record/ i\\n' > user-export.ldif

Explanation: Run an ldbsearch in the users container only, using sub-tree search for objectclass=user. If you need the whole directory, you can modify the search base to use the root or some other OU. The output from ldbsearch is then piped into a really long grep command that returns only appropriate attributes to keep in the new directory. This is obviously subjective, and probably should be tailored to your specific use case. Finally, we use sed to insert the changetype line (needed to tell ldbmodify that we are adding a user), and prefix with a blank line (to make it easier to read) for each exported object.

Note: You will need to modify the output file and remove any objects that you don't want transferred. The output file will contain objects (service users, built-ins, etc.) that can break your new directory if you fail to remove them! It will also contain the old domain in both the "dn" and "distinguishedName" attributies that must be changed before import.

To import, after editing the file and transferring to the new server, simply run the following command on your new samba domain controller:

ldbmodify -H /var/lib/samba/private/sam.ldb user-export.ldif

Password Complexity

By default, Samba requires strong passwords. To disable the complexity check, issue the following command:

# samba-tool domain passwordsettings set --complexity=off