Git Product home page Git Product logo

net-ldapapi's Introduction

The Net::LDAPapi Perl Module uses the OpenLDAP and Mozilla C api's to directly access and manipulate an LDAP v2 or LDAP v3 server.

net-ldapapi's People

Contributors

hyc avatar phillipod avatar quanah avatar rra avatar spacetrout avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

net-ldapapi's Issues

Asynchronous bind from the Perl OO API calls ldap_sasl_bind with invalid arguments

This code:

#!/usr/bin/perl
use Net::LDAPapi;
my $ld = Net::LDAPapi->new("localhost");
my $msg = $ld->bind(-dn => "cn=admin,dc=example,dc=com", -password => "password");

Results in:

# perl bind-test.pl
Usage: Net::LDAPapi::ldap_sasl_bind(ld, dn, passwd, sctrls, serverctrls, clientctrls, msgidp) at /usr/local/lib/perl/5.14.2/Net/LDAPapi.pm line 469.

Looks like the prototype for ldap_sasl_bind() in LDAPapi.xs is wrong - notice the 'sctrls' and 'serverctrls':

int
ldap_sasl_bind(ld, dn, passwd, sctrls, serverctrls, clientctrls, msgidp)
    LDAP *          ld
    LDAP_CHAR *     dn
    LDAP_CHAR *     passwd
    LDAPControl **  serverctrls
    LDAPControl **  clientctrls
    int             msgidp = NO_INIT
    CODE:
    { ... }

Remove support for the Mozilla LDAP SDK

The mozilla ldap SDK has been abandoned by Mozilla and is no longer maintained. For 3.1, we should remove any mention of it, and simply make the API conform to OpenLDAP's C API.

listen_for_changes(): cookie file must exist even for first run scenario

The listen_for_changes() function opens the cookie file and reads it. If the file does not exist, it warn()'s and does not proceed.

In the case of a first run, it's seems perfectly safe to allow the creation of the file if it does not exist. It's certainly much easier to use than having to create an empty file.

ldap_set_option(LDAP_OPT_TIMEOUT, 1) on OpenLDAP returns -1

See #20 for full background.

ldap_set_option() and ldap_get_option() do not have support to serialize/deserialize 'struct timeval' option objects, and so for example an invalid parameter is passed into the C ldap_set_option(), resulting in a -1 return.

Memory leak in Net::LDApapi listen_for_changes

We are seeing a slow but steady memory leak when using the listen_for_changes function from Net::LDAPapi. Here is code that I run that exhibits the problem:

sub listen_for_changes1 {

    my $this_base = 'cn=accesslog';
    my $this_filter = 'objectclass=*';
    my $this_cookie = '/var/run/ldap-sync-suprivilegegroup.cookie';
                                                                                              
    if (!(-e $this_cookie)) {
        open(my $f, q{>}, $this_cookie);
        close($f);
    }

    my $msgid = $LDAP->listen_for_changes(-basedn  => $this_base,
                                          -scope   => LDAP_SCOPE_SUBTREE,
                                          -filter  => $this_filter,
                                          -cookie  => $this_cookie);
    while (1) {
        while (my @entries = $LDAP->next_changed_entries($msgid, 0, -1)) {
        }
    }
}

If I run the above code and then continually make changes to the data, the memory use of the perl script slowly (but surely) increases until after about a week it is using up most of the memory on the server.

Here are the relevant Debian packages installed on this server:

ii  ldap-utils                         2.4.47+dfsg-1~bpo9+1su1
ii  libldap-2.4-2:amd64                2.4.47+dfsg-1~bpo9+1su1
ii  libldap-common                     2.4.47+dfsg-1~bpo9+1su1
ii  libnet-ldap-perl                   1:0.6500+dfsg-1
ii  libnet-ldapapi-perl                3.0.5-1~bpo9+1 

POD documentation inconsistencies

Hi,

The following LDAPapi.pm functions:

  • add
  • add_s
  • modify
  • modify_s

have the following documentation signatures:

=item add DN ATTR SCTRLS CCTRLS
=item add_s DN ATTR SCTRLS CCTRLS
=item modify DN MOD
=item modify_s DN MOD

They have the following rearrange() patterns:

