Implementing a Samba LDAP Primary Domain Controller Setup

Vincent Danen

March 25, 2008

Copyright © 2003 Jim Colling

Originally written for the MandrakeSecure website.

The example server box is i686 Mandrake 9.0 with all the updates I can get my hands on. To cut down on network traffic and to ease security, it houses both the OpenLDAP server and Samba. It has also been tested on Mandrake 9.1.

Speaking of Mandrake 9.1, the reader would be well advised to ensure that all updates have been installed for the OpenLDAP package as some bugs were discovered in the original release of OpenLDAP that comes with Mandrake 9.1.

As of the writing of this document, Samba 3.0 is still in Alpha stage. There will be differences in implementation / configuration but anyone adequately familiar with 2.2.x will probably be able to figure it out. This document is meant to be an addendum to the OpenLDAP for Authentication topic and the basic Samba PDC instructions. Many thanks and all credit due to the authors of these documents. Problems discovered in this document should be forwarded to me at this email address. Go easy on me, I'm new at this. :-)

Basic procedure for implementing this HOWTO should be as follows:

  1. Implement the article on OpenLDAP authentication. This will eliminate the Linux based authentication portion. When finished, return to this HOWTO. Also don't bother, just yet, with the section on Samba as we do not yet have it installed. While you are implementing this article read very, *VERY* carefully. The font is small and I found it quite easy to miss important steps while I was doing it. Also the volume of information provided, while very informative and necessary, increases the odds of an error. I would consider it wise to install the GUI-LDAP browser/editor called gq so that you can easily see exactly what is occurring in the database and delete records if you don't quite get it right the first time. Here is the topic on OpenLDAP authentication; gq is on the contribs CD. One might acquire it by going to http://plf.zarb.org/~nanardon and adding a contrib source to rpmdrake. Having done this facilitates the use of urpmi [gq package name], which automates rpm and is nicer to use. I've used gq-0.7.0beta2-1mdk on the original Mandrake 9.0 box which I found at speakeasy. Note that migrating old userid's over to samba-ldap may be something to put off until a fully functioning samba-ldap system has been established. In this way, we will also be able to take advantage of the special scripts provided for this purpose. At least two accounts will be required immediately for testing, however. These are Administrator (or an administrator) and a regular unprivileged user.
  2. Performance of a certain amount of complexity management will also be worth while. This material can cause headaches, so take things one step at a time. In the same spirit, if you've never installed a Samba PDC without LDAP, it is probably wise to give that a try before moving on to this, the next level. The basic process for doing this can be found in the docs section of mandrakeuser. org and can be performed with OpenLDAP installed and configured without any harm. You can get your Samba rpm packages from download.samba.org. While they will be needed in the next step, do not install the LDAP packages for this stage. Use the others instead.
  3. Ensure that you have the NetBIOS ports 136,137 and 138 available to both the OpenLDAP / Samba server and the client systems. While doing this, it may also be desirable to check on OpenLDAP ports 389 and 636. Especially if your OpenLDAP and Samba servers are not on the same box. Don't forget to start the daemons first as shown below.
[root@ldap]# service ldap start; service smb start

Most network people will say that having one box performing both the Firewall and File Server functions is a poor security practice and they are correct. This may not be practical, reasonable or possible on many systems, however. Home networks, for example, may find themselves in situations similar to my own. I am not only poorly funded but I am also situated behind an Internet Service Provider's hard-core, supra-draconian firewall and bandwidth management system. Such is the price one finds oneself paying for high speed access in a small rural college town.

But I digress. As a result of the above, I've provided a commented example [rules.txt /etc/shorewall/rules] file here. How useful this is depends on much, so your mileage may vary.

OK, you've made it this far, now you are ready for cross-platform samba-ldap!! Because we've performed step 1, we already have a working and at least minimally populated OpenLDAP database and, because we have performed step 2, we already have a good idea of what settings are required to get a Samba PDC server to authenticate users for Windows. We are still missing some things however.

  • We may have to upgrade to our new samba-ldap packages from the old Samba packages.
  • We have to make the same adjustments to smb.conf as mentioned in the Samba PDC article with several additional adjustments for LDAP.
  • We need to make some design decisions about where in the database we want our computer accounts placed.
  • We must configure the Perl scripts that will manage our accounts in the LDAP database.
  • We need to make one minor change to _/etc/ldap.conf_
  • Security must be tailored to reduce the new system's exposure.

