Example 1: A Directory-Enabled finger Service

   

Example 1: A Directory-Enabled finger Service

A finger service is a simple client/server account lookup mechanism supported by all Unix operating systems. A finger client exists for most desktop operating systems, including all flavors of Unix, Microsoft Windows, and Apple MacOS. A finger server, included with all Unix systems, can return information about local accounts to all finger clients on the network (finger servers have been developed for non-Unix systems as well). The finger clients and servers communicate using a simple text-based protocol that was originally developed by the BSD Unix developers in the 1980s.

Assuming that many end users have access to a finger client and know how to use it, it's sensible to make some of the people information stored in a directory service available via finger. This section presents source code and usage examples for a directory-enabled finger server written in Perl. The directory-enabled finger service searches an LDAP directory and returns information about people.

The Integration Approach

The goal is to leverage the knowledge and client software that users already have, so a gateway is used to integrate finger with LDAP. On most Unix systems, an executable called in.fingerd is executed in response to incoming finger protocol requests . Replacing that executable with a script that understands the finger protocol but uses LDAP to retrieve information establishes compatibility with existing clients. This is an example of bringing the directory service to your users; no new client software needs to be installed for people to access the directory via the finger gateway.

The LDAP finger gateway is a standalone executable; it does not execute within the confines of an existing application. Therefore, nearly any programming language that provides access to LDAP could be used. The gateway example is written in the Perl 5 language, and it uses the PerLDAP object-oriented LDAP access module available from the Mozilla Web site at http://mozilla.org/directory/perldap. This choice allows rapid prototyping, provides maximum portability for the code, and performs acceptably. The lfingerd.pl script replaces the standard in.fingerd binary program executed by Unix's inetd process, which is responsible for managing the execution of a variety of TCP/IP services.

Directory Use

The lfingerd.pl gateway uses a directory service in a simple way. The LDAP service is accessed anonymously; that is, without authentication. Given a query string that is sent by the finger client, a search for user entries is performed with a filter that includes an (objectClass=person) component. Each entry returned by the LDAP search is printed in a format that is familiar to finger users.

Along with contact information such as name and telephone number, the lfingerd.pl gateway retrieves status information for AOL Instant Messenger (AIM) users. This feature relies on Netscape Directory Server 6, which allows retrieval of instant messaging online/offline status over LDAP for person entries that include appropriate attributes. Listing 22.1 shows a sample entry that includes an AIM ID.

Listing 22.1 An Entry That Includes an AIM ID
 dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen sn: Jensen givenName: Barbara objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson  objectClass: nsAIMPresence  ou: Product Development ou: People L: Cupertino uid: bjensen mail: bjensen@example.com telephoneNumber: +1 408 555 1862 facsimileTelephoneNumber: +1 408 555 1992 roomNumber: 0209 userPassword: hifalutin  nsAIMID:Babs Jensen  

The AIM- related attributes and values are shown in bold type. nsAIMPresence is an auxiliary object class that allows these three attribute types:

  1. nsAIMID . An AIM identifier; also known as a screen name (syntax DirectoryString ).

  2. nsAIMStatusText . An enumerated text attribute that indicates the user's online or offline status. It has one of these values: ONLINE , OFFLINE , ERROR (syntax DirectoryString ).

  3. nsAIMStatusGraphic . A GIF image that reflects the user's status in a graphical way (syntax OctetString ).

In Netscape Directory Server 6, the nsAIMStatusText and nsAIMStatusGraphic attributes are virtual, operational attributes. Recall from Chapter 2, Introduction to LDAP, that operational attributes must be retrieved by name when an LDAP search operation is used to retrieve them. The nsAIMStatusText and nsAIMStatusGraphic attributes are also virtual , which means the attribute values are not stored in the directory server's database on disk but instead are computed on demand. For these two attributes, the values are computed by a Presence plug-in that is bundled with Netscape Directory Server 6. The Presence plug-in connects to AOL's AIM service to compute the correct nsAIMStatusText and nsAIMStatusGraphic values for each entry returned by an LDAP search operation.

The lfingerd.pl gateway avoids reading unnecessary attributes from the user entries. The additional load placed on the directory service may be estimated directly on the basis of the expected use of the finger gateway. There are no other significant directory architecture issues to consider for this application.