sub add { $self->rearrange(['DN', 'MOD', 'SCTRLS', 'CCTRLS'], @args); }
sub add_s { $self->rearrange(['DN', 'MOD', 'SCTRLS', 'CCTRLS'], @args); }
sub modify {$self->rearrange(['DN', 'MOD', 'SCTRLS', 'CCTRLS'], @args); }
sub modify_s { $self->rearrange(['DN', 'MOD', 'SCTRLS', 'CCTRLS'], @args); }

This impacts the usability of the documentation for the add() and add_s() functions, as the uppercased names seem to indicate the name for named parameter passing.

Changing the POD wouldn't break existing working code, but the API then becomes murky.
Changing the code (to e.g., 'ATTR' for add() and add_s()) breaks code only currently working through knowledge of internals.

What're your thoughts?

Cheers,
Phillip

Server control requests get eaten after a NULL character in the berval

Hi,

I was looking into the syncrepl issue reported by Nat Sincheler, which I guess is the syncrepl issue you mentioned in #14. I don't think I've identified his issue, but we're definitely not handling BER correctly - in what appears to be a mirror of #28

net-ldapapi/LDAPapi.pm: 

sub create_control {
# SNIP
    my $status = ldap_create_control($oid, $berval, length($berval), $critical, $ctrl);
# SNIP
}

net-ldapapi/LDAPapi.xs:

int ldap_create_control(oid, bv_val, bv_len, iscritical, ctrlp) {
/* SNIP */
        ctrl->ldctl_value.bv_val = ber_strdup(bv_val);
        ctrl->ldctl_value.bv_len = bv_len;
/* SNIP */
}

openldap/libraries/liblber/memory.c:

char * ber_strdup( LDAP_CONST char *s ) {
        return ber_strdup_x( s, NULL );
}

char *ber_strdup_x( LDAP_CONST char *s, void *ctx ) {
        char    *p;
        size_t  len;
/* SNIP */
        len = strlen( s ) + 1;
        if ( (p = ber_memalloc_x( len, ctx )) != NULL ) {
                AC_MEMCPY( p, s, len );
        }

        return p;
}

If a berval containing an otherwise valid '\x00' byte is attempted to be passed, all data after the '\x00' byte will be discarded due to strlen() stopping at '\x00', say for instance the 'beforeCount' on a VLV control.

Using the sample code in #28, but changing 'beforeCount' to 0, I get this:

===== Server Side Sort and Virtual List View
 + Loading ASN for SortKeyList, SortResult, VirtualListViewRequest, VirtualListViewResponse
 + Constructing Server Side Sort control
sss ctrl berval =
[0000]   30 13 30 11  04 02 73 6E  80 08 32 2E  35 2E 31 33   0.0. ..sn ..2. 5.13
[0010]   2E 33 81 01  FF                                      .3.. .
 + Constructing Virtual List View control
vlv ctrl berval =
[0000]   30 0E 02 01  00 02 01 03  A0 06 02 01  01 02 01 00   0... .... .... ....
 + Searching for results
 - Fail
Protocol error
 + Parsing first entry
