fakeldap 0.0.1 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +7 -1
  3. data/lib/fakeldap.rb +133 -10
  4. data/lib/fakeldap/version.rb +1 -1
  5. metadata +50 -191
  6. data/vendor/ruby-ldapserver/COPYING +0 -27
  7. data/vendor/ruby-ldapserver/ChangeLog +0 -83
  8. data/vendor/ruby-ldapserver/Manifest.txt +0 -32
  9. data/vendor/ruby-ldapserver/README +0 -222
  10. data/vendor/ruby-ldapserver/Rakefile +0 -22
  11. data/vendor/ruby-ldapserver/doc/LDAP.html +0 -104
  12. data/vendor/ruby-ldapserver/doc/LDAP/Abandon.html +0 -112
  13. data/vendor/ruby-ldapserver/doc/LDAP/Error.html +0 -115
  14. data/vendor/ruby-ldapserver/doc/LDAP/ResultError.html +0 -241
  15. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AdminLimitExceeded.html +0 -158
  16. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AffectsMultipleDSAs.html +0 -158
  17. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AliasDereferencingProblem.html +0 -158
  18. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AliasProblem.html +0 -158
  19. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AttributeOrValueExists.html +0 -158
  20. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AuthMethodNotSupported.html +0 -158
  21. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Busy.html +0 -158
  22. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/CompareFalse.html +0 -158
  23. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/CompareTrue.html +0 -158
  24. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ConfidentialityRequired.html +0 -158
  25. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ConstraintViolation.html +0 -158
  26. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/EntryAlreadyExists.html +0 -158
  27. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InappropriateAuthentication.html +0 -158
  28. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InappropriateMatching.html +0 -158
  29. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InsufficientAccessRights.html +0 -158
  30. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidAttributeSyntax.html +0 -158
  31. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidCredentials.html +0 -158
  32. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidDNSyntax.html +0 -158
  33. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/IsLeaf.html +0 -158
  34. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/LoopDetect.html +0 -158
  35. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NamingViolation.html +0 -158
  36. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NoSuchAttribute.html +0 -158
  37. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NoSuchObject.html +0 -158
  38. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NotAllowedOnNonLeaf.html +0 -158
  39. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NotAllowedOnRDN.html +0 -158
  40. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ObjectClassModsProhibited.html +0 -158
  41. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ObjectClassViolation.html +0 -158
  42. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/OperationsError.html +0 -158
  43. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Other.html +0 -158
  44. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ProtocolError.html +0 -158
  45. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Referral.html +0 -158
  46. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/SaslBindInProgress.html +0 -158
  47. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/SizeLimitExceeded.html +0 -158
  48. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/StrongAuthRequired.html +0 -158
  49. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Success.html +0 -158
  50. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/TimeLimitExceeded.html +0 -158
  51. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Unavailable.html +0 -158
  52. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UnavailableCriticalExtension.html +0 -158
  53. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UndefinedAttributeType.html +0 -158
  54. data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UnwillingToPerform.html +0 -158
  55. data/vendor/ruby-ldapserver/doc/LDAP/Server.html +0 -1056
  56. data/vendor/ruby-ldapserver/doc/LDAP/Server/Connection.html +0 -1353
  57. data/vendor/ruby-ldapserver/doc/LDAP/Server/Filter.html +0 -634
  58. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule.html +0 -1132
  59. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/DefaultMatchingClass.html +0 -219
  60. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Equality.html +0 -170
  61. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/IA5Downcase.html +0 -143
  62. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/IA5Trim.html +0 -155
  63. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Integer.html +0 -143
  64. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Ordering.html +0 -212
  65. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/StringDowncase.html +0 -143
  66. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/StringTrim.html +0 -154
  67. data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Substrings.html +0 -177
  68. data/vendor/ruby-ldapserver/doc/LDAP/Server/Operation.html +0 -2994
  69. data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema.html +0 -2024
  70. data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema/AttributeType.html +0 -1462
  71. data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema/ObjectClass.html +0 -1097
  72. data/vendor/ruby-ldapserver/doc/LDAP/Server/Syntax.html +0 -1254
  73. data/vendor/ruby-ldapserver/doc/LDAP/Server/VERSION.html +0 -134
  74. data/vendor/ruby-ldapserver/doc/_index.html +0 -662
  75. data/vendor/ruby-ldapserver/doc/class_list.html +0 -36
  76. data/vendor/ruby-ldapserver/doc/css/common.css +0 -1
  77. data/vendor/ruby-ldapserver/doc/css/full_list.css +0 -50
  78. data/vendor/ruby-ldapserver/doc/css/style.css +0 -303
  79. data/vendor/ruby-ldapserver/doc/file.README.html +0 -399
  80. data/vendor/ruby-ldapserver/doc/file_list.html +0 -38
  81. data/vendor/ruby-ldapserver/doc/frames.html +0 -13
  82. data/vendor/ruby-ldapserver/doc/index.html +0 -399
  83. data/vendor/ruby-ldapserver/doc/js/app.js +0 -204
  84. data/vendor/ruby-ldapserver/doc/js/full_list.js +0 -112
  85. data/vendor/ruby-ldapserver/doc/js/jquery.js +0 -154
  86. data/vendor/ruby-ldapserver/doc/method_list.html +0 -1571
  87. data/vendor/ruby-ldapserver/doc/top-level-namespace.html +0 -88
  88. data/vendor/ruby-ldapserver/examples/README +0 -89
  89. data/vendor/ruby-ldapserver/examples/mkcert.rb +0 -31
  90. data/vendor/ruby-ldapserver/examples/rbslapd1.rb +0 -111
  91. data/vendor/ruby-ldapserver/examples/rbslapd2.rb +0 -161
  92. data/vendor/ruby-ldapserver/examples/rbslapd3.rb +0 -172
  93. data/vendor/ruby-ldapserver/examples/speedtest.rb +0 -37
  94. data/vendor/ruby-ldapserver/lib/ldap/server.rb +0 -4
  95. data/vendor/ruby-ldapserver/lib/ldap/server/connection.rb +0 -276
  96. data/vendor/ruby-ldapserver/lib/ldap/server/filter.rb +0 -223
  97. data/vendor/ruby-ldapserver/lib/ldap/server/match.rb +0 -283
  98. data/vendor/ruby-ldapserver/lib/ldap/server/operation.rb +0 -487
  99. data/vendor/ruby-ldapserver/lib/ldap/server/preforkserver.rb +0 -93
  100. data/vendor/ruby-ldapserver/lib/ldap/server/result.rb +0 -71
  101. data/vendor/ruby-ldapserver/lib/ldap/server/schema.rb +0 -592
  102. data/vendor/ruby-ldapserver/lib/ldap/server/server.rb +0 -89
  103. data/vendor/ruby-ldapserver/lib/ldap/server/syntax.rb +0 -235
  104. data/vendor/ruby-ldapserver/lib/ldap/server/tcpserver.rb +0 -91
  105. data/vendor/ruby-ldapserver/lib/ldap/server/util.rb +0 -88
  106. data/vendor/ruby-ldapserver/lib/ldap/server/version.rb +0 -11
  107. data/vendor/ruby-ldapserver/test/core.schema +0 -582
  108. data/vendor/ruby-ldapserver/test/encoding_test.rb +0 -279
  109. data/vendor/ruby-ldapserver/test/filter_test.rb +0 -107
  110. data/vendor/ruby-ldapserver/test/match_test.rb +0 -59
  111. data/vendor/ruby-ldapserver/test/schema_test.rb +0 -113
  112. data/vendor/ruby-ldapserver/test/syntax_test.rb +0 -40
  113. data/vendor/ruby-ldapserver/test/test_helper.rb +0 -2
  114. data/vendor/ruby-ldapserver/test/util_test.rb +0 -51