Upgrading to Samba-LDAP

In order to perform our upgrade, new samba-ldap packages can be retrieved from the same location mentioned before. When we do this, the old configuration files will be copied to a new file named [old file name].rpmsave.

If you install an external source (ie. a Sambaldap source via the PLF pages mentioned momentarily), then use this command:

[root@ldap]# urpmi samba-server-ldap

If would rather not install an external source, you will have to go to download.samba.org and download and install them by hand using:

[root@ldap]# rpm -U [package name]

The real difference is that urpmi takes care of the dependencies automatically. The above source can be added from plf.zarb.org.

Adjustments to smb.conf

Next we need to refer back to this section on Samba in the OpenLDAP Auth topic. Follow the instructions but with these caveats:

The article suggests the following settings:

ldap admin dn = cn=root,dc=mylan,dc=net
ldap server = 127.0.0.1
ldap suffix = dc=mylan,dc=net
ldap port = 389
ldap ssl = start_tls

We don't really need the overhead that accompanies encryption between two servers on the same system. If a cracker can gain access to your system at this level then likely they can get your encryption codes also, rendering the point moot. If your LDAP server is not on the same machine you would definitely want this on.

More specifically, if you have:

ldap ssl = start_tls

then you should set ldap port = 389. If you have:

ldap ssl = on

then you should set ldap port = 636. Finally, if you have:

ldap ssl = off

or

#ldap ssl = start_tls

(commented out), then you should set #ldap port = 389 (also commented out).

Again, since both our Samba and our OpenLDAP servers are on the same box, we will go with the last one.

Settings specific to a particular versions of Microsoft's OS's are dealt with in the basic Samba PDC article and are consequently outside the scope of this HOWTO.

Remember to pay close attention to the comments in the _smb.conf_ file. They can be quite educational. All in all then, the settings in smb.conf to be added to those found in the basic Samba PDC article are:

#in the global section:
[global]
ldap admin dn = cn=root,dc=mylan,dc=net
ldap server = 127.0.0.1
ldap suffix = dc=mylan,dc=net
#ldap ssl = start_tls
add user script = /usr/share/samba/scripts/smbldap-useradd.pl -w -d /dev/null -g machines \
 -c 'Machine Account' -s /bin/false %u
domain admin group = root Administrator @adm @Administrators @wheel

(Note the line wrap in the above example; this should all be on one line in your file.)

When Samba goes to manipulate or read the OpenLDAP database, it needs to have an administrative level of access. This is what the ldap admin dn setting is used for, but have you noticed something missing? No password! Just like in a normal Samba PDC implementation we need to use:

[root@ldap]# smbpasswd -w [password]

to store the password in /etc/samba/secrets.tdb.

In Windows Networking, computers are treated like users. They have their own userid's. The add user script line, mentioned above, will cause a machine that successfully joins the domain to be added to the LDAP database automatically. This will ease management of Computer accounts.

Exploring the various other Perl scripts available in the /usr/share/samba/scripts directory might also be wise. Some of them do require minor changes. Take import_smbpasswd, for example. It requires changes to the section displayed below that reflect the system as it actually is:

#################################################
## set these to a value appropriate for your site
##

$DN="ou=people,dc=mylan,dc=net";
$ROOTDN="cn=root,dc=mylan,dc=net";
# If you use perl special character  in your
# rootpw, escape them:
# $rootpw = "secr\@t" instead of $rootpw = "secr@t"
$rootpw = "n0pass";
$LDAPSERVER="scooby";

##
## end local site variables
#################################################

Since the script requires the $rootpw password value in clear text, the file is only readable by root. This is for your own protection, but if you use the script, please remember to remove the password once you have imported all your users. The fewer plain text passwords laying around the better.