perl: error.c:255: ldap_parse_result: Assertion `r != ((void *)0)' failed.
Aborted

However, with the following change:

--- LDAPapi.xs.old      2015-06-14 04:54:23.000000000 +1200
+++ LDAPapi.xs  2015-12-01 00:53:17.000000000 +1300
@@ -1863,8 +1863,7 @@
         LDAPControl *ctrl = malloc(sizeof(LDAPControl));

         ctrl->ldctl_oid          = ber_strdup(oid);
-        ctrl->ldctl_value.bv_val = ber_strdup(bv_val);
-        ctrl->ldctl_value.bv_len = bv_len;
+       ber_str2bv(bv_val, bv_len, 1, &ctrl->ldctl_value);
         ctrl->ldctl_iscritical   = iscritical;

         ctrlp = ctrl;

I get this output:

===== Server Side Sort and Virtual List View
 + Loading ASN for SortKeyList, SortResult, VirtualListViewRequest, VirtualListViewResponse
 + Constructing Server Side Sort control
sss ctrl berval =
[0000]   30 13 30 11  04 02 73 6E  80 08 32 2E  35 2E 31 33   0.0. ..sn ..2. 5.13
[0010]   2E 33 81 01  FF                                      .3.. .
 + Constructing Virtual List View control
vlv ctrl berval =
[0000]   30 0E 02 01  00 02 01 03  A0 06 02 01  01 02 01 00   0... .... .... ....
 + Searching for results
 + Parsing first entry
result = $VAR1 = {
          'matcheddn' => undef,
          'referrals' => [],
          'errmsg' => undef,
          'serverctrls' => [
                             32738608,
                             27748368
                           ],
          'errcode' => 0
        };
 + Reading result-scope server response controls
 + Response control 32738608 [1.2.840.113556.1.4.474]
berval =
[0000]   30 03 0A 01  00                                      0... .
 + Parsing SSS response berval
$VAR1 = {
          'sortResult' => 0
        };
 + Response control 27748368 [2.16.840.1.113730.3.4.10]
berval =
[0000]   30 14 02 01  01 02 02 7E  B0 0A 01 00  04 08 50 0E   0... ...~ .... ..P.
[0010]   97 02 00 00  00 00                                   .... ..
 + Parsing VLV response berval
$VAR1 = {
          'contextID' => 'P',
          'contentCount' => 32432,
          'virtualListViewResult' => 0,
          'targetPosition' => 1
        };
 + Search results
dn: cn=Test User,ou=Users,o=Test Data,c=nz
dn: cn=Ani Odey,ou=Users,o=Test Data,c=nz
dn: cn=Vevelyn Odette,ou=Users,o=Test Data,c=nz
dn: cn=Donyetta Odett,ou=Users,o=Test Data,c=nz

To sum up - does it make sense to replace the ber_strdup() with ber_str2bv() in the XS wrapper ldap_create_control() ?

As I say, I don't think this is related to the syncrepl issue - but only because I don't see how a '\x00' character could be inserted into the BER of 'mode' on the syncRequestValue....

Perhaps there is another way we should be reading the user-provided BER? Otherwise, I'm happy to prepare a pull request for this, targeting a 3.0.5 or 3.1.x release

Cheers,
Phillip

Release planning

So the point raised in #13 regarding moving to version 3.1.x is interesting.

I'd like to see an 3.0.x API compatible release with recent bugfixes and enhancements, and ideally, I'd like the developer test suite I'm working on shipped with this release, so as to aid development during the API changes.

However, if API changes are possible within 3.1.x, it may be worth considering a few other things as well - such as providing emulated versions of ldap_url_search() for OpenLDAP, dropping functions not common across the target SDK's, or otherwise gracefully handling the lack of the ldap_url_search() methods (use of the LDAP_VENDOR_NAME and LDAP_NOT_SUPPORTED might do the trick here, in which case it could target 3.0.4).

I'll setup a couple of milestones on github, one targeting 3.0.4 and one targeting 3.1.0 to aid planning.

Will keep this ticket open till the release plan has been completed.

search_s() clobbers ATTRS parameter

The following code:

print "===== SEARCH\n";

my $search_msg = $ld->search(
  -basedn => "o=Test Data,c=NZ",
  -scope => LDAP_SCOPE_SUBTREE,
  -filter => "(sn=Last)",
  -attrs => \@{['cn']},
  -attrsonly => 0);

my $search_result = $ld->parse_result($ld->result($search_msg));

if ($search_result->{'errcode'} != LDAP_SUCCESS) {
  print "- Fail\n";
}

for (my $entry = $ld->first_entry(); $entry; $entry = $ld->next_entry) {
  print "dn: " . $ld->get_dn() . "\n";

  for (my $attribute = $ld->first_attribute; $attribute; $attribute = $ld->next_attribute) {
    foreach my $value ($ld->get_values($attribute)) {
      print $attribute . ": " . $value . "\n";
    }
  }
}

print "===== SEARCH_S\n";

my $search_s_result = $ld->search_s(
  -basedn => "o=Test Data,c=NZ",
  -scope => LDAP_SCOPE_SUBTREE,
  -filter => "(sn=Last)",
  -attrs => \@{['cn']},
  -attrsonly => 0);

if ($search_s_result != LDAP_SUCCESS) {
  print "- Fail\n";
}

for (my $entry = $ld->first_entry(); $entry; $entry = $ld->next_entry) {
  print "dn: " . $ld->get_dn() . "\n";

  for (my $attribute = $ld->first_attribute; $attribute; $attribute = $ld->next_attribute) {
    foreach my $value ($ld->get_values($attribute)) {
      print $attribute . ": " . $value . "\n";
    }
  }
}

produces the following output:

===== SEARCH
dn: cn=Full,ou=Users,o=Test Data,c=nz
cn: Full
===== SEARCH_S
dn: cn=Full,ou=Users,o=Test Data,c=nz
cn: Full
sn: Last
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
givenName: First

search() looks like the following:

sub search
{
...;
    if( !defined($attrs) ) {
        my @null_array = ();
        $attrs = \@null_array;
    }
...
}

search_s() looks like the following:

sub search_s
{
...;
    if( !defined($attrs) == undef ) {
        my @null_array = ();
        $attrs = \@null_array;
    }
...;
}

I think the conditional in search_s() is being parsed as:

if (!(defined($attrs) == undef)) {
}

In effect, if $attrs isn't passed at all, it's essentially a NOP - $attrs = undef and defined(undef) == undef.
But if $attrs is passed, defined($attrs) != undef - so the negation proceeds into the conditional block.

I'll submit a pull request for this shortly. :)

syncrepl cookie should be an opaque value

#23 not-withstanding, listen_for_changes() currently requires a path to an existing file (see #22). For a new API in 3.1, it should not be tied to a file - it should be the responsibility of the calling application to persist the sync cookie.

In order to maintain feature parity and minimise disruption to API consumers, a Perl-level helper could be provided that implements the same semantics.

ldap_result() doesn't honour passed timeout value.

This code blocks indefinitely:

print "===== LISTEN_FOR_CHANGES / NEXT_CHANGED_ENTRIES\n";

my $listen_msg = $ld->listen_for_changes(
  -basedn => "dc=example,dc=com",
  -scope => LDAP_SCOPE_SUBTREE,
  -filter => "(objectClass=*)",
  -cookie => "/tmp/tmp.cookie", # has to exist first, even for first-run. There will be a pull request...
);

# First result should be Sync Info (LDAP_RES_INTERMEDIATE)
@entries = $ld->next_changed_entries($listen_msg, 0, 1);

# Second result should be empty if run after cookie has been updated,
# and therefore the timeout of "1" should be honoured
@entries = $ld->next_changed_entries($listen_msg, 0, 1);

LDAPapi.xs has this:

int
ldap_result(ld, msgid, all, timeout, result)
   ... 
   CODE:
    {
        struct timeval *tv_timeout = NULL, timeoutbuf;
        if (atof(timeout) > 0 && timeout && *timeout) { ... }
        RETVAL = ldap_result(ld, msgid, all, NULL, &result);
    }
   ...

The NULL parameter being passed is the timeout.

The result of this is that on OpenLDAP ldap_result() will use whatever has been set by ldap_set_options(), with the default being to wait forever (equivalent to timeout being set to -1), while Mozilla LDAP's ldap_result() will just wait forever.

In effect, synchronous operations work perfectly - but the asynchronous API does not - once ldap_result() is called, it's synchronous for the scope of of the all parameter unless a timeout has been set by ldap_set_options().

Note that fixing this has a knock-on impact to actually using next_changed_entries() in a timeout environment as next_changed_entries() does not support the case where a timeout has occurred.

I'll create a pull request to resolve both these things. Happily the test suite in #5 will already test the majority of the frequently consumed synchronous and asynchronous API .

result() blocking when called with output from rename()

Following code blocks:

print "===== RENAME\n";

my $rename_msg = $ld->rename(-dn => 'cn=Test User,dc=example,dc=com', -newrdn => 'cn=Test User', -newsuper => 'ou=Users,dc=example,dc=com');
my $rename_result = {$ld->parse_result($ld->result($rename_msg, 0))};

print $ld->{"status"} . "\n";
print Dumper($rename_result) . "\n";
print $ld->errstring . "\n";

if ($rename_result->{'errcode'} != LDAP_SUCCESS) {
  print "- Fail\n";
}

LDAPapi.xs/ldap_rename does not include msgidp in OUTPUT list.

int
ldap_rename(ld, dn, newrdn, newSuperior, deleteoldrdn, sctrls, cctrls, msgidp)
    LDAP *         ld
    LDAP_CHAR *    dn
    LDAP_CHAR *    newrdn
    LDAP_CHAR *    newSuperior
    int            deleteoldrdn
    LDAPControl ** sctrls
    LDAPControl ** cctrls
    int            msgidp = NO_INIT
    CODE:
    {
        RETVAL = ldap_rename(ld, dn, newrdn, newSuperior,
                    deleteoldrdn, sctrls, cctrls, &msgidp);
    }
    OUTPUT:
    RETVAL

next_changed_entries function documentation needs clarification

The documentation for the next_changed_entries function shows that it takes three parameters: MSGID ALL TIMEOUT. The meaning of the second and third parameters is unclear.

If the solution is "they mean the same as for the result function", then something to that effect should be added to next_changed_entries's documentation.

Also, "This function is too be used together with listen_for_changes" should be "This function is to be used together with listen_for_changes " (emphasis added).

Improve test case code coverage

So the existing code coverage from testing (https://github.com/quanah/net-ldapapi/blob/master/net-ldapapi/trunk/test.pl) is:

---------------------------- ------ ------ ------ ------ ------ ------ ------
File                           stmt   bran   cond    sub    pod   time  total
---------------------------- ------ ------ ------ ------ ------ ------ ------
LDAPapi.xs                      6.4    2.6    n/a    n/a    n/a    n/a    5.0
blib/lib/Net/LDAPapi.pm        18.4    9.8   19.2   21.9   52.0  100.0   18.1
Total                          14.6    7.5   19.2   21.9   52.0  100.0   14.4
---------------------------- ------ ------ ------ ------ ------ ------ ------

or 14.4% code coverage.

So I've started adding BDD testing.

To see what I'm doing: master...phillipod:test-coverage

For what I've done so far, I've got:

---------------------------- ------ ------ ------ ------ ------ ------ ------
File                           stmt   bran   cond    sub    pod   time  total
---------------------------- ------ ------ ------ ------ ------ ------ ------
LDAPapi.xs                      6.4    2.6    n/a    n/a    n/a    n/a    5.0
blib/lib/Net/LDAPapi.pm        12.9    6.9   19.2   17.1   52.0  100.0   13.9
Total                          10.8    5.5   19.2   17.1   52.0  100.0   11.4
---------------------------- ------ ------ ------ ------ ------ ------ ------

Currently only 11.4% - but before I push on too far, any comments?

I like the BDD style - the test cases are easily understandable, etc etc.

But perhaps Test::BDD::Cucumber is an odd requirement - perhaps only run the BDD tests in a developer mode, keeping test.pl for installation verification?

Or I'm happy to consider an alternative approach..

ldap_search_ext() and ldap_search_ext_s() segfault when used with timeout

While undocumented in the POD, the OO interface exposes the time out parameter accepted by ldap_search_ext(_s)(). When used in an idiomatic manner, there is a segfault. See below example code and output:

print "===== SEARCH_S WITH TIMEOUT\n";

my $search_s_result = $ld->search_s(
  -basedn => "o=Test Data,c=NZ",
  -scope => LDAP_SCOPE_SUBTREE,
  -filter => "(sn=Last)",
  -attrs => ['cn', 'sn'],
  -attrsonly => 0,
  -timeout => 1);

if ($search_s_result != LDAP_SUCCESS) {
  print "- Fail\n";
}

for (my $entry = $ld->first_entry(); $entry; $entry = $ld->next_entry) {
  print "dn: " . $ld->get_dn() . "\n";

  for (my $attribute = $ld->first_attribute; $attribute; $attribute = $ld->next_attribute) {
    foreach my $value ($ld->get_values($attribute)) {
      print $attribute . ": " . $value . "\n";
    }
  }
}

Output:

===== SEARCH_S WITH TIMEOUT
Segmentation fault (core dumped)

Anaysis indicates that the XS wrappers ldap_search_ext(_s)() both expect a 'struct timeval *' passed from perl-space, which is strange considering ldap_result does accept idiomatic time outs.

See below function definition:

int
ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timeout, sizelimit, res)
    LDAP *           ld
    LDAP_CHAR *      base
    int              scope
    LDAP_CHAR *      filter
    SV *             attrs
    int              attrsonly
    LDAPControl **   sctrls
    LDAPControl **   cctrls
    struct timeval * timeout
    int              sizelimit
    LDAPMessage *    res = NO_INIT
    CODE:
    { ... }

I am currently working on a larger refactor in relation to timeouts in order to resolve #21

Future of the syncrepl consumer

Given the goal of maintaining parity with the underlying C API in #13, is a syncrepl consumer actually a valid component of core Net::LDAPapi?

There is an opportunity with 3.1 to introduce some sort of server control extension system where server control API implementations could reside..

Clarification of msgfree when used with next_changed_entries in doc

I would suggest you add the call to msgfree to the code fragment in the documentation for next_changed_entries. I had the msgfree OUTSIDE the loop because I was worried that msgfree would mess up the ldap object's listening. To avoid other users making that sort of mistake in the future, adding the msgfree call in the documentation for next_changed_entries would be helpful.

In other words, change this

   while(1) {
       while( @entries = $ld->next_changed_entries($msgid, 0, -1) ) {
           foreach $entry (@entries) {
               print "entry dn is <".$ld->get_dn($entry->{'entry'})."> ".
                   $entry->{'state'}."\n";
           }
       }
   }

to this

   while(1) {
       while( @entries = $ld->next_changed_entries($msgid, 0, -1) ) {
           foreach $entry (@entries) {
               print "entry dn is <".$ld->get_dn($entry->{'entry'})."> ".
                   $entry->{'state'}."\n";
           }
           $ld->msgfree();
       }
   }

RFE: Provide a polling mechanism

It would be nice if this library exposed the underlying TCP connection’s file descriptor so that it could be polled. The ldapwalk.pl demonstration of fetching an async response appears to rely on a function that blocks. Allowing an external event loop to poll the file descriptor would facilitate integration into event loops and such.

Thank you!

Server control responses get eaten after a NULL character in the berval

This is gonna be a long comment, so I'll present the data in this comment and move to a second comment.

This code...

print "===== Server Side Sort and Virtual List View\n";

use Convert::ASN1;
use Devel::Hexdump 'xd';
use Data::Dumper;

print " + Loading ASN for SortKeyList, SortResult, VirtualListViewRequest, VirtualListViewResponse\n";

my $asn = Convert::ASN1->new;
$asn->prepare(<<ASN) or die "prepare: ", $asn->error;
  SortKey ::= SEQUENCE {
    attributeType   OCTET STRING,
    orderingRule    [0] OCTET STRING OPTIONAL,
    reverseOrder    [1] BOOLEAN
  }

  SortKeyList ::= SEQUENCE OF SortKey

  SortResult ::= SEQUENCE {
    sortResult  ENUMERATED,
    attributeType [0] OCTET STRING OPTIONAL
  }

  VirtualListViewRequest ::= SEQUENCE {
    beforeCount    INTEGER,
    afterCount     INTEGER,
    target       CHOICE {
      byOffset        [0] SEQUENCE {
        offset          INTEGER,
        contentCount    INTEGER
      },
      greaterThanOrEqual [1] OCTET STRING
    },
    contextID OCTET STRING OPTIONAL
  }

  VirtualListViewResponse ::= SEQUENCE {
    targetPosition    INTEGER,
    contentCount     INTEGER,
    virtualListViewResult ENUMERATED,
    contextID OCTET STRING OPTIONAL
  }

ASN

print " + Constructing Server Side Sort control\n";
my $sss = $asn->find('SortKeyList');
my $sss_response = $asn->find('SortResult');
my $sss_berval = $sss->encode([{attributeType => 'sn', 'orderingRule' => '2.5.13.3', reverseOrder => 1}]) or die $asn->error;
my $sss_ctrl = $ld->create_control(
  -oid => '1.2.840.113556.1.4.473',
  -berval => $sss_berval,
);

print "sss ctrl berval = \n";
print xd $sss_berval;

print " + Constructing Virtual List View control\n";
my $vlv = $asn->find('VirtualListViewRequest');
my $vlv_response = $asn->find('VirtualListViewResponse');
my $vlv_berval = $vlv->encode(beforeCount => 1, afterCount => 3, target => { byOffset => { offset => 1, contentCount => 0 } }) or die $asn->error;;
my $vlv_ctrl = $ld->create_control(
  -oid => '2.16.840.1.113730.3.4.9',
  -berval => $vlv_berval,
);

print "vlv ctrl berval = \n";
print xd $vlv_berval;


print " + Searching for results\n";
my $search_s_result = $ld->search_s(
  -basedn => "dc=example,dc=com",
  -scope => LDAP_SCOPE_SUBTREE,
  -filter => "(sn=*)",
  -sctrls => [$sss_ctrl, $vlv_ctrl]);

if ($search_s_result != LDAP_SUCCESS) {
  print " - Fail\n";
  print $ld->errstring . "\n";
}

print " + Parsing first entry\n";


my $entry = $ld->first_entry();

my %search_s_response = $ld->parse_result();
print "result = ";
print Dumper(\%search_s_response);

print " + Reading result-scope server response controls\n";

my @response_sctrls = @{$search_s_response{'serverctrls'}};

foreach my $response_sctrl (@response_sctrls) {
  my $oid = $ld->get_control_oid($response_sctrl);
  my $berval = $ld->get_control_berval($response_sctrl);
  my $isCritical = $ld->get_control_critical($response_sctrl);

  my $result;

  print " + Response control $response_sctrl [" . $oid . "]\n";
  print "berval = \n";
  print xd $berval;

  if ($oid eq "1.2.840.113556.1.4.474") {
    print " + Parsing SSS response berval\n";

    $result = $sss_response->decode($berval) || warn $sss_response->error;

  } elsif ($oid eq "2.16.840.1.113730.3.4.10") {
    print " + Parsing VLV response berval\n";

    $result = $vlv_response->decode($berval) || warn $vlv_response->error;
  }

  #print Dumper($result);

}

print " + Search results\n";
for ( ; $entry; $entry = $ld->next_entry) {
  print "dn: " . $ld->get_dn() . "\n";
}

Produces

===== Server Side Sort and Virtual List View
 + Loading ASN for SortKeyList, SortResult, VirtualListViewRequest, VirtualListViewResponse
 + Constructing Server Side Sort control
sss ctrl berval =
[0000]   30 13 30 11  04 02 73 6E  80 08 32 2E  35 2E 31 33   0.0. ..sn ..2. 5.13
[0010]   2E 33 81 01  FF                                      .3.. .
 + Constructing Virtual List View control
vlv ctrl berval =
[0000]   30 0E 02 01  01 02 01 03  A0 06 02 01  01 02 01 00   0... .... .... ....
 + Searching for results
 + Parsing first entry
result = {
  'matcheddn' => undef,
  'referrals' => [],
  'errmsg' => undef,
  'serverctrls' => [
                     22959920,
                     22271136
                   ],
  'errcode' => 0
}
 + Reading result-scope server response controls
 + Response control 22959920 [1.2.840.113556.1.4.474]
berval =
[0000]   30 03 0A 01                                          0...
 + Parsing SSS response berval
decode error at /usr/share/perl5/Convert/ASN1/_decode.pm line 64.
 + Response control 22271136 [2.16.840.1.113730.3.4.10]
berval =
[0000]   30 14 02 01  01 02 02 7E  B0 0A 01                   0... ...~ ...
 + Parsing VLV response berval
decode error at /usr/share/perl5/Convert/ASN1/_decode.pm line 64.
 + Search results
dn: cn=Test User,ou=Users,dc=example,dc=com
dn: cn=Ani Odey,ou=Users,dc=example,dc=com
dn: cn=Vevelyn Odette,ou=Users,dc=example,dc=com
dn: cn=Donyetta Odett,ou=Users,dc=example,dc=com

Wireshark output for same PDU

    LDAPMessage searchResDone(2) success [4 results]
        messageID: 2
        protocolOp: searchResDone (5)
            searchResDone
                resultCode: success (0)
                matchedDN:
                errorMessage:
        controls: 2 items
            Control
                SortResult
                    sortResult: success (0)
            Control
                controlValue: 301402010102027eb00a01000408403a877c677f0000

Drop deprecated functions add/add_s

Drop deprecated API's add/add_s

Quoting quanah in #13,

Hm, this seems somewhat broken overall. add/add_s are part of the deprecated OpenLDAP API, and no longer available. The new fuctions are ldap_add_ext and ldap_add_ext_s, which both take dn, attrs, sctrls, cctrls. (I know the Net::LDAPapi code uses them behind the scenes). Overall, I'm fine with the following:

If we move to Net::LDAPapi version 3.1.x, we can change the API however we want. The original concept was to have parity with the underlying C API. Both Mozilla and OpenLDAP's C API's support add_ext(_s). I'd like to see the Net::LDAPapi code remove the deprecated functions, and then we can fix the function documentation to match the correct current C API functions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.