datacom-net-ldap 0.5.0.datacom
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.autotest +11 -0
- data/.rspec +2 -0
- data/Contributors.rdoc +22 -0
- data/Hacking.rdoc +68 -0
- data/History.rdoc +198 -0
- data/License.rdoc +29 -0
- data/Manifest.txt +50 -0
- data/README.rdoc +49 -0
- data/Rakefile +74 -0
- data/autotest/discover.rb +1 -0
- data/lib/net-ldap.rb +2 -0
- data/lib/net/ber.rb +320 -0
- data/lib/net/ber/ber_parser.rb +168 -0
- data/lib/net/ber/core_ext.rb +62 -0
- data/lib/net/ber/core_ext/array.rb +96 -0
- data/lib/net/ber/core_ext/bignum.rb +22 -0
- data/lib/net/ber/core_ext/false_class.rb +10 -0
- data/lib/net/ber/core_ext/fixnum.rb +66 -0
- data/lib/net/ber/core_ext/string.rb +78 -0
- data/lib/net/ber/core_ext/true_class.rb +12 -0
- data/lib/net/ldap.rb +1646 -0
- data/lib/net/ldap/dataset.rb +154 -0
- data/lib/net/ldap/dn.rb +225 -0
- data/lib/net/ldap/entry.rb +185 -0
- data/lib/net/ldap/filter.rb +781 -0
- data/lib/net/ldap/password.rb +37 -0
- data/lib/net/ldap/pdu.rb +273 -0
- data/lib/net/ldap/version.rb +5 -0
- data/lib/net/snmp.rb +270 -0
- data/net-ldap.gemspec +61 -0
- data/spec/integration/ssl_ber_spec.rb +36 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unit/ber/ber_spec.rb +141 -0
- data/spec/unit/ber/core_ext/string_spec.rb +51 -0
- data/spec/unit/ldap/dn_spec.rb +80 -0
- data/spec/unit/ldap/entry_spec.rb +51 -0
- data/spec/unit/ldap/filter_spec.rb +115 -0
- data/spec/unit/ldap_spec.rb +78 -0
- data/test/common.rb +3 -0
- data/test/test_entry.rb +59 -0
- data/test/test_filter.rb +122 -0
- data/test/test_ldap_connection.rb +24 -0
- data/test/test_ldif.rb +79 -0
- data/test/test_password.rb +17 -0
- data/test/test_rename.rb +77 -0
- data/test/test_snmp.rb +114 -0
- data/test/testdata.ldif +101 -0
- data/testserver/ldapserver.rb +210 -0
- data/testserver/testdata.ldif +101 -0
- metadata +213 -0
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require 'hoe'
|
5
|
+
|
6
|
+
Hoe.plugin :doofus
|
7
|
+
Hoe.plugin :git
|
8
|
+
Hoe.plugin :gemspec
|
9
|
+
|
10
|
+
Hoe.spec 'net-ldap' do |spec|
|
11
|
+
spec.rubyforge_name = spec.name
|
12
|
+
|
13
|
+
spec.developer("Francis Cianfrocca", "blackhedd@rubyforge.org")
|
14
|
+
spec.developer("Emiel van de Laar", "gemiel@gmail.com")
|
15
|
+
spec.developer("Rory O'Connell", "rory.ocon@gmail.com")
|
16
|
+
spec.developer("Kaspar Schiess", "kaspar.schiess@absurd.li")
|
17
|
+
spec.developer("Austin Ziegler", "austin@rubyforge.org")
|
18
|
+
|
19
|
+
spec.remote_rdoc_dir = ''
|
20
|
+
spec.rsync_args << ' --exclude=statsvn/'
|
21
|
+
|
22
|
+
spec.url = %W(http://rubyldap.com/ https://github.com/ruby-ldap/ruby-net-ldap)
|
23
|
+
|
24
|
+
spec.history_file = 'History.rdoc'
|
25
|
+
spec.readme_file = 'README.rdoc'
|
26
|
+
|
27
|
+
spec.extra_rdoc_files = FileList["*.rdoc"].to_a
|
28
|
+
|
29
|
+
spec.extra_dev_deps << [ "hoe-git", "~> 1" ]
|
30
|
+
spec.extra_dev_deps << [ "hoe-gemspec", "~> 1" ]
|
31
|
+
spec.extra_dev_deps << [ "metaid", "~> 1" ]
|
32
|
+
spec.extra_dev_deps << [ "flexmock", "~> 0.9.0" ]
|
33
|
+
spec.extra_dev_deps << [ "rspec", "~> 2.0" ]
|
34
|
+
|
35
|
+
spec.clean_globs << "coverage"
|
36
|
+
|
37
|
+
spec.spec_extras[:required_ruby_version] = ">= 1.8.7"
|
38
|
+
spec.multiruby_skip << "1.8.6"
|
39
|
+
spec.multiruby_skip << "1_8_6"
|
40
|
+
|
41
|
+
spec.need_tar = true
|
42
|
+
end
|
43
|
+
|
44
|
+
# I'm not quite ready to get rid of this, but I think "rake git:manifest" is
|
45
|
+
# sufficient.
|
46
|
+
namespace :old do
|
47
|
+
desc "Build the manifest file from the current set of files."
|
48
|
+
task :build_manifest do |t|
|
49
|
+
require 'find'
|
50
|
+
|
51
|
+
paths = []
|
52
|
+
Find.find(".") do |path|
|
53
|
+
next if File.directory?(path)
|
54
|
+
next if path =~ /\.svn/
|
55
|
+
next if path =~ /\.git/
|
56
|
+
next if path =~ /\.hoerc/
|
57
|
+
next if path =~ /\.swp$/
|
58
|
+
next if path =~ %r{coverage/}
|
59
|
+
next if path =~ /~$/
|
60
|
+
paths << path.sub(%r{^\./}, '')
|
61
|
+
end
|
62
|
+
|
63
|
+
File.open("Manifest.txt", "w") do |f|
|
64
|
+
f.puts paths.sort.join("\n")
|
65
|
+
end
|
66
|
+
|
67
|
+
puts paths.sort.join("\n")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Run a full set of integration and unit tests"
|
72
|
+
task :cruise => [:test, :spec]
|
73
|
+
|
74
|
+
# vim: syntax=ruby
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/lib/net-ldap.rb
ADDED
data/lib/net/ber.rb
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
require 'net/ldap/version'
|
3
|
+
|
4
|
+
module Net # :nodoc:
|
5
|
+
##
|
6
|
+
# == Basic Encoding Rules (BER) Support Module
|
7
|
+
#
|
8
|
+
# Much of the text below is cribbed from Wikipedia:
|
9
|
+
# http://en.wikipedia.org/wiki/Basic_Encoding_Rules
|
10
|
+
#
|
11
|
+
# The ITU Specification is also worthwhile reading:
|
12
|
+
# http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
13
|
+
#
|
14
|
+
# The Basic Encoding Rules were the original rules laid out by the ASN.1
|
15
|
+
# standard for encoding abstract information into a concrete data stream.
|
16
|
+
# The rules, collectively referred to as a transfer syntax in ASN.1
|
17
|
+
# parlance, specify the exact octet sequences which are used to encode a
|
18
|
+
# given data item. The syntax defines such elements as: the
|
19
|
+
# representations for basic data types, the structure of length
|
20
|
+
# information, and the means for defining complex or compound types based
|
21
|
+
# on more primitive types. The BER syntax, along with two subsets of BER
|
22
|
+
# (the Canonical Encoding Rules and the Distinguished Encoding Rules), are
|
23
|
+
# defined by the ITU-T's X.690 standards document, which is part of the
|
24
|
+
# ASN.1 document series.
|
25
|
+
#
|
26
|
+
# == Encoding
|
27
|
+
# The BER format specifies a self-describing and self-delimiting format
|
28
|
+
# for encoding ASN.1 data structures. Each data element is encoded as a
|
29
|
+
# type identifier, a length description, the actual data elements, and
|
30
|
+
# where necessary, an end-of-content marker. This format allows a receiver
|
31
|
+
# to decode the ASN.1 information from an incomplete stream, without
|
32
|
+
# requiring any pre-knowledge of the size, content, or semantic meaning of
|
33
|
+
# the data.
|
34
|
+
#
|
35
|
+
# <Type | Length | Value [| End-of-Content]>
|
36
|
+
#
|
37
|
+
# == Protocol Data Units (PDU)
|
38
|
+
# Protocols are defined with schema represented in BER, such that a PDU
|
39
|
+
# consists of cascaded type-length-value encodings.
|
40
|
+
#
|
41
|
+
# === Type Tags
|
42
|
+
# BER type tags are represented as single octets (bytes). The lower five
|
43
|
+
# bits of the octet are tag identifier numbers and the upper three bits of
|
44
|
+
# the octet are used to distinguish the type as native to ASN.1,
|
45
|
+
# application-specific, context-specific, or private. See
|
46
|
+
# Net::BER::TAG_CLASS and Net::BER::ENCODING_TYPE for more information.
|
47
|
+
#
|
48
|
+
# If Class is set to Universal (0b00______), the value is of a type native
|
49
|
+
# to ASN.1 (e.g. INTEGER). The Application class (0b01______) is only
|
50
|
+
# valid for one specific application. Context_specific (0b10______)
|
51
|
+
# depends on the context and private (0b11_______) can be defined in
|
52
|
+
# private specifications
|
53
|
+
#
|
54
|
+
# If the primitive/constructed bit is zero (0b__0_____), it specifies that
|
55
|
+
# the value is primitive like an INTEGER. If it is one (0b__1_____), the
|
56
|
+
# value is a constructed value that contains type-length-value encoded
|
57
|
+
# types like a SET or a SEQUENCE.
|
58
|
+
#
|
59
|
+
# === Defined Universal (ASN.1 Native) Types
|
60
|
+
# There are a number of pre-defined universal (native) types.
|
61
|
+
#
|
62
|
+
# <table>
|
63
|
+
# <tr><th>Name</th><th>Primitive<br />Constructed</th><th>Number</th></tr>
|
64
|
+
# <tr><th>EOC (End-of-Content)</th><th>P</th><td>0: 0 (0x0, 0b00000000)</td></tr>
|
65
|
+
# <tr><th>BOOLEAN</th><th>P</th><td>1: 1 (0x01, 0b00000001)</td></tr>
|
66
|
+
# <tr><th>INTEGER</th><th>P</th><td>2: 2 (0x02, 0b00000010)</td></tr>
|
67
|
+
# <tr><th>BIT STRING</th><th>P</th><td>3: 3 (0x03, 0b00000011)</td></tr>
|
68
|
+
# <tr><th>BIT STRING</th><th>C</th><td>3: 35 (0x23, 0b00100011)</td></tr>
|
69
|
+
# <tr><th>OCTET STRING</th><th>P</th><td>4: 4 (0x04, 0b00000100)</td></tr>
|
70
|
+
# <tr><th>OCTET STRING</th><th>C</th><td>4: 36 (0x24, 0b00100100)</td></tr>
|
71
|
+
# <tr><th>NULL</th><th>P</th><td>5: 5 (0x05, 0b00000101)</td></tr>
|
72
|
+
# <tr><th>OBJECT IDENTIFIER</th><th>P</th><td>6: 6 (0x06, 0b00000110)</td></tr>
|
73
|
+
# <tr><th>Object Descriptor</th><th>P</th><td>7: 7 (0x07, 0b00000111)</td></tr>
|
74
|
+
# <tr><th>EXTERNAL</th><th>C</th><td>8: 40 (0x28, 0b00101000)</td></tr>
|
75
|
+
# <tr><th>REAL (float)</th><th>P</th><td>9: 9 (0x09, 0b00001001)</td></tr>
|
76
|
+
# <tr><th>ENUMERATED</th><th>P</th><td>10: 10 (0x0a, 0b00001010)</td></tr>
|
77
|
+
# <tr><th>EMBEDDED PDV</th><th>C</th><td>11: 43 (0x2b, 0b00101011)</td></tr>
|
78
|
+
# <tr><th>UTF8String</th><th>P</th><td>12: 12 (0x0c, 0b00001100)</td></tr>
|
79
|
+
# <tr><th>UTF8String</th><th>C</th><td>12: 44 (0x2c, 0b00101100)</td></tr>
|
80
|
+
# <tr><th>RELATIVE-OID</th><th>P</th><td>13: 13 (0x0d, 0b00001101)</td></tr>
|
81
|
+
# <tr><th>SEQUENCE and SEQUENCE OF</th><th>C</th><td>16: 48 (0x30, 0b00110000)</td></tr>
|
82
|
+
# <tr><th>SET and SET OF</th><th>C</th><td>17: 49 (0x31, 0b00110001)</td></tr>
|
83
|
+
# <tr><th>NumericString</th><th>P</th><td>18: 18 (0x12, 0b00010010)</td></tr>
|
84
|
+
# <tr><th>NumericString</th><th>C</th><td>18: 50 (0x32, 0b00110010)</td></tr>
|
85
|
+
# <tr><th>PrintableString</th><th>P</th><td>19: 19 (0x13, 0b00010011)</td></tr>
|
86
|
+
# <tr><th>PrintableString</th><th>C</th><td>19: 51 (0x33, 0b00110011)</td></tr>
|
87
|
+
# <tr><th>T61String</th><th>P</th><td>20: 20 (0x14, 0b00010100)</td></tr>
|
88
|
+
# <tr><th>T61String</th><th>C</th><td>20: 52 (0x34, 0b00110100)</td></tr>
|
89
|
+
# <tr><th>VideotexString</th><th>P</th><td>21: 21 (0x15, 0b00010101)</td></tr>
|
90
|
+
# <tr><th>VideotexString</th><th>C</th><td>21: 53 (0x35, 0b00110101)</td></tr>
|
91
|
+
# <tr><th>IA5String</th><th>P</th><td>22: 22 (0x16, 0b00010110)</td></tr>
|
92
|
+
# <tr><th>IA5String</th><th>C</th><td>22: 54 (0x36, 0b00110110)</td></tr>
|
93
|
+
# <tr><th>UTCTime</th><th>P</th><td>23: 23 (0x17, 0b00010111)</td></tr>
|
94
|
+
# <tr><th>UTCTime</th><th>C</th><td>23: 55 (0x37, 0b00110111)</td></tr>
|
95
|
+
# <tr><th>GeneralizedTime</th><th>P</th><td>24: 24 (0x18, 0b00011000)</td></tr>
|
96
|
+
# <tr><th>GeneralizedTime</th><th>C</th><td>24: 56 (0x38, 0b00111000)</td></tr>
|
97
|
+
# <tr><th>GraphicString</th><th>P</th><td>25: 25 (0x19, 0b00011001)</td></tr>
|
98
|
+
# <tr><th>GraphicString</th><th>C</th><td>25: 57 (0x39, 0b00111001)</td></tr>
|
99
|
+
# <tr><th>VisibleString</th><th>P</th><td>26: 26 (0x1a, 0b00011010)</td></tr>
|
100
|
+
# <tr><th>VisibleString</th><th>C</th><td>26: 58 (0x3a, 0b00111010)</td></tr>
|
101
|
+
# <tr><th>GeneralString</th><th>P</th><td>27: 27 (0x1b, 0b00011011)</td></tr>
|
102
|
+
# <tr><th>GeneralString</th><th>C</th><td>27: 59 (0x3b, 0b00111011)</td></tr>
|
103
|
+
# <tr><th>UniversalString</th><th>P</th><td>28: 28 (0x1c, 0b00011100)</td></tr>
|
104
|
+
# <tr><th>UniversalString</th><th>C</th><td>28: 60 (0x3c, 0b00111100)</td></tr>
|
105
|
+
# <tr><th>CHARACTER STRING</th><th>P</th><td>29: 29 (0x1d, 0b00011101)</td></tr>
|
106
|
+
# <tr><th>CHARACTER STRING</th><th>C</th><td>29: 61 (0x3d, 0b00111101)</td></tr>
|
107
|
+
# <tr><th>BMPString</th><th>P</th><td>30: 30 (0x1e, 0b00011110)</td></tr>
|
108
|
+
# <tr><th>BMPString</th><th>C</th><td>30: 62 (0x3e, 0b00111110)</td></tr>
|
109
|
+
# </table>
|
110
|
+
module BER
|
111
|
+
VERSION = Net::LDAP::VERSION
|
112
|
+
|
113
|
+
##
|
114
|
+
# Used for BER-encoding the length and content bytes of a Fixnum integer
|
115
|
+
# values.
|
116
|
+
MAX_FIXNUM_SIZE = 0.size
|
117
|
+
|
118
|
+
##
|
119
|
+
# BER tag classes are kept in bits seven and eight of the tag type
|
120
|
+
# octet.
|
121
|
+
#
|
122
|
+
# <table>
|
123
|
+
# <tr><th>Bitmask</th><th>Definition</th></tr>
|
124
|
+
# <tr><th><tt>0b00______</tt></th><td>Universal (ASN.1 Native) Types</td></tr>
|
125
|
+
# <tr><th><tt>0b01______</tt></th><td>Application Types</td></tr>
|
126
|
+
# <tr><th><tt>0b10______</tt></th><td>Context-Specific Types</td></tr>
|
127
|
+
# <tr><th><tt>0b11______</tt></th><td>Private Types</td></tr>
|
128
|
+
# </table>
|
129
|
+
TAG_CLASS = {
|
130
|
+
:universal => 0b00000000, # 0
|
131
|
+
:application => 0b01000000, # 64
|
132
|
+
:context_specific => 0b10000000, # 128
|
133
|
+
:private => 0b11000000, # 192
|
134
|
+
}
|
135
|
+
|
136
|
+
##
|
137
|
+
# BER encoding type is kept in bit 6 of the tag type octet.
|
138
|
+
#
|
139
|
+
# <table>
|
140
|
+
# <tr><th>Bitmask</th><th>Definition</th></tr>
|
141
|
+
# <tr><th><tt>0b__0_____</tt></th><td>Primitive</td></tr>
|
142
|
+
# <tr><th><tt>0b__1_____</tt></th><td>Constructed</td></tr>
|
143
|
+
# </table>
|
144
|
+
ENCODING_TYPE = {
|
145
|
+
:primitive => 0b00000000, # 0
|
146
|
+
:constructed => 0b00100000, # 32
|
147
|
+
}
|
148
|
+
|
149
|
+
##
|
150
|
+
# Accepts a hash of hashes describing a BER syntax and converts it into
|
151
|
+
# a byte-keyed object for fast BER conversion lookup. The resulting
|
152
|
+
# "compiled" syntax is used by Net::BER::BERParser.
|
153
|
+
#
|
154
|
+
# This method should be called only by client classes of Net::BER (e.g.,
|
155
|
+
# Net::LDAP and Net::SNMP) and not by clients of those classes.
|
156
|
+
#
|
157
|
+
# The hash-based syntax uses TAG_CLASS keys that contain hashes of
|
158
|
+
# ENCODING_TYPE keys that contain tag numbers with object type markers.
|
159
|
+
#
|
160
|
+
# :<TAG_CLASS> => {
|
161
|
+
# :<ENCODING_TYPE> => {
|
162
|
+
# <number> => <object-type>
|
163
|
+
# },
|
164
|
+
# },
|
165
|
+
#
|
166
|
+
# === Permitted Object Types
|
167
|
+
# <tt>:string</tt>:: A string value, represented as BerIdentifiedString.
|
168
|
+
# <tt>:integer</tt>:: An integer value, represented with Fixnum.
|
169
|
+
# <tt>:oid</tt>:: An Object Identifier value; see X.690 section
|
170
|
+
# 8.19. Currently represented with a standard array,
|
171
|
+
# but may be better represented as a
|
172
|
+
# BerIdentifiedOID object.
|
173
|
+
# <tt>:array</tt>:: A sequence, represented as BerIdentifiedArray.
|
174
|
+
# <tt>:boolean</tt>:: A boolean value, represented as +true+ or +false+.
|
175
|
+
# <tt>:null</tt>:: A null value, represented as BerIdentifiedNull.
|
176
|
+
#
|
177
|
+
# === Example
|
178
|
+
# Net::LDAP defines its ASN.1 BER syntax something like this:
|
179
|
+
#
|
180
|
+
# class Net::LDAP
|
181
|
+
# AsnSyntax = Net::BER.compile_syntax({
|
182
|
+
# :application => {
|
183
|
+
# :primitive => {
|
184
|
+
# 2 => :null,
|
185
|
+
# },
|
186
|
+
# :constructed => {
|
187
|
+
# 0 => :array,
|
188
|
+
# # ...
|
189
|
+
# },
|
190
|
+
# },
|
191
|
+
# :context_specific => {
|
192
|
+
# :primitive => {
|
193
|
+
# 0 => :string,
|
194
|
+
# # ...
|
195
|
+
# },
|
196
|
+
# :constructed => {
|
197
|
+
# 0 => :array,
|
198
|
+
# # ...
|
199
|
+
# },
|
200
|
+
# }
|
201
|
+
# })
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# NOTE:: For readability and formatting purposes, Net::LDAP and its
|
205
|
+
# siblings actually construct their syntaxes more deliberately,
|
206
|
+
# as shown below. Since a hash is passed in the end in any case,
|
207
|
+
# the format does not matter.
|
208
|
+
#
|
209
|
+
# primitive = { 2 => :null }
|
210
|
+
# constructed = {
|
211
|
+
# 0 => :array,
|
212
|
+
# # ...
|
213
|
+
# }
|
214
|
+
# application = {
|
215
|
+
# :primitive => primitive,
|
216
|
+
# :constructed => constructed
|
217
|
+
# }
|
218
|
+
#
|
219
|
+
# primitive = {
|
220
|
+
# 0 => :string,
|
221
|
+
# # ...
|
222
|
+
# }
|
223
|
+
# constructed = {
|
224
|
+
# 0 => :array,
|
225
|
+
# # ...
|
226
|
+
# }
|
227
|
+
# context_specific = {
|
228
|
+
# :primitive => primitive,
|
229
|
+
# :constructed => constructed
|
230
|
+
# }
|
231
|
+
# AsnSyntax = Net::BER.compile_syntax(:application => application,
|
232
|
+
# :context_specific => context_specific)
|
233
|
+
def self.compile_syntax(syntax)
|
234
|
+
# TODO 20100327 AZ: Should we be allocating an array of 256 values
|
235
|
+
# that will either be +nil+ or an object type symbol, or should we
|
236
|
+
# allocate an empty Hash since unknown values return +nil+ anyway?
|
237
|
+
out = [ nil ] * 256
|
238
|
+
syntax.each do |tag_class_id, encodings|
|
239
|
+
tag_class = TAG_CLASS[tag_class_id]
|
240
|
+
encodings.each do |encoding_id, classes|
|
241
|
+
encoding = ENCODING_TYPE[encoding_id]
|
242
|
+
object_class = tag_class + encoding
|
243
|
+
classes.each do |number, object_type|
|
244
|
+
out[object_class + number] = object_type
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
out
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class Net::BER::BerError < RuntimeError; end
|
254
|
+
|
255
|
+
##
|
256
|
+
# An Array object with a BER identifier attached.
|
257
|
+
class Net::BER::BerIdentifiedArray < Array
|
258
|
+
attr_accessor :ber_identifier
|
259
|
+
|
260
|
+
def initialize(*args)
|
261
|
+
super
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
##
|
266
|
+
# A BER object identifier.
|
267
|
+
class Net::BER::BerIdentifiedOid
|
268
|
+
attr_accessor :ber_identifier
|
269
|
+
|
270
|
+
def initialize(oid)
|
271
|
+
if oid.is_a?(String)
|
272
|
+
oid = oid.split(/\./).map {|s| s.to_i }
|
273
|
+
end
|
274
|
+
@value = oid
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_ber
|
278
|
+
to_ber_oid
|
279
|
+
end
|
280
|
+
|
281
|
+
def to_ber_oid
|
282
|
+
@value.to_ber_oid
|
283
|
+
end
|
284
|
+
|
285
|
+
def to_s
|
286
|
+
@value.join(".")
|
287
|
+
end
|
288
|
+
|
289
|
+
def to_arr
|
290
|
+
@value.dup
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
##
|
295
|
+
# A String object with a BER identifier attached.
|
296
|
+
class Net::BER::BerIdentifiedString < String
|
297
|
+
attr_accessor :ber_identifier
|
298
|
+
def initialize args
|
299
|
+
super args
|
300
|
+
# LDAP uses UTF-8 encoded strings
|
301
|
+
self.encode('UTF-8') if self.respond_to?(:encoding) rescue self
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
module Net::BER
|
306
|
+
##
|
307
|
+
# A BER null object.
|
308
|
+
class BerIdentifiedNull
|
309
|
+
attr_accessor :ber_identifier
|
310
|
+
def to_ber
|
311
|
+
"\005\000"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# The default BerIdentifiedNull object.
|
317
|
+
Null = Net::BER::BerIdentifiedNull.new
|
318
|
+
end
|
319
|
+
|
320
|
+
require 'net/ber/core_ext'
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
# Implements Basic Encoding Rules parsing to be mixed into types as needed.
|
5
|
+
module Net::BER::BERParser
|
6
|
+
primitive = {
|
7
|
+
1 => :boolean,
|
8
|
+
2 => :integer,
|
9
|
+
4 => :string,
|
10
|
+
5 => :null,
|
11
|
+
6 => :oid,
|
12
|
+
10 => :integer,
|
13
|
+
13 => :string # (relative OID)
|
14
|
+
}
|
15
|
+
constructed = {
|
16
|
+
16 => :array,
|
17
|
+
17 => :array
|
18
|
+
}
|
19
|
+
universal = { :primitive => primitive, :constructed => constructed }
|
20
|
+
|
21
|
+
primitive = { 10 => :integer }
|
22
|
+
context = { :primitive => primitive }
|
23
|
+
|
24
|
+
# The universal, built-in ASN.1 BER syntax.
|
25
|
+
BuiltinSyntax = Net::BER.compile_syntax(:universal => universal,
|
26
|
+
:context_specific => context)
|
27
|
+
|
28
|
+
##
|
29
|
+
# This is an extract of our BER object parsing to simplify our
|
30
|
+
# understanding of how we parse basic BER object types.
|
31
|
+
def parse_ber_object(syntax, id, data)
|
32
|
+
# Find the object type from either the provided syntax lookup table or
|
33
|
+
# the built-in syntax lookup table.
|
34
|
+
#
|
35
|
+
# This exceptionally clever bit of code is verrrry slow.
|
36
|
+
object_type = (syntax && syntax[id]) || BuiltinSyntax[id]
|
37
|
+
|
38
|
+
# == is expensive so sort this so the common cases are at the top.
|
39
|
+
if object_type == :string
|
40
|
+
s = Net::BER::BerIdentifiedString.new(data || "")
|
41
|
+
s.ber_identifier = id
|
42
|
+
s
|
43
|
+
elsif object_type == :integer
|
44
|
+
j = 0
|
45
|
+
data.each_byte { |b| j = (j << 8) + b }
|
46
|
+
j
|
47
|
+
elsif object_type == :oid
|
48
|
+
# See X.690 pgh 8.19 for an explanation of this algorithm.
|
49
|
+
# This is potentially not good enough. We may need a
|
50
|
+
# BerIdentifiedOid as a subclass of BerIdentifiedArray, to
|
51
|
+
# get the ber identifier and also a to_s method that produces
|
52
|
+
# the familiar dotted notation.
|
53
|
+
oid = data.unpack("w*")
|
54
|
+
f = oid.shift
|
55
|
+
g = if f < 40
|
56
|
+
[0, f]
|
57
|
+
elsif f < 80
|
58
|
+
[1, f - 40]
|
59
|
+
else
|
60
|
+
# f - 80 can easily be > 80. What a weird optimization.
|
61
|
+
[2, f - 80]
|
62
|
+
end
|
63
|
+
oid.unshift g.last
|
64
|
+
oid.unshift g.first
|
65
|
+
# Net::BER::BerIdentifiedOid.new(oid)
|
66
|
+
oid
|
67
|
+
elsif object_type == :array
|
68
|
+
seq = Net::BER::BerIdentifiedArray.new
|
69
|
+
seq.ber_identifier = id
|
70
|
+
sio = StringIO.new(data || "")
|
71
|
+
# Interpret the subobject, but note how the loop is built:
|
72
|
+
# nil ends the loop, but false (a valid BER value) does not!
|
73
|
+
while (e = sio.read_ber(syntax)) != nil
|
74
|
+
seq << e
|
75
|
+
end
|
76
|
+
seq
|
77
|
+
elsif object_type == :boolean
|
78
|
+
data != "\000"
|
79
|
+
elsif object_type == :null
|
80
|
+
n = Net::BER::BerIdentifiedNull.new
|
81
|
+
n.ber_identifier = id
|
82
|
+
n
|
83
|
+
else
|
84
|
+
raise Net::BER::BerError, "Unsupported object type: id=#{id}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
private :parse_ber_object
|
88
|
+
|
89
|
+
##
|
90
|
+
# This is an extract of how our BER object length parsing is done to
|
91
|
+
# simplify the primary call. This is defined in X.690 section 8.1.3.
|
92
|
+
#
|
93
|
+
# The BER length will either be a single byte or up to 126 bytes in
|
94
|
+
# length. There is a special case of a BER length indicating that the
|
95
|
+
# content-length is undefined and will be identified by the presence of
|
96
|
+
# two null values (0x00 0x00).
|
97
|
+
#
|
98
|
+
# <table>
|
99
|
+
# <tr>
|
100
|
+
# <th>Range</th>
|
101
|
+
# <th>Length</th>
|
102
|
+
# </tr>
|
103
|
+
# <tr>
|
104
|
+
# <th>0x00 -- 0x7f<br />0b00000000 -- 0b01111111</th>
|
105
|
+
# <td>0 - 127 bytes</td>
|
106
|
+
# </tr>
|
107
|
+
# <tr>
|
108
|
+
# <th>0x80<br />0b10000000</th>
|
109
|
+
# <td>Indeterminate (end-of-content marker required)</td>
|
110
|
+
# </tr>
|
111
|
+
# <tr>
|
112
|
+
# <th>0x81 -- 0xfe<br />0b10000001 -- 0b11111110</th>
|
113
|
+
# <td>1 - 126 bytes of length as an integer value</td>
|
114
|
+
# </tr>
|
115
|
+
# <tr>
|
116
|
+
# <th>0xff<br />0b11111111</th>
|
117
|
+
# <td>Illegal (reserved for future expansion)</td>
|
118
|
+
# </tr>
|
119
|
+
# </table>
|
120
|
+
#
|
121
|
+
#--
|
122
|
+
# This has been modified from the version that was previously inside
|
123
|
+
# #read_ber to handle both the indeterminate terminator case and the
|
124
|
+
# invalid BER length case. Because the "lengthlength" value was not used
|
125
|
+
# inside of #read_ber, we no longer return it.
|
126
|
+
def read_ber_length
|
127
|
+
n = getbyte
|
128
|
+
|
129
|
+
if n <= 0x7f
|
130
|
+
n
|
131
|
+
elsif n == 0x80
|
132
|
+
-1
|
133
|
+
elsif n == 0xff
|
134
|
+
raise Net::BER::BerError, "Invalid BER length 0xFF detected."
|
135
|
+
else
|
136
|
+
v = 0
|
137
|
+
read(n & 0x7f).each_byte do |b|
|
138
|
+
v = (v << 8) + b
|
139
|
+
end
|
140
|
+
|
141
|
+
v
|
142
|
+
end
|
143
|
+
end
|
144
|
+
private :read_ber_length
|
145
|
+
|
146
|
+
##
|
147
|
+
# Reads a BER object from the including object. Requires that #getbyte is
|
148
|
+
# implemented on the including object and that it returns a Fixnum value.
|
149
|
+
# Also requires #read(bytes) to work.
|
150
|
+
#
|
151
|
+
# This does not work with non-blocking I/O.
|
152
|
+
def read_ber(syntax = nil)
|
153
|
+
# TODO: clean this up so it works properly with partial packets coming
|
154
|
+
# from streams that don't block when we ask for more data (like
|
155
|
+
# StringIOs). At it is, this can throw TypeErrors and other nasties.
|
156
|
+
|
157
|
+
id = getbyte or return nil # don't trash this value, we'll use it later
|
158
|
+
content_length = read_ber_length
|
159
|
+
|
160
|
+
if -1 == content_length
|
161
|
+
raise Net::BER::BerError, "Indeterminite BER content length not implemented."
|
162
|
+
else
|
163
|
+
data = read(content_length)
|
164
|
+
end
|
165
|
+
|
166
|
+
parse_ber_object(syntax, id, data)
|
167
|
+
end
|
168
|
+
end
|