/*
 * Author: Bryan Berns <berns@uwalumni.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

 /*
  * This file provides the GSSAPI interface to support Kerberos SSPI within
  * OpenSSH.  This is only a partial definition of the full GSSAPI specification
  * since OpenSSH only requires a subset of the overall functionality.
  *
  * The definitions are derived from information provided in RFC2744.  In
  * addition, RFC2743 provides additional information on the GSSAPI
  * specification and intended operation.
  */

#include <windows.h>
#include <stdint.h>

#define SECURITY_WIN32
#include <security.h>

/*
 * Common Structures & Type Definitions
 */

typedef uint32_t OM_uint32;

typedef char *gss_name_struct, *gss_name_t;

typedef struct cred_st *gss_cred_id_t;
typedef CtxtHandle *gss_ctx_id_t;

typedef OM_uint32 gss_qop_t;
typedef OM_uint32 gss_cred_usage_t;

typedef struct gss_buffer_desc_struct
{
	size_t length;
	void *value;
}
gss_buffer_desc, *gss_buffer_t;

typedef struct gss_OID_desc_struct
{
	OM_uint32 length;
	void *elements;
}
gss_OID_desc, *gss_OID;

typedef struct gss_OID_set_desc_struct
{
	size_t  count;
	gss_OID elements;
}
gss_OID_set_desc, *gss_OID_set;

typedef struct gss_channel_bindings_struct 
{
	OM_uint32 initiator_addrtype;
	gss_buffer_desc initiator_address;
	OM_uint32 acceptor_addrtype;
	gss_buffer_desc acceptor_address;
	gss_buffer_desc application_data;
} 
gss_channel_bindings_desc, *gss_channel_bindings_t;

/*
 * Input & Return Flags 
 */

/* Credential Usage Indication Options */
#define GSS_C_BOTH      0
#define GSS_C_INITIATE  1
#define GSS_C_ACCEPT    2

/* Context Flag Options */
#define GSS_C_DELEG_FLAG        1
#define GSS_C_MUTUAL_FLAG       2
#define GSS_C_REPLAY_FLAG       4
#define GSS_C_SEQUENCE_FLAG     8
#define GSS_C_CONF_FLAG         16
#define GSS_C_INTEG_FLAG        32
#define GSS_C_ANON_FLAG         64
#define GSS_C_PROT_READY_FLAG   128
#define GSS_C_TRANS_FLAG        256
#define GSS_C_DELEG_POLICY_FLAG 32768

/* Display Status Code Types */
#define GSS_C_GSS_CODE  1
#define GSS_C_MECH_CODE 2

/* Convenience Null Castless Comparison Options */
#define GSS_C_NO_NAME             ((gss_name_t) 0)
#define GSS_C_NO_BUFFER           ((gss_buffer_t) 0)
#define GSS_C_NO_OID              ((gss_OID) 0)
#define GSS_C_NO_OID_SET          ((gss_OID_set) 0)
#define GSS_C_NO_CONTEXT          ((gss_ctx_id_t) 0)
#define GSS_C_NO_CREDENTIAL       ((gss_cred_id_t) 0)
#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)

/* Convenience Initializer For Empty Buffer */
#define GSS_C_EMPTY_BUFFER {0, NULL}

/* Default Quality of Protection Code */
#define GSS_C_QOP_DEFAULT 0

 /* Infinite Context / Credential Value */
#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)

/*
 * Status & Return Code Processing
 */

#define GSS_S_COMPLETE 0

#define GSS_C_CALLING_ERROR_OFFSET 24
#define GSS_C_ROUTINE_ERROR_OFFSET 16
#define GSS_C_SUPPLEMENTARY_OFFSET 0
#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)

#define GSS_CALLING_ERROR(x)      ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
#define GSS_ROUTINE_ERROR(x)      ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
#define GSS_ERROR(x)              ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))

#define GSS_S_BAD_MECH             (((OM_uint32)  1ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_NAME             (((OM_uint32)  2ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_NAMETYPE         (((OM_uint32)  3ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_BINDINGS         (((OM_uint32)  4ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_STATUS           (((OM_uint32)  5ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_SIG              (((OM_uint32)  6ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_NO_CRED              (((OM_uint32)  7ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_NO_CONTEXT           (((OM_uint32)  8ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DEFECTIVE_TOKEN      (((OM_uint32)  9ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DEFECTIVE_CREDENTIAL (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_CREDENTIALS_EXPIRED  (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_CONTEXT_EXPIRED      (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_FAILURE              (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_QOP              (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAUTHORIZED         (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAVAILABLE          (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DUPLICATE_ELEMENT    (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_NAME_NOT_MN          (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)

#define GSS_S_CONTINUE_NEEDED      (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
#define GSS_S_DUPLICATE_TOKEN      (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
#define GSS_S_OLD_TOKEN            (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
#define GSS_S_UNSEQ_TOKEN          (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
#define GSS_S_GAP_TOKEN            (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))

/* 
 * Function Prototypes 
 */

OM_uint32 
gss_accept_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle,
	gss_cred_id_t acceptor_cred_handle, gss_buffer_t input_token_buffer, 
	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);

OM_uint32
gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name, 
	OM_uint32 time_req, 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);

OM_uint32 
gss_add_oid_set_member(OM_uint32 * minor_status, gss_OID member_oid, 
	gss_OID_set * oid_set);

OM_uint32
gss_create_empty_oid_set(OM_uint32 * minor_status, gss_OID_set * oid_set);

OM_uint32 
gss_init_sec_context(
	OM_uint32 * minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t * context_handle,
	gss_name_t target_name, gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings,
	gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags,
	OM_uint32 * time_rec);

OM_uint32 
gss_delete_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle,
	gss_buffer_t output_token);

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);

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);

OM_uint32 
gss_export_name(OM_uint32 * minor_status, const gss_name_t input_name, 
	gss_buffer_t exported_name);

OM_uint32 
gss_get_mic(OM_uint32 * minor_status, gss_ctx_id_t context_handle, 
	gss_qop_t qop_req, gss_buffer_t message_buffer, 
	gss_buffer_t message_token);

OM_uint32 
gss_import_name(OM_uint32 * minor_status, gss_buffer_t input_name_buffer,
	gss_OID input_name_type, gss_name_t * output_name);

OM_uint32 
gss_indicate_mechs(OM_uint32 * minor_status, gss_OID_set * mech_set);

OM_uint32 
gss_release_buffer(OM_uint32 * minor_status, gss_buffer_t buffer);

OM_uint32 
gss_release_cred(OM_uint32 * minor_status, gss_cred_id_t * cred_handle);

OM_uint32 
gss_release_name(OM_uint32 * minor_status, gss_name_t * input_name);

OM_uint32 
gss_release_oid_set(OM_uint32 * minor_status, gss_OID_set * set);

OM_uint32 
gss_test_oid_set_member(OM_uint32 * minor_status, gss_OID member, 
	gss_OID_set set, int * present);

OM_uint32 
gss_verify_mic(OM_uint32 * minor_status, gss_ctx_id_t context_handle, 
	gss_buffer_t message_buffer, gss_buffer_t message_token, 
	gss_qop_t * qop_state);

extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;