### Local Variables: *** ### mode:perl *** ### comment-column:0 *** ### comment-start: "### " *** ### comment-end: "***" *** ### End: *** # # ****************DO NOT MOVE OR CHANGE LINES ABOVE THIS********************* # # The first set of lines runs perl from any shell. The second set of lines # identifies the rest of the file as PERL for EMACS autoformatting. # See end of copyright for more information. # # # ------------------------------------------------------------------- # X-BONE # # http://www.isi.edu/xbone # USC Information Sciences Institute (USC/ISI) # Marina del Rey, California 90292, USA # Copyright (c) 1998-2005 # # ------------------------------------------------------------------- # # Copyright (c) 1998-2005 by the University of Southern California. # All rights reserved. # # Permission to use, copy, modify, and distribute this software and # its documentation in source and binary forms for non-commercial # purposes and without fee is hereby granted, provided that the above # copyright notice appear in all copies and that both the copyright # notice and this permission notice appear in supporting # documentation, and that any documentation, advertising materials, # and other materials related to such distribution and use acknowledge # that the software was developed by the University of Southern # California, Information Sciences Institute. The name of the # University may not be used to endorse or promote products derived # from this software without specific prior written permission. # # THE UNIVERSITY OF SOUTHERN CALIFORNIA MAKES NO REPRESENTATIONS ABOUT # THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS # PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # Other copyrights might apply to parts of this software and are so # noted when applicable. # # ------------------------------------------------------------------- # # Effort partly sponsored by the Defense Advanced Research Projects # Agency (DARPA) and Air Force Research Laboratory, Air Force Materiel # Command, USAF, under agreement numbers F30602-98-1-0200 (X-Bone) and # F30602-01-2-0529 (DynaBone). The views and conclusions contained # herein are those of the authors and should not be interpreted as # necessarily representing the official policies or endorsements, # either expressed or implied, of the Defense Advanced Research # Projects Agency (DARPA), the Air Force Research Laboratory, or the # U.S. Government. # # This work was partly supported by the NSF STI-XTEND (ANI-0230789) # and NETFS (ANI-0129689) projects. Any opinions, findings, and # conclusions or recommendations expressed in this material are those # of the authors and do not necessarily reflect the views of the # National Science Foundation. # # -------------------------------------------------------------------------- # $RCSfile: XB_LDAP.pm,v $ # # $Revision: 1.14 $ # $Author: pingali $ # $Date: 2005/04/10 06:45:03 $ # $State: Exp $ # ---------------------------------------------------------------------------- # # Primary Author: Runfang Zhou package XB_LDAP; require Exporter; @ISA = qw(Exporter); @Export = qw(); @EXPORT_OK = qw( LDAP_search LDAP_register LDAP_unregister ); use strict; use sigtrap; use Data::Dumper; use XB_Log; use Net::LDAPS; use XB_Params; my $modname = "XB_LDAP::"; # Description: # Connect to the LDAP server # Arguments: # Already specified in the node_opts. Should we support # overriding of those values? # Returns: # $ldap - handle to the connection # Exceptions: # XB_LDAP::connect # sub LDAP_connect () { my ($ldap); my $procname = "LDAP_connect"; #XB_Log::log "info", "-> $modname$procname"; eval { # Options that must be used my $ldapconf = $XB_Params::node_opts{'ldap'}; (not defined $ldapconf) and XB_Log::log ("debug3", "node_opts{ldap} undefined here") and die "ldap"; #XB_Log::log "debug1", # "LDAP server configuration used = " . Dumper($ldapconf); $ldap = Net::LDAPS -> new ($ldapconf->{server}, version => $ldapconf->{version}, port => $ldapconf->{port}, cafile => $ldapconf->{ca_cert}, clientcert => $ldapconf->{node_cert}, clientkey => $ldapconf->{node_key}, verify => 'require', debug => 0, ) or do { XB_Log::log ("debug3", "Unable to connect to server $@"); die "connect"; }; }; #XB_Log::log "info", "<- $modname$procname"; return ($ldap) unless $@; unless ($@ =~ /^(connect|ldap)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; }; # Description: # binds to the object corresponding this host # Arguments: # handle returned by connect # Returns: # nothing # Exceptions: # XB_LDAP::LDAP_bind # sub LDAP_bind ($) { #XXX has to use profiles my ($ldap) = @_; my $procname = "LDAP_bind"; #XB_Log::log "info", "-> $modname$procname"; eval { # Options that must be used my $ldapconf = $XB_Params::node_opts{'ldap'}; #=> this is the DN to which we will bind my $dn = $ldapconf->{userdn}; my $mesg = $ldap->bind($dn, password => $ldapconf->{password}, version => $ldapconf->{version}) ; if ($mesg->code) { XB_Log::log ("debug3", "Unable to the bind to dn $dn" . $mesg->error); die "bind"; } }; #XB_Log::log "info", "<- $modname$procname"; return 1 unless $@; unless ($@ =~ /^(bind)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; } # Description: # unbinds # Arguments: # handle returned by connect # Returns: # nothing # Exceptions: # XB_LDAP::unbind # sub LDAP_unbind ($) { my ($ldap) = @_; my $procname = "LDAP_unbind"; #XB_Log::log "info", "-> $modname$procname"; eval { $ldap->unbind() or do { XB_Log::log ("debug3", "Unable to the unbind") and die "unbind"; } }; #XB_Log::log "info", "<- $modname$procname"; return ($ldap) unless $@; unless ($@ =~ /^(unbind)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; } # Description: # search for specific attributes under a given prefix tree # Arguments: # what? - # # Returns: # # Exceptions: # sub LDAP_search ($$;$) { my ($what,$where,$attrvals) = @_; my ($dn, @attrlist, %results) = (); my $procname = "LDAP_search"; #XB_Log::log "info", "-> $modname$procname"; eval { #=> connect to the server; my $ldap = LDAP_connect(); LDAP_bind($ldap); my $ldapconf = $XB_Params::node_opts{'ldap'}; my $hostname = $ldapconf->{hostname}; my $instance = $ldapconf->{instance}; if ($what !~ /(config|registry|acl|ca)/) { XB_Log::log ("debug3", "Search target ($what) is inappropriate"); die "params"; } if ($where !~ /(local|global)/) { XB_Log::log ("debug3", "Search scope ($where) is inappropriate"); die "params"; } $_ = $what; SWITCH : { (/config/i) and do { $dn = "cn=$instance,cn=$hostname,ou=config,ou=$where,ou=xbone"; @attrlist = ( "xbattr", "xbacl", "xbregister"); #=> do the actual search my $mesg = $ldap->search( # perform a search base => $dn, filter => "(objectClass=XBoneInstance)" ); $mesg->code and do { XB_Log::log ("debug3", $mesg->error); die "search"; }; #=> process the reply foreach my $entry ($mesg->entries) { #$entry->dump; foreach my $attr (@attrlist){ # XXX have to handle multivalued attributes here my @list = $entry->get_value($attr); $results{$hostname}{$attr} = \@list; }; # for each attribute }; last SWITCH; }; (/registry/i) and do { my %subdirs = (); $subdirs{local}{privateregistry} = 1; $subdirs{local}{registry} = 1; if ($where !~ /^(global)$/) { $subdirs{global}{registry} = 1; } foreach my $scope (keys %subdirs){ foreach my $dir (keys %{$subdirs{$scope}}){ $dn = "ou=$dir,ou=$scope,ou=xbone"; @attrlist = ( "xbattr" ); my $filter = "(objectClass=XBoneInstance)"; if (defined $attrvals){ foreach my $attr (keys %{$attrvals}){ my $val = $attrvals->{$attr}; my $exp = "(xbattr=\'$attr = $val\')"; $filter = $filter . $exp; } } $filter = "(\&$filter)"; #=> do the actual search my $mesg = $ldap->search( # perform a search base => $dn, filter => $filter, ); $mesg->code and do { XB_Log::log ("debug3", $mesg->error); die "search"; }; #=> process the reply foreach my $entry ($mesg->entries) { #$entry->dump; $hostname = $entry->get_value("cn"); next if (not defined $hostname or $hostname eq ""); foreach my $attr (@attrlist){ # XXX have to handle multivalued attributes here my @list = $entry->get_value($attr); $results{$hostname}{$attr} = \@list; }; # for each attribute }; }; #subdirectories }; # scope last SWITCH; }; (/acl/i) and do { my %subdirs = (); $subdirs{local}{acl} = 1; if ($where !~ /^(global)$/) { $subdirs{global}{acl} = 1; } foreach my $scope (keys %subdirs){ $dn = "ou=acl,ou=$scope,ou=xbone"; @attrlist = ( "xbacl" ); #=> do the actual search my $mesg = $ldap->search( # perform a search base => $dn, filter => "(objectClass=XBoneGroup)" ); $mesg->code and do { XB_Log::log ("debug3", $mesg->error); die "search"; }; #=> process the reply foreach my $entry ($mesg->entries) { #$entry->dump; $hostname = $entry->get_value("cn"); next if (not defined $hostname or $hostname eq ""); foreach my $attr (@attrlist){ # XXX have to handle multivalued attributes here my @list = $entry->get_value($attr); $results{$hostname}{$attr} = \@list; }; # for each attribute }; }; # scope last SWITCH; }; (/^(ca)$/i) and do { my %subdirs = (); $subdirs{local}{ca} = 1; if ($where !~ /^(global)$/) { $subdirs{global}{ca} = 1; } foreach my $scope (keys %subdirs){ foreach my $dir (keys %{$subdirs{$scope}}){ $dn = "ou=$dir,ou=$scope,ou=xbone"; @attrlist = ( "cACertificate;binary", "certificateRevocationList;binary" ); #=> do the actual search my $mesg = $ldap->search( # perform a search base => $dn, filter => "(objectClass=XBoneCA)" ); $mesg->code and do { XB_Log::log ("debug3", $mesg->error); die "search"; }; #=> process the reply foreach my $entry ($mesg->entries) { #$entry->dump; $hostname = $entry->get_value("cn"); next if (not defined $hostname or $hostname eq ""); foreach my $attr (@attrlist){ # XXX have to handle multivalued attributes my @list = $entry->get_value($attr); $results{$hostname}{$attr} = \@list; }; # for each attribute }; }; }; last SWITCH; }; }; #XB_Log::log "info", "LDAP results" . Dumper(\%results); LDAP_unbind($ldap); }; #XB_Log::log "info", "<- $modname$procname"; return (\%results) unless $@; unless ($@ =~ /^(params|unbind|bind|connect|search)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; }; # Description: # registers attributes for a given host # Arguments: # attribute hash ( # => (MAY) # : # => (MAY) # ) # Returns: # # Exceptions: # sub LDAP_register ($) { my ($attrhash) = @_; my ($ldap, $result, $dn, @reghash); my $procname = "LDAP_register"; #XB_Log::log "info", "-> $modname$procname"; eval { #=> connect to the server; $ldap = LDAP_connect; LDAP_bind($ldap); my $ldapconf = $XB_Params::node_opts{'ldap'}; my $hostname = $ldapconf->{hostname}; my $server = $ldapconf->{server}; my $scope = $ldapconf->{scope}; my $dir = "registry"; if ( $ldapconf->{scope} !~ /(global)/i){ $dir = "privateregistry"; } eval { # create a group entry if that doesnt already exist. $dn = "cn=$server,ou=$dir,ou=local,ou=xbone"; my $mesg = $ldap->search( # perform a search base => $dn, filter => "(objectClass=XBoneGroup)" ); if ( $mesg->code ) { $@ = ""; @reghash = [ 'objectclass' => 'XBoneGroup', 'cn' => $server, ]; $result = $ldap->add($dn, 'attr' => @reghash); $result->code and XB_Log::log ("debug3", $result->error) and die("search"); } else { #XB_Log::log ("debug3", "Group node already exists. ". # "So dont bother"); } }; if ($@) { XB_Log::log ("err", "Either the oid $dn does not " . "exist or cannot be created. $@ "); die("search"); }; # Now create the host-specific entry. $dn = "cn=$hostname,cn=$server,ou=$dir,ou=local,ou=xbone"; # copy the necessary attributes my @xbattr = (); foreach my $attr (keys %{$attrhash}){ next if ($attr eq "enable"); next if ($attr eq "variable"); my $val = $attrhash->{$attr}; my $entry = "\'$attr = $val\'"; push (@xbattr, $entry); }; @reghash = [ 'objectclass' => 'XBoneInstance', 'cn' => $hostname, 'xbattr' => \@xbattr ]; # delete the old entry and ignore the result $result = $ldap->delete($dn); # now create the new entry $result = $ldap->add($dn, 'attr' => @reghash); $result->code and XB_Log::log ("debug3", $result->error) and die "add"; LDAP_unbind($ldap); }; #XB_Log::log "info", "<- $modname$procname"; return 1 unless $@; unless ($@ =~ /^(unbind|bind|connect|add)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; }; # Description: # delete an entry # Arguments: # XXX ? what should be passed to this function? # Returns: # # Exceptions: # sub LDAP_unregister () { my $ldap; my $procname = "LDAP_unregister"; #XB_Log::log "info", "-> $modname$procname"; my $result; eval { #=> connect to the server; $ldap = LDAP_connect; LDAP_bind($ldap); my $ldapconf = $XB_Params::node_opts{'ldap'}; my $hostname = $ldapconf->{hostname}; my $server = $ldapconf->{server}; my $dir = "registry"; if ( $ldapconf->{scope} !~ /(global)/i){ $dir = "privateregistry"; } my $dn = "cn=$hostname,cn=$server,ou=$dir,ou=local,ou=xbone"; $result = $ldap->delete($dn); $result->code and XB_Log::log ("debug3", $result->error) and die "delete"; LDAP_unbind($ldap); }; #XB_Log::log "info", "<- $modname$procname"; return ($result) unless $@; unless ($@ =~ /^(unbind|bind|connect|delete)/){ XB_Log::log "warning", " ! $procname caught unexpected exception $@"; } die "$modname$procname"; }; 1; __END__