The
OpenLDAP Perl Backend
Reinhard E. Voglmaier
OpenLDAP is the reference implementation for the LDAP protocol.
The OpenLDAP distribution [1] is not just an LDAP server but also
offers a framework containing everything necessary to build an LDAP
workbench. And, most importantly for projects with a small budget,
it's completely open source and free.
In a previous Sys Admin article ("The OpenLDAP Proxy Server",
May 2004 http://www.samag.com/documents/s=9142/sam0405c/),
I described how to set up and run the OpenLDAP Proxy Server. In
this article, I will present another backend I have found very handy
and flexible. Unfortunately, the OpenLDAP project has one weakness
-- the documentation is a little lacking. With incomplete documentation,
people run into trouble using software, even if it is high quality.
I hope to help lower the learning curve a bit so that readers can
take full advantage of this high-performing and versatile software
without losing too much time.
To begin, I will show you a rough schema of the overall architecture
of OpenLDAP. Some of this information was presented in my previous
article, but an understanding of the architecture is important for
our purposes here. As usual, all examples and code used in this
article are available at the Sys Admin Web site: http://www.sysadminmag.com/code/.
The OpenLDAP Architecture
The OpenLDAP server can be considered as consisting of two big
blocks: a frontend speaking the LDAP protocol with the clients,
and a backend actually providing the data (Figure 1). This is a
very rough view; in reality, there are many more components working
hand in hand. For our purposes, however, this picture works quite
well. I stated that the backend provides the data without telling
you from where; this was intentional. The LDAP protocol specifies
nothing about how the data has to be held. The OpenLDAP server leaves
this up to you, giving you the choice between different backends.
OpenLDAP already ships with a number of different backends. When
you compile the OpenLDAP server, you decide which backend(s) you
will use. The backend must be compiled into the server in order
to be used. You can use more than one backend in parallel. Each
backend then serves a different partition of the LDAP database.
Figure 2 shows the OpenLDAP server backend with different backends.
I assume here that the reader has a basic understanding of LDAP.
You can find more on the LDAP protocol in The ABC's of LDAP
[2] as well as other books on this subject.
The most frequently used backends are those that store the data
in embedded relational databases. The backend uses the API of the
embedded RDBMS; therefore, the database software must be installed
on the same machine. Frequently used embedded RDBMS are the Berkeley
DB distributed as open source software from SleepyCat [3], or GDBM
also available as open source software from the Free Software Foundation
[4]. There are also other backends, such as the proxy backend I
described in my previous article [5]. The proxy backend accesses
another LDAP server upon client request and sends the result back
to the client.
The Perl backend is very flexible; it allows you to execute Perl
code on behalf of client requests. This enables you to get data
from nearly every resource you need. You could store the data, for
example, on the file system. You could contact a different LDAP
server, you could get the data from an Oracle database, or you could
mix these three methods. You could use the OpenLDAP server with
a custom Perl Backend to easily give your application a standard
LDAP interface. The frontend of your custom OpenLDAP server speaks
the LDAP protocol; meanwhile, the Perl LDAP backend accesses data
in your application. This is a quick and economic way to "LDAP-enable"
existing applications without touching the application logic in
any way.
The Perl Backend
The LDAP protocol is a message-oriented protocol. A client sends
a request to the server and the server answers with a message indicating
whether it did what the client wanted and eventually sends the requested
data, or the server informs the client of the failure and returns
an error code. The LDAP protocol knows the following operations:
- Interrogation Operations: search, compare
- Update Operations: add, delete, modifyDN, modify
- Authentication and Control Operations: bind, unbind, abandon
These operations are mapped by the Perl backend to a Perl object.
The OpenLDAP uses further operations for internal purposes, such
as the initialization and the configuration of the backend. These
operations also have to be implemented in the object; in a moment,
we will see how. In reality, all operations are first mapped to
C functions; these C functions work as wrappers around calls to
Perl. The wrappers use the Perl C API to call Perl code. I will
cover this more in the section "Embedding Perl in C". Not all operations
are mapped to Perl code. The unbind and abandon operations are actually
mapped onto null pointers. Some initialization operations are implemented
in C without involving Perl.
The Perl Object must be located into a Perl Module; let's call
it PerlBackend.pm. The methods of the object must correspond to
the previously mentioned operations. When OpenLDAP starts up, it
initializes the Perl backend. During its initialization phase, the
Perl backend calls the object constructor followed by a call to
the object methods init() to allow further object setup and
configure() to read in the configuration parameters from
the configuration file. After the Perl backend is loaded, the object
methods are ready to use.
Embedding Perl in C
I won't explain here how to embed Perl in C -- that could fill
an entire book. But I will give you a little overview. If you want
to dig deeper into this subject, take a look at the man pages of
Perl [6] or at one of these books: Advanced Perl Programming
[7] for embedding Perl in C and Extending and Embedding Perl
[8] for a detailed look into the Perl Internals.
Using Perl from C means using its C API. Your C program must make
calls to the internal functions and Macros as documented in the
Perl manual pages. Once you have written the program, you must compile
it using the Perl header files and the Perl library. You need a
full Perl installation on your machine to do so. You also need to
compile and link your program exactly the same way you compiled
and linked Perl itself; otherwise, the compilation will fail or
you will get fatal errors at run time. Perl provides a utility that
outputs the exact compiler and link loader flags.
All variables passed to Perl are passed via the Perl stack. This
means that the variables to be passed to a Perl procedure are pushed
onto the stack; meanwhile, the variables you wish to get back are
popped from the stack. You have to remember that the stack is used
as FIFO, which means you get the values out in the opposite order
you put them in. Also note that using the stack is exactly how Perl
internally passes variables between subroutines and their callers.
One thing I would like to warn you about is "dynamic loadable
C modules". The problem arises if you use modules that are written
in C within your Perl object. If you use modules that use C in your
embedded Perl code, the interpreter may not know how to load dynamic
libraries, and you may run into trouble. Perl as usual, however,
helps you out of this situation. The same utility that provides
hints about compiler or loader switches can also generate C code
to help you bind the needed dynamic modules correctly into your
program. We will see the Perl utility a little bit later.
That's all I wanted to tell you about embedding Perl in C; I recommend
referring to the Perl man pages if you need more information. The
following man pages particularly are of interest: "perlembed", "percall",
"perlapi", and "perlguts".
The Module: PerlBackend.pm
Now let's look at an example implementation of the backend Perl
object. I will show you an object that does nothing; from this,
you can build up the actions you need (see Listing 1). The new method
constructs the object. Here you can declare all the data that your
object will handle; however, this is more of a help for documenting
the object because you can add new data without problems later.
You could also give the object a pointer to an empty array:
my $this = {} ;
The init() method allows you to initialize the object -- you
may have a further configuration file you can read in or you can get
these details from a connection via TCP or a database or whatever
you want. The config() method gets its information from the
configuration file. Listing 2 shows the part of the configuration
file responsible for the Perl backend. The method is called once for
every line, so the first call is config("host","authentication1.LdapAbc.org"),
the second config("port", 329), and so on.
The bind() method is the one that allows you to authenticate
the user. Listing 3 shows an example of how this information is
used to authenticate against another LDAP server. You could also
connect to a RDBMS or to a Radius server using the user credentials
that the bind() method gets as its arguments. The host and
port numbers are stored in the object created at the startup of
the LDAP server and read from its configuration file. Here you see
also how the init() method is used to preload the connection
to the LDAP server against which the authentication is made.
Compilation and Configuration of OpenLDAP
Now that I've shown how easy it is to use the Perl backend, let's
look at how we get the OpenLDAP server in place. To begin, download
the source code from the home page of OpenLDAP [1]. Uncompress it
in your working directory. The makefiles must now be built in order
to reflect your local environment. You must make sure to get the
correct locations of the include files and libraries of your Perl
distribution. As I mentioned previously, Perl can help you do this.
Here the utility Perl gives you a hand in getting the locations.
The following:
perl -MExtUtils::Embed -ccopts
prints out the compiler options that have been used to compile Perl,
and:
perl -MExtUtils::Embed -ldopts
prints out the link loader options. Now you need the instruction of
how to add dynamic loadable Perl modules, which themselves use C libraries.
Again, Perl itself produces the correct code with the instruction:
perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
Now, let's look at how to produce makefiles for your environment.
This is achieved with the configure utility delivered with
the OpenLDAP distribution. This utility is self-explaining using the
-h switch, for example:
./configure -h
Here is the configure script I used on my machine to produce the makefiles:
CC=gcc \
./configure --disable-ldbm \
--disable-bdb \
--with-threads=no \
--enable-perl \
--prefix=/usr/local/LdapPerl
This should produce all you need. Check the makefiles created, however,
to see whether they contain the correct compiler switches for Perl.
It may be that the executable continues to produce core dumps. This
is a sign that you should also compile the Perl distribution on your
platform and use this freshly compiled Perl environment for your OpenLDAP
Perl backend.
Once you have produced the makefiles, you must execute a make
depend to resolve all dependencies. After that, launch a make,
followed by a make install. Your OpenLDAP distribution will
then be installed under the directory configured with the --prefix
switch. Now you can begin to configure your OpenLDAP installation.
Edit the slapd.conf file as described in the "Administration Manual"
contained in the OpenLDAP distribution. Now, we'll take a look at
the options necessary for the Perl backend. You must start the Perl
section by stating that Perl is your database for the backend. This
is done in line 1. Then you need to define the root of the LDAP
tree the Perl backend is serving. You do this with the suffix instruction
in line 2. The next two lines define the directory in which the
Perl module containing the Perl object lives and define the name
of this module. Then you're done. The remaining two lines define
parameters needed by the Perl module. Here you can define as many
parameters as your Perl object needs. After this, you are ready
to write the Perl object and finally use it. Have fun!
Limitations of the Perl Backend and a Brief Look at the New
Version
The most critical limitation of this version is that a lot of
data on the OpenLDAP server is not available in the Perl object.
This data is contained in a number of structures and is transferred
from the frontend to the backend. Once arrived in the backend, it
can be used by the single backends available in OpenLDAP. Consequently,
because the Perl backend has no data describing the actual connection,
it cannot handle sessions. It can, however, handle simple connections
in a handle-and-forget way.
The OpenLDAP frontend, however, identifies sessions internally
by an integer value. Work is actually underway to modify the Perl
backend architecture to add the ability to exchange more data structures
between C and Perl. Let's take a brief look at the new Perl objects
implementing the data structures that should be handled:
Backend -- This structure contains data about the Perl backend
itself. It also provides pointers to the functions implemented in
Perl. The function pointers used in the C part of the backend are
mapped onto the methods of the PerlBackend object.
ConnectionPool -- This structure contains pointers to all connections
known by the OpenLDAP server. It also has the capability to implement
a connection administration policy. For example, if you decide to
drop connections depending on certain conditions or if a connection
has been idle for too long, you can close it -- assuming the connection
has been left open after an error condition on the client application.
Or you can close connections that have used too many resources.
Connection, from C to Perl -- This structure contains data about
the actual request, such as information about the time the connection
was opened, the time of the last activity, details about the used
protocol, such as TCP or UDP, SASL, TLS, authorization and authentication
details, and similar data. The structure in C is mapped onto a Perl
object. The methods in the Perl object are accessors to the data
mapped onto private data in the Perl object.
SlapReply, from Perl to C -- This structure contains the results
and all the interesting details traveling back to the client. The
structure in C is mapped onto a Perl object. The methods in the
Perl object are accessors to the data mapped onto private data in
the Perl object.
Trouble also could arise if you use multithreading. For the time
being, the Perl backend does not support multithreading, so it is
safer to add the --with-threads=no switch to the configure
option. These data structures will be mapped directly to Perl objects.
Figure 3 shows the new architecture. This method of mapping C structs
to Perl is not easy to implement for the C programmer, but once
available, it provides an environment that should be familiar to
the Perl programmer.
Conclusion
The OpenLDAP server is high-performing, standardized, and economic
software. From its first release as University of Michigan (UMich)
LDAP server to its actual implementation, it has matured into a
product that not only is of academic importance but has proved to
possess all the characteristics needed for use in a production environment.
The OpenLDAP implementation however distinguishes itself from
all other implementation because it is the only one that offers
a family of servers, not just an LDAP server. You get an replication
server, a proxy LDAP server, an LDAP server able to access directly
a RDBMS, a metadirectory, an LDAP server able to convert the LDAP
protocol to Perl, etc., etc., and last but not least, an LDAP server.
If this is not enough, you are free to implement a brand new backend
to suit whatever needs you have.
In this article, I have shown the actual implementation of the
Perl backend. What is the big advantage the Perl backend offers
to you? Clearly, you can achieve exactly the same things if you
program in C. But can you really? Perl is a programming language
that allows rapid prototyping. Once you have a working product,
you can decide whether you should port your programs to C. Perl
offers a lot of libraries, all of them ready to use for many purposes.
It has modules for Oracle, LDAP, various DBMS, Radius, Excel, and
much more. Furthermore, you can access Perl via your own application;
I don't know any LDAP server implementation that can do this.
An interesting application of the Perl backend could be also one
that is CORBA enabled; please let me know if you are playing around
with such stuff. Also, if you are interested in the next steps of
the Perl backend, check out the home page of the OpenLDAP Perl Backend
project [9].
Resources
1. OpenLDAP Home Page -- http://www.openldap.org
2. Voglmaier, Reinhard E. 2003. The ABC's of LDAP. Auerbach
Publications.
3. SleepyCat Distribution -- http://www.sleepycat.com
4. Free Software Foundation -- http://www.fsf.org
5. Voglmaier, Reinhard E. "The OpenLDAP Proxy Server," Sys
Admin 13(5):18-22.
6. Perl Man Pages -- http://cpan.perl.org
7. Srinivasam, Sriram. 1997. Advanced Perl Programming.
O'Reilly & Associates.
8. Jenness, Tim, and Simon Cozens. 2002. Extending and Embedding
Perl. Manning.
9. Perl Backend Home Page -- http://sourceforge.com/PerlBackend
Reinhard Voglmaier studied physics at the University of Munich
in Germany and graduated from Max Planck Institute for Astrophysics
and Extraterrestrial Physics in Munich. After working in the IT
department at the German University of the Army in the field of
computer architecture, he was employed as a Specialist for Automation
in Honeywell and then as a Unix Systems Specialist for performance
questions in database/network installations in Siemens Nixdorf.
Currently, he is responsible of LDAP Services at GlaxoSmithKline,
Italy. He's also the author of The ABC's of LDAP (Auerbach
Pub, November 2003). He can be reached at Reinhard.E.Voglmaier@gsk.com. |