net-ldap 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of net-ldap might be problematic. Click here for more details.

data/History.txt CHANGED
@@ -1,5 +1,11 @@
1
- === Net::LDAP 0.0.5 / 2009-03-xx
1
+ === Net::LDAP 0.1.0 / 2010-03-08
2
+ * Small fixes throughout, more to come.
3
+ * Ruby 1.9 support added.
4
+ * Ruby 1.8.6 and below support removed. If we can figure out a compatible way
5
+ to reintroduce this, we will.
6
+ * New maintainers, new project repository location. Please see the README.txt.
2
7
 
8
+ === Net::LDAP 0.0.5 / 2009-03-xx
3
9
  * 13 minor enhancements:
4
10
  * Added Net::LDAP::Entry#to_ldif
5
11
  * Supported rootDSE searches with a new API.
@@ -21,7 +27,6 @@
21
27
  * Added support for binary values in Net::LDAP::Entry LDIF conversions
22
28
  and marshalling.
23
29
  * Migrated to 'hoe' as the new project droid.
24
-
25
30
  * 14 bugs fixed:
26
31
  * Silenced some annoying warnings in filter.rb. Thanks to "barjunk"
27
32
  for pointing this out.
@@ -47,7 +52,6 @@
47
52
  * Minor bug fixes here and there.
48
53
 
49
54
  === Net::LDAP 0.0.4 / 2006-08-15
50
-
51
55
  * Undeprecated Net::LDAP#modify. Thanks to Justin Forder for
52
56
  providing the rationale for this.
53
57
  * Added a much-expanded set of special characters to the parser
@@ -60,12 +64,10 @@
60
64
  called more than one on a given Net::LDAP object.
61
65
 
62
66
  === Net::LDAP 0.0.3 / 2006-07-26
63
-
64
67
  * Added simple TLS encryption.
65
68
  Thanks to Garett Shulman for suggestions and for helping test.
66
69
 
67
70
  === Net::LDAP 0.0.2 / 2006-07-12
68
-
69
71
  * Fixed malformation in distro tarball and gem.
70
72
  * Improved documentation.
71
73
  * Supported "paged search control."
@@ -80,7 +82,6 @@
80
82
  * Added support for RFC-2254 filter syntax.
81
83
 
82
84
  === Net::LDAP 0.0.1 / 2006-05-01
83
-
84
85
  * Initial release.
85
86
  * Client functionality is near-complete, although the APIs
86
87
  are not guaranteed and may change depending on feedback
data/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  Net::LDAP is copyrighted free software by Francis Cianfrocca
2
- <garbagecat10@gmail.com>. You can redistribute it and/or modify it under either
3
- the terms of the GPL (see the file COPYING), or the conditions below:
2
+ <garbagecat10@gmail.com> and other contributors. You can redistribute it and/or
3
+ modify it under either the terms of the GPL (see the file COPYING), or the
4
+ conditions below:
4
5
 
5
6
  1. You may make and give away verbatim copies of the source form of the
6
7
  software without restriction, provided that you duplicate all of the
data/Manifest.txt CHANGED
@@ -4,9 +4,17 @@ LICENSE
4
4
  Manifest.txt
5
5
  README.txt
6
6
  Rakefile
7
- Release-Announcement
7
+ lib/net-ldap.rb
8
8
  lib/net/ber.rb
9
+ lib/net/ber/ber_parser.rb
9
10
  lib/net/ldap.rb
11
+ lib/net/ldap/core_ext/all.rb
12
+ lib/net/ldap/core_ext/array.rb
13
+ lib/net/ldap/core_ext/bignum.rb
14
+ lib/net/ldap/core_ext/false_class.rb
15
+ lib/net/ldap/core_ext/fixnum.rb
16
+ lib/net/ldap/core_ext/string.rb
17
+ lib/net/ldap/core_ext/true_class.rb
10
18
  lib/net/ldap/dataset.rb
11
19
  lib/net/ldap/entry.rb
12
20
  lib/net/ldap/filter.rb
@@ -14,8 +22,10 @@ lib/net/ldap/pdu.rb
14
22
  lib/net/ldap/psw.rb
15
23
  lib/net/ldif.rb
16
24
  lib/net/snmp.rb
