Copyright © 2003 Buchan Milne

Originally written for the MandrakeSecure website.

In what is now becoming a series on LDAP, previous articles have already covered basic LDAP setup and UNIX authentication, and the basics of building a samba PDC backended on OpenLDAP. However, many of the advantages of using LDAP as a backend for storing Samba accounts can only be realised by replicating the LDAP database to slave servers, which was not covered in either article.

The advantages that are available in running slave LDAP servers include:

  • Redundancy
  • Reduced network traffic
  • Better performance of LDAP clients (samba, nss_ldap, pam_ldap, MTAs)
  • Disconnected authentication

One can see that all of these benefits would be advantageous to both UNIX authentication, and authentication of Windows clients via Samba. In fact, the use of LDAP as authentication backend is the only way to implement Backup Domain Controllers with Samba (besides home-cooked rsync scripts).

In addition, having Samba on an LDAP backend allows non-root users (who have Domain Admin rights) to join machines to the Domain (this is not possible when using the smbpasswd file).

In this article, we will look at the various aspects of setting up your domain, with the objectives of enabling disconnected Unix authentication and PDC/BDC functionality with Samba, using the following values in the examples in this document:

Setting Value
Base DN: dc=mylan,dc=net
Mail Domain: mylan.net
Root DN: cn=root,dc=mylan,dc=net
Samba DN(s): cn=samba,dc=mylan,dc=net
Mail Host: mail.mylan.net
LDAP Master server: ldap.mylan.net
LDAP Slave servers: ldap1.mylan.net; ldap2.mylan.net
Netbios Domain Name: mylan

Initial LDAP Setup

While the original LDAP article covers the initial setup of the LDAP server and clients in detail, there are some issues which have caused frustration, and they will be mentioned here in the hope of allowing some of you to go home on time for a change!

Avoiding editing the migration scripts

When using the migration tools, the first article suggested editing the scripts to customise the settings. However, since those files will likely be lost in an upgrade (they are not marked as config files to rpm), and since scripts should not rely on editing of the files, I prefer to use the mechanism provided in the migration tools, the use of shell variables.

Following the example configuration, we would set these variables instead of editing the migrate_common.ph as in the migration section of the first article:

[root@ldap ~]# export LDAP_BASEDN="dc=mylan,dc=net"
[root@ldap ~]# export LDAP_DEFAULT_MAIL_DOMAIN="mylan.net"
[root@ldap ~]# export LDAP_DEFAULT_MAIL_HOST="mail.mylan.net"
[root@ldap ~]# export LDAP_EXTENDED_SCHEMA=1

For actually adding the entries to the LDAP server, I would follow a similar approach to save typing:

[root@ldap ~]# LDAP_ROOTDN="cn=root,dc=mylan,dc=net"
[root@ldap ~]# read -s -p "Enter LDAP Root DN Password: " LDAP_BINDPW
[root@ldap ~]# <span class="input LDAP_ADD="ldapadd -x -H ldap://localhost -D $LDAP_ROOTDN -w $L

Note that the LDAP password is not exported, since it is only needed in the current shell. It is now much simpler to import data into the LDAP server. From the /usr/share/openldap/migration directory, to import the base entries, run:

[root@ldap ~]# ./migrate_base.pl | $LDAP_ADD

Importing the base entries has been the cause of much frustration for people who use a longer suffix than the examples of mylan.net, padl.com and example.com that are available all over. This frustration is avoided simply by use the “-c” option with ldapadd, as we have in the LDAP_ADD variable. If you have received errors such as “parent does not exist” or “No such object”, this is for you!

Initial Samba setup for LDAP

The second LDAP article covers the setup of a single samba server on an LDAP backend well, but one of the steps (mentioned in both articles) is providing samba with it’s LDAP password.

One of my pet hates is seeing clear-text passwords, and unfortunately providing samba with it’s LDAP password is one case where this is usually necessary. If you thought storing the LDAP password in a shell variable (as above) was insecure, you will see that this is the reason for it. I prefer a password in a shell variable than on my screen and in my history, since I can unset the variable when I am done. By using the “-s” switch to read, we avoid seeing the password when we enter it, thus we don’t see it at all. Now, passing the LDAP password of your choice is as easy as:

[root@ldap ~]# read -s -p "Enter LDAP Root DN Password: " LDAP_BINDPW
Enter LDAP Root DN Password:
[root@ldap ~]# smbpasswd -w $LDAP_BINDPW

