I just whipped up another phonebook app since the one provided does not work with certs on IE without more tweaking and uses ldapsearch..... Would you be interested in placing it on the tools page? Jason. ---- start script #!/usr/bin/perl -T ################################################################################################## # This is a mini phonebook cgi I hacked up for getitng certs from a directory # There is a lot that can be done to improve it # But it suits my needs. If you make changes please send me a copy for the archive. # Jason Brvenik - [EMAIL PROTECTED] # Usual disclaimers... # Released under GPL found at http://www.gnu.org/copyleft/gpl.txt ################################################################################################# # TODO # 1) Add decode cert to link certs to a specific email address when multiple exist # instead of the user having to search for the correct one # 2) Error checking and more Error checking # 3) Better Input checking # 4) use HTML::Template for simple customization # 5) More consistent use of CGI; use locale; # In case we strip out chars for input checking, this makes sure we support non US locales use Mozilla::LDAP::Conn; # All the LDAP stuff use MIME::Base64; # Used to encode the certs for text display use CGI; # easier to interact with www use MD5; # Used to create a hash of the cert since LDAP can return attributes in random order $debug = 0; # Turns on debugging $cgi = new CGI; # create the cgi object $odd_color = "#EEEEEE"; $even_color = "#DDDDDD"; $ldap_host = "your.directory.server"; # what directory to search # easier to interact with www $ldap_port = "389"; # what port to use $ldap_scope = "subtree"; # what type of search to perform $base_dn = "c=ww"; # where to start the search from $bind_dn = ""; # authenticate as this user - "" means anonymous $bind_pw = ""; # users password = "" means anonymous or no password # This is a hash for building the search results and defining the attributes returned # The format is like this # "fieldname" => "Human Name" # To be able to display a field you must specify an entry in this hash and the display_order array. # Placing it in attr_hash but not display_order will result in the attribute being # returned from the directory but not displayed to the user # until the record is requested specifically by a clickthrough %attr_hash = ( "telephonenumber" => "Phone", "rfc822mailbox" => "E-Mail", "commonname" => "Full name" ); # The order is defined by placement in the display_order array. # If it's not in this array it doesn't get displayed for the search results @display_order = ("commonname","rfc822mailbox","telephonenumber"); # Build the array specifying the attributes to fetch from the directory here. foreach $key ( %attr_hash ) { push(@attrs, $key); } # get parameters passed # for filter we remove common wildcards and search operators # to prevent people circumventing our predefined search filter # and doing searches for * or objectclasses... # This one # s/\*||\%||\|||\;||\'||\"||\&||\!||\\||\///g; # removes the chars * % | ; ' " & ! \ / $filter = $cgi->param('filter'); # The initial search term if ( defined $filter ) { $filter =~ s/\*||\%||\|||\;||\'||\"||\&||\!||\\||\///g; $print_filter = $filter; if ( $filter eq "" ){ print_header(); print_html_header(); print 'You must enter a valid search string' . $cgi->br . "\n"; print_html_footer(); exit; } $filter = '(|(cn=*' . $filter . '*)(rfc822mailbox=*' . $filter . '*))'; } $dn = $cgi->unescape($cgi->param('dn')); # The DN of a requested record $getcert = $cgi->param('getcert'); # Flag to retrieve a cert $certhash = $cgi->param('certhash'); # Hash of specific cert requested. Useful when there are multiple certs $help = $cgi->param('help'); # Flag to say when to display help $| = 1; # No buffering; print_header(); # Print the appropriate header. if ( defined $getcert ) { send_cert_bin(); exit; } # Send back the binary certificate for import into a browser # It isn't a get cert request. Handle as a search print_html_header(); # Debugging code to spit out the parameters passed if ($debug) { @vars = $cgi->param; foreach $var (@vars) { print $var . ":" . $cgi->param($var) . $cgi->br . "\n"; } print $cgi->hr; } # It's a request for a specific record. if ( defined $dn ) { send_record(); print $cgi->end_html; exit; } # Not looking for a specific record. # Present the search form. print_search_form(); # Either you are just getting to the form or help has been requested if ( (!defined $filter) || ($help==1) ) { print_help_text(); } # Exit here on the initial request if ( !defined $filter) { print_html_footer();exit; } # There is a filter defined. Set up a table for the search results start_table(); print_results(); end_table(); print_html_footer(); ##################################################################### ##################################################################### # End of main program. # ##################################################################### ##################################################################### ##################################################################### # Determines what type header to return based on request. # # If it is the initial or record request we are sending back html # If it is a getcert request we need to send back either a pkix or # x509 depending on browser # ##################################################################### sub print_header() { if ( defined $getcert && defined $dn) { # return the appropriate header to the browser if ( $cgi->user_agent() =~ /MSIE/ ) { # For IE print $cgi->header(-type=>'application/pkix-cert'); } else { # For Netscape print $cgi->header(-type=>'application/x-x509-email-cert'); } } else { print $cgi->header(); } } ##################################################################### # Send back the certificate requested in binary format # So that the browser can import it directly. ##################################################################### sub send_cert_bin() { @attrs = ("usercertificate"); $ldap = new Mozilla::LDAP::Conn($ldap_host,$ldap_port,$bind_dn,$bind_pw) || die("could not connect to directory\n"); if ( $entry = $ldap->search($dn, $ldap_scope, "objectclass=*", 0, @attrs) ) { foreach $key (keys %{$entry}) { foreach $value ( @{$entry->{$key}} ) { $md5 = MD5->hexhash($value); print $value if ( $md5 eq $certhash ); # This ensures the requested cert is sent } } } else { print "Could Not find entry $dn" . $cgi->br . "\n"; } $ldap->close(); } ##################################################################### # Send back a ldap record in html format ##################################################################### sub send_record() { @attrs = ("commonname", "surname", "telephonenumber", "rfc822mailbox", "usercertificate"); $ldap = new Mozilla::LDAP::Conn($ldap_host,$ldap_port,$bind_dn,$bind_pw) || die("could not connect to directory\n"); if ( $entry = $ldap->search($dn, $ldap_scope, "objectclass=*", 0, @attrs) ) { print "<TABLE border=1>\n"; $count = 0; foreach $key (keys %{$entry}) { foreach $value ( @{$entry->{$key}} ) { next if ( !defined $value ); print "<TR bgcolor=" . (($count % 2) ? $even_color:$odd_color) . ">\n"; # use the pretty name if we know it if ( defined %attr_hash->{$key} ) { $key = %attr_hash->{$key}; } if ( $key =~ /usercertificate/i ) { $md5 = MD5->hexhash($value); $value = encode_base64($value); $tkey = "<a href=" . $cgi->url . "?dn=" . $cgi->escape($dn) . "&getcert=1&certhash=" . $md5 . ">Get Certificate</a>\n"; } else { $tkey = $key; } # TESTING # print "<TD>" . $tkey . "</TD><TD>" . $value . "</TD></TR>\n"; print "<TD>" . $tkey . "</TD><TD>" . $value . "</TD></TR>\n"; $count++; } } print "</TABLE>\n"; } else { print "Could Not find entry $dn<BR>\n"; } $ldap->close(); } ##################################################################### # Print a html page header. # This is not the content header but the top of the page # being returned to the browser. # Place things you want to appear before the search form # and any records returned here. ##################################################################### sub print_html_header() { print $cgi->start_html(-title=>'Directory Search', -author=>'[EMAIL PROTECTED]'); } ##################################################################### # Print the bottom of the html content # place things here you want to appear after the search form # and any records returned. ##################################################################### sub print_html_footer() { print $cgi->end_html; } ##################################################################### # Print the search form. This will appear between the html_header # and the html_footer sections ##################################################################### sub print_search_form() { print $cgi->startform(-method=>'POST', -action=>$cgi->url); print $cgi->textfield(-name=>'filter', -size=>50, -maxlength=>80); print $cgi->submit; print $cgi->endform; } ##################################################################### # Print out some help text on usage # This will only appear if requested or it's the forst invocation # of this script. # The placement is under the actual search form ##################################################################### sub print_help_text() { print $cgi->hr . $cgi->br . "Type in a name or email address. Partial matches are acceptable." . $cgi->br . "\n"; } ##################################################################### # The table definition goes here. ##################################################################### sub start_table() { print $cgi->hr . "Your search for " . $cgi->b($print_filter) . " returned the following" . $cgi->br . "\n"; print "<TABLE border=1><TR>\n"; foreach $key (@display_order) { print "<TD>" . %attr_hash->{$key} . "</TD>\n"; } print "</TR>\n"; } ##################################################################### # This prints the results of the search in the table ##################################################################### sub print_results() { $count = 0; $ldap = new Mozilla::LDAP::Conn($ldap_host,$ldap_port,$bind_dn,$bind_pw) || die("could not connect to directory\n"); if ( $entry = $ldap->search($base_dn, $ldap_scope, $filter, 0, @attrs) ) { while ( $entry ) { print "<TR bgcolor=" . (($count % 2) ? $even_color:$odd_color) . ">\n"; $count++; # foreach $key (@attrs) { foreach $key (@display_order) { $value = @{$entry->{$key}}[0]; if ( $key =~ /usercertificate/i ) { $value = encode_base64($value); } if ( $key =~ /rfc822mailbox/i ) { $value = "<a href=mailto:" . $value . ">" . $value . "</a>\n"; } if ( $key =~ /commonname/i ) { $value = "<a href=" . $cgi->url . "?dn=" . $cgi->escape($entry->getDN()) . ">" . $value . "</a>\n"; } print "<TD>" . $value . "</TD>"; } print "</TR>\n"; $entry = $ldap->nextEntry(); } } else { print("<TD>No entries returned</TD>" . $cgi->br . "\n"); } $ldap->close(); } sub end_table() { print "</TABLE>"; }
