\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7<F<2PFAFZUP_xxnnx\F5\AF\B9\91\C8\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\DB\00CUZZxix‚\EB\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\C0\00\00b\00d\00\FF\C4\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\C4\00\00\00\00\00\00\00\00\00\00\001A!Q\FF\C4\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\C4\00\00\00\00\00\00\00\00\00\00!1AQ\FF\DA\00\00\00?\00\F6\00\00\00\00\00\00\00\00\00\00\A0\00\00\C5\CF\F8\E7Ó\FCjD~\B9^\AD\%\B3]\D8cs-\BBs,-\A0\00"\80\00%\B83rÏ^K~F\A4ea\00E\00\C6\EE=u\B1\9B\D1\00@\00r\BE8\F9:\FE5#.M\00\E7\CB\C9q\CBq\D6\F2\BE\B7\C7>\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7	\8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh
\00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€
\00$\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95
59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>C///</title>
</head>
=begin
Copyright Â© 2010 Dan Wanek <dan.wanek@gmail.com>

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
    #              [Credentials] :credentials set to open the context in behalf of someone (delegated_credentials)
    # @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,
                                                opts[:credentials],
                                                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

    def verify_mic(token,mic)
      min_stat = FFI::MemoryPointer.new :OM_uint32
      in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new
      in_buff.value = token
      mic_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new
      mic_buff.value = mic
      maj_stat = GSSAPI::LibGSSAPI.gss_verify_mic(min_stat, @context, in_buff.pointer, mic_buff.pointer, 0)
      raise GssApiError.new(maj_stat, min_stat), "Failed to gss_verify_mic" if maj_stat != 0
      return (maj_stat == 0)
    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 ?