If you are using your rootdn account for samba, the first step may be unnecessary if you entered it above. If you are done with your password for the moment, remove it from your shell with ‘unset LDAP_BINDPW’.

Changes required on the Master LDAP Server

To make provision for slave LDAP servers, we need to make some changes to the slapd.conf file on the master LDAP server, and possibly add some entries to the LDAP directory, which will be used for the replication. Note that all the changes we are adding here are database-specific options (as opposed to global options), so they must be added after the database directive for the database you are replicating.

LDAP replication works by notifying each slave LDAP server of changes that have been made on the master server. For you to have a consistent directory across your servers, this requires that the copies of the directory are consistent to begin with (which we will do later), and then updates to each server need to be tracked to ensure that a given server has received all it’s updates. To accomplish this, OpenLDAP uses a replication log file, which logs all the changes that must be made across all servers. Each replication host will also have a log file, indicating which updates still need to be applied. These changes are managed by a separate daemon, slurpd, which spawns a separate instance per replication host.

The first change we need to make on the server is thus to tell OpenLDAP which file to use as a log file. Add a “replogfile” directive to slapd.conf:

replogfile      /var/lib/ldap/replog

Note that slapd needs to be able to create (or write to, if it already exists) the file, so it is best to leave it in a place that the user slapd runs as has write access. Also, since the replog is associated with a database, placing it in the directory specified in the “directory” directive for the database is convenient.

Now, for each LDAP slave, we need to add a replica section, which will specify the host to replicate to, the LDAP DN to connect to the replica as, the bind method (and password in the case of clear-text) and ssl settings. Assuming we were wanting to replicate the LDAP directory to hosts ldap1.mylan.net, ldap2.myland.net, we would add something like this to slapd.conf on the master:

replica host=ldap1.mylan.net:389
        binddn=ldap.mylan.net,ou=Hosts,dc=mylan,dc=net
        bindmethod=simple credentials='4l70szch'
        tls=yes

replica host=ldap2.mylan.net:389
        binddn=ldap.mylan.net,ou=Hosts,dc=mylan,dc=net
        bindmethod=simple credentials='4l70szch'
        tls=yes

It is essential that the password is secured in some fashion, either via SASL (which is beyond the scope of this article, and I’m waiting for an article that does cover it!), or if you are using simple bind, via either ssl or tls. Please note that the use of SSL or TLS requires that you specify the host as the name that appears on the SSL certificate the host is using. The simplest way to ensure this is to use the FQDN on the certificate and in the host entry for the replica, and ensure that you have working DNS, specifically resolution of the FQDN to the IP address of the host.

I would suggest using a password generator to generate passwords, the one above was generated for use in this document using passwd-gen (available in contrib).

Now, we also need to ensure that this DN exists in the directory, and that it has the password to authenticate against. If you already have an LDAP entity that can be used for this (in this case an entry from the hosts file for the server itself that was imported with migrate_hosts.pl), you could do something like this:

[root@ldap ~]# slappasswd -s 4l70szch
{SSHA}ZVlKuLSLDJ/2AVbedB3qQ+S6c6K+Fgum
[root@ldap ~]# LDAP_MODIFY="ldapmodify -x -H ldap://localhost -D $LDAP_ROOTDN
[root@ldap ~]# $LDAP_MODIFY
dn: cn=ldap.mylan.net,ou=Hosts,dc=mylan,dc=net
changetype: modify
add: objectclass
objectclass: simpleSecurityObject
-
add: userPassword
userPassword: {SSHA}ZVlKuLSLDJ/2AVbedB3qQ+S6c6K+Fgum
^D
modifying entry "ldap.mylan.net,ou=Hosts,dc=mylan,dc=net"
^C
[root@ldap ~]#

Note, the ^D indicates the use of the key combination CTRL-D to signify the end of input, after which the modification will be applied. The ^C ends the ldapmodify session.

We will need to restart the ldap server, which will then start up a slurpd to replicate to ldap1.mylan.net, but first we need to configure ldap1.mylan.net.

Setting up the Slave LDAP Servers

You should repeat this section for each of your LDAP slaves, in this case we will use ldap1.mylan.net.

Before we start, you need to ensure you have the necessary software installed on each machine which is to become a slave LDAP server. You will need at least the ‘openldap-servers’ package, but openldap-clients, openldap, nss_ldap and pam_ldap may be useful, depending on your objectives. To install all the LDAP software we will be using, run the following command:

[root@ldap ~]# urpmi openldap openldap-clients openldap-servers nss_ldap pam_ldap

Apparently on Debian systems the equivalent command would be something like ‘apt-get install slapd ldap-utils nss_ldap pam_ldap’

In setting up each slave LDAP server, we need to complete a number of tasks. First, we should copy all the configurations from the master server (as for example, we don’t want ACLs weaker on the slave). We then need to make a few changes to make slapd run as a slave (instead of allowing updates as usual, it will only accept changes from the master, and refer all requests for modifications to the master). We can then start up the LDAP server, and import the entire directory.

Copying configuration files

First, you need to get copies of all the config files to the slave server. The most convenient way is probably via scp. If you have not used scp before, see [/syshardening/openssh.php Using OpenSSH]. Assuming we have a secure, convenient means of using ssh (such as via ssh-agent/keychain and keys with passphrases), you can copy the configuration files across to the first LDAP slave as follows:

[root@ldap ~]# scp ldap:/etc/openldap/slapd.conf /etc/openldap/

Be sure to copy any other config files you have modified, or added to the master server. Examples include /etc/openldap/slapd.access.conf, /etc/samba/samba-slapd.include, /usr/share/openldap/schema/samba.schema:

[root@ldap1 ~]# scp ldap:/etc/openldap/slapd.access.conf /etc/openldap/
[root@ldap1 ~]# scp ldap:/etc/samba/samba-slapd.include /etc/samba/
[root@ldap1 ~]# scp ldap:/usr/share/openldap/schema/samba.schema \
/usr/share/openldap/schema/

The file /etc/samba-slapd.include has not been discussed before. It just contains directives to index the rid (which samba uses when doing lookups on users, so indexing it should improve samba’s LDAP queries), and an ACL to protect the samba passwords in the lmPassword and ntPassword attributes. You may want to instead make these changes in the slapd.conf file itself, or you could use an include directive in slapd.conf, between the existing ACLs and index directives, such as include /etc/samba/samba-slapd.include

Modifications to slapd.conf

Before we continue, just undo the changes we made above on the master to add the replica hosts in the slapd.conf on the slave.

We need to tell slapd a few things now, first, which DN to accept updates from, with:

updatedn "ldap.mylan.net,ou=Hosts,dc=mylan,dc=net"

We also need to tell slapd that it is to refer any changes not from the replica DN to the master server, by adding:

updateref "ldap://ldap.mylan.net"

Finally, we also need to add ACLs on the slave to allow the DN used for replica update write access, so in each set of ACLs covering entries which need to be replicated, add write access for the replication DN, such as:

access to attr=userPassword
        by self read
        by anonymous auth
        by dn="cn=ldap.mylan.net,ou=Hosts,dc=mylan,dc=net" write
        by * none

Remember also to check any ACLs defined in files included in your slapd.conf, such as /etc/openldap/slapd.access.conf and /etc/samba/samba-slapd.include.

Transferring the directory to the slave

We need to initialise the LDAP directory on the slave server. To my knowledge, the best way to do this is to run an ldap dump (slapcat) on the slave, and pipe the LDIF data into slapadd, which must be done while the slave server is not running. To ensure consistency, we must prevent any changes from occuring on the master server. The OpenLDAP documentation recommends stopping the master LDAP server, however small installations which rely on the master LDAP server will want to rather put the master server into read-only mode (also mentioned in the OpenLDAP documentation).

On the master server, set it to read-only mode (by placing “readonly on” in the section of the slapd.conf file for the database you want to have in read-only mode), and restart. If you have just one database on the master server, you can do this as follows:

[root@ldap ~]# echo "readonly on" >> /etc/openldap/slapd.conf
[root@ldap ~]# service ldap restart
Stopping slapd:                                                 [  OK  ]
Stopping slurpd:                                                [FAILED]
ldaps
Starting slapd (ldap + ldaps):                                  [  OK  ]

Starting slurpd:                                                [  OK  ]
[root@ldap ~]#