17
- pre-setup.rb
18
- setup.rb
25
+ spec/integration/ssl_ber_spec.rb
26
+ spec/spec.opts
27
+ spec/spec_helper.rb
28
+ spec/unit/ber/ber_spec.rb
19
29
  test/common.rb
20
30
  test/test_ber.rb
21
31
  test/test_entry.rb
@@ -24,7 +34,5 @@ test/test_ldif.rb
24
34
  test/test_password.rb
25
35
  test/test_snmp.rb
26
36
  test/testdata.ldif
27
- tests/NOTICE.txt
28
- tests/testldap.rb
29
37
  testserver/ldapserver.rb
30
38
  testserver/testdata.ldif
data/README.txt CHANGED
@@ -1,62 +1,68 @@
1
1
  = Net::LDAP for Ruby
2
2
 
3
- * http://rubyforge.org/projects/net-ldap
4
-
5
- == DESCRIPTION:
3
+ == Description
6
4
 
7
5
  Pure Ruby LDAP library.
8
6
 
9
- == FEATURES/PROBLEMS:
7
+ == Where
8
+
9
+ === Issues & Project Homepage
10
+
11
+ http://rubyforge.org/projects/net-ldap
12
+
13
+ === Code
10
14
 
11
- The Lightweight Directory Access Protocol (LDAP) is an Internet protocol
12
- for accessing distributed directory services.
15
+ http://github.com/RoryO/ruby-net-ldap/
13
16
 
14
- Net::LDAP is an LDAP support library written in pure Ruby. It supports
15
- most LDAP client features and a subset of server features as well.
17
+ == FEATURES/PROBLEMS
18
+
19
+ The Lightweight Directory Access Protocol (LDAP) is an Internet protocol for
20
+ accessing distributed directory services.
21
+
22
+ Net::LDAP is an LDAP support library written in pure Ruby. It supports most
23
+ LDAP client features and a subset of server features as well.
16
24
 
17
25
  * Standards-based (going for RFC 4511)
18
26
  * Portable: 100% Ruby
19
27
 
20
- == SYNOPSIS:
28
+ == SYNOPSIS
21
29
 
22
30
  See Net::LDAP for documentation and usage samples.
23
31
 
24
- == REQUIREMENTS:
32
+ == REQUIREMENTS
25
33
 
26
- Net::LDAP requires Ruby 1.8.2 or better.
34
+ Net::LDAP requires Ruby 1.8.7-compliant interpreter or better.
27
35
 
28
- == INSTALL:
36
+ == INSTALL
29
37
 
30
- Net::LDAP is a pure Ruby library. It does not require any external
31
- libraries.
32
-
33
- You can install the RubyGems version of Net::LDAP available from the
34
- usual sources.
38
+ Net::LDAP is a pure Ruby library. It does not require any external libraries.
39
+ You can install the RubyGems version of Net::LDAP available from the usual
40
+ sources.
35
41
 
36
42
  * gem install net-ldap
37
43
 
38
- If using the packaged (.tgz) version; it can be installed with:
39
-
40
- * ruby setup.rb
44
+ Simply require 'net/ldap'.
41
45
 
42
- == CREDITS:
46
+ == CREDITS
43
47
 
44
48
  Net::LDAP was originally developed by:
45
49
 
46
- * Francis Cianfrocca <garbagecat10@gmail.com>
50
+ * Francis Cianfrocca blackhedd@rubyforge.org
47
51
 
48
52
  Contributions since:
49
53
 
50
- * Austin Ziegler <halostatue@gmail.com>
51
- * Emiel van de Laar <gemiel@gmail.com>
54
+ * Emiel van de Laar emiel@rubyforge.org
55
+ * Rory O'Connell rory.ocon@gmail.com
56
+ * Kaspar Schiess eule@rubyforge.org
57
+ * Austin Ziegler austin@rubyforge.org
52
58
 
53
- == LICENSE:
59
+ == LICENSE
54
60
 
55
- Copyright (C) 2006 by Francis Cianfrocca
61
+ Copyright (C) 2006 - 2010 by Francis Cianfrocca and other contributors.
56
62
 
57
63
  Please read the file LICENSE for licensing restrictions on this library. In
58
64
  the simplest terms, this library is available under the same terms as Ruby
59
65
  itself.
60
66
 
