#include "idl_types.h"

/*
  the base dcerpc packet definitions - not traditionally coded as IDL,
  but given that pidl can handle it nicely it simplifies things a lot
  to do it this way

  see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for packet
  layouts
*/
[] 
interface dcerpc
{
	typedef [public] struct {
		GUID uuid;
		uint32 if_version;
	} dcerpc_syntax_id;

	typedef struct {
		uint16 context_id;
		uint8 num_transfer_syntaxes;
		dcerpc_syntax_id abstract_syntax;
		dcerpc_syntax_id transfer_syntaxes[num_transfer_syntaxes];
	} dcerpc_ctx_list;

	typedef struct {
		uint16 max_xmit_frag;
		uint16 max_recv_frag;
		uint32 assoc_group_id;
		uint8  num_contexts;
		dcerpc_ctx_list ctx_list[num_contexts];
		[flag(NDR_ALIGN8)]    DATA_BLOB _pad;
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_bind;


	const uint8 DCERPC_REQUEST_LENGTH = 24;
	const uint8 DCERPC_MAX_SIGN_SIZE  = 32;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint16 opnum;
		[flag(NDR_ALIGN8)]    DATA_BLOB _pad;
		[flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
	} dcerpc_request;

	const int DCERPC_BIND_PROVIDER_REJECT = 2;
	const int DCERPC_BIND_REASON_ASYNTAX  = 1;

	typedef struct {
		uint16 result;
		uint16 reason;
		dcerpc_syntax_id syntax;
	} dcerpc_ack_ctx;

	typedef struct {
		uint16 max_xmit_frag;
		uint16 max_recv_frag;
		uint32 assoc_group_id;
		ascstr3 secondary_address;
		[flag(NDR_ALIGN4)]    DATA_BLOB _pad1;
		uint8 num_results;
		dcerpc_ack_ctx ctx_list[num_results];
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_bind_ack;

	typedef struct {
		uint16 reject_reason;
		uint32 num_versions;
		uint32 versions[num_versions];
	} dcerpc_bind_nak;

	const uint8 DCERPC_RESPONSE_LENGTH = 24;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint8 cancel_count;
		[flag(NDR_ALIGN8)]    DATA_BLOB _pad;
		[flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
	} dcerpc_response;


	const int DCERPC_FAULT_OP_RNG_ERROR       = 0x1c010002;
	const int DCERPC_FAULT_UNK_IF             = 0x1c010003;
	const int DCERPC_FAULT_NDR                = 0x000006f7;
	const int DCERPC_FAULT_INVALID_TAG        = 0x1c000006;
	const int DCERPC_FAULT_CONTEXT_MISMATCH   = 0x1c00001a;
	const int DCERPC_FAULT_OTHER              = 0x00000001;

	/* we return this fault when we haven't yet run the test
	   to see what fault w2k3 returns in this case */
	const int DCERPC_FAULT_TODO         = 0x00000042;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint8 cancel_count;
		uint32 status;
	} dcerpc_fault;


	const uint8 DCERPC_AUTH_TYPE_NONE     = 0;
	const uint8 DCERPC_AUTH_TYPE_KRB5     = 1;
	const uint8 DCERPC_AUTH_TYPE_SPNEGO   = 9;
	const uint8 DCERPC_AUTH_TYPE_NTLMSSP  = 10;
	const uint8 DCERPC_AUTH_TYPE_SCHANNEL = 68;
	
	const uint8 DCERPC_AUTH_LEVEL_NONE      = 1;
	const uint8 DCERPC_AUTH_LEVEL_CONNECT   = 2;
	const uint8 DCERPC_AUTH_LEVEL_CALL      = 3;
	const uint8 DCERPC_AUTH_LEVEL_PACKET    = 4;
	const uint8 DCERPC_AUTH_LEVEL_INTEGRITY = 5;
	const uint8 DCERPC_AUTH_LEVEL_PRIVACY   = 6;

	typedef [public] struct {
		uint8  auth_type; 
		uint8  auth_level;
		uint8  auth_pad_length;
		uint8  auth_reserved;
		uint32 auth_context_id;
		[flag(NDR_REMAINING)] DATA_BLOB credentials;
	} dcerpc_auth;

	typedef [public] struct {
		uint32 _pad;
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_auth3;

	typedef enum {
		DCERPC_PKT_REQUEST     =  0,
		DCERPC_PKT_PING        =  1,
		DCERPC_PKT_RESPONSE    =  2,
		DCERPC_PKT_FAULT       =  3,
		DCERPC_PKT_WORKING     =  4,
		DCERPC_PKT_NOCALL      =  5,
		DCERPC_PKT_REJECT      =  6,
		DCERPC_PKT_ACK         =  7,
		DCERPC_PKT_CL_CANCEL   =  8,
		DCERPC_PKT_FACK        =  9,
		DCERPC_PKT_CANCEL_ACK  = 10,
		DCERPC_PKT_BIND        = 11,
		DCERPC_PKT_BIND_ACK    = 12,
		DCERPC_PKT_BIND_NAK    = 13,
		DCERPC_PKT_ALTER       = 14,
		DCERPC_PKT_ALTER_ACK   = 15,
		DCERPC_PKT_AUTH3       = 16,
		DCERPC_PKT_SHUTDOWN    = 17,
		DCERPC_PKT_CO_CANCEL   = 18,
		DCERPC_PKT_ORPHANED    = 19
	} dcerpc_pkt_type;

	typedef [nodiscriminant] union {
		[case(DCERPC_PKT_REQUEST)]   dcerpc_request  request;
		[case(DCERPC_PKT_RESPONSE)]  dcerpc_response response;
		[case(DCERPC_PKT_BIND)]      dcerpc_bind     bind;
		[case(DCERPC_PKT_BIND_ACK)]  dcerpc_bind_ack bind_ack;
		[case(DCERPC_PKT_ALTER)]     dcerpc_bind     alter;
		[case(DCERPC_PKT_ALTER_ACK)] dcerpc_bind_ack alter_ack;
		[case(DCERPC_PKT_FAULT)]     dcerpc_fault    fault;
		[case(DCERPC_PKT_AUTH3)]     dcerpc_auth3    auth;
		[case(DCERPC_PKT_BIND_NAK)]  dcerpc_bind_nak bind_nak;
	} dcerpc_payload;


	/* pfc_flags values */
	const uint8 DCERPC_PFC_FLAG_FIRST  = 0x01;
	const uint8 DCERPC_PFC_FLAG_LAST   = 0x02;
	const uint8 DCERPC_PFC_FLAG_NOCALL = 0x20;

	/* these offsets are needed by the signing code */
	const uint8 DCERPC_DREP_OFFSET     =  4;
	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;

	/* little-endian flag */
	const uint8 DCERPC_DREP_LE  = 0x10;

	typedef [public] struct {
		uint8 rpc_vers;		/* RPC version */
		uint8 rpc_vers_minor;	/* Minor version */
		uint8 ptype;		/* Packet type */
		uint8 pfc_flags;	/* Fragmentation flags */
		uint8 drep[4];		/* NDR data representation */
		uint16 frag_length;	/* Total length of fragment */
		uint16 auth_length;	/* authenticator length */
		uint32 call_id;		/* Call identifier */
		
		[switch_is(ptype)] dcerpc_payload u;
	} dcerpc_packet;
}