15
1 Interactive LDAP in C/C++ Interpreter Joshua Liu ([email protected]) Harry H. Cheng ([email protected]) Integration Engineering Laboratory Department of Mechanical and Aeronautical Engineering University of California One Shields Avenue Davis, CA 95616 Abstract This article describes how to use the Lightweight Directory Access Protocol (LDAP) interactively with a C/C++ interpreter through the Ch LDAP package. Ch is an embeddable C/C++ interpreter that provides a superset of C. Ch LDAP is an open source binding to the open source OpenLDAP C API, and can be used to build client LDAP programs to add, delete, modify, and search entries in a X.500 directory service. These client programs can then be used directly for Ch CGI programming to LDAP directory service operations across the Internet. Using Ch and Ch LDAP, both are freely available for downloading on the Internet, LDAP programs can be developed quickly, executed without compilation, and used readily for CGI programming. Applications of the open source Ch LDAP will be presented in this article. 1 Introduction LDAP stands for Lightweight Directory Access Protocol. A directory in LDAP is a specialized database designed for fast queries and high volume lookups [1]. It consists of entries that can contain a number of different attributes, each of which can be used to filter searches. LDAP is a directory access protocol to a X.500 directory service [1]. The X.500 directory service was created with large complex organizations in mind and is itself also large and complicated [2]. OpenLDAP is an open source implementation of the lightweight version of this directory protocol. In the January 2002 issue of the Linux Magazine, the Guru Guidance column finished its three part series on OpenLDAP. It covered configuring the server daemon, encryption, authentication, and setting up a LDAP database [3,4,5]. Now that OpenLDAP is up and running, this article will address the issues of writing LDAP client programs using the OpenLDAP C API, interactively in a C/C++ interpreter, as well as through web based applications. Writing programs using the OpenLDAP C APIs allows the administrator to create custom executables with which to modify, add, delete, and search entries of a X.500

Interactive LDAP in C/C++ Interpreter - Tech Communityhosteddocs.ittoolbox.com/InteractiveLDAP.pdf · LDAP stands for Lightweight Directory Access Protocol. A directory in LDAP is

  • Upload
    lamcong

  • View
    242

  • Download
    0

Embed Size (px)

Citation preview

1

Interactive LDAP in C/C++ Interpreter

Joshua Liu ([email protected]) Harry H. Cheng ([email protected])

Integration Engineering Laboratory Department of Mechanical and Aeronautical Engineering

University of California One Shields Avenue

Davis, CA 95616

Abstract

This article describes how to use the Lightweight Directory Access Protocol (LDAP) interactively with a C/C++ interpreter through the Ch LDAP package. Ch is an embeddable C/C++ interpreter that provides a superset of C. Ch LDAP is an open source binding to the open source OpenLDAP C API, and can be used to build client LDAP programs to add, delete, modify, and search entries in a X.500 directory service. These client programs can then be used directly for Ch CGI programming to LDAP directory service operations across the Internet. Using Ch and Ch LDAP, both are freely available for downloading on the Internet, LDAP programs can be developed quickly, executed without compilation, and used readily for CGI programming. Applications of the open source Ch LDAP will be presented in this article.

1 Introduction

LDAP stands for Lightweight Directory Access Protocol. A directory in LDAP is a specialized database designed for fast queries and high volume lookups [1]. It consists of entries that can contain a number of different attributes, each of which can be used to filter searches. LDAP is a directory access protocol to a X.500 directory service [1]. The X.500 directory service was created with large complex organizations in mind and is itself also large and complicated [2]. OpenLDAP is an open source implementation of the lightweight version of this directory protocol.

In the January 2002 issue of the Linux Magazine, the Guru Guidance column finished its three part series on OpenLDAP. It covered configuring the server daemon, encryption, authentication, and setting up a LDAP database [3,4,5]. Now that OpenLDAP is up and running, this article will address the issues of writing LDAP client programs using the OpenLDAP C API, interactively in a C/C++ interpreter, as well as through web based applications.

