Dear reader, I still am unable to add or modify attributes of an DN entry. I've followed the suggestion from Graham Barr to check the result(error) code after execution of the ADD and MODIFY as well as change the DN used.Although no checks for errors were performed in the original script (which at this point is just an attempt to figure out how things work, and certainly not fit for use in an production environment), they are clearly visible in the dumped hash. Nevertheless I've added printing of verbose error info. The info displayed for DN tells me how many DN's were involved in the action? Two things in the duped hash intrigue me. First there is an empty 'changes' array and second no discernible value for 'matchedDN'. So the code now used is as followes: #!d:\perl\bin\perl.exe
use Data::Dumper; use Net::LDAP; use strict; my ($attr,$err,$ldap,$mesg,$userToAuthenticate,$passwd,@ocs,@atts,@bju_attrs,%add_attrs,%modify_attrs); @bju_attrs = qw ( givenName sn physicalDeliveryOfficeName telephoneNumber streetAddress postOfficeBox l st postalCode c co countryCode homePhone pager mobile facsimileTelephoneNumber ipPhone title department company manager directReports); $add_attrs { givenName } = "JustaName"; $modify_attrs {company} = "Roodbms"; $userToAuthenticate = $ARGV[0]; #print STDOUT ("userToAuthenticate= $userToAuthenticate\n"); $passwd = $ARGV[1]; #print STDOUT ("passwd= $passwd\n"); die "No credentials provided\n" if (! $userToAuthenticate or ! $passwd); $ldap = Net::LDAP->new ( "wserv02.roodbms" ) or die "$@"; $mesg = $ldap->bind ( "$userToAuthenticate", password => "$passwd", version => 3 ); print STDOUT ("After: bind\, mesg= \n".Dumper(%$mesg)."\n\n"); #my @Attrs = qw( ); # request all available attributes # to be returned. #my $result = LDAPsearch ( $ldap, "sn=ordinary", \...@attrs); my $result = LDAPsearch ( $ldap, "sn=ordinary", \...@bju_attrs); print STDOUT ("result= \n".Dumper(%$result)."\n\n"); print_result_by_entry($result); # # Now attempt to add/modify (a) value(s) to/of a DN # #my $dn = "DC=Roodbms,CN=Users,CN=ordinary"; # This is shown in LDAPExplorerTool2 my $dn = "CN=ordinary,CN=Users,DC=Roodbms"; # Changed as suggested by Graham Barr # # First attempt: ADD # foreach $attr (keys %add_attrs) { print STDOUT ("Adding attribute: $attr with value: ".$add_attrs{$attr}."\n"); } my $result = LDAPaddUsingHash ( $ldap, $dn, \%add_attrs ); $result = LDAPsearch ( $ldap, "sn=ordinary", \...@bju_attrs); print STDOUT ("result->code= ".$result->code."\n"); print STDOUT ("result (after add)= \n".Dumper(%$result)."\n\n"); print_result_by_entry($result); print STDOUT LDAPerror("Add",$result); # # Then attempt: MODIFY # foreach $attr (keys %modify_attrs) { print STDOUT ("\nModifying attribute: $attr to: ".$modify_attrs{$attr}."\n"); } my $result = LDAPmodifyUsingHash ( $ldap, $dn, \%modify_attrs ); $result = LDAPsearch ( $ldap, "sn=ordinary", \...@bju_attrs); print STDOUT ("result->code= ".$result->code."\n"); print STDOUT ("result (after modify)= \n".Dumper(%$result)."\n\n"); print_result_by_entry($result); print STDOUT LDAPerror("Modify",$result); $err = $ldap->unbind; # # Several functions to use # sub LDAPerror { my ($from, $mesg) = @_; print "Return code: ", $mesg->code."\n"; print "Message: ", $mesg->error_name; print ", ", $mesg->error_text; print "MessageID: ", $mesg->mesg_id."\n"; print "DN: ", $mesg->dn; #--- # Programmer note: # # "$mesg->error" DOESN'T work!!! # #print "\tMessage: ", $mesg->error; #----- } sub print_result_by_entry { my ($result) = @_; my @entries = $result->entries; my $entr; foreach $entr ( @entries ) { print "DN: ", $entr->dn, "\n"; my $attr; foreach $attr ( sort $entr->attributes ) { # skip binary we can't handle next if ( $attr =~ /;binary$/ ); print " $attr : ", $entr->get_value ( $attr ) ,"\n"; } print "#-------------------------------\n"; } } sub print_result_by_struct { my ($struct) = @_; #------------ # # Accessing the data as if in a structure # i.e. Using the "as_struct" method # my $href = $result->as_struct; # get an array of the DN names my @arrayOfDNs = keys %$href; # use DN hashes # process each DN using it as a key foreach ( @arrayOfDNs ) { print $_, "\n"; my $valref = $$href{$_}; # get an array of the attribute names # passed for this one DN. my @arrayOfAttrs = sort keys %$valref; #use Attr hashes my $attrName; foreach $attrName (@arrayOfAttrs) { # skip any binary data: yuck! next if ( $attrName =~ /;binary$/ ); # get the attribute value (pointer) using the # attribute name as the hash my $attrVal = @$valref{$attrName}; print "\t $attrName: @$attrVal \n"; } print "#-------------------------------\n"; } } sub LDAPsearch { my ($ldap,$searchString,$attrs,$base) = @_; # if they don't pass a base... set it for them if (!$base ) { $base = "dc=Roodbms"; } # if they don't pass an array of attributes... # set up something for them # if (!$attrs ) { $attrs = [ 'cn','mail' ]; } # if (!$attrs ) { $attrs = [ 'cn', 'userPrincipalName' ]; } my $result = $ldap->search ( base => "$base", scope => "sub", filter => "$searchString", attrs => $attrs ); return $result; } sub LDAPmodifyUsingHash { my ($ldap, $dn, $whatToChange ) = @_; my $entry = Net::LDAP::Entry->new('DN'); print STDOUT ("whatToChange= \n".Dumper(%$whatToChange)."\n\n"); # my $result = $ldap->modify ( $dn, # replace => { $whatToChange } # ); # return $result; $entry->changetype('modify'); $entry->replace(%$whatToChange); # for adding and updating # $entry->replace( "company" => "Roodbms"); $entry->update($ldap); return $entry; } sub LDAPaddUsingHash { my ($ldap, $dn, $whatToChange ) = @_; my $entry = Net::LDAP::Entry->new('DN'); $entry->changetype('add'); print STDOUT ("whatToChange= \n".Dumper(%$whatToChange)."\n\n"); # my $result = $ldap->modify ( $dn, # add => { $whatToChange } # ); # return $result; foreach my $attr (keys %$whatToChange) { $entry->add( $attr => $$whatToChange{$attr}); $entry->update($ldap); } return $entry; } This code has the following effect: After: bind, mesg= $VAR1 = 'parent'; $VAR2 = bless( { 'net_ldap_version' => 3, 'net_ldap_scheme' => 'ldap', 'net_ldap_debug' => 0, 'net_ldap_socket' => bless( \*Symbol::GEN0, 'IO::Socket::INET' ), 'net_ldap_host' => 'wserv02.roodbms', 'net_ldap_uri' => 'wserv02.roodbms', 'net_ldap_resp' => {}, 'net_ldap_mesg' => {}, 'net_ldap_async' => 0, 'net_ldap_port' => 389, 'net_ldap_refcnt' => 1 }, 'Net::LDAP' ); $VAR3 = 'errorMessage'; $VAR4 = ''; $VAR5 = 'ctrl_hash'; $VAR6 = undef; $VAR7 = 'resultCode'; $VAR8 = 0; $VAR9 = 'callback'; $VAR10 = undef; $VAR11 = 'mesgid'; $VAR12 = 1; $VAR13 = 'matchedDN'; $VAR14 = ''; $VAR15 = 'controls'; $VAR16 = undef; $VAR17 = 'raw'; $VAR18 = undef; result= $VAR1 = 'parent'; $VAR2 = bless( { 'net_ldap_version' => 3, 'net_ldap_scheme' => 'ldap', 'net_ldap_debug' => 0, 'net_ldap_socket' => bless( \*Symbol::GEN0, 'IO::Socket::INET' ), 'net_ldap_host' => 'wserv02.roodbms', 'net_ldap_uri' => 'wserv02.roodbms', 'net_ldap_resp' => {}, 'net_ldap_mesg' => {}, 'net_ldap_async' => 0, 'net_ldap_port' => 389, 'net_ldap_refcnt' => 1 }, 'Net::LDAP' ); $VAR3 = 'entries'; $VAR4 = [ bless( { 'changes' => [], 'changetype' => 'modify', 'asn' => { 'objectName' => 'CN=ordinary,CN=Users,DC=Roodbms', 'attributes' => [ { 'type' => 'sn', 'vals' => [ 'ordinary' ] }, { 'type' => 'title', 'vals' => [ 'Functienaam' ] }, { 'type' => 'company', 'vals' => [ 'BJU' ] }, { 'type' => 'countryCode', 'vals' => [ '0' ] } ] } }, 'Net::LDAP::Entry' ) ]; $VAR5 = 'errorMessage'; $VAR6 = ''; $VAR7 = 'ctrl_hash'; $VAR8 = undef; $VAR9 = 'resultCode'; $VAR10 = 0; $VAR11 = 'callback'; $VAR12 = undef; $VAR13 = 'matchedDN'; $VAR14 = ''; $VAR15 = 'mesgid'; $VAR16 = 2; $VAR17 = 'controls'; $VAR18 = undef; $VAR19 = 'raw'; $VAR20 = undef; DN: CN=ordinary,CN=Users,DC=Roodbms company : BJU countryCode : 0 sn : ordinary title : Functienaam #------------------------------- Adding attribute: givenName with value: JustaName whatToChange= $VAR1 = 'givenName'; $VAR2 = 'JustaName'; result->code= 0 result (after add)= $VAR1 = 'parent'; $VAR2 = bless( { 'net_ldap_version' => 3, 'net_ldap_scheme' => 'ldap', 'net_ldap_debug' => 0, 'net_ldap_socket' => bless( \*Symbol::GEN0, 'IO::Socket::INET' ), 'net_ldap_host' => 'wserv02.roodbms', 'net_ldap_uri' => 'wserv02.roodbms', 'net_ldap_resp' => {}, 'net_ldap_mesg' => {}, 'net_ldap_async' => 0, 'net_ldap_port' => 389, 'net_ldap_refcnt' => 1 }, 'Net::LDAP' ); $VAR3 = 'entries'; $VAR4 = [ bless( { 'changes' => [], 'changetype' => 'modify', 'asn' => { 'objectName' => 'CN=ordinary,CN=Users,DC=Roodbms', 'attributes' => [ { 'type' => 'sn', 'vals' => [ 'ordinary' ] }, { 'type' => 'title', 'vals' => [ 'Functienaam' ] }, { 'type' => 'company', 'vals' => [ 'BJU' ] }, { 'type' => 'countryCode', 'vals' => [ '0' ] } ] } }, 'Net::LDAP::Entry' ) ]; $VAR5 = 'errorMessage'; $VAR6 = ''; $VAR7 = 'ctrl_hash'; $VAR8 = undef; $VAR9 = 'resultCode'; $VAR10 = 0; $VAR11 = 'callback'; $VAR12 = undef; $VAR13 = 'matchedDN'; $VAR14 = ''; $VAR15 = 'mesgid'; $VAR16 = 4; $VAR17 = 'controls'; $VAR18 = undef; $VAR19 = 'raw'; $VAR20 = undef; DN: CN=ordinary,CN=Users,DC=Roodbms company : BJU countryCode : 0 sn : ordinary title : Functienaam #------------------------------- Return code: 0 Message: LDAP_SUCCESS, Operation completed without error MessageID: 4 DN: 1 Modifying attribute: company to: Roodbms whatToChange= $VAR1 = 'company'; $VAR2 = 'Roodbms'; result->code= 0 result (after modify)= $VAR1 = 'parent'; $VAR2 = bless( { 'net_ldap_version' => 3, 'net_ldap_scheme' => 'ldap', 'net_ldap_debug' => 0, 'net_ldap_socket' => bless( \*Symbol::GEN0, 'IO::Socket::INET' ), 'net_ldap_host' => 'wserv02.roodbms', 'net_ldap_uri' => 'wserv02.roodbms', 'net_ldap_resp' => {}, 'net_ldap_mesg' => {}, 'net_ldap_async' => 0, 'net_ldap_port' => 389, 'net_ldap_refcnt' => 1 }, 'Net::LDAP' ); $VAR3 = 'entries'; $VAR4 = [ bless( { 'changes' => [], 'changetype' => 'modify', 'asn' => { 'objectName' => 'CN=ordinary,CN=Users,DC=Roodbms', 'attributes' => [ { 'type' => 'sn', 'vals' => [ 'ordinary' ] }, { 'type' => 'title', 'vals' => [ 'Functienaam' ] }, { 'type' => 'company', 'vals' => [ 'BJU' ] }, { 'type' => 'countryCode', 'vals' => [ '0' ] } ] } }, 'Net::LDAP::Entry' ) ]; $VAR5 = 'errorMessage'; $VAR6 = ''; $VAR7 = 'ctrl_hash'; $VAR8 = undef; $VAR9 = 'resultCode'; $VAR10 = 0; $VAR11 = 'callback'; $VAR12 = undef; $VAR13 = 'matchedDN'; $VAR14 = ''; $VAR15 = 'mesgid'; $VAR16 = 6; $VAR17 = 'controls'; $VAR18 = undef; $VAR19 = 'raw'; $VAR20 = undef; DN: CN=ordinary,CN=Users,DC=Roodbms company : BJU countryCode : 0 sn : ordinary title : Functienaam #------------------------------- Return code: 0 Message: LDAP_SUCCESS, Operation completed without error MessageID: 6 DN: 1 As may be seen: although no discernble error (at least for me) has been detected, neither the ADD nor the MODIFY seems to have any effect. This still puzzles me. Thanks for any helpful suggestion(s)! Piet