net-ldap 0.0.5
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.
Potentially problematic release.
This version of net-ldap might be problematic. Click here for more details.
- data/COPYING +272 -0
- data/History.txt +96 -0
- data/LICENSE +55 -0
- data/Manifest.txt +30 -0
- data/README.txt +62 -0
- data/Rakefile +18 -0
- data/Release-Announcement +95 -0
- data/lib/net/ber.rb +557 -0
- data/lib/net/ldap.rb +1613 -0
- data/lib/net/ldap/dataset.rb +108 -0
- data/lib/net/ldap/entry.rb +269 -0
- data/lib/net/ldap/filter.rb +499 -0
- data/lib/net/ldap/pdu.rb +258 -0
- data/lib/net/ldap/psw.rb +64 -0
- data/lib/net/ldif.rb +39 -0
- data/lib/net/snmp.rb +297 -0
- data/pre-setup.rb +45 -0
- data/setup.rb +1366 -0
- data/test/common.rb +7 -0
- data/test/test_ber.rb +100 -0
- data/test/test_entry.rb +7 -0
- data/test/test_filter.rb +83 -0
- data/test/test_ldif.rb +59 -0
- data/test/test_password.rb +17 -0
- data/test/test_snmp.rb +130 -0
- data/test/testdata.ldif +101 -0
- data/tests/NOTICE.txt +6 -0
- data/tests/testldap.rb +190 -0
- data/testserver/ldapserver.rb +229 -0
- data/testserver/testdata.ldif +101 -0
- metadata +105 -0
data/lib/net/ldap/pdu.rb
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
# $Id$
|
2
|
+
#
|
3
|
+
# LDAP PDU support classes
|
4
|
+
#
|
5
|
+
#----------------------------------------------------------------------------
|
6
|
+
#
|
7
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
8
|
+
#
|
9
|
+
# Gmail: garbagecat10
|
10
|
+
#
|
11
|
+
# This program is free software; you can redistribute it and/or modify
|
12
|
+
# it under the terms of the GNU General Public License as published by
|
13
|
+
# the Free Software Foundation; either version 2 of the License, or
|
14
|
+
# (at your option) any later version.
|
15
|
+
#
|
16
|
+
# This program is distributed in the hope that it will be useful,
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
# GNU General Public License for more details.
|
20
|
+
#
|
21
|
+
# You should have received a copy of the GNU General Public License
|
22
|
+
# along with this program; if not, write to the Free Software
|
23
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
24
|
+
#
|
25
|
+
#---------------------------------------------------------------------------
|
26
|
+
|
27
|
+
module Net
|
28
|
+
|
29
|
+
class LdapPduError < StandardError; end
|
30
|
+
|
31
|
+
class LdapPdu
|
32
|
+
|
33
|
+
BindRequest = 0
|
34
|
+
BindResult = 1
|
35
|
+
UnbindRequest = 2
|
36
|
+
SearchRequest = 3
|
37
|
+
SearchReturnedData = 4
|
38
|
+
SearchResult = 5
|
39
|
+
ModifyResponse = 7
|
40
|
+
AddResponse = 9
|
41
|
+
DeleteResponse = 11
|
42
|
+
ModifyRDNResponse = 13
|
43
|
+
SearchResultReferral = 19
|
44
|
+
ExtendedRequest = 23
|
45
|
+
ExtendedResponse = 24
|
46
|
+
|
47
|
+
attr_reader :msg_id, :app_tag
|
48
|
+
attr_reader :search_dn, :search_attributes, :search_entry
|
49
|
+
attr_reader :search_referrals
|
50
|
+
attr_reader :search_parameters, :bind_parameters
|
51
|
+
|
52
|
+
# An LDAP PDU always looks like a BerSequence with
|
53
|
+
# at least two elements: an integer (message-id number), and
|
54
|
+
# an application-specific sequence.
|
55
|
+
# Some LDAPv3 packets also include an optional
|
56
|
+
# third element, which is a sequence of "controls"
|
57
|
+
# (See RFC 2251, section 4.1.12).
|
58
|
+
# The application-specific tag in the sequence tells
|
59
|
+
# us what kind of packet it is, and each kind has its
|
60
|
+
# own format, defined in RFC-1777.
|
61
|
+
# Observe that many clients (such as ldapsearch)
|
62
|
+
# do not necessarily enforce the expected application
|
63
|
+
# tags on received protocol packets. This implementation
|
64
|
+
# does interpret the RFC strictly in this regard, and
|
65
|
+
# it remains to be seen whether there are servers out
|
66
|
+
# there that will not work well with our approach.
|
67
|
+
#
|
68
|
+
# Added a controls-processor to SearchResult.
|
69
|
+
# Didn't add it everywhere because it just _feels_
|
70
|
+
# like it will need to be refactored.
|
71
|
+
#
|
72
|
+
def initialize ber_object
|
73
|
+
begin
|
74
|
+
@msg_id = ber_object[0].to_i
|
75
|
+
# Modified 25Nov06. We want to "un-decorate" the ber-identifier
|
76
|
+
# of the incoming packet. Originally we did this by subtracting 0x60,
|
77
|
+
# which ASSUMES the identifier is a constructed app-specific value.
|
78
|
+
# But at least one value (UnbindRequest) is app-specific primitive.
|
79
|
+
# So it makes more sense just to grab the bottom five bits.
|
80
|
+
#@app_tag = ber_object[1].ber_identifier - 0x60
|
81
|
+
@app_tag = ber_object[1].ber_identifier & 31
|
82
|
+
@ldap_controls = []
|
83
|
+
rescue
|
84
|
+
# any error becomes a data-format error
|
85
|
+
raise LdapPduError.new( "ldap-pdu format error" )
|
86
|
+
end
|
87
|
+
|
88
|
+
case @app_tag
|
89
|
+
when BindResult
|
90
|
+
parse_bind_response ber_object[1]
|
91
|
+
when SearchReturnedData
|
92
|
+
parse_search_return ber_object[1]
|
93
|
+
when SearchResultReferral
|
94
|
+
parse_search_referral ber_object[1]
|
95
|
+
when SearchResult
|
96
|
+
parse_ldap_result ber_object[1]
|
97
|
+
parse_controls(ber_object[2]) if ber_object[2]
|
98
|
+
when ModifyResponse
|
99
|
+
parse_ldap_result ber_object[1]
|
100
|
+
when AddResponse
|
101
|
+
parse_ldap_result ber_object[1]
|
102
|
+
when DeleteResponse
|
103
|
+
parse_ldap_result ber_object[1]
|
104
|
+
when ModifyRDNResponse
|
105
|
+
parse_ldap_result ber_object[1]
|
106
|
+
when SearchRequest
|
107
|
+
parse_ldap_search_request ber_object[1]
|
108
|
+
when BindRequest
|
109
|
+
parse_bind_request ber_object[1]
|
110
|
+
when UnbindRequest
|
111
|
+
parse_unbind_request ber_object[1]
|
112
|
+
when ExtendedResponse
|
113
|
+
parse_ldap_result ber_object[1]
|
114
|
+
else
|
115
|
+
raise LdapPduError.new( "unknown pdu-type: #{@app_tag}" )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns a hash which (usually) defines the members :resultCode, :errorMessage, and :matchedDN.
|
120
|
+
# These values come directly from an LDAP response packet returned by the remote peer.
|
121
|
+
# See #result_code for a sugaring.
|
122
|
+
#
|
123
|
+
def result
|
124
|
+
@ldap_result || {}
|
125
|
+
end
|
126
|
+
|
127
|
+
# This returns an LDAP result code taken from the PDU,
|
128
|
+
# but it will be nil if there wasn't a result code.
|
129
|
+
# That can easily happen depending on the type of packet.
|
130
|
+
#
|
131
|
+
def result_code code = :resultCode
|
132
|
+
@ldap_result and @ldap_result[code]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Return RFC-2251 Controls if any.
|
136
|
+
# Messy. Does this functionality belong somewhere else?
|
137
|
+
def result_controls
|
138
|
+
@ldap_controls
|
139
|
+
end
|
140
|
+
|
141
|
+
# Return serverSaslCreds, which are only present in BindResponse packets.
|
142
|
+
# Messy. Does this functionality belong somewhere else?
|
143
|
+
# We ought to refactor the accessors of this class before they get any kludgier.
|
144
|
+
def result_server_sasl_creds
|
145
|
+
@ldap_result && @ldap_result[:serverSaslCreds]
|
146
|
+
end
|
147
|
+
|
148
|
+
# parse_ldap_result
|
149
|
+
#
|
150
|
+
def parse_ldap_result sequence
|
151
|
+
sequence.length >= 3 or raise LdapPduError
|
152
|
+
@ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]}
|
153
|
+
end
|
154
|
+
|
155
|
+
private :parse_ldap_result
|
156
|
+
|
157
|
+
# A Bind Response may have an additional field, ID [7], serverSaslCreds, per RFC 2251 pgh 4.2.3.
|
158
|
+
#
|
159
|
+
def parse_bind_response sequence
|
160
|
+
sequence.length >= 3 or raise LdapPduError
|
161
|
+
@ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]}
|
162
|
+
@ldap_result[:serverSaslCreds] = sequence[3] if sequence.length >= 4
|
163
|
+
@ldap_result
|
164
|
+
end
|
165
|
+
|
166
|
+
private :parse_bind_response
|
167
|
+
|
168
|
+
# Definition from RFC 1777 (we're handling application-4 here)
|
169
|
+
#
|
170
|
+
# Search Response ::=
|
171
|
+
# CHOICE {
|
172
|
+
# entry [APPLICATION 4] SEQUENCE {
|
173
|
+
# objectName LDAPDN,
|
174
|
+
# attributes SEQUENCE OF SEQUENCE {
|
175
|
+
# AttributeType,
|
176
|
+
# SET OF AttributeValue
|
177
|
+
# }
|
178
|
+
# },
|
179
|
+
# resultCode [APPLICATION 5] LDAPResult
|
180
|
+
# }
|
181
|
+
#
|
182
|
+
# We concoct a search response that is a hash of the returned attribute values.
|
183
|
+
# NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES.
|
184
|
+
# This is to make them more predictable for user programs, but it
|
185
|
+
# may not be a good idea. Maybe this should be configurable.
|
186
|
+
# ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes,
|
187
|
+
# we also return @search_entry, which is an LDAP::Entry object.
|
188
|
+
# If that works out well, then we'll remove the first two.
|
189
|
+
#
|
190
|
+
# Provisionally removed obsolete search_attributes and search_dn, 04May06.
|
191
|
+
#
|
192
|
+
def parse_search_return sequence
|
193
|
+
sequence.length >= 2 or raise LdapPduError
|
194
|
+
@search_entry = LDAP::Entry.new( sequence[0] )
|
195
|
+
sequence[1].each {|seq|
|
196
|
+
@search_entry[seq[0]] = seq[1]
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
# A search referral is a sequence of one or more LDAP URIs.
|
201
|
+
# Any number of search-referral replies can be returned by the server, interspersed
|
202
|
+
# with normal replies in any order.
|
203
|
+
# Until I can think of a better way to do this, we'll return the referrals as an array.
|
204
|
+
# It'll be up to higher-level handlers to expose something reasonable to the client.
|
205
|
+
def parse_search_referral uris
|
206
|
+
@search_referrals = uris
|
207
|
+
end
|
208
|
+
|
209
|
+
# Per RFC 2251, an LDAP "control" is a sequence of tuples, each consisting
|
210
|
+
# of an OID, a boolean criticality flag defaulting FALSE, and an OPTIONAL
|
211
|
+
# Octet String. If only two fields are given, the second one may be
|
212
|
+
# either criticality or data, since criticality has a default value.
|
213
|
+
# Someday we may want to come back here and add support for some of
|
214
|
+
# more-widely used controls. RFC-2696 is a good example.
|
215
|
+
#
|
216
|
+
def parse_controls sequence
|
217
|
+
@ldap_controls = sequence.map do |control|
|
218
|
+
o = OpenStruct.new
|
219
|
+
o.oid,o.criticality,o.value = control[0],control[1],control[2]
|
220
|
+
if o.criticality and o.criticality.is_a?(String)
|
221
|
+
o.value = o.criticality
|
222
|
+
o.criticality = false
|
223
|
+
end
|
224
|
+
o
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
private :parse_controls
|
229
|
+
|
230
|
+
# (provisional, must document)
|
231
|
+
def parse_ldap_search_request sequence
|
232
|
+
s = OpenStruct.new
|
233
|
+
s.base_object,
|
234
|
+
s.scope,
|
235
|
+
s.deref_aliases,
|
236
|
+
s.size_limit,
|
237
|
+
s.time_limit,
|
238
|
+
s.types_only,
|
239
|
+
s.filter,
|
240
|
+
s.attributes = sequence
|
241
|
+
@search_parameters = s
|
242
|
+
end
|
243
|
+
|
244
|
+
# (provisional, must document)
|
245
|
+
def parse_bind_request sequence
|
246
|
+
s = OpenStruct.new
|
247
|
+
s.version,
|
248
|
+
s.name,
|
249
|
+
s.authentication = sequence
|
250
|
+
@bind_parameters = s
|
251
|
+
end
|
252
|
+
|
253
|
+
# (provisional, must document)
|
254
|
+
# UnbindRequest has no content so this is a no-op.
|
255
|
+
def parse_unbind_request sequence
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end # module Net
|
data/lib/net/ldap/psw.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# $Id$
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#----------------------------------------------------------------------------
|
5
|
+
#
|
6
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
7
|
+
#
|
8
|
+
# Gmail: garbagecat10
|
9
|
+
#
|
10
|
+
# This program is free software; you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU General Public License as published by
|
12
|
+
# the Free Software Foundation; either version 2 of the License, or
|
13
|
+
# (at your option) any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU General Public License
|
21
|
+
# along with this program; if not, write to the Free Software
|
22
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
23
|
+
#
|
24
|
+
#---------------------------------------------------------------------------
|
25
|
+
#
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
module Net
|
30
|
+
class LDAP
|
31
|
+
|
32
|
+
|
33
|
+
class Password
|
34
|
+
class << self
|
35
|
+
|
36
|
+
# Generate a password-hash suitable for inclusion in an LDAP attribute.
|
37
|
+
# Pass a hash type (currently supported: :md5 and :sha) and a plaintext
|
38
|
+
# password. This function will return a hashed representation.
|
39
|
+
# STUB: This is here to fulfill the requirements of an RFC, which one?
|
40
|
+
# TODO, gotta do salted-sha and (maybe) salted-md5.
|
41
|
+
# Should we provide sha1 as a synonym for sha1? I vote no because then
|
42
|
+
# should you also provide ssha1 for symmetry?
|
43
|
+
def generate( type, str )
|
44
|
+
case type
|
45
|
+
when :md5
|
46
|
+
require 'md5'
|
47
|
+
"{MD5}#{ [MD5.new( str.to_s ).digest].pack("m").chomp }"
|
48
|
+
when :sha
|
49
|
+
require 'sha1'
|
50
|
+
"{SHA}#{ [SHA1.new( str.to_s ).digest].pack("m").chomp }"
|
51
|
+
# when ssha
|
52
|
+
else
|
53
|
+
raise Net::LDAP::LdapError.new( "unsupported password-hash type (#{type})" )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end # class LDAP
|
62
|
+
end # module Net
|
63
|
+
|
64
|
+
|
data/lib/net/ldif.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# $Id$
|
2
|
+
#
|
3
|
+
# Net::LDIF for Ruby
|
4
|
+
#
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
8
|
+
#
|
9
|
+
# Gmail: garbagecat10
|
10
|
+
#
|
11
|
+
# This program is free software; you can redistribute it and/or modify
|
12
|
+
# it under the terms of the GNU General Public License as published by
|
13
|
+
# the Free Software Foundation; either version 2 of the License, or
|
14
|
+
# (at your option) any later version.
|
15
|
+
#
|
16
|
+
# This program is distributed in the hope that it will be useful,
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
# GNU General Public License for more details.
|
20
|
+
#
|
21
|
+
# You should have received a copy of the GNU General Public License
|
22
|
+
# along with this program; if not, write to the Free Software
|
23
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
24
|
+
#
|
25
|
+
#
|
26
|
+
|
27
|
+
# THIS FILE IS A STUB.
|
28
|
+
|
29
|
+
module Net
|
30
|
+
|
31
|
+
class LDIF
|
32
|
+
|
33
|
+
|
34
|
+
end # class LDIF
|
35
|
+
|
36
|
+
|
37
|
+
end # module Net
|
38
|
+
|
39
|
+
|
data/lib/net/snmp.rb
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
# $Id$
|
2
|
+
#
|
3
|
+
# NET::SNMP
|
4
|
+
#
|
5
|
+
#----------------------------------------------------------------------------
|
6
|
+
#
|
7
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
8
|
+
#
|
9
|
+
# Gmail: garbagecat10
|
10
|
+
#
|
11
|
+
# This program is free software; you can redistribute it and/or modify
|
12
|
+
# it under the terms of the GNU General Public License as published by
|
13
|
+
# the Free Software Foundation; either version 2 of the License, or
|
14
|
+
# (at your option) any later version.
|
15
|
+
#
|
16
|
+
# This program is distributed in the hope that it will be useful,
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
# GNU General Public License for more details.
|
20
|
+
#
|
21
|
+
# You should have received a copy of the GNU General Public License
|
22
|
+
# along with this program; if not, write to the Free Software
|
23
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
24
|
+
#
|
25
|
+
#---------------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'net/ber'
|
30
|
+
|
31
|
+
|
32
|
+
module Net
|
33
|
+
|
34
|
+
class SNMP
|
35
|
+
|
36
|
+
AsnSyntax = BER.compile_syntax({
|
37
|
+
:application => {
|
38
|
+
:primitive => {
|
39
|
+
1 => :integer, # Counter32, (RFC2578 sec 2)
|
40
|
+
2 => :integer, # Gauge32 or Unsigned32, (RFC2578 sec 2)
|
41
|
+
3 => :integer # TimeTicks32, (RFC2578 sec 2)
|
42
|
+
},
|
43
|
+
:constructed => {
|
44
|
+
}
|
45
|
+
},
|
46
|
+
:context_specific => {
|
47
|
+
:primitive => {
|
48
|
+
},
|
49
|
+
:constructed => {
|
50
|
+
0 => :array, # GetRequest PDU (RFC1157 pgh 4.1.2)
|
51
|
+
1 => :array, # GetNextRequest PDU (RFC1157 pgh 4.1.3)
|
52
|
+
2 => :array # GetResponse PDU (RFC1157 pgh 4.1.4)
|
53
|
+
}
|
54
|
+
}
|
55
|
+
})
|
56
|
+
|
57
|
+
# SNMP 32-bit counter.
|
58
|
+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
59
|
+
# A 32-bit counter is an ASN.1 application [1] implicit unsigned integer
|
60
|
+
# with a range from 0 to 2^^32 - 1.
|
61
|
+
class Counter32
|
62
|
+
def initialize value
|
63
|
+
@value = value
|
64
|
+
end
|
65
|
+
def to_ber
|
66
|
+
@value.to_ber_application(1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# SNMP 32-bit gauge.
|
71
|
+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
72
|
+
# A 32-bit counter is an ASN.1 application [2] implicit unsigned integer.
|
73
|
+
# This is also indistinguishable from Unsigned32. (Need to alias them.)
|
74
|
+
class Gauge32
|
75
|
+
def initialize value
|
76
|
+
@value = value
|
77
|
+
end
|
78
|
+
def to_ber
|
79
|
+
@value.to_ber_application(2)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# SNMP 32-bit timer-ticks.
|
84
|
+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
85
|
+
# A 32-bit counter is an ASN.1 application [3] implicit unsigned integer.
|
86
|
+
class TimeTicks32
|
87
|
+
def initialize value
|
88
|
+
@value = value
|
89
|
+
end
|
90
|
+
def to_ber
|
91
|
+
@value.to_ber_application(3)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class SnmpPdu
|
97
|
+
class Error < StandardError; end
|
98
|
+
|
99
|
+
PduTypes = [
|
100
|
+
:get_request,
|
101
|
+
:get_next_request,
|
102
|
+
:get_response,
|
103
|
+
:set_request,
|
104
|
+
:trap
|
105
|
+
]
|
106
|
+
ErrorStatusCodes = { # Per RFC1157, pgh 4.1.1
|
107
|
+
0 => "noError",
|
108
|
+
1 => "tooBig",
|
109
|
+
2 => "noSuchName",
|
110
|
+
3 => "badValue",
|
111
|
+
4 => "readOnly",
|
112
|
+
5 => "genErr"
|
113
|
+
}
|
114
|
+
|
115
|
+
class << self
|
116
|
+
def parse ber_object
|
117
|
+
n = new
|
118
|
+
n.send :parse, ber_object
|
119
|
+
n
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
attr_reader :version, :community, :pdu_type, :variables, :error_status
|
124
|
+
attr_accessor :request_id, :error_index
|
125
|
+
|
126
|
+
|
127
|
+
def initialize args={}
|
128
|
+
@version = args[:version] || 0
|
129
|
+
@community = args[:community] || "public"
|
130
|
+
@pdu_type = args[:pdu_type] # leave nil unless specified; there's no reasonable default value.
|
131
|
+
@error_status = args[:error_status] || 0
|
132
|
+
@error_index = args[:error_index] || 0
|
133
|
+
@variables = args[:variables] || []
|
134
|
+
end
|
135
|
+
|
136
|
+
#--
|
137
|
+
def parse ber_object
|
138
|
+
begin
|
139
|
+
parse_ber_object ber_object
|
140
|
+
rescue Error
|
141
|
+
# Pass through any SnmpPdu::Error instances
|
142
|
+
raise $!
|
143
|
+
rescue
|
144
|
+
# Wrap any basic parsing error so it becomes a PDU-format error
|
145
|
+
raise Error.new( "snmp-pdu format error" )
|
146
|
+
end
|
147
|
+
end
|
148
|
+
private :parse
|
149
|
+
|
150
|
+
def parse_ber_object ber_object
|
151
|
+
send :version=, ber_object[0].to_i
|
152
|
+
send :community=, ber_object[1].to_s
|
153
|
+
|
154
|
+
data = ber_object[2]
|
155
|
+
case (app_tag = data.ber_identifier & 31)
|
156
|
+
when 0
|
157
|
+
send :pdu_type=, :get_request
|
158
|
+
parse_get_request data
|
159
|
+
when 1
|
160
|
+
send :pdu_type=, :get_next_request
|
161
|
+
# This PDU is identical to get-request except for the type.
|
162
|
+
parse_get_request data
|
163
|
+
when 2
|
164
|
+
send :pdu_type=, :get_response
|
165
|
+
# This PDU is identical to get-request except for the type,
|
166
|
+
# the error_status and error_index values are meaningful,
|
167
|
+
# and the fact that the variable bindings will be non-null.
|
168
|
+
parse_get_response data
|
169
|
+
else
|
170
|
+
raise Error.new( "unknown snmp-pdu type: #{app_tag}" )
|
171
|
+
end
|
172
|
+
end
|
173
|
+
private :parse_ber_object
|
174
|
+
|
175
|
+
#--
|
176
|
+
# Defined in RFC1157, pgh 4.1.2.
|
177
|
+
def parse_get_request data
|
178
|
+
send :request_id=, data[0].to_i
|
179
|
+
# data[1] is error_status, always zero.
|
180
|
+
# data[2] is error_index, always zero.
|
181
|
+
send :error_status=, 0
|
182
|
+
send :error_index=, 0
|
183
|
+
data[3].each {|n,v|
|
184
|
+
# A variable-binding, of which there may be several,
|
185
|
+
# consists of an OID and a BER null.
|
186
|
+
# We're ignoring the null, we might want to verify it instead.
|
187
|
+
unless v.is_a?(Net::BER::BerIdentifiedNull)
|
188
|
+
raise Error.new(" invalid variable-binding in get-request" )
|
189
|
+
end
|
190
|
+
add_variable_binding n, nil
|
191
|
+
}
|
192
|
+
end
|
193
|
+
private :parse_get_request
|
194
|
+
|
195
|
+
#--
|
196
|
+
# Defined in RFC1157, pgh 4.1.4
|
197
|
+
def parse_get_response data
|
198
|
+
send :request_id=, data[0].to_i
|
199
|
+
send :error_status=, data[1].to_i
|
200
|
+
send :error_index=, data[2].to_i
|
201
|
+
data[3].each {|n,v|
|
202
|
+
# A variable-binding, of which there may be several,
|
203
|
+
# consists of an OID and a BER null.
|
204
|
+
# We're ignoring the null, we might want to verify it instead.
|
205
|
+
add_variable_binding n, v
|
206
|
+
}
|
207
|
+
end
|
208
|
+
private :parse_get_response
|
209
|
+
|
210
|
+
|
211
|
+
def version= ver
|
212
|
+
unless [0,2].include?(ver)
|
213
|
+
raise Error.new("unknown snmp-version: #{ver}")
|
214
|
+
end
|
215
|
+
@version = ver
|
216
|
+
end
|
217
|
+
|
218
|
+
def pdu_type= t
|
219
|
+
unless PduTypes.include?(t)
|
220
|
+
raise Error.new("unknown pdu-type: #{t}")
|
221
|
+
end
|
222
|
+
@pdu_type = t
|
223
|
+
end
|
224
|
+
|
225
|
+
def error_status= es
|
226
|
+
unless ErrorStatusCodes.has_key?(es)
|
227
|
+
raise Error.new("unknown error-status: #{es}")
|
228
|
+
end
|
229
|
+
@error_status = es
|
230
|
+
end
|
231
|
+
|
232
|
+
def community= c
|
233
|
+
@community = c.to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
#--
|
237
|
+
# Syntactic sugar
|
238
|
+
def add_variable_binding name, value=nil
|
239
|
+
@variables ||= []
|
240
|
+
@variables << [name, value]
|
241
|
+
end
|
242
|
+
|
243
|
+
def to_ber_string
|
244
|
+
[
|
245
|
+
version.to_ber,
|
246
|
+
community.to_ber,
|
247
|
+
pdu_to_ber_string
|
248
|
+
].to_ber_sequence
|
249
|
+
end
|
250
|
+
|
251
|
+
#--
|
252
|
+
# Helper method that returns a PDU payload in BER form,
|
253
|
+
# depending on the PDU type.
|
254
|
+
def pdu_to_ber_string
|
255
|
+
case pdu_type
|
256
|
+
when :get_request
|
257
|
+
[
|
258
|
+
request_id.to_ber,
|
259
|
+
error_status.to_ber,
|
260
|
+
error_index.to_ber,
|
261
|
+
[
|
262
|
+
@variables.map {|n,v|
|
263
|
+
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
|
264
|
+
}
|
265
|
+
].to_ber_sequence
|
266
|
+
].to_ber_contextspecific(0)
|
267
|
+
when :get_next_request
|
268
|
+
[
|
269
|
+
request_id.to_ber,
|
270
|
+
error_status.to_ber,
|
271
|
+
error_index.to_ber,
|
272
|
+
[
|
273
|
+
@variables.map {|n,v|
|
274
|
+
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
|
275
|
+
}
|
276
|
+
].to_ber_sequence
|
277
|
+
].to_ber_contextspecific(1)
|
278
|
+
when :get_response
|
279
|
+
[
|
280
|
+
request_id.to_ber,
|
281
|
+
error_status.to_ber,
|
282
|
+
error_index.to_ber,
|
283
|
+
[
|
284
|
+
@variables.map {|n,v|
|
285
|
+
[n.to_ber_oid, v.to_ber].to_ber_sequence
|
286
|
+
}
|
287
|
+
].to_ber_sequence
|
288
|
+
].to_ber_contextspecific(2)
|
289
|
+
else
|
290
|
+
raise Error.new( "unknown pdu-type: #{pdu_type}" )
|
291
|
+
end
|
292
|
+
end
|
293
|
+
private :pdu_to_ber_string
|
294
|
+
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|