Article Figure 1 jan2007.tar

Providing Feature-Rich File Services with Samba and LDAP

Tom O'Donnell

While many people view Samba as a way to enable Windows networking on Linux and related systems, it's actually an implementation of the cross-platform SMB (Server Message Block) protocol, which was developed by IBM back in the mid-1980s. Although Microsoft has extensively used and extended SMB -- they even coined an alternate name for it: Common Internet File System or CIFS -- the protocol has long been a part of Linux as well. In fact, Samba was born not long after Linux, back in the days of Windows 3.1. Since then, Samba has evolved into a stable, feature-rich software suite, and now it's just as viable a solution for serving network files to Windows clients as using actual Windows servers.

In fact, many Samba deployments involve setting up a Primary Domain Controller (and potentially even Backup Domain Controllers) to provide features associated with Windows-style domains, particularly central authentication for file access. There is an alternative approach, however, which provides many of the same benefits without the need for a PDC. By tying Samba to LDAP, you can provide network file services with central authentication as well as other perks, like access control lists and a server-side recycle bin. The end result is a file serving solution that rivals proprietary operating systems, like Windows or Netware, yet is built entirely out of open source components.

To accomplish this feat, you'll need at least one server running Samba and one server running LDAP. They can be on the same machine or separate, and there are benefits to using more than one of either. For example, one LDAP server can operate like a domain controller by providing authentication for Samba shares on several servers, while multiple directory servers can (through LDAP replication) provide distributed authentication across the network, not unlike Active Directory.

In this article, I will explain the steps required to get Samba running, as well as what modifications are needed in LDAP to properly authenticate end users. To keep the story focused on Samba, I'll assume that you already have an LDAP directory installed and populated with users. If you need help getting to that point, consult the OpenLDAP Administrator's Guide at:

http://www.openldap.org
            
While this demonstration was assembled on Fedora Core 5 with Samba 3.0.23b and OpenLDAP 2.3.24, it should work about the same on other distributions and with other LDAP providers, as long as the version of Samba is 3.x. The paths given for Samba and OpenLDAP files are based on builds using default locations. For simplicity's sake, we'll assume both services are running on the same machine.

Installing Samba

The first objective is to download and build the most recent Samba release, which is available at:

http://www.samba.org 
with the filename samba-latest.tar.gz. Once downloaded, the following commands handle the installation:

tar -xzvf samba-latest.tar.gz 
cd samba-version_number/source
./configure --with-acl-support 
make 
make install 
The only configure option we need is the one to support access control lists. There is a "--with-ldap" option, but it's set to yes by default, so we don't need to include it.

For the ACL option to be of any use, the file system where the shared directory is located must be mounted with that option enabled. You can do this by adding the appropriate flag to the share point's entry in /etc/fstab. In this case, assume that we have /home on a partition and will put our shares there:

/dev/sda2   /home   ext3   defaults,acl 
    
Note that many file systems (including ext2/ext3) have ACL support built into the 2.6 kernel, but you'll likely need a kernel patch if you're using 2.4.

Configuring Samba

Once the installation is complete, we can edit the configuration file smb.conf (located in /etc/samba/ or /usr/local/samba/lib/, depending on the Samba version) to set up the server and its shares. There are plenty of options available for this file, including security and performance tweaks you should investigate before unleashing Samba on your production network. To learn more, consult the voluminous man page for smb.conf or the annotated sample file that is installed with Samba. For this demonstration, let's keep it relatively simple:

#====================== Global Settings =========================== 
[global] 
   #--- server identity 
   workgroup = sampleworkgroup 
   netbios name = sambaserver 
   server string = Just a sample Samba server 
   #--- logging options 
   log level = 2 
   debug pid = yes 
   debug timestamp = yes 
   debug uid = yes 
   #--- LDAP authentication settings 
   passdb backend = ldapsam:ldap://localhost 
   ldap suffix = dc=example,dc=com 
   ldap user suffix = ou=people 
   ldap admin dn = cn=Manager,dc=example,dc=com 