The End-User Experience

Listing 22.2 shows a finger command (in bold type), along with the output produced by a standard, non-LDAP-enabled Unix finger service.

Listing 22.2 A Non-LDAP-Enabled Unix finger Lookup for dsmith
  finger dsmith@unix.example.com  Login name: dsmith                      In real life: Daniel Smith Directory: /u/dsmith                    Shell: /bin/tcsh On since Jul 14 09:05:10 on console from :0 8 minutes 42 seconds Idle Time No unread mail Project: Human Resources web site Plan: Send me e-mail at dsmith@example.com 

Listing 22.3 shows a lookup using the LDAP directory-enabled finger service. In this case, only one entry matches the query string.

Listing 22.4 shows an LDAP-enabled finger example that returns an entry with more attributes. Babs's entry contains postalAddress and labeledURI attributes, as well as an nsAIMID attribute. Babs is currently logged in to AOL Instant Messenger.

Listing 22.3 An LDAP finger Lookup for smith
  finger smith@example.com  [example.com] Example.Com LDAP Finger Service Login name:  dsmith                           In real life: Daniel Smith E-Mail:      dsmith@example.com               Phone: +1 408 555 9519 Department:  Human Resources                  Room:  0368 One entry matched 'smith' 
Listing 22.4 An LDAP finger Lookup for bjensen
  finger bjensen@example.com  [example.com] Example.Com LDAP Finger Service Login name:  bjensen                          In real life: Barbara Jensen E-Mail:      bjensen@example.com              Phone: +1 408 555 1862 Department:  Product Development              Room:  0209 AIM ID:      Babs Jensen (status: ONLINE) Address:     1234 Main St. $ Mountain View, CA $ 94043 URL:         http://homepages.example.com/bjensen My Home Page One entry matched 'bjensen' 

Listing 22.5 shows one more example. Four entries match the query string "carter"; the finger LDAP gateway returns information about all of them.

Listing 22.5 An LDAP finger Lookup That Returns Multiple Entries
  finger carter@example.com  [example.com] Example.Com LDAP Finger Service Login name:  scarter                          In real life: Sam Carter E-Mail:      scarter@example.com              Phone: +1 408 555 4798 Department:  Accounting                       Room:  4612 AIM ID:      Sam Carter Ex (status: OFFLINE) Login name:  scarte2                          In real life: Stephen Carter E-Mail:      scarte2@example.com              Phone: +1 408 555 6022 Department:  Product Development              Room:  2013 Login name:  kcarter                          In real life: Karen Carter E-Mail:      kcarter@example.com              Phone: +1 408 555 4675 Department:  Human Resources                  Room:  2320 AIM ID:      KarenCarter42 (status: OFFLINE) Login name:  mcarter                          In real life: Mike Carter E-Mail:      mcarter@example.com              Phone: +1 408 555 1846 Department:  Accounting                       Room:  3819 AIM ID:      MikeCarterCPA (status: ONLINE) 4 entries matched 'carter' 

The Source Code

The lfingerd.pl source code consists of a single script, which is presented here in pieces to aid understanding. Listing 22.6 shows the prelude and main module.

