--- a/shelldap Wed Jan 13 11:14:26 2016 -0800
+++ b/shelldap Wed Jun 07 14:59:48 2017 -0700
@@ -138,6 +138,19 @@
=over 4
+=item B<paginate>
+
+Integer. If enabled, shelldap will attempt to use server side
+pagination to build listings. Note: if you're using this to avoid
+sizelimit errors, you'll likely need server configuration to raise the
+limits for paginated results.
+
+ --paginate 100
+
+=back
+
+=over 4
+
=item B<promptpass>
Force password prompting. Useful to temporarily override cached
@@ -341,7 +354,7 @@
inspect posixAccount organizationalUnit
inspect _schema
-The output is a list of found objectClasses, their schema heirarchy
+The output is a list of found objectClasses, their schema hierarchy
(up to 'top'), whether or not they are a structural class, and then
a merged list of all valid attributes for the given objectClasses.
Attributes are marked as either required or optional, and whether
@@ -448,15 +461,19 @@
LDAP_OTHER
LDAP_TIMEOUT
LDAP_NO_MEMORY
- LDAP_CONNECT_ERROR /;
+ LDAP_EXTENSION_PASSWORD_MODIFY
+ LDAP_CONNECT_ERROR
+ LDAP_CONTROL_PAGED /;
use Net::LDAP::Util qw/ canonical_dn ldap_explode_dn /;
use Net::LDAP::LDIF;
+use Net::LDAP::Extension::SetPassword;
+use Net::LDAP::Control::Paged;
use Data::Dumper;
use File::Temp;
use Algorithm::Diff;
use Carp 'confess';
use base 'Term::Shell';
-require Net::LDAP::Extension::SetPassword;
+
my $conf = $main::conf;
@@ -508,6 +525,17 @@
print "Cipher in use: ", $self->ldap()->cipher(), "\n";
}
+ # check for the pagination extension on the server early, and bail
+ # if necessary.
+ if ( $conf->{'paginate'} && $conf->{'paginate'} =~ /^\d+$/ && $conf->{'paginate'} > 0 ) {
+ unless ( $self->{'root_dse'}->supported_control(LDAP_CONTROL_PAGED) ) {
+ die "Server pagination is enabled, but the server doesn't seem to support it.\n";
+ }
+ }
+ else {
+ $conf->{'paginate'} = undef;
+ }
+
# try an initial search and bail early if it doesn't work. (bad baseDN?)
my $s = $self->search();
die "LDAP baseDN error: ", $s->{'message'}, "\n" if $s->{'code'};
@@ -873,7 +901,8 @@
}
-### Perform an LDAP search.
+### Perform an LDAP search, optionally with the server side pager
+### control.
###
### Returns a hashref containing the return code and
### an arrayref of Net::LDAP::Entry objects.
@@ -882,11 +911,18 @@
{
my $self = shift;
my $opts = shift || {};
+ my $controls = [];
$opts->{'base'} ||= $self->base(),
$opts->{'filter'} ||= '(objectClass=*)';
$opts->{'scope'} ||= 'base';
+ my $pager;
+ if ( $conf->{'paginate'} ) {
+ $pager = Net::LDAP::Control::Paged->new( size => $conf->{'paginate'} );
+ push( @$controls, $pager );
+ }
+
my $search = sub {
return $self->ldap->search(
base => $opts->{'base'},
@@ -894,19 +930,41 @@
scope => $opts->{'scope'},
timelimit => $conf->{'timeout'},
typesonly => ! $opts->{'vals'},
- attrs => $opts->{'attrs'} || ['*']
+ attrs => $opts->{'attrs'} || ['*'],
+ control => $controls
);
};
- my $s = $self->with_retry( $search );
+ my $s;
+ my $entries = [];
+ my $token = '-';
+
+ if ( $conf->{'paginate'} ) {
+ while( $token ) {
+ $s = $self->with_retry( $search );
+ push( @$entries, $s->entries() );
+
+ my $page_response = $s->control( LDAP_CONTROL_PAGED ) or last;
+ $token = $page_response->cookie;
+ $pager->cookie( $token );
+ }
+ }
+ else {
+ $s = $self->with_retry( $search );
+ $entries = [ $s->entries() ];
+ }
+
my $rv = {
code => $s->code(),
- message => $s->error(),
- entries => []
+ message => $s->error()
};
- $rv->{'entries'} =
- $opts->{'scope'} eq 'base' ? [ $s->shift_entry() ] : [ $s->entries() ];
+ if ( $opts->{'scope'} eq 'base' ) {
+ $rv->{'entries'} = [ $s->shift_entry() ]
+ }
+ else {
+ $rv->{'entries'} = $entries;
+ }
return $rv;
}
@@ -2116,8 +2174,7 @@
$self->{'root_dse'} ||= $self->ldap->root_dse();
- my $pw_extension = '1.3.6.1.4.1.4203.1.11.1';
- unless ( $self->{'root_dse'}->supported_extension( $pw_extension ) ) {
+ unless ( $self->{'root_dse'}->supported_extension(LDAP_EXTENSION_PASSWORD_MODIFY) ) {
print "Sorry, password changes not supported by LDAP server.\n";
return;
}
@@ -2275,7 +2332,7 @@
}
-### Recursively walk an objectClass heirarchy, returning an array
+### Recursively walk an objectClass hierarchy, returning an array
### of inheritence.
###
sub findall_supers
@@ -2303,7 +2360,7 @@
use warnings;
$0 = 'shelldap';
-my $VERSION = '1.3.2';
+my $VERSION = '1.4.0';
use Getopt::Long;
use YAML::Syck;
@@ -2322,6 +2379,7 @@
'binddn|D=s',
'basedn|b=s',
'cacheage=i',
+ 'paginate=i',
'promptpass|W',
'timeout=i',
'sasl|Y=s',