(&(|(sn=smith)(sn=jones))(cn=john*))
Note that the (cn=john*) search filter matches any cn that begins with "john": it matches cn=john doe as well as cn=johnathon doe.
Following Referrals with ldapsearch
By default, the ldapsearch tool shipped with OpenLDAP 2 prints information about referral objects but does not automatically follow them. For example, let's use ldapsearch to list all entries in your directory that possess an ou attribute:
$ ldapsearch -H ldap://localhost/ -LL -x
> -b "dc=plainjoe,dc=org" "(ou=*)" ou
# plainjoe.org
dn: dc=plainjoe,dc=org
ou: PlainJoe Dot Org
# people, plainjoe.org
dn: ou=people,dc=plainjoe,dc=org
ou: people
# Search reference
# refldap://ldap2.plainjoe.org/ou=hosts,dc=plainjoe,dc=org??sub
Note that ldapsearch returned the referral value, but not the entries below the ou=hosts,dc=plainjoe,dc=org naming context. This information is obviously useful when you're trying to debug a directory tree that is distributed between several servers, but it's not what you want if you only intend to look up information. To follow the search referral, give the -C (chase referrals) option when you invoke ldapsearch:
$ ldapsearch -H ldap://localhost/ -LL -x
> -b "dc=plainjoe,dc=org" "(ou=*)" ou
# plainjoe.org
dn: dc=plainjoe,dc=org
ou: PlainJoe Dot Org
# people, plainjoe.org
dn: ou=people,dc=plainjoe,dc=org
ou: people
# hosts, plainjoe.org
dn: ou=hosts,dc=plainjoe,dc=org
ou: hosts
Limiting Your Searches
A production directory can easily grow to thousands or millions of entries—and with such large directories, searches with filters such as (objectclass=*) can put quite a strain on the directory server and generate more output than you want to deal with. Therefore, ldapsearch lets you define limits for both the client and the server that control the amount of time a search is allowed to take and the number of entries it is allowed to return. Table 5-2 lists the ldapsearch parameters that limit the resources required by any search.
Table 5-2. Command-line parameters for defining search limits in ldapsearch
Parameter
Description
-l integer
Specifies the number of seconds in real time to wait for a response to a search request. A value of 0 removes the timelimit default in ldap.conf.
-z integer
Defines the maximum number of entries to be retrieved as a result of a successful search request. A value of 0 removes the limits set by the sizelimit option in ldap.conf.
You can also specify limits on the server, in the slapd.conf file. Table 5-3 lists the global parameters that limit searches.
Table 5-3. OpenLDAP 2 slapd.conf global search limit parameters
Parameter
Description
sizelimit integer
Defines the maximum number of entries that the server will return to a client when responding to a search request. The default value is 500 entries.
timelimit integer
Specifies the maximum number of seconds in real time to be spent when responding to a search request. The default limit is 1 hour (3,600 seconds).
* * *
[1] For the full details of representing LDAP searches using strings, read RFC 2254.
Determining a Server's Capabilities
Chapter 2 alluded to two new LDAPv3 features: the subschemaSubentry and the rootDSE objects. Both of these objects allow clients to find out information about a previously unknown directory server.
The rootDSE object contains information about features such as the server naming context, implemented SASL mechanisms, and supported LDAP extensions and controls. LDAPv3 requires that the rootDSE has an empty DN. To list the rootDSE, perform a base-level search using a DN of "". OpenLDAP will provide only values held by the rootDSE if the search requests that operational attributes be returned, so the + character is appended to the search request.
$ ldapsearch -x -s base -b "" "(objectclass=*)" +
dn:
structuralObjectClass: OpenLDAProotDSE
namingContexts: dc=plainjoe,dc=org
supportedControl: 2.16.840.1.113730.3.4.2
supportedControl: 1.3.6.1.4.1.4203.1.10.2
supportedControl: 1.2.826.0.1.334810.2.3
supportedExtension: 1.3.6.1.4.1.4203.1.11.3
supportedExtension: 1.3.6.1.4.1.4203.1.11.1
supportedExtension: 1.3.6.1.4.1.1466.20037
supportedFeatures: 1.3.6.1.4.1.4203.1.5.1
supportedFeatures: 1.3.6.1.4.1.4203.1.5.2
supportedFeatures: 1.3.6.1.4.1.4203.1.5.3
supportedFeatures: 1.3.6.1.4.1.4203.1.5.4
supportedFeatures: 1.3.6.1.4.1.4203.1.5.5
supportedLDAPVersion: 3
supportedSASLMechanisms: GSSAPI
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: CRAM-MD5
subschemaSubentry: cn=Subschema
This list can change over time and will vary from server to server. Our example shows us that this server supports:
StartTLS (OID 1.3.6.1.4.1.1466.20037) and two other extended operations
ManageDsaIT (OID 2.16.840.1.113730.3.4.2) and two other LDAP controls
LDAPv3 operations only
The GSSAPI, DIGEST-MD5, and CRAM-MD5 SASL mechanisms
A single naming context of "dc=plainjoe,dc=org"
There may be additional attributes and values, depending on the LDAP server.
The SubSchemaSubentry attribute specifies the base search suffix for querying the schema supported by the server. This means that clients can verify that the server supports a given matching rule, attribute type, or object class prior to performing an operation that depends on a certain characteristic. The output from the following ldapsearch command shows the kind of information that is in the SubSchemaSubentry tree. Since this tree contains many entries, I've shortened it for convenience.
$ ldapsearch -D "cn=Manager,dc=plainjoe,dc=org"
> -w n0pass -x -s base -b "cn=SubSchema"
> "(objectclass=*)" +
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )
. . .
matchingRules: ( 2.5.13.2 NAME 'caseIgnoreMatch' SYNTAX
1.3.6.1.4.1.1466.115.121.1.15 )
. . .
attributeTypes: ( 0.9.2342.19200300.100.1.42 NAME ( 'pager' 'pagerTelephoneNumber' )
EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX
1.3.6.1.4.1.1466.115.121.1.50 )
. . .
objectClasses: ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY
( userPassword $ telephoneNumber $ seeAlso $ description ) )
. . .
* * *
Tip
You can't modify the schema supported by an OpenLDAP directory server by modifying entries contained in the cn=SubSchema tree.
* * *
Creating Custom Schema Files for slapd
There are times when the standard schema files distributed with your LDAP server don't meet the needs of your application. Creating a custom schema file for OpenLDAP is a simple process:
Assign a unique OID for all new attribute types and object classes.
Create the schema file and include it in slapd.conf.
It's also possible to create alternate schema syntaxes and matching rules, but implementing them is beyond the scope of this book; typically, they require implementing a plug-in for the directory server or modifying the server's source code. For more information on this process, you should consult the OpenLDAP source code or your vendor's documentation for other directory servers.
Chapter 2 described how to obtain a private enterprise number from IANA (see the form at http://www.iana.org/cgi-bin/enterprise.pl and
RFC 3383). When creating new attributes or object classes, it is a good idea to use an OID that is guaranteed to be unique, whether or not the schema will ever be used outside of your organization. The best way to guarantee that the OID is unique is to obtain a private enterprise number and place all your definitions under that number.
For example, suppose that an LDAP client application requires a new object class based on person. This new object class should contain all of the attributes possessed by the person object, with the addition of the userPassword and mail attributes.
In order to create this new object, I have allocated the OID arc of 1.3.6.1.4.1.7165.1.1.1 for the new object classes:
iso (1)
org (3)
dod (6)
internet (1)
private (4)
enterprise (1)
SAMBA.org (7165)
plainjoe.org (1)
O'Reilly LDAP Book(1)
The private enterprise number 7165 has been issued by IANA for use by the Samba developers, the 7165.1 arc has been allocated to the plainjoe.org domain, and 7165.1.1 has been set aside for this book; I can't touch the numbers above 7165.1 in the tree, but I have complete freedom to assign numbers below it as I see fit. I've chosen to allocate 7165.1.1.1 to ldap object classes that I create and 7165.1.1.2 for new attributes. I could put my new objects directly under plainjoe.org, but that might cause problems if I want to create other kinds of objects (for example, private SNMP MIBs):
SAMBA.org (7165)
plainjoe.org (1)
O'Reilly LDAP Book(1)
|-- objectclasses (1)
|-- attributeTypes (2)
Let's call the new object plainjoePerson. Add the following definition to a custom schema file named plainjoe.schema; you'll use this file for all custom objects that you define.
## objectclass definition for 'plainjoePerson' depends on core.schema.
objectclass ( 1.3.6.1.4.1.7165.1.1.1.1 NAME 'plainjoePerson'
SUP person STRUCTURAL
MUST (userPassword $ mail) )
LDAP's object inheritance allows this new object to reuse the existing characteristics of person; you need to add only the new required attributes. If new attributes are defined as well, they must be defined prior to their use in the plainjoePerson object. The new object has to be defined as STRUCTURAL since it is derived from a structural class.
New attributes can be defined in the same way or even be derived from existing attributes. RFC 2252 should be considered required reading in this case, as it describes the various LDAPv3 syntaxes and matching rules. For example, you could create a new attribute named plainjoePath to store a single, case-sensitive pathname by defining the following in plainjoe.schema:
## Store a case-sensitive path to a directory.
attributetype( 1.3.6.1.4.1.7165.1.1.2.1 NAME 'plainjoePath'
DESC 'A directory on disk'
SUBSTR caseExactIA5SubstringsMatch
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
* * *
Tip
Servers other than OpenLDAP may use a different schema syntax for representing object classes. You should refer to your directory server's vendor documentation for more details. General LDAPv3 schema syntax is described in RFC 2252.
* * *
Finally, you need to add an include line in slapd.conf for your new schema file:
# /usr/local/etc/openldap/slapd.conf
# Global section
## Include the minimum schema required.
include /usr/local/etc/openldap/schema/core.schema
## **NEW**
## Include support for special plainjoe objects.
include /usr/local/etc/openldap/schema/plainjoe.schema
After restarting slapd, you can now add objects of the type plainjoePerson or include the plainjoePath in entries that use the extensibleObject class.
SASL and OpenLDAP
The final section of this chapter explores how to replace the simple authentication used in your current directory server with SASL mechanisms. You will be using the GSSAPI mechanism for Kerberos 5 authentication (RFCs 1510, 2743, and 2478). The examples assume that a Kerberos realm named PLAINJOE.ORG has already been established and that a service principal named ldapadmin has been created. If you are unclear on the details of Kerberos 5, a good place to start would be Kerberos: A Network Authentication System, by Brian Tung (Addison-Wesley), or The Moron's Guide to Kerberos, located at http://www.isi.edu/gost/brian/security/kerberos.html.
So far, the rootdn and rootpw values used in slapd.conf have appeared similar to:
rootdn "cn=Manager,dc=plainjoe,dc=org"
rootpw {SSHA}2aksIaicAvwc+DhCrXUFlhgWsbBJPLxy
In OpenLDAP 2.1, an SASL ID can be converted to a distinguished name and used for authentication or authorization wherever a normal DN would be appropriate. This includes operations such as defining the updatedn used for replication or the binddn used by a client in a search request. There's one important exception to this rule: don't use an SASL ID as the DN of an entry in the directory. To summarize from Chapter 3, an SASL ID converted to a DN appears as:
uid=name[,realm=realm],cn=mechanism,cn=auth
To illustrate how to use SASL as the authentication mechanism, we'll replace the rootdn in our master server's slapd.conf with the Kerberos 5 principal ldapadmin. Following the conversion algorithm just discussed, the new rootdn in slapd.conf will be:
## New SASL-based rootdn
rootdn "uid=ldapadmin,cn=gssapi,cn=auth"
The rootpw entry can be deleted because authentication for the new rootdn will be done using the SASL GSSAPI mechanism. The OpenLDAP server must possess a valid keytab file containing the key for decrypting tickets transmitted with client requests.[2] Moreover, our tests will assume that the server is configured to use the default realm of PLAINJOE.ORG.
Once the configuration change has been made, restart slapd. You can then verify that the change has been made correctly by using the ldapadd command to add an entry; the rootdn is currently the only DN allowed to write to the directory.
To run this test, create a file with an LDIF entry; we'll use the following LDIF entry, stored in /tmp/test.ldif:
## Test user to verify that the new rootdn is OK.
dn: cn=test user,ou=people,dc=plainjoe,dc=org
cn: test user
sn: test
objectclass: person
To add this entry to the directory, invoke ldapadd with some additional arguments:
$ kinit [email protected]
Password for [email protected]: password
$ klist
Ticket cache: FILE:/tmp/krb5cc_780
Default principal: [email protected]
Valid starting Expires Service principal
11/28/02 19:20:15 11/29/02 05:20:15 krbtgt/[email protected]
$ ldapmodify -a -H ldap://master.plainjoe.org/
> -f testuser.ldif
SASL/GSSAPI authentication started
SASL username: [email protected]
SASL SSF: 56
SASL installing layers
adding new entry "cn=test user,ou=people,dc=plainjoe,dc=org"
$ klist
Ticket cache: FILE:/tmp/krb5cc_780
Default principal: [email protected]
Valid starting Expires Service principal
11/28/02 19:20:15 11/29/02 05:20:15 krbtgt/[email protected]
11/28/02 19:23:34 11/29/02 05:20:15 ldap/[email protected]
If the server does not support the particular mechanism needed, GSSAPI in this case, authentication will fail. The -Y option can be used to specify an SASL authentication mechanism rather than letting the client and server attempt to negotiate a valid type that is supported by both. As seen earlier, the client can obtain a list of the mechanisms that the server supports by querying the server's rootDSE and viewing the values of the supportedSASLMechanisms attribut
e.
After becoming accustomed to SASL user IDs, you can incorporate them into the ACLs defined in slapd.conf. Following the rule that an SASL ID can be used anywhere a DN is used to represent an authenticated user, SASL IDs can follow the by keyword in an ACL definition. For example, the following definition allows the Kerberos principal jerry to edit the mail attribute for all users in the people organizational unit:
access to dn=".*,ou=people,dc=plainjoe,dc=org" attrs=mail
by "uid=jerry,cn=gssapi,cn=auth" write
* * *
[2] More information on generating keytab files can be found on the kadmin(8) manpage.
Part II. Application Integration
Chapter 6
Chapter 7
Chapter 8
Chapter 9
Chapter 10
Chapter 6. Replacing NIS
One of LDAP's chief advantages is its ability to consolidate multiple directory services into one. This chapter examines the pros and cons of using LDAP as a replacement for Sun's Network Information Service (NIS). NIS is used primarily by Unix clients to centralize management of user information and passwords, hostnames and IP addresses, automount maps (files that control the mounting of remote file systems), and other administrative information. NIS clients for other operating systems, such as Windows NT 4.0, exist, though they aren't particularly common.[1]
While the focus of this chapter is using an LDAP directory as a replacement for NIS domains, many other tools are used to distribute management information on Unix systems; for example, many sites use rsync(1) to push administrative files, such as /etc/passwd, to client machines. While this chapter assumes that you are replacing NIS with an LDAP directory, adapting these techniques I present to other schemes for sharing the data in /etc/passwd, /etc/hosts, and other key files should be straightforward:
LDAP System Administration Page 13