net-ssh-kerberos 0.1.3 → 0.2.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.
data/Rakefile CHANGED
@@ -7,14 +7,13 @@ begin
7
7
  gem.name = "net-ssh-kerberos"
8
8
  gem.summary = %Q{Add Kerberos support to Net::SSH}
9
9
  gem.description = <<-EOTEXT
10
- Adds support for Microsoft Kerberos (SSPI) with the Net:SSH gem.
10
+ Extends Net::SSH by adding Kerberos authentication capability for password-less logins on multiple platforms.
11
11
  EOTEXT
12
12
  gem.email = "joe@ankhcraft.com"
13
13
  gem.homepage = "http://github.com/joekhoobyar/net-ssh-kerberos"
14
14
  gem.authors = ["Joe Khoobyar"]
15
15
  gem.rubyforge_project = 'net-ssh-krb'
16
16
  gem.add_runtime_dependency(%q<net-ssh>, [">= 2.0"])
17
- gem.add_runtime_dependency(%q<rubysspi>, [">= 1.3"])
18
17
 
19
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
19
  end
@@ -42,6 +41,33 @@ rescue LoadError
42
41
  end
43
42
  end
44
43
 
44
+ # These are new tasks
45
+ begin
46
+ require 'rake/contrib/sshpublisher'
47
+ namespace :rubyforge do
48
+
49
+ desc "Release gem and RDoc documentation to RubyForge"
50
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
51
+
52
+ namespace :release do
53
+ desc "Publish RDoc to RubyForge."
54
+ task :docs => [:rdoc] do
55
+ config = YAML.load(
56
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
57
+ )
58
+
59
+ host = "#{config['username']}@rubyforge.org"
60
+ remote_dir = "/var/www/gforge-projects/net-ssh-krb/"
61
+ local_dir = 'doc'
62
+
63
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
64
+ end
65
+ end
66
+ end
67
+ rescue LoadError
68
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
69
+ end
70
+
45
71
 
46
72
  task :default => :test
47
73
 
@@ -53,9 +79,12 @@ Rake::RDocTask.new do |rdoc|
53
79
  else
54
80
  version = ""
55
81
  end
82
+ rdoc.options << '--line-numbers' << '--inline-source' <<
83
+ '--main' << 'README.rdoc' <<
84
+ '--charset' << 'utf-8'
56
85
 
57
- rdoc.rdoc_dir = 'rdoc'
58
- rdoc.title = "Net-ssh-kerberos #{version}"
86
+ rdoc.rdoc_dir = 'doc'
87
+ rdoc.title = "Net::SSH::Kerberos #{version}"
59
88
  rdoc.rdoc_files.include('README*')
60
89
  rdoc.rdoc_files.include('lib/**/*.rb')
61
90
  end
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 1
4
- :patch: 3
3
+ :minor: 2
4
+ :patch: 0
@@ -10,20 +10,17 @@ module Net
10
10
  class GssapiWithMic < Abstract
11
11
  include Net::SSH::Kerberos::Constants
12
12
 
13
- # OID 1.2.840.113554.1.2.2 - Kerberos 5 (RFC 1964)
14
- SUPPORTED_OID = "\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
15
-
16
13
  # Attempts to perform gssapi-with-mic Kerberos authentication
17
14
  def authenticate(next_service, username, password=nil)
18
- gss_klass = (defined?(Net::SSH::Kerberos::SSPI::Context) ?
19
- Net::SSH::Kerberos::SSPI::Context : Net::SSH::Kerberos::GSS::Context)
15
+ gss_klass = (defined?(Net::SSH::Kerberos::Drivers::SSPI::Context) ?
16
+ Net::SSH::Kerberos::Drivers::SSPI::Context : Net::SSH::Kerberos::Drivers::GSS::Context)
20
17
  gss = nil
21
18
 
22
19
  # Try to start gssapi-with-mic authentication.
23
20
  debug { "trying kerberos authentication" }
24
21
  req = userauth_request(username, next_service, "gssapi-with-mic")
25
- req.write_long 1
26
- req.write_string SUPPORTED_OID
22
+ req.write_long(1)
23
+ req.write_string(supported_oid = 6.chr + GSS_KRB5_MECH.length.chr + GSS_KRB5_MECH)
27
24
  send_message req
28
25
  message = session.next_message
29
26
  case message.type
@@ -38,7 +35,7 @@ module Net
38
35
 
39
36
  # Try to match the OID.
