# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description:
#   Partial C706.pdf + [MS-RPCE] implementation
#
#   Best way to learn how to use these calls is to grab the protocol standard
#   so you understand what the call does, and then read the test case located
#   at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC
#
# ToDo: 
# [ ] Take out all the security provider stuff out of here (e.g. RPC_C_AUTHN_WINNT)
#	 and put it elsewhere. This will make the coder cleaner and easier to add 
#	 more SSP (e.g. NETLOGON)
# 

import asyncio
import logging
import socket
import sys
from binascii import unhexlify

from aiosmb.crypto.symmetric import RC4

from aiosmb import logger as LOG


from aiosmb.dcerpc.v5.structure import Structure,pack,unpack
from aiosmb.dcerpc.v5 import uuid
from aiosmb.dcerpc.v5.uuid import uuidtup_to_bin, generate, stringver_to_bin, bin_to_uuidtup
from aiosmb.dcerpc.v5.dtypes import UCHAR, ULONG, USHORT
from aiosmb.dcerpc.v5.ndr import NDRSTRUCT
from aiosmb.dcerpc.v5 import hresult_errors
from minikerberos.gssapi import *


# MS/RPC Constants
MSRPC_REQUEST   = 0x00
MSRPC_PING	  = 0x01
MSRPC_RESPONSE  = 0x02
MSRPC_FAULT	 = 0x03
MSRPC_WORKING   = 0x04
MSRPC_NOCALL	= 0x05
MSRPC_REJECT	= 0x06
MSRPC_ACK	   = 0x07
MSRPC_CL_CANCEL = 0x08
MSRPC_FACK	  = 0x09
MSRPC_CANCELACK = 0x0A
MSRPC_BIND	  = 0x0B
MSRPC_BINDACK   = 0x0C
MSRPC_BINDNAK   = 0x0D
MSRPC_ALTERCTX  = 0x0E
MSRPC_ALTERCTX_R= 0x0F
MSRPC_AUTH3	 = 0x10
MSRPC_SHUTDOWN  = 0x11
MSRPC_CO_CANCEL = 0x12
MSRPC_ORPHANED  = 0x13

# MS/RPC Packet Flags
PFC_FIRST_FRAG	 = 0x01
PFC_LAST_FRAG	  = 0x02

# For PDU types bind, bind_ack, alter_context, and
# alter_context_resp, this flag MUST be interpreted as PFC_SUPPORT_HEADER_SIGN
MSRPC_SUPPORT_SIGN  = 0x04

#For the
#remaining PDU types, this flag MUST be interpreted as PFC_PENDING_CANCEL.
MSRPC_PENDING_CANCEL= 0x04

PFC_RESERVED_1	  = 0x08
PFC_CONC_MPX		= 0x10
PFC_DID_NOT_EXECUTE = 0x20
PFC_MAYBE		   = 0x40
PFC_OBJECT_UUID	 = 0x80

# Auth Types - Security Providers
RPC_C_AUTHN_NONE		  = 0x00
RPC_C_AUTHN_GSS_NEGOTIATE = 0x09
RPC_C_AUTHN_WINNT		 = 0x0A
RPC_C_AUTHN_GSS_SCHANNEL  = 0x0E
RPC_C_AUTHN_GSS_KERBEROS  = 0x10
RPC_C_AUTHN_NETLOGON	  = 0x44
RPC_C_AUTHN_DEFAULT	   = 0xFF

# Auth Levels
RPC_C_AUTHN_LEVEL_NONE		  = 1
RPC_C_AUTHN_LEVEL_CONNECT	   = 2
RPC_C_AUTHN_LEVEL_CALL		  = 3
RPC_C_AUTHN_LEVEL_PKT		   = 4
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5
RPC_C_AUTHN_LEVEL_PKT_PRIVACY   = 6

#Reasons for rejection of a context element, included in bind_ack result reason
rpc_provider_reason = {
	0	   : 'reason_not_specified',
	1	   : 'abstract_syntax_not_supported',
	2	   : 'proposed_transfer_syntaxes_not_supported',
	3	   : 'local_limit_exceeded',
	4	   : 'protocol_version_not_specified',
	8	   : 'authentication_type_not_recognized',
	9	   : 'invalid_checksum'
}

MSRPC_CONT_RESULT_ACCEPT = 0
MSRPC_CONT_RESULT_USER_REJECT = 1
MSRPC_CONT_RESULT_PROV_REJECT = 2

#Results of a presentation context negotiation
rpc_cont_def_result = {
	0	   : 'acceptance',
	1	   : 'user_rejection',
	2	   : 'provider_rejection'
}

#status codes, references:
#https://docs.microsoft.com/windows/desktop/Rpc/rpc-return-values
#https://msdn.microsoft.com/library/default.asp?url=/library/en-us/randz/protocol/common_return_values.asp
#winerror.h
#https://www.opengroup.org/onlinepubs/9629399/apdxn.htm

