I have a quick question about the Net::LDAP::LDIF module.
I noticed that the LDIF module requires the use of Net::LDAP::Entry objects since its methods are all against Entry objects...
The script snippet below is fully capable of updating the directory below, but I'd prefer to create LDIF files rather than direct updates.
If I uncomment these two lines, the script will update directly and it works.
#my $result = $dne->update($AD_ldap);
#$result->code && warn "failed to add entry for $user ", $result->error ;
Unfortunately, the LDIF file only contains the DN of the user followed by an add line like this:
dn: CN=Dan Cutler,OU=ClientX,DC=MyCompany,DC=com
MyCompany-ClientKey: ClientX
The LDIF file is missing everything else. (like "changetype: modify", and the new attribute name "MyCompany-ClientKey").
Any Suggestions?
Thanks!!
$AD_ldap = Net::LDAP->new($AD_host) or die "$@";
$ldif = new Net::LDAP::LDIF ('Mirgrate_ou_name_to_attr.ldif','w',
encode => 'base64',
change => '1');
# bind for searches using system account
my $AD_mesg = $AD_ldap->bind( $AD_bind_user, password => $AD_bind_pw, port => 3268);
if ($AD_mesg->code) { print "AD bind failed with ", $AD_mesg->code , "\n"; }
my $AD_result = $AD_ldap->search ( base => $base_dn,
filter => '(objectclass=organizationalUnit)',
scope => 'one',
attrs => ['name']
);
my @AD_entries = $AD_result->entries;
# Get AD OUs
print "AD OUs =========================================\n";
foreach my $ADentr ( @AD_entries ) {
my $name = $ADentr->get_value('name');
my $dn = $ADentr->dn();
print "Finding users under OU $dn with name = $name...\n";
my @users = users_under_ou($dn,'AD'); # sub returns all user DNs with scope=base and baseDN is the group DN
foreach my $user (@users) {
print "Modifying User $user setting MyCompany-ClientKey to $name\n";
my $dne = Net::LDAP::Entry->new;
$dne->dn($user);
$dne->changetype('modify');
$dne->add ( MyCompany-ClientKey => $name );
#my $result = $dne->update($AD_ldap);
#$result->code && warn "failed to add entry for $user ", $result->error ;
#$dne->dump();
$ldif->write($dne);
}
print "\n";
}
--Dan
I must still be missing something. I still get no changetype:modify or the new attr in the LDIF file.
I changed my $ldif line to be this:
$ldif = Net::LDAP::LDIF->new ('changes.ldif','w', changes => '1');
And the other lines to be this:
...
my $dne = Net::LDAP::Entry->new;
$dne->dn($user);
$dne->changetype('modify');
$dne->add ( MyCompany-ClientKey => $name );
$ldif->write_entry($dne);
}
}
$ldif->done();
Am I still missing something or doing something else wrong?
Thanks again Graham!
-----Original Message-----
From: Graham Barr [mailto:gb...@pobox.com]
Sent: Monday, November 29, 2010 4:47 PM
To: Dan Cutler
Cc: perl...@perl.org
Subject: Re: LDIF file instead of updating directory
On Nov 29, 2010, at 15:36 , Dan Cutler wrote:
> Hi all,
>
> I have a quick question about the Net::LDAP::LDIF module.
>
> I noticed that the LDIF module requires the use of Net::LDAP::Entry objects since its methods are all against Entry objects...
>
> The script snippet below is fully capable of updating the directory below, but I'd prefer to create LDIF files rather than direct updates.
If you create an LDIF object with
my $ldif = Net::LDAP::LDIF->new( "file.ldif", "w", changes => 1);
then you can call $ldif->write_entry($dne); for each entry
and call $ldif->done; at the end of your script. you should have an ldif file with changetype: modify entries in it.
Graham.
I always found it quite annoying that one needs two different
objects/methods when writing a Net:LLDAP:Entry to either a directory server
or an LDIF file.
With directory servers you can do
$entry->update($ldap)
while with LDIF you need
$ldif->write_entry($entry)
This always requires a distinction in the code path in the perl scripts
although LDIF makes a nice output when doing a "dry run", and Perl
should be able to do the RightThing(tm).
I have attached a patch that extends Net::LDAP::Entry->update
by accepting an Net::LDAP::LDIF object as a parameter too.
It would be great if this patch would make it into the next release
of perl-ldap.
Best regards
Peter
--
Peter Marschall
pe...@adpm.de
use Net::LDAP::Util qw(ldap_error_name ldap_error_text ldap_error_desc);
$result = $ldap->add( $dn, attr => [ %$attrs ] );
if ( $result->code ) {
$error = $result->code;
$errtxt = ldap_error_name( $result->code );
Log(" ERROR adding $dn: $errtxt");
$errtxt = ldap_error_text( $result->code );
Log(" ERROR adding $dn: $errtxt");
$errtxt = ldap_error_desc( $result->code );
Log(" ERROR adding $dn: $errtxt");
}
That gives me the following:
ERROR adding mail=MILLENNIUMTENS,o=site: LDAP_INVALID_SYNTAX
ERROR adding mail=MILLENNIUMTENS,o=site: Some part of the request
contained an invalid syntax. It could be a search with an invalid filter
or a request to modify the schema and the given schema has a bad syntax.
ERROR adding mail=MILLENNIUMTENS,o=site: Invalid syntax
If I set $ldap->debug(12) then a ton of info is written to STDERR that
contains the details I need (showing the value that caused the error).
Net::LDAP=HASH(0x2993f4) received:
0000 30 86: SEQUENCE {
0002 02 1: INTEGER = 5
0005 69 81: [APPLICATION 9] {
0007 0A 1: ENUM = 21
000A 04 0: STRING = ''
000C 04 74: STRING = 'Bad SMTP Address; not canonical form,
Attribute=mail, Value=MILLENNIUMTENS'
0058 : }
0058 : }
Is there a way in NET::LDAP to grab that error string other than
redirecting STDERR and parsing it? "LDAP_INVALID_SYNTAX" is not
particularly helpful in diagnosing why the syntax was invalid.
Thanks,
Rick
Use $result->error_text() to get that text. See the Net::LDAP::Message documentation...
Note that servers may not return anything helpful to you in that field. The LDAP RFCs tell you not to rely on its contents.
Chris