net-ldap 0.0.5 → 0.1.0
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/History.txt +7 -6
- data/LICENSE +3 -2
- data/Manifest.txt +13 -5
- data/README.txt +34 -28
- data/Rakefile +115 -11
- data/lib/net-ldap.rb +1 -0
- data/lib/net/ber.rb +52 -514
- data/lib/net/ber/ber_parser.rb +112 -0
- data/lib/net/ldap.rb +486 -540
- data/lib/net/ldap/core_ext/all.rb +43 -0
- data/lib/net/ldap/core_ext/array.rb +42 -0
- data/lib/net/ldap/core_ext/bignum.rb +25 -0
- data/lib/net/ldap/core_ext/false_class.rb +11 -0
- data/lib/net/ldap/core_ext/fixnum.rb +64 -0
- data/lib/net/ldap/core_ext/string.rb +40 -0
- data/lib/net/ldap/core_ext/true_class.rb +11 -0
- data/lib/net/ldap/dataset.rb +64 -73
- data/lib/net/ldap/entry.rb +0 -9
- data/lib/net/ldap/filter.rb +1 -8
- data/lib/net/ldap/pdu.rb +2 -3
- data/lib/net/ldap/psw.rb +31 -38
- data/lib/net/ldif.rb +2 -7
- data/lib/net/snmp.rb +2 -4
- data/spec/integration/ssl_ber_spec.rb +36 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/ber/ber_spec.rb +18 -0
- data/test/common.rb +0 -4
- data/test/test_ber.rb +73 -95
- data/test/test_filter.rb +1 -1
- data/test/test_ldif.rb +1 -1
- data/test/test_snmp.rb +61 -78
- data/testserver/ldapserver.rb +0 -19
- metadata +118 -24
- data/Release-Announcement +0 -95
- data/pre-setup.rb +0 -45
- data/setup.rb +0 -1366
- data/tests/NOTICE.txt +0 -6
- data/tests/testldap.rb +0 -190
data/History.txt
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
-
=== Net::LDAP 0.0
|
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
|
3
|
-
the terms of the GPL (see the file COPYING), or the
|
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
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
4
|
-
|
5
|
-
== DESCRIPTION:
|
3
|
+
== Description
|
6
4
|
|
7
5
|
Pure Ruby LDAP library.
|
8
6
|
|
9
|
-
==
|
7
|
+
== Where
|
8
|
+
|
9
|
+
=== Issues & Project Homepage
|
10
|
+
|
11
|
+
http://rubyforge.org/projects/net-ldap
|
12
|
+
|
13
|
+
=== Code
|
10
14
|
|
11
|
-
|
12
|
-
for accessing distributed directory services.
|
15
|
+
http://github.com/RoryO/ruby-net-ldap/
|
13
16
|
|
14
|
-
|
15
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
50
|
+
* Francis Cianfrocca blackhedd@rubyforge.org
|
47
51
|
|
48
52
|
Contributions since:
|
49
53
|
|
50
|
-
*
|
51
|
-
*
|
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
|
-
|
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
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
1
|
+
require "rubygems"
|
2
|
+
require 'hanna/rdoctask'
|
4
3
|
require 'hoe'
|
5
4
|
|
6
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
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
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
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
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
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'
|