An Unofficial HOWTO build a FreeBSD 5.x Fileserver using Samba/Active Directory Services
by Michael Brown

mikal at mikro-net dot com
http://oslabs.mikro-net.com/
version 0.93 - 02/14/2004
this is a work in progress
Updates by Graham Dunn - March 30, 2005

First of all:
Links:



Introduction:

This document is meant as a guide to build a fileserver that runs on FreeBSD 5.3-RELEASE which operates seamlessly in a Microsoft Active Directory Environment, whether it be Windows 2000 or 2003. Windows domain members (clients) can browse shares on this server as if it were a windows server. Permissions can be granted on a domain user/group basis through Samba's winbind mapping AD sccounts to FreeBSD 5.3's built in POSIX ACLs (using UFS2). All of this is possible from Samba's abilty to use Kerberos/SASL and LDAP to authenticate as if it were a native Windows machine. We will let the OS take care of the depencies for the samba3 package. Other services beside SMB/CIFS can be extended via PAM (ssh,ftp,printing,etc) through single-sign on through AD, but that would be beyond the scope of this document (although not at all difficult- see http://www.bzerk.nl/documents/ntdomauth/ for an ftp example using pam_winbind). For more in-depth research into Samba and its functionality, please see http://us1.samba.org/samba/docs, an Official Samba Documentation link page. Much of the information in this document is in fact indebted to the links on this page.
For information on mapping principals from alternative kerberos realms to AD principals (i.e. with MIT or Heimdal KDC's) see http://www.microsoft.com/windows2000/techinfo/planning/security/kerbsteps.asp.

Caveat:

This document assumes an intermediate level of familiarity with basic networking principles, FreeBSD and unix-like systems in general. It also assumes you have a functional Windows 2000 or 2003 Active Directory Domain Controller in your network and you have an account with the administrative right to add machine accounts to the domain. You will need this account information to authenticate to Active Directory. We will not be using Samba's name-services daemon (nmbd) in this scenario, as we are striving to push all naming contexts through DNS.

I have added some comments to the config files, please read them. These comments are to explain some of the why/how of features within that particular file. I hope it may help in some way. You will replace the following information in the config files (as described in the howto) with that which is applicable to your realm/domain:

fbsdad is our FreeBSD box's hostname
example.com is your AD domain FQDN/kerberos realm, which would make our box fbsdad.example.com
dc.example.com is the FQDN of your AD Domain Controller
192.168.129.50(/24) is the IP address of dc.example.com
admin is your account login
cn=admin,cn=users,dc=example,dc=com is the ldap dn for your admin AD account
pa55w0rd is the AD password for the admin account
*EOF* indicates the end of that particular config file

This was done with FreeBSD 5.3-RELEASE and works against Win2k 'Native Mode'/2k3 'Windows Server 2003 Functional Level'.
This is also assuming standard FreeBSD 5.3 install, with samba as a package.

IFS2 ACLS

FreeBSD-POSIX ACLs now exist (since FreeBSD 5.1-RELEASE) for UFS2 enabling fine grained permission sets. To activate the ACLs you must edit /etc/fstab to mount the filesystems correctly. You must add the option 'acls' to the filesystems you wish to activate. Example:
cat /etc/fstab
# Device Mountpoint FStype   Options Dump Pass#
/dev/ad0s1b   none   swap   sw        0   0
/dev/ad0s1a   /      ufs    rw,acls   1   1
/dev/ad0s1h   /exp   ufs    rw,acls   2   2
/dev/ad0s1g   /home  ufs    rw,acls   2   2
/dev/ad0s1f   /tmp   ufs    rw,acls   2   2
/dev/ad0s1d   /usr   ufs    rw,acls   2   2
/dev/ad0s1e   /var   ufs    rw,acls   2   2
/dev/acd0     /cdrom cd9660 ro,noauto 0   0
*EOF*

Active Directory's (IMHO) most secure form eschews NetBIOS and places all name service requests within DNS. To begin, edit your /etc/resolv.conf file so that you use your AD domain controller as a nameserver, preferably the primary nameserver; also add the domain name as at least one of the search domains:
cat /etc/resolv.conf
search example.com
domain example.com
#add other search domains here
#This is the AD dc
nameserver 192.0.34.43
#Add any other dns servers here

We're going to be using the ports system to get all of the required install packages.

Kerberos

FreeBSD comes with Heimdal 0.6.1 (kerberos) installed under /usr, which we will be using here.

Create /etc/krb5.conf:
cat /etc/krb5.conf
#/etc/krb5.conf
#where you want your logs
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log

#Your AD domain FQDN (must be uppercase)
[libdefaults]
default_realm = EXAMPLE.COM

# AD domain, DC FQDNs
[realms]
EXAMPLE.COM = {
kdc
default_domain = example.com
admin_server = dc.example.com
}

#Translating all possibles to EXAMPLE.COM
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
.EXAMPLE.COM = EXAMPLE.COM

#This is used if you have alternative KDC's in you realm (not windows)
#that you are mapping trust accounts to in the windows domain
#see http://www.microsoft.com/windows2000/techinfo/planning/security/kerbsteps.asp
#[kdc]
#profile = /home/krb5kdc/kdc.conf

#self-explanatory
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
*EOF*



Since we are using Kerberos auth, at this point you must insure that your box's system clock is within 600 seconds (5 minutes) of your domain controller's clock.

So we need a ntp daemon to synchronize our system clock against the DC's time service. Please make sure your windomain ntp services checks against a valid time server! We will obtain this from ports:
cd /usr/ports/net/ntp
make install clean

Create necessary config files (/etc/ntp.conf, /etc/ntp.drift):
cat /etc/ntp.conf
# /etc/ntp.conf
# This is your AD DC - we will synchronize against it's time service
server dc.example.com prefer
driftfile /etc/ntp.drift
*EOF*
touch /etc/ntp.drift
Launch the daemon:
/usr/local/bin/ntpd -c /etc/ntp.conf
You can automate this to run at system start, of course.
The ntp package includes a client tool, ntpdc. We will use this to check our connection; type 'ntpdc' and at the prompt type 'peers' (Type 'help' at the prompt to see available commands - man ntpdc for more info):
ntpdc
ntpdc>peers
     remote      local    st poll reach   delay   offset    disp
=======================================================================
*dc.example.com 192.168.12.18  3 1024    37 0.00049 -0.021527 0.46245
ntpdc>
You should see something similar to the above.
A quick and dirty alternative workaround is to get the DC's clock time manually and set the box to it:
Stop the ntpd deamon (if running), and type ntpdate dc.example.com
Test Krb5 install against active directory KDC:
/usr/local/bin/kinit Administrator
password for Administrator@EXAMPLE.COM:
p455w0rd
 *Enter your domain admin password*

List current kerberos tickets with '/usr/local/bin/klist' command:
/usr/local/bin/klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@EXAMPLE.COM

Valid starting Expires Service principal
02/06/04 21:54:40 02/07/04 07:54:40 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 02/07/04 21:54:40

This means you have a valid ticket granting ticket (tgt) from MS AD! Half of the hard part is over. :)