Writing programs using the OpenLDAP C APIs allows the administrator to create custom executables with which to modify, add, delete, and search entries of a X.500

2

directory service. To create these program quickly and efficiently, Ch (an embeddable C/C++ interpreter) and Ch LDAP (a Ch binding to the OpenLDAP C library) can be used. By using an interpreter, applications can be developed rapidly without the tedious compile/link/execute/debug cycles.

The Ch LDAP package is interactive, capable of interfacing with binary, static or dynamic C/C++ libraries, and embeddable in other applications. It is especially suitable for rapid prototyping and web-based applications. Applications of Ch LDAP including web-based directory operations are presented in this article with examples. 2 Interpretive LDAP in Ch Ch is a C/C++ interpreter that is designed for cross platform scripting, shell programming, 2D/3D plotting, numerical computing, and embedded scripting. It conforms to the ISO C standard with salient extensions [6]. Ch is freely available for downloading on the internet. Some of Ch’s salient features are listed as follows:

High Level Language: Ch bridges the gap between low and high level languages. Ch retains low-level features of C such as accessing memory for hardware interfaces, but Ch is also a high-level language environment with classes, strings, computational arrays, and shell programming.

Object Based: Ch supports classes, objects and encapsulation in C++ for object-oriented programming.

Cross Platform Shell: Ch acts as a universal shell that can be used as a login shell, similar to Bourne, Bash, tcsh, as well as MS-DOS shell in Windows.

Platform Independent: A Ch program can run in an heterogeneous computing environment with different hardware and operating systems, including Windows, Linux, Mac OSX, and UNIX. Ch programs can be developed on one machine and then deployed on all platforms supported by Ch.

Web Enabled: The CGI development module for Web servers allows Ch programs to be readily used in Web programming. Ch allows rapid development and deployment for Web based applications and services. Ch applets can be executed across a network on different platforms on the fly. Most importantly, Ch can leverage a large body of existing C programs [7]. Ch enables C/C++ language programmers to implement almost any programming task in one language and run it in any platform.

Ch LDAP is a Ch binding to OpenLDAP. The open source Ch LDAP package includes the OpenLDAP header files, Ch function files, Ch LDAP dynamically loaded library, as well as all the files and utilities used to create Ch LDAP. This package allows users to execute OpenLDAP programs interactively in Ch without compilation. The Ch LDAP package contains the following files chldap/ demos: OpenLDAP demos in C, ready to run in Ch dl: dynamically loaded libraries include: header files lib: .chf function files src: development files and utilities used to build Ch LDAP

3

2.1 Installing and Setting up Ch and Ch LDAP Ch can be freely downloaded from http://www.softintegration.com. The directory

where Ch is installed is referred to as <CHHOME>. Ch LDAP can be downloaded at http://chldap.sourceforge.net. Uncompress the package and move the directory /chldap to <CHHOME>/package/chldap, which will now be the home directory of Ch LDAP and referred to as <CHLDAP>.