rpc_status_codes = {
	0x00000005 : 'rpc_s_access_denied',
	0x00000008 : 'Authentication type not recognized',
	0x000006D8 : 'rpc_fault_cant_perform', 
	0x000006C6 : 'rpc_x_invalid_bound',				# the arrays bound are invalid
	0x000006E4 : 'rpc_s_cannot_support: The requested operation is not supported.',			   # some operation is not supported
	0x000006F7 : 'rpc_x_bad_stub_data',				# the stub data is invalid, doesn't match with the IDL definition
	0x1C010001 : 'nca_s_comm_failure',				 # unable to get response from server:
	0x1C010002 : 'nca_s_op_rng_error',				 # bad operation number in call
	0x1C010003 : 'nca_s_unk_if',					   # unknown interface
	0x1C010006 : 'nca_s_wrong_boot_time',			  # client passed server wrong server boot time
	0x1C010009 : 'nca_s_you_crashed',				  # a restarted server called back a client
	0x1C01000B : 'nca_s_proto_error',				  # someone messed up the protocol
	0x1C010013 : 'nca_s_out_args_too_big ',			# output args too big
	0x1C010014 : 'nca_s_server_too_busy',			  # server is too busy to handle call
	0x1C010015 : 'nca_s_fault_string_too_long',		# string argument longer than declared max len
	0x1C010017 : 'nca_s_unsupported_type ',			# no implementation of generic operation for object
	0x1C000001 : 'nca_s_fault_int_div_by_zero',
	0x1C000002 : 'nca_s_fault_addr_error ',
	0x1C000003 : 'nca_s_fault_fp_div_zero',
	0x1C000004 : 'nca_s_fault_fp_underflow',
	0x1C000005 : 'nca_s_fault_fp_overflow',
	0x1C000006 : 'nca_s_fault_invalid_tag',
	0x1C000007 : 'nca_s_fault_invalid_bound ',
	0x1C000008 : 'nca_s_rpc_version_mismatch',
	0x1C000009 : 'nca_s_unspec_reject ',
	0x1C00000A : 'nca_s_bad_actid',
	0x1C00000B : 'nca_s_who_are_you_failed',
	0x1C00000C : 'nca_s_manager_not_entered ',
	0x1C00000D : 'nca_s_fault_cancel',
	0x1C00000E : 'nca_s_fault_ill_inst',
	0x1C00000F : 'nca_s_fault_fp_error',
	0x1C000010 : 'nca_s_fault_int_overflow',
	0x1C000012 : 'nca_s_fault_unspec',
	0x1C000013 : 'nca_s_fault_remote_comm_failure ',
	0x1C000014 : 'nca_s_fault_pipe_empty ',
	0x1C000015 : 'nca_s_fault_pipe_closed',
	0x1C000016 : 'nca_s_fault_pipe_order ',
	0x1C000017 : 'nca_s_fault_pipe_discipline',
	0x1C000018 : 'nca_s_fault_pipe_comm_error',
	0x1C000019 : 'nca_s_fault_pipe_memory',
	0x1C00001A : 'nca_s_fault_context_mismatch ',
	0x1C00001B : 'nca_s_fault_remote_no_memory ',
	0x1C00001C : 'nca_s_invalid_pres_context_id',
	0x1C00001D : 'nca_s_unsupported_authn_level',
	0x1C00001F : 'nca_s_invalid_checksum ',
	0x1C000020 : 'nca_s_invalid_crc',
	0x1C000021 : 'nca_s_fault_user_defined',
	0x1C000022 : 'nca_s_fault_tx_open_failed',
	0x1C000023 : 'nca_s_fault_codeset_conv_error',
	0x1C000024 : 'nca_s_fault_object_not_found ',
	0x1C000025 : 'nca_s_fault_no_client_stub',
	0x16c9a000 : "rpc_s_mod",
	0x16c9a001 : "rpc_s_op_rng_error",
	0x16c9a002 : "rpc_s_cant_create_socket",
	0x16c9a003 : "rpc_s_cant_bind_socket",
	0x16c9a004 : "rpc_s_not_in_call",
	0x16c9a005 : "rpc_s_no_port",
	0x16c9a006 : "rpc_s_wrong_boot_time",
	0x16c9a007 : "rpc_s_too_many_sockets",
	0x16c9a008 : "rpc_s_illegal_register",
	0x16c9a009 : "rpc_s_cant_recv",
	0x16c9a00a : "rpc_s_bad_pkt",
	0x16c9a00b : "rpc_s_unbound_handle",
	0x16c9a00c : "rpc_s_addr_in_use",
	0x16c9a00d : "rpc_s_in_args_too_big",
	0x16c9a00e : "rpc_s_string_too_long",
	0x16c9a00f : "rpc_s_too_many_objects",
	0x16c9a010 : "rpc_s_binding_has_no_auth",
	0x16c9a011 : "rpc_s_unknown_authn_service",
	0x16c9a012 : "rpc_s_no_memory",
	0x16c9a013 : "rpc_s_cant_nmalloc",
	0x16c9a014 : "rpc_s_call_faulted",
	0x16c9a015 : "rpc_s_call_failed",
	0x16c9a016 : "rpc_s_comm_failure",
	0x16c9a017 : "rpc_s_rpcd_comm_failure",
	0x16c9a018 : "rpc_s_illegal_family_rebind",
	0x16c9a019 : "rpc_s_invalid_handle",
	0x16c9a01a : "rpc_s_coding_error",
	0x16c9a01b : "rpc_s_object_not_found",
	0x16c9a01c : "rpc_s_cthread_not_found",
	0x16c9a01d : "rpc_s_invalid_binding",
	0x16c9a01e : "rpc_s_already_registered",
	0x16c9a01f : "rpc_s_endpoint_not_found",
	0x16c9a020 : "rpc_s_invalid_rpc_protseq",
	0x16c9a021 : "rpc_s_desc_not_registered",
	0x16c9a022 : "rpc_s_already_listening",
	0x16c9a023 : "rpc_s_no_protseqs",
	0x16c9a024 : "rpc_s_no_protseqs_registered",
	0x16c9a025 : "rpc_s_no_bindings",
	0x16c9a026 : "rpc_s_max_descs_exceeded",
	0x16c9a027 : "rpc_s_no_interfaces",
	0x16c9a028 : "rpc_s_invalid_timeout",
	0x16c9a029 : "rpc_s_cant_inq_socket",
	0x16c9a02a : "rpc_s_invalid_naf_id",
	0x16c9a02b : "rpc_s_inval_net_addr",
	0x16c9a02c : "rpc_s_unknown_if",
	0x16c9a02d : "rpc_s_unsupported_type",
	0x16c9a02e : "rpc_s_invalid_call_opt",
	0x16c9a02f : "rpc_s_no_fault",
	0x16c9a030 : "rpc_s_cancel_timeout",
	0x16c9a031 : "rpc_s_call_cancelled",
	0x16c9a032 : "rpc_s_invalid_call_handle",
	0x16c9a033 : "rpc_s_cannot_alloc_assoc",
	0x16c9a034 : "rpc_s_cannot_connect",
	0x16c9a035 : "rpc_s_connection_aborted",
	0x16c9a036 : "rpc_s_connection_closed",
	0x16c9a037 : "rpc_s_cannot_accept",
	0x16c9a038 : "rpc_s_assoc_grp_not_found",
	0x16c9a039 : "rpc_s_stub_interface_error",
	0x16c9a03a : "rpc_s_invalid_object",
	0x16c9a03b : "rpc_s_invalid_type",
	0x16c9a03c : "rpc_s_invalid_if_opnum",
	0x16c9a03d : "rpc_s_different_server_instance",
	0x16c9a03e : "rpc_s_protocol_error",
	0x16c9a03f : "rpc_s_cant_recvmsg",
	0x16c9a040 : "rpc_s_invalid_string_binding",
	0x16c9a041 : "rpc_s_connect_timed_out",
	0x16c9a042 : "rpc_s_connect_rejected",
	0x16c9a043 : "rpc_s_network_unreachable",
	0x16c9a044 : "rpc_s_connect_no_resources",
	0x16c9a045 : "rpc_s_rem_network_shutdown",
	0x16c9a046 : "rpc_s_too_many_rem_connects",
	0x16c9a047 : "rpc_s_no_rem_endpoint",
	0x16c9a048 : "rpc_s_rem_host_down",
	0x16c9a049 : "rpc_s_host_unreachable",
	0x16c9a04a : "rpc_s_access_control_info_inv",
	0x16c9a04b : "rpc_s_loc_connect_aborted",
	0x16c9a04c : "rpc_s_connect_closed_by_rem",
	0x16c9a04d : "rpc_s_rem_host_crashed",
	0x16c9a04e : "rpc_s_invalid_endpoint_format",
	0x16c9a04f : "rpc_s_unknown_status_code",
	0x16c9a050 : "rpc_s_unknown_mgr_type",
	0x16c9a051 : "rpc_s_assoc_creation_failed",
	0x16c9a052 : "rpc_s_assoc_grp_max_exceeded",
	0x16c9a053 : "rpc_s_assoc_grp_alloc_failed",
	0x16c9a054 : "rpc_s_sm_invalid_state",
	0x16c9a055 : "rpc_s_assoc_req_rejected",
	0x16c9a056 : "rpc_s_assoc_shutdown",
	0x16c9a057 : "rpc_s_tsyntaxes_unsupported",
	0x16c9a058 : "rpc_s_context_id_not_found",
	0x16c9a059 : "rpc_s_cant_listen_socket",
	0x16c9a05a : "rpc_s_no_addrs",
	0x16c9a05b : "rpc_s_cant_getpeername",
	0x16c9a05c : "rpc_s_cant_get_if_id",
	0x16c9a05d : "rpc_s_protseq_not_supported",
	0x16c9a05e : "rpc_s_call_orphaned",
	0x16c9a05f : "rpc_s_who_are_you_failed",
	0x16c9a060 : "rpc_s_unknown_reject",
	0x16c9a061 : "rpc_s_type_already_registered",
	0x16c9a062 : "rpc_s_stop_listening_disabled",
	0x16c9a063 : "rpc_s_invalid_arg",
	0x16c9a064 : "rpc_s_not_supported",
	0x16c9a065 : "rpc_s_wrong_kind_of_binding",
	0x16c9a066 : "rpc_s_authn_authz_mismatch",
	0x16c9a067 : "rpc_s_call_queued",
	0x16c9a068 : "rpc_s_cannot_set_nodelay",
	0x16c9a069 : "rpc_s_not_rpc_tower",
	0x16c9a06a : "rpc_s_invalid_rpc_protid",
	0x16c9a06b : "rpc_s_invalid_rpc_floor",
	0x16c9a06c : "rpc_s_call_timeout",
	0x16c9a06d : "rpc_s_mgmt_op_disallowed",
	0x16c9a06e : "rpc_s_manager_not_entered",
	0x16c9a06f : "rpc_s_calls_too_large_for_wk_ep",
	0x16c9a070 : "rpc_s_server_too_busy",
	0x16c9a071 : "rpc_s_prot_version_mismatch",
	0x16c9a072 : "rpc_s_rpc_prot_version_mismatch",
	0x16c9a073 : "rpc_s_ss_no_import_cursor",
	0x16c9a074 : "rpc_s_fault_addr_error",
	0x16c9a075 : "rpc_s_fault_context_mismatch",
	0x16c9a076 : "rpc_s_fault_fp_div_by_zero",
	0x16c9a077 : "rpc_s_fault_fp_error",
	0x16c9a078 : "rpc_s_fault_fp_overflow",
	0x16c9a079 : "rpc_s_fault_fp_underflow",
	0x16c9a07a : "rpc_s_fault_ill_inst",
	0x16c9a07b : "rpc_s_fault_int_div_by_zero",
	0x16c9a07c : "rpc_s_fault_int_overflow",
	0x16c9a07d : "rpc_s_fault_invalid_bound",
	0x16c9a07e : "rpc_s_fault_invalid_tag",
	0x16c9a07f : "rpc_s_fault_pipe_closed",
	0x16c9a080 : "rpc_s_fault_pipe_comm_error",
	0x16c9a081 : "rpc_s_fault_pipe_discipline",
	0x16c9a082 : "rpc_s_fault_pipe_empty",
	0x16c9a083 : "rpc_s_fault_pipe_memory",
	0x16c9a084 : "rpc_s_fault_pipe_order",
	0x16c9a085 : "rpc_s_fault_remote_comm_failure",
	0x16c9a086 : "rpc_s_fault_remote_no_memory",
	0x16c9a087 : "rpc_s_fault_unspec",
	0x16c9a088 : "uuid_s_bad_version",
	0x16c9a089 : "uuid_s_socket_failure",
	0x16c9a08a : "uuid_s_getconf_failure",
	0x16c9a08b : "uuid_s_no_address",
	0x16c9a08c : "uuid_s_overrun",
	0x16c9a08d : "uuid_s_internal_error",
	0x16c9a08e : "uuid_s_coding_error",
	0x16c9a08f : "uuid_s_invalid_string_uuid",
	0x16c9a090 : "uuid_s_no_memory",
	0x16c9a091 : "rpc_s_no_more_entries",
	0x16c9a092 : "rpc_s_unknown_ns_error",
	0x16c9a093 : "rpc_s_name_service_unavailable",
	0x16c9a094 : "rpc_s_incomplete_name",
	0x16c9a095 : "rpc_s_group_not_found",
	0x16c9a096 : "rpc_s_invalid_name_syntax",
	0x16c9a097 : "rpc_s_no_more_members",
	0x16c9a098 : "rpc_s_no_more_interfaces",
	0x16c9a099 : "rpc_s_invalid_name_service",
	0x16c9a09a : "rpc_s_no_name_mapping",
	0x16c9a09b : "rpc_s_profile_not_found",
	0x16c9a09c : "rpc_s_not_found",
	0x16c9a09d : "rpc_s_no_updates",
	0x16c9a09e : "rpc_s_update_failed",
	0x16c9a09f : "rpc_s_no_match_exported",
	0x16c9a0a0 : "rpc_s_entry_not_found",
	0x16c9a0a1 : "rpc_s_invalid_inquiry_context",
	0x16c9a0a2 : "rpc_s_interface_not_found",
	0x16c9a0a3 : "rpc_s_group_member_not_found",
	0x16c9a0a4 : "rpc_s_entry_already_exists",
	0x16c9a0a5 : "rpc_s_nsinit_failure",
	0x16c9a0a6 : "rpc_s_unsupported_name_syntax",
	0x16c9a0a7 : "rpc_s_no_more_elements",
	0x16c9a0a8 : "rpc_s_no_ns_permission",
	0x16c9a0a9 : "rpc_s_invalid_inquiry_type",
	0x16c9a0aa : "rpc_s_profile_element_not_found",
	0x16c9a0ab : "rpc_s_profile_element_replaced",
	0x16c9a0ac : "rpc_s_import_already_done",
	0x16c9a0ad : "rpc_s_database_busy",
	0x16c9a0ae : "rpc_s_invalid_import_context",
	0x16c9a0af : "rpc_s_uuid_set_not_found",
	0x16c9a0b0 : "rpc_s_uuid_member_not_found",
	0x16c9a0b1 : "rpc_s_no_interfaces_exported",
	0x16c9a0b2 : "rpc_s_tower_set_not_found",
	0x16c9a0b3 : "rpc_s_tower_member_not_found",
	0x16c9a0b4 : "rpc_s_obj_uuid_not_found",
	0x16c9a0b5 : "rpc_s_no_more_bindings",
	0x16c9a0b6 : "rpc_s_invalid_priority",
	0x16c9a0b7 : "rpc_s_not_rpc_entry",
	0x16c9a0b8 : "rpc_s_invalid_lookup_context",
	0x16c9a0b9 : "rpc_s_binding_vector_full",
	0x16c9a0ba : "rpc_s_cycle_detected",
	0x16c9a0bb : "rpc_s_nothing_to_export",
	0x16c9a0bc : "rpc_s_nothing_to_unexport",
	0x16c9a0bd : "rpc_s_invalid_vers_option",
	0x16c9a0be : "rpc_s_no_rpc_data",
	0x16c9a0bf : "rpc_s_mbr_picked",
	0x16c9a0c0 : "rpc_s_not_all_objs_unexported",
	0x16c9a0c1 : "rpc_s_no_entry_name",
	0x16c9a0c2 : "rpc_s_priority_group_done",
	0x16c9a0c3 : "rpc_s_partial_results",
	0x16c9a0c4 : "rpc_s_no_env_setup",
	0x16c9a0c5 : "twr_s_unknown_sa",
	0x16c9a0c6 : "twr_s_unknown_tower",
	0x16c9a0c7 : "twr_s_not_implemented",
	0x16c9a0c8 : "rpc_s_max_calls_too_small",
	0x16c9a0c9 : "rpc_s_cthread_create_failed",
	0x16c9a0ca : "rpc_s_cthread_pool_exists",
	0x16c9a0cb : "rpc_s_cthread_no_such_pool",
	0x16c9a0cc : "rpc_s_cthread_invoke_disabled",
	0x16c9a0cd : "ept_s_cant_perform_op",
	0x16c9a0ce : "ept_s_no_memory",
	0x16c9a0cf : "ept_s_database_invalid",
	0x16c9a0d0 : "ept_s_cant_create",
	0x16c9a0d1 : "ept_s_cant_access",
	0x16c9a0d2 : "ept_s_database_already_open",
	0x16c9a0d3 : "ept_s_invalid_entry",
	0x16c9a0d4 : "ept_s_update_failed",
	0x16c9a0d5 : "ept_s_invalid_context",
	0x16c9a0d6 : "ept_s_not_registered",
	0x16c9a0d7 : "ept_s_server_unavailable",
	0x16c9a0d8 : "rpc_s_underspecified_name",
	0x16c9a0d9 : "rpc_s_invalid_ns_handle",
	0x16c9a0da : "rpc_s_unknown_error",
	0x16c9a0db : "rpc_s_ss_char_trans_open_fail",
	0x16c9a0dc : "rpc_s_ss_char_trans_short_file",
	0x16c9a0dd : "rpc_s_ss_context_damaged",
	0x16c9a0de : "rpc_s_ss_in_null_context",
	0x16c9a0df : "rpc_s_socket_failure",
	0x16c9a0e0 : "rpc_s_unsupported_protect_level",
	0x16c9a0e1 : "rpc_s_invalid_checksum",
	0x16c9a0e2 : "rpc_s_invalid_credentials",
	0x16c9a0e3 : "rpc_s_credentials_too_large",
	0x16c9a0e4 : "rpc_s_call_id_not_found",
	0x16c9a0e5 : "rpc_s_key_id_not_found",
	0x16c9a0e6 : "rpc_s_auth_bad_integrity",
	0x16c9a0e7 : "rpc_s_auth_tkt_expired",
	0x16c9a0e8 : "rpc_s_auth_tkt_nyv",
	0x16c9a0e9 : "rpc_s_auth_repeat",
	0x16c9a0ea : "rpc_s_auth_not_us",
	0x16c9a0eb : "rpc_s_auth_badmatch",
	0x16c9a0ec : "rpc_s_auth_skew",
	0x16c9a0ed : "rpc_s_auth_badaddr",
	0x16c9a0ee : "rpc_s_auth_badversion",
	0x16c9a0ef : "rpc_s_auth_msg_type",
	0x16c9a0f0 : "rpc_s_auth_modified",
	0x16c9a0f1 : "rpc_s_auth_badorder",
	0x16c9a0f2 : "rpc_s_auth_badkeyver",
	0x16c9a0f3 : "rpc_s_auth_nokey",
	0x16c9a0f4 : "rpc_s_auth_mut_fail",
	0x16c9a0f5 : "rpc_s_auth_baddirection",
	0x16c9a0f6 : "rpc_s_auth_method",
	0x16c9a0f7 : "rpc_s_auth_badseq",
	0x16c9a0f8 : "rpc_s_auth_inapp_cksum",
	0x16c9a0f9 : "rpc_s_auth_field_toolong",
	0x16c9a0fa : "rpc_s_invalid_crc",
	0x16c9a0fb : "rpc_s_binding_incomplete",
	0x16c9a0fc : "rpc_s_key_func_not_allowed",
	0x16c9a0fd : "rpc_s_unknown_stub_rtl_if_vers",
	0x16c9a0fe : "rpc_s_unknown_ifspec_vers",
	0x16c9a0ff : "rpc_s_proto_unsupp_by_auth",
	0x16c9a100 : "rpc_s_authn_challenge_malformed",
	0x16c9a101 : "rpc_s_protect_level_mismatch",
	0x16c9a102 : "rpc_s_no_mepv",
	0x16c9a103 : "rpc_s_stub_protocol_error",
	0x16c9a104 : "rpc_s_class_version_mismatch",
	0x16c9a105 : "rpc_s_helper_not_running",
	0x16c9a106 : "rpc_s_helper_short_read",
	0x16c9a107 : "rpc_s_helper_catatonic",
	0x16c9a108 : "rpc_s_helper_aborted",
	0x16c9a109 : "rpc_s_not_in_kernel",
	0x16c9a10a : "rpc_s_helper_wrong_user",
	0x16c9a10b : "rpc_s_helper_overflow",
	0x16c9a10c : "rpc_s_dg_need_way_auth",
	0x16c9a10d : "rpc_s_unsupported_auth_subtype",
	0x16c9a10e : "rpc_s_wrong_pickle_type",
	0x16c9a10f : "rpc_s_not_listening",
	0x16c9a110 : "rpc_s_ss_bad_buffer",
	0x16c9a111 : "rpc_s_ss_bad_es_action",
	0x16c9a112 : "rpc_s_ss_wrong_es_version",
	0x16c9a113 : "rpc_s_fault_user_defined",
	0x16c9a114 : "rpc_s_ss_incompatible_codesets",
	0x16c9a115 : "rpc_s_tx_not_in_transaction",
	0x16c9a116 : "rpc_s_tx_open_failed",
	0x16c9a117 : "rpc_s_partial_credentials",
	0x16c9a118 : "rpc_s_ss_invalid_codeset_tag",
	0x16c9a119 : "rpc_s_mgmt_bad_type",
	0x16c9a11a : "rpc_s_ss_invalid_char_input",
	0x16c9a11b : "rpc_s_ss_short_conv_buffer",
	0x16c9a11c : "rpc_s_ss_iconv_error",
	0x16c9a11d : "rpc_s_ss_no_compat_codeset",
	0x16c9a11e : "rpc_s_ss_no_compat_charsets",
	0x16c9a11f : "dce_cs_c_ok",
	0x16c9a120 : "dce_cs_c_unknown",
	0x16c9a121 : "dce_cs_c_notfound",
	0x16c9a122 : "dce_cs_c_cannot_open_file",
	0x16c9a123 : "dce_cs_c_cannot_read_file",
	0x16c9a124 : "dce_cs_c_cannot_allocate_memory",
	0x16c9a125 : "rpc_s_ss_cleanup_failed",
	0x16c9a126 : "rpc_svc_desc_general",
	0x16c9a127 : "rpc_svc_desc_mutex",
	0x16c9a128 : "rpc_svc_desc_xmit",
	0x16c9a129 : "rpc_svc_desc_recv",
	0x16c9a12a : "rpc_svc_desc_dg_state",
	0x16c9a12b : "rpc_svc_desc_cancel",
	0x16c9a12c : "rpc_svc_desc_orphan",
	0x16c9a12d : "rpc_svc_desc_cn_state",
	0x16c9a12e : "rpc_svc_desc_cn_pkt",
	0x16c9a12f : "rpc_svc_desc_pkt_quotas",
	0x16c9a130 : "rpc_svc_desc_auth",
	0x16c9a131 : "rpc_svc_desc_source",
	0x16c9a132 : "rpc_svc_desc_stats",
	0x16c9a133 : "rpc_svc_desc_mem",
	0x16c9a134 : "rpc_svc_desc_mem_type",
	0x16c9a135 : "rpc_svc_desc_dg_pktlog",
	0x16c9a136 : "rpc_svc_desc_thread_id",
	0x16c9a137 : "rpc_svc_desc_timestamp",
	0x16c9a138 : "rpc_svc_desc_cn_errors",
	0x16c9a139 : "rpc_svc_desc_conv_thread",
	0x16c9a13a : "rpc_svc_desc_pid",
	0x16c9a13b : "rpc_svc_desc_atfork",
	0x16c9a13c : "rpc_svc_desc_cma_thread",
	0x16c9a13d : "rpc_svc_desc_inherit",
	0x16c9a13e : "rpc_svc_desc_dg_sockets",
	0x16c9a13f : "rpc_svc_desc_timer",
	0x16c9a140 : "rpc_svc_desc_threads",
	0x16c9a141 : "rpc_svc_desc_server_call",
	0x16c9a142 : "rpc_svc_desc_nsi",
	0x16c9a143 : "rpc_svc_desc_dg_pkt",
	0x16c9a144 : "rpc_m_cn_ill_state_trans_sa",
	0x16c9a145 : "rpc_m_cn_ill_state_trans_ca",
	0x16c9a146 : "rpc_m_cn_ill_state_trans_sg",
	0x16c9a147 : "rpc_m_cn_ill_state_trans_cg",
	0x16c9a148 : "rpc_m_cn_ill_state_trans_sr",
	0x16c9a149 : "rpc_m_cn_ill_state_trans_cr",
	0x16c9a14a : "rpc_m_bad_pkt_type",
	0x16c9a14b : "rpc_m_prot_mismatch",
	0x16c9a14c : "rpc_m_frag_toobig",
	0x16c9a14d : "rpc_m_unsupp_stub_rtl_if",
	0x16c9a14e : "rpc_m_unhandled_callstate",
	0x16c9a14f : "rpc_m_call_failed",
	0x16c9a150 : "rpc_m_call_failed_no_status",
	0x16c9a151 : "rpc_m_call_failed_errno",
	0x16c9a152 : "rpc_m_call_failed_s",
	0x16c9a153 : "rpc_m_call_failed_c",
	0x16c9a154 : "rpc_m_errmsg_toobig",
	0x16c9a155 : "rpc_m_invalid_srchattr",
	0x16c9a156 : "rpc_m_nts_not_found",
	0x16c9a157 : "rpc_m_invalid_accbytcnt",
	0x16c9a158 : "rpc_m_pre_v2_ifspec",
	0x16c9a159 : "rpc_m_unk_ifspec",
	0x16c9a15a : "rpc_m_recvbuf_toosmall",
	0x16c9a15b : "rpc_m_unalign_authtrl",
	0x16c9a15c : "rpc_m_unexpected_exc",
	0x16c9a15d : "rpc_m_no_stub_data",
	0x16c9a15e : "rpc_m_eventlist_full",
	0x16c9a15f : "rpc_m_unk_sock_type",
	0x16c9a160 : "rpc_m_unimp_call",
	0x16c9a161 : "rpc_m_invalid_seqnum",
	0x16c9a162 : "rpc_m_cant_create_uuid",
	0x16c9a163 : "rpc_m_pre_v2_ss",
	0x16c9a164 : "rpc_m_dgpkt_pool_corrupt",
	0x16c9a165 : "rpc_m_dgpkt_bad_free",
	0x16c9a166 : "rpc_m_lookaside_corrupt",
	0x16c9a167 : "rpc_m_alloc_fail",
	0x16c9a168 : "rpc_m_realloc_fail",
	0x16c9a169 : "rpc_m_cant_open_file",
	0x16c9a16a : "rpc_m_cant_read_addr",
	0x16c9a16b : "rpc_svc_desc_libidl",
	0x16c9a16c : "rpc_m_ctxrundown_nomem",
	0x16c9a16d : "rpc_m_ctxrundown_exc",
	0x16c9a16e : "rpc_s_fault_codeset_conv_error",
	0x16c9a16f : "rpc_s_no_call_active",
	0x16c9a170 : "rpc_s_cannot_support",
	0x16c9a171 : "rpc_s_no_context_available",
}