nss_ldap

Install nss_ldap from ports
cd /usr/ports/net/nss_ldap
make install
Symlink the library to needed locations:
ln -s /usr/local/lib/nss_ldap.so.1 /usr/lib/
ln -s /usr/local/lib/nss_ldap.so.1 /usr/lib/nss_ldap.so.2

Enterprise Root CA

This example assumes you have the Enterprise Root CA certificate from MS Certificate Services (this needs to be installed somewhere in the domain so DC's can be connected to via LDAP over SSL). For a guide on how to obtain this certificate click *here*.

create ldap.conf:

Configure OpenLDAP

cat /usr/local/etc/openldap/ldap.conf
# Active Directory server. Define multiple servers by delimiting
# them with spaces.
host dc.example.com

# Search base
base dc=example,dc=com

# LDAP version 3
ldap_version 3

#URI for AD server
#Switch these if not using LDAP/SSL or do not have the MS Cert Svcs installed
#in the domain
#URI ldap://dc.example.com
URI ldaps://dc.example.com

# Bind DN (this might not be needed at all for anon LDAP connections(win2k)).
# This should be the DN of the AD account you have
# that can create machine accounts
binddn cn=ldapadmin,cn=users,dc=example,dc=com
bindpw p455w0rd
# Use port 636 for SSL
#port 636 (not really needed when ssl=on it is port 636 by default)

# Search scope
scope sub

# User ID attr for AD
pam_login_attribute sAMAccountName

#MD5 passwd hash
pam_password md5
# Break of the connection after one hour idle time
idle_timelimit 3600
# This is mapping made possible by nss_ldap
# Bases for the searches. These should be the OU's
# you create the user accounts in.
# Here we reference the standard default AD user container
# Please change to the container your users reside in
nss_base_passwd cn=Users,dc=example,dc=com?one
nss_base_group cn=Users,dc=example,dc=com?one

# The msSFU mappings reference Microsoft's Services for Unix
# Which you may uncomment if you have this installed on your DC
# *Schema mappings for Active Directory*
nss_map_objectclass posixAccount User
nss_map_objectclass shadowAccount User
nss_map_attribute uid sAMAccountName
#nss_map_attribute userPassword msSFUPassword
#nss_map_attribute homeDirectory msSFUHomeDirectory
nss_map_attribute uniqueMember member
nss_map_attribute cn sAMAccountName
#nss_map_attribute homeDirectory msSFUHomeDirectory
nss_map_objectclass posixGroup Group
pam_login_attribute sAMAccountName
pam_filter objectclass=User
pam_password ad

# SSL is enabled - Comment this line if no MS Enterprise Root CA Cert
ssl on

# OpenLDAP SSL options
# Require and verify server certificate (yes/no)
# Default is "no" Uncomment this is you have a client cert (you won't MS LDAP
# over SSL does not auth client cert, just a valid AD password)
#tls_checkpeer yes
# CA certificates for server certificate verification
# At least one of these are required if tls_checkpeer is "yes"
# This again refers to the MS Root CA Cert - comment it if none
TLS_CACERT /etc/ca/ldapca.pem

# SSL cipher suite
# See man ciphers for syntax
# comment this if no cert
tls_ciphers TLSv1

# Disable SASL security layers. This is needed for AD.
sasl_secprops maxssf=0

# Override the default Kerberos ticket cache location.
krb5_ccname FILE:/tmp/krb5cc_0
*EOF*

Test out your openldap installation with ldapsearch:
/usr/bin/ldapsearch -Y GSSAPI
SASL/GSSAPI authentication started
SASL username: admin@EXAMPLE.COM
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <> with scope sub
# filter: (objectclass=*)
# requesting: ALL
#

etc,etc.....
It should print out lines upon lines of AD info for you, as you are
authenticating to the AD tree through SASL from the former ticket you were
granted from the dc. Now check your ticket list:
/usr/local/bin/klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@EXAMPLE.COM

Valid starting Expires Service principal
02/06/04 21:54:40 02/07/04 07:54:40 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 02/07/04 21:54:40
02/06/04 21:57:28 02/07/04 07:54:40 ldap/dc.example.com@EXAMPLE.COM
renew until 02/07/04 21:54:40

Good. You will see these tickets if an ldapsearch command was issued without
the '-x' param.

Installing Samba

We are almost ready to install samba, we just need to prepare the environment.

Edit /etc/pam.d/login
cat /etc/pam.d/login
#
# $FreeBSD: src/etc/pam.d/login,v 1.16 2003/06/14 12:35:05 des Exp $
#
# PAM configuration for the "login" service
#

# auth
auth required pam_nologin.so no_warn
auth sufficient pam_self.so no_warn
auth include system
auth sufficient /usr/lib/pam_winbind.so
# account
account requisite pam_securetty.so
account include system
account sufficient /usr/lib/pam_winbind.so
# session
session include system

# password
password include system
*EOF*

Create /etc/nsswitch.conf
cat /etc/nsswitch.conf
passwd: files winbind
group:  files winbind
*EOF*

Install samba from package pkg_add -r samba3

Create smb.conf - this is a hardened example that assumes you have the Root CA certificate from MS Cert Services (this needs to be installed somewhere in the domain so DC's can be connected to via LDAP over SSL).

cat /usr/samba/lib/smb.conf

# Global parameters
[global]
        workgroup = WORKGROUP
        realm = EXAMPLE.COM
        server string = Samba File Server %v
        security = ADS
        client schannel = Yes
        server schannel = Yes
        passdb backend = ldapsam:ldap://dc.example.com
        socket options = TCP_NODELAY
        dns proxy = No
        ldap admin dn = cn=Administrator,cn=users,DC=example,DC=com
        ldap suffix = DC=example,DC=com
        idmap backend = idmap_rid:WORKGROUP=10000-20000
        allow trusted domains = no
        idmap uid = 10000-20000
        idmap gid = 10000-20000
        winbind separator = .
        winbind enum users = No
        winbind enum groups = No
        winbind use default domain = Yes
        force create mode = 0664
        force directory mode = 0775
        dos filemode = Yes

*EOF*

Create secrets.tdb for ldap connect to AD (specify admin password)
/usr/local/bin/smbpasswd -w p455w0rd

You should still have a valid ticket from the domain controller, so join the server to the domain:
/usr/local/bin/net ads join
Using short domain name -- EXAMPLE
Joined 'FBSDAD' to realm 'EXAMPLE.COM'

This shows a successful join.
Test it:
/usr/local/bin/net ads testjoin
Join is OK.
Check your ticket list; it should look similar to this:
/usr/local/bin/klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@EXAMPLE.COM

Valid starting Expires Service principal
02/07/04 21:33:03 02/08/04 07:33:01 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 02/08/04 21:33:03
02/07/04 21:33:02 02/08/04 07:33:01 ldap/dc.example.com@EXAMPLE.COM
renew until 02/08/04 21:54:40
02/07/04 21:33:09 02/08/04 07:33:01 dc$@EXAMPLE.COM
renew until 02/08/04 21:33:03
02/07/04 21:33:09 02/08/04 07:35:09 kadmin/changepw@EXAMPLE.COM
renew until 02/08/04 21:35:09

This reflects all the AD kerberos tickets that have beem gained thus far.
Start the server /usr/local/etc/rc.d/samba start
Now check to see if winbind is grabbing the Windows domain accounts:
/usr/local/bin/wbinfo -u
administrator
admin
mary
etc.....
/usr/local/bin/wbinfo -g
Domain Users
Domain Admins
Enterprise Admins
etc......
Check /var/log/samba.log (or wherever you are logging samba) for errors.

The finish line is within reach, but first we must explore FreeBSD's ACL interface.
There are two main commands for our needs: setfacl and getfacl. For greater detail man getfacl or man setfacl. Now that we have the Samba daemons running, we can connect to the DC and extract account information that will be added to this box's current databases.

Use the 'pw' command, which will, if winbind is working properly, populate the db. We're using idmap_rid, which just uses the windows SID to set the uid and gid. This keeps your userid consistent across machines.

pw usershow 1001
EXAMPLE\administrator:*:1001:1001::0:0:administrator:/home/EXAMPLE/administrator:/usr/local/bin/bash
pw usershow 1002
EXAMPLE\admin :*:1002:1001::0:0:admin:/home/EXAMPLE/admin:/usr/local/bin/bash
pw groupshow EXAMPLE\\Domain\ Admins
EXAMPLE\Domain Admins:*:1002:EXAMPLE\administrator,EXAMPLE\admin,EXAMPLE\mary

etc....
Our shared directory /home/share, needs to be accessible by your domain account:
setfacl -m u:1002:rwx /home/share
Check acls on that directory:
getfacl /home/share
#file:/home/share
#owner:0
#group:0
user::rwx
user:EXAMPLE\admin:rwx
group::r-x
mask::rwx
other::r-x

Ok.... So far so good. Let's connect with Samba's smbclient (again, using our kerberos ticket, thus the '-k' option) to a share on the AD domain controller, let's assume the share UNC path is '\\dc.example.com\usershare':
/usr/samba/bin/smbclient -k //dc.example.com/usershare
OS=[Windows Server 2003 3790] Server=[Windows Server 2003 5.2]
smb: \>

Let's connect to ourselves (our Samba share), but while authenticating to the DC (via our kerberos tgt):
smbclient -k //fbsdad/share
OS=[Unix] Server=[Samba 3.0.x]
smb: \>

Now for the final test - in your network, there is certainly a winstation!(2000/XP)
Navigate to it and login as your admin account.
Open an explorer window and connect to your freebsd box using the UNC name: \\fbsdad
Right click on the share folder and select 'properties'.
Select the 'security' tab.
*click on images to enlarge*

Is EXAMPLE\admin listed? GOOD! Your AD acls are being properly mapped to your local POSIX acls. Note that you cannot change ACLs via windows unless you are the file's owner or root.

Troubleshooting

Check the time on your workstations if they're having problems connecting to the share. They need to be within 5 minutes of the server, or their Kerberos ticket will be rejected.
Copyright (c) 2004 Michael Brown