@@ -334,8 +334,9 @@ class LdapError < StandardError; end
334334 68 => "Entry Already Exists"
335335 }
336336
337- module LdapControls
338- PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
337+ module LDAPControls
338+ PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
339+ DELETE_TREE = "1.2.840.113556.1.4.805"
339340 end
340341
341342 def self . result2string ( code ) #:nodoc:
@@ -552,7 +553,7 @@ def open
552553 # anything with the bind results. We then pass self to the caller's
553554 # block, where he will execute his LDAP operations. Of course they will
554555 # all generate auth failures if the bind was unsuccessful.
555- raise Net :: LDAP :: LdapError , "Open already in progress" if @open_connection
556+ raise LdapError , "Open already in progress" if @open_connection
556557
557558 begin
558559 @open_connection = Net ::LDAP ::Connection . new ( :host => @host ,
@@ -1022,6 +1023,19 @@ def delete(args)
10221023 @result == 0
10231024 end
10241025
1026+ # Delete an entry from the LDAP directory along with all subordinate entries.
1027+ # the regular delete method will fail to delete an entry if it has subordinate
1028+ # entries. This method sends an extra control code to tell the LDAP server
1029+ # to do a tree delete. ('1.2.840.113556.1.4.805')
1030+ #
1031+ # Returns True or False to indicate whether the delete succeeded. Extended
1032+ # status information is available by calling #get_operation_result.
1033+ #
1034+ # dn = "[email protected] , ou=people, dc=example, dc=com" 1035+ # ldap.delete_tree :dn => dn
1036+ def delete_tree ( args )
1037+ delete ( args . merge ( :control_codes => [ [ LDAPControls ::DELETE_TREE , true ] ] ) )
1038+ end
10251039 # This method is experimental and subject to change. Return the rootDSE
10261040 # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if
10271041 # the server doesn't return the record.
@@ -1092,7 +1106,7 @@ def search_subschema_entry
10921106 #++
10931107 def paged_searches_supported?
10941108 @server_caps ||= search_root_dse
1095- @server_caps [ :supportedcontrol ] . include? ( Net :: LDAP :: LdapControls :: PagedResults )
1109+ @server_caps [ :supportedcontrol ] . include? ( LDAPControls :: PAGED_RESULTS )
10961110 end
10971111end # class LDAP
10981112
@@ -1389,7 +1403,7 @@ def search(args = {})
13891403 controls = [ ]
13901404 controls <<
13911405 [
1392- Net :: LDAP :: LdapControls :: PagedResults . to_ber ,
1406+ LDAPControls :: PAGED_RESULTS . to_ber ,
13931407 # Criticality MUST be false to interoperate with normal LDAPs.
13941408 false . to_ber ,
13951409 rfc2696_cookie . map { |v | v . to_ber } . to_ber_sequence . to_s . to_ber
@@ -1437,7 +1451,7 @@ def search(args = {})
14371451 more_pages = false
14381452 if result_code == 0 and controls
14391453 controls . each do |c |
1440- if c . oid == Net :: LDAP :: LdapControls :: PagedResults
1454+ if c . oid == LDAPControls :: PAGED_RESULTS
14411455 # just in case some bogus server sends us more than 1 of these.
14421456 more_pages = false
14431457 if c . value and c . value . length > 0
@@ -1545,9 +1559,9 @@ def rename args
15451559 #++
15461560 def delete ( args )
15471561 dn = args [ :dn ] or raise "Unable to delete empty DN"
1548-
1562+ controls = args . include? ( :control_codes ) ? args [ :control_codes ] . to_ber_control : nil #use nil so we can compact later
15491563 request = dn . to_s . to_ber_application_string ( 10 )
1550- pkt = [ next_msgid . to_ber , request ] . to_ber_sequence
1564+ pkt = [ next_msgid . to_ber , request , controls ] . compact . to_ber_sequence
15511565 @conn . write pkt
15521566
15531567 ( be = @conn . read_ber ( Net ::LDAP ::AsnSyntax ) ) && ( pdu = Net ::LDAP ::PDU . new ( be ) ) && ( pdu . app_tag == 11 ) or raise Net ::LDAP ::LdapError , "response missing or invalid"
0 commit comments