Listing 22.6 The lfingerd.pl Prelude and Main Module
 1. #!/usr/local/bin/perl   2. #   3. # lfingerd -- a Perl 5 script that implements the server side   4. #   of the BSD finger protocol using an LDAP server as its   5. #   database of user information. Also returns AIM   6. #   online/offline status if Netscape Directory Server 6 or   7. #   later is used.   8. #   9. # From the 2nd Edition of the book:  10. #   "Understanding and Deploying LDAP Directory Services"  11. #   by Timothy A. Howes, Mark C. Smith, and Gordon S. Good.  12. #  13. # Requires: PerLDAP  14. #  15.  16. use Mozilla::LDAP::Conn;  17.  18. # Banner:  19. $banner = "Example.Com LDAP Finger Service";  20.  21. # LDAP server information:  22. $ldapbase = "dc=example,dc=com";  23. $ldaphost = "ldap.example.com";  24. $ldapport = "389";  25.  26. # Constants:  27. $unknown = "???";  28. $separator = "\n";  29. @attrlist = ( "cn", "uid", "mail", "departmentNumber",  30.     "telephoneNumber", "roomNumber", "postalAddress",  31.     "ou", "title", "displayName", "description",  32.     "labeledURI", "nsAIMID", "nsAIMStatusText" );  33.  34. # Start of main:  35. $ = 1;     # enable autoflush of output upon print  36. print "$banner\n\n";  37. $ = 0;     # disable autoflush  38.  39. # grab query string and chop off newline and return characters  40. $query = <STDIN>;  41. chop $query;  42. if ( $query =~ /\r$/ ) {  43.     chop $query;  44. }  45.  46. # form a filter using the query string  47. if ( $query =~ /.*=.*/ ) {  48.     $filter = "(&(objectClass=person)($query))";  49. } else {  50.     $filter = "(&(objectClass=person)"  51.             . "((sn=$query)(cn=$query)(uid=$query)))";  52. }  53.  54.  55. # open an anonymous connection to the LDAP server  56. $ldap = new Mozilla::LDAP::Conn( $ldaphost, $ldapport );  57. die "Unable to connect to server at "  58.         . "ldap://$ldaphost:$ldapport\n" unless $ldap;  59.  60. # search the directory  61. $entry = $ldap->search( $ldapbase, "subtree", $filter,  62.         0, @attrlist );  63.  64. # display all the results  65. if ( $entry ) {  66.     $count = 0;  67.     do {  68.         displayEntry( $entry );  69.         $entry = $ldap->nextEntry;  70.         ++$count;  71.     } while ( $entry );  72.  73.     if ( $count > 1 ) {  74.         print $count, " entries matched '$query'\n";  75.     } else {  76.         print "One entry matched '$query'\n";  77.     }  78.  79. } else {  80.     print "No entries matched '$query'\n";  81. }  82.  83. # close LDAP connection and clean up  84. $ldap->close;  85.  86. # End of main.  87. 

The following list summarizes the actions performed in Listing 22.6:

  1. The LDAP server information is specified on lines 21 to 24. Constants used elsewhere in the script are defined on lines 26 to 32.

  2. When executed, the main module displays a banner string (defined on line 19 and printed by lines 35 to 37) that lets the user know he has connected to an LDAP finger service.

  3. The query string sent by the client is read and cleaned up. In the finger protocol, the client sends a text query string that is terminated with a newline character and a carriage return. The Perl code on lines 39 to 44 reads the query string from standard input and removes any end-of-line characters (inetd always arranges for protocol data sent by clients to be passed to standard input).

  4. The query string is used to form an LDAP search filter (lines 46 “52). If the query string contains an equal sign, it is assumed to be an LDAP filter component; otherwise a filter that specifies an exact match on sn , cn , or uid is created. In either case, an (objectClass=person) component is included to limit the search results to people entries.

  5. The code on lines 55 to 84 uses PerLDAP calls to connect to the LDAP server, perform a search, and display all of the entries found. No authentication is done; all queries are anonymous.

Listing 22.7 shows the displayEntry subroutine, which is used to produce a nicely formatted entry display. This routine is straightforward. It uses simple printf statements to produce a formatted display of an LDAP entry. The resulting text is sent to standard output, which the Unix inetd process has arranged to be sent back to the finger client.

Listing 22.7 The lfingerd.pl displayEntry Subroutine
 88.  89. # Start of displayEntry:  90. sub  91. displayEntry {  92.     local( $entry ) = @_;  93.     local( $value, @attrs );  94.  95.     @attrs = ( "displayName", "cn" );  96.     printf( "Login name:  %-8s             "  97.             . "            In real life: %s\n",  98.             getSimpleValue( $entry, "uid" ),  99.             getFirstValue( $entry, *attrs )); 100. 101.     printf( "E-Mail:      %-32s Phone: %s\n", 102.             getSimpleValue( $entry, "mail" ), 103.             getSimpleValue( $entry, "telephoneNumber" )); 104. 105.     @attrs = ( "ou", "departmentNumber" ); 106.     printf( "Department:  %-32s Room:  %s\n", 107.             getFirstValue( $entry, *attrs ), 108.             getSimpleValue( $entry, "roomNumber" )); 109. 110.     $value = getSimpleValue( $entry, "nsAIMID" ); 111.     if ( $value ne $unknown ) { 112.         printf( "AIM ID:      %s (status: %s)\n", $value, 113.                 getSimpleValue( $entry, "nsAIMStatusText" )); 114.     } 115. 116.     $value = getSimpleValue( $entry, "postalAddress" ); 117.     if ( $value ne $unknown ) { 118.         print "Address:     $value\n"; 119.     } 120. 121.     $value = getSimpleValue( $entry, "title" ); 122.     if ( $value ne $unknown ) { 123.         print "Title:       $value\n"; 124.     } 125. 126.     $value = getSimpleValue( $entry, "description" ); 127.     if ( $value ne $unknown ) { 128.         print "Description: $value\n"; 129.     } 130. 131.     displayAllValues( $entry, "labeledURI", "URL:         " ); 132. 133.     print $separator; 134. } 135. # End of displayEntry. 136. 