class DCERPCException(Exception):
	"""
	This is the exception every client should catch regardless of the underlying
	DCERPC Transport used.
	"""
	def __init__(self, error_string=None, error_code=None, packet=None):
		"""
		:param string error_string: A string you want to show explaining the exception. Otherwise the default ones will be used
		:param integer error_code: the error_code if we're using a dictionary with error's descriptions
		:param NDR packet: if successfully decoded, the NDR packet of the response call. This could probably have useful
		information
		"""
		Exception.__init__(self)
		self.packet = packet
		self.error_string = error_string
		if packet is not None:
			try:
				self.error_code = packet['ErrorCode']
			except:
				self.error_code = error_code
		else:
			self.error_code = error_code

	def get_error_code( self ):
		return self.error_code
 
	def get_packet( self ):
		return self.packet

	def __str__( self ):
		key = self.error_code
		if self.error_string is not None:
			return self.error_string
		if key in rpc_status_codes:
			error_msg_short = rpc_status_codes[key]
			return 'DCERPC Runtime Error: code: 0x%x - %s ' % (self.error_code, error_msg_short)
		else:
			return 'DCERPC Runtime Error: unknown error code: 0x%x' % self.error_code

# Context Item
class CtxItem(Structure):
	structure = (
		('ContextID','<H=0'),
		('TransItems','B=0'),
		('Pad','B=0'),
		('AbstractSyntax','20s=""'),
		('TransferSyntax','20s=""'),
	)

class CtxItemResult(Structure):
	structure = (
		('Result','<H=0'),
		('Reason','<H=0'),
		('TransferSyntax','20s=""'),
	)

class SEC_TRAILER(Structure):
	commonHdr = (
		('auth_type', 'B=10'),
		('auth_level','B=0'),
		('auth_pad_len','B=0'),
		('auth_rsvrd','B=0'),
		('auth_ctx_id','<L=747920'),
	)

class MSRPCHeader(Structure):
	_SIZE = 16
	commonHdr = ( 
		('ver_major','B=5'),							  # 0
		('ver_minor','B=0'),							  # 1
		('type','B=0'),								   # 2
		('flags','B=0'),								  # 3
		('representation','<L=0x10'),					 # 4
		('frag_len','<H=self._SIZE+len(auth_data)+(16 if (self["flags"] & 0x80) > 0 else 0)+len(pduData)+len(pad)+len(sec_trailer)'),  # 8
		('auth_len','<H=len(auth_data)'),				 # 10
		('call_id','<L=1'),							   # 12	<-- Common up to here (including this)
	)

	structure = ( 
		('dataLen','_-pduData','self["frag_len"]-self["auth_len"]-self._SIZE-(8 if self["auth_len"] > 0 else 0)'),
		('pduData',':'),								
		('_pad', '_-pad','(4 - ((self._SIZE + (16 if (self["flags"] & 0x80) > 0 else 0) + len(self["pduData"])) & 3) & 3)'),
		('pad', ':'),
		('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
		('sec_trailer',':'),
		('auth_dataLen','_-auth_data','self["auth_len"]'),
		('auth_data',':'),
	)

	def __init__(self, data = None, alignment = 0):
		Structure.__init__(self,data, alignment)
		if data is None:
			self['ver_major'] = 5
			self['ver_minor'] = 0
			self['flags'] = PFC_FIRST_FRAG | PFC_LAST_FRAG
			self['type'] = MSRPC_REQUEST
			self.__frag_len_set = 0
			self['auth_len'] = 0
			self['pduData'] = b''
			self['auth_data'] = b''
			self['sec_trailer'] = b''
			self['pad'] = b''

	def get_header_size(self):
		return self._SIZE + (16 if (self["flags"] & PFC_OBJECT_UUID) > 0 else 0)

	def get_packet(self):
		if self['auth_data'] != b'':
			self['auth_len'] = len(self['auth_data'])
		# The sec_trailer structure MUST be 4-byte aligned with respect to 
		# the beginning of the PDU. Padding octets MUST be used to align the 
		# sec_trailer structure if its natural beginning is not already 4-byte aligned
		##self['pad'] = '\xAA' * (4 - ((self._SIZE + len(self['pduData'])) & 3) & 3)

		return self.getData()

class MSRPCRequestHeader(MSRPCHeader):
	_SIZE = 24
	commonHdr = MSRPCHeader.commonHdr + ( 
		('alloc_hint','<L=0'),							# 16
		('ctx_id','<H=0'),								# 20
		('op_num','<H=0'),								# 22
		('_uuid','_-uuid','16 if self["flags"] & 0x80 > 0 else 0' ), # 22
		('uuid',':'),								# 22
	)

	def __init__(self, data = None, alignment = 0):
		MSRPCHeader.__init__(self, data, alignment)
		if data is None:
		   self['type'] = MSRPC_REQUEST
		   self['ctx_id'] = 0
		   self['uuid'] = b''

class MSRPCRespHeader(MSRPCHeader):
	_SIZE = 24
	commonHdr = MSRPCHeader.commonHdr + ( 
		('alloc_hint','<L=0'),						  # 16   
		('ctx_id','<H=0'),							  # 20
		('cancel_count','<B=0'),						# 22
		('padding','<B=0'),							 # 23
	)

	def __init__(self, aBuffer = None, alignment = 0):
		MSRPCHeader.__init__(self, aBuffer, alignment)
		if aBuffer is None:
			self['type'] = MSRPC_RESPONSE
			self['ctx_id'] = 0

class MSRPCBind(Structure):
	_CTX_ITEM_LEN = len(CtxItem())
	structure = ( 
		('max_tfrag','<H=4280'),
		('max_rfrag','<H=4280'),
		('assoc_group','<L=0'),
		('ctx_num','B=0'),
		('Reserved','B=0'),
		('Reserved2','<H=0'),
		('_ctx_items', '_-ctx_items', 'self["ctx_num"]*self._CTX_ITEM_LEN'),
		('ctx_items',':'),
	)
 
	def __init__(self, data = None, alignment = 0):
		Structure.__init__(self, data, alignment)
		if data is None:
			self['max_tfrag'] = 4280
			self['max_rfrag'] = 4280
			self['assoc_group'] = 0
			self['ctx_num'] = 1
			self['ctx_items'] = b''
		self.__ctx_items = []

	def addCtxItem(self, item):
		self.__ctx_items.append(item)
	
	def getData(self):
		self['ctx_num'] = len(self.__ctx_items)
		for i in self.__ctx_items:
			self['ctx_items'] += i.getData()
		return Structure.getData(self)

class MSRPCBindAck(MSRPCHeader):
	_SIZE = 26 # Up to SecondaryAddr
	_CTX_ITEM_LEN = len(CtxItemResult())
	structure = ( 
		('max_tfrag','<H=0'),
		('max_rfrag','<H=0'),
		('assoc_group','<L=0'),
		('SecondaryAddrLen','<H&SecondaryAddr'), 
		('SecondaryAddr','z'),						  # Optional if SecondaryAddrLen == 0
		('PadLen','_-Pad','(4-((self["SecondaryAddrLen"]+self._SIZE) % 4))%4'),
		('Pad',':'),
		('ctx_num','B=0'),
		('Reserved','B=0'),
		('Reserved2','<H=0'),
		('_ctx_items','_-ctx_items','self["ctx_num"]*self._CTX_ITEM_LEN'),
		('ctx_items',':'),
		('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
		('sec_trailer',':'),
		('auth_dataLen','_-auth_data','self["auth_len"]'),
		('auth_data',':'),
	)
	def __init__(self, data = None, alignment = 0):
		self.__ctx_items = []
		MSRPCHeader.__init__(self,data,alignment)
		if data is None:
			self['Pad'] = b''
			self['ctx_items'] = b''
			self['sec_trailer'] = b''
			self['auth_data'] = b''

	def getCtxItems(self):
		return self.__ctx_items

	def getCtxItem(self,index):
		return self.__ctx_items[index-1]

	def fromString(self, data):
		Structure.fromString(self,data)
		# Parse the ctx_items
		data = self['ctx_items']
		for i in range(self['ctx_num']):
			item = CtxItemResult(data)
			self.__ctx_items.append(item)
			data = data[len(item):]
			
class MSRPCBindNak(Structure):
	structure = ( 
		('RejectedReason','<H=0'),
		('SupportedVersions',':'),
	)
	def __init__(self, data = None, alignment = 0):
		Structure.__init__(self,data,alignment)
		if data is None:
			self['SupportedVersions'] = b''

class DCERPC:
	# Standard NDR Representation
	NDRSyntax   = uuidtup_to_bin(('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0'))
	# NDR 64
	NDR64Syntax = uuidtup_to_bin(('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0'))
	transfer_syntax =  NDRSyntax


class DCERPC_RawCall(MSRPCRequestHeader):
	def __init__(self, op_num, data = b'', uuid=None):
		MSRPCRequestHeader.__init__(self)
		self['op_num'] = op_num
		self['pduData'] = data
		if uuid is not None:
			self['flags'] |= PFC_OBJECT_UUID
			self['uuid'] = uuid

	def setData(self, data):
		self['pduData'] = data

# 2.2.6 Type Serialization Version 1
class CommonHeader(NDRSTRUCT):
	structure = (
		('Version', UCHAR),
		('Endianness', UCHAR),
		('CommonHeaderLength', USHORT),
		('Filler', ULONG),
	)
	def __init__(self, data = None,isNDR64 = False):
		NDRSTRUCT.__init__(self, data, isNDR64)
		if data is None:
			self['Version'] = 1
			self['Endianness'] = 0x10
			self['CommonHeaderLength'] = 8
			self['Filler'] = 0xcccccccc

class PrivateHeader(NDRSTRUCT):
	structure = (
		('ObjectBufferLength', ULONG),
		('Filler', ULONG),
	)
	def __init__(self, data = None,isNDR64 = False):
		NDRSTRUCT.__init__(self, data, isNDR64)
		if data is None:
			self['Filler'] = 0xcccccccc

class TypeSerialization1(NDRSTRUCT):
	commonHdr = (
		('CommonHeader', CommonHeader),
		('PrivateHeader', PrivateHeader),
	)
	def getData(self, soFar = 0):
		self['PrivateHeader']['ObjectBufferLength'] = len(NDRSTRUCT.getData(self, soFar)) + len(
			NDRSTRUCT.getDataReferents(self, soFar)) - len(self['CommonHeader']) - len(self['PrivateHeader'])
		return NDRSTRUCT.getData(self, soFar)
