Permalink
Browse files

Merge pull request #17 from marschap/next

preparation for the next release
  • Loading branch information...
2 parents 95c0049 + 4a0c544 commit 30373aaa8d5f80474f2ef53760475dd0253bdb48 @marschap committed Jan 26, 2013
View
@@ -5,7 +5,7 @@
package Net::LDAP;
use strict;
-use Socket qw(AF_INET AF_INET6 AF_UNSPEC);
+use Socket qw(AF_INET AF_INET6 AF_UNSPEC SOL_SOCKET SO_KEEPALIVE);
use IO::Socket;
use IO::Select;
use Tie::Hash;
@@ -105,7 +105,7 @@ sub new {
my $scheme = $arg->{scheme} || 'ldap';
my $h = $uri;
if (defined($h)) {
- $h =~ s,^(\w+)://,, and $scheme = $1;
+ $h =~ s,^(\w+)://,, and $scheme = lc($1);
$h =~ s,/.*,,; # remove path part
$h =~ s/%([A-Fa-f0-9]{2})/chr(hex($1))/eg; # unescape
}
@@ -119,6 +119,9 @@ sub new {
return undef unless $obj->{net_ldap_socket};
+ $obj->{net_ldap_socket}->setsockopt(SOL_SOCKET, SO_KEEPALIVE, $arg->{keepalive} ? 1 : 0)
+ if (defined($arg->{keepalive}));
+
$obj->{net_ldap_resp} = {};
$obj->{net_ldap_version} = $arg->{version} || $LDAP_VERSION;
$obj->{net_ldap_async} = $arg->{async} ? 1 : 0;
View
@@ -89,6 +89,14 @@ Port to connect to on the remote server. May be overridden by C<HOST>.
Connection scheme to use when not using an URI as C<HOST>.
(Default: ldap)
+=item keepalive =E<gt> 1
+
+If given, set the socket's SO_KEEPALIVE option depending on
+the boolean value of the option.
+(Default: use system default)
+
+Failures in changing the socket's SO_KEEPALIVE option are ignored.
+
=item timeout =E<gt> N
Timeout passed to L<IO::Socket> when connecting the remote server.
View
@@ -4,7 +4,7 @@
package Net::LDAP::Constant;
-our $VERSION = '0.17';
+our $VERSION = '0.18';
use Exporter qw(import);
@@ -632,6 +632,60 @@ Indicates if the server supports the Modify Increment extension (RFC 4525)
=back
+=head2 Active Directory Capability OIDs
+
+The following constants are specific to Microsoft Active Directory.
+They serve to denote capabilities via the non-standard attribute
+C<supportedCapabilities> in the Root DSE.
+
+=over 4
+
+=item LDAP_CAP_ACTIVE_DIRECTORY (1.2.840.113556.1.4.800)
+
+Indicates that the LDAP server is running Active Directory
+and is running as AD DS.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG (1.2.840.113556.1.4.1791)
+
+Indicates that the LDAP server on the DC is capable of signing and sealing
+on an NTLM authenticated connection, and that the server is capable of
+performing subsequent binds on a signed or sealed connection.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_V51 (1.2.840.113556.1.4.1670)
+
+On an Active Directory DC operating as AD DS, the presence of this capability
+indicates that the LDAP server is running at least the Windows 2003.
+
+On an Active Directory DC operating as AD LDS, the presence of this capability
+indicates that the LDAP server is running at least the Windows 2008.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_ADAM (1.2.840.113556.1.4.1851)
+
+Indicates that the LDAP server is running Active Directory as AD LDS.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_ADAM_DIGEST (1.2.840.113556.1.4.1880)
+
+Indicates on a DC operating as AD LDS,
+that the DC accepts DIGEST-MD5 binds for AD LDS security principals.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_PARTIAL_SECRETS (1.2.840.113556.1.4.1920)
+
+Indicates that the Active Directory DC operating as AD DS, is an RODC.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_V60 (1.2.840.113556.1.4.1935)
+
+Indicates that the LDAP server is running at least the Windows 2008.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_V61_R2 (1.2.840.113556.1.4.2080)
+
+Indicates that the LDAP server is running at least the Windows 2008 R2.
+
+=item LDAP_CAP_ACTIVE_DIRECTORY_W8 (1.2.840.113556.1.4.2237)
+
+Indicates that the LDAP server is running at least the Windows 2012.
+
+=back
+
=head1 SEE ALSO
L<Net::LDAP>,
@@ -106,7 +106,11 @@ Net::LDAP::Control::Paged - LDAPv3 Paged results control object
=head1 DESCRIPTION
C<Net::LDAP::Control::Paged> provides an interface for the creation and manipulation
-of objects that represent the C<pagedResultsControl> as described by RFC-2696.
+of objects that represent the C<pagedResultsControl> as described by RFC 2696.
+
+The control is allowed on LDAP search requests (L<Net::LDAP/search>) only.
+On other operations it will - depending on the value of the parameter
+C<critical> - either be ignored or lead to errors.
=head1 CONSTRUCTOR ARGUMENTS
@@ -139,7 +139,7 @@ authorization or data confidentiality, a single C<Proxy Authorization Control>
may be included in any search, compare, modify, add, delete, or moddn or
extended operation.
-As cqrequired by the RFC, the criticality of this control is automatically set to
+As required by the RFC, the criticality of this control is automatically set to
TRUE in order to protect clients from submitting requests with other identities
that they intend to.
@@ -80,7 +80,7 @@ Cancel an outstanding operation. C<OPERATION> may be a number or an
object which is a sub-class of L<Net::LDAP::Message>, returned from a
previous method call.
-OPTIONS is a list of key/value pairs. The following keys are reconized:
+OPTIONS is a list of key/value pairs. The following keys are recognized:
=over 4
@@ -72,7 +72,7 @@ by another method:
Send a refresh operation for an object.
-OPTIONS is a list of key/value pairs. The following keys are reconized:
+OPTIONS is a list of key/value pairs. The following keys are recognized:
=over 4
View
@@ -1220,6 +1220,87 @@ With groups, the same applies to the C<groupType> bit-field:
attrs => [ '1.1' ]
);
+=head2 How can I search for all members of a group in AD (including group nesting)?
+
+AD allows you to find all members of a specified group, the direct members
+plus those that are member of the group via group nesting.
+
+The trick to this is the special C<LDAP_MATCHING_RULE_IN_CHAIN> matching rule:
+
+ $mesg = $ldap->search( base => 'cn=Users,dc=your,dc=ads,dc=domain',
+ filter => '(memberOf:1.2.840.113556.1.4.1941:=cn=Testgroup,dc=your,dc=ads,dc=domain)',
+ attrs => [ '1.1' ]
+ );
+
+=head2 How can I search for all groups one user is a member of in AD (including group nesting)?
+
+Similarly you can search for all the groups one user is member of, either directly
+or via group nesting.
+
+ $mesg = $ldap->search( base => 'dc=your,dc=ads,dc=domain',
+ filter => '(member:1.2.840.113556.1.4.1941:=cn=TestUser,ou=Users,dc=your,dc=ads,dc=domain)',
+ attrs => [ '1.1' ]
+ );
+
+=head2 How do I search for all members of a large group in AD?
+
+AD normally restricts the number of attribute values returned in one query.
+The exact number depends on the AD server version: it was ~1000 in Win2000,
+1500 in Win2003 and is 5000 in Win2008 & Win2008R2.
+
+Performing the same standard search again will yield the same values again.
+
+So, how can you get all members of a really large AD group?
+
+The trick to use here is to use Microsoft's I<range option> when searching,
+i.e instead of doing one search for plain C<member>, perform multiple searches
+for e.g. C<member;range=1000-*> where the range starting index increases accordingly:
+
+ my $mesg;
+ my @members;
+ my $index = 0;
+
+ while ($index ne '*') {
+ $mesg = $ldap->search( base => 'cn=Testgroup,dc=your,dc=ads,dc=domain',
+ filter => '(objectclass=group)',
+ scope => 'base',
+ attrs => ($index > 0) ? "member;range=$index-*" : 'member'
+ );
+ if ($mesg->code == LDAP_SUCCESS) {
+ my $entry = $mesg->entry(0);
+ my $attr;
+
+ # large group: let's do the range option dance
+ if (($attr) = grep(/^member;range=/, $entry->attributes)) {
+ push(@members, $entry->get_value($attr));
+
+ if ($attr =~ /^member;range=\d+-(.*)$/) {
+ $index = $1;
+ $index++ if ($index ne '*');
+ }
+ }
+ # small group: no need for the range dance
+ else {
+ @members = $entry->get_value('member');
+ last;
+ }
+ }
+ # failure
+ else {
+ last;
+ }
+ }
+
+ if ($mesg->code == LDAP_SUCCESS) {
+ # success: @members contains the members of the group
+ }
+ else {
+ # failure: deal with the error in $mesg
+ }
+
+See L<http://msdn.microsoft.com/en-us/library/windows/desktop/aa367017.aspx>
+for more details.
+
=head2 How do I create a Microsoft Exchange 5.x user?
This is a solution provided by a perl-ldap user.
View
@@ -6,7 +6,7 @@ package Net::LDAP::Filter;
use strict;
-our $VERSION = '0.18';
+our $VERSION = '0.19';
# filter = "(" filtercomp ")"
# filtercomp = and / or / not / item
@@ -273,4 +273,24 @@ sub _string { # prints things of the form (<op> (<list>) ... )
die "Internal error $_[0]";
}
+sub negate {
+ my $self = shift;
+
+ %{$self} = _negate(%{$self});
+
+ $self;
+}
+
+sub _negate { # negate a filter tree
+ for ($_[0]) {
+ /^and/ and return ( 'or' => [ map { { _negate(%$_) }; } @{$_[1]} ] );
+ /^or/ and return ( 'and' => [ map { { _negate(%$_) }; } @{$_[1]} ] );
+ /^not/ and return %{$_[1]};
+ /^(present|equalityMatch|greaterOrEqual|lessOrEqual|approxMatch|substrings|extensibleMatch)/
+ and do return ( 'not' => { $_[0 ], $_[1] } );
+ }
+
+ die "Internal error $_[0]";
+}
+
1;
View
@@ -18,9 +18,10 @@ associated escaping mechanisms.
=over 4
-=item new ( FILTER )
+=item new ( [ FILTER ] )
-Create a new object and parse FILTER.
+Create a new object.
+If FILTER is given, parse it.
=back
@@ -30,7 +31,8 @@ Create a new object and parse FILTER.
=item parse ( FILTER )
-Parse FILTER. The next call to ber will return this filter encoded.
+Parse FILTER, updating the object to represent it.
+The next call to ber will return this filter encoded.
=item as_string
@@ -41,6 +43,23 @@ Return the filter in text form.
Print the text representation of the filter to FH, or the currently
selected output handle if FH is not given.
+=item negate ( )
+
+Logically negate/invert the filter object so that it matches the opposite
+set of entries as the original.
+
+Instead of simply negating the text form by surrounding it with the B<not>
+operator, the negation is done by recursively applying I<De Morgan's law>.
+
+Here is an example:
+
+ (|(&(cn=A)(cn=B))(|(!(cn=C))(cn=D)))
+
+gets negated to
+
+ (&(|(!(cn=A))(!(cn=B)))(&(cn=C)(!(cn=D))))
+
+
=back
=head1 FILTER SYNTAX
View
@@ -41,8 +41,8 @@ This method will block until the whole search request has finished.
=item entry ( INDEX )
-Return the N'th entry, which will be a L<Net::LDAP::Entry> object. If
-INDEX is greater than the total number of entries returned then
+Return the N'th entry (zero-based), which will be a L<Net::LDAP::Entry> object.
+If INDEX is greater or equal than the total number of entries returned then
C<undef> will be returned.
This method will block until the search request has returned enough
Oops, something went wrong.

0 comments on commit 30373aa

Please sign in to comment.