22#include <winpr/assert.h>
23#include <winpr/wtypes.h>
26#include <winpr/wlog.h>
27#include <winpr/print.h>
28#include <winpr/asn1.h>
29#include <winpr/sspi.h>
30#include <winpr/collections.h>
32#include <rdpear-common/ndr.h>
33#include <rdpear-common/rdpear_common.h>
34#include <rdpear-common/rdpear_asn1.h>
36#include <freerdp/config.h>
37#include <freerdp/freerdp.h>
38#include <freerdp/addin.h>
39#include <freerdp/client/channels.h>
40#include <freerdp/channels/log.h>
41#include <freerdp/channels/rdpear.h>
43#define TAG CHANNELS_TAG("rdpear.client")
45#ifndef MAX_KEYTAB_NAME_LEN
46#define MAX_KEYTAB_NAME_LEN 1100
50krb5_error_code encode_krb5_authenticator(
const krb5_authenticator* rep, krb5_data** code_out);
51krb5_error_code encode_krb5_ap_rep(
const krb5_ap_rep* rep, krb5_data** code_out);
57 krb5_context krbContext;
60static const BYTE payloadHeader[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
63static krb5_error_code RPC_ENCRYPTION_KEY_to_keyblock(krb5_context ctx,
65 krb5_keyblock** pkeyblock)
69 WINPR_ASSERT(pkeyblock);
71 if (!key->reserved3.length)
72 return KRB5KDC_ERR_NULL_KEY;
75 krb5_init_keyblock(ctx, (krb5_enctype)key->reserved2, key->reserved3.length, pkeyblock);
79 krb5_keyblock* keyblock = *pkeyblock;
80 memcpy(keyblock->contents, key->reserved3.value, key->reserved3.length);
85 krb5_keyusage kusage, krb5_cksumtype cksumtype,
93 krb5_keyblock* keyblock = NULL;
94 krb5_data data = { 0 };
96 krb5_error_code rv = RPC_ENCRYPTION_KEY_to_keyblock(ctx, key, &keyblock);
100 data.data = (
char*)plain->Asn1Buffer;
101 data.length = plain->Asn1BufferHints.count;
103 rv = krb5_c_make_checksum(ctx, cksumtype, keyblock, kusage, &data, out);
105 krb5_free_keyblock(ctx, keyblock);
118 krb5_keyblock* keyblock = NULL;
119 krb5_data data = { 0 };
120 krb5_enc_data enc = { 0 };
123 krb5_error_code rv = RPC_ENCRYPTION_KEY_to_keyblock(ctx, key, &keyblock);
127 data.data = (
char*)plain->Asn1Buffer;
128 data.length = plain->Asn1BufferHints.count;
130 rv = krb5_c_encrypt_length(ctx, keyblock->enctype, data.length, &elen);
133 if (!elen || (elen > UINT32_MAX))
135 rv = KRB5_PARSE_MALFORMED;
138 enc.ciphertext.length = (
unsigned int)elen;
139 enc.ciphertext.data = malloc(elen);
140 if (!enc.ciphertext.data)
146 rv = krb5_c_encrypt(ctx, keyblock, kusage, NULL, &data, &enc);
148 out->data = enc.ciphertext.data;
149 out->length = enc.ciphertext.length;
151 krb5_free_keyblock(ctx, keyblock);
156 krb5_keyusage kusage,
const krb5_data* cipher,
161 WINPR_ASSERT(cipher);
162 WINPR_ASSERT(cipher->length);
165 krb5_keyblock* keyblock = NULL;
166 krb5_data data = { 0 };
167 krb5_enc_data enc = { 0 };
169 krb5_error_code rv = RPC_ENCRYPTION_KEY_to_keyblock(ctx, key, &keyblock);
173 enc.kvno = KRB5_PVNO;
174 enc.enctype = (krb5_enctype)key->reserved2;
175 enc.ciphertext.length = cipher->length;
176 enc.ciphertext.data = cipher->data;
178 data.length = cipher->length;
179 data.data = (
char*)malloc(cipher->length);
186 rv = krb5_c_decrypt(ctx, keyblock, kusage, NULL, &enc, &data);
188 plain->Asn1Buffer = (BYTE*)data.data;
189 plain->Asn1BufferHints.count = data.length;
191 krb5_free_keyblock(ctx, keyblock);
195static BOOL rdpear_send_payload(RDPEAR_PLUGIN* rdpear, IWTSVirtualChannelCallback* pChannelCallback,
202 wStream* unencodedContent = rdpear_encodePayload(isKerb, payload);
203 if (!unencodedContent)
206 const size_t unencodedLen = Stream_GetPosition(unencodedContent);
208#if UINT32_MAX < SIZE_MAX
209 if (unencodedLen > UINT32_MAX)
213 SecBuffer inBuffer = { (ULONG)unencodedLen, SECBUFFER_DATA, Stream_Buffer(unencodedContent) };
215 if (!freerdp_nla_encrypt(rdpear->rdp_context, &inBuffer, &cryptedBuffer))
218 finalStream = Stream_New(NULL, 200);
221 Stream_Write_UINT32(finalStream, 0x4EACC3C8);
222 Stream_Write_UINT32(finalStream, cryptedBuffer.cbBuffer);
223 Stream_Write_UINT32(finalStream, 0x00000000);
224 Stream_Write_UINT32(finalStream, 0x00000000);
225 Stream_Write_UINT64(finalStream, 0);
228 if (!Stream_EnsureRemainingCapacity(finalStream, cryptedBuffer.cbBuffer))
231 Stream_Write(finalStream, cryptedBuffer.pvBuffer, cryptedBuffer.cbBuffer);
233 const size_t pos = Stream_GetPosition(finalStream);
234#if UINT32_MAX < SIZE_MAX
235 if (pos > UINT32_MAX)
240 callback->channel->Write(callback->channel, (ULONG)pos, Stream_Buffer(finalStream), NULL);
241 ret = (status == CHANNEL_RC_OK);
243 WLog_DBG(TAG,
"rdpear_send_payload=0x%x", status);
245 sspi_SecBufferFree(&cryptedBuffer);
246 Stream_Free(unencodedContent, TRUE);
247 Stream_Free(finalStream, TRUE);
251static BOOL rdpear_prepare_response(NdrContext* rcontext, BOOL isKerb, UINT16 callId, UINT32 status,
252 NdrContext** pwcontext,
wStream* retStream)
254 WINPR_ASSERT(rcontext);
255 WINPR_ASSERT(pwcontext);
259 NdrContext* wcontext = ndr_context_copy(rcontext);
263 if (!Stream_EnsureRemainingCapacity(retStream,
sizeof(payloadHeader)))
266 Stream_Write(retStream, payloadHeader,
sizeof(payloadHeader));
268 if (!ndr_write_header(wcontext, retStream) || !ndr_start_constructed(wcontext, retStream) ||
269 !ndr_write_pickle(wcontext, retStream))
276 if (!ndr_write_uint32(wcontext, retStream, v))
279 if (!ndr_write_uint16(wcontext, retStream, callId) ||
280 !ndr_write_uint16(wcontext, retStream, 0x0000) ||
281 !ndr_write_uint32(wcontext, retStream, status) ||
282 !ndr_write_uint16(wcontext, retStream, callId) ||
283 !ndr_write_uint16(wcontext, retStream, 0x0000))
286 *pwcontext = wcontext;
290 ndr_context_destroy(&wcontext);
294static BOOL rdpear_kerb_version(NdrContext* rcontext,
wStream* s, UINT32* pstatus, UINT32* pversion)
296 *pstatus = ERROR_INVALID_DATA;
298 if (!ndr_read_uint32(rcontext, s, pversion))
301 WLog_DBG(TAG,
"-> KerbNegotiateVersion(v=0x%x)", *pversion);
307static BOOL rdpear_kerb_ComputeTgsChecksum(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
wStream* s,
311 krb5_checksum checksum = { 0 };
314 *pstatus = ERROR_INVALID_DATA;
315 WLog_DBG(TAG,
"-> ComputeTgsChecksum");
317 if (!ndr_read_ComputeTgsChecksumReq(rcontext, s, NULL, &req) ||
318 !ndr_treat_deferred_read(rcontext, s))
323 kerb_do_checksum(rdpear->krbContext, req.Key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
324 (krb5_cksumtype)req.ChecksumType, req.requestBody, &checksum);
328 asn1Payload = rdpear_enc_Checksum(req.ChecksumType, &checksum);
333 resp->Asn1Buffer = Stream_Buffer(asn1Payload);
334 const size_t pos = Stream_GetPosition(asn1Payload);
335 if (pos > UINT32_MAX)
337 resp->Asn1BufferHints.count = (UINT32)pos;
341 ndr_destroy_ComputeTgsChecksumReq(rcontext, NULL, &req);
342 krb5_free_checksum_contents(rdpear->krbContext, &checksum);
343 Stream_Free(asn1Payload, FALSE);
347static BOOL rdpear_kerb_BuildEncryptedAuthData(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
351 krb5_data encrypted = { 0 };
353 krb5_error_code rv = 0;
355 *pstatus = ERROR_INVALID_DATA;
356 WLog_DBG(TAG,
"-> BuildEncryptedAuthData");
358 if (!ndr_read_BuildEncryptedAuthDataReq(rcontext, s, NULL, &req) ||
359 !ndr_treat_deferred_read(rcontext, s))
362 rv = kerb_do_encrypt(rdpear->krbContext, req.Key, (krb5_keyusage)req.KeyUsage,
363 req.PlainAuthData, &encrypted);
368 asn1Payload = rdpear_enc_EncryptedData(req.Key->reserved2, &encrypted);
375 asn1->Asn1Buffer = Stream_Buffer(asn1Payload);
376 const size_t pos = Stream_GetPosition(asn1Payload);
377 if (pos > UINT32_MAX)
379 asn1->Asn1BufferHints.count = (UINT32)pos;
383 krb5_free_data_contents(rdpear->krbContext, &encrypted);
384 ndr_destroy_BuildEncryptedAuthDataReq(rcontext, NULL, &req);
385 Stream_Free(asn1Payload, FALSE);
392 return ConvertWCharNToUtf8Alloc(src->Buffer, src->strLength, NULL);
395static BOOL extractAuthData(
const KERB_ASN1_DATA* src, krb5_authdata* authData, BOOL* haveData)
400 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
402 WinPrAsn1_INTEGER adType = 0;
406 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
409 wStream subStream = WinPrAsn1DecGetStream(&dec2);
410 if (!Stream_GetRemainingLength(&subStream))
413 if (!WinPrAsn1DecReadSequence(&dec2, &dec3))
416 if (!WinPrAsn1DecReadContextualInteger(&dec3, 0, &error, &adType) ||
417 !WinPrAsn1DecReadContextualOctetString(&dec3, 1, &error, &os, FALSE))
420 if (os.len > UINT32_MAX)
423 authData->ad_type = adType;
424 authData->length = (
unsigned int)os.len;
425 authData->contents = os.data;
430static BOOL extractChecksum(
const KERB_ASN1_DATA* src, krb5_checksum* dst)
434 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
438 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
441 WinPrAsn1_INTEGER cksumtype = 0;
442 if (!WinPrAsn1DecReadContextualInteger(&dec2, 0, &error, &cksumtype) ||
443 !WinPrAsn1DecReadContextualOctetString(&dec2, 1, &error, &os, FALSE))
446 if (os.len > UINT32_MAX)
448 dst->checksum_type = cksumtype;
449 dst->length = (
unsigned int)os.len;
450 dst->contents = os.data;
454#define FILETIME_TO_UNIX_OFFSET_S 11644473600LL
456static LONGLONG krb5_time_to_FILETIME(
const krb5_timestamp* ts, krb5_int32 usec)
459 return (((*ts + FILETIME_TO_UNIX_OFFSET_S) * (1000LL * 1000LL) + usec) * 10LL);
462static void krb5_free_principal_contents(krb5_context ctx, krb5_principal principal)
464 WINPR_ASSERT(principal);
465 krb5_free_data_contents(ctx, &principal->realm);
466 krb5_free_data(ctx, principal->data);
469static BOOL rdpear_kerb_CreateApReqAuthenticator(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
473 krb5_error_code rv = 0;
474 wStream* asn1EncodedAuth = NULL;
476 krb5_data authenticator = { 0 };
477 krb5_data* der = NULL;
478 krb5_keyblock* subkey = NULL;
479 krb5_principal_data client = { 0 };
481 *pstatus = ERROR_INVALID_DATA;
482 WLog_DBG(TAG,
"-> CreateApReqAuthenticator");
484 if (!ndr_read_CreateApReqAuthenticatorReq(rcontext, s, NULL, &req) ||
485 !ndr_treat_deferred_read(rcontext, s))
488 krb5_authdata authdata = { 0 };
489 krb5_authdata* authDataPtr[2] = { &authdata, NULL };
492 if (!extractAuthData(req.AuthData, &authdata, &haveData))
494 WLog_ERR(TAG,
"error retrieving auth data");
495 winpr_HexDump(TAG, WLOG_DEBUG, req.AuthData->Asn1Buffer,
496 req.AuthData->Asn1BufferHints.count);
500 if (req.SkewTime->QuadPart)
502 WLog_ERR(TAG,
"!!!!! should handle SkewTime !!!!!");
507 rv = RPC_ENCRYPTION_KEY_to_keyblock(rdpear->krbContext, req.SubKey, &subkey);
510 WLog_ERR(TAG,
"error importing subkey");
515 krb5_authenticator authent = { .checksum = NULL,
517 .seq_number = req.SequenceNumber,
518 .authorization_data = haveData ? authDataPtr : NULL };
520 client.type = req.ClientName->NameType;
521 if (req.ClientName->nameHints.count > INT32_MAX)
524 client.length = (krb5_int32)req.ClientName->nameHints.count;
525 client.data = calloc(req.ClientName->nameHints.count,
sizeof(krb5_data));
529 for (
int i = 0; i < client.length; i++)
531 krb5_data* cur = &client.data[i];
532 cur->data = KERB_RPC_UNICODESTR_to_charptr(&req.ClientName->Names[i]);
535 const size_t len = strnlen(cur->data, MAX_KEYTAB_NAME_LEN + 1);
536 if (len > MAX_KEYTAB_NAME_LEN)
539 "Invalid ClientName length %" PRIuz
540 ", limited to %u characters. ClientName: (%s)",
541 MAX_KEYTAB_NAME_LEN, len, cur->data);
544 cur->length = (
unsigned int)len;
546 client.realm.data = KERB_RPC_UNICODESTR_to_charptr(req.ClientRealm);
547 if (!client.realm.data)
550 const size_t len = strnlen(client.realm.data, MAX_KEYTAB_NAME_LEN + 1);
551 if (len > MAX_KEYTAB_NAME_LEN)
553 WLog_ERR(TAG,
"Invalid realm length %" PRIuz
", limited to %u characters. Realm: (%s)",
554 MAX_KEYTAB_NAME_LEN, len, client.realm.data);
557 client.realm.length = (
unsigned int)len;
558 authent.client = &client;
560 krb5_checksum checksum;
561 krb5_checksum* pchecksum = NULL;
564 if (!extractChecksum(req.GssChecksum, &checksum))
566 WLog_ERR(TAG,
"Error getting the checksum");
569 pchecksum = &checksum;
571 authent.checksum = pchecksum;
573 krb5_us_timeofday(rdpear->krbContext, &authent.ctime, &authent.cusec);
575 rv = encode_krb5_authenticator(&authent, &der);
578 WLog_ERR(TAG,
"error encoding authenticator");
583 .Asn1Buffer = (BYTE*)der->data,
584 .Asn1BufferHints = { .count = der->length } };
586 rv = kerb_do_encrypt(rdpear->krbContext, req.EncryptionKey, (krb5_keyusage)req.KeyUsage,
587 &plain_authent, &authenticator);
590 WLog_ERR(TAG,
"error encrypting authenticator");
594 asn1EncodedAuth = rdpear_enc_EncryptedData(req.EncryptionKey->reserved2, &authenticator);
595 if (!asn1EncodedAuth)
597 WLog_ERR(TAG,
"error encoding to ASN1");
606 const size_t size = Stream_GetPosition(asn1EncodedAuth);
607 if (size > UINT32_MAX)
609 resp->Authenticator.Asn1BufferHints.count = (UINT32)size;
610 resp->Authenticator.Asn1Buffer = Stream_Buffer(asn1EncodedAuth);
611 resp->AuthenticatorTime.QuadPart = krb5_time_to_FILETIME(&authent.ctime, authent.cusec);
615 resp->Authenticator.Pdu = 6;
616 resp->KerbProtocolError = rv;
617 krb5_free_principal_contents(rdpear->krbContext, &client);
618 krb5_free_data(rdpear->krbContext, der);
619 krb5_free_data_contents(rdpear->krbContext, &authenticator);
621 krb5_free_keyblock(rdpear->krbContext, subkey);
622 ndr_destroy_CreateApReqAuthenticatorReq(rcontext, NULL, &req);
623 Stream_Free(asn1EncodedAuth, FALSE);
627static BOOL rdpear_findEncryptedData(
const KERB_ASN1_DATA* src,
int* penctype, krb5_data* data)
631 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
633 WinPrAsn1_INTEGER encType = 0;
636 if (!WinPrAsn1DecReadSequence(&dec, &dec2) ||
637 !WinPrAsn1DecReadContextualInteger(&dec2, 0, &error, &encType) ||
638 !WinPrAsn1DecReadContextualOctetString(&dec2, 2, &error, &os, FALSE))
641 if (os.len > UINT32_MAX)
643 data->data = (
char*)os.data;
644 data->length = (
unsigned int)os.len;
649static BOOL rdpear_kerb_UnpackKdcReplyBody(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
wStream* s,
654 *pstatus = ERROR_INVALID_DATA;
656 if (!ndr_read_UnpackKdcReplyBodyReq(rcontext, s, NULL, &req) ||
657 !ndr_treat_deferred_read(rcontext, s))
660 if (req.StrengthenKey)
662 WLog_ERR(TAG,
"StrengthenKey not supported yet");
666 WLog_DBG(TAG,
"-> UnpackKdcReplyBody: KeyUsage=0x%x PDU=0x%x", req.KeyUsage, req.Pdu);
671 krb5_data asn1Data = { 0 };
673 if (!rdpear_findEncryptedData(req.EncryptedData, &encType, &asn1Data) || !asn1Data.length)
676 resp->KerbProtocolError = kerb_do_decrypt(
677 rdpear->krbContext, req.Key, (krb5_keyusage)req.KeyUsage, &asn1Data, &resp->ReplyBody);
678 resp->ReplyBody.Pdu = req.Pdu;
683 ndr_destroy_UnpackKdcReplyBodyReq(rcontext, NULL, &req);
687static BOOL rdpear_kerb_DecryptApReply(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
wStream* s,
692 *pstatus = ERROR_INVALID_DATA;
693 if (!ndr_read_DecryptApReplyReq(rcontext, s, NULL, &req) ||
694 !ndr_treat_deferred_read(rcontext, s))
697 WLog_DBG(TAG,
"-> DecryptApReply");
701 krb5_data asn1Data = { 0 };
703 if (!rdpear_findEncryptedData(req.EncryptedReply, &encType, &asn1Data) || !asn1Data.length)
708 kerb_do_decrypt(rdpear->krbContext, req.Key, KRB5_KEYUSAGE_AP_REP_ENCPART, &asn1Data, resp);
711 WLog_ERR(TAG,
"error decrypting");
719 ndr_destroy_DecryptApReplyReq(rcontext, NULL, &req);
723static BOOL rdpear_kerb_PackApReply(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
wStream* s,
727 krb5_data asn1Data = { 0 };
728 krb5_data* out = NULL;
730 WLog_DBG(TAG,
"-> PackApReply");
731 *pstatus = ERROR_INVALID_DATA;
732 if (!ndr_read_PackApReplyReq(rcontext, s, NULL, &req) || !ndr_treat_deferred_read(rcontext, s))
735 krb5_error_code rv = kerb_do_encrypt(rdpear->krbContext, req.SessionKey,
736 KRB5_KEYUSAGE_AP_REP_ENCPART, req.ReplyBody, &asn1Data);
741 reply.enc_part.kvno = KRB5_PVNO;
742 reply.enc_part.enctype = (krb5_enctype)req.SessionKey->reserved2;
743 reply.enc_part.ciphertext.length = asn1Data.length;
744 reply.enc_part.ciphertext.data = asn1Data.data;
746 rv = encode_krb5_ap_rep(&reply, &out);
750 resp->PackedReply = (BYTE*)out->data;
751 resp->PackedReplyHints.count = out->length;
755 krb5_free_data_contents(rdpear->krbContext, &asn1Data);
756 ndr_destroy_PackApReplyReq(rcontext, NULL, &req);
760static BOOL rdpear_ntlm_version(NdrContext* rcontext,
wStream* s, UINT32* pstatus, UINT32* pversion)
762 *pstatus = ERROR_INVALID_DATA;
764 if (!ndr_read_uint32(rcontext, s, pversion))
767 WLog_DBG(TAG,
"-> NtlmNegotiateVersion(v=0x%x)", *pversion);
773static UINT rdpear_decode_payload(RDPEAR_PLUGIN* rdpear,
774 IWTSVirtualChannelCallback* pChannelCallback,
777 UINT ret = ERROR_INVALID_DATA;
778 NdrContext* context = NULL;
779 NdrContext* wcontext = NULL;
782 UINT32 uint32Resp = 0;
790 wStream* respStream = Stream_New(NULL, 500);
795 switch (rdpear_packageType_from_name(packageName))
797 case RDPEAR_PACKAGE_KERBEROS:
800 case RDPEAR_PACKAGE_NTLM:
804 WLog_ERR(TAG,
"unknown package type");
813 context = ndr_read_header(s);
814 if (!context || !ndr_read_constructed(context, s, &commandStream) ||
815 !ndr_read_pickle(context, &commandStream))
823 if (!ndr_read_uint32(context, &commandStream, &v))
827 if (!ndr_read_uint16(context, &commandStream, &callId) ||
828 !ndr_read_uint16(context, &commandStream, &callId2) || (callId != callId2))
831 ret = CHANNEL_RC_NOT_OPEN;
834 case RemoteCallKerbNegotiateVersion:
836 respDescr = ndr_uint32_descr();
838 if (rdpear_kerb_version(context, &commandStream, &status, &uint32Resp))
841 case RemoteCallKerbCreateApReqAuthenticator:
842 resp = &createApReqAuthenticatorResp;
843 respDescr = ndr_CreateApReqAuthenticatorResp_descr();
845 if (rdpear_kerb_CreateApReqAuthenticator(rdpear, context, &commandStream, &status,
846 &createApReqAuthenticatorResp))
849 case RemoteCallKerbDecryptApReply:
851 respDescr = ndr_KERB_ASN1_DATA_descr();
853 if (rdpear_kerb_DecryptApReply(rdpear, context, &commandStream, &status, &asn1Data))
856 case RemoteCallKerbComputeTgsChecksum:
858 respDescr = ndr_KERB_ASN1_DATA_descr();
860 if (rdpear_kerb_ComputeTgsChecksum(rdpear, context, &commandStream, &status, &asn1Data))
863 case RemoteCallKerbBuildEncryptedAuthData:
865 respDescr = ndr_KERB_ASN1_DATA_descr();
867 if (rdpear_kerb_BuildEncryptedAuthData(rdpear, context, &commandStream, &status,
871 case RemoteCallKerbUnpackKdcReplyBody:
872 resp = &unpackKdcReplyBodyResp;
873 respDescr = ndr_UnpackKdcReplyBodyResp_descr();
875 if (rdpear_kerb_UnpackKdcReplyBody(rdpear, context, &commandStream, &status,
876 &unpackKdcReplyBodyResp))
879 case RemoteCallKerbPackApReply:
880 resp = &packApReplyResp;
881 respDescr = ndr_PackApReplyResp_descr();
883 if (rdpear_kerb_PackApReply(rdpear, context, &commandStream, &status, &packApReplyResp))
886 case RemoteCallNtlmNegotiateVersion:
888 respDescr = ndr_uint32_descr();
890 if (rdpear_ntlm_version(context, &commandStream, &status, &uint32Resp))
895 WLog_DBG(TAG,
"Unhandled callId=0x%x", callId);
896 winpr_HexDump(TAG, WLOG_DEBUG, Stream_PointerAs(&commandStream, BYTE),
897 Stream_GetRemainingLength(&commandStream));
901 if (!rdpear_prepare_response(context, isKerb, callId, status, &wcontext, respStream))
904 if (resp && respDescr)
906 WINPR_ASSERT(respDescr->writeFn);
908 BOOL r = respDescr->writeFn(wcontext, respStream, NULL, resp) &&
909 ndr_treat_deferred_write(wcontext, respStream);
911 if (respDescr->destroyFn)
912 respDescr->destroyFn(wcontext, NULL, resp);
916 WLog_DBG(TAG,
"!writeFn || !ndr_treat_deferred_write");
921 if (!ndr_end_constructed(wcontext, respStream) ||
922 !rdpear_send_payload(rdpear, pChannelCallback, isKerb, respStream))
924 WLog_DBG(TAG,
"rdpear_send_payload !!!!!!!!");
929 ndr_context_destroy(&context);
932 ndr_context_destroy(&wcontext);
935 Stream_Free(respStream, TRUE);
939static UINT rdpear_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* s)
942 WINPR_ASSERT(callback);
943 UINT ret = ERROR_INVALID_DATA;
947 if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
948 return ERROR_INVALID_DATA;
950 UINT32 protocolMagic = 0;
953 Stream_Read_UINT32(s, protocolMagic);
954 if (protocolMagic != 0x4EACC3C8)
955 return ERROR_INVALID_DATA;
957 Stream_Read_UINT32(s, Length);
959 Stream_Read_UINT32(s, Version);
960 if (Version != 0x00000000)
961 return ERROR_INVALID_DATA;
966 if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
967 return ERROR_INVALID_DATA;
969 SecBuffer inBuffer = { Length, SECBUFFER_TOKEN, Stream_PointerAs(s,
void) };
972 RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)callback->plugin;
973 WINPR_ASSERT(rdpear);
974 if (!freerdp_nla_decrypt(rdpear->rdp_context, &inBuffer, &decrypted))
980 Stream_StaticInit(&decodedStream, decrypted.pvBuffer, decrypted.cbBuffer);
981 WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, &decodedStream);
983 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
989 if (!WinPrAsn1DecReadContextualOctetString(&dec2, 1, &error, &packageName, FALSE))
992 if (!WinPrAsn1DecReadContextualOctetString(&dec2, 2, &error, &payload, FALSE))
996 Stream_StaticInit(&payloadStream, payload.data, payload.len);
998 ret = rdpear_decode_payload(rdpear, pChannelCallback, &packageName, &payloadStream);
1000 sspi_SecBufferFree(&decrypted);
1009static UINT rdpear_on_open(IWTSVirtualChannelCallback* pChannelCallback)
1011 WINPR_UNUSED(pChannelCallback);
1012 return CHANNEL_RC_OK;
1020static UINT rdpear_on_close(IWTSVirtualChannelCallback* pChannelCallback)
1022 WINPR_UNUSED(pChannelCallback);
1023 return CHANNEL_RC_OK;
1030 RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)base;
1031 krb5_free_context(rdpear->krbContext);
1034static UINT init_plugin_cb(
GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
1037 WINPR_UNUSED(settings);
1039 RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)base;
1040 rdpear->rdp_context = rcontext;
1041 if (krb5_init_context(&rdpear->krbContext))
1042 return CHANNEL_RC_INITIALIZATION_ERROR;
1043 return CHANNEL_RC_OK;
1046static const IWTSVirtualChannelCallback rdpear_callbacks = { rdpear_on_data_received,
1047 rdpear_on_open, rdpear_on_close,
1055FREERDP_ENTRY_POINT(UINT rdpear_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1057 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPEAR_DVC_CHANNEL_NAME,
1059 &rdpear_callbacks, init_plugin_cb, terminate_plugin_cb);
2.2.2.1.8 BuildEncryptedAuthData
2.2.2.1.7 ComputeTgsChecksum
2.2.2.1.4 CreateApReqAuthenticator
2.2.2.1.4 CreateApReqAuthenticator
2.2.1.2.8 KERB_RPC_ENCRYPTION_KEY
2.3.10 RPC_UNICODE_STRING (MS-DTYP)
2.2.2.1.6 UnpackKdcReplyBody
2.2.2.1.6 UnpackKdcReplyBody