61
- Available under the same terms as Ruby. See LICENSE in the main
62
- distribution for full licensing information.
67
+ Available under the same terms as Ruby. See LICENSE in the main distribution
68
+ for full licensing information.
data/Rakefile CHANGED
@@ -1,18 +1,122 @@
1
- # -*- ruby -*-
2
-
3
- require 'rubygems'
1
+ require "rubygems"
2
+ require 'hanna/rdoctask'
4
3
  require 'hoe'
5
4
 
6
- # Add 'lib' to load path.
7
- $LOAD_PATH.unshift( "#{File.dirname(__FILE__)}/lib" )
5
+ $LOAD_PATH.unshift('lib')
8
6
 
9
- # Pull in local 'net/ldap' as opposed to an installed version.
10
7
  require 'net/ldap'
11
8
 
12
- Hoe.new('net-ldap', Net::LDAP::VERSION) do |p|
13
- p.rubyforge_name = 'net-ldap'
14
- p.developer('Francis Cianfrocca', 'garbagecat10@gmail.com')
15
- p.developer('Emiel van de Laar', 'gemiel@gmail.com')
9
+ require "rake/gempackagetask"
10
+ require "rake/rdoctask"
11
+
12
+ PKG_NAME = 'net-ldap'
13
+ PKG_VERSION = Net::LDAP::VERSION
14
+ PKG_DIST = "#{PKG_NAME}-#{PKG_VERSION}"
15
+ PKG_TAR = "pkg/#{PKG_DIST}.tar.gz"
16
+ MANIFEST = File.read("Manifest.txt").split
17
+ MINRUBY = "1.8.7"
18
+
19
+ Hoe.plugin :git
20
+
21
+ Hoe.spec PKG_NAME do
22
+ self.version = PKG_VERSION
23
+ self.rubyforge_name = PKG_NAME
24
+
25
+ developer "Francis Cianfrocca", "blackhedd@rubyforge.org"
26
+ developer "Emiel van de Laar", "gemiel@gmail.com"
27
+ developer "Rory O'Connell", "rory.ocon@gmail.com"
28
+ developer "Kaspar Schiess", "kaspar.schiess@absurd.li"
29
+ developer "Austin Ziegler", "austin@rubyforge.org"
30
+
31
+ self.remote_rdoc_dir = ''
32
+ rsync_args << ' --exclude=statsvn/'
33
+
34
+ self.url = %W(http://net-ldap.rubyforge.org/ http://github.com/RoryO/ruby-net-ldap)
35
+
36
+ self.summary = "Pure Ruby LDAP support library with most client features and some server features."
37
+ self.changes = paragraphs_of(self.history_file, 0..1).join("\n\n")
38
+ self.description = paragraphs_of(self.readme_file, 2..2).join("\n\n")
39
+
40
+ extra_dev_deps << [ "archive-tar-minitar", "~>0.5.1" ]
41
+ extra_dev_deps << [ "hanna", "~>0.1.2" ]
42
+ extra_dev_deps << [ "hoe-git", "~>1" ]
43
+ clean_globs << "coverage"
44
+
45
+ spec_extras[:required_ruby_version] = ">= #{MINRUBY}"
46
+ multiruby_skip << "1.8.6"
47
+ multiruby_skip << "1_8_6"
48
+
49
+ # This is a lie because I will continue to use Archive::Tar::Minitar.
50
+ self.need_tar = false
51
+ end
52
+
53
+ desc "Build a Net-LDAP .tar.gz distribution."
54
+ task :tar => [ PKG_TAR ]
55
+ file PKG_TAR => [ :test ] do |t|
56
+ require 'archive/tar/minitar'
57
+ require 'zlib'
58
+ files = MANIFEST.map { |f|
59
+ fn = File.join(PKG_DIST, f)
60
+ tm = File.stat(f).mtime
61
+
62
+ if File.directory?(f)
63
+ { :name => fn, :mode => 0755, :dir => true, :mtime => tm }
64
+ else
65
+ mode = if f =~ %r{^bin}
66
+ 0755
67
+ else
68
+ 0644
69
+ end
70
+ data = File.read(f)
71
+ { :name => fn, :mode => mode, :data => data, :size => data.size,
72
+ :mtime => tm }
73
+ end
74
+ }
75
+
76
+ begin
77
+ unless File.directory?(File.dirname(t.name))
78
+ require 'fileutils'
79
+ File.mkdir_p File.dirname(t.name)
80
+ end
81
+ tf = File.open(t.name, 'wb')
82
+ gz = Zlib::GzipWriter.new(tf)
83
+ tw = Archive::Tar::Minitar::Writer.new(gz)
84
+
85
+ files.each do |entry|
86
+ if entry[:dir]
87
+ tw.mkdir(entry[:name], entry)
88
+ else
89
+ tw.add_file_simple(entry[:name], entry) { |os|
90
+ os.write(entry[:data])
91
+ }
92
+ end
93
+ end
94
+ ensure
95
+ tw.close if tw
96
+ gz.close if gz
97
+ end
16
98
  end
99
+ task :package => [ PKG_TAR ]
100
+
101
+ desc "Build the manifest file from the current set of files."
102
+ task :build_manifest do |t|
103
+ require 'find'
104
+
105
+ paths = []
106
+ Find.find(".") do |path|
107
+ next if File.directory?(path)
108
+ next if path =~ /\.svn/
109
+ next if path =~ /\.git/
110
+ next if path =~ /\.hoerc/
111
+ next if path =~ /\.swp$/
112
+ next if path =~ %r{coverage/}
113
+ next if path =~ /~$/
114
+ paths << path.sub(%r{^\./}, '')
115
+ end
17
116
 
18
- # vim: syntax=Ruby
117
+ File.open("Manifest.txt", "w") do |f|
118
+ f.puts paths.sort.join("\n")
119
+ end
120
+
121
+ puts paths.sort.join("\n")
122
+ end
data/lib/net-ldap.rb ADDED
@@ -0,0 +1 @@
1
+ require 'net/ldap'
data/lib/net/ber.rb CHANGED
@@ -1,5 +1,3 @@
1
- # $Id$
2
- #
3
1
  # NET::BER
4
2
  # Mixes ASN.1/BER convenience methods into several standard classes.
5
3
  # Also provides BER parsing functionality.
@@ -25,533 +23,73 @@
25
23
  # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
24
  #
27
25
  #---------------------------------------------------------------------------
28
- #
29
- #
30
-
31
26
 
32
27
  module Net
33
-
34
28
  module BER
35
-
36
- class BerError < StandardError; end
37
-
38
-
39
- class BerIdentifiedString < String
40
- attr_accessor :ber_identifier
41
- def initialize args
42
- super args
43
- end
44
- end
45
-
46
- class BerIdentifiedArray < Array
47
- attr_accessor :ber_identifier
48
- def initialize
49
- super
50
- end
51
- end
52
-
53
- class BerIdentifiedNull
54
- attr_accessor :ber_identifier
55
- def to_ber
56
- "\005\000"
57
- end
58
- end
59
-
60
- class BerIdentifiedOid
61
- attr_accessor :ber_identifier
62
- def initialize oid
63
- if oid.is_a?(String)
64
- oid = oid.split(/\./).map {|s| s.to_i }
65
- end
66
- @value = oid
67
- end
68
- def to_ber
69
- # Provisional implementation.
70
- # We ASSUME that our incoming value is an array, and we
71
- # use the Array#to_ber_oid method defined below.
72
- # We probably should obsolete that method, actually, in
73
- # and move the code here.
74
- # WE ARE NOT CURRENTLY ENCODING THE BER-IDENTIFIER.
75
- # This implementation currently hardcodes 6, the universal OID tag.
76
- ary = @value.dup
77
- first = ary.shift
78
- raise Net::BER::BerError.new(" invalid OID" ) unless [0,1,2].include?(first)
79
- first = first * 40 + ary.shift
80
- ary.unshift first
81
- oid = ary.pack("w*")
82
- [6, oid.length].pack("CC") + oid
83
- end
84
- end
85
-
86
- #--
87
- # This condenses our nicely self-documenting ASN hashes down
88
- # to an array for fast lookups.
89
- # Scoped to be called as a module method, but not intended for
90
- # user code to call.
91
- #
92
- def self.compile_syntax syn
93
- out = [nil] * 256
94
- syn.each {|tclass,tclasses|
95
- tagclass = {:universal=>0, :application=>64, :context_specific=>128, :private=>192} [tclass]
96
- tclasses.each {|codingtype,codings|
97
- encoding = {:primitive=>0, :constructed=>32} [codingtype]
98
- codings.each {|tag,objtype|
99
- out[tagclass + encoding + tag] = objtype
100
- }
101
- }
102
- }
103
- out
104
- end
105
-
106
- # This module is for mixing into IO and IO-like objects.
107
- module BERParser
108
-
109
- # The order of these follows the class-codes in BER.
110
- # Maybe this should have been a hash.
111
- TagClasses = [:universal, :application, :context_specific, :private]
112
-
113
- BuiltinSyntax = BER.compile_syntax( {
114
- :universal => {
115
- :primitive => {
116
- 1 => :boolean,
117
- 2 => :integer,
118
- 4 => :string,
119
- 5 => :null,
120
- 6 => :oid,
121
- 10 => :integer,
122
- 13 => :string # (relative OID)
123
- },
124
- :constructed => {
125
- 16 => :array,
126
- 17 => :array
127
- }
128
- },
129
- :context_specific => {
130
- :primitive => {
131
- 10 => :integer
132
- }
133
- }
134
- })
135
-
136
- #
137
- # read_ber
138
- # TODO: clean this up so it works properly with partial
139
- # packets coming from streams that don't block when
140
- # we ask for more data (like StringIOs). At it is,
141
- # this can throw TypeErrors and other nasties.
29
+ VERSION = '0.1.0'
30
+
142
31
  #--
143
- # BEWARE, this violates DRY and is largely equal in functionality to
144
- # read_ber_from_string. Eventually that method may subsume the functionality
145
- # of this one.
146
- #
147
- def read_ber syntax=nil
148
- # don't bother with this line, since IO#getbyte by definition returns nil on eof.
149
- #return nil if eof?
150
-
151
- id = getbyte or return nil # don't trash this value, we'll use it later
152
- #tag = id & 31
153
- #tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" )
154
- #tagclass = TagClasses[ id >> 6 ]
155
- #encoding = (id & 0x20 != 0) ? :constructed : :primitive
156
-
157
- n = getbyte
158
- lengthlength,contentlength = if n <= 127
159
- [1,n]
160
- else
161
- # Replaced the inject because it profiles hot.
162
- #j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getbyte}
163
- j = 0
164
- read( n & 127 ).each_byte {|n1| j = (j << 8) + n1}
165
- [1 + (n & 127), j]
166
- end
167
-
168
- newobj = read contentlength
169
-
170
- # This exceptionally clever and clear bit of code is verrrry slow.
171
- objtype = (syntax && syntax[id]) || BuiltinSyntax[id]
172
-
173
-
174
- # == is expensive so sort this if/else so the common cases are at the top.
175
- obj = if objtype == :string
176
- #(newobj || "").dup
177
- s = BerIdentifiedString.new( newobj || "" )
178
- s.ber_identifier = id
179
- s
180
- elsif objtype == :integer
181
- j = 0
182
- newobj.each_byte {|b| j = (j << 8) + b}
183
- j
184
- elsif objtype == :oid
185
- # cf X.690 pgh 8.19 for an explanation of this algorithm.
186
- # Potentially not good enough. We may need a BerIdentifiedOid
187
- # as a subclass of BerIdentifiedArray, to get the ber identifier
188
- # and also a to_s method that produces the familiar dotted notation.
189
- oid = newobj.unpack("w*")
190
- f = oid.shift
191
- g = if f < 40
192
- [0, f]
193
- elsif f < 80
194
- [1, f-40]
195
- else
196
- [2, f-80] # f-80 can easily be > 80. What a weird optimization.
197
- end
198
- oid.unshift g.last
199
- oid.unshift g.first
200
- oid
201
- elsif objtype == :array
202
- #seq = []
203
- seq = BerIdentifiedArray.new
204
- seq.ber_identifier = id
205
- sio = StringIO.new( newobj || "" )
206
- # Interpret the subobject, but note how the loop
207
- # is built: nil ends the loop, but false (a valid
208
- # BER value) does not!
209
- while (e = sio.read_ber(syntax)) != nil
210
- seq << e
32
+ # This condenses our nicely self-documenting ASN hashes down
33
+ # to an array for fast lookups.
34
+ # Scoped to be called as a module method, but not intended for
35
+ # user code to call.
36
+ #
37
+ def self.compile_syntax(syn)
38
+ out = [nil] * 256
39
+ syn.each do |tclass, tclasses|
40
+ tagclass = {:universal=>0, :application=>64, :context_specific=>128, :private=>192} [tclass]
41
+ tclasses.each do |codingtype,codings|
42
+ encoding = {:primitive=>0, :constructed=>32} [codingtype]
43
+ codings.each {|tag, objtype| out[tagclass + encoding + tag] = objtype }
211
44
  end
212
- seq
213
- elsif objtype == :boolean
214
- newobj != "\000"
215
- elsif objtype == :null
216
- n = BerIdentifiedNull.new
217
- n.ber_identifier = id
218
- n
219
- else
220
- #raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" )
221
- raise BerError.new( "unsupported object type: id=#{id}" )
222
45
  end
223
-
224
- # Add the identifier bits into the object if it's a String or an Array.
225
- # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway.
226
- # Replaced this mechanism with subclasses because the instance_eval profiled too hot.
227
- #obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end"
228
- #obj.ber_identifier = id if obj.respond_to?(:ber_identifier)
229
- obj
230
-
46
+ out
231
47
  end
232
48
 
233
- #--
234
- # Violates DRY! This replicates the functionality of #read_ber.
235
- # Eventually this method may replace that one.
236
- # This version of #read_ber behaves properly in the face of incomplete
237
- # data packets. If a full BER object is detected, we return an array containing
238
- # the detected object and the number of bytes consumed from the string.
239
- # If we don't detect a complete packet, return nil.
240
- #
241
- # Observe that weirdly we recursively call the original #read_ber in here.
242
- # That needs to be fixed if we ever obsolete the original method in favor of this one.
243
- def read_ber_from_string str, syntax=nil
244
- id = str[0] or return nil
245
- n = str[1] or return nil
246
- n_consumed = 2
247
- lengthlength,contentlength = if n <= 127
248
- [1,n]
249
- else
250
- n1 = n & 127
251
- return nil unless str.length >= (n_consumed + n1)
252
- j = 0
253
- n1.times {
254
- j = (j << 8) + str[n_consumed]
255
- n_consumed += 1
256
- }
257
- [1 + (n1), j]
258
- end
259
-
260
- return nil unless str.length >= (n_consumed + contentlength)
261
- newobj = str[n_consumed...(n_consumed + contentlength)]
262
- n_consumed += contentlength
263
-
264
- objtype = (syntax && syntax[id]) || BuiltinSyntax[id]
265
-
266
- # == is expensive so sort this if/else so the common cases are at the top.
267
- obj = if objtype == :array
268
- seq = BerIdentifiedArray.new
269
- seq.ber_identifier = id
270
- sio = StringIO.new( newobj || "" )
271
- # Interpret the subobject, but note how the loop
272
- # is built: nil ends the loop, but false (a valid
273
- # BER value) does not!
274
- # Also, we can use the standard read_ber method because
275
- # we know for sure we have enough data. (Although this
276
- # might be faster than the standard method.)
277
- while (e = sio.read_ber(syntax)) != nil
278
- seq << e
279
- end
280
- seq
281
- elsif objtype == :string
282
- s = BerIdentifiedString.new( newobj || "" )
283
- s.ber_identifier = id
284
- s
285
- elsif objtype == :integer
286
- j = 0
287
- newobj.each_byte {|b| j = (j << 8) + b}
288
- j
289
- elsif objtype == :oid
290
- # cf X.690 pgh 8.19 for an explanation of this algorithm.
291
- # Potentially not good enough. We may need a BerIdentifiedOid
292
- # as a subclass of BerIdentifiedArray, to get the ber identifier
293
- # and also a to_s method that produces the familiar dotted notation.
294
- oid = newobj.unpack("w*")
295
- f = oid.shift
296
- g = if f < 40
297
- [0,f]
298
- elsif f < 80
299
- [1, f-40]
300
- else
301
- [2, f-80] # f-80 can easily be > 80. What a weird optimization.
302
- end
303
- oid.unshift g.last
304
- oid.unshift g.first
305
- oid
306
- elsif objtype == :boolean
307
- newobj != "\000"
308
- elsif objtype == :null
309
- n = BerIdentifiedNull.new
310
- n.ber_identifier = id
311
- n
312
- else
313
- raise BerError.new( "unsupported object type: id=#{id}" )
314
- end
315
-
316
- [obj, n_consumed]
317
- end
318
-
319
- end # module BERParser
320
- end # module BER
321
-
322
- end # module Net
323
-
324
-
325
- class IO
326
- include Net::BER::BERParser
327
- end
328
-
329
- require "stringio"
330
- class StringIO
331
- include Net::BER::BERParser
332
- end
333
-
334
- begin
335
- require 'openssl'
336
- class OpenSSL::SSL::SSLSocket
337
- include Net::BER::BERParser
338
- end
339
- rescue LoadError
340
- # Ignore LoadError.
341
- # DON'T ignore NameError, which means the SSLSocket class
342
- # is somehow unavailable on this implementation of Ruby's openssl.
343
- # This may be WRONG, however, because we don't yet know how Ruby's
344
- # openssl behaves on machines with no OpenSSL library. I suppose
345
- # it's possible they do not fail to require 'openssl' but do not
346
- # create the classes. So this code is provisional.
347
- # Also, you might think that OpenSSL::SSL::SSLSocket inherits from
348
- # IO so we'd pick it up above. But you'd be wrong.
349
- end
350
-
351
-
352
-
353
- class String
354
- include Net::BER::BERParser
355
- def read_ber syntax=nil
356
- StringIO.new(self).read_ber(syntax)
357
- end
358
- def read_ber! syntax=nil
359
- obj,n_consumed = read_ber_from_string(self, syntax)
360
- if n_consumed
361
- self.slice!(0...n_consumed)
362
- obj
363
- else
364
- nil
365
- end
49
+ def to_ber
50
+ # Provisional implementation.
51
+ # We ASSUME that our incoming value is an array, and we
52
+ # use the Array#to_ber_oid method defined below.
53
+ # We probably should obsolete that method, actually, in
54
+ # and move the code here.
55
+ # WE ARE NOT CURRENTLY ENCODING THE BER-IDENTIFIER.
56
+ # This implementation currently hardcodes 6, the universal OID tag.
57
+ ary = @value.dup
58
+ first = ary.shift
59
+ raise Net::BER::BerError.new(" invalid OID" ) unless [0,1,2].include?(first)
60
+ first = first * 40 + ary.shift
61
+ ary.unshift first
62
+ oid = ary.pack("w*")
63
+ [6, oid.length].pack("CC") + oid
366
64
  end
367
- end
368
-
369
- #----------------------------------------------
370
-
371
-
372
- class FalseClass
373
- #
374
- # to_ber
375
- #
376
- def to_ber
377
- "\001\001\000"
378
- end
379
- end
380
-
381
-
382
- class TrueClass
383
- #
384
- # to_ber
385
- #
386
- def to_ber
387
- "\001\001\001"
388
65
  end
389
66
  end
390
67
 
391
-
392
-
393
- class Fixnum
394
- #
395
- # to_ber
396
- #
397
- def to_ber
398
- "\002" + to_ber_internal
399
- end
400
-
401
- #
402
- # to_ber_enumerated
403
- #
404
- def to_ber_enumerated
405
- "\012" + to_ber_internal
406
- end
407
-
408
- #
409
- # to_ber_length_encoding
410
- #
411
- def to_ber_length_encoding
412
- if self <= 127
413
- [self].pack('C')
414
- else
415
- i = [self].pack('N').sub(/^[\0]+/,"")
416
- [0x80 + i.length].pack('C') + i
68
+ module Net
69
+ module BER
70
+ class BerError < StandardError; end
71
+
72
+ class BerIdentifiedString < String
73
+ attr_accessor :ber_identifier
74
+ def initialize args
75
+ super args
76
+ end
417
77
  end
418
- end
419
-
420
- # Generate a BER-encoding for an application-defined INTEGER.
421
- # Example: SNMP's Counter, Gauge, and TimeTick types.
422
- #
423
- def to_ber_application tag
424
- [0x40 + tag].pack("C") + to_ber_internal
425
- end
426
-
427
- #--
428
- # Called internally to BER-encode the length and content bytes of a Fixnum.
429
- # The caller will prepend the tag byte.
430
- def to_ber_internal
431
- # PLEASE optimize this code path. It's awfully ugly and probably slow.
432
- # It also doesn't understand negative numbers yet.
433
- raise Net::BER::BerError.new( "range error in fixnum" ) unless self >= 0
434
- z = [self].pack("N")
435
- zlen = if self < 0x80
436
- 1
437
- elsif self < 0x8000
438
- 2
439
- elsif self < 0x800000
440
- 3
441
- else
442
- 4
78
+
79
+ class BerIdentifiedArray < Array
80
+ attr_accessor :ber_identifier
81
+ def initialize(*args)
82
+ super
83
+ end
443
84
  end
444
- [zlen].pack("C") + z[0-zlen,zlen]
445
- end
446
- private :to_ber_internal
447
-
448
- end # class Fixnum
449
-
450
-
451
- class Bignum
452
-
453
- def to_ber
454
- #i = [self].pack('w')
455
- #i.length > 126 and raise Net::BER::BerError.new( "range error in bignum" )
456
- #[2, i.length].pack("CC") + i
457
-
458
- # Ruby represents Bignums as two's-complement numbers so we may actually be
459
- # good as far as representing negatives goes.
460
- # I'm sure this implementation can be improved performance-wise if necessary.
461
- # Ruby's Bignum#size returns the number of bytes in the internal representation
462
- # of the number, but it can and will include leading zero bytes on at least
463
- # some implementations. Evidently Ruby stores these as sets of quadbytes.
464
- # It's not illegal in BER to encode all of the leading zeroes but let's strip
465
- # them out anyway.
466
- #
467
- sz = self.size
468
- out = "\000" * sz
469
- (sz*8).times {|bit|
470
- if self[bit] == 1
471
- out[bit/8] += (1 << (bit % 8))
472
- end
473
- }
474
-
475
- while out.length > 1 and out[-1] == 0
476
- out.slice!(-1,1)
85
+
86
+ class BerIdentifiedNull
87
+ attr_accessor :ber_identifier
88
+ def to_ber
89
+ "\005\000"
90
+ end
477
91
  end
478
-
479
- [2, out.length].pack("CC") + out.reverse
480
92
  end
481
-
482
93
  end
483
94
 
484
-
485
-
486
- class String
487
- #
488
- # to_ber
489
- # A universal octet-string is tag number 4,
490
- # but others are possible depending on the context, so we
491
- # let the caller give us one.
492
- # The preferred way to do this in user code is via to_ber_application_sring
493
- # and to_ber_contextspecific.
494
- #
495
- def to_ber code = 4
496
- [code].pack('C') + length.to_ber_length_encoding + self
497
- end
498
-
499
- #
500
- # to_ber_application_string
501
- #
502
- def to_ber_application_string code
503
- to_ber( 0x40 + code )
504
- end
505
-
506
- #
507
- # to_ber_contextspecific
508
- #
509
- def to_ber_contextspecific code
510
- to_ber( 0x80 + code )
511
- end
512
-
513
- end # class String
514
-
515
-
516
-
517
- class Array
518
- #
519
- # to_ber_appsequence
520
- # An application-specific sequence usually gets assigned
521
- # a tag that is meaningful to the particular protocol being used.
522
- # This is different from the universal sequence, which usually
523
- # gets a tag value of 16.
524
- # Now here's an interesting thing: We're adding the X.690
525
- # "application constructed" code at the top of the tag byte (0x60),
526
- # but some clients, notably ldapsearch, send "context-specific
527
- # constructed" (0xA0). The latter would appear to violate RFC-1777,
528
- # but what do I know? We may need to change this.
529
- #
530
-
531
- def to_ber id = 0; to_ber_seq_internal( 0x30 + id ); end
532
- def to_ber_set id = 0; to_ber_seq_internal( 0x31 + id ); end
533
- def to_ber_sequence id = 0; to_ber_seq_internal( 0x30 + id ); end
534
- def to_ber_appsequence id = 0; to_ber_seq_internal( 0x60 + id ); end
535
- def to_ber_contextspecific id = 0; to_ber_seq_internal( 0xA0 + id ); end
536
-
537
- def to_ber_oid
538
- ary = self.dup
539
- first = ary.shift
540
- raise Net::BER::BerError.new( "invalid OID" ) unless [0,1,2].include?(first)
541
- first = first * 40 + ary.shift
542
- ary.unshift first
543
- oid = ary.pack("w*")
544
- [6, oid.length].pack("CC") + oid
545
- end
546
-
547
- private
548
- def to_ber_seq_internal code
549
- s = ''
550
- self.each{|x| s = s + x}
551
- [code].pack('C') + s.length.to_ber_length_encoding + s
552
- end
553
-
554
-
555
- end # class Array
556
-
557
-
95
+ require 'net/ber/ber_parser'