The domain admin group setting in /etc/smb.conf is a list of users and groups of users who are allowed to administer the system. The list above is an example of users and groups you may wish to include. Note that the @ symbol is used to tag groups so that the system can tell the difference between a user and a group. By default, only people who are listed here, or in one of the groups listed here, can add users or machines to the system.

The "Computers" OU

Next, we have to make an adjustment to our OpenLDAP database. Specifically, we will need an additional organizational unit (ou).

So far we are keeping our users under the People ou but we still need a place for our computer accounts. We'll call this place ou=Computers,sc=mylan,dc=net as shown below. Create a text file with the following contents named ComputersOU.ldif:

dn: ou=Computers,dc=mylan,dc=net
ou: Computers
objectClass: top
objectClass: organizationalUnit
objectClass: domainRelatedObject
associatedDomain: mylan.net

Now, as root, use this command to add it to the system:

[root@ldap]# ldapadd -x -D "dc=mylan,dc=net" -W -f ComputersOU.ldif

As a side note, I will mention that amongst user accounts of any sort (i.e. whether it be a computer account or a living breathing user) the uidNumber must be unique. For example, there should be only one uidNumber: 501 anywhere in the dc=mylan,dc=net domain.

Configuring the Perl Scripts

Let's talk about the script configuration file, /etc/samba/smbldap_conf.pm. This file provides information about how you want things to the Perl scripts we will be using to manage our system. Now again, this is another well commented script file. Reading these comments, as before, can prove highly educational. Open it using your favourite text editor and set the following:

$slaveLDAP = "127.0.0.1";

$masterLDAP = "127.0.0.1";

$suffix = "dc=mylan,dc=net";

$usersou = q(People);

$computersou = q(Computers);

$groupsou = q(Group);

#Where mylan is the name of our domain. It should be the same as the
#workgroup setting in '/etc/smb.conf'
$binddn = "cn=root,dc=mylan,dc=net";

$bindpasswd = "place password belonging to the binddn above, here";

$_userLoginShell = q(/bin/bash);

$_userHomePrefix = q(/home/);

#All users must belong to at least one group.  On my system this group
#is called dusers and the gidNumber is entered below.
$_defaultUserGid = 1002;

#All computer accounts must also belong to at least one group.
#On my system this group is called "Machines" and the gidNumber is
#entered below.
$_defaultComputerGid = 421;
#Note: Use a drive letter below that is not being used, otherwise
#there will be trouble. It has to be unique. There can't be two named Z:

#I'm going to use 'Z:' but you can use anything that is free on all
#systems.
$_userHomeDrive = q(Z:);

Now that we can use our scripts, we need to ensure that we have an Administrator account, an adm group, a dusers group, a Machines group and at least one unprivileged user. The unprivileged user I am using is jcolling. Those who lean on the Unix side may certainly use root instead of Administrator, if they wish.

To check for the groups, you can do as I have done:

[root@ldap]# smbldap-groupshow [name of group]

For example:

[root@ldap]# smbldap-groupshow adm
dn: cn=adm,ou=Group,dc=mylan,dc=net
objectClass: posixGroup
cn: adm
gidNumber: 1001

Checking for the users is only slightly different. Don't be alarmed if you see the users passwords though. Due to the $binddn = "dc=mylan,dc=net" setting, the scripts access the system as root and are entitled to them. Just remember to clear your screen afterwords with the clear command (or CTRL-L):