#====================== Share Definitions =========================== 
[sharedata] 
   #--- general settings 
   comment = Something for everyone 
   directory = /home/shared 
   read only  = No 
   hide unreadable = Yes 
   #--- settings for the recycle bin 
   vfs objects = recycle 
   recycle:repository = /home/shared-recycle/ 
   recycle:noversions = 2 

[secretdata] 
   directory = /home/secret 
   browseable = No 
   valid users = jack jill 
   hosts allow = 192.168.1.0/255.255.255.0 
The configuration is divided into two sections, Global Definitions and Share Definitions. The global settings define qualities of the server itself, such as the workgroup to which it belongs, its NetBIOS name, and its server string, which is simply the description that clients will see when browsing the network. To help troubleshoot later, we include relatively verbose logging options. And, we add some settings related to our LDAP server.

Below the global section are the definitions of each share. In this example, we've created two contrasting shares, one for everyone on the network and another just for a select few. The first starts with a descriptive comment (again for client browsers) and the server-side location of the shared folder. We also need to indicate that the share is not read only, since the default is to make it so. By including "hide unreadable = Yes," we set it so that end users will only see items that they are able to access. There is one more permissions-related setting we want, the "nt acl support" flag, but it's set to yes by default, so we can omit it.

In addition to the parameters inherent in smb.conf, Samba 3 introduces new tools in the form of add-on VFS modules. Some of these, like a shadow copy utility and a module to help support Netatalk (the Unix/Linux implementation of AppleTalk), are included as part of the standard Samba install. Others, such as a virus scan integrator from http://www.openantivirus.org, are available separately. Our server uses one of the included modules: the recycle VFS. This handy tool, analogous to Netware's "Salvage File" utility, keeps deleted or modified files in a separate location for easy restores. We're even keeping multiple versions, just in case.

The second share is aptly labeled "secretshare", as the last two lines restrict access to only certain users, and they can only get there from one private subnet. The parameter "browseable = No" ensures that clients won't see this share in network browsers -- akin to tacking "$" onto the end of a Windows share name -- so the only way to get there is to type the path directly. Because we don't specify otherwise, the share defaults to read only, which is probably for the best, since we don't set up a recycle bin either.

Based on our smb.conf file, Figure 1 shows how a Windows XP client will see the server in "My Network Places" when we're up and running. This shows many of the settings at work: the server string, the server NetBIOS name, and one of the share names with its share comment. Note that the second share isn't visible, because we specified that it not be browseable.

Although this example doesn't use them, Samba offers a couple of unique shares with special properties. One of these, distinguished by the name [homes], maps private home directories for individual users. The [printers] share is another and, not surprisingly, it deals with SMB shared printers. For more information on this, consult the Samba documentation.

Before we move on, we need to let the Samba server know the password for the LDAP admin account listed in smb.conf. To accomplish this, we use the multipurpose utility smbpasswd with a "-w" designated just for this purpose. It takes the password (in this case, the default for the Manager user in OpenLDAP) as a parameter:

smbpasswd -w secret
     
Testing the Samba Server

At this point, we should be able to start Samba and test it. There are two daemons involved: smbd, the actual file-serving process, and nmbd, which helps the client and server find each other over NetBIOS. You can start both with one command:

/etc/init.d/smb starts
     
To make sure these processes begin running at boot, enable this script in your run-level startup.

When you edit and save smb.conf, the server often picks up on the change automatically, so there's usually no need to restart the daemons for the new settings to take effect. Changing a key identifier -- the server's NetBIOS name, for example -- does call for fresh start, however:

/etc/init.d/smb restart
You can check your progress so far by attempting to contact the server using its UNC path name \\sambaserver from a Windows client. You won't be able to authenticate, but you should at least get a login box on the client. If not, or if Samba wouldn't start at all, you may be able to tell why by tailing /var/log/samba/smbd.log, the default log file. Samba also includes a useful utility called testparm, which parses your smb.conf file and displays relevant errors or warnings. Finally, if the client and server can ping each other but Samba doesn't appear to work, be sure they can communicate over the ports involved, UDP 137-138 and TCP 139.