To run the demos, startup Ch and go to <CHLDAP>/demos and open any of the demo programs. Modify the ldap_host, root_dn, root_pw, and base variables to match your slapd.conf file. After you have finished modifying the demo files, type the program name, for example “./ldap_search.c”, on the command line to execute it. Be sure to have the LDAP server, slapd, running so Ch can communicate with it. 2.2 Application Example The following program uses many of the OpenLDAP C API functions to perform a search of a LDAP directory service. The detailed man pages of all the API functions can be found at http://www.openldap.org. This demo program, ldap_search.c, is shown in Listing 1 and is located in the /demos directory of the Ch LDAP package. This program begins by initializing a set of variables that are needed to contact the server. The LDAP object is a structure that contains the session information. The variable auth_method is set to LDAP_AUTH_SIMPLE, indicating that simple authentication is to be used, rather than Kerberos or SASL. Next, root_dn is set to “cn=Manager, dc=example, dc=com” and root_pw to “secret”, but you will want to set these two variables to match the entries in your slapd.conf file. Now the search base and search filter need to be defined. The variable base refers to the base distinguished name (or base DN) on which to search, and filter is the search filter that the results will be filtered through. In this example, the search is performed on "dc=example, dc=com" and by setting filter equal to "(objectClass=*)" every entry in the base DN is returned [2]. The function ldap_init opens a connection to a LDAP server on "localhost". The constant LDAP_PORT is equal to 389, which is the default LDAP port. The function ldap_bind_s now binds, passing the root DN and password to the server and authenticating using simple authentication. The synchronous search function ldap_search_s will be used to begin our search of the directory. This function begins searching at the base DN and returns all matches to the filter, which in this case is every entry in the directory. If the search is successful, it will return a LDAPMessage object for each matching entry. To access the entries, the ldap_first_entry function is used to retrieve the first entry and then ldap_next_entry is used to get each subsequent entry. To access the attributes of the entries, the function ldap_first_attribute is used to find the first attribute and then ldap_next_attribute is called to acquire the following attributes. To actually view the attributes of the entry, the function ldap_get_values will need to be called which will return an array of values that can now be read [1]. After the search is complete and the entries returned, a final series of functions are called to free up the allocated memory. The program can then unbind from the server and exit. The output of this program is shown in Figure 1. It is executed without compilation in Ch shell by simply typing in the filename on the command prompt.

4

Figure 1. Running ldap_search.c in Ch Shell.

3 Web-Based Ch LDAP through CGI Typically CGI programs written in C have to be compiled, which makes them difficult to modify and maintain. But with Ch, existing C code can be used directly as a CGI program. With only a few minor modifications, the existing C code can be readily used for CGI programming, allowing the LDAP directory to be open to searches performed over the Internet.

The Ch CGI toolkit can be downloaded from www.softintegration.com. Install Ch CGI and configure your web server according to the installation instructions. After the configuration is complete, start up your web server and run some of the demos located in /var/www/html/chhtml/toolkit/demos/cgi/sample/. The home directory of the web server is located in /var/www so make a copy of your .chrc file from your home directory and copy it to /var/www. To run the Ch LDAP CGI demo program, copy ldap_search.html and ldap_search.ch from <CHHOME>/package/chldap/demos/CGI to /var/www/html/ and /var/www/cgi-bin/, respectively. You can now open ldap_search.html in your favorite browser and run a search on your LDAP directory.

5

3.1 CGI Application Examples Two examples for web-based LDAP in Ch LDAP will be presented in this

section. In the first example, the source code for the user interface in Figure 2, ldap_search.html, is shown in Listing 2. The interface uses the method POST to take in the contents of the form entries and sends them to the server. The entry in ACTION lets the server know where the program ldap_search.ch is located. The values entered in the entries “base DN” and “filter” are assigned to the variables base and filter, respectively. The web page, ldap_search.html, with the default entry values filled in can be seen in Figure 2.

6

Figure 2. User interface for LDAP directory search: ldap_search.html.

The Ch CGI program, ldap_search.ch, is shown in Listing 3. The demo C

program, ldap_search.c, and the demo CGI program, ldap_search.ch, differ in a few small ways. To indicate that ldap_search.ch is a script, the first line of the program starts with shebang #!/bin/ch. The header file #include <cgi.h>, which contains the CRequest and CResponse classes, similar to ones in ASP and JSP, is also added to the list of header files [7].

The CRequest class is used to retrieve values from ldap_search.html and is used as follows: class CRequest Request; ... char* base = Request.getForm("base"); char* filter = Request.getForm("filter"); ...

7

In ldap_search.ch, the value base is the value of the base DN entry and the value filter is the value of the filter entry filled out in the ldap_search.html form. The CResponse class is used to generate the HTML code to display the output, which in this case, are the search results. This class is used in ldap_search.ch as follows: class CResponse Response; ... Response.begin(); Response.title("OpenLDAP"); ... printf("<BR>"); printf("Returned dn: %s\n", dn); printf("<BR>"); ... Response.end(); ...

The HTML code generated is used to create the search results page in which all the matching entries of the directory will be printed out. The resulting page from running the