[root@ldap]# smbldap-usershow Administrator
dn: uid=Administrator,ou=People,dc=mylan,dc=net
sn: Administrator
mail: root@mylan.net
mailForwardingAddress: Administrator@mail.mylan.net
mailHost: mail.mylan.net
objectClass: mailRecipient
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: kerberosSecurityObject
objectClass: shadowAccount
objectClass: sambaAccount
userPassword:: [I've deleted this for security reasons]
shadowLastChange: 12110
shadowMax: 99999
shadowWarning: 7
krbName: Administrator@MYLAN.NET
loginShell: /bin/bash
uidNumber: 1000
homeDirectory: /home/Administrator
gecos: Administrator
gidNumber: 1001
mailLocalAddress: root@mylan.net
uid: Administrator
pwdLastSet: 1046627953
logonTime: 0
logoffTime: 2147483647
kickoffTime: 2147483647
pwdCanChange: 0
pwdMustChange: 2147483647
displayName: Administrator
cn: Administrator
rid: 3000
primaryGroupID: 3003
lmPassword: [I've deleted this for security reasons]
ntPassword: [I've deleted this for security reasons]
acctFlags: [UX         ]

[root@ldap]# clear

If you are missing users or groups they are easily added using smbldap-groupadd and smbldap-useradd as shown below. Just remember to keep the default gidNumbers straight in /etc/samba/smbldap_conf.pm.

The commands to add each user/group are as follows:

[root@ldap]# smbldap-groupadd adm
[root@ldap]# smbldap-groupadd Machines
[root@ldap]# smbldap-groupadd dusers
[root@ldap]# smbldap-useradd -a -P -m -E '' -F '' -g adm -G dusers Administrator
[root@ldap]# smbldap-useradd -a -P -m -E '' -F '' -g dusers unpriviledgeduser

Note that I've been using dusers because users is already a local group in /etc/group.

Editing /etc/ldap.conf

OK, now we have a new (ou) which we have yet to set up access for. Fixing this situation will entail editing /etc/ldap.conf.

Remember these lines in /etc/ldap.conf from the OpenLDAP Auth article?

nss_base_passwd         ou=People,dc=mylan,dc=net?one
nss_base_shadow         ou=People,dc=mylan,dc=net?one
nss_base_group          ou=Group,dc=mylan,dc=net?one
nss_base_hosts          ou=Hosts,dc=mylan,dc=net?one

On the LDAP server machine, and only on the LDAP server machine, we need to change the first one to read:

nss_base_passwd         dc=mylan,dc=net?sub

We need to do this because if we don't, the system will not be able to find the Computer accounts which don't live in the People organizational unit. When we add them, they will live in the Computers organizational unit and when Samba goes hunting for them we want it to start at the base and continue down the directory tree so that it finds ALL user accounts.

Security

Security is our last issue. Log into Linux as the unprivileged user and from the command line execute:

[root@ldap]# ldapsearch -LL -H ldap://localhost -b"dc=mylan,dc=net" -x "(uid=Administrator)" \
| grep Password

Whoa! The unprivileged user can see all the Windows NT and Lanmanager passwords! We have got to fix this. Fortunately, the fix is as simple as altering the first line of /etc/slapd.access.conf. It used to read:

access to dn=".*,dc=mylan,dc=net" attr=userPassword

...but now we should change it to this to secure those passwords:

access to dn=".*,dc=mylan,dc=net" attr=userPassword,lmPassword,ntPassword

Now the OpenLDAP server needs to be restarted. We do this in the same manner as mentioned in the OpenLDAP Auth article, namely:

[root@ldap]# service ldap restart

To double check those password attributes, you man now wish to run the ldapsearch command again. You shouldn't see any passwords this time.

Now the last major security issue we have to worry about is securing the server.

If you have a firewall running on this box, shut it down momentarily and enter the netstat command shown below and notice any connections from Samba's ports (i.e. ports 137 - 139) open to the Internet.

[root@ldap]# netstat -ntupl | grep smbd; netstat -ntupl | grep nmbd

Your output will be different but should resemble mine:

[root@ldap]# netstat -ntupl | grep smbd; netstat -ntupl | grep nmbd
tcp        0      0 0.0.0.0:139             0.0.0.0:* LISTEN      28174/smbd
udp        0      0 208.152.4.207:137       0.0.0.0:*             28184/nmbd
udp        0      0 192.168.1.253:137       0.0.0.0:*             28184/nmbd
udp        0      0 0.0.0.0:137             0.0.0.0:*             28184/nmbd
udp        0      0 208.152.4.207:138       0.0.0.0:*             28184/nmbd
udp        0      0 192.168.1.253:138       0.0.0.0:*             28184/nmbd
udp        0      0 0.0.0.0:138             0.0.0.0:*             28184/nmbd

Now I know that eth0 (a.k.a 208.152.4.207, in my case ) is non-local (i.e. the Internet) and eth1 ( a.k.a 192.168.1.253 ) is my local network. This is not secure because folks from outside my network can talk to my Samba server over eth0. I can secure it by making two minor changes to /etc/samba/smb.conf. In smb.conf you will find two lines similar to these:

#  hosts allow = 192.168.1. 192.168.2. 127.

;   interfaces = 192.168.12.2/24 192.168.13.2/24

#Change the first one to read:

   hosts allow = 192.168.1. 127.

#and the second one to read:

   interfaces = 192.168.1.253/24

#and lastly add this line, also, in the global section:

        bind interfaces only = yes

Ensure that either reverse DNS lookups work or that you have a good /etc/hosts file, otherwise you may get weird errors on the samba side, and no connection on the windows side when using hosts allow.

Now restart both the firewall and the Samba server and let's take a second look with the netstat command again:

[root@ldap]# netstat -ntupl | grep smbd; netstat -ntupl | grep nmbd

Mine now gives this output. Notice that IP address 208.152.4.207 is no longer displayed, indicating that access is no longer available to that IP address:

[root@ldap]# netstat -ntupl | grep smbd; netstat -ntupl | grep nmbd
tcp        0      0 0.0.0.0:139             0.0.0.0:* LISTEN     28311/smbd
udp        0      0 192.168.1.253:137       0.0.0.0:*            28321/nmbd
udp        0      0 0.0.0.0:137             0.0.0.0:*            28321/nmbd
udp        0      0 192.168.1.253:138       0.0.0.0:*            28321/nmbd
udp        0      0 0.0.0.0:138             0.0.0.0:*            28321/nmbd

Congratulations!

You've just finished your samba-ldap PDC! Remember to make any necessary adjustments to your client systems in accordance with standard Samba PDC procedure then use the Administrator user's userid and password to add your machine to the domain.

According to discussion on the OpenLDAP lists, these next comments do not pertain to the smbldap-tools package (i.e. the Perl scripts in /usr/share/samba/scripts) but they are important if you are going to write scripts in languages other than Perl. Now, if you have things set such that you never have more than one entity, either an administrator or a script etc., making changes at one time you may safely ignore these issues. Otherwise you may be interested in the information below.

OpenLDAP is a trimmed down Object Orientated DBMS as opposed to an RDBMS or Relational DBMS. Trimmed down means that some of the functions one might normally find in a DBMS have been omitted. This lack of function is not by any means a bad thing as it facilitates speed and compatibility across different versions of LDAP. However because of this, some creativity is frequently required when writing scripts that manage the system.

Specific problems I have encountered include the inability to efficiently retrieve the largest uidNumber in the database and the lack of record-locking facilities. The former can be resolved by adding the uidPool and gidPool objectClass'es to the proxyuser. One then uses these to store the largest uidNumber or gidNumber so that we don't have to query the entire system to retrieve them. The later can be resolved by using a data structure called a semaphore in our local scripts. Also, by specifying the entire dn, including the value to be modified, in the script such that if the value is modified by another script before we can finish our modification, our modification will fail because the dn no longer exists. Semaphores exist in Perl, PHP and also I believe in Python. To find out more about them, use an on-line reference appropriate to the script language you wish to use. Most of these explain the concept sufficiently so that even one who does not know the script language in question can understand it.

Credits

The amount of help I received in compiling this article was phenomenal. When I started, I was new to authentication, OpenLDAP and Samba PDC's. The guidance I received from the folks listed here was invaluable. Doubly so since this HOWTO is a direct contribution to my graduate thesis on Cross-platform user authentication. I owe a great number of people thanks however it is likely that I will not be able to list them all. The listed sources then, are those to whom I feel especially indebted.

  • Buchan Milne
  • Vincent Danen
  • The online Samba Community
  • The online OpenLDAP Community

Copyright © 2003 Jim Colling