#!/usr/local/bin/perl # @(#)Esp3Ldap.pm 1.4 09/21/00 17:05:27 ############################################################# # Utilities for LDAP access via Net::LDAP for ESP account info # Written by CEM 6/00 # # Note on error handling: addEntry returns the error message in a parameter, # while singleSearch returns it via the die/eval mechanism. So the underlying # routines in this module are not (yet?) consistent in how they propagate # error messages back to the caller. # # Lurking bug? # I had to remove a couple of eval {}'s once to prevent hanging in openLdap # to ED. But even with them back now, it doesn't hang any more. # During the time of hang, other LDAP searches e.g. findNid.pl worked fine. # # TO DO: the demo ESP login screens have not been tested with the new error # handling added 9/21. ############################################################ #use Mozilla::LDAP qw(:all); # not enough/doesn't work use Mozilla::LDAP::Conn; use Mozilla::LDAP::Utils; use Mozilla::LDAP::Entry; #use Mozilla::LDAP::API; # didn't help with ldapCount package Esp3Ldap; $basedir = "/bryan/carol/winref"; # CEM test on mhahn #$basedir = "/home/dbbrowse/WinrefBoot"; ############################################################ # connectToEd # # Connect and bind to ED/LDAP sub connectToEd { my ($log) = @_; my $host = "ldap.hp.com"; my $pass = "esp;ldap"; my $dn = "cn=esp, ou=Application Servers, o=hp.com"; my $doSSL = 1; return openLdap($log, $host, $pass, $dn, $doSSL); } ############################################################ # connectToESP # # Connect and bind to ESP/LDAP sub connectToEsp { my ($log) = @_; #my $host = "booboo.cup.hp.com"; my $host = "15.9.88.139"; # In case of DNS troubles my $pass = "violet"; my $dn = "cn=manager, o=hp.com"; #my $dn = "o=hp.com"; # nope my $doSSL = 0; # current server is OpenLDAP, # doesn't easily support SSL # Netscape/iPlanet will support SSL return openLdap($log, $host, $pass, $dn, $doSSL); } ############################################################ # openLdap # # Connect and bind to an LDAP server # # If successful, returns a connection handle. # sub openLdap { my ($log, $host, $pass, $dn, $doSSL) = @_; my %ld = Mozilla::LDAP::Utils::ldapArgs(); $ld{"host"} = $host; #$ld{"port"} = "636"; # For unsecured use port 389, for SSL use # use port 636. ED allows only SSL bind. $ld{"port"} = $doSSL ? "636" : "389" ; $ld{"pswd"} = $pass; $ld{"bind"} = $dn; $ld{"cert"} = "$basedir/LIB/cert7.db" if ($doSSL); my $secure = $doSSL ? "secure" : "unsecure" ; printf $log "Attempting $secure connection to $host..."; my $conn = new Mozilla::LDAP::Conn(\%ld); if (!$conn) { my $msg = "Connection to $host failed: $@"; printf $log "$msg\n"; # $@ is the Perl syntax error msg from last eval. die $msg; } printf $log "Successful.\n"; return($conn); } ################################################################### # search # # Pretty much like Mozilla::LDAP search() except with display of output. # # Search LDAP using the specified connection. # Returns an object of class Mozilla::LDAP::Entry. # To convert the result to an array of hashes (one hash per result # object), call getResultArray. # Or to get the rest of the search results, you'll need the $conn # handle, like this: # # while ($entry) { # $entry->printLDIF(); # $entry = $conn->nextEntry(); # } # # Specify an empty @attr array to return all attributes. sub search { my ($log, $verbose, $doDump, $conn, $filter, @attr) = @_; my $base = "o=hp.com"; # So far, same for both LDAPs printf $log "Search filter: $filter\n"; printf $log "Starting search..." if $verbose; my $mesg = $conn->search($base, "sub", $filter, 0, @attr); if ($conn->getErrorCode) { my $msg = ldapError($log, "search", $conn); die $msg; } if (!$mesg) { my $reason = ": $!"; if ($reason =~ /^: Resource temporarily unavailable/) { $reason = ""; # Get this message when nothing was found. Seems bogus. } my $msg = "Nothing returned from search$reason"; printf $log "$msg\n"; die $msg; } #my $n = ldapCount($mesg); # doesn't work #printf $log "Done. Found $n matching entries.\n"; printf $log "Done.\n"; # Haven't tried this, but it sure looks like this loop would modify # what the connection handle points to, caller should use with care. if ($doDump) { my $entry = $mesg; # modify?? a copy my $i; while ($entry) { printf $log "\n%d ------------------------------------------\n", $i++; dumpEntry($log, $entry); $entry = $conn->nextEntry(); } } return($mesg); } ####################################################################### # getResultArray # # Convert Net::LDAP::Search object returned by search to an array of # hashes. For convenience of ESP user account management, any attributes # that have multiple values are converted to have just one value # (e.g. the "mail" attribute). # # Note: so for the "mail" conversion to work, the emailaddress and preferredmail # attributes must have been specified to return from the original search. # # Converts the Search object to the more familiar array of hashes. # There will be one array element (hash) for each LDAP entry. sub getResultArray { my ($log, $verbose, $conn, $entry, $doEmail, $limit) = @_; my @array, $val; my $cnt = 0; my $unlimited = ($limit == 0 ? 1 : 0); while ($entry && ($unlimited || $cnt++ < $limit)) { my %hash; # clear hash for next entry $dn = $entry->getDN(); printf $log "Checking entry $dn.\n" if $verbose; if ($doEmail) { # Convert ED/LDAP email attribute to a single value we can rely on. # So far there has always been something in at least one of # emailAddress and preferredMail. We could hunt through the "mail" # attribute list if necessary. $val = $entry->{emailaddress}[0]; # SEA mail if (!$val) { printf $log "Warning: nothing in emailAddress, trying ". "preferredMail.\n" if $verbose; $val = $entry->{preferredmail}[0]; } if (!$val) { printf $log "Error: nothing in preferredMail either!\n" if $verbose; } else { $entry->addValue("espmail", $val); } } #foreach my $attr ( $entry->attributes ) # Might need to do it this way: #my @attrs = ldapAttrs($entry); #foreach my $attr ($entry->ldapAttrs) my @la = ldapAttrs($entry); foreach my $attr (@la) { #my @values = $entry->getValues($attr); # function not there my @values; my $i = 0; while (my $val = $entry->{$attr}[$i++]) { push @values, $val; } if ($#values < 0) { printf $log "Warning: $attr is empty.\n" if $verbose; } else { $hash{$attr} = $values[0]; # store the value in our hash } if ($#values > 0) { my $n = $#values + 1; if ($verbose) { # This happens a lot for "mail" attr and it's OK, so make it # a short message. printf $log "Note: for $attr, saving only first of $n values.\n"; foreach my $v (@values) { printf $log "\t$v\n"; } } } } push @array, { %hash }; # add the hash to our array $entry = $conn->nextEntry; } if ($limit && $cnt >= $limit) { printf $log "There are more entries but stopped converting after $limit.\n"; } return(@array); } ############################################################################### # dn2uid # # Convert a DN (distinguished name) to a uid (unique ID), suitable for # looking up the ED/LDAP entry associated with this DN. # The DN is specified as a comma-separated string. # # What does the returned manager's DN look like? # "emailaddress=carol_mattsson@hp.com, ou=Employees, o=hp.com" # # We don't search on DN, that is not an indexed field and the search will # time out. We Form uid from emailaddress minus the @hp.com. # # In ED, uid field sometimes includes the @ info - actually it's for # non non-HP only, e.g. "melvin_h_spam@non.hp.com." sub dn2uid { my ($log, $comma_string) = @_; print $log "dn2uid: $comma_string\n"; my $uid; my @rdns = split /, /, $comma_string; while (my $rdn = shift @rdns) { my ($key, $value) = split "=", $rdn; if ($key =~ /emailaddress/i) { # Must do case insensitive # search on attribute names ($uid, $x) = split "@", $value; last; } } if (!$uid) { printf $log "WARNING: Could not form uid from dn: $dn.\n" } return ($uid); } ################################################################## # addEntry # # Add a new entry to an LDAP directory. # # Like Mozilla::LDAP conn->add() except with display of output. # # NEW ERROR HANDLING HAS NOT BEEN TESTED!! CEM 9/21/00. sub addEntry { my ($log, $verbose, $conn, $createEntry) = @_; printf $log "About to add entry.......................\n"; dumpEntry($log, $createEntry); my $res = $conn->add($createEntry); if ($conn->getErrorCode()) { my $msg1 = ldapError($log, "add", $conn); my $msg2 = $conn->getErrorString(); die "$msg1 -- $msg2"; } return($res); } ################################################################## # dumpEntry sub dumpEntry { my ($log, $entry) = @_; printf $log "dn: %s\n", $entry->getDN; # Dump the values of this entry in attribute order. #foreach my $key (sort $entry->ldapAttrs) { my (@attrs) = ldapAttrs($entry); #foreach my $key (sort ldapAttrs($entry)) { foreach my $key (sort @attrs) { my @values; # empty it if ($key =~ /;binary$/) { $values[0] = ""; } else { #@values = $entry->{$key}; # not quite right #@values = $entry->getValues($key); # function not there #my $val2 = $entry->{$key}[0]; # ok my $i = 0; while (my $val = $entry->{$key}[$i++]) { push @values, $val; } } printf $log "%24s : %s\n", $key, $values[0]; shift @values; # careful, don't want to affect entry # we SHOULD be shifting our copy foreach my $value (@values) { # There seems to be some empty last value, don't know # where it came from, but don't print it. if ($value) { printf $log "%24s %s\n", "", $value; } } } } ################################################################## # ldapError # # The following Net::LDAP methods return a Net::LDAP::Message # object, which if the code() method returns non-zero, contains # a message which can be displayed by this method: # abandon, add, bind, compare, delete, modify, moddn, search, and unbind. # # To do-- see if the above methods are the ones that return the additional # info in perLDAP. # # Remember to check the DN and make sure there's a top object, # if "no such object" error. Also check args to ldap->add method. # # LDAP_OPERATIONS_ERROR in bind probably means server is down. # # Returns the error message as well as logging it. sub ldapError { my ($log, $from, $mesg) = @_; my ($matchedDn, $addlMessage); # Goes to STDOUT so can't control, but better than nothing. # Error message from last LDAP call: # Actually, it's same as results of getErrorString(), I think it's # just an alternate to getErrorString then formatting it yourself. #printf $log "Sending last LDAP error msg to stdout.\n"; #$mesg->printError(); $matchedDn = ""; $addlMessage = ""; my $code = $mesg->getErrorCode(\$matchedDn, \$addlMessage); my $humanReadable = $mesg->getErrorString(); my $msg = "LDAP error code $code in $from: $humanReadable\n" . "Matched DN: $matchedDn. Additional message: $addlMessage"; printf $log "$msg\n"; return($msg); } ####################################################################### # addEspUser # # Add a user with the specified attributes to ESP/LDAP. # # If telnet is empty in ED, the specified telnet is used. # # Returns message and user's first name. # If message is empty then the add was successful. sub addEspUser { my ($log, $last, $empnum, $telnet, $userid, $password, $verbose) = @_; #=========================================================== # Get the necessary user attributes from ED/LDAP. #my @attrs = qw( # c # cn # departmentNumber # emailAddress # givenName # hpBusinessOrganization # hpBusinessRegion # hpBusinessSector # hpFullName # hpOrganizationChartGroup # hpTelnetNumber # l # mailstop # manager # modifyTimestamp # o # ou # preferredMail # sn # telephoneNumber); # Attribute names must be downshifted to work in perLDAP # This was not necessary using NET::LDAP my @attrs = qw( c cn departmentnumber emailaddress givenname hpbusinessorganization hpbusinessregion hpbusinesssector hpfullname hporganizationchartgroup hptelnetnumber l mailstop manager modifytimestamp o ou preferredmail sn telephonenumber); my $field = ($empnum =~ /^\D+\d+/) ? "nonhptype" : "employeetype"; push @attrs, $field; $field = ($empnum =~ /^\D+\d+/) ? "nonhpuniqueid" : "employeenumber"; # Yes, caller gave us the empNum, but it's # convenient to fetch it from the LDAP entry later. push @attrs, $field; # Later we form the dn from userid and o=hp.com # Later we set "community" to "HP-ED/LDAP" # Later we fill in employeeType to HP-emp or HP-nid according to $empnum # Later we fill in manager attributes from looking up the manager record # Later we set userRoles and grantedPrivileges to defaults, and fill in # the password. # Set the search filter for the user specified. # We must search on at least ONE indexed attribute. In this case both # nonhpuniqueid and employeenumber are indexed. $field = ($empnum =~ /^\D+\d+/) ? "nonhpuniqueid" : "employeenumber"; my $filter = "(&(sn=$last)($field=$empnum))"; # Connect to ED/LDAP. my $conn; eval { $conn = Esp3Ldap::connectToEd($log) }; # Now that openLdap dies if connection fails, there will actually be a more # detailed error message in $@. But this sub is used by a browser, so we # want a more understandable message, so we just let Esp3Ldap log the error # and display a nicer (but dumber) message for the user. Same for search() # below. return ("Couldn't connect to Enterprise Directory. Account not created.\n") if (!$conn); # Search for the user's entry in ED/LDAP; my $userResult; eval { $userResult = Esp3Ldap::search($log, $verbose, $verbose, $conn, $filter, @attrs) }; if (my $next = $conn->nextEntry) { printf $log "Alert: more than one user entry found: " . $next->getDN() . ". Using only first one.\n"; } # If all is working normally, the search would only fail because # empnum didn't match lastname. if (!$userResult) { return ("Could not find person matching $last $empnum in" . " Enterprise Directory. Account not created."); } # OK, we found the user's entry. Get the manager attributes. @attrs = qw( emailaddress employeenumber givenname hptelnetnumber manager preferredmail sn telephonenumber); # Set the filter to search for the manager entry my $mgr = $userResult->{manager}[0]; my $uid = Esp3Ldap::dn2uid($log, $mgr); $filter = "(uid=$uid)"; # Search for the manager entry in ED/LDAP; my $mgrResult; eval { $mgrResult = Esp3Ldap::search($log, $verbose, $verbose, $conn, $filter, @attrs) }; if (!$mgrResult) { printf $log "ED manager search failed: $dn $last $empnum.\n"; return ("Could not find info for user's manager $dn" . " in Enterprise Directory. Account not created."); } if (my $next = $conn->nextEntry) { printf $log "Alert: more than one manager entry found: " . $next->getDN() . ". Using only first one.\n"; } # One more time... search for the manager's manager's entry in ED/LDAP; # If we don't find it, go ahead and create the account anyway. The update # process may be able to fill in the manager's manager info off-line. @attrs = qw(employeenumber); my $mgrMgr = $mgrResult->{manager}[0]; $uid = Esp3Ldap::dn2uid($log, $mgrMgr); $filter = "(uid=$uid)"; my $mgrMgrResult; eval { $mgrMgrResult = Esp3Ldap::search($log, $verbose, $verbose, $conn, $filter, @attrs) }; if (!$mgrMgrResult) { printf $log "Warning! Could not find info for manager's manager $dn in ED. Manager's employee number won't be available in the new account.\n"; } if (my $next = $conn->nextEntry) { printf $log "Alert: more than manager manager entry found: " . $next->getDN() . ". Using only first one.\n"; } # We are done with the connection to ED/LDAP. disconnect($log, $conn); #=========================================================== # OK, we have all the user attributes. Now create the new user entry. # First we need an entry to create. Map the search results from ED to ESP # where necessary, and return them in the form of an an LDAP::Entry object. my $createEntry = getEspAttrs($log, $verbose, $telnet, $userResult, $mgrResult, $mgrMgrResult); # Fill in other attributes in the entry. $createEntry->setDN("uid=$userid, o=hp.com"); $createEntry->addValue("uid", $userid); # must be set in both places $createEntry->addValue("objectClass", "top"); $createEntry->addValue("objectClass", "person"); $createEntry->addValue("objectClass", "organizationalperson"); $createEntry->addValue("objectClass", "inetorgperson"); $createEntry->addValue("objectClass", "espuser"); $createEntry->addValue("community", "HP-ED/LDAP"); my $value = ($empnum =~ /^\D+\d+/) ? "non-HP" : "HP"; $createEntry->addValue("employeetype", $value ); $value = ($empnum =~ /^\D+\d+/) ? "Non-HP Employee" : "HP Employee"; $createEntry->addValue("userroles", $value ); # Must use '', "" gives bracket mismatch compile error #$createEntry->setValues("grantedprivileges", [ # not in perLDAP 1.0 #$createEntry->{grantedprivileges} = [ # attribute not set at all! # 'Create virtual teams', # 'Request virtual team membership', # 'Publish vteam docs', # 'Publish public docs' ]; # Granted privileges might not be used, might be derived from user roles. $createEntry->addValue("grantedprivileges", "Create virtual teams"); $createEntry->addValue("grantedprivileges", "Request virtual team membership"); $createEntry->addValue("grantedprivileges", "Publish vteam docs"); $createEntry->addValue("grantedprivileges", "Publish public docs"); my $salt = "salt shared with SC"; my $encrypted = crypt($pass, $salt); $createEntry->addValue("initialpassword", $encrypted); # Connect to ESP/LDAP. eval { $conn = Esp3Ldap::connectToEsp($log) }; return("Can't connect to ESP user directory. Account not created.\n") if (!$conn); # Now create the entry. my $mesg; eval { $mesg = Esp3Ldap::addEntry($log, $verbose, $conn, $createEntry) }; if (!$mesg) { if ($msg =~ /already exists/i) { ## Need to check string vals return("User account \"$userid\" already exists in ESP." . " New account not added."); # Interpret other messages here. } else { return("User info OK in Enterprise Directory but could not create" . " new account ($userid) in ESP."); } } printf $log "Entry for $userid successfully added to ESP.\n"; # Fetch the firstname to return. my $firstname = $createEntry->{givenname}[0]; # To check the results, for now run grepLdap. # We are done with the connection to ED/LDAP. disconnect($log, $conn); return("", $firstname); # No message indicates success. } #################################################################### # getEspAttrs # # Map ED attributes returned by search for user and manager, into # a new entry suitable adding to ESP/LDAP. sub getEspAttrs { my ($log, $verbose, $telnet, $userSearch, $mgrSearch, $mgrMgrSearch) = @_; my $createEntry = new Mozilla::LDAP::Entry(); my $val; #=============================================== # Map the user entries my $entry = $userSearch; $dn = $entry->getDN; printf $log "Fetching values from ED user entry $dn.\n" if $verbose; # Go from emailAddress and preferredMail -> mail $val = mapEmail($log, $entry); if ($val) { $createEntry->addValue("mail", $val); } # Go from employeeNumber and nonHpUniqueId -> employeeNumber $val = mapEmployeeNumber($log, $entry); if ($val) { $createEntry->addValue("employeenumber", $val); } # Go from nonHptype and employeeType -> employmentStatus $val = mapEmploymentStatus($log, $entry); if ($val) { $createEntry->addValue("employmentstatus", $val); } foreach $name ( c, cn, departmentnumber, givenname, hpbusinessorganization, hpbusinessregion, hpbusinesssector, hpfullname, hporganizationchartgroup, hptelnetnumber, l, mailstop, modifytimestamp, o, ou, sn, telephonenumber) { $val = $entry->{$name}[0]; if ($val) { $createEntry->addValue("$name", $val); } else { printf $log "Missing $name in ED user entry. Attribute not set!\n"; } } # Fill in telnet if it's missing $val = $createEntry->{hptelnetnumber}[0]; if (!$val) { printf $log "Alert: telnet is empty, using user-specified value.\n"; $createEntry->addValue("hptelnetnumber", $telnet); } #=============================================== # Map the manager entries. $entry = $mgrSearch; $dn = $entry->getDN; printf $log "Converting ED manager entry $dn.\n" if $verbose; $val = $entry->{employeenumber}[0]; if ($val) { $createEntry->addValue("mgremployeenumber", $val); } else { printf $log "No manager employee number. Attribute not set!\n"; } $val = $entry->{hptelnetnumber}[0]; if ($val) { $createEntry->addValue("mgrhptelnetnumber", $val); } else { printf $log "No manager hp telnet number. Attribute not set!\n"; } $val = $entry->{givenname}[0]; if ($val) { $createEntry->addValue("mgrgivenname", $val); } else { printf $log "No manager given name. Attribute not set!\n"; } $val = mapEmail($log, $entry); if ($val) { $createEntry->addValue("mgrmail", $val); } $val = $entry->{sn}[0]; if ($val) { $createEntry->addValue("mgrsn", $val); } else { printf $log "No manager surname. Attribute not set!\n"; } $val = $entry->{telephonenumber}[0]; if ($val) { $createEntry->addValue("mgrtelephonenumber", $val); } else { printf $log "No manager telephone number. Attribute not set!\n"; } #=============================================== # Get the Manager's Manager's employee number. if (!$mgrMgrSearch) { printf $log "Nothing in manager manager entry. Skipping it.\n"; } else { $entry = $mgrMgrSearch; $dn = $entry->getDN; printf $log "Converting ED manager manager's entry $dn.\n" if $verbose; $val = $entry->{employeenumber}[0]; if ($val) { $createEntry->addValue("mgrmgremployeenumber", $val); } else { printf $log "No manager's manager's employee number. " . "Attribute not set!\n"; } } return($createEntry); } ###################################################################3 # mapEmail # # Convert ED/LDAP email attribute to a single value we can rely on. # Go from emailAddress and preferredMail -> mail sub mapEmail { my ($log, $entry) = @_; my $email, $val; $val = $entry->{emailaddress}[0]; # SEA mail if (!$val) { printf $log "Warning: nothing in emailAddress, trying preferredMail.\n"; $val = $entry->{preferredmail}[0]; } if (!$val) { printf $log "Error: nothing in preferredMail either!\n"; } else { $email = $val; } return($email); } ###################################################################3 # mapEmployeeNumber # # Go from employeeNumber and nonHpUniqueId -> employeeNumber sub mapEmployeeNumber { my ($log, $entry) = @_; my $val; $val = $entry->{employeenumber}[0]; if ($val) { return($val); } $val = $entry->{nonhpuniqueid}[0]; if ($val) { return($val); } printf $log "Error: Nothing in employeeNumber or nonHpUniqueId! " . "Not setting attribute.\n"; return; } ######################################################################## # mapEmploymentStatus # # Go from nonHpType and employeeType -> employmentStatus sub mapEmploymentStatus { my ($log, $entry) = @_; my $val; $val = $entry->{employeetype}[0]; if (!$val) { printf $log "Warning: nothing in employeeType, trying nonHpType.\n"; $val = $entry->{nonhptype}[0]; } if (!$val) { printf $log "Error: nothing in nonHpType either!\n"; return; } else { return($val); } } #################################################################### # ldapCount # # Substitute for $mesg->count() available in Net::LDAP # We are accessing the internal handles from the Mozilla::LDAP::Conn # object only because there is no OO access to the count() method. # See the LDAP FAQ "How do I count the number of entries a search # found?" for reference < http://www.mozilla.org/directory/faq/perldap-faq.html # # Need Mozilla::LDAP::API for this??? Nope, getLD still not found. # # Needs work. Just returns -1 no matter what. sub ldapCount { my ($conn) = @_; my $connHandle = $conn->{"ld"}; my $lastResultHandle = $conn->{"ldres"}; #my $connHandle = $conn->getLD(); # available in newer perLDAP? #my $lastResultHandle = $conn->getRes(); # this way in the FAQ my $count = Mozilla::LDAP::API::ldap_count_entries( $connHandle, $lastResultHandle); return($count); } #################################################################### # ldapAttrs # # Return an array of attribute names # Pulled from printLDIF in Entry.pm, might not be that maintainable # if perLDAP version changes. # # Usage: # my @attrs = ldapAttrs($entry); # my @attrs = $entry->ldapAttrs(); # which one??? # foreach $attr (@attrs) { # printf "%s : %s\n", $attr, $entry->{$attr}[0]; # } sub ldapAttrs { my ($self) = @_; my @attrs; foreach my $attr (@{$self->{"_oc_order_"}}) { next if ($attr =~ /^_.+_$/); next if $self->{"_${attr}_deleted_"}; push @attrs, $attr; #grep((print "$attr: $_\n"), @{$self->{$attr}}); } return @attrs; } #################################################################### # disconnect # # Just like unbind or close or whatever, with error reporting. sub disconnect { my ($log, $conn) = @_; my $res = $conn->close(); if (!$res) { printf $log "Unsuccessful LDAP disconnect: $!\n"; } } #################################################################### # singleSearch # # Connect to ED LDAP server and search for entries where surname # or telnet matches the given string. # # Specialized version of grepLdap.pl for WinRef submittal form account # team lookup function. # # Written by CEM 9/00 # # Example search strings: # # mattsson find all entries with first or last name of "mattsson" # carol find all entries with first or last name of "carol" # *2779 find all entries with telnet ending in "2779" # robert* find all entries with first or last name beginning with "robert," # including "Robert J" Crum. # alexander find all entries with first or last name of "alexander" - returns # a LOT if return limit isn't set. # # See atLookup.pl for example call and how to initialize the log file. # # Design note: Only the sn and hptelnetnumber are indexed fields in the # ED/LDAP. E-mail and givenname aren't, so those are not good for # search strings. # # More on inputs: # # List of attributes by default is # @attrs = qw(sn givenname hptelnetnumber ou emailaddress preferredmail); # Run "grepLdap.pl -A..." to see examples of other attribute names available. # # If you care about e-mail, you must specify emailaddress and preferredmail # attributes to return. GetResultArray will combine these two into a single # "mail" attribute. # # Log must be a filehandle to an already open file, else logging goes # to stdout. # # Returns an array of hashes. There will be one hash # for each search result (entry) found. There will be a hash value for each # attribute specified in attrsToGet (except for "mail" -- see above). # # Limit specifies the maximum number of entries to return. Default is 0, # which means unlimited. # # If there was an error, an exception will be thrown (via die (new thing # for Carol!!)) so caller should check for the error by wrapping the call # with eval{}. # # Error handling not well tested as of 9/00 -- CEM ############################################################# sub singleSearch { my ($searchStr, $limit, $verbose, $attrsToGet, $logTo) = @_; my @attrs = @$attrsToGet; # Dereference array my $log; my $progName = "Esp3Ldap::singleSearch"; my $doHP = 0; # Log to stdout if $log not specified if ($logTo) { $log = $logTo; } else { $log = new FileHandle; $log->open(">&STDOUT") || die "Can\'t dup STDOUT for $progName log: $!"; } printf $log "$progName: get @attrs<>\n"; # Connect to ED/LDAP. # Careful!!! Once this hung until I removed the eval {} -- CEM 9/00 eval { $conn = Esp3Ldap::connectToEd($log) }; #$conn = Esp3Ldap::connectToEd($log); die "Could not connect to Enterprise Directory: $@" if ($@); die "Could not connect to Enterprise Directory." if (!$conn); printf $log "Connected to ED/LDAP.\n" if $verbose; # Form our search filter. # For telnet, or any search that may be prefixed with a wildcard, # make sure there's no blank between the = and *. # Apparently no blanks allowed in perLDAP version!!! # Get "bad search filter" error if blank between attr and = e.g. # (&(sn =mattsson)(givenname =carol)) is a bad search filter. my $doTelnet = ($searchStr =~ /\d/) ? 1 : 0; my $filter = "(|"; if ($doTelnet) { $filter .= "(hptelnetnumber=$searchStr)"; } else { $filter .= "(sn=$searchStr)"; $filter .= "(givenname=$searchStr)"; } $filter .= ")"; # Form the list of attributes to return. if (!@attrs) { @attrs = qw(sn givenname hptelnetnumber ou emailaddress preferredmail mail); } # Do the search my $mesg = Esp3Ldap::search($log, $verbose, 0, $conn, $filter, @attrs); printf $log "Back from search.\n" if $verbose; # This is a test # die "Testing from Esp3Ldap: search failed"; # Testing from Esp3Ldap: search failed at /home/mattsson/sccs/ # perLdap/Esp3Ldap.pm line 1041. # Convert search object (result) to array of hashes. my @array = Esp3Ldap::getResultArray( $log, $verbose, $conn, $mesg, $doHP, $limit); # We are done with this connection. Esp3Ldap::disconnect($log, $conn); return(@array); } 1;