CGI script ldap_search.ch is displayed in Figure 3, and shows the same results as the search performed by the standalone C program ldap_search.c.

8

Figure 3. Results from running CGI program ldap_search.ch.

The second example of a web-based application using Ch LDAP deals with

graphical plotting. As an administrator of an LDAP directory service, it is helpful to have statistics available for review. Ch allows the generation of dynamic plots for visual

analysis over the web. As an example, a web plot of the number of searches performed over a period of one month is shown in Figure 4. The source code for ldap_plot.ch is

available at http://chldap.sourceforge.net.

9

Figure 4. Web plot generated by CGI program ldap_plot.ch.

When creating a CGI program it is often necessary to debug the code. A Ch CGI program with the –g option after the command #!/bin/ch, turns the web browser into a text window where errors are outputted [7]. This allows developers to quickly identify errors in program code and correct them efficiently. 4 Conclusions Ch and Ch LDAP, freely available for downloading from the internet, have been introduced in this article. Ch provides a powerful environment for interactive application development. By using the Ch LDAP package, cross platform client programs can be developed quickly to interact with LDAP directory services. Ch allows C OpenLDAP programs to be readily used as CGI programs for adding, deleting, modifying and searching entries of an LDAP directory service across the Internet. These CGI programs are easy to develop and maintain for web-based applications.

10

References

1. Howes, Timothy. “The Lightweight Directory Access Protocol: X.500 Lite.” CITI Technical Report 95-8. July 1995. http://www.openldap.org

2. OpenLDAP 2.1 Administrator’s Guide: http://www.openldap.org 3. Frisch, AEleen. “Exploring LDAP – Part I.” Linux Magazine January 2002

4. Frisch, AEleen. “Exploring LDAP – Part II.” Linux Magazine February 2002

5. Frisch, AEleen. “Exploring LDAP – Part III.” Linux Magazine March 2002

6. Cheng, Harry. The Ch Language Environment User’s Guide. SoftIntegration, Inc.,

2002. http://www.softintegration.com. 7. SoftIntegration, Inc. The Ch Language Environment CGI Toolkit User’s Guide.

Also see http://www.softintegration.com/products/toolkit/cgi/. 8. Ch LDAP homepage: http://chldap.sourceforge.net

11

Listing 1 . OpenLDAP C client directory search program: ldap_search.c.

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <lber.h> #include <ldap.h> int main( int argc, char *argv[] ) { LDAP *ld; int auth_method = LDAP_AUTH_SIMPLE; int desired_version = LDAP_VERSION3; char *ldap_host = "localhost"; char *root_dn = "cn=Manager, dc=example, dc=com"; char *root_pw = "secret"; char* base="dc=example,dc=com"; char* filter="(objectClass=*)"; char* errstring; char* dn = NULL; char* attr; char** vals; int i; int result; BerElement* ber; LDAPMessage* msg; LDAPMessage* entry; //initialize LDAP library and open connection if ((ld = ldap_init(ldap_host, LDAP_PORT)) == NULL ) { perror( "ldap_init failed" ); exit( EXIT_FAILURE ); } //set protocol version if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) != LDAP_OPT_SUCCESS) { ldap_perror(ld, "ldap_set_option"); exit(EXIT_FAILURE); } //create LDAP bind if (ldap_bind_s(ld, root_dn, root_pw, auth_method) != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_bind" ); exit( EXIT_FAILURE ); } //perform directory search if (ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, filter, NULL, 0, &msg) != LDAP_SUCCESS) { ldap_perror( ld, "ldap_search_s" ); exit(EXIT_FAILURE); } printf("The number of entries returned was %d\n\n", ldap_count_entries(ld, msg)); //iterate through returned entries for( entry = ldap_first_entry(ld, msg);entry != NULL; entry = ldap_next_entry(ld,entry)) { if((dn = ldap_get_dn(ld, entry)) != NULL) { printf("Returned dn: %s\n", dn); ldap_memfree(dn); } for( attr = ldap_first_attribute(ld, entry, &ber); attr != NULL; attr = ldap_next_attribute(ld, entry, ber)) { if ((vals = ldap_get_values(ld, entry, attr)) != NULL) { for(i = 0; vals[i] != NULL; i++) { printf("%s: %s\n", attr, vals[i]); } ldap_value_free(vals);

