gssapi-1.2.0/0000755000175000017500000000000012551171260012350 5ustar globusglobusgssapi-1.2.0/lib/0000755000175000017500000000000012551171257013124 5ustar globusglobusgssapi-1.2.0/lib/gssapi.rb0000644000175000017500000000063312551171257014741 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end require 'ffi' module GSSAPI module LibGSSAPI extend FFI::Library FFI::add_typedef(:uint32, :OM_uint32) GSSAPI_LIB_TYPE = :mit unless defined?(GSSAPI_LIB_TYPE) end end require 'gssapi/exceptions' require 'gssapi/lib_gssapi' require 'gssapi/simple' gssapi-1.2.0/lib/gssapi/0000755000175000017500000000000012551171257014412 5ustar globusglobusgssapi-1.2.0/lib/gssapi/heimdal.rb0000644000175000017500000000033412551171257016342 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end module GSSAPI module LibGSSAPI GSSAPI_LIB_TYPE = :heimdal end end gssapi-1.2.0/lib/gssapi/lib_gssapi.rb0000644000175000017500000004334512551171257017064 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end require 'gssapi/lib_gssapi_loader' module GSSAPI module LibGSSAPI # Libc functions # void *malloc(size_t size); attach_function :malloc, [:size_t], :pointer # void *memcpy(void *dest, const void *src, size_t n); attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer # This is a generic Managed Struct subclass that hides the [] methods. # Classes that implement this class should provide accessor methods to get to the attributes. class GssMStruct < FFI::ManagedStruct private def [](key) super(key) end def []=(key,val) super(key,val) end end # This is a generic Unmanaged Struct subclass that hides the [] methods. # Classes that implement this class should provide accessor methods to get to the attributes. class GssUMStruct < FFI::Struct private def [](key) super(key) end def []=(key,val) super(key,val) end end # This module provides a layout for both the managed and unmanaged GssBufferDesc structs. module GssBufferDescLayout def self.included(base) base.class_eval do layout :length, :OM_uint32, :value, :pointer # pointer of :void def length self[:length] end def value if(self[:length] == 0) nil else self[:value].read_string(self[:length]) end end end end end # This class implements the gss_buffer_desc type. Use #pointer to emulate gss_buffer_t # If you are setting the value of the buffer and it is not being set from the function # this is the type of buffer you should use. If the buffer is being allocated and set # inside the function you should use a ManagedGssBufferDesc instead so gss_release_buffer # is called for it. It states in the manpage for each gss function whether or not # gss_release_buffer needs to be called or not. # @example # buff = UnManagedGssBufferDesc.new # buff.value = "This is a test" class UnManagedGssBufferDesc < GssUMStruct include GssBufferDescLayout def initialize(ptr = nil) if(ptr.nil?) super(FFI::Pointer.new(FFI::MemoryPointer.new(self.size))) else super(ptr) end end # Set the value of the string for the "value" parameter. This method also # appropriately sets the length parameter. def value=(val) if(val.nil?) self[:length] = 0 self[:value] = val elsif(val.is_a?(String)) buff = FFI::MemoryPointer.from_string(val) self[:length] = val.length self[:value] = buff elsif(val.is_a?(Fixnum)) buff = FFI::MemoryPointer.new :OM_uint32 buff.write_int val self[:length] = FFI::type_size :OM_uint32 self[:value] = buff else raise StandardError, "Can't handle type #{val.class.name}" end end end # This class implements the gss_buffer_desc type. Use #pointer to emulate gss_buffer_t # Only functions that need to call gss_release_buffer should use this type. It states # in the manpage for each function whether or not it should be called. If it does not # you should be using UnManagedGssBufferDesc instead. class ManagedGssBufferDesc < GssMStruct include GssBufferDescLayout def initialize(ptr = nil) if(ptr.nil?) super(FFI::Pointer.new(FFI::MemoryPointer.new(self.size))) else super(ptr) end end def self.release(ptr) puts "Releasing ManagedGssBufferDesc at #{ptr.address.to_s(16)}" if $DEBUG min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_release_buffer(min_stat, ptr) end end # @example # iov_buff = GssIOVBufferDesc.new # str = FFI::MemoryPointer.from_string("This is the string") # iov_buff[:type] = 1 # iov_buff[:buffer][:length] = str.size # iov_buff[:buffer][:value] = str class GssIOVBufferDesc < FFI::Struct layout :type, :OM_uint32, :buffer, UnManagedGssBufferDesc end class GssChannelBindingsStruct < FFI::Struct layout :initiator_addrtype, :OM_uint32, :initiator_address, UnManagedGssBufferDesc, :acceptor_addrtype, :OM_uint32, :acceptor_address, UnManagedGssBufferDesc, :application_data, UnManagedGssBufferDesc no_chn_bind = FFI::MemoryPointer.new :pointer # no_chn_bind.write_int 0 end # This s a generic AutoPointer. Gss pointers that implement this class should also implement a # class method called release_ptr that releases the structure pointed to by this pointer. class GssPointer < FFI::AutoPointer def address_of ptr_p = FFI::MemoryPointer.new :pointer ptr_p.write_pointer(self) end def self.release(ptr) if( ptr.address == 0 ) puts "Releasing #{self.name} NULL POINTER: Not freeing" if $DEBUG return else puts "Releasing #{self.name} at #{ptr.address.to_s(16)}" if $DEBUG self.release_ptr(ptr) end end end # A wrapper around gss_name_t so that it garbage collects class GssNameT < GssPointer def self.release_ptr(name_ptr) puts "Releasing gss_name_t at #{name_ptr.address.to_s(16)}" if $DEBUG min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_release_name(min_stat, name_ptr) end end class GssCtxIdT < GssPointer def self.release_ptr(context_ptr) min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_delete_sec_context(min_stat, context_ptr, LibGSSAPI::GSS_C_NO_BUFFER) end def self.gss_c_no_context self.new(GSSAPI::LibGSSAPI::GSS_C_NO_CONTEXT) end end # gss_cred_id_t class GssCredIdT < GssPointer def self.release_ptr(cred_ptr) puts "Releasing gss_cred_id_t at #{cred_ptr.address.to_s(16)}" if $DEBUG min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_release_cred(min_stat, cred_ptr) end end # OM_uint32 gss_release_buffer(OM_uint32 * minor_status, gss_buffer_t buffer); # Function definitions # -------------------- # OM_uint32 gss_import_name(OM_uint32 * minor_status, const gss_buffer_t input_name_buffer, const gss_OID input_name_type, gss_name_t * output_name); # @example: # host_str = 'host@example.com' # buff_str = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new # buff_str[:length] = host_str.length # buff_str[:value] = FFI::MemoryPointer.from_string(host_str) # name = FFI::MemoryPointer.new :pointer # gss_name_t # min_stat = FFI::MemoryPointer.new :OM_uint32 # maj_stat = GSSAPI::LibGSSAPI.gss_import_name(min_stat, buff_str.pointer, GSSAPI::LibGSSAPI.GSS_C_NT_HOSTBASED_SERVICE, name) # name = name.get_pointer(0) # Remember to free the allocated name (gss_name_t) space with gss_release_name attach_function :gss_import_name, [:pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_export_name(OM_uint32 * minor_status, const gss_name_t input_name, gss_buffer_t exported_name); attach_function :gss_export_name, [:pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_canonicalize_name(OM_uint32 * minor_status, const gss_name_t input_name, const gss_OID mech_type, gss_name_t * output_name) attach_function :gss_canonicalize_name, [:pointer, :pointer, :pointer, :pointer], :OM_uint32 begin # OM_uint32 gss_oid_to_str(OM_uint32 *minor_status, const gss_OID oid, gss_buffer_t oid_str); # @example: # min_stat = FFI::MemoryPointer.new :OM_uint32 # oidstr = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new # maj_stat = GSSAPI::LibGSSAPI.gss_oid_to_str(min_stat, GSSAPI::LibGSSAPI.GSS_C_NT_HOSTBASED_SERVICE, oidstr.pointer) # oidstr[:value].read_string attach_function :gss_oid_to_str, [:pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_str_to_oid(OM_uint32 *minor_status, const gss_buffer_t oid_str, gss_OID *oid); # @example: Simulate GSS_C_NT_HOSTBASED_SERVICE # min_stat = FFI::MemoryPointer.new :OM_uint32 # str = "{ 1 2 840 113554 1 2 1 4 }" # oidstr = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new # oidstr[:length] = str.length # oidstr[:value] = FFI::MemoryPointer.from_string str # oid = FFI::MemoryPointer.new :pointer # min_stat = FFI::MemoryPointer.new :OM_uint32 # maj_stat = GSSAPI::LibGSSAPI.gss_str_to_oid(min_stat, oidstr.pointer, oid) # oid = GSSAPI::LibGSSAPI::GssOID.new(oid.get_pointer(0)) attach_function :gss_str_to_oid, [:pointer, :pointer, :pointer], :OM_uint32 rescue FFI::NotFoundError => ex warn "WARNING: Could not load OID conversion methods. Check your GSSAPI C library for an update" end # OM_uint32 gss_init_sec_context(OM_uint32 * minor_status, const gss_cred_id_t initiator_cred_handle, # gss_ctx_id_t * context_handle, const gss_name_t target_name, const gss_OID mech_type, OM_uint32 req_flags, # OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, # gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec); attach_function :gss_init_sec_context, [:pointer, :pointer, :pointer, :pointer, :pointer, :OM_uint32, :OM_uint32, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, const gss_cred_id_t acceptor_cred_handle, # const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t *src_name, gss_OID *mech_type, # gss_buffer_t output_token, OM_uint32 *ret_flags, OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle); attach_function :gss_accept_sec_context, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_display_name(OM_uint32 * minor_status, gss_name_t input_name, gss_buffer_t output_name_buffer, gss_OID * output_name_type); attach_function :gss_display_name, [:pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_acquire_cred(OM_uint32 *minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, # gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec); attach_function :gss_acquire_cred, [:pointer, :pointer, :OM_uint32, :pointer, :OM_uint32, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_wrap(OM_uint32 * minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, # gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int * conf_state, gss_buffer_t output_message_buffer); # @example: # min_stat = FFI::MemoryPointer.new :OM_uint32 # Remember to free the allocated output_message_buffer with gss_release_buffer attach_function :gss_wrap, [:pointer, :pointer, :int, :OM_uint32, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_unwrap(OM_uint32 * minor_status, const gss_ctx_id_t context_handle, # const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, gss_qop_t * qop_state); # @example: # min_stat = FFI::MemoryPointer.new :OM_uint32 # Remember to free the allocated output_message_buffer with gss_release_buffer attach_function :gss_unwrap, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_get_mic(OM_uint32 * minor_status, const gss_ctx_id_t context_handle, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer) attach_function :gss_get_mic, [:pointer, :pointer, :OM_uint32, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_delete_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, gss_buffer_t output_token); attach_function :gss_delete_sec_context, [:pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_release_name(OM_uint32 * minor_status, gss_name_t * name); attach_function :gss_release_name, [:pointer, :pointer], :OM_uint32 # OM_uint32 gss_release_buffer(OM_uint32 * minor_status, gss_buffer_t buffer); attach_function :gss_release_buffer, [:pointer, :pointer], :OM_uint32 # OM_uint32 gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle); attach_function :gss_release_cred, [:pointer, :pointer], :OM_uint32 # Used to register alternate keytabs # OM_uint32 krb5_gss_register_acceptor_identity(const char *); attach_function :krb5_gss_register_acceptor_identity, [:string], :OM_uint32 # OM_uint32 gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value, int status_type, gss_OID mech_type, OM_uint32 *message_context, gss_buffer_t status_string) attach_function :gss_display_status, [:pointer, :OM_uint32, :int, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_krb5_copy_ccache(OM_uint32 *minor_status, gss_cred_id_t cred_handle, krb5_ccache out_ccache) attach_function :gss_krb5_copy_ccache, [:pointer, :pointer, :pointer], :OM_uint32 # Variable definitions # -------------------- # Flag bits for context-level services. GSS_C_DELEG_FLAG = 1 GSS_C_MUTUAL_FLAG = 2 GSS_C_REPLAY_FLAG = 4 GSS_C_SEQUENCE_FLAG = 8 GSS_C_CONF_FLAG = 16 GSS_C_INTEG_FLAG = 32 GSS_C_ANON_FLAG = 64 GSS_C_PROT_READY_FLAG = 128 GSS_C_TRANS_FLAG = 256 GSS_C_DELEG_POLICY_FLAG = 32768 # Credential usage options GSS_C_BOTH = 0 GSS_C_INITIATE = 1 GSS_C_ACCEPT = 2 # Misc Constants GSS_C_INDEFINITE = 0xffffffff # Expiration time of 2^32-1 seconds means infinite lifetime for sec or cred context # Message Offsets GSS_C_CALLING_ERROR_OFFSET = 24 GSS_C_ROUTINE_ERROR_OFFSET = 16 GSS_C_SUPPLEMENTARY_OFFSET = 0 # GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul) # GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul) # GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul) # QOP (Quality of Protection) GSS_C_QOP_DEFAULT = 0 # GSSAPI Status & Error Codes GSS_S_COMPLETE = 0 GSS_C_GSS_CODE = 1 GSS_C_MECH_CODE = 2 GSS_C_CALLING_ERRORS = { (1 << GSS_C_CALLING_ERROR_OFFSET) => "GSS_S_CALL_INACCESSIBLE_READ", (2 << GSS_C_CALLING_ERROR_OFFSET) => "GSS_S_CALL_INACCESSIBLE_WRITE", (3 << GSS_C_CALLING_ERROR_OFFSET) => "GSS_S_CALL_BAD_STRUCTURE" } GSS_C_SUPPLEMENTARY_CODES = { (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) => "GSS_S_CONTINUE_NEEDED", (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) => "GSS_S_DUPLICATE_TOKEN", (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) => "GSS_S_OLD_TOKEN", (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) => "GSS_S_UNSEQ_TOKEN", (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) => "GSS_S_GAP_TOKEN" } GSS_C_ROUTINE_ERRORS = { (1 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_MECH", (2 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_NAME", (3 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_NAMETYPE", (4 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_BINDINGS", (5 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_STATUS", (6 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_SIG", (7 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_NO_CRED", (8 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_NO_CONTEXT", (9 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_DEFECTIVE_TOKEN", (10 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_DEFECTIVE_CREDENTIAL", (11 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_CREDENTIALS_EXPIRED", (12 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_CONTEXT_EXPIRED", (13 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_FAILURE", (14 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_BAD_QOP", (15 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_UNAUTHORIZED", (16 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_UNAVAILABLE", (17 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_DUPLICATE_ELEMENT", (18 << GSS_C_ROUTINE_ERROR_OFFSET) => "GSS_S_NAME_NOT_MN" } # IOV Buffer Types (gssapi_ext.h) GSS_IOV_BUFFER_TYPE_EMPTY = 0 GSS_IOV_BUFFER_TYPE_DATA = 1 # Packet data GSS_IOV_BUFFER_TYPE_HEADER = 2 # Mechanism header GSS_IOV_BUFFER_TYPE_MECH_PARAMS = 3 # Mechanism specific parameters GSS_IOV_BUFFER_TYPE_TRAILER = 7 # Mechanism trailer GSS_IOV_BUFFER_TYPE_PADDING = 9 # Padding GSS_IOV_BUFFER_TYPE_STREAM = 10 # Complete wrap token GSS_IOV_BUFFER_TYPE_SIGN_ONLY = 11 # Sign only packet data # Flags GSS_IOV_BUFFER_FLAG_MASK = 0xFFFF0000 GSS_IOV_BUFFER_FLAG_ALLOCATE = 0x00010000 # indicates GSS should allocate GSS_IOV_BUFFER_FLAG_ALLOCATED = 0x00020000 # indicates caller should free # Various Null values. (gssapi.h) GSS_C_NO_NAME = FFI::Pointer.new(:pointer, 0) # ((gss_name_t) 0) GSS_C_NO_BUFFER = FFI::Pointer.new(:pointer, 0) # ((gss_buffer_t) 0) GSS_C_NO_OID = FFI::Pointer.new(:pointer, 0) # ((gss_OID) 0) GSS_C_NO_OID_SET = FFI::Pointer.new(:pointer, 0) # ((gss_OID_set) 0) GSS_C_NO_CONTEXT = FFI::Pointer.new(:pointer, 0) # ((gss_ctx_id_t) 0) GSS_C_NO_CREDENTIAL = FFI::Pointer.new(:pointer, 0) # ((gss_cred_id_t) 0) GSS_C_NO_CHANNEL_BINDINGS = FFI::Pointer.new(:pointer, 0) # ((gss_channel_bindings_t) 0) GSS_C_EMPTY_BUFFER = ManagedGssBufferDesc.new end #end LibGSSAPI end #end GSSAPI gssapi-1.2.0/lib/gssapi/simple.rb0000644000175000017500000003042212551171257016231 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end module GSSAPI # This class is a simple wrapper around the most common usage of GSSAPI. If you are looking at doing # something a bit more advanced you may want to check out the LibGSSAPI module. class Simple attr_reader :context attr_reader :delegated_credentials # Initialize a new GSSAPI::Simple object # @param [String] host_name the fully qualified host name # @param [String] service_name The service name. This can either be a # GSS_KRB5_NT_PRINCIPAL_NAME in the form of srvc/fqdn@REALM # or # GSS_C_NT_HOSTBASED_SERVICE in the form of srvc@fqdn # If there is no '@fqdn' part, the host_name will be appended. # If no service_name is given at all the default service of 'host@fqdn' will be used. def initialize(host_name, service_name=nil, keytab=nil) @host = host_name @service = service_name.nil? ? "host@#{@host}" : (service_name.include?('@') ? service_name : "#{service_name}@#{@host}") @int_svc_name = import_name(@service) @context = nil # the security context @scred = nil # the service credentials. really only used for the server-side via acquire_credentials set_keytab(keytab) unless keytab.nil? @delegated_credentials = nil end # Convert a String to a GSSAPI usable buffer (gss_buffer_desc) # @param [String] str the string to convert def import_name(str) buff_str = LibGSSAPI::UnManagedGssBufferDesc.new buff_str.value = str # Choose the appropriate mechanism based on the string passed. if (str =~ /[A-Za-z0-9]+\/[^@]+@.+$/) mech = LibGSSAPI::GssOID.gss_c_no_oid else mech = LibGSSAPI::GSS_C_NT_HOSTBASED_SERVICE end name = FFI::MemoryPointer.new :pointer # gss_name_t min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_import_name(min_stat, buff_str.pointer, mech, name) raise GssApiError.new(maj_stat, min_stat), "gss_import_name did not return GSS_S_COMPLETE" if maj_stat != 0 LibGSSAPI::GssNameT.new(name.get_pointer(0)) end # Initialize the GSS security context (client initiator). If there was a previous call that issued a # continue you can pass the continuation token in via the token param. # If no flags are set the default flags are LibGSSAPI::GSS_C_MUTUAL_FLAG | LibGSSAPI::GSS_C_SEQUENCE_FLAG # @param [String] in_token an input token sent from the remote service in a continuation. # @param [Hash] opts misc opts to be set # @option opts [Fixnum] :flags override all other flags. If you set the :delegate option this option will override it. # @see http://tools.ietf.org/html/rfc4121#section-4.1.1.1 # @option opts [Boolean] :delegate if true set the credential delegate flag # @return [String, true] if a continuation flag is set it will return the output token that is needed to send # to the remote host. Otherwise it returns true and the GSS security context has been established. def init_context(in_token = nil, opts = {}) min_stat = FFI::MemoryPointer.new :OM_uint32 pctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of) mech = LibGSSAPI::GssOID.gss_c_no_oid if(opts[:flags]) flags = opts[:flags] else flags = (LibGSSAPI::GSS_C_MUTUAL_FLAG | LibGSSAPI::GSS_C_SEQUENCE_FLAG | LibGSSAPI::GSS_C_CONF_FLAG | LibGSSAPI::GSS_C_INTEG_FLAG) flags |= LibGSSAPI::GSS_C_DELEG_FLAG if opts[:delegate] flags |= LibGSSAPI::GSS_C_DELEG_POLICY_FLAG if opts[:delegate] end in_tok = LibGSSAPI::UnManagedGssBufferDesc.new in_tok.value = in_token out_tok = LibGSSAPI::ManagedGssBufferDesc.new ret_flags = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_init_sec_context(min_stat, nil, pctx, @int_svc_name, mech, flags, 0, nil, in_tok.pointer, nil, out_tok.pointer, ret_flags, nil) raise GssApiError.new(maj_stat, min_stat), "gss_init_sec_context did not return GSS_S_COMPLETE" if maj_stat > 1 # The returned context may be equal to the passed in @context. If so, we # must not create another AutoPointer to the same gss_buffer_t. If we do # we will double delete it. ctx = pctx.get_pointer(0) @context = LibGSSAPI::GssCtxIdT.new(ctx) if ctx != @context maj_stat == 1 ? out_tok.value : true end # Accept a security context that was initiated by a remote peer. # @param [String] in_token The token sent by the remote client to initiate the context # @return [String, true] If this is part of a continuation it will return a token to be passed back to the remote # otherwise it will simply return true. def accept_context(in_token) raise GssApiError, "No credentials yet acquired. Call #{self.class.name}#acquire_credentials first" if @scred.nil? min_stat = FFI::MemoryPointer.new :OM_uint32 pctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of) no_chn_bind = LibGSSAPI::GSS_C_NO_CHANNEL_BINDINGS @client = FFI::MemoryPointer.new :pointer # Will hold the initiating client name after the call mech = FFI::MemoryPointer.new :pointer # Will hold the mech being used after the call in_tok = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_tok.value = in_token out_tok = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new ret_flags = FFI::MemoryPointer.new :OM_uint32 delegated_cred_handle = FFI::MemoryPointer.new :pointer maj_stat = LibGSSAPI.gss_accept_sec_context(min_stat, pctx, @scred, in_tok.pointer, no_chn_bind, @client, mech, out_tok.pointer, ret_flags, nil, delegated_cred_handle) raise GssApiError.new(maj_stat, min_stat), "gss_accept_sec_context did not return GSS_S_COMPLETE" if maj_stat > 1 if (ret_flags.read_uint32 & LibGSSAPI::GSS_C_DELEG_FLAG) != 0 @delegated_credentials = LibGSSAPI::GssCredIdT.new(delegated_cred_handle.get_pointer(0)) end # The returned context may be equal to the passed in @context. If so, we # must not create another AutoPointer to the same gss_buffer_t. If we do # we will double delete it. ctx = pctx.get_pointer(0) @context = LibGSSAPI::GssCtxIdT.new(ctx) if ctx != @context out_tok.length > 0 ? out_tok.value : true end def get_mic(token) min_stat = FFI::MemoryPointer.new :OM_uint32 qop_req = GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = token out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new maj_stat = GSSAPI::LibGSSAPI.gss_get_mic(min_stat, @context, qop_req, in_buff.pointer, out_buff.pointer) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_get_mic" if maj_stat != 0 out_buff.value end # Get textual representation of internal GSS name # @return [String] textual representation of internal GSS name def display_name raise GssApiError.new(), "No context accepted yet. Call #{self.class.name}#accept_context(in_token) first" if @client.nil? output_name = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_display_name(min_stat, @client.get_pointer(0), output_name.pointer, nil) if maj_stat != GSSAPI::LibGSSAPI::GSS_S_COMPLETE raise GssApiError.new(maj_stat, min_stat), "gss_display_name did not return GSS_S_COMPLETE but #{ maj_stat }" end output_name.value end # Acquire security credentials. This does not log you in. It grabs the credentials from a cred cache or keytab. # @param [Hash] opts options to pass to the gss_acquire_cred function. # @option opts [String] :usage The credential usage type (:accept, :initiate, :both). It defaults to 'accept' since # this method is most usually called on the server only. # @return [true] It will return true if everything succeeds and the @scred variable will be set for future methods. If # an error ocurrs an exception will be raised. def acquire_credentials(princ = @int_svc_name, opts = {:usage => :accept}) min_stat = FFI::MemoryPointer.new :OM_uint32 scred = FFI::MemoryPointer.new :pointer case opts[:usage] when :accept usage = LibGSSAPI::GSS_C_ACCEPT when :initiate usage = LibGSSAPI::GSS_C_INITIATE when :both usage = LibGSSAPI::GSS_C_BOTH else raise GssApiError, "Bad option passed to #{self.class.name}#acquire_credentials" end maj_stat = LibGSSAPI.gss_acquire_cred(min_stat, princ, 0, LibGSSAPI::GSS_C_NO_OID_SET, usage, scred, nil, nil) raise GssApiError.new(maj_stat, min_stat), "gss_acquire_cred did not return GSS_S_COMPLETE" if maj_stat != 0 @scred = LibGSSAPI::GssCredIdT.new(scred.get_pointer(0)) true end # Wrap a message using gss_wrap. It can either encrypt the message (confidentiality) or simply sign it (integrity). # @param [String] msg The message to wrap # @param [Boolean] encrypt Whether or not to encrypt the message or just sign it. The default is to encrypt. # @return [String] The wrapped message. It will raise an exception on error def wrap_message(msg, encrypt = true) min_stat = FFI::MemoryPointer.new :OM_uint32 conf_req = (encrypt ? 1 : 0) qop_req = GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = msg conf_state = FFI::MemoryPointer.new :OM_uint32 out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new maj_stat = GSSAPI::LibGSSAPI.gss_wrap(min_stat, @context, conf_req, qop_req, in_buff.pointer, conf_state, out_buff.pointer) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_wrap message" if maj_stat != 0 out_buff.value end # Unwrap a message previously wrapped with gss_wrap. # @param [String] msg The message to unwrap # @param [Boolean] encrypted Whether or not this message was encrypted (true) or just signed (false) def unwrap_message(msg, encrypted = true) min_stat = FFI::MemoryPointer.new :OM_uint32 in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = msg out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new conf_state = FFI::MemoryPointer.new :int conf_state.write_int((encrypted ? 1 : 0)) q_op = FFI::MemoryPointer.new :OM_uint32 q_op.write_int(0) maj_stat = GSSAPI::LibGSSAPI.gss_unwrap(min_stat, @context, in_buff.pointer, out_buff.pointer, conf_state, q_op) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_unwrap message" if maj_stat != 0 out_buff.value end # Add a path to a custom keytab file # @param [String] keytab the path to the keytab def set_keytab(keytab) maj_stat = LibGSSAPI.krb5_gss_register_acceptor_identity(keytab) raise GssApiError.new(maj_stat, min_stat), "krb5_gss_register_acceptor_identity did not return GSS_S_COMPLETE" if maj_stat != 0 true end end # Simple end # GSSAPI gssapi-1.2.0/lib/gssapi/extensions.rb0000644000175000017500000000437712551171257017151 0ustar globusglobus=begin Copyright © 2014 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end module GSSAPI module LibGSSAPI # Some versions of GSSAPI might not have support for IOV yet. begin # OM_uint32 GSSAPI_LIB_FUNCTION gss_wrap_iov( OM_uint32 * minor_status, gss_ctx_id_t context_handle, # int conf_req_flag, gss_qop_t qop_req, int * conf_state, gss_iov_buffer_desc * iov, int iov_count ); attach_function :gss_wrap_iov, [:pointer, :pointer, :int, :OM_uint32, :pointer, :pointer, :int], :OM_uint32 # OM_uint32 GSSAPI_LIB_FUNCTION gss_unwrap_iov ( OM_uint32 * minor_status, gss_ctx_id_t context_handle, # int * conf_state, gss_qop_t * qop_state, gss_iov_buffer_desc * iov, int iov_count ) attach_function :gss_unwrap_iov, [:pointer, :pointer, :pointer, :pointer, :pointer, :int], :OM_uint32 # OM_uint32 GSSAPI_LIB_CALL gss_wrap_iov_length ( OM_uint32 * minor_status, gss_ctx_id_t context_handle, # int conf_req_flag, gss_qop_t qop_req, int * conf_state, gss_iov_buffer_desc * iov, int iov_count) attach_function :gss_wrap_iov_length, [:pointer, :pointer, :int, :OM_uint32, :pointer, :pointer, :int], :OM_uint32 rescue FFI::NotFoundError => ex warn "WARNING: Could not load IOV methods. Check your GSSAPI C library for an update" end begin # OM_uint32 gss_wrap_aead(OM_uint32 * minor_status, gss_ctx_id_t context_handle, int conf_req_flag, # gss_qop_t qop_req, gss_buffer_t input_assoc_buffer, # gss_buffer_t input_payload_buffer, int * conf_state, gss_buffer_t output_message_buffer); attach_function :gss_wrap_aead, [:pointer, :pointer, :int, :OM_uint32, :pointer, :pointer, :pointer, :pointer], :OM_uint32 # OM_uint32 gss_unwrap_aead(OM_uint32 * minor_status, gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, # gss_buffer_t input_assoc_buffer, gss_buffer_t output_payload_buffer, int * conf_state, gss_qop_t * qop_state); attach_function :gss_unwrap_aead, [:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer], :OM_uint32 rescue FFI::NotFoundError => ex warn "WARNING: Could not load AEAD methods. Check your GSSAPI C library for an update" end end end gssapi-1.2.0/lib/gssapi/lib_gssapi_loader.rb0000644000175000017500000000601412551171257020402 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end module GSSAPI module LibGSSAPI class GssOID < FFI::Struct layout :length, :OM_uint32, :elements, :pointer # pointer of :void def self.gss_c_no_oid self.new(GSSAPI::LibGSSAPI::GSS_C_NO_OID) end end def self.load_mit host_os = RbConfig::CONFIG['host_os'] case host_os when /linux/ gssapi_lib = 'libgssapi_krb5.so.2' ffi_lib gssapi_lib, FFI::Library::LIBC when /darwin/ gssapi_lib = '/usr/lib/libgssapi_krb5.dylib' ffi_lib gssapi_lib, FFI::Library::LIBC when /mswin|mingw32|windows/ # Pull the gssapi32 path from the environment if it exist, otherwise use the default in Program Files gssapi32_path = ENV['gssapi32'] ? ENV['gssapi32'] : 'C:\Program Files (x86)\MIT\Kerberos\bin\gssapi32.dll' ffi_lib gssapi32_path, FFI::Library::LIBC # Required the MIT Kerberos libraries to be installed ffi_convention :stdcall else raise LoadError, "This host OS (#{host_os}) is not supported by ruby gssapi and the MIT libraries." end # -------------------- MIT Specifics -------------------- attach_variable :__GSS_C_NT_HOSTBASED_SERVICE, :GSS_C_NT_HOSTBASED_SERVICE, :pointer # type gss_OID attach_variable :__GSS_C_NT_EXPORT_NAME, :GSS_C_NT_EXPORT_NAME, :pointer # type gss_OID LibGSSAPI.const_set("GSS_C_NT_HOSTBASED_SERVICE", __GSS_C_NT_HOSTBASED_SERVICE) LibGSSAPI.const_set("GSS_C_NT_EXPORT_NAME", __GSS_C_NT_EXPORT_NAME) end def self.load_heimdal host_os = RbConfig::CONFIG['host_os'] case host_os when /linux/ gssapi_lib = 'libgssapi.so.3' when /darwin/ # use Heimdal Kerberos since Mac MIT Kerberos is OLD. Do a "require 'gssapi/heimdal'" first gssapi_lib = '/usr/heimdal/lib/libgssapi.dylib' else raise LoadError, "This host OS (#{host_os}) is not supported by ruby gssapi and the Heimdal libraries." end ffi_lib gssapi_lib, FFI::Library::LIBC # ------------------ Heimdal Specifics ------------------ attach_variable :__gss_c_nt_hostbased_service_oid_desc, GssOID attach_variable :__gss_c_nt_export_name_oid_desc, GssOID LibGSSAPI.const_set("GSS_C_NT_HOSTBASED_SERVICE", FFI::Pointer.new(__gss_c_nt_hostbased_service_oid_desc.to_ptr)) LibGSSAPI.const_set("GSS_C_NT_EXPORT_NAME", FFI::Pointer.new(__gss_c_nt_export_name_oid_desc.to_ptr)) end # Heimdal supported the *_iov functions before MIT did so in some OS distributions if # you need IOV support and MIT does not provide it try the Heimdal libs and then # before doing a "require 'gssapi'" do a "require 'gssapi/heimdal'" and that will attempt # to load the Heimdal libs case GSSAPI_LIB_TYPE when :mit load_mit when :heimdal load_heimdal else raise LoadError, "Unexpected Lib type: #{GSSAPI_LIB_TYPE}" end end end gssapi-1.2.0/lib/gssapi/exceptions.rb0000644000175000017500000000311612551171257017121 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end module GSSAPI class GssApiError < StandardError include LibGSSAPI def message; to_s + ": " + @s; end def initialize(maj_stat = nil, min_stat = nil) # If raised as class (raise GssApiError, "msg) the error message is given # as the first parameter. if maj_stat.class == String @s = maj_stat return super maj_stat end if(maj_stat.nil? && min_stat.nil?) @s = '(no error info)' else min = FFI::MemoryPointer.new :OM_uint32 message_context = FFI::MemoryPointer.new :OM_uint32 @s = '' oid = GssOID.gss_c_no_oid min_stat = min_stat.read_uint32 [[maj_stat, GSS_C_GSS_CODE], [min_stat, GSS_C_MECH_CODE]].each do |m, t| message_context.write_int 0 begin out_buff = ManagedGssBufferDesc.new maj = gss_display_status(min, m, t, oid, message_context, out_buff.pointer) if (maj != 0) @s += "failed to retrieve GSSAPI display for status #{m}" @s += " of major status #{maj_stat}, minor_status #{min_stat}\n" @s += "(with major status #{maj}, minor status #{min.read_uint32}\n" break end @s += out_buff.value.to_s + "\n" end while message_context.read_int != 0 end end # We need to call this so we can pass the message to the Error when we have no arguments super() end end end gssapi-1.2.0/COPYING0000644000175000017500000000204312551171257013410 0ustar globusglobusCopyright © 2010 Dan Wanek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gssapi-1.2.0/Rakefile0000644000175000017500000000031712551171257014024 0ustar globusglobusrequire "bundler/gem_tasks" desc "Open a Pry Console" task :console do require "pry" require "pathname" $: << (Pathname(__FILE__).dirname + "lib").to_s require "gssapi" ARGV.clear Pry.start end gssapi-1.2.0/examples/0000755000175000017500000000000012551171257014174 5ustar globusglobusgssapi-1.2.0/examples/gss_server.rb0000644000175000017500000000144212551171257016704 0ustar globusglobusrequire 'gssapi' require 'base64' require 'socket' host = 'example.org' service = 'host' keytab = "#{ENV['HOME']}/.gssapi/krb5.keytab" # this is optional, but probably required if not running as root tcpsrv = TCPServer.new(host, 8082) loop do Thread.start(tcpsrv.accept) do |s| print(s, "Accepted Connection\n") stok = s.gets.chomp print(s, "Received string#{stok}\n") srv = GSSAPI::Simple.new(host, service, keytab) srv.acquire_credentials otok = srv.accept_context(Base64.strict_decode64(stok.chomp)) s.write("#{Base64.strict_encode64(otok)}\n") begin emsg = s.gets.chomp msg = srv.unwrap_message(Base64.strict_decode64(emsg.chomp)) puts "Received: #{msg}" end while msg != 'exit' print(s, "Closing Socket\n") s.close end end gssapi-1.2.0/examples/gss_iov_client.rb0000644000175000017500000000204412551171257017530 0ustar globusglobus#!/usr/bin/env ruby $: << '../lib' $: << '.' #require 'gssapi/heimdal' require 'gssapi' require 'gss_iov_helpers' require 'base64' require 'socket' class GssIovClient include GssIOVHelpers def initialize @host = 'example.org' @service = 'host' @sock = TCPSocket.new(@host, 8082) @gss = GSSAPI::Simple.new(@host, @service) end def run handshake begin print "> " msg = STDIN.gets.chomp emsg = iov_encrypt(msg) @sock.write("#{emsg.last}\n") end while msg != 'exit' @sock.close end private def handshake tok = @gss.init_context stok = Base64.strict_encode64(tok) @sock.write("#{stok}\n") # send initial token stok = @sock.gets.chomp # get back continuation token ctx = @gss.init_context(Base64.strict_decode64(stok.chomp)) # complete security context puts "Connection #{(ctx ? 'succeeded' : 'failed')}" end # Encrypt message def msg_enc(msg) emsg = @gss.wrap_message(msg) Base64.strict_encode64(emsg) end end cli = GssIovClient.new cli.run gssapi-1.2.0/examples/gss_client.rb0000644000175000017500000000116112551171257016652 0ustar globusglobusrequire 'gssapi' require 'base64' require 'socket' host = 'example.org' service = 'host' sock = TCPSocket.new(host, 8082) cli = GSSAPI::Simple.new(host, service) tok = cli.init_context stok = Base64.strict_encode64(tok) sock.write("#{stok}\n") # send initial token stok = sock.gets.chomp # get back continuation token ctx = cli.init_context(Base64.strict_decode64(stok.chomp)) # complete security context puts "Connection #{(ctx ? 'succeeded' : 'failed')}" begin print "> " msg = STDIN.gets.chomp emsg = cli.wrap_message(msg) sock.write("#{Base64.strict_encode64(emsg)}\n") end while msg != 'exit' sock.close gssapi-1.2.0/examples/gss_iov_helpers.rb0000644000175000017500000000562712551171257017726 0ustar globusglobusmodule GssIOVHelpers def iov_encrypt(str) iov_cnt = 3 iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt) iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address)) iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE) iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1))) iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA) iov1[:buffer].value = str iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2))) iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_PADDING | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE) conf_state = FFI::MemoryPointer.new :uint32 min_stat = FFI::MemoryPointer.new :uint32 maj_stat = GSSAPI::LibGSSAPI.gss_wrap_iov(min_stat, @gss.context, 1, GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT, conf_state, iov, iov_cnt) token = [iov0[:buffer].length].pack('L') token += iov0[:buffer].value token += iov1[:buffer].value pad_len = iov2[:buffer].length token += iov2[:buffer].value if pad_len > 0 [pad_len, token] end # @return [String] the unencrypted response string def iov_decrypt(str) puts "Decrypting message:\n#{str}" iov_cnt = 3 iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt) iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address)) iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE) iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1))) iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA) iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2))) iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA) str.force_encoding('BINARY') #str.sub!(/^.*Content-Type: application\/octet-stream\r\n(.*)--Encrypted.*$/m, '\1') len = str.unpack("L").first puts "LEN: #{len}" iov_data = str.unpack("LA#{len}A*") iov0[:buffer].value = iov_data[1] iov1[:buffer].value = iov_data[2] min_stat = FFI::MemoryPointer.new :uint32 conf_state = FFI::MemoryPointer.new :uint32 conf_state.write_int(1) qop_state = FFI::MemoryPointer.new :uint32 qop_state.write_int(0) puts "Unwrapping IOV...." maj_stat = GSSAPI::LibGSSAPI.gss_unwrap_iov(min_stat, @gss.context, conf_state, qop_state, iov, iov_cnt) puts "Done Unwrapping IOV...." if(maj_stat == 0) puts "Success!!!" else puts "GSSAPI Failure. Status Codes(major: #{maj_stat}, minor: #{min_stat.read_int})" end puts "???HELLO???" iov1[:buffer].value end end gssapi-1.2.0/examples/gss_iov_server.rb0000644000175000017500000000262512551171257017565 0ustar globusglobus#!/usr/bin/env ruby $: << '../lib' $: << '.' #require 'gssapi/heimdal' require 'gssapi' require 'gss_iov_helpers' require 'base64' require 'socket' class GssIovServer include GssIOVHelpers def initialize @host = 'example.org' @service = "host" @keytab = "#{ENV['HOME']}/.gssapi/krb5.keytab" # this is optional, but probably required if not running as root @port = 8082 @tcpsrv = TCPServer.new(@host, @port) end def runner loop do puts "Listening on port #{@port}" Thread.start(@tcpsrv.accept) do |s| init_krb handshake(s) begin emsg = (s.gets.chomp) puts "---> Received: #{emsg}" msg = iov_decrypt(emsg) puts "===> Received: #{msg}" end while msg != 'exit' print(s, "Closing Socket\n") s.close puts "Closed...." end end end private def init_krb @gss = GSSAPI::Simple.new(@host, @service, @keytab) @gss.acquire_credentials puts "HELLO" end def handshake(sock) print(sock, "Accepted Connection\n") stok = sock.gets.chomp print(sock, "Received string#{stok}\n") otok = @gss.accept_context(Base64.strict_decode64(stok.chomp)) sock.write("#{Base64.strict_encode64(otok)}\n") end # Decrypt message def msg_dec(msg) @gss.unwrap_message(Base64.strict_decode64(msg.chomp)) end end gserv = GssIovServer.new gserv.runner gssapi-1.2.0/preamble0000644000175000017500000000022212551171257014064 0ustar globusglobus=begin Copyright © 2010 Dan Wanek Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php =end gssapi-1.2.0/VERSION0000644000175000017500000000000612551171257013422 0ustar globusglobus1.2.0 gssapi-1.2.0/README.md0000644000175000017500000000144612551171257013642 0ustar globusglobus# Ruby GSSAPI Library This is a wrapper around the system GSSAPI library (MIT only at this time). It exposes the low-level GSSAPI methods like gss_init_sec_context and gss_wrap and also provides an easier to use wrapper on top of this for common usage scenarios. I'm going to try and maintain most of the docs in the Github WIKI for this project so please check there for documentation and examples. https://github.com/zenchild/gssapi/wiki Also check out the examples directory for some stubbed out client/server examples. ## Note on IOV and AEAD functions If you require the IOV and AEAD functions you will have to `require "gssapi/extensions"` to gain access to them. #### License Copyright © 2010 Dan Wanek Ruby gssapi is licensed under the MIT license (see COPYING) gssapi-1.2.0/gssapi.gemspec0000644000175000017500000000212412551171257015210 0ustar globusglobus# -*- encoding: utf-8 -*- lib = File.expand_path('lib/', __FILE__) $:.unshift lib unless $:.include?(lib) require 'date' Gem::Specification.new do |gem| gem.name = "gssapi" gem.version = File.open('VERSION').readline.chomp gem.date = Date.today.to_s gem.platform = Gem::Platform::RUBY gem.rubyforge_project = nil gem.author = "Dan Wanek" gem.email = "dan.wanek@gmail.com" gem.homepage = "http://github.com/zenchild/gssapi" gem.license = "MIT" gem.summary = "A FFI wrapper around the system GSSAPI library." gem.description = <<-EOF A FFI wrapper around the system GSSAPI library. Please make sure and read the Yard docs or standard GSSAPI documentation if you have any questions. There is also a class called GSSAPI::Simple that wraps many of the common features used for GSSAPI. EOF gem.files = `git ls-files`.split(/\n/) gem.require_path = "lib" gem.rdoc_options = %w(-x test/ -x examples/) gem.extra_rdoc_files = %w(README.md COPYING Changelog.md) gem.required_ruby_version = '>= 1.8.7' gem.add_runtime_dependency 'ffi', '>= 1.0.1' end gssapi-1.2.0/test/0000755000175000017500000000000012551171257013335 5ustar globusglobusgssapi-1.2.0/test/spec/0000755000175000017500000000000012551171257014267 5ustar globusglobusgssapi-1.2.0/test/spec/test_buffer_spec.rb0000644000175000017500000000067312551171257020144 0ustar globusglobus$: << File.dirname(__FILE__) + '/../../lib/' require 'gssapi' describe GSSAPI::LibGSSAPI::UnManagedGssBufferDesc, 'Unmanaged Buffer Test' do it 'should create a new UnManagedGssBufferDesc and assign to it and test GC' do 0.upto 100 do |i| b = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new GC.start b.value = 'asdf' end # If we get here without any errors we should be golden true.should be_true end end gssapi-1.2.0/test/spec/gssapi_simple_spec.rb0000644000175000017500000000120212551171257020460 0ustar globusglobus$: << File.dirname(__FILE__) + '/../../lib/' require 'gssapi' require 'base64' require 'yaml' describe GSSAPI::Simple, 'Test the Simple GSSAPI interface' do before :all do @conf = YAML.load_file "#{File.dirname(__FILE__)}/conf_file.yaml" end it 'should get the initial context for a client' do gsscli = GSSAPI::Simple.new(@conf[:c_host], @conf[:c_service]) token = gsscli.init_context token.should_not be_empty end it 'should acquire credentials for a server service' do gsscli = GSSAPI::Simple.new(@conf[:s_host], @conf[:s_service], @conf[:keytab]) gsscli.acquire_credentials.should be_true end end gssapi-1.2.0/Changelog.md0000644000175000017500000000077212551171257014575 0ustar globusglobus## Version 1.1.1 * Allow GssApiError to be initialized with string. * Add display_name wrapper for gss_display_name to GSSAPI::Simple * gss_iov examples * Ruby 1.8.x support * Change loader for MIT and Heimdal to be a bit cleaner. Fix syntax in simple.rb * Do a gss_acquire_cred for every connection to the server. * updating path to gssapi32.dll ## Version 1.1.2 * add gss_get_mic ## Version 1.2.0 * Move IOV and AEAD to gssapi/extensions.rb so it can be loaded separately when needed gssapi-1.2.0/metadata.yml0000644000175000017500000000403112551171260014651 0ustar globusglobus--- !ruby/object:Gem::Specification name: gssapi version: !ruby/object:Gem::Version version: 1.2.0 platform: ruby authors: - Dan Wanek autorequire: bindir: bin cert_chain: [] date: 2014-09-20 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: ffi requirement: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 1.0.1 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 1.0.1 description: |2 A FFI wrapper around the system GSSAPI library. Please make sure and read the Yard docs or standard GSSAPI documentation if you have any questions. There is also a class called GSSAPI::Simple that wraps many of the common features used for GSSAPI. email: dan.wanek@gmail.com executables: [] extensions: [] extra_rdoc_files: - README.md - COPYING - Changelog.md files: - COPYING - Changelog.md - Gemfile - README.md - Rakefile - VERSION - examples/gss_client.rb - examples/gss_iov_client.rb - examples/gss_iov_helpers.rb - examples/gss_iov_server.rb - examples/gss_server.rb - gssapi.gemspec - lib/gssapi.rb - lib/gssapi/exceptions.rb - lib/gssapi/extensions.rb - lib/gssapi/heimdal.rb - lib/gssapi/lib_gssapi.rb - lib/gssapi/lib_gssapi_loader.rb - lib/gssapi/simple.rb - preamble - test/spec/gssapi_simple_spec.rb - test/spec/test_buffer_spec.rb homepage: http://github.com/zenchild/gssapi licenses: - MIT metadata: {} post_install_message: rdoc_options: - -x - test/ - -x - examples/ require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 1.8.7 required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: A FFI wrapper around the system GSSAPI library. test_files: [] gssapi-1.2.0/Gemfile0000644000175000017500000000004612551171257013651 0ustar globusglobussource "https://rubygems.org" gemspec