@@ -1,172 +0,0 @@
1
- #!/usr/local/bin/ruby -w
2
-
3
- # This is similar to rbslapd1.rb but here we use TOMITA Masahiro's prefork
4
- # library: <http://raa.ruby-lang.org/project/prefork/>
5
- # Advantages over Ruby threading:
6
- # - each client connection is handled in its own process; don't need
7
- # to worry about Ruby thread blocking (except if one client issues
8
- # overlapping LDAP operations down the same connection, which is uncommon)
9
- # - better scalability on multi-processor systems
10
- # - better scalability on single-processor systems (e.g. shouldn't hit
11
- # max FDs per process limit)
12
- # Disadvantages:
13
- # - client connections can't share state in RAM. So our shared directory
14
- # now has to be read from disk, and flushed to disk after every update.
15
- #
16
- # Additionally, I have added schema support. An LDAP v3 client can
17
- # query the schema remotely, and adds/modifies have data validated.
18
-
19
- $:.unshift('../lib')
20
-
21
- require 'ldap/server'
22
- require 'ldap/server/schema'
23
- require 'yaml'
24
-
25
- $debug = nil # $stderr
26
-
27
- # An object to keep our in-RAM database and synchronise it to disk
28
- # when necessary
29
-
30
- class Directory
31
- attr_reader :data
32
-
33
- def initialize(filename)
34
- @filename = filename
35
- @stat = nil
36
- update
37
- end
38
-
39
- # synchronise with directory on disk (re-read if it has changed)
40
-
41
- def update
42
- begin
43
- tmp = {}
44
- sb = File.stat(@filename)
45
- return if @stat and @stat.ino == sb.ino and @stat.mtime == sb.mtime
46
- File.open(@filename) do |f|
47
- tmp = YAML::load(f.read)
48
- @stat = f.stat
49
- end
50
- rescue Errno::ENOENT
51
- end
52
- @data = tmp
53
- end
54
-
55
- # write back to disk
56
-
57
- def write
58
- File.open(@filename+".new","w") { |f| f.write(YAML::dump(@data)) }
59
- File.rename(@filename+".new",@filename)
60
- @stat = File.stat(@filename)
61
- end
62
-
63
- # run a block while holding a lock on the database
64
-
65
- def lock
66
- File.open(@filename+".lock","w") do |f|
67
- f.flock(File::LOCK_EX) # will block here until lock available
68
- yield
69
- end
70
- end
71
- end
72
-
73
- # We subclass the Operation class, overriding the methods to do what we need
74
-
75
- class DirOperation < LDAP::Server::Operation
76
- def initialize(connection, messageID, dir)
77
- super(connection, messageID)
78
- @dir = dir
79
- end
80
-
81
- def search(basedn, scope, deref, filter)
82
- $debug << "Search: basedn=#{basedn.inspect}, scope=#{scope.inspect}, deref=#{deref.inspect}, filter=#{filter.inspect}\n" if $debug
83
- basedn.downcase!
84
-
85
- case scope
86
- when LDAP::Server::BaseObject
87
- # client asked for single object by DN
88
- @dir.update
89
- obj = @dir.data[basedn]
90
- raise LDAP::ResultError::NoSuchObject unless obj
91
- ok = LDAP::Server::Filter.run(filter, obj)
92
- $debug << "Match=#{ok.inspect}: #{obj.inspect}\n" if $debug
93
- send_SearchResultEntry(basedn, obj) if ok
94
-
95
- when LDAP::Server::WholeSubtree
96
- @dir.update
97
- @dir.data.each do |dn, av|
98
- $debug << "Considering #{dn}\n" if $debug
99
- next unless dn.index(basedn, -basedn.length) # under basedn?
100
- next unless LDAP::Server::Filter.run(filter, av) # attribute filter?
101
- $debug << "Sending: #{av.inspect}\n" if $debug
102
- send_SearchResultEntry(dn, av)
103
- end
104
-
105
- else
106
- raise LDAP::ResultError::UnwillingToPerform, "OneLevel not implemented"
107
-
108
- end
109
- end
110
-
111
- def add(dn, entry)
112
- entry = @schema.validate(entry)
113
- entry['createTimestamp'] = [Time.now.gmtime.strftime("%Y%m%d%H%MZ")]
114
- entry['creatorsName'] = [@connection.binddn.to_s]
115
- # FIXME: normalize the DN and check it's below our root DN
116
- # FIXME: validate that a superior object exists
117
- # FIXME: validate that entry contains the RDN attribute (yuk)
118
- dn.downcase!
119
- @dir.lock do
120
- @dir.update
121
- raise LDAP::ResultError::EntryAlreadyExists if @dir.data[dn]
122
- @dir.data[dn] = entry
123
- @dir.write
124
- end
125
- end
126
-
127
- def del(dn)
128
- dn.downcase!
129
- @dir.lock do
130
- @dir.update
131
- raise LDAP::ResultError::NoSuchObject unless @dir.data.has_key?(dn)
132
- @dir.data.delete(dn)
133
- @dir.write
134
- end
135
- end
136
-
137
- def modify(dn, ops)
138
- dn.downcase!
139
- @dir.lock do
140
- @dir.update
141
- entry = @dir.data[dn]
142
- raise LDAP::ResultError::NoSuchObject unless entry
143
- entry = @schema.validate(ops, entry) # also does the update
144
- entry['modifyTimestamp'] = [Time.now.gmtime.strftime("%Y%m%d%H%MZ")]
145
- entry['modifiersName'] = [@connection.binddn.to_s]
146
- @dir.data[dn] = entry
147
- @dir.write
148
- end
149
- end
150
- end
151
-
152
- directory = Directory.new("ldapdb.yaml")
153
-
154
- schema = LDAP::Server::Schema.new
155
- schema.load_system
156
- schema.load_file("../test/core.schema")
157
- schema.resolve_oids
158
-
159
- s = LDAP::Server.new(
160
- :port => 1389,
161
- :nodelay => true,
162
- :listen => 10,
163
- # :ssl_key_file => "key.pem",
164
- # :ssl_cert_file => "cert.pem",
165
- # :ssl_on_connect => true,
166
- :operation_class => DirOperation,
167
- :operation_args => [directory],
168
- :schema => schema,
169
- :namingContexts => ['dc=example,dc=com']
170
- )
171
- s.run_prefork
172
- s.join
@@ -1,37 +0,0 @@
1
- #!/usr/local/bin/ruby
2
-
3
- require 'ldap'
4
-
5
- CHILDREN = 10
6
- CONNECTS = 1 # per child
7
- SEARCHES = 100 # per connection
8
-
9
- pids = []
10
- CHILDREN.times do
11
- pids << fork do
12
- CONNECTS.times do
13
- conn = LDAP::Conn.new("localhost",1389)
14
- conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
15
- conn.bind
16
- SEARCHES.times do
17
- res = conn.search("cn=Fred Flintstone,dc=example,dc=com", LDAP::LDAP_SCOPE_BASE,
18
- "(objectclass=*)") do |e|
19
- #puts "#{$$} #{e.dn.inspect}"
20
- end
21
- end
22
- conn.unbind
23
- end
24
- end
25
- end
26
- okcount = 0
27
- badcount = 0
28
- pids.each do |p|
29
- Process.wait(p)
30
- if $?.exitstatus == 0
31
- okcount += 1
32
- else
33
- badcount += 1
34
- end
35
- end
36
- puts "Children finished: #{okcount} ok, #{badcount} failed"
37
- exit badcount > 0 ? 1 : 0
@@ -1,4 +0,0 @@
1
- require 'ldap/server/result'
2
- require 'ldap/server/connection'
3
- require 'ldap/server/operation'
4
- require 'ldap/server/server'
@@ -1,276 +0,0 @@
1
- require 'thread'
2
- require 'openssl'
3
- require 'ldap/server/result'
4
-
5
- module LDAP
6
- class Server
7
-
8
- # An object which handles an LDAP connection. Note that LDAP allows
9
- # requests and responses to be exchanged asynchronously: e.g. a client
10
- # can send three requests, and the three responses can come back in
11
- # any order. For that reason, we start a new thread for each request,
12
- # and we need a mutex on the io object so that multiple responses don't
13
- # interfere with each other.
14
-
15
- class Connection
16
- attr_reader :binddn, :version, :opt
17
-
18
- def initialize(io, opt={})
19
- @io = io
20
- @opt = opt
21
- @mutex = Mutex.new
22
- @active_reqs = {} # map message ID to thread object
23
- @binddn = nil
24
- @version = 3
25
- @logger = @opt[:logger] || $stderr
26
- @ssl = false
27
-
28
- startssl if @opt[:ssl_on_connect]
29
- end
30
-
31
- def log(msg)
32
- @logger << "[#{@io.peeraddr[3]}]: #{msg}\n"
33
- end
34
-
35
- def startssl # :yields:
36
- @mutex.synchronize do
37
- raise LDAP::ResultError::OperationsError if @ssl or @active_reqs.size > 0
38
- yield if block_given?
39
- @io = OpenSSL::SSL::SSLSocket.new(@io, @opt[:ssl_ctx])
40
- @io.sync_close = true
41
- @io.accept
42
- @ssl = true
43
- end
44
- end
45
-
46
- # Read one ASN1 element from the given stream.
47
- # Return String containing the raw element.
48
-
49
- def ber_read(io)
50
- blk = io.read(2) # minimum: short tag, short length
51
- throw(:close) if blk.nil?
52
-
53
- codepoints = blk.respond_to?(:codepoints) ? blk.codepoints.to_a : blk
54
-
55
- tag = codepoints[0] & 0x1f
56
- len = codepoints[1]
57
-
58
- if tag == 0x1f # long form
59
- tag = 0
60
- while true
61
- ch = io.getc
62
- blk << ch
63
- tag = (tag << 7) | (ch & 0x7f)
64
- break if (ch & 0x80) == 0
65
- end
66
- len = io.getc
67
- blk << len
68
- end
69
-
70
- if (len & 0x80) != 0 # long form
71
- len = len & 0x7f
72
- raise LDAP::ResultError::ProtocolError, "Indefinite length encoding not supported" if len == 0
73
- offset = blk.length
74
- blk << io.read(len)
75
- # is there a more efficient way of doing this?
76
- len = 0
77
- blk[offset..-1].each_byte { |b| len = (len << 8) | b }
78
- end
79
-
80
- offset = blk.length
81
- blk << io.read(len)
82
- return blk
83
- # or if we wanted to keep the partial decoding we've done:
84
- # return blk, [blk[0] >> 6, tag], offset
85
- end
86
-
87
- def handle_requests
88
- operationClass = @opt[:operation_class]
89
- ocArgs = @opt[:operation_args] || []
90
- catch(:close) do
91
- while true
92
- begin
93
- blk = ber_read(@io)
94
- asn1 = OpenSSL::ASN1::decode(blk)
95
- # Debugging:
96
- # puts "Request: #{blk.unpack("H*")}\n#{asn1.inspect}" if $debug
97
-
98
- raise LDAP::ResultError::ProtocolError, "LDAPMessage must be SEQUENCE" unless asn1.is_a?(OpenSSL::ASN1::Sequence)
99
- raise LDAP::ResultError::ProtocolError, "Bad Message ID" unless asn1.value[0].is_a?(OpenSSL::ASN1::Integer)
100
- messageId = asn1.value[0].value
101
-
102
- protocolOp = asn1.value[1]
103
- raise LDAP::ResultError::ProtocolError, "Bad protocolOp" unless protocolOp.is_a?(OpenSSL::ASN1::ASN1Data)
104
- raise LDAP::ResultError::ProtocolError, "Bad protocolOp tag class" unless protocolOp.tag_class == :APPLICATION
105
-
106
- # controls are not properly implemented
107
- c = asn1.value[2]
108
- if c.is_a?(OpenSSL::ASN1::ASN1Data) and c.tag_class == :APPLICATION and c.tag == 0
109
- controls = c.value
110
- end
111
-
112
- case protocolOp.tag
113
- when 0 # BindRequest
114
- abandon_all
115
- @binddn, @version = operationClass.new(self,messageId,*ocArgs).
116
- do_bind(protocolOp, controls)
117
-
118
- when 2 # UnbindRequest
119
- throw(:close)
120
-
121
- when 3 # SearchRequest
122
- # Note: RFC 2251 4.4.4.1 says behaviour is undefined if
123
- # client sends an overlapping request with same message ID,
124
- # so we don't have to worry about the case where there is
125
- # already a thread with this id in @active_reqs.
126
- # However, to avoid a race we copy messageId/
127
- # protocolOp/controls into thread-local variables, because
128
- # they will change when the next request comes in.
129
- #
130
- # There is a theoretical race condition here: a client could
131
- # send an abandon request before Thread.current is assigned to
132
- # @active_reqs[thrm]. It's not a problem, because abandon isn't
133
- # guaranteed to work anyway. Doing it this way ensures that
134
- # @active_reqs does not leak memory on a long-lived connection.
135
-
136
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
137
- begin
138
- @active_reqs[thrm] = Thread.current
139
- operationClass.new(self,thrm,*ocArgs).do_search(thrp, thrc)
140
- ensure
141
- @active_reqs.delete(thrm)
142
- end
143
- end
144
-
145
- when 6 # ModifyRequest
146
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
147
- begin
148
- @active_reqs[thrm] = Thread.current
149
- operationClass.new(self,thrm,*ocArgs).do_modify(thrp, thrc)
150
- ensure
151
- @active_reqs.delete(thrm)
152
- end
153
- end
154
-
155
- when 8 # AddRequest
156
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
157
- begin
158
- @active_reqs[thrm] = Thread.current
159
- operationClass.new(self,thrm,*ocArgs).do_add(thrp, thrc)
160
- ensure
161
- @active_reqs.delete(thrm)
162
- end
163
- end
164
-
165
- when 10 # DelRequest
166
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
167
- begin
168
- @active_reqs[thrm] = Thread.current
169
- operationClass.new(self,thrm,*ocArgs).do_del(thrp, thrc)
170
- ensure
171
- @active_reqs.delete(thrm)
172
- end
173
- end
174
-
175
- when 12 # ModifyDNRequest
176
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
177
- begin
178
- @active_reqs[thrm] = Thread.current
179
- operationClass.new(self,thrm,*ocArgs).do_modifydn(thrp, thrc)
180
- ensure
181
- @active_reqs.delete(thrm)
182
- end
183
- end
184
-
185
- when 14 # CompareRequest
186
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
187
- begin
188
- @active_reqs[thrm] = Thread.current
189
- operationClass.new(self,thrm,*ocArgs).do_compare(thrp, thrc)
190
- ensure
191
- @active_reqs.delete(thrm)
192
- end
193
- end
194
-
195
- when 16 # AbandonRequest
196
- abandon(protocolOp.value)
197
-
198
- else
199
- raise LDAP::ResultError::ProtocolError, "Unrecognised protocolOp tag #{protocolOp.tag}"
200
- end
201
-
202
- rescue LDAP::ResultError::ProtocolError, OpenSSL::ASN1::ASN1Error => e
203
- send_notice_of_disconnection(LDAP::ResultError::ProtocolError.new.to_i, e.message)
204
- throw(:close)
205
-
206
- # all other exceptions propagate up and are caught by tcpserver
207
- end
208
- end
209
- end
210
- abandon_all
211
- end
212
-
213
- def write(data)
214
- @mutex.synchronize do
215
- @io.write(data)
216
- @io.flush
217
- end
218
- end
219
-
220
- def writelock
221
- @mutex.synchronize do
222
- yield @io
223
- @io.flush
224
- end
225
- end
226
-
227
- def abandon(messageID)
228
- @mutex.synchronize do
229
- thread = @active_reqs.delete(messageID)
230
- thread.raise LDAP::Abandon if thread and thread.alive?
231
- end
232
- end
233
-
234
- def abandon_all
235
- return if @active_reqs.size == 0
236
- @mutex.synchronize do
237
- @active_reqs.each do |id, thread|
238
- thread.raise LDAP::Abandon if thread.alive?
239
- end
240
- @active_reqs = {}
241
- end
242
- end
243
-
244
- def send_unsolicited_notification(resultCode, opt={})
245
- protocolOp = [
246
- OpenSSL::ASN1::Enumerated(resultCode),
247
- OpenSSL::ASN1::OctetString(opt[:matchedDN] || ""),
248
- OpenSSL::ASN1::OctetString(opt[:errorMessage] || ""),
249
- ]
250
- if opt[:referral]
251
- rs = opt[:referral].collect { |r| OpenSSL::ASN1::OctetString(r) }
252
- protocolOp << OpenSSL::ASN1::Sequence(rs, 3, :IMPLICIT, :APPLICATION)
253
- end
254
- if opt[:responseName]
255
- protocolOp << OpenSSL::ASN1::OctetString(opt[:responseName], 10, :IMPLICIT, :APPLICATION)
256
- end
257
- if opt[:response]
258
- protocolOp << OpenSSL::ASN1::OctetString(opt[:response], 11, :IMPLICIT, :APPLICATION)
259
- end
260
- message = [
261
- OpenSSL::ASN1::Integer(0),
262
- OpenSSL::ASN1::Sequence(protocolOp, 24, :IMPLICIT, :APPLICATION),
263
- ]
264
- message << opt[:controls] if opt[:controls]
265
- write(OpenSSL::ASN1::Sequence(message).to_der)
266
- end
267
-
268
- def send_notice_of_disconnection(resultCode, errorMessage="")
269
- send_unsolicited_notification(resultCode,
270
- :errorMessage=>errorMessage,
271
- :responseName=>"1.3.6.1.4.1.1466.20036"
272
- )
273
- end
274
- end
275
- end # class Server
276
- end # module LDAP