40
37
  oid = message.read_string
41
- if oid != SUPPORTED_OID
38
+ if oid != supported_oid
42
39
  info { "gssapi-with-mic failed (USERAUTH_GSSAPI_RESPONSE)" }
43
40
  return false
44
41
  end
@@ -1,24 +1,11 @@
1
1
  require 'net/ssh'
2
+ require 'net/ssh/errors'
3
+
4
+ module Net; module SSH; module Kerberos
5
+ end; end; end
6
+
2
7
  require 'net/ssh/kerberos/constants'
8
+ require 'net/ssh/kerberos/context'
9
+ require 'net/ssh/kerberos/drivers'
3
10
  #require 'net/ssh/kerberos/kex'
4
-
5
- if RUBY_PLATFORM.include?('win') && ! RUBY_PLATFORM.include?('dar'); then
6
- begin
7
- require 'net/ssh/kerberos/sspi'
8
- rescue Exception => e
9
- if RuntimeError === e and e.message =~ /^LoadLibrary: ([^\s]+)/
10
- $stderr.puts "error: While loading Kerberos SSPI: failed to load library: #{$1}"
11
- else
12
- raise e
13
- end
14
- end
15
- end
16
- require 'net/ssh/kerberos/gss'
17
11
  require 'net/ssh/authentication/methods/gssapi_with_mic'
18
-
19
- module Net
20
- module SSH
21
- module Kerberos
22
- end
23
- end
24
- end
@@ -1,11 +1,7 @@
1
1
  module Net; module SSH; module Kerberos
2
2
  module Constants
3
3
 
4
-
5
- #--
6
4
  # GSSAPI Key exchange method specific messages
7
- #++
8
-
9
5
  KEXGSS_INIT = 30
10
6
  KEXGSS_CONTINUE = 31
11
7
  KEXGSS_COMPLETE = 32
@@ -14,10 +10,7 @@ module Net; module SSH; module Kerberos
14
10
  KEXGSS_GROUPREQ = 40
15
11
  KEXGSS_GROUP = 41
16
12
 
17
- #--
18
13
  # GSSAPI User authentication method specific messages
19
- #++
20
-
21
14
  USERAUTH_GSSAPI_RESPONSE = 60
22
15
  USERAUTH_GSSAPI_TOKEN = 61
23
16
  USERAUTH_GSSAPI_EXCHANGE_COMPLETE = 63
@@ -25,6 +18,9 @@ module Net; module SSH; module Kerberos
25
18
  USERAUTH_GSSAPI_ERRTOK = 65
26
19
  USERAUTH_GSSAPI_MIC = 66
27
20
 
21
+ # GSSAPI constant OID(s)
22
+ GSS_KRB5_MECH = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
23
+ GSS_KRB5_MECH_USER2USER = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"
28
24
  end
29
25
  end; end; end
30
26
 
