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:
[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.
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.
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
#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.
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.
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]
[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: email@example.com 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: firstname.lastname@example.org 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.
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:
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 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 22.214.171.124: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 126.96.36.199: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 188.8.131.52, 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 184.108.40.206 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
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.
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.
Copyright © 2003 Jim Colling