As you will see, we now have slurpd starting up as well (as a result of our changes above). Now, we can run the LDAP query on the slave server, or run slapcat, and pipe the output directly into the database. An LDAP query may be easier, but will possibly not return all entries in the directory (specifically if you have more entries than your LDAP server is configured to return on a query, or if your query does not take LDAP server settings into account, or if the DN you use does not have access to all data. Ensure that the ldap server is not running on the slave server, as we are going to use slapadd (instead of ldapadd), since we have only one account that will be able to do modifications to the directory, but it is not in the local copy of the directory yet. It would also be possible to uncomment the settings for the slave, and use ldapadd as the rootdn, but that could mean that the master LDAP server would have to run in read-only mode for longer. To accomplish this easily, we want to be able to run some commands as the user who the ldap server runs as, which means we don’t have to worry about permissions afterwards on new files. This requires that the user has a valid shell, which is most likely not the case by default. On Mandrake, simply run ‘usermod -s /bin/bash ldap‘ as root first. Then run something like this on the slave:

[root@ldap1 ~]# ssh ldap1.mylan.net slapcat | su ldap -c 'slapadd -c; slapindex'

This runs slapcat on the master (ldap.mylan.net), and brings back the output to stdout on the slave (ldap1.mylan.net), which we then pipe into ‘slapadd -c’, and slapindex, both run as the user ‘ldap’.

If you do not have ssh setup (either via ssh keys or using password authentication) to allow connections as root, and you have fewer entries that your LDAP search limit, you can run an LDAP query on the slave:

[root@ldap1 ~]# ldapsearch -x -LLL -h ldap.mylan.net -D "cn=root,dc=mylan,dc=net" -W \
 | su ldap -c 'slapadd -c;slapindex'
Enter LDAP Password:
[root@ldap1 ~]#

Last resort is to run slapcat -l <file> on the master LDAP server, transfer the file to the slave server, and run su ldap -c ‘slapadd -c -l <file>;slapindex’.

We are now ready to fire up the slapd on the slave:

[root@ldap1 ~]# service ldap start
Stopping slapd:                                                 [  OK  ]
ldaps
Starting slapd (ldap + ldaps):                                  [  OK  ]

Now, you can restart the master LDAP server in read-write mode. Comment out the “readonly on” you added above and restart the master server:

[root@ldap ~]# perl -pi -e 's/^readonly on/#readonly on/g' /etc/openldap/slap
[root@ldap ~]# service ldap restart
ldaps
Starting slapd (ldap + ldaps):                                  [  OK  ]
Starting slurpd:                                                [  OK  ]

While it is not critical at this stage, in future you will want to minimise the amount of time that your master is in read-only mode, since this will prevent users from changing their passwords, other admins from making their changes etc. As your enterprise grows and you rely more on your LDAP service, this will become more important. So, get into the habit of being quick with a new slave LDAP server. You should not need to have the master server in readonly mode for more than a minute when adding a slave, if you follow the method above.

Remember to set the ldap user’s shell (on the slave) back in the interest of security! ‘usermod -s /bin/false ldap’ should do.

Testing replication

The whole point of this exercise was to have working replication, so it is worthwhile ensuring that it works correctly. I find the easiest way is to modify the gecos of my own user account on the master, and query it on the slave. I guess it would also be feasible to use a separate LDAP entity for this, but would be more effort. Since we already have the smbldap tools available and configured on the master server (see article 2), it is convenient to use them to modify values, since we don’t have to bother with passwords. In this example, I will use the account “joe” from the first article:

[root@ldap ~]# smbldap-usermod -c "Joe User - ldap replication test 1" joe
[root@ldap ~]# ldapsearch -x -h ldap1 "(uid=joe)" gecos -LLL
dn: uid=joe,ou=People,dc=mylan,dc=net
gecos: Joe User - ldap replication test 1

[root@ldap ~]#

You should also test a few more attributes to ensure that ACLs on the slave work, so test an attribute for each ACL you have.

If you don’t get your modification back, you have a problem with your replication, which you need to fix before we progress further. On the master server, you should find a file such as /var/lib/ldap/replica/ldap1.mylan.net:389.rej and /var/lib/ldap/replica/slurpd.replog which should contain some debugging information which should be able to help you find out what is wrong. You may want to test various pieces of the replication setup, such as binding to the slave as the updatedn, or running slurpd in one-shot mode (‘slurpd -o -d31 -r /var/lib/ldap/replica/slurpd.replog‘ should work to test slurpd). Unfortunately not all the errors from slurpd in one-shot mode are self-explanatory.

If replication is working, remember to set Joe’s gecos back, or he might complain when he gets to his Linux workstation and the screen saver dialog doesn’t have his name correct anymore!

Disconnected Authentication

To complete our first objective, disconnected authentication, we finally need to do the client-side setup on the LDAP slave. The most important thing here is the configuration of the host in /etc/ldap.conf, as this hostname must be resolvable to the local machine at all times. The next decision is whether to use SSL/TLS here or not. Since all communication will be local, SSL/TLS should not be necessary for encryption support between the client and the server. This frees us from the need to specify an FQDN, and we can use the loopback IP address, 127.0.0.1.

We mentioned redundancy, and to achieve that goal, you can configure multiple LDAP servers in the host line of /etc/ldap.conf. If the first server listed (which should be the localhost on a slave server) is not available, pam_ldap and nss_ldap should failover to the next server in the list.

Now, you should be able to disconnect your LDAP slave from the network, and still be able to authenticate. Note however that you may have problems if your network interface stays up, as slapd or pam_ldap or nss_ldap may try and use it, and not return. So, you may have to manually take the interface down, with something like ‘ifdown eth0’. If your NIC is supported by ifstatus (check with ‘ifstatus -v’ while both connected and disconnected), then ifplugd will do this for you on Mandrake 9.1, and you won’t have to think about it. However, this issue seems to have been resolved with the latest pam_ldap packages which are available as updates for Mandrake 9.1.

If you only wanted disconnected authentication (for example for use on laptops which run Linux), you can skip the Samba bits and go right to the end.

If you cannot authenticate while disconnected, you have a problem you must solve before continuing.

Configuring the Samba “BDC

Before continuing with this section, ensure you have installed the software required, you should use the latest samba packages available from the samba ftp mirrors, compiled with ldap support. ‘urpmi samba-server-ldap’ should be sufficient to install the necessary software if you have set up your urpmi sources at http://plf.zarb.org/~nanardon/ . (I am not aware of Debian sources for samba packages compiled with LDAP support, so I am not aware of an apt-get equivalent.)

Preparing the LDAP directory for Samba

As before, we need to configure a few aspects of how Samba will connect to the LDAP server. The first issue to be decided is which DN samba will use when connecting to the LDAP server. To decide this, it is worthwhile reviewing what changes a Samba BDC will be making to the directory. At minimum Samba will need to be able to modify the attributes that it uses for authentication, namely lmPassword, ntPassword and pwdLastSet when users change their passwords from the BDC.

Unfortunately, Samba (at least 2.2.x) makes changes to all the attributes it uses when modifying one, so Samba-2.2.x will additionally need write access all those defined in the objectclass:SambaAccount.

If you want to be able to create user accounts from the remote server, Samba (or rather the DN used in the ‘add user script’, thus the DN configured in the smbldap_conf.pm on the BDC) will also need to have write access to the OU used for storing user accounts, and must have write access to all attributes. Similarly, if you want to be able to join machines to the domain from the BDC without pre-making machine accounts, you will need to give Samba (via the DN in smbldap_conf.pm) write access to the OU you use for machine accounts.

Since Samba thus has many rights on the directory, some people will be satisfied in giving samba the rootdn account. However, note that Samba will then store the LDAP rootdn password in a plaintext-readable format on the machine (both in the secrets.tdb file for internal Samba use, and if you use smbldap-tools, in the smbldap_conf.pm file). Also, using a separate DN will give more traceability to modifications to the directory. Any modifications will mark the entries modified with the DN that made the most recent changes, and using one DN for multiple modifiers defeats the point of maintaining this data.

In this example, we will add a new LDAP entry, “cn=samba,dc=mylan,dc=net” to the root of our directory, for use by samba. First ensure that your new samba DN is added to the existing ACLs for ntPassword and lmPassword, then add something like the following to the ACL section of your slapd.conf file:

access to attr=uid,rid,cn,logonTime,logoffTime,kickoffTime,pwdCanchange,pwdMustchange,\
acctFlags,displayName,smbHome,scriptPath,profilePath,description,userWorkstations,\
primaryGroupID,domain
        by dn="uid=root,ou=People,dc=mylan,dc=net" write
        by dn="cn=samba,dc=mylan,dc=net" write
        by * read

access to dn="ou=People,dc=mylan,dc=net"
        by dn="uid=root,ou=People,dc=mylan,dc=net" write
        by dn="cn=samba,dc=mylan,dc=net" write
        by * read

access to dn="ou=Group,dc=mylan,dc=net"
        by dn="uid=root,ou=People,dc=mylan,dc=net" write
        by dn="cn=samba,dc=mylan,dc=net" write
        by * read



[root@ldap ~]# slappasswd -s 8gi42uie
{SSHA}Yc0VQhwX8IQGyKDnWLUrP+OTnRYAjhl/

[root@ldap ~]# $LDAP_ADD
dn: cn=samba,dc=mylan,dc=netobjectclass: top
objectclass: simpleSecurityObject
userPassword: {SSHA}Yc0VQhwX8IQGyKDnWLUrP+OTnRYAjhl/
adding new entry "cn=samba,dc=mylan,dc=net"

You must now replace your previous settings in /etc/samba/smb.conf and /etc/samba/smbldap_conf.pm, and tell Samba the password for the new DN:

[root@ldap ~]# smbpasswd -w 8gi42uie

Whether you want each samba server using the LDAP server to use its own DN is a choice for you to make. Doing so will allow better auditing (from the ldap data you would be able to know which server had made the most recent change, which would narrow down the search for the admin who made a mistake), but will be more effort. If you choose to do so, just repeat the steps above, adding the new DN to the existing samba ACLs on the directory.

After making your changes, test your ACLs, ensuring that now samba has the ability to make changes to those attributes. For example, you can create a new user using smbldap-useradd and then test that you can disable the user via smbpasswd. This is also a convenient time to ensure that your LDAP data is replicating to the slave. You will probably have to change some of the ACLs on the slave to allow samba to read the attributes it needs.

Configuration file changes for the Samba BDC

The majority of the configuration from your PDC will apply to your BDC, so copy your smb.conf from the PDC to the BDC, and the smbldap_conf.pm also. The changes you should make to the smb.conf on the BDC include:

  • netbios name (if you set it manually on the PDC) - smb.conf
  • If your PDC runs as a WINS server, make your BDC a WINS client of the PDC instead, since Samba does not support WINS replication yet - smb.conf
  • If you are using different DNs, change them - smb.conf
  • Don’t set the BDC as domain master, but ensure it is set up for domain logons - smb.conf
  • Affinity of clients for a certain logon server can be adjusted with os level - smb.conf
  • In the smbldap_conf.pm, where you previously set $slaveLDAP and $masterLDAP, you should obviously ensure they point to the relevant LDAP servers.

The final change to the smb.conf file relates to the creation of machine accounts. When you join a machine to the domain, samba will do a check for a machine account on the LDAP server, and if no account exists, it will run the “add user script”, and query its LDAP server again for an account. You may find that Samba does not wait long enough between adding the account (to the master) and checking for the account on the slave to allow replication to occur. If this is the case, you can just force samba to wait after running the script by making the full “add user script” on the slave look something like this (which will make it wait for 5 seconds):

add user script = /usr/share/samba/scripts/smbldap-useradd.pl -w -d /dev/null \
 -g machines -c 'Machine Account' -s /bin/false %u; sleep 5

Remember to import Samba’s LDAP DN password on the slave via smbpasswd -w <password>.

The last bit that is important is importing the domain SID, which the PDC has, on the BDC. On the BDC, run something like this:

[root@ldap ~]# smbpasswd -S -r ldap.mylan.net

Start your samba server up on the slave, and you should now be able to join a Windows machine to the domain, via either machine. If you imported a uid=root account, that had an smbpasswd, you should be able to use that account. Additionally, any user that is a member of the adm group on one of the machines should have rights to join the machine to the domain. This is controlled by the permissions on the smbldap-tools scripts and configuration file. Additionally, members of the adm group should have Domain Admin rights on the windows machines, controlled by the “domain admin group” parameter in the smb.conf file. Furthermore, members of the adm group should be able to administer printers on any Mandrake samba servers, due to the “printer admin group” default parameter, and the permissions on the files in the print$ share.

For more detail on joining Windows clients to a Samba Domain Controller, including screenshots, please see the relevant section of the Mandrake Community Wiki. Note of course that although the screenshots show the use of the root account, any Domain Admin account should be able to join machines to the domain.

You should be able to log in to the windows client with a domain account (after the reboot) to either server. Test this by stopping samba on one machine at a time (if the server you are stopping is your WINS server, you must not shut nmbd down but rather just the smbd’s, which you can do (assuming no users have files open) with ‘killall smbd’ as root).

Complications for Windows-specific features

Note that there are additional complications for LDAP domain controllers that you will encounter on your first login, relating to profiles and login scripts. When using LDAP accounts, Samba will first check to see if the LDAP account for the user has profilePath and scriptPath LDAP attributes, in which case those paths will be used for locating the user’s profile and login script. If the attributes do not exist for the LDAP account, Samba will fall back to the settings in smb.conf. While settings in smb.conf are not as flexible, the use of samba macros in the ‘logon path’ and ‘login script’ entries allows easy customisation. Additionally, if you are using multiple domain controllers to cut down on bandwidth, having the profilePath contain the server name defeats this purpose. Unfortunately, the smbldap-tools will always set the LDAP attributes, so if you don’t use them, you must currently delete them manually, in which case it is also a good time to add any additional attributes for the user.

Also, the user logging must either have rights to create a profile directory, or their profile directory must exist and be accessible by them. An example of one way to achieve this is given in the example config file, using a ‘root preexec’ on the profiles share to create and assign permissions on the profile directory.

The final issue is with retaining existing profiles. For Windows NT-based (ie Windows NT, Windows 2000, Windows XP Professional) version, the registry settings in a user’s profile are protected by ACLs, so when copying profiles (such as a local profile to the server), you must ensure that you assign the new (domain) user account rights to use the profile. If you are migrating a large network from an existing Windows domain, it is not easy to do this, and you may want to use Samba3 instead, which is able to retain the SIDs for each user, making this unnecessary.

You may notice that you now end up with multiple of your profile. Ideally you will want to ensure that profiles are replicated somehow, but that is beyond the scope of this article. It seems the windows machines will always attempt to log on to the server they most recently logged into. If this machine is not available, they will query for a logon server.

Password Changing, Expiry and Synchronisation

Depending on your future plans for your network, you may want to accomplish different objectives for password synchronisation, expiry etc. The most basic password-changing aspect is an administrative user changing passwords for users, which can be done conveniently on any machine setup for smbldap-tools by using smbldap-passwd. However, in most cases you will want the users to be able to change their passwords easily on their own, and in all likelihood you will want to enforce password changes at regular intervals. The issues we will look at in accomplishing this include:

  • Windows users changing their Windows password from their Windows client (probably the most important in the short-term)
  • Windows users changing their Unix password from their Windows client (important if you authenticate other services on Unix via the Unix password

in LDAP, such as IMAP/SSH servers etc)

  • Unix users changing their Unix password from their Unix machine (if you have Unix/Linux desktops, you will want this at least)
  • Unix users changing their Windows password from their Unix machine (the most difficult part)

Changing Samba passwords from Windows machines

Password changing for windows machines should now work as follows:

  • User runs password-changing tool (ie CTRL-ALT-DEL->Change Password)
  • If samba is configured for unix password synchronisation, either via a password script or via pam, Samba will first try to change the Unix password.
  • If the Unix password change succeeded (if configured) or if samba is not configured for Unix password synchronisation, Samba will try to change the ntPassword and lmPassword attributes in its LDAP server.
  • If Samba is a “PDC”, its changes should be successful. If samba is a “BDC”, its first attempt should fail, returning a referral to the master LDAP server. Samba should then rebind to the master LDAP server, and attempt to change lmPassword and ntPassword.
  • If this is all successful, Windows should tell you your password change was successful.

Windows users changing Unix passwords

To keep passwords in synchronisation, it is possible to have samba change the users Unix password whenever they change their Windows/Samba password. To do this, you need to enable the unix password sync option, and either use passwd program = /usr/bin/passwd %u or pam password change = yes, both of which require a suitable passwd chat.

The advantage of using pam is that you can customise the way Samba passwords are changed, however by default they will work just like the passwd program (since the /etc/pam.d/samba file by default should use pam_stack and pass password changes on to the configuration in /etc/pam.d/system-auth).

Note that the password change operation will take place as root, so any Samba server that does Unix password synchronisation for LDAP accounts must be configured to bind as a DN that has write access to the password attributes in LDAP, normally by configuring a rootbinddn in /etc/ldap.conf and entering the password for that DN in plain text in /etc/ldap.secret. Finally, note that failure of a Unix password change operation will cause the samba password change to fail, so ensure your Unix password change for other users works as root before testing from Windows clients.

Full configuration for Unix password synchronisation via Samba could look like this:

unix password sync = yes
pam password change = yes
passwd chat = *New*UNIX*password* %n\n *Re*ype*new*UNIX*password* %n\n \
*passwd:*all*authentication*tokens*updated*successfully*

Unix users changing Unix passwords

If your pam_ldap is set up correctly according to the original article, then password changes should work from your Unix clients, however note that some packages of openldap have a bug in this regard. If you have updated to the latest openldap packages for Mandrakelinux, everything should work fine. Note that a user will require their existing Unix password in LDAP in order to be able to change their password. Also, in most cases it should not be possible for the local root user to be able to change other users passwords in LDAP, since you would not place your rootdn password on the clients.

Unix users change Windows passwords

This is one of the most difficult to solve cleanly, as there are only two ways this can be accomplished, one which is not available in maintained form, the other has security implications:

  • There is a version of pam_ldap available that will modify the lmPassword and ntPassword attributes when changing the userPassword attribute, however it is not maintained and has not been merged into the mainline pam_ldap.
  • pam_smbpass (part of the Samba suite) will, when samba is compiled with ldapsam support, change Samba passwords in the configured sam backend on the machine where it is called, however this requires that each pam_smbpass installation installed for this purpose be provided with an LDAP DN with rights to change the password, and the password for that rootdn be imported into Samba, consequently stored in plain-text in one of Samba’s tdb files (protected with file permissions of course). This is no better than entering your rootdn password into /etc/ldap.secret and should be avoided on non-server machines.

At present, since your Unix users are likely to be more command-line literate, it may be best to have them change their Samba password manually with smbpasswd.

Password Expiry

Password expiry for Samba password will only be fully functional with Samba-3 on a “rich” SAM backend, including LDAP. The Samba schema for Samba-2.2.x includes password-expiry-related attributes, but only minimal use is made of them. While it is possible to get samba to cause a password-expiry prompt to appear at login time, changing the password will not update the password age, thus the following login prompt will still result in a password-expiry dialog. Also, an expired samba password may also not prevent a user from logging in. The updating of password ages could be done via a modified ‘passwd program’ and a cron job (this is being investigated).

However, Samba can be configured to “obey pam restrictions”, in which case Samba will deny logins to users when a pam “account” or “session” module has failed. Thus, if you expire Unix accounts via the LDAP attribute *shadowExpire*, both Unix and Samba accounts will be locked out until their passwords are reset. Unfortunately it seems impossible to have users warned automatically when their passwords are about to expire (as it would be with Samba-3), so you may have to write a script to check for accounts that are about to expire.

Exercises for the student

There are always things that can be improved upon, and these are some examples which the author is currently implementing, but are not complete or have not been in production for sufficient time that the author is willing to make them available for public scrutiny:

  • Using regex-based ACLs for slapd.conf, allowing generic ACLs in the global section of slapd.conf, instead of per-db ACLs
  • Using OUs to group entities that require the same Access Controls (such as Domain Controllers and/or LDAP slaves), allowing fewer ACLs (which can have a significant performance impact)
  • Patching the smbldap-tools to make the addition of profilePath and scriptPath attributes configurable
  • Implementation of password-unexpiry for Samba passwords in LDAP
  • Two-way (minimum) replication of user profiles (since one-way is too easy to give for homework)
  • Update to OpenLDAP-2.1 and Samba3

Cleaning up

No job is done until the tools have been put back in their places, and in our case that applies to any changes you made to your configurations during testing. So, remember to remove any passwords you used for migrating data (such as in the import_smbpasswd.pl file), turn logging back to sane levels, change any passwords that may have been transmitted in the clear or stored in files with weak permissions. Remove unnecessary bloat from your configuration files (you may want to make backups first), and ensure all the services are configured to start at boot. You should also ensure that your backup system takes snapshots of your LDAP database.

Credits and References

A number of people have been involved in allowing me to complete this document. Firstly, Vincent Danen, whose LDAP authentication article allowed me to get our LDAP authentication working correctly. Without Jim Collings, who wrote the initial Samba+LDAP PDC article I would not have been motivated to tackle this large topic, since we already had everything running. Of course, the The Samba Team who provide excellent software and better support, as well as the OpenLDAP developers.

I located a lot of documentation covering issues relating to LDAP (including ACLs and replication etc) and Samba. Some good documents which have content I have not referred to or covered are referenced below:

Copyright © 2003 Buchan Milne