Listing 22.8 shows the code for three subroutines that are called from displayEntry : displayAllValues , getSimpleValue , and getFirstValue . All of these display subroutines access values from an LDAP entry by using PerLDAP's attribute hash array.

Listing 22.8 Additional lfingerd.pl Display Subroutines
 137. 138. # Start of displayAllValues: 139. sub 140. displayAllValues { 141.     local( $entry, $attr, $prefix ) = @_; 142.     local( $value ); 143. 144.     if ( $entry->{$attr} ) { 145.         foreach $value (@{$entry->{$attr}}) { 146.             print $prefix, $value, "\n"; 147.         } 148.     } 149. } 150. # End of displayAllValues. 151. 152. # Start of getSimpleValue: 153. sub 154. getSimpleValue { 155.     local( $entry, $attr ) = @_; 156.     local( $value ); 157. 158.     if ( $entry->{$attr} ) { 159.         $value = $entry->{$attr}[0]; 160.     } else { 161.         $value = $unknown; 162.     } 163. 164.     $value; 165. } 166. # End of getSimpleValue. 167. 168. # Start of getFirstValue: 169. sub 170. getFirstValue { 171.     local( $entry, *attrs ) = @_; 172.     local( $a ); 173.     local( $value ); 174. 175.     $value = $unknown; 176. 177.     foreach $a (@attrs) { 178.         $value = getSimpleValue( $entry, $a ); 179.         last if ( $value ne $unknown ); 180.     } 181. 182.     $value; 183. } 184. # End of getFirstValue. 

Finally, the system's /etc/inetd.conf configuration file must be modified to tell inetd to execute the lfingerd.pl script instead of the standard in.fingerd executable. Listing 22.9 shows the altered portion of the /etc/inetd.conf file used on a Sun Solaris Unix system.

Listing 22.9 Changes to /etc/inetd.conf to Enable the lfingerd.pl Script
 1. #finger stream  tcp  nowait  nobody  /usr/sbin/in.fingerd        in.fingerd 2. finger  stream  tcp  nowait  nobody  /usr/local/etc/lfingerd.pl  lfingerd.pl 

Line 1, which is commented out, is the line originally used to invoke the standard in.fingerd executable. Line 2 is the line that must be added to invoke the new lfingerd.pl Perl script; this line assumes the script is installed in the /usr/local/etc directory. Don't forget to restart the inetd process after making these changes.

Ideas for Improvement

Many things could be done to improve the LDAP finger gateway. Here are some ideas:

  • Sort the entries before displaying them. Sorting would be helpful when more than a few entries are found.

  • Improve the display of special attributes. For example, postalAddress attributes use the dollar sign ( $ ) character as a line separator, but the lfingerd.pl script does not take this into account.

  • Improve the generation of search filters. As written, the script does not examine the query string at all; it just searches for all entries whose surname , full name, or user ID exactly matches the query string. A more intelligent script might examine the query string and generate different filters depending on its content. For example, a query string that consists only of numbers might trigger a search by telephone number.

  • Enhance the lfingerd.pl script to log all finger client connections and queries to a file and consider whether additional measures should be taken to enhance security. Although all access to the directory through the gateway is unauthenticated, lfingerd.pl does open another channel through which unscrupulous hackers may attack your directory service.

   


Understanding and Deploying LDAP Directory Services
Understanding and Deploying LDAP Directory Services (2nd Edition)
ISBN: 0672323168
EAN: 2147483647
Year: 2002
Pages: 242

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net