net-ssh-kerberos 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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