@@ -0,0 +1,75 @@
1
+ module Net; module SSH; module Kerberos
2
+
3
+ class Context
4
+
5
+ class GeneralError < StandardError; end
6
+
7
+ class State < Struct.new(:handle, :result, :token, :timestamp)
8
+ def complete?; result.complete? end
9
+ end
10
+
11
+ attr_reader :cred_name, :cred_krb_name, :server_name, :server_krb_name
12
+
13
+ def initialize
14
+ raise "Don't create this class directly - use a subclass" if self.class == Context
15
+ end
16
+
17
+ def create(user, host)
18
+ dispose if @credentials or @target or @handle
19
+
20
+ creds, name = acquire_current_credentials
21
+ begin
22
+ @cred_name = name.to_s.sub(/^[^\\\/]*[\\\/]/, '')
23
+ @cred_krb_name = @cred_name.gsub('@', '/');
24
+
25
+ z = (user.include?('@') ? user.gsub('@','/') : user+'/')
26
+ unless z.downcase == @cred_krb_name[0,z.length].downcase
27
+ raise GeneralError, "Credentials mismatch: current is #{@cred_name}, requested is #{user}"
28
+ end
29
+ @credentials = creds
30
+ ensure
31
+ if @credentials.nil?
32
+ release_credentials creds
33
+ @cred_name = @cred_krb_name = nil
34
+ end
35
+ end
36
+
37
+ @server_name = Socket.gethostbyname(host)[0]
38
+ @target, @server_krb_name = import_server_name host
39
+
40
+ true
41
+ end
42
+
43
+ def credentials?; ! @credentials.nil? end
44
+
45
+ def established?; ! @handle.nil? && (@state.nil? || @state.complete?) end
46
+
47
+ def init(token=nil); raise NotImplementedError, "subclasses must implement this method" end
48
+
49
+ def get_mic(token); raise NotImplementedError, "subclasses must implement this method" end
50
+
51
+ def dispose
52
+ @handle and delete_context @handle
53
+ @credentials and release_credentials @credentials
54
+ @target and release_server_name @target
55
+ ensure
56
+ @credentials = @cred_name = @cred_krb_name = nil
57
+ @target = @server_name = @server_krb_name = nil
58
+ @handle = @state = nil
59
+ end
60
+
61
+ private
62
+
63
+ def acquire_current_credentials; raise NotImplementedError, "subclasses must implement this method" end
64
+
65
+ def release_credentials(creds); raise NotImplementedError, "subclasses must implement this method" end
66
+
67
+ def import_server_name(host); raise NotImplementedError, "subclasses must implement this method" end
68
+
69
+ def release_server_name(target); raise NotImplementedError, "subclasses must implement this method" end
70
+
71
+ def delete_context(handle); raise NotImplementedError, "subclasses must implement this method" end
72
+
73
+ end
74
+
75
+ end; end; end
@@ -0,0 +1,57 @@
1
+ require 'dl/import'
2
+ require 'dl/struct'
3
+
4
+ module Net; module SSH; module Kerberos;
5
+
6
+ module Drivers
7
+
8
+ # Some useful DL extensions.
9
+ module DLExtensions
10
+ PTR_ENC = proc{|v| v && (DL::PtrData===v ? v : v.to_ptr) }
11
+ PTR_REF_ENC = proc{|v| (v.nil? ? DL::PtrData.new(v) : (DL::PtrData===v ? v : v.to_ptr)).ref }
12
+
13
+ module ClassMethods
14
+ def PTR_DEC(t) proc{|v| v && t.new(v)} end
15
+ def PTR_REF_DEC(t) proc{|v| v && v.ptr && t.new(v.ptr)} end
16
+
17
+ def struct2(fields, &block)
18
+ t = struct fields
19
+ return t unless block_given?
20
+ t.instance_variable_set :@methods, Module.new(&block)
21
+ class << t
22
+ alias :new_struct :new
23
+ def new(ptr)
24
+ mem = new_struct(ptr)
25
+ mem.extend @methods
26
+ mem
27
+ end
28
+ end
29
+ t
30
+ end
31
+ end
32
+
33
+ def self.included(base)
34
+ base.extend ClassMethods
35
+ end
36
+ end
37
+
38
+ @@available = []
39
+ def self.available; @@available end
40
+
41
+ if RUBY_PLATFORM.include?('win') && ! RUBY_PLATFORM.include?('dar'); then
42
+ begin require 'net/ssh/kerberos/drivers/sspi'; available << 'SSPI'
43
+ rescue => e
44
+ raise e unless RuntimeError === e and e.message =~ /^LoadLibrary: ([^\s]+)/
45
+ $stderr.puts "error: While loading Kerberos SSPI: failed to load library: #{$1}"
46
+ end
47
+ end
48
+ begin require 'net/ssh/kerberos/drivers/gss'; available << 'GSS'
49
+ rescue => e; raise e if available.empty?
50
+ end
51
+
52
+ if available.empty?
53
+ $stderr.puts "error: Failed to a find a supported GSS implementation on this platform (#{RUBY_PLATFORM})"
54
+ end
55
+ end
56
+
57
+ end; end; end
@@ -0,0 +1,263 @@
1
+ module Net; module SSH; module Kerberos; module Drivers;
2
+
3
+ module GSS
4
+
5
+ include Net::SSH::Kerberos::Constants
6
+
7
+ GSS_C_INITIATE = 1
8
+
9
+ GSS_C_DELEG_FLAG = 1
10
+ GSS_C_MUTUAL_FLAG = 2
11
+ GSS_C_REPLAY_FLAG = 4
12
+ GSS_C_SEQUENCE_FLAG = 8
13
+ GSS_C_CONF_FLAG = 16
14
+ GSS_C_INTEG_FLAG = 32
15
+ GSS_C_ANON_FLAG = 64
16
+ GSS_C_PROT_READY_FLAG = 128
17
+ GSS_C_TRANS_FLAG = 256
18
+
19
+ GSS_C_NO_NAME = nil
20
+ GSS_C_NO_BUFFER = nil
21
+ GSS_C_NO_OID = nil
22
+ GSS_C_NO_OID_SET = nil
23
+ GSS_C_NO_CONTEXT = nil
24
+ GSS_C_NO_CREDENTIAL = nil
25
+ GSS_C_NO_CHANNEL_BINDINGS = nil
26
+ GSS_C_QOP_DEFAULT = 0
27
+
28
+ GSS_S_COMPLETE = 0
29
+ GSS_S_CONTINUE_NEEDED = 1
30
+ GSS_S_DUPLICATE_TOKEN = 2
31
+ GSS_S_OLD_TOKEN = 4
32
+ GSS_S_UNSEQ_TOKEN = 8
33
+ GSS_S_GAP_TOKEN = 16
34
+
35
+ GSS_C_GSS_CODE = 1
36
+ GSS_C_MECH_CODE = 2
37
+
38
+ module API
39
+ extend DL::Importable
40
+ include DLExtensions
41
+
42
+ def self.gss_func(sym, sig)
43
+ extern "OM_uint32 #{sym} (OM_uint32_ref, #{sig})"
44
+ module_eval <<-"EOCODE"
45
+ alias :_#{sym} :#{sym}
46
+ module_function :_#{sym}
47
+ def #{sym}(*args)
48
+ _#{sym}(*(args.unshift(0)))
49
+ @retval = GssResult.new(@retval, @args.shift)
50
+ end
51
+ module_function :#{sym}
52
+ EOCODE
53
+ end
54
+
55
+ if RUBY_PLATFORM =~ /cygwin/
56
+ dlload('cyggss-1.dll')
57
+ else
58
+ dlload('libgssapi_krb5.so')
59
+ end
60
+
61
+ typealias "void **", "p", PTR_REF_ENC, proc{|v| v.ptr}
62
+ typealias "GssResult", "L", proc{|v| v.to_i }, proc{|v| GssResult.new(v) }
63
+ typealias 'OM_uint32', 'unsigned int'
64
+ typealias "OM_uint32_ref", 'unsigned int ref'
65
+ typealias 'size_t', 'unsigned int'
66
+ typealias "gss_bytes_t", "P" #, nil, nil, "P", PTR_ENC
67
+ GssBuffer = struct2 [ "size_t length", "gss_bytes_t value" ] do
68
+ def to_s; value.to_s(length) if length > 0 end
69
+ end
70
+ typealias 'gss_buffer_desc', 'GssBuffer'
71
+ typealias 'gss_buffer_t', 'gss_buffer_desc *'
72
+ GssOID = struct2 [ "OM_uint32 length", "gss_bytes_t elements" ] do
73
+ def eql?(oid) !oid.nil? && length==oid.length && to_s==oid.to_s end
74
+ def ==(oid) !oid.nil? && length==oid.length && to_s==oid.to_s end
75
+ def to_s; elements.to_s(length) if length > 0 end
76
+ def inspect; 'OID: ' + (to_s.unpack("H2" * length).join(' ') rescue 'nil') end
77
+ end
78
+ def GssOID.create(bytes) new [bytes.length, bytes].pack("LP#{bytes.length}").to_ptr end
79
+ typealias 'gss_OID', 'P', PTR_ENC, PTR_DEC(GssOID)
80
+ typealias 'gss_OID_ref', 'p', PTR_REF_ENC, PTR_REF_DEC(GssOID)
81
+ GssOIDSet = struct2 [ "size_t count", "gss_OID elements" ] do
82
+ def oids
83
+ if @oids.nil? or elements != (@oids.first.to_ptr rescue nil)
84
+ @oids = []
85
+ 0.upto(count-1) { |n| @oids[n] = GssOID.new(elements + n*GssOID.size) } unless elements.nil?
86
+ end
87
+ @oids
88
+ end
89
+ def inspect; 'OIDSet: [' + oids.map {|o| o.inspect }.join(', ') + ']' end
90
+ end
91
+ typealias 'gss_OID_set', 'P', PTR_ENC, PTR_DEC(GssOIDSet)
92
+ typealias 'gss_OID_set_ref', 'p', PTR_REF_ENC, PTR_REF_DEC(GssOIDSet)
93
+
94
+ typealias 'gss_ctx_id_t', 'void *'
95
+ typealias 'gss_ctx_id_ref', 'void **'
96
+ typealias 'gss_cred_id_t', 'void *'
97
+ typealias 'gss_cred_id_ref', 'void **'
98
+ typealias 'gss_name_t', 'void *'
99
+ typealias 'gss_name_ref', 'void **'
100
+ typealias 'gss_qop_t', 'OM_uint32'
101
+ typealias 'gss_qop_ref', 'OM_uint32_ref'
102
+ typealias 'gss_cred_usage_t', 'int'
103
+ typealias 'gss_cred_usage_ref', 'int ref'
104
+
105
+ class GssResult
106
+ def initialize(code, minor=nil) @value, @minor = code, minor end
107
+ def ok?; major.zero? end
108
+ def complete?; status.zero? end
109
+ def incomplete?; false end
110
+ def failure?; major.nonzero? end
111
+ def temporary_failure?
112
+ routine_error==GSS_S_CREDENTIALS_EXPIRED ||
113
+ routine_error==GSS_S_CONTEXT_EXPIRED ||
114
+ routine_error==GSS_S_UNAVAILABLE
115
+ end
116
+ def major; (@value >> 16) & 0x0000ffff end
117
+ def status; @value & 0x0000ffff end
118
+ def calling_error; (@value >> 24) & 0x000000ff end
119
+ def routine_error; (@value >> 16) & 0x000000ff end
120
+ def to_i; @value end
121
+ def to_s
122
+ orig_retval, orig_args = API._retval_, API._args_
123
+ begin
124
+ msgctx, msgbuff, msglist = 0, API::GssBuffer.malloc, []
125
+ begin
126
+ result = API.gss_display_status @value, GSS_C_GSS_CODE, GSS_C_NO_OID, msgctx, msgbuff
127
+ result.ok? or return 'unknown'
128
+ msgctx = API._args_[3]
129
+ msglist << msgbuff.to_s
130
+ API.gss_release_buffer msgbuff
131
+ end until msgctx.zero?
132
+ msglist.empty? ? 'ok' : msglist.join(', ')
133
+ ensure
134
+ API.instance_eval { @retval = orig_retval; @args = orig_args }
135
+ end
136
+ end
137
+ end
138
+
139
+ gss_func "gss_acquire_cred", "gss_name_t, OM_uint32, gss_OID_set, gss_cred_usage_t, gss_cred_id_ref, void *, OM_uint32_ref"
140
+ gss_func "gss_inquire_cred", "gss_cred_id_t, gss_name_ref, OM_uint32_ref, gss_cred_usage_ref, gss_OID_set_ref"
141
+ gss_func "gss_import_name", "gss_buffer_t, gss_OID, gss_name_ref"
142
+ gss_func "gss_display_name", "gss_name_t, gss_buffer_t, gss_OID_ref"
143
+ gss_func "gss_release_cred", "gss_cred_id_ref"
144
+ gss_func "gss_release_oid_set", "gss_OID_set_ref"
145
+ gss_func "gss_release_name", "gss_name_ref"
146
+ gss_func "gss_release_buffer", "gss_buffer_t"
147
+ gss_func "gss_init_sec_context", "gss_cred_id_t, gss_ctx_id_ref, gss_name_t, gss_OID, OM_uint32, OM_uint32, void *, "+
148
+ "gss_buffer_t, gss_OID_ref, gss_buffer_t, OM_uint32_ref, OM_uint32_ref"
149
+ gss_func "gss_delete_sec_context", "gss_ctx_id_ref, gss_buffer_t"
150
+ gss_func "gss_get_mic", "gss_ctx_id_t, gss_qop_t, gss_buffer_t, gss_buffer_t"
151
+ gss_func "gss_display_status", "OM_uint32, int, gss_OID, OM_uint32_ref, gss_buffer_t"
152
+ gss_func "gss_indicate_mechs", "gss_OID_set_ref"
153
+ end
154
+
155
+ # GSSAPI / Kerberos 5 OID(s)
156
+ GSS_C_NT_PRINCIPAL = API::GssOID.create("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01")
157
+ GSS_C_NT_MACHINE_UID_NAME = API::GssOID.create("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02")
158
+ GSS_C_NT_STRING_UID_NAME = API::GssOID.create("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")
159
+ GSS_C_NT_HOSTBASED_SERVICE = API::GssOID.create("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")
160
+ GSS_C_NT_ANONYMOUS = API::GssOID.create("\x2b\x06\x01\x05\x06\x03")
161
+ GSS_C_NT_EXPORT_NAME = API::GssOID.create("\x2b\x06\x01\x05\x06\x04")
162
+ GSS_C_KRB5 = API::GssOID.create(GSS_KRB5_MECH)
163
+
164
+ # GSSAPI / Kerberos 5 Deprecated / Proprietary OID(s)
165
+ GSS_C_NT_HOSTBASED_SERVICE_X = API::GssOID.create("\x2b\x06\x01\x05\x06\x02")
166
+
167
+ # GSSAPI - Kerberos 5 mechanism support.
168
+ result = API.gss_indicate_mechs nil
169
+ result.ok? or raise "gss_indicate_mechs failed: #{result}"
170
+ if API._args_[0].oids.include? GSS_C_KRB5
171
+ API.gss_release_oid_set API._args_[0]
172
+ else
173
+ raise "This GSSAPI library reports no support for Kerberos authentication"
174
+ end
175
+
176
+ class Context < Net::SSH::Kerberos::Context
177
+
178
+ GssResult = API::GssResult
179
+
180
+ def init(token=nil)
181
+ unless token.nil?
182
+ input = API::GssBuffer.malloc
183
+ input.value = token.to_ptr
184
+ input.length = token.length
185
+ end
186
+ buffer = API::GssBuffer.malloc
187
+ context = @state.handle if @state
188
+ result = API.gss_init_sec_context @credentials, context, @target, GSS_C_KRB5,
189
+ GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG, 60,
190
+ GSS_C_NO_CHANNEL_BINDINGS, input, nil, buffer, 0, 0
191
+ result.failure? and raise GeneralError, "Error initializing security context: #{result}"
192
+ begin
193
+ @state = State.new(API._args_[1], result, buffer.to_s, nil)
194
+ @handle = @state.handle if result.complete?
195
+ return @state.token
196
+ ensure
197
+ API.gss_release_buffer buffer if buffer.value
198
+ end
199
+ end
200
+
201
+ def get_mic(token)
202
+ input = API::GssBuffer.malloc
203
+ input.value = token.to_ptr
204
+ input.length = token.length
205
+ @state.result = API.gss_get_mic @handle, GSS_C_QOP_DEFAULT, input, output=API::GssBuffer.malloc
206
+ unless @state.result.complete? and output
207
+ raise GeneralError, "Error creating the signature: #{@state.result}"
208
+ end
209
+ begin return output.to_s
210
+ ensure API.gss_release_buffer output
211
+ end
212
+ end
213
+
214
+ protected
215
+
216
+ def state; @state end
217
+
218
+ private
219
+
220
+ def acquire_current_credentials
221
+ result = API.gss_acquire_cred nil, 60, nil, GSS_C_INITIATE, nil, nil, 0
222
+ result.ok? or raise GeneralError, "Error acquiring credentials: #{result}"
223
+ result = API.gss_inquire_cred creds=API._args_[4], nil, 0, 0, nil
224
+ result.ok? or raise GeneralError, "Error inquiring credentials: #{result}"
225
+ begin
226
+ name, oids = API._args_[1], API._args_[4]
227
+ result = API.gss_display_name name, buffer=API::GssBuffer.malloc, nil
228
+ result.ok? or raise GeneralError, "Error getting display name: #{result}"
229
+ begin return [creds, buffer.to_s]
230
+ ensure API.gss_release_buffer buffer
231
+ end
232
+ ensure
233
+ API.gss_release_name name
234
+ API.gss_release_oid_set oids
235
+ end
236
+ end
237
+
238
+ def release_credentials(creds)
239
+ creds.nil? or API.gss_release_cred creds
240
+ end
241
+
242
+ def import_server_name(host)
243
+ host = 'host@' + host
244
+ buffer = API::GssBuffer.malloc
245
+ buffer.value = host.to_ptr
246
+ buffer.length = host.length
247
+ result = API.gss_import_name buffer, GSS_C_NT_HOSTBASED_SERVICE, nil
248
+ result.failure? and raise GeneralError, "Error importing name: #{result}"
249
+ [API._args_[2], host]
250
+ end
251
+
252
+ def release_server_name(target)
253
+ target.nil? or API.gss_release_name target
254
+ end
255
+
256
+ def delete_context(handle)
257
+ handle.nil? or API.gss_delete_sec_context handle, nil
258
+ end
259
+
260
+ end
261
+
262
+ end
263
+ end; end; end; end