Configuring LDAP

To prepare LDAP as an authentication source, we need to add some new attributes to our directory. These attributes aren't part of a stock OpenLDAP install, so we need to extend the schema. To begin, go back to the unzipped Samba download and copy the file samba-version_number/examples/LDAP/samba.schema to /usr/local/etc/openldap/schema/ (or whatever folder contains your other schema files). Then add the following lines to /usr/local/etc/openldap/slapd.conf:

include /usr/local/etc/openldap/schema/cosine.schema 
include /usr/local/etc/openldap/schema/inetorgperson.schema 
include /usr/local/etc/openldap/schema/nis.schema 
include /usr/local/etc/openldap/schema/samba.schema 
The first three files are installed (but not included in the default configuration) with OpenLDAP, and they're commonly used, so you may already have some of them enabled. The last file introduces the Samba-specific attributes. Remember, you'll need to restart the LDAP server for the schema extensions to become available.

These directory changes add two new object classes and several resultant attributes that our accounts will need. The first class, sambaSamAccount, provides attributes relating to authentication, including sambaSID (a unique identifier for each Samba account), sambaNTPassword (a Windows NT hash of the user's password), and sambaLMPassword (a LANMAN hash of the password). The other class, posixAccount, adds uidNumber and gidNumber to give users Unix-style user and group numbers, which allow them to own and access files just like local users.

Now the question is: how do you populate these fields for your LDAP user accounts? Unfortunately, there isn't an easy answer. We could almost do it using ldapmodify commands and some well-crafted LDIF files, but the sambaLMPassword and sambaNTPassword attributes expect encrypted values, so we can't just insert a plain-text password. Fortunately, because Samba is looking to LDAP as its authentication source, the smbpasswd utility is now equipped to set or change those password hashes for us. However, the user accounts don't have the required sambaSamAccount object class yet, so running smbpasswd to set the attributes will fail.

One way through this is to make an LDIF file that adds the object classes and all attributes except the passwords, then run smbpasswd to set the password hashes. To go this route, we'd need a fixuser.ldif file like this:

dn: cn=username,ou=people,dc=example,dc=com 
changetype: modify 
objectClass: person 
objectClass: sambaSamAccount 
objectClass: posixAccount 
uidNumber: 10418 
gidNumber: 100 
homeDirectory: /home/username 
uid: username 
sambaSID: S-1-5-21-3182778698-226005414-4011289646-21836 
Keep a few pointers in mind when determining which values to use. Most importantly, uidNumber, uid, and sambaSID must be unique for every user in the directory. The uid is often the same as the user's cn, while the uidNumber is conventionally over 1000. Though we haven't dealt with groups up to this point, they can be Samba-enabled in LDAP, too, so the gidNumber can be relevant to file access. For now, what's important is that users have a gidNumber, since it's required for the posixAccount class. The homeDirectory attribute is also mandatory, and it has an added role if you make one of those special [homes] shares, since it provides the path that will map to the user's home location.

The lengthy sambaSID is composed of two parts, the domain's SID and a unique number for the user. To find the domain SID, use this command:

net getlocalsid
You could theoretically set the user part to anything, as long as all users' sambaSIDs are different, but the convention is to take the uidNumber, multiply it by two, and add 1000 -- hence the "21836" is this user's sambaSID.

Then we can add all the changes to the directory with an ldapmodify command:

ldapmodify -x -D cn=Manager,dc=example,dc=com -W -f fixuser.ldif
    
After that, we can set the password attributes with smbpasswd and a uid:

smbpasswd username
There are alternatives to using LDIF files and smbpasswd, and they may be applicable in certain situations. If you don't have many users to change, you can do the job through the phpLDAPadmin Web front end (available at http://phpldapadmin.sourceforge.net/), which will kindly encrypt passwords as needed if you enter them as plain text. For a bigger job, PADL software offers a number of Perl scripts (available at http://www.padl.com/OSS/MigrationTools.html) to assist with migration from flat files and other directories. In addition, the smbldap-tools package (available at http://sourceforge.net/projects/smbldap-tools/) includes tools which, though intended for Samba/LDAP scenarios with domain controllers, may also be of interest. If nothing else, the Perl scripts at these sites show you which functions to use if you want to write your own code to encrypt and store passwords.

Once the user accounts are ready, we need to let the operating system know about them, so they can be used for file ownership and permissions. To do this, alter the Name Service Switch file, /etc/nsswitch.conf, adding "ldap" to the following lines:

passwd:     files ldap 
shadow:     files ldap
group:      files ldap 
    
Putting It All Together

Now that both Samba and LDAP are ready, we're almost done. All that's left is to create the shared folders and grant access to users. For simple situations, the usual Unix ownership and permissions will do:

mkdir /home/shared /home/shared-recycle 
chmod 755 /home/shared 
mkdir /home/shared/jacks_files 
chown jack:root /home/shared/jacks_files 
chmod 755 /home/shared/jacks_files 
    
Now Jack owns his files, but others can read them if they want.

For more complex needs, we can use an access control list:

mkdir /home/shared/jills_files 
chown jill:root /home/shared/jills_files 
chmod 700 /home/shared/jills_files 
setfacl -m mask::rwx /home/shared/jills_files 
setfacl -m user:jack:rwx /home/shared/jills_files 
setfacl -m user:john:rx /home/shared/jills_files 
This way, Jill and Jack have full access, John has read access, and no one else can get in at all -- an arrangement we couldn't offer using only chown and chmod. The ACL mask sets the maximum possible permissions; in this case we set it to rwx, so we can give Jack full access. A long format listing shows that the folder's permissions now end with a plus sign, which denotes extended attributes. The particular user rights can be verified with the command:

getfacl /home/shared/jills_files 
    
Though only Jack and Jill have access to the "secretdata" share through Samba, it's still a good idea to set its permissions to 700, chown it to root, and use an ACL, so unauthorized local accounts can't get to the files on the server:

mkdir /home/secret 
chmod 700 /home/secret 
chown root:root /home/secret 
setfacl -m mask::rx /home/secret 
setfacl -m user:jill:rx /home/secret 
setfacl -m user:jack:rx /home/secret 
    
Now if you connect from a Windows client using the Samba share's UNC path, you should be able to authenticate as one of the LDAP users you modified, and you should see whatever files and folders the user has rights to. In our example, if you log in to \\sambaserver\sharedata as Jack, you'll see "jacks_files" and "jills_files", while logging in as Jane will only show you "jacks_files". You may not even have to log in again, if your local username and password match those in LDAP. When you first access the Samba server, Windows tries the local credentials against the server first, and if they work, your client will connect automatically.

If you're still unable to authenticate, the Samba logs will likely tell you why. One common error message is NT_STATUS_WRONG_PASSWORD, which means that the password you entered doesn't match the hashed Samba password values in LDAP. Another error you may see is NT_STATUS_NO_SUCH_USER, which means that the LDAP account lacks one or more of the posixAccount or sambaSamAccount attributes. If troubles persist, you might try restarting Samba and OpenLDAP, just to make sure they've caught all the configuration changes.

Once the server is running and clients are connecting, you can check your progress with smbstatus, another tool in the Samba suite. Its output shows which users are connected, which machines they're connected from (by computer name and IP address), and which files they have open.

Conclusion

Using this Samba/LDAP set up as a foundation, you can build even more complex functionality. You can tie LDAP groups into Samba, then set permissions by groups as well as users. You can map shares to client drive letters with the Windows command-line tool "net use". Using the open source tool pGina (http://sourceforge.net/projects/pgina/), you can even set your client machines' initial login to bounce off LDAP, run network login scripts, and use roaming profiles. The possibilities are intriguing, and with Samba version 4 development well underway, they're likely to get even better.

Tom O'Donnell is a network and server administrator at the University of Maine, Farmington. He acknowledges his co-workers Aaron Gagnon and David Irving for their wisdom and counsel on Samba and LDAP matters. Tom can be reached via email at: tomod@maine.edu.