Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
40
third_party/FreeRDP/channels/rdpear/common/CMakeLists.txt
vendored
Normal file
40
third_party/FreeRDP/channels/rdpear/common/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2024 David Fort <contact@hardening-consulting.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_library(rdpear-common INTERFACE)
|
||||
add_library(
|
||||
rdpear-common-obj STATIC ndr.c rdpear_asn1.c rdpear_common.c rdpear-common/ndr.h rdpear-common/rdpear_asn1.h
|
||||
rdpear-common/rdpear_common.h
|
||||
)
|
||||
|
||||
target_include_directories(rdpear-common SYSTEM INTERFACE ${KRB5_INCLUDE_DIRS})
|
||||
target_compile_options(rdpear-common INTERFACE ${KRB5_CFLAGS})
|
||||
target_link_options(rdpear-common INTERFACE ${KRB5_LDFLAGS})
|
||||
|
||||
target_include_directories(rdpear-common-obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(rdpear-common-obj SYSTEM PRIVATE ${KRB5_INCLUDE_DIRS})
|
||||
target_link_directories(rdpear-common INTERFACE ${KRB5_LIBRARY_DIRS})
|
||||
target_link_libraries(rdpear-common INTERFACE ${KRB5_LIBRARIES} rdpear-common-obj)
|
||||
|
||||
freerdp_client_pc_add_library_private(rdpear-common-obj)
|
||||
|
||||
channel_install(rdpear-common ${FREERDP_ADDIN_PATH} "FreeRDPTargets")
|
||||
channel_install(rdpear-common-obj ${FREERDP_ADDIN_PATH} "FreeRDPTargets")
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
1011
third_party/FreeRDP/channels/rdpear/common/ndr.c
vendored
Normal file
1011
third_party/FreeRDP/channels/rdpear/common/ndr.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
268
third_party/FreeRDP/channels/rdpear/common/rdpear-common/ndr.h
vendored
Normal file
268
third_party/FreeRDP/channels/rdpear/common/rdpear-common/ndr.h
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Authentication redirection virtual channel
|
||||
*
|
||||
* Copyright 2024 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CHANNELS_RDPEAR_NDR_H_
|
||||
#define CHANNELS_RDPEAR_NDR_H_
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#define NDR_PTR_NULL (0UL)
|
||||
|
||||
#define NDR_SIMPLE_TYPE_DECL(LOWER, UPPER) \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##LOWER(NdrContext* context, wStream* s, \
|
||||
UPPER* v); \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##LOWER##_(NdrContext* context, wStream* s, \
|
||||
const void* hints, void* v); \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##LOWER(NdrContext* context, wStream* s, \
|
||||
UPPER v); \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##LOWER##_( \
|
||||
NdrContext* context, wStream* s, const void* hints, const void* v); \
|
||||
FREERDP_LOCAL \
|
||||
extern const NdrMessageDescr ndr_##LOWER##_descr_s; \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL NdrMessageType ndr_##LOWER##_descr(void)
|
||||
|
||||
#define NDR_ARRAY_OF_TYPE_DECL(TYPE, UPPERTYPE) \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##TYPE##Array( \
|
||||
NdrContext* context, wStream* s, const void* hints, void* v); \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##TYPE##Array( \
|
||||
NdrContext* context, wStream* s, const void* hints, const void* v); \
|
||||
FREERDP_LOCAL \
|
||||
void ndr_destroy_##TYPE##Array(NdrContext* context, const void* hints, void* obj); \
|
||||
FREERDP_LOCAL \
|
||||
extern const NdrMessageDescr ndr_##TYPE##Array_descr_s; \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL NdrMessageType ndr_##TYPE##Array_descr(void); \
|
||||
\
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##TYPE##VaryingArray( \
|
||||
NdrContext* context, wStream* s, const void* hints, void* v); \
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##TYPE##VaryingArray( \
|
||||
NdrContext* context, wStream* s, const void* hints, const void* v); \
|
||||
extern const NdrMessageDescr ndr_##TYPE##VaryingArray_descr_s; \
|
||||
NdrMessageType ndr_##TYPE##VaryingArray_descr(void)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct NdrContext_s NdrContext;
|
||||
|
||||
typedef UINT32 ndr_refid;
|
||||
|
||||
typedef BOOL (*NDR_READER_FN)(NdrContext* context, wStream* s, const void* hints, void* target);
|
||||
typedef BOOL (*NDR_WRITER_FN)(NdrContext* context, wStream* s, const void* hints,
|
||||
const void* obj);
|
||||
typedef void (*NDR_DESTROY_FN)(NdrContext* context, const void* hints, void* obj);
|
||||
typedef void (*NDR_DUMP_FN)(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj);
|
||||
|
||||
/** @brief arity of a message */
|
||||
typedef enum
|
||||
{
|
||||
NDR_ARITY_SIMPLE,
|
||||
NDR_ARITY_ARRAYOF,
|
||||
NDR_ARITY_VARYING_ARRAYOF,
|
||||
} NdrTypeArity;
|
||||
|
||||
/** @brief message descriptor */
|
||||
typedef struct
|
||||
{
|
||||
NdrTypeArity arity;
|
||||
size_t itemSize;
|
||||
WINPR_ATTR_NODISCARD NDR_READER_FN readFn;
|
||||
WINPR_ATTR_NODISCARD NDR_WRITER_FN writeFn;
|
||||
NDR_DESTROY_FN destroyFn;
|
||||
NDR_DUMP_FN dumpFn;
|
||||
} NdrMessageDescr;
|
||||
|
||||
typedef const NdrMessageDescr* NdrMessageType;
|
||||
|
||||
/** @brief pointer or not and if null is accepted */
|
||||
typedef enum
|
||||
{
|
||||
NDR_NOT_POINTER,
|
||||
NDR_POINTER_NON_NULL,
|
||||
NDR_POINTER
|
||||
} NdrPointerType;
|
||||
|
||||
/** @brief descriptor of a field in a structure */
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
size_t structOffset;
|
||||
NdrPointerType pointerType;
|
||||
ssize_t hintsField;
|
||||
NdrMessageType typeDescr;
|
||||
} NdrFieldStruct;
|
||||
|
||||
/** @brief structure descriptor */
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
size_t nfields;
|
||||
const NdrFieldStruct* fields;
|
||||
} NdrStructDescr;
|
||||
|
||||
/** @brief a deferred pointer */
|
||||
typedef struct
|
||||
{
|
||||
ndr_refid ptrId;
|
||||
const char* name;
|
||||
void* hints;
|
||||
void* target;
|
||||
NdrMessageType msg;
|
||||
} NdrDeferredEntry;
|
||||
|
||||
FREERDP_LOCAL void ndr_context_free(NdrContext* context);
|
||||
|
||||
static inline void ndr_context_destroy(NdrContext** pcontext)
|
||||
{
|
||||
WINPR_ASSERT(pcontext);
|
||||
ndr_context_free(*pcontext);
|
||||
*pcontext = nullptr;
|
||||
}
|
||||
|
||||
WINPR_ATTR_MALLOC(ndr_context_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL NdrContext* ndr_context_new(BOOL bigEndianDrep, BYTE version);
|
||||
|
||||
FREERDP_LOCAL void ndr_context_reset(NdrContext* context);
|
||||
|
||||
WINPR_ATTR_MALLOC(ndr_context_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL NdrContext* ndr_context_copy(const NdrContext* src);
|
||||
|
||||
WINPR_ATTR_MALLOC(ndr_context_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL NdrContext* ndr_read_header(wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_header(NdrContext* context, wStream* s);
|
||||
|
||||
NDR_SIMPLE_TYPE_DECL(uint8, UINT8);
|
||||
NDR_SIMPLE_TYPE_DECL(uint16, UINT16);
|
||||
NDR_SIMPLE_TYPE_DECL(uint32, UINT32);
|
||||
NDR_SIMPLE_TYPE_DECL(uint64, UINT64);
|
||||
|
||||
NDR_ARRAY_OF_TYPE_DECL(uint8, BYTE);
|
||||
NDR_ARRAY_OF_TYPE_DECL(uint16, UINT16);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_skip_bytes(NdrContext* context, wStream* s,
|
||||
size_t nbytes);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_align(NdrContext* context, wStream* s,
|
||||
size_t sz);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_align(NdrContext* context, wStream* s,
|
||||
size_t sz);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_data(NdrContext* context, wStream* s,
|
||||
const void* data, size_t sz);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_pickle(NdrContext* context, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_pickle(NdrContext* context, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_constructed(NdrContext* context, wStream* s,
|
||||
wStream* target);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_constructed(NdrContext* context, wStream* s,
|
||||
wStream* payload);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_start_constructed(NdrContext* context, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_end_constructed(NdrContext* context, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_wchar(NdrContext* context, wStream* s,
|
||||
WCHAR* ptr);
|
||||
|
||||
/** @brief hints for a varying conformant array */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 length;
|
||||
UINT32 maxLength;
|
||||
} NdrVaryingArrayHints;
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_uconformant_varying_array(
|
||||
NdrContext* context, wStream* s, const NdrVaryingArrayHints* hints, NdrMessageType itemType,
|
||||
void* ptarget);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_uconformant_varying_array(
|
||||
NdrContext* context, wStream* s, const NdrVaryingArrayHints* hints, NdrMessageType itemType,
|
||||
const void* src);
|
||||
|
||||
/** @brief hints for a conformant array */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 count;
|
||||
} NdrArrayHints;
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_uconformant_array(NdrContext* context,
|
||||
wStream* s,
|
||||
const NdrArrayHints* hints,
|
||||
NdrMessageType itemType,
|
||||
void* vtarget);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_uconformant_array(NdrContext* context,
|
||||
wStream* s, UINT32 len,
|
||||
NdrMessageType itemType,
|
||||
const BYTE* ptr);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_struct_read_fromDescr(NdrContext* context,
|
||||
wStream* s,
|
||||
const NdrStructDescr* descr,
|
||||
void* target);
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_struct_write_fromDescr(NdrContext* context,
|
||||
wStream* s,
|
||||
const NdrStructDescr* descr,
|
||||
const void* src);
|
||||
FREERDP_LOCAL
|
||||
void ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
|
||||
const NdrStructDescr* descr, const void* obj);
|
||||
FREERDP_LOCAL
|
||||
void ndr_struct_destroy(NdrContext* context, const NdrStructDescr* descr, void* pptr);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL ndr_refid ndr_pointer_refid(const void* ptr);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_refpointer(NdrContext* context, wStream* s,
|
||||
UINT32* refId);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_context_allocatePtr(NdrContext* context,
|
||||
const void* ptr,
|
||||
ndr_refid* prefId,
|
||||
BOOL* pnewPtr);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_pointedMessageEx(NdrContext* context,
|
||||
wStream* s, ndr_refid ptrId,
|
||||
NdrMessageType descr,
|
||||
void* hints, void** target);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_push_deferreds(NdrContext* context,
|
||||
NdrDeferredEntry* deferreds,
|
||||
size_t ndeferred);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_treat_deferred_read(NdrContext* context,
|
||||
wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_treat_deferred_write(NdrContext* context,
|
||||
wStream* s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CHANNELS_RDPEAR_NDR_H_ */
|
||||
36
third_party/FreeRDP/channels/rdpear/common/rdpear-common/rdpear_asn1.h
vendored
Normal file
36
third_party/FreeRDP/channels/rdpear/common/rdpear-common/rdpear_asn1.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN1 routines for RDPEAR
|
||||
*
|
||||
* Copyright 2024 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RPDEAR_RDPEAR_ASN1_H__
|
||||
#define RPDEAR_RDPEAR_ASN1_H__
|
||||
|
||||
#include <krb5.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
WINPR_ATTR_MALLOC(Stream_Free, 1)
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL wStream* rdpear_enc_Checksum(UINT32 cksumtype,
|
||||
krb5_checksum* csum);
|
||||
|
||||
WINPR_ATTR_MALLOC(Stream_Free, 1)
|
||||
WINPR_ATTR_NODISCARD FREERDP_LOCAL wStream* rdpear_enc_EncryptedData(UINT32 encType,
|
||||
krb5_data* payload);
|
||||
|
||||
#endif /* RPDEAR_RDPEAR_ASN1_H__ */
|
||||
243
third_party/FreeRDP/channels/rdpear/common/rdpear-common/rdpear_common.h
vendored
Normal file
243
third_party/FreeRDP/channels/rdpear/common/rdpear-common/rdpear_common.h
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2023 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_RDPEAR_COMMON_H
|
||||
#define FREERDP_CHANNEL_RDPEAR_COMMON_H
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/asn1.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#include <rdpear-common/ndr.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RDPEAR_PACKAGE_KERBEROS,
|
||||
RDPEAR_PACKAGE_NTLM,
|
||||
RDPEAR_PACKAGE_UNKNOWN
|
||||
} RdpEarPackageType;
|
||||
|
||||
/* RDPEAR 2.2.1.1 */
|
||||
typedef enum
|
||||
{
|
||||
// Start Kerberos remote calls
|
||||
RemoteCallKerbMinimum = 0x100,
|
||||
RemoteCallKerbNegotiateVersion = 0x100,
|
||||
RemoteCallKerbBuildAsReqAuthenticator,
|
||||
RemoteCallKerbVerifyServiceTicket,
|
||||
RemoteCallKerbCreateApReqAuthenticator,
|
||||
RemoteCallKerbDecryptApReply,
|
||||
RemoteCallKerbUnpackKdcReplyBody,
|
||||
RemoteCallKerbComputeTgsChecksum,
|
||||
RemoteCallKerbBuildEncryptedAuthData,
|
||||
RemoteCallKerbPackApReply,
|
||||
RemoteCallKerbHashS4UPreauth,
|
||||
RemoteCallKerbSignS4UPreauthData,
|
||||
RemoteCallKerbVerifyChecksum,
|
||||
RemoteCallKerbReserved1,
|
||||
RemoteCallKerbReserved2,
|
||||
RemoteCallKerbReserved3,
|
||||
RemoteCallKerbReserved4,
|
||||
RemoteCallKerbReserved5,
|
||||
RemoteCallKerbReserved6,
|
||||
RemoteCallKerbReserved7,
|
||||
RemoteCallKerbDecryptPacCredentials,
|
||||
RemoteCallKerbCreateECDHKeyAgreement,
|
||||
RemoteCallKerbCreateDHKeyAgreement,
|
||||
RemoteCallKerbDestroyKeyAgreement,
|
||||
RemoteCallKerbKeyAgreementGenerateNonce,
|
||||
RemoteCallKerbFinalizeKeyAgreement,
|
||||
RemoteCallKerbMaximum = 0x1ff,
|
||||
// End Kerberos remote calls
|
||||
|
||||
// Start NTLM remote calls
|
||||
RemoteCallNtlmMinimum = 0x200,
|
||||
RemoteCallNtlmNegotiateVersion = 0x200,
|
||||
RemoteCallNtlmLm20GetNtlm3ChallengeResponse,
|
||||
RemoteCallNtlmCalculateNtResponse,
|
||||
RemoteCallNtlmCalculateUserSessionKeyNt,
|
||||
RemoteCallNtlmCompareCredentials,
|
||||
RemoteCallNtlmMaximum = 0x2ff,
|
||||
// End NTLM remote calls
|
||||
} RemoteGuardCallId;
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL RdpEarPackageType rdpear_packageType_from_name(const WinPrAsn1_OctetString* package);
|
||||
|
||||
WINPR_ATTR_MALLOC(Stream_Free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL wStream* rdpear_encodePayload(BOOL isKerb, wStream* payload);
|
||||
|
||||
#define RDPEAR_COMMON_MESSAGE_DECL(V) \
|
||||
WINPR_ATTR_NODISCARD \
|
||||
FREERDP_LOCAL BOOL ndr_read_##V(NdrContext* context, wStream* s, const void* hints, V* obj); \
|
||||
WINPR_ATTR_NODISCARD \
|
||||
FREERDP_LOCAL BOOL ndr_write_##V(NdrContext* context, wStream* s, const void* hints, \
|
||||
const V* obj); \
|
||||
FREERDP_LOCAL void ndr_destroy_##V(NdrContext* context, const void* hints, V* obj); \
|
||||
FREERDP_LOCAL void ndr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const V* obj); \
|
||||
WINPR_ATTR_NODISCARD \
|
||||
FREERDP_LOCAL NdrMessageType ndr_##V##_descr(void)
|
||||
|
||||
/** @brief 2.2.1.2.2 KERB_RPC_OCTET_STRING */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 length;
|
||||
BYTE* value;
|
||||
} KERB_RPC_OCTET_STRING;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_OCTET_STRING);
|
||||
|
||||
/** @brief 2.2.1.2.1 KERB_ASN1_DATA */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 Pdu;
|
||||
NdrArrayHints Asn1BufferHints;
|
||||
BYTE* Asn1Buffer;
|
||||
} KERB_ASN1_DATA;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(KERB_ASN1_DATA);
|
||||
|
||||
/** @brief 2.3.10 RPC_UNICODE_STRING (MS-DTYP) */
|
||||
typedef struct
|
||||
{
|
||||
NdrVaryingArrayHints lenHints;
|
||||
UINT32 strLength;
|
||||
WCHAR* Buffer;
|
||||
} RPC_UNICODE_STRING;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(RPC_UNICODE_STRING);
|
||||
|
||||
/** @brief 2.2.1.2.3 KERB_RPC_INTERNAL_NAME */
|
||||
typedef struct
|
||||
{
|
||||
UINT16 NameType;
|
||||
NdrArrayHints nameHints;
|
||||
RPC_UNICODE_STRING* Names;
|
||||
} KERB_RPC_INTERNAL_NAME;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_INTERNAL_NAME);
|
||||
|
||||
/** @brief 2.2.1.2.8 KERB_RPC_ENCRYPTION_KEY */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 reserved1;
|
||||
UINT32 reserved2;
|
||||
KERB_RPC_OCTET_STRING reserved3;
|
||||
} KERB_RPC_ENCRYPTION_KEY;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_ENCRYPTION_KEY);
|
||||
|
||||
/** @brief 2.2.2.1.8 BuildEncryptedAuthData */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 KeyUsage;
|
||||
KERB_RPC_ENCRYPTION_KEY* Key;
|
||||
KERB_ASN1_DATA* PlainAuthData;
|
||||
} BuildEncryptedAuthDataReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(BuildEncryptedAuthDataReq);
|
||||
|
||||
/** @brief 2.2.2.1.7 ComputeTgsChecksum */
|
||||
typedef struct
|
||||
{
|
||||
KERB_ASN1_DATA* requestBody;
|
||||
KERB_RPC_ENCRYPTION_KEY* Key;
|
||||
UINT32 ChecksumType;
|
||||
} ComputeTgsChecksumReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(ComputeTgsChecksumReq);
|
||||
|
||||
/** @brief 2.2.2.1.4 CreateApReqAuthenticator */
|
||||
typedef struct
|
||||
{
|
||||
KERB_RPC_ENCRYPTION_KEY* EncryptionKey;
|
||||
ULONG SequenceNumber;
|
||||
KERB_RPC_INTERNAL_NAME* ClientName;
|
||||
RPC_UNICODE_STRING* ClientRealm;
|
||||
PLARGE_INTEGER SkewTime;
|
||||
KERB_RPC_ENCRYPTION_KEY* SubKey; // optional
|
||||
KERB_ASN1_DATA* AuthData; // optional
|
||||
KERB_ASN1_DATA* GssChecksum; // optional
|
||||
ULONG KeyUsage;
|
||||
} CreateApReqAuthenticatorReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(CreateApReqAuthenticatorReq);
|
||||
|
||||
/** @brief 2.2.2.1.4 CreateApReqAuthenticator */
|
||||
typedef struct
|
||||
{
|
||||
LARGE_INTEGER AuthenticatorTime;
|
||||
KERB_ASN1_DATA Authenticator;
|
||||
LONG KerbProtocolError;
|
||||
} CreateApReqAuthenticatorResp;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(CreateApReqAuthenticatorResp);
|
||||
|
||||
/** @brief 2.2.2.1.6 UnpackKdcReplyBody */
|
||||
typedef struct
|
||||
{
|
||||
KERB_ASN1_DATA* EncryptedData;
|
||||
KERB_RPC_ENCRYPTION_KEY* Key;
|
||||
KERB_RPC_ENCRYPTION_KEY* StrengthenKey;
|
||||
ULONG Pdu;
|
||||
ULONG KeyUsage;
|
||||
} UnpackKdcReplyBodyReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(UnpackKdcReplyBodyReq);
|
||||
|
||||
/** @brief 2.2.2.1.6 UnpackKdcReplyBody */
|
||||
typedef struct
|
||||
{
|
||||
LONG KerbProtocolError;
|
||||
KERB_ASN1_DATA ReplyBody;
|
||||
} UnpackKdcReplyBodyResp;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(UnpackKdcReplyBodyResp);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KERB_ASN1_DATA* EncryptedReply;
|
||||
KERB_RPC_ENCRYPTION_KEY* Key;
|
||||
} DecryptApReplyReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(DecryptApReplyReq);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KERB_ASN1_DATA* Reply;
|
||||
KERB_ASN1_DATA* ReplyBody;
|
||||
KERB_RPC_ENCRYPTION_KEY* SessionKey;
|
||||
} PackApReplyReq;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(PackApReplyReq);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NdrArrayHints PackedReplyHints;
|
||||
BYTE* PackedReply;
|
||||
} PackApReplyResp;
|
||||
|
||||
RDPEAR_COMMON_MESSAGE_DECL(PackApReplyResp);
|
||||
|
||||
#undef RDPEAR_COMMON_MESSAGE_DECL
|
||||
|
||||
#endif /* FREERDP_CHANNEL_RDPEAR_COMMON_H */
|
||||
104
third_party/FreeRDP/channels/rdpear/common/rdpear_asn1.c
vendored
Normal file
104
third_party/FreeRDP/channels/rdpear/common/rdpear_asn1.c
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN1 routines for RDPEAR
|
||||
*
|
||||
* Copyright 2024 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <rdpear-common/rdpear_asn1.h>
|
||||
#include <winpr/asn1.h>
|
||||
|
||||
wStream* rdpear_enc_Checksum(UINT32 cksumtype, krb5_checksum* csum)
|
||||
{
|
||||
/**
|
||||
* Checksum ::= SEQUENCE {
|
||||
* cksumtype [0] Int32,
|
||||
* checksum [1] OCTET STRING
|
||||
* }
|
||||
*/
|
||||
wStream* ret = nullptr;
|
||||
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
return nullptr;
|
||||
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)cksumtype))
|
||||
goto out;
|
||||
|
||||
WinPrAsn1_OctetString octets;
|
||||
octets.data = (BYTE*)csum->contents;
|
||||
octets.len = csum->length;
|
||||
if (!WinPrAsn1EncContextualOctetString(enc, 1, &octets) || !WinPrAsn1EncEndContainer(enc))
|
||||
goto out;
|
||||
|
||||
ret = Stream_New(nullptr, 1024);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (!WinPrAsn1EncToStream(enc, ret))
|
||||
{
|
||||
Stream_Free(ret, TRUE);
|
||||
ret = nullptr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wStream* rdpear_enc_EncryptedData(UINT32 encType, krb5_data* payload)
|
||||
{
|
||||
/**
|
||||
* EncryptedData ::= SEQUENCE {
|
||||
* etype [0] Int32 -- EncryptionType --,
|
||||
* kvno [1] UInt32 OPTIONAL,
|
||||
* cipher [2] OCTET STRING -- ciphertext
|
||||
* }
|
||||
*/
|
||||
wStream* ret = nullptr;
|
||||
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
return nullptr;
|
||||
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)encType))
|
||||
goto out;
|
||||
|
||||
WinPrAsn1_OctetString octets;
|
||||
octets.data = (BYTE*)payload->data;
|
||||
octets.len = payload->length;
|
||||
if (!WinPrAsn1EncContextualOctetString(enc, 2, &octets) || !WinPrAsn1EncEndContainer(enc))
|
||||
goto out;
|
||||
|
||||
ret = Stream_New(nullptr, 1024);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (!WinPrAsn1EncToStream(enc, ret))
|
||||
{
|
||||
Stream_Free(ret, TRUE);
|
||||
ret = nullptr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return ret;
|
||||
}
|
||||
572
third_party/FreeRDP/channels/rdpear/common/rdpear_common.c
vendored
Normal file
572
third_party/FreeRDP/channels/rdpear/common/rdpear_common.c
vendored
Normal file
@@ -0,0 +1,572 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2023 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <rdpear-common/rdpear_common.h>
|
||||
#include <rdpear-common/rdpear_asn1.h>
|
||||
#include <rdpear-common/ndr.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <winpr/print.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define TAG CHANNELS_TAG("rdpear")
|
||||
|
||||
static char kerberosPackageName[] = {
|
||||
'K', 0, 'e', 0, 'r', 0, 'b', 0, 'e', 0, 'r', 0, 'o', 0, 's', 0
|
||||
};
|
||||
static char ntlmPackageName[] = { 'N', 0, 'T', 0, 'L', 0, 'M', 0 };
|
||||
|
||||
RdpEarPackageType rdpear_packageType_from_name(const WinPrAsn1_OctetString* package)
|
||||
{
|
||||
if (package->len == sizeof(kerberosPackageName) &&
|
||||
memcmp(package->data, kerberosPackageName, package->len) == 0)
|
||||
return RDPEAR_PACKAGE_KERBEROS;
|
||||
|
||||
if (package->len == sizeof(ntlmPackageName) &&
|
||||
memcmp(package->data, ntlmPackageName, package->len) == 0)
|
||||
return RDPEAR_PACKAGE_NTLM;
|
||||
|
||||
return RDPEAR_PACKAGE_UNKNOWN;
|
||||
}
|
||||
|
||||
wStream* rdpear_encodePayload(BOOL isKerb, wStream* payload)
|
||||
{
|
||||
wStream* ret = nullptr;
|
||||
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
return nullptr;
|
||||
|
||||
/* TSRemoteGuardInnerPacket ::= SEQUENCE { */
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
/* packageName [1] OCTET STRING */
|
||||
WinPrAsn1_OctetString packageOctetString;
|
||||
if (isKerb)
|
||||
{
|
||||
packageOctetString.data = (BYTE*)kerberosPackageName;
|
||||
packageOctetString.len = sizeof(kerberosPackageName);
|
||||
}
|
||||
else
|
||||
{
|
||||
packageOctetString.data = (BYTE*)ntlmPackageName;
|
||||
packageOctetString.len = sizeof(ntlmPackageName);
|
||||
}
|
||||
|
||||
if (!WinPrAsn1EncContextualOctetString(enc, 1, &packageOctetString))
|
||||
goto out;
|
||||
|
||||
/* buffer [2] OCTET STRING*/
|
||||
WinPrAsn1_OctetString payloadOctetString = { Stream_GetPosition(payload),
|
||||
Stream_Buffer(payload) };
|
||||
if (!WinPrAsn1EncContextualOctetString(enc, 2, &payloadOctetString))
|
||||
goto out;
|
||||
|
||||
/* } */
|
||||
if (!WinPrAsn1EncEndContainer(enc))
|
||||
goto out;
|
||||
|
||||
ret = Stream_New(nullptr, 100);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (!WinPrAsn1EncToStream(enc, ret))
|
||||
{
|
||||
Stream_Free(ret, TRUE);
|
||||
ret = nullptr;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define RDPEAR_SIMPLE_MESSAGE_TYPE(V) \
|
||||
BOOL ndr_read_##V(NdrContext* context, wStream* s, const void* hints, V* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
return ndr_struct_read_fromDescr(context, s, &V##_struct, obj); \
|
||||
} \
|
||||
BOOL ndr_write_##V(NdrContext* context, wStream* s, const void* hints, const V* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
return ndr_struct_write_fromDescr(context, s, &V##_struct, obj); \
|
||||
} \
|
||||
void ndr_destroy_##V(NdrContext* context, const void* hints, V* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
ndr_struct_destroy(context, &V##_struct, obj); \
|
||||
} \
|
||||
void ndr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const V* obj) \
|
||||
{ \
|
||||
ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
|
||||
} \
|
||||
\
|
||||
static BOOL ndr_descr_read_##V(NdrContext* context, wStream* s, const void* hints, void* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
return ndr_struct_read_fromDescr(context, s, &V##_struct, obj); \
|
||||
} \
|
||||
static BOOL ndr_descr_write_##V(NdrContext* context, wStream* s, const void* hints, \
|
||||
const void* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
return ndr_struct_write_fromDescr(context, s, &V##_struct, obj); \
|
||||
} \
|
||||
static void ndr_descr_destroy_##V(NdrContext* context, const void* hints, void* obj) \
|
||||
{ \
|
||||
WINPR_UNUSED(hints); \
|
||||
ndr_struct_destroy(context, &V##_struct, obj); \
|
||||
} \
|
||||
static void ndr_descr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj) \
|
||||
{ \
|
||||
ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
|
||||
} \
|
||||
\
|
||||
static NdrMessageDescr ndr_##V##_descr_s = { \
|
||||
NDR_ARITY_SIMPLE, sizeof(V), ndr_descr_read_##V, ndr_descr_write_##V, \
|
||||
ndr_descr_destroy_##V, ndr_descr_dump_##V, \
|
||||
}; \
|
||||
\
|
||||
NdrMessageType ndr_##V##_descr(void) \
|
||||
{ \
|
||||
return &ndr_##V##_descr_s; \
|
||||
}
|
||||
|
||||
static const NdrFieldStruct KERB_RPC_OCTET_STRING_fields[] = {
|
||||
{ "Length", offsetof(KERB_RPC_OCTET_STRING, length), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
|
||||
{ "value", offsetof(KERB_RPC_OCTET_STRING, value), NDR_POINTER_NON_NULL, 0,
|
||||
&ndr_uint8Array_descr_s }
|
||||
};
|
||||
static const NdrStructDescr KERB_RPC_OCTET_STRING_struct = { "KERB_RPC_OCTET_STRING", 2,
|
||||
KERB_RPC_OCTET_STRING_fields };
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_RPC_OCTET_STRING)
|
||||
|
||||
/* ============================= KERB_ASN1_DATA ============================== */
|
||||
|
||||
static const NdrFieldStruct KERB_ASN1_DATA_fields[] = {
|
||||
{ "Pdu", offsetof(KERB_ASN1_DATA, Pdu), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
|
||||
{ "Count", offsetof(KERB_ASN1_DATA, Asn1BufferHints.count), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "Asn1Buffer", offsetof(KERB_ASN1_DATA, Asn1Buffer), NDR_POINTER_NON_NULL, 1,
|
||||
&ndr_uint8Array_descr_s }
|
||||
};
|
||||
static const NdrStructDescr KERB_ASN1_DATA_struct = { "KERB_ASN1_DATA",
|
||||
ARRAYSIZE(KERB_ASN1_DATA_fields),
|
||||
KERB_ASN1_DATA_fields };
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_ASN1_DATA)
|
||||
|
||||
/* ============================ RPC_UNICODE_STRING ========================== */
|
||||
|
||||
BOOL ndr_read_RPC_UNICODE_STRING(NdrContext* context, wStream* s, const void* hints,
|
||||
RPC_UNICODE_STRING* res)
|
||||
{
|
||||
NdrDeferredEntry bufferDesc = { NDR_PTR_NULL, "RPC_UNICODE_STRING.Buffer", &res->lenHints,
|
||||
(void*)&res->Buffer, ndr_uint16VaryingArray_descr() };
|
||||
UINT16 Length = 0;
|
||||
UINT16 MaximumLength = 0;
|
||||
|
||||
WINPR_UNUSED(hints);
|
||||
if (!ndr_read_uint16(context, s, &Length) || !ndr_read_uint16(context, s, &MaximumLength) ||
|
||||
!ndr_read_refpointer(context, s, &bufferDesc.ptrId) || Length > MaximumLength)
|
||||
return FALSE;
|
||||
|
||||
res->lenHints.length = Length;
|
||||
res->lenHints.maxLength = MaximumLength;
|
||||
res->strLength = Length / 2;
|
||||
|
||||
return ndr_push_deferreds(context, &bufferDesc, 1);
|
||||
}
|
||||
|
||||
static BOOL ndr_descr_read_RPC_UNICODE_STRING(NdrContext* context, wStream* s, const void* hints,
|
||||
void* res)
|
||||
{
|
||||
return ndr_read_RPC_UNICODE_STRING(context, s, hints, res);
|
||||
}
|
||||
|
||||
BOOL ndr_write_RPC_UNICODE_STRING(NdrContext* context, wStream* s,
|
||||
WINPR_ATTR_UNUSED const void* hints,
|
||||
const RPC_UNICODE_STRING* res)
|
||||
{
|
||||
WINPR_ASSERT(res);
|
||||
if (!ndr_write_uint32(context, s, res->lenHints.length))
|
||||
return FALSE;
|
||||
|
||||
if (!ndr_write_uint32(context, s, res->lenHints.maxLength))
|
||||
return FALSE;
|
||||
|
||||
return ndr_write_data(context, s, res->Buffer, res->strLength);
|
||||
}
|
||||
|
||||
static BOOL ndr_write_RPC_UNICODE_STRING_(NdrContext* context, wStream* s, const void* hints,
|
||||
const void* pvres)
|
||||
{
|
||||
const RPC_UNICODE_STRING* res = pvres;
|
||||
return ndr_write_RPC_UNICODE_STRING(context, s, hints, res);
|
||||
}
|
||||
|
||||
void ndr_dump_RPC_UNICODE_STRING(wLog* logger, UINT32 lvl, size_t indentLevel,
|
||||
const RPC_UNICODE_STRING* obj)
|
||||
{
|
||||
WINPR_UNUSED(indentLevel);
|
||||
WLog_Print(logger, lvl, "\tLength=%u MaximumLength=%u", obj->lenHints.length,
|
||||
obj->lenHints.maxLength);
|
||||
winpr_HexLogDump(logger, lvl, obj->Buffer, obj->lenHints.length);
|
||||
}
|
||||
|
||||
static void ndr_descr_dump_RPC_UNICODE_STRING(wLog* logger, UINT32 lvl, size_t indentLevel,
|
||||
const void* obj)
|
||||
{
|
||||
ndr_dump_RPC_UNICODE_STRING(logger, lvl, indentLevel, obj);
|
||||
}
|
||||
|
||||
void ndr_destroy_RPC_UNICODE_STRING(NdrContext* context, const void* hints, RPC_UNICODE_STRING* obj)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
WINPR_UNUSED(hints);
|
||||
if (!obj)
|
||||
return;
|
||||
free(obj->Buffer);
|
||||
obj->Buffer = nullptr;
|
||||
}
|
||||
|
||||
static void ndr_descr_destroy_RPC_UNICODE_STRING(NdrContext* context, const void* hints, void* obj)
|
||||
{
|
||||
ndr_destroy_RPC_UNICODE_STRING(context, hints, obj);
|
||||
}
|
||||
|
||||
static const NdrMessageDescr RPC_UNICODE_STRING_descr_s = { NDR_ARITY_SIMPLE,
|
||||
sizeof(RPC_UNICODE_STRING),
|
||||
ndr_descr_read_RPC_UNICODE_STRING,
|
||||
ndr_write_RPC_UNICODE_STRING_,
|
||||
ndr_descr_destroy_RPC_UNICODE_STRING,
|
||||
ndr_descr_dump_RPC_UNICODE_STRING };
|
||||
|
||||
NdrMessageType ndr_RPC_UNICODE_STRING_descr(void)
|
||||
{
|
||||
return &RPC_UNICODE_STRING_descr_s;
|
||||
}
|
||||
|
||||
/* ========================= RPC_UNICODE_STRING_Array ======================== */
|
||||
|
||||
static BOOL ndr_read_RPC_UNICODE_STRING_Array(NdrContext* context, wStream* s, const void* hints,
|
||||
void* v)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(hints);
|
||||
return ndr_read_uconformant_array(context, s, hints, ndr_RPC_UNICODE_STRING_descr(), v);
|
||||
}
|
||||
|
||||
static BOOL ndr_write_RPC_UNICODE_STRING_Array(NdrContext* context, wStream* s, const void* ghints,
|
||||
const void* v)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(ghints);
|
||||
|
||||
const NdrArrayHints* hints = (const NdrArrayHints*)ghints;
|
||||
|
||||
return ndr_write_uconformant_array(context, s, hints->count, ndr_RPC_UNICODE_STRING_descr(), v);
|
||||
}
|
||||
|
||||
static const NdrMessageDescr RPC_UNICODE_STRING_Array_descr_s = {
|
||||
NDR_ARITY_ARRAYOF,
|
||||
sizeof(RPC_UNICODE_STRING),
|
||||
ndr_read_RPC_UNICODE_STRING_Array,
|
||||
ndr_write_RPC_UNICODE_STRING_Array,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
static NdrMessageType ndr_RPC_UNICODE_STRING_Array_descr(void)
|
||||
{
|
||||
return &RPC_UNICODE_STRING_Array_descr_s;
|
||||
}
|
||||
|
||||
/* ========================== KERB_RPC_INTERNAL_NAME ======================== */
|
||||
|
||||
BOOL ndr_read_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s, const void* hints,
|
||||
KERB_RPC_INTERNAL_NAME* res)
|
||||
{
|
||||
WINPR_ASSERT(res);
|
||||
|
||||
union
|
||||
{
|
||||
RPC_UNICODE_STRING** ppstr;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.ppstr = &res->Names;
|
||||
NdrDeferredEntry names = { NDR_PTR_NULL, "KERB_RPC_INTERNAL_NAME.Names", &res->nameHints,
|
||||
cnv.pv, ndr_RPC_UNICODE_STRING_Array_descr() };
|
||||
|
||||
UINT16 nameCount = 0;
|
||||
WINPR_UNUSED(hints);
|
||||
|
||||
if (!ndr_read_uint16(context, s, &res->NameType) || !ndr_read_uint16(context, s, &nameCount))
|
||||
return FALSE;
|
||||
|
||||
res->nameHints.count = nameCount;
|
||||
|
||||
return ndr_read_refpointer(context, s, &names.ptrId) && ndr_push_deferreds(context, &names, 1);
|
||||
}
|
||||
|
||||
static BOOL ndr_descr_read_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s,
|
||||
const void* hints, void* res)
|
||||
{
|
||||
return ndr_read_KERB_RPC_INTERNAL_NAME(context, s, hints, res);
|
||||
}
|
||||
|
||||
BOOL ndr_write_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s, const void* hints,
|
||||
const KERB_RPC_INTERNAL_NAME* res)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
WINPR_UNUSED(s);
|
||||
WINPR_UNUSED(hints);
|
||||
WINPR_UNUSED(res);
|
||||
WLog_ERR(TAG, "TODO: implement this");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ndr_dump_KERB_RPC_INTERNAL_NAME(wLog* logger, UINT32 lvl, size_t indentLevel,
|
||||
const KERB_RPC_INTERNAL_NAME* obj)
|
||||
{
|
||||
WINPR_UNUSED(indentLevel);
|
||||
WINPR_UNUSED(obj);
|
||||
WLog_Print(logger, lvl, "TODO: implement this");
|
||||
}
|
||||
|
||||
static void ndr_descr_dump_KERB_RPC_INTERNAL_NAME(wLog* logger, UINT32 lvl, size_t indentLevel,
|
||||
const void* obj)
|
||||
{
|
||||
ndr_dump_KERB_RPC_INTERNAL_NAME(logger, lvl, indentLevel, obj);
|
||||
}
|
||||
|
||||
void ndr_destroy_KERB_RPC_INTERNAL_NAME(NdrContext* context, const void* hints,
|
||||
KERB_RPC_INTERNAL_NAME* obj)
|
||||
{
|
||||
WINPR_UNUSED(hints);
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
for (UINT32 i = 0; i < obj->nameHints.count; i++)
|
||||
ndr_destroy_RPC_UNICODE_STRING(context, nullptr, &obj->Names[i]);
|
||||
|
||||
free(obj->Names);
|
||||
obj->Names = nullptr;
|
||||
}
|
||||
|
||||
static void ndr_descr_destroy_KERB_RPC_INTERNAL_NAME(NdrContext* context, const void* hints,
|
||||
void* obj)
|
||||
{
|
||||
ndr_destroy_KERB_RPC_INTERNAL_NAME(context, hints, obj);
|
||||
}
|
||||
|
||||
static NdrMessageDescr KERB_RPC_INTERNAL_NAME_descr_s = { NDR_ARITY_SIMPLE,
|
||||
sizeof(KERB_RPC_INTERNAL_NAME),
|
||||
ndr_descr_read_KERB_RPC_INTERNAL_NAME,
|
||||
nullptr,
|
||||
ndr_descr_destroy_KERB_RPC_INTERNAL_NAME,
|
||||
ndr_descr_dump_KERB_RPC_INTERNAL_NAME };
|
||||
|
||||
NdrMessageType ndr_KERB_RPC_INTERNAL_NAME_descr(void)
|
||||
{
|
||||
return &KERB_RPC_INTERNAL_NAME_descr_s;
|
||||
}
|
||||
|
||||
/* ========================== KERB_RPC_ENCRYPTION_KEY ======================== */
|
||||
|
||||
static const NdrFieldStruct KERB_RPC_ENCRYPTION_KEY_fields[] = {
|
||||
{ "reserved1", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved1), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "reserved2", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved2), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "reserved3", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved3), NDR_NOT_POINTER, -1,
|
||||
&ndr_KERB_RPC_OCTET_STRING_descr_s }
|
||||
};
|
||||
static const NdrStructDescr KERB_RPC_ENCRYPTION_KEY_struct = {
|
||||
"KERB_RPC_ENCRYPTION_KEY", ARRAYSIZE(KERB_RPC_ENCRYPTION_KEY_fields),
|
||||
KERB_RPC_ENCRYPTION_KEY_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_RPC_ENCRYPTION_KEY)
|
||||
|
||||
/* ========================== BuildEncryptedAuthDataReq ======================== */
|
||||
|
||||
static const NdrFieldStruct BuildEncryptedAuthDataReq_fields[] = {
|
||||
{ "KeyUsage", offsetof(BuildEncryptedAuthDataReq, KeyUsage), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "key", offsetof(BuildEncryptedAuthDataReq, Key), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "plainAuthData", offsetof(BuildEncryptedAuthDataReq, PlainAuthData), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s }
|
||||
};
|
||||
static const NdrStructDescr BuildEncryptedAuthDataReq_struct = {
|
||||
"BuildEncryptedAuthDataReq", ARRAYSIZE(BuildEncryptedAuthDataReq_fields),
|
||||
BuildEncryptedAuthDataReq_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(BuildEncryptedAuthDataReq)
|
||||
|
||||
/* ========================== ComputeTgsChecksumReq ======================== */
|
||||
|
||||
static const NdrFieldStruct ComputeTgsChecksumReq_fields[] = {
|
||||
{ "requestBody", offsetof(ComputeTgsChecksumReq, requestBody), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "key", offsetof(ComputeTgsChecksumReq, Key), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "ChecksumType", offsetof(ComputeTgsChecksumReq, ChecksumType), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s }
|
||||
};
|
||||
static const NdrStructDescr ComputeTgsChecksumReq_struct = {
|
||||
"ComputeTgsChecksumReq", ARRAYSIZE(ComputeTgsChecksumReq_fields), ComputeTgsChecksumReq_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(ComputeTgsChecksumReq)
|
||||
|
||||
/* ========================== CreateApReqAuthenticatorReq ======================== */
|
||||
|
||||
static const NdrFieldStruct CreateApReqAuthenticatorReq_fields[] = {
|
||||
{ "EncryptionKey", offsetof(CreateApReqAuthenticatorReq, EncryptionKey), NDR_POINTER_NON_NULL,
|
||||
-1, &ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "SequenceNumber", offsetof(CreateApReqAuthenticatorReq, SequenceNumber), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "ClientName", offsetof(CreateApReqAuthenticatorReq, ClientName), NDR_POINTER_NON_NULL, -1,
|
||||
&KERB_RPC_INTERNAL_NAME_descr_s },
|
||||
{ "ClientRealm", offsetof(CreateApReqAuthenticatorReq, ClientRealm), NDR_POINTER_NON_NULL, -1,
|
||||
&RPC_UNICODE_STRING_descr_s },
|
||||
{ "SkewTime", offsetof(CreateApReqAuthenticatorReq, SkewTime), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_uint64_descr_s },
|
||||
{ "SubKey", offsetof(CreateApReqAuthenticatorReq, SubKey), NDR_POINTER, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "AuthData", offsetof(CreateApReqAuthenticatorReq, AuthData), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "GssChecksum", offsetof(CreateApReqAuthenticatorReq, GssChecksum), NDR_POINTER, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "KeyUsage", offsetof(CreateApReqAuthenticatorReq, KeyUsage), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
};
|
||||
static const NdrStructDescr CreateApReqAuthenticatorReq_struct = {
|
||||
"CreateApReqAuthenticatorReq", ARRAYSIZE(CreateApReqAuthenticatorReq_fields),
|
||||
CreateApReqAuthenticatorReq_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(CreateApReqAuthenticatorReq)
|
||||
|
||||
/* ========================== CreateApReqAuthenticatorResp ======================== */
|
||||
|
||||
static const NdrFieldStruct CreateApReqAuthenticatorResp_fields[] = {
|
||||
{ "AuthenticatorTime", offsetof(CreateApReqAuthenticatorResp, AuthenticatorTime),
|
||||
NDR_NOT_POINTER, -1, &ndr_uint64_descr_s },
|
||||
{ "Authenticator", offsetof(CreateApReqAuthenticatorResp, Authenticator), NDR_NOT_POINTER, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "KerbProtocolError", offsetof(CreateApReqAuthenticatorResp, KerbProtocolError),
|
||||
NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
|
||||
};
|
||||
|
||||
static const NdrStructDescr CreateApReqAuthenticatorResp_struct = {
|
||||
"CreateApReqAuthenticatorResp", ARRAYSIZE(CreateApReqAuthenticatorResp_fields),
|
||||
CreateApReqAuthenticatorResp_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(CreateApReqAuthenticatorResp)
|
||||
|
||||
/* ========================== UnpackKdcReplyBodyReq ======================== */
|
||||
|
||||
static const NdrFieldStruct UnpackKdcReplyBodyReq_fields[] = {
|
||||
{ "EncryptedData", offsetof(UnpackKdcReplyBodyReq, EncryptedData), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "Key", offsetof(UnpackKdcReplyBodyReq, Key), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "StrenghtenKey", offsetof(UnpackKdcReplyBodyReq, StrengthenKey), NDR_POINTER, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
|
||||
{ "Pdu", offsetof(UnpackKdcReplyBodyReq, Pdu), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
|
||||
{ "KeyUsage", offsetof(UnpackKdcReplyBodyReq, KeyUsage), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
};
|
||||
|
||||
static const NdrStructDescr UnpackKdcReplyBodyReq_struct = {
|
||||
"UnpackKdcReplyBodyReq", ARRAYSIZE(UnpackKdcReplyBodyReq_fields), UnpackKdcReplyBodyReq_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(UnpackKdcReplyBodyReq)
|
||||
|
||||
/* ========================== UnpackKdcReplyBodyResp ======================== */
|
||||
|
||||
static const NdrFieldStruct UnpackKdcReplyBodyResp_fields[] = {
|
||||
{ "KerbProtocolError", offsetof(UnpackKdcReplyBodyResp, KerbProtocolError), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "ReplyBody", offsetof(UnpackKdcReplyBodyResp, ReplyBody), NDR_NOT_POINTER, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s }
|
||||
};
|
||||
|
||||
static const NdrStructDescr UnpackKdcReplyBodyResp_struct = {
|
||||
"UnpackKdcReplyBodyResp", ARRAYSIZE(UnpackKdcReplyBodyResp_fields),
|
||||
UnpackKdcReplyBodyResp_fields
|
||||
};
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(UnpackKdcReplyBodyResp)
|
||||
|
||||
/* ========================== DecryptApReplyReq ======================== */
|
||||
|
||||
static const NdrFieldStruct DecryptApReplyReq_fields[] = {
|
||||
{ "EncryptedReply", offsetof(DecryptApReplyReq, EncryptedReply), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "Key", offsetof(DecryptApReplyReq, Key), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s }
|
||||
};
|
||||
|
||||
static const NdrStructDescr DecryptApReplyReq_struct = { "DecryptApReplyReq",
|
||||
ARRAYSIZE(DecryptApReplyReq_fields),
|
||||
DecryptApReplyReq_fields };
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(DecryptApReplyReq)
|
||||
|
||||
/* ========================== PackApReplyReq ======================== */
|
||||
|
||||
static const NdrFieldStruct PackApReplyReq_fields[] = {
|
||||
{ "Reply", offsetof(PackApReplyReq, Reply), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "ReplyBody", offsetof(PackApReplyReq, ReplyBody), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_ASN1_DATA_descr_s },
|
||||
{ "SessionKey", offsetof(PackApReplyReq, SessionKey), NDR_POINTER_NON_NULL, -1,
|
||||
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s }
|
||||
};
|
||||
|
||||
static const NdrStructDescr PackApReplyReq_struct = { "PackApReplyReq",
|
||||
ARRAYSIZE(PackApReplyReq_fields),
|
||||
PackApReplyReq_fields };
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(PackApReplyReq)
|
||||
|
||||
/* ========================== PackApReplyResp ======================== */
|
||||
|
||||
static const NdrFieldStruct PackApReplyResp_fields[] = {
|
||||
{ "PackedReplySize", offsetof(PackApReplyResp, PackedReplyHints), NDR_NOT_POINTER, -1,
|
||||
&ndr_uint32_descr_s },
|
||||
{ "PackedReply", offsetof(PackApReplyResp, PackedReply), NDR_POINTER_NON_NULL, 0,
|
||||
&ndr_uint8Array_descr_s },
|
||||
};
|
||||
|
||||
static const NdrStructDescr PackApReplyResp_struct = { "PackApReplyResp",
|
||||
ARRAYSIZE(PackApReplyResp_fields),
|
||||
PackApReplyResp_fields };
|
||||
|
||||
RDPEAR_SIMPLE_MESSAGE_TYPE(PackApReplyResp)
|
||||
30
third_party/FreeRDP/channels/rdpear/common/test/CMakeLists.txt
vendored
Normal file
30
third_party/FreeRDP/channels/rdpear/common/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
set(MODULE_NAME "TestRdpear")
|
||||
set(MODULE_PREFIX "TEST_RDPEAR")
|
||||
|
||||
set(TEST_RDPEAR_DRIVER TestRdpear.c)
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(TEST_RDPEAR_TESTS TestNdr.c)
|
||||
|
||||
if(BUILD_TESTING_INTERNAL)
|
||||
list(APPEND TEST_RDPEAR_TESTS TestNdrEar.c)
|
||||
endif()
|
||||
|
||||
create_test_sourcelist(TEST_RDPEAR_SRCS TestRdpear.c ${TEST_RDPEAR_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${TEST_RDPEAR_SRCS})
|
||||
|
||||
add_compile_definitions(TESTING_OUTPUT_DIRECTORY="${PROJECT_BINARY_DIR}")
|
||||
add_compile_definitions(TESTING_SRC_DIRECTORY="${PROJECT_SOURCE_DIR}")
|
||||
|
||||
target_link_libraries(${MODULE_NAME} freerdp winpr freerdp-client rdpear-common)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Rdpear/Test")
|
||||
40
third_party/FreeRDP/channels/rdpear/common/test/TestNdr.c
vendored
Normal file
40
third_party/FreeRDP/channels/rdpear/common/test/TestNdr.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <rdpear-common/ndr.h>
|
||||
|
||||
int TestNdr(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
int retCode = -2;
|
||||
NdrContext* context = ndr_context_new(FALSE, 1);
|
||||
if (!context)
|
||||
return -1;
|
||||
|
||||
BYTE payload[] = {
|
||||
// == conformant array ==
|
||||
0x02, 0x00, 0x00, 0x00, // (nitems)
|
||||
0x30, 0x00, // content
|
||||
0x00, 0x00 // (padding)
|
||||
};
|
||||
wStream staticS;
|
||||
wStream* s = Stream_StaticInit(&staticS, payload, sizeof(payload));
|
||||
|
||||
BYTE* target = nullptr;
|
||||
NdrArrayHints hints = { 2 };
|
||||
NdrDeferredEntry e = { 0x020028, "arrayContent", &hints, (void*)&target,
|
||||
ndr_uint8Array_descr() };
|
||||
|
||||
if (!ndr_push_deferreds(context, &e, 1))
|
||||
goto out;
|
||||
|
||||
if (!ndr_treat_deferred_read(context, s))
|
||||
goto out;
|
||||
|
||||
NdrMessageType descr = ndr_uint8Array_descr();
|
||||
descr->destroyFn(context, &hints, target);
|
||||
free(target);
|
||||
retCode = 0;
|
||||
out:
|
||||
ndr_context_destroy(&context);
|
||||
return retCode;
|
||||
}
|
||||
417
third_party/FreeRDP/channels/rdpear/common/test/TestNdrEar.c
vendored
Normal file
417
third_party/FreeRDP/channels/rdpear/common/test/TestNdrEar.c
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include <rdpear-common/ndr.h>
|
||||
#include <rdpear-common/rdpear_common.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b)) ? (a) : (b)
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)) ? (a) : (b)
|
||||
#endif
|
||||
|
||||
static BYTE nextValue(BYTE old, INT32 offset, char symbol, char startSymbol)
|
||||
{
|
||||
const INT32 uold = 16 * old;
|
||||
const INT32 diff = symbol - startSymbol;
|
||||
const INT32 res = uold + diff + offset;
|
||||
return (BYTE)MIN(MAX(0, res), UINT8_MAX);
|
||||
}
|
||||
|
||||
static BYTE* parseHexBlock(const char* str, size_t* plen)
|
||||
{
|
||||
WINPR_ASSERT(str);
|
||||
WINPR_ASSERT(plen);
|
||||
|
||||
BYTE* ret = malloc(strlen(str) / 2);
|
||||
BYTE* dest = ret;
|
||||
const char* ptr = str;
|
||||
BYTE tmp = 0;
|
||||
size_t nchars = 0;
|
||||
size_t len = 0;
|
||||
|
||||
for (; *ptr; ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
if (nchars)
|
||||
{
|
||||
WLog_ERR("", "error parsing hex block, unpaired char");
|
||||
free(ret);
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
tmp = nextValue(tmp, 0, *ptr, '0');
|
||||
nchars++;
|
||||
if (nchars == 2)
|
||||
{
|
||||
*dest = tmp;
|
||||
dest++;
|
||||
len++;
|
||||
tmp = 0;
|
||||
nchars = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
tmp = nextValue(tmp, 10, *ptr, 'a');
|
||||
nchars++;
|
||||
if (nchars == 2)
|
||||
{
|
||||
*dest = tmp;
|
||||
dest++;
|
||||
len++;
|
||||
tmp = 0;
|
||||
nchars = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
tmp = nextValue(tmp, 10, *ptr, 'A');
|
||||
nchars++;
|
||||
if (nchars == 2)
|
||||
{
|
||||
*dest = tmp;
|
||||
dest++;
|
||||
len++;
|
||||
tmp = 0;
|
||||
nchars = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WLog_ERR("", "invalid char in hex block");
|
||||
free(ret);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
*plen = len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int TestNdrEarWrite(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
int rc = -1;
|
||||
BYTE buffer[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
KERB_ASN1_DATA asn1 = { 7, { 16 }, buffer };
|
||||
|
||||
wStream* s = Stream_New(nullptr, 100);
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
NdrContext* context = ndr_context_new(FALSE, 1);
|
||||
if (!context)
|
||||
goto fail;
|
||||
|
||||
if (!ndr_write_KERB_ASN1_DATA(context, s, nullptr, &asn1))
|
||||
goto fail;
|
||||
if (!ndr_treat_deferred_write(context, s))
|
||||
goto fail;
|
||||
|
||||
// winpr_HexDump("", WLOG_DEBUG, Stream_Buffer(s), Stream_GetPosition(s));
|
||||
|
||||
rc = 0;
|
||||
fail:
|
||||
ndr_context_destroy(&context);
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL run_payload(NdrContext* context, const BYTE* payload4, size_t sizeofPayload4)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!payload4)
|
||||
return FALSE;
|
||||
|
||||
CreateApReqAuthenticatorReq createApReqAuthenticatorReq = WINPR_C_ARRAY_INIT;
|
||||
|
||||
wStream staticS = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&staticS, payload4, sizeofPayload4);
|
||||
if (!ndr_skip_bytes(context, s, 4)) /* skip union id */
|
||||
return FALSE;
|
||||
if (!ndr_read_CreateApReqAuthenticatorReq(context, s, nullptr, &createApReqAuthenticatorReq))
|
||||
return FALSE;
|
||||
if (!ndr_treat_deferred_read(context, s))
|
||||
return FALSE;
|
||||
if (createApReqAuthenticatorReq.KeyUsage != 7)
|
||||
return FALSE;
|
||||
if (!createApReqAuthenticatorReq.EncryptionKey)
|
||||
return FALSE;
|
||||
if (createApReqAuthenticatorReq.SubKey)
|
||||
return FALSE;
|
||||
if (!createApReqAuthenticatorReq.ClientName)
|
||||
return FALSE;
|
||||
if (createApReqAuthenticatorReq.ClientName->nameHints.count != 1)
|
||||
return FALSE;
|
||||
if (!createApReqAuthenticatorReq.ClientRealm)
|
||||
return FALSE;
|
||||
if (!createApReqAuthenticatorReq.AuthData)
|
||||
return FALSE;
|
||||
if (createApReqAuthenticatorReq.AuthData->Asn1BufferHints.count != 2)
|
||||
return FALSE;
|
||||
if (!createApReqAuthenticatorReq.SkewTime)
|
||||
return FALSE;
|
||||
if (createApReqAuthenticatorReq.SkewTime->QuadPart != 0)
|
||||
return FALSE;
|
||||
|
||||
ndr_destroy_CreateApReqAuthenticatorReq(context, nullptr, &createApReqAuthenticatorReq);
|
||||
ndr_context_reset(context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int TestNdrEarRead(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
int retCode = -1;
|
||||
|
||||
/* ====================================================================== */
|
||||
NdrContext* context = ndr_context_new(FALSE, 1);
|
||||
if (!context)
|
||||
return -1;
|
||||
|
||||
{
|
||||
retCode = -2;
|
||||
const BYTE payload[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // (PduType)
|
||||
0x02, 0x00, 0x00, 0x00, // (Length)
|
||||
0x28, 0x00, 0x02, 0x00, // (Asn1Buffer)
|
||||
|
||||
// == conformant array ==
|
||||
0x02, 0x00, 0x00, 0x00, // (nitems)
|
||||
0x30, 0x00, // content
|
||||
0x00, 0x00 // (padding)
|
||||
};
|
||||
|
||||
wStream staticS = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&staticS, payload, sizeof(payload));
|
||||
|
||||
KERB_ASN1_DATA asn1 = WINPR_C_ARRAY_INIT;
|
||||
if (!ndr_read_KERB_ASN1_DATA(context, s, nullptr, &asn1) ||
|
||||
!ndr_treat_deferred_read(context, s) || asn1.Asn1BufferHints.count != 2 ||
|
||||
*asn1.Asn1Buffer != 0x30)
|
||||
goto out;
|
||||
ndr_destroy_KERB_ASN1_DATA(context, nullptr, &asn1);
|
||||
ndr_context_reset(context);
|
||||
|
||||
/* ====================================================================== */
|
||||
}
|
||||
{
|
||||
retCode = -3;
|
||||
const BYTE payload2[] = {
|
||||
// ------------ a RPC_UNICODE_STRING: Administrateur -------------------------
|
||||
0x1c, 0x00, // (Length)
|
||||
0x1e, 0x00, // (MaximumLength)
|
||||
0x1c, 0x00, 0x02, 0x00, // (Buffer ptr)
|
||||
// == conformant array ==
|
||||
0x0f, 0x00, 0x00, 0x00, // (maximum count)
|
||||
0x00, 0x00, 0x00, 0x00, // (offset)
|
||||
0x0e, 0x00, 0x00, 0x00, // (length)
|
||||
|
||||
0x48, 0x00, 0x41, 0x00, 0x52, 0x00, 0x44, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x49, 0x00,
|
||||
0x4e, 0x00, 0x47, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
wStream staticS = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&staticS, payload2, sizeof(payload2));
|
||||
RPC_UNICODE_STRING unicode = WINPR_C_ARRAY_INIT;
|
||||
if (!ndr_read_RPC_UNICODE_STRING(context, s, nullptr, &unicode) ||
|
||||
!ndr_treat_deferred_read(context, s))
|
||||
goto out;
|
||||
ndr_destroy_RPC_UNICODE_STRING(context, nullptr, &unicode);
|
||||
ndr_context_reset(context);
|
||||
}
|
||||
{
|
||||
retCode = -4;
|
||||
/* ====================================================================== */
|
||||
const BYTE payload3[] = {
|
||||
// ------------ an KERB_RPC_INTERNAL_NAME: HARDENING3.COM -------------------------
|
||||
0x01, 0x00, // (NameType)
|
||||
0x01, 0x00, // (NameCount)
|
||||
0x10, 0x00, 0x02, 0x00, // (Names)
|
||||
// == conformant array ==
|
||||
0x01, 0x00, 0x00, 0x00, // (nitems)
|
||||
|
||||
// = RPC_UNICODE_STRING =
|
||||
0x1c, 0x00, // (Length)
|
||||
0x1e, 0x00, // (MaximumLength)
|
||||
0x14, 0x00, 0x02, 0x00, /// (Buffer ptr)
|
||||
// == Uni-dimensional Conformant-varying Array ==
|
||||
0x0f, 0x00, 0x00, 0x00, // (maximum count)
|
||||
0x00, 0x00, 0x00, 0x00, // (offset)
|
||||
0x0e, 0x00, 0x00, 0x00, // (length)
|
||||
0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
|
||||
0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x75, 0x00, 0x72, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
KERB_RPC_INTERNAL_NAME intName = WINPR_C_ARRAY_INIT;
|
||||
|
||||
wStream staticS = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&staticS, payload3, sizeof(payload3));
|
||||
if (!ndr_read_KERB_RPC_INTERNAL_NAME(context, s, nullptr, &intName) ||
|
||||
!ndr_treat_deferred_read(context, s))
|
||||
goto out;
|
||||
ndr_destroy_KERB_RPC_INTERNAL_NAME(context, nullptr, &intName);
|
||||
ndr_context_reset(context);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
{
|
||||
retCode = -5;
|
||||
const BYTE payload4[] = {
|
||||
0x03, 0x01, 0x03, 0x01, // unionId / unionId
|
||||
0x04, 0x00, 0x02, 0x00, // (EncryptionKey ptr)
|
||||
0xf8, 0xca, 0x95, 0x11, // (SequenceNumber)
|
||||
0x0c, 0x00, 0x02, 0x00, // (ClientName ptr)
|
||||
0x18, 0x00, 0x02, 0x00, // (ClientRealm ptr)
|
||||
0x20, 0x00, 0x02, 0x00, // (SkewTime ptr)
|
||||
0x00, 0x00, 0x00, 0x00, // (SubKey ptr)
|
||||
0x24, 0x00, 0x02, 0x00, // (AuthData ptr)
|
||||
0x2c, 0x00, 0x02, 0x00, // (GssChecksum ptr)
|
||||
0x07, 0x00, 0x00, 0x00, // (KeyUsage)
|
||||
|
||||
// === EncryptionKey ===
|
||||
0x40, 0xe9, 0x12, 0xdf, // reserved1
|
||||
0x12, 0x00, 0x00, 0x00, // reserved2
|
||||
// KERB_RPC_OCTET_STRING
|
||||
0x4c, 0x00, 0x00, 0x00, // (length)
|
||||
0x08, 0x00, 0x02, 0x00, // (value ptr)
|
||||
// == conformant array ==
|
||||
0x4c, 0x00, 0x00, 0x00, // (length)
|
||||
0xc4, 0x41, 0xee, 0x34, 0x82, 0x2b, 0x29, 0x61, 0xe2, 0x96, 0xb5, 0x75, 0x61, 0x2d,
|
||||
0xbf, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x89, 0x08, 0x60, 0x2e, 0x30, 0x3e, 0xfe, 0x56, 0x11, 0xf0,
|
||||
0x31, 0xf2, 0xd6, 0x2e, 0x3d, 0x33, 0xfe, 0xce, 0x56, 0x12, 0xbf, 0xb2, 0xe5, 0x86,
|
||||
0x29, 0x8d, 0x29, 0x74, 0x1f, 0x8a, 0xf9, 0xb9, 0x8c, 0xd4, 0x86, 0x3a, 0x21, 0x92,
|
||||
0xb2, 0x07, 0x95, 0x4b, 0xea, 0xee,
|
||||
|
||||
//=== ClientName - KERB_RPC_INTERNAL_NAME ===
|
||||
0x01, 0x00, // (NameType)
|
||||
0x01, 0x00, // (NameCount)
|
||||
0x10, 0x00, 0x02, 0x00, // (Names)
|
||||
|
||||
0x01, 0x00, 0x00, 0x00, // (nitems)
|
||||
|
||||
// = RPC_UNICODE_STRING =
|
||||
0x1c, 0x00, // (Length)
|
||||
0x1e, 0x00, // (MaximumLength)
|
||||
0x14, 0x00, 0x02, 0x00, //(Buffer ptr)
|
||||
// == Uni-dimensional Conformant-varying Array ==
|
||||
0x0f, 0x00, 0x00, 0x00, // (maximum count)
|
||||
0x00, 0x00, 0x00, 0x00, // (offset)
|
||||
0x0e, 0x00, 0x00, 0x00, // (length)
|
||||
0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
|
||||
0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x75, 0x00, 0x72, 0x00,
|
||||
|
||||
// === ClientRealm - RPC_UNICODE_STRING ===
|
||||
0x1c, 0x00, // (Length)
|
||||
0x1e, 0x00, // (MaximumLength)
|
||||
0x1c, 0x00, 0x02, 0x00, // (Buffer ptr)
|
||||
// == Uni-dimensional conformant varying array ==
|
||||
0x0f, 0x00, 0x00, 0x00, // (maximum count)
|
||||
0x00, 0x00, 0x00, 0x00, // (offset)
|
||||
0x0e, 0x00, 0x00, 0x00, // (length)
|
||||
0x48, 0x00, 0x41, 0x00, 0x52, 0x00, 0x44, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x49, 0x00,
|
||||
0x4e, 0x00, 0x47, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, // padding
|
||||
|
||||
// == SkewTime ==
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// === AuthData - KERB_ASN1_DATA ==
|
||||
0x00, 0x00, 0x00, 0x00, // (PduType)
|
||||
0x02, 0x00, 0x00, 0x00, // (Length)
|
||||
0x28, 0x00, 0x02, 0x00, // (Asn1Buffer)
|
||||
// == conformant array ==
|
||||
0x02, 0x00, 0x00, 0x00, // (nitems)
|
||||
0x30, 0x00, 0x00, 0x00, // (padding)
|
||||
|
||||
// === GssChecksum - KERB_ASN1_DATA ===
|
||||
0x08, 0x00, 0x00, 0x00, // (PduType)
|
||||
0x1b, 0x00, 0x00, 0x00, // (Length)
|
||||
0x30, 0x00, 0x02, 0x00, // (Asn1Buffer)
|
||||
// == conformant array ==
|
||||
0x1b, 0x00, 0x00, 0x00, // (length)
|
||||
0x30, 0x19, 0xa0, 0x03, 0x02, 0x01, 0x07, 0xa1, 0x12, 0x04, 0x10, 0xb9, 0x4f, 0xcd,
|
||||
0xae, 0xd9, 0xa8, 0xff, 0x49, 0x69, 0x5a, 0xd1, 0x1d, 0x38, 0x49, 0xb6, 0x92, 0x00
|
||||
};
|
||||
if (!run_payload(context, payload4, sizeof(payload4)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
{
|
||||
retCode = -6;
|
||||
size_t sizeofPayload4 = 0;
|
||||
BYTE* payload4 = parseHexBlock("03 01 03 01 \
|
||||
04 00 02 00 38 9e ef 6b 0c 00 02 00 18 00 02 00 \
|
||||
20 00 02 00 00 00 00 00 24 00 02 00 2c 00 02 00 \
|
||||
07 00 00 00 13 8a a5 a8 12 00 00 00 20 00 00 00 \
|
||||
08 00 02 00 20 00 00 00 c9 03 42 a8 17 8f d9 c4 \
|
||||
9b d2 c4 6e 73 64 98 7b 90 f5 9a 28 77 8e ca de \
|
||||
29 2e a3 8d 8a 56 36 d5 01 00 01 00 10 00 02 00 \
|
||||
01 00 00 00 1c 00 1e 00 14 00 02 00 0f 00 00 00 \
|
||||
00 00 00 00 0e 00 00 00 41 00 64 00 6d 00 69 00 \
|
||||
6e 00 69 00 73 00 74 00 72 00 61 00 74 00 65 00 \
|
||||
75 00 72 00 1c 00 1e 00 1c 00 02 00 0f 00 00 00 \
|
||||
00 00 00 00 0e 00 00 00 48 00 41 00 52 00 44 00 \
|
||||
45 00 4e 00 49 00 4e 00 47 00 33 00 2e 00 43 00 \
|
||||
4f 00 4d 00 00 00 00 00 00 00 00 00 00 00 00 00 \
|
||||
02 00 00 00 28 00 02 00 02 00 00 00 30 00 00 00 \
|
||||
08 00 00 00 1b 00 00 00 30 00 02 00 1b 00 00 00 \
|
||||
30 19 a0 03 02 01 07 a1 12 04 10 e4 aa ff 2b 93 \
|
||||
97 4c f2 5c 0b 49 85 72 92 94 54 00",
|
||||
&sizeofPayload4);
|
||||
const BOOL rc = run_payload(context, payload4, sizeofPayload4);
|
||||
free(payload4);
|
||||
if (!rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ============ successful end of test =============== */
|
||||
retCode = 0;
|
||||
out:
|
||||
ndr_context_destroy(&context);
|
||||
return retCode;
|
||||
}
|
||||
|
||||
int TestNdrEar(int argc, char* argv[])
|
||||
{
|
||||
const int rc = TestNdrEarWrite(argc, argv);
|
||||
if (rc)
|
||||
return rc;
|
||||
return TestNdrEarRead(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user