12

} ldap_memfree(attr); } if (ber != NULL) { ber_free(ber,0); } printf("\n"); } ldap_msgfree(msg); result = ldap_unbind_s(ld); if (result != 0) { fprintf(stderr, "ldap_unbind_s: %s\n", ldap_err2string(result)); exit( EXIT_FAILURE ); } return EXIT_SUCCESS; }

13

Listing 2. HTML OpenLDAP directory search user interface: ldap_search.html.

<! Created by Joshua Liu, 11/1/03> <HTML><HEAD> <TITLE> Ch LDAP CGI Web Search </TITLE> <body bgcolor="#FFFFFF" text="#000000" vlink="#FF0000"> </HEAD><BODY> <H1> Ch LDAP directory search </H1> <HR><PRE> <FORM METHOD="POST" ACTION="/cgi-bin/ldap_search.ch"> base DN: <INPUT NAME="base" VALUE="dc=example,dc=com" SIZE="40"> filter: <INPUT NAME="filter" VALUE="(objectClass=*)" SIZE="40"> <INPUT TYPE=submit VALUE="Search"> <INPUT TYPE=reset VALUE="reset"> </FORM> </PRE> <p> <HR> </BODY> </HTML>

14

Listing 3. Ch CGI OpenLDAP directory search program: ldap_search.ch.

#!/bin/ch #include <cgi.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <lber.h> #include <ldap.h>

int main() { class CRequest Request; class CResponse Response; LDAP *ld; char* base = Request.getForm("base"); char* filter = Request.getForm("filter"); int auth_method = LDAP_AUTH_SIMPLE; int desired_version = LDAP_VERSION3; char *ldap_host = "localhost"; char *root_dn = "cn=Manager, dc=example, dc=com"; char *root_pw = "secret"; char* errstring; char* dn = NULL; char* attr; char** vals; int i; int result; BerElement* ber; LDAPMessage* msg; LDAPMessage* entry; Response.begin(); Response.title("OpenLDAP"); //initialize LDAP library and open connection if ((ld = ldap_init(ldap_host, LDAP_PORT)) == NULL ) { perror( "ldap_init failed" ); exit( EXIT_FAILURE ); } //set protocol version if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) != LDAP_OPT_SUCCESS) { ldap_perror(ld, "ldap_set_option"); exit(EXIT_FAILURE); } //create LDAP bind if (ldap_bind_s(ld, root_dn, root_pw, auth_method) != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_bind" ); exit( EXIT_FAILURE ); } //perform directory search if (ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, filter, NULL, 0, &msg) != LDAP_SUCCESS) { ldap_perror( ld, "ldap_search_s" ); exit(EXIT_FAILURE); } printf("Search results"); printf("<BR>"); //iterate through returned entries for(entry = ldap_first_entry(ld, msg); entry != NULL; entry = ldap_next_entry(ld, entry)) { if((dn = ldap_get_dn(ld, entry)) != NULL) { printf("<BR>"); printf("Returned dn: %s\n", dn); printf("<BR>"); ldap_memfree(dn); } for( attr = ldap_first_attribute(ld, entry, &ber);attr != NULL;attr = ldap_next_attribute(ld,

15

entry, ber)) { if ((vals = ldap_get_values(ld, entry, attr)) != NULL) { for(i = 0; vals[i] != NULL; i++) { printf("%s: %s\n", attr, vals[i]); printf("<BR>"); } ldap_value_free(vals); } ldap_memfree(attr); } if (ber != NULL) { ber_free(ber,0); } printf("\n"); } Response.end(); ldap_msgfree(msg); result = ldap_unbind_s(ld); if (result != 0) { fprintf(stderr, "ldap_unbind_s: %s\n", ldap_err2string(result)); exit( EXIT_FAILURE ); } return EXIT_SUCCESS; }