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,
 
  196                                RdpEarPackageType packageType, 
wStream* payload)
 
  202  wStream* unencodedContent = rdpear_encodePayload(packageType, 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, 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) ||         
 
  270      !ndr_write_uint16(wcontext, retStream, callId) || 
 
  271      !ndr_write_uint16(wcontext, retStream, 0x0000) || 
 
  272      !ndr_write_uint32(wcontext, retStream, status) || 
 
  273      !ndr_write_uint16(wcontext, retStream, callId) || 
 
  274      !ndr_write_uint16(wcontext, retStream, 0x0000))   
 
  277  *pwcontext = wcontext;
 
  281    ndr_context_destroy(&wcontext);
 
  285static BOOL rdpear_kerb_version(NdrContext* rcontext, 
wStream* s, UINT32* pstatus, UINT32* pversion)
 
  287  *pstatus = ERROR_INVALID_DATA;
 
  289  if (!ndr_read_uint32(rcontext, s, pversion))
 
  292  WLog_DBG(TAG, 
"-> KerbNegotiateVersion(v=0x%x)", *pversion);
 
  298static BOOL rdpear_kerb_ComputeTgsChecksum(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext, 
wStream* s,
 
  302  krb5_checksum checksum = { 0 };
 
  305  *pstatus = ERROR_INVALID_DATA;
 
  306  WLog_DBG(TAG, 
"-> ComputeTgsChecksum");
 
  308  if (!ndr_read_ComputeTgsChecksumReq(rcontext, s, NULL, &req) ||
 
  309      !ndr_treat_deferred_read(rcontext, s))
 
  314      kerb_do_checksum(rdpear->krbContext, req.Key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
 
  315                       (krb5_cksumtype)req.ChecksumType, req.requestBody, &checksum);
 
  319  asn1Payload = rdpear_enc_Checksum(req.ChecksumType, &checksum);
 
  324  resp->Asn1Buffer = Stream_Buffer(asn1Payload);
 
  325  const size_t pos = Stream_GetPosition(asn1Payload);
 
  326  if (pos > UINT32_MAX)
 
  328  resp->Asn1BufferHints.count = (UINT32)pos;
 
  332  ndr_destroy_ComputeTgsChecksumReq(rcontext, NULL, &req);
 
  333  krb5_free_checksum_contents(rdpear->krbContext, &checksum);
 
  334  Stream_Free(asn1Payload, FALSE);
 
  338static BOOL rdpear_kerb_BuildEncryptedAuthData(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
 
  342  krb5_data encrypted = { 0 };
 
  344  krb5_error_code rv = 0;
 
  346  *pstatus = ERROR_INVALID_DATA;
 
  347  WLog_DBG(TAG, 
"-> BuildEncryptedAuthData");
 
  349  if (!ndr_read_BuildEncryptedAuthDataReq(rcontext, s, NULL, &req) ||
 
  350      !ndr_treat_deferred_read(rcontext, s))
 
  353  rv = kerb_do_encrypt(rdpear->krbContext, req.Key, (krb5_keyusage)req.KeyUsage,
 
  354                       req.PlainAuthData, &encrypted);
 
  359  asn1Payload = rdpear_enc_EncryptedData(req.Key->reserved2, &encrypted);
 
  366  asn1->Asn1Buffer = Stream_Buffer(asn1Payload);
 
  367  const size_t pos = Stream_GetPosition(asn1Payload);
 
  368  if (pos > UINT32_MAX)
 
  370  asn1->Asn1BufferHints.count = (UINT32)pos;
 
  374  krb5_free_data_contents(rdpear->krbContext, &encrypted);
 
  375  ndr_destroy_BuildEncryptedAuthDataReq(rcontext, NULL, &req);
 
  376  Stream_Free(asn1Payload, FALSE);
 
  383  return ConvertWCharNToUtf8Alloc(src->Buffer, src->strLength, NULL);
 
  386static BOOL extractAuthData(
const KERB_ASN1_DATA* src, krb5_authdata* authData, BOOL* haveData)
 
  391  WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
 
  393  WinPrAsn1_INTEGER adType = 0;
 
  397  if (!WinPrAsn1DecReadSequence(&dec, &dec2))
 
  400  wStream subStream = WinPrAsn1DecGetStream(&dec2);
 
  401  if (!Stream_GetRemainingLength(&subStream))
 
  404  if (!WinPrAsn1DecReadSequence(&dec2, &dec3))
 
  407  if (!WinPrAsn1DecReadContextualInteger(&dec3, 0, &error, &adType) ||
 
  408      !WinPrAsn1DecReadContextualOctetString(&dec3, 1, &error, &os, FALSE))
 
  411  if (os.len > UINT32_MAX)
 
  414  authData->ad_type = adType;
 
  415  authData->length = (
unsigned int)os.len;
 
  416  authData->contents = os.data;
 
  421static BOOL extractChecksum(
const KERB_ASN1_DATA* src, krb5_checksum* dst)
 
  425  WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
 
  429  if (!WinPrAsn1DecReadSequence(&dec, &dec2))
 
  432  WinPrAsn1_INTEGER cksumtype = 0;
 
  433  if (!WinPrAsn1DecReadContextualInteger(&dec2, 0, &error, &cksumtype) ||
 
  434      !WinPrAsn1DecReadContextualOctetString(&dec2, 1, &error, &os, FALSE))
 
  437  if (os.len > UINT32_MAX)
 
  439  dst->checksum_type = cksumtype;
 
  440  dst->length = (
unsigned int)os.len;
 
  441  dst->contents = os.data;
 
  445#define FILETIME_TO_UNIX_OFFSET_S 11644473600LL 
  447static LONGLONG krb5_time_to_FILETIME(
const krb5_timestamp* ts, krb5_int32 usec)
 
  450  return (((*ts + FILETIME_TO_UNIX_OFFSET_S) * (1000LL * 1000LL) + usec) * 10LL);
 
  453static void krb5_free_principal_contents(krb5_context ctx, krb5_principal principal)
 
  455  WINPR_ASSERT(principal);
 
  456  krb5_free_data_contents(ctx, &principal->realm);
 
  457  krb5_free_data(ctx, principal->data);
 
  460static BOOL rdpear_kerb_CreateApReqAuthenticator(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext,
 
  464  krb5_error_code rv = 0;
 
  465  wStream* asn1EncodedAuth = NULL;
 
  467  krb5_data authenticator = { 0 };
 
  468  krb5_data* der = NULL;
 
  469  krb5_keyblock* subkey = NULL;
 
  470  krb5_principal_data client = { 0 };
 
  472  *pstatus = ERROR_INVALID_DATA;
 
  473  WLog_DBG(TAG, 
"-> CreateApReqAuthenticator");
 
  475  if (!ndr_read_CreateApReqAuthenticatorReq(rcontext, s, NULL, &req) ||
 
  476      !ndr_treat_deferred_read(rcontext, s))
 
  479  krb5_authdata authdata = { 0 };
 
  480  krb5_authdata* authDataPtr[2] = { &authdata, NULL };
 
  483  if (!extractAuthData(req.AuthData, &authdata, &haveData))
 
  485    WLog_ERR(TAG, 
"error retrieving auth data");
 
  486    winpr_HexDump(TAG, WLOG_DEBUG, req.AuthData->Asn1Buffer,
 
  487                  req.AuthData->Asn1BufferHints.count);
 
  491  if (req.SkewTime->QuadPart)
 
  493    WLog_ERR(TAG, 
"!!!!! should handle SkewTime !!!!!");
 
  498    rv = RPC_ENCRYPTION_KEY_to_keyblock(rdpear->krbContext, req.SubKey, &subkey);
 
  501      WLog_ERR(TAG, 
"error importing subkey");
 
  506  krb5_authenticator authent = { .checksum = NULL,
 
  508                               .seq_number = req.SequenceNumber,
 
  509                               .authorization_data = haveData ? authDataPtr : NULL };
 
  511  client.type = req.ClientName->NameType;
 
  512  if (req.ClientName->nameHints.count > INT32_MAX)
 
  515  client.length = (krb5_int32)req.ClientName->nameHints.count;
 
  516  client.data = calloc(req.ClientName->nameHints.count, 
sizeof(krb5_data));
 
  520  for (
int i = 0; i < client.length; i++)
 
  522    krb5_data* cur = &client.data[i];
 
  523    cur->data = KERB_RPC_UNICODESTR_to_charptr(&req.ClientName->Names[i]);
 
  526    const size_t len = strnlen(cur->data, MAX_KEYTAB_NAME_LEN + 1);
 
  527    if (len > MAX_KEYTAB_NAME_LEN)
 
  530               "Invalid ClientName length %" PRIuz
 
  531               ", limited to %u characters. ClientName: (%s)",
 
  532               MAX_KEYTAB_NAME_LEN, len, cur->data);
 
  535    cur->length = (
unsigned int)len;
 
  537  client.realm.data = KERB_RPC_UNICODESTR_to_charptr(req.ClientRealm);
 
  538  if (!client.realm.data)
 
  541  const size_t len = strnlen(client.realm.data, MAX_KEYTAB_NAME_LEN + 1);
 
  542  if (len > MAX_KEYTAB_NAME_LEN)
 
  544    WLog_ERR(TAG, 
"Invalid realm length %" PRIuz 
", limited to %u characters. Realm: (%s)",
 
  545             MAX_KEYTAB_NAME_LEN, len, client.realm.data);
 
  548  client.realm.length = (
unsigned int)len;
 
  549  authent.client = &client;
 
  551  krb5_checksum checksum;
 
  552  krb5_checksum* pchecksum = NULL;
 
  555    if (!extractChecksum(req.GssChecksum, &checksum))
 
  557      WLog_ERR(TAG, 
"Error getting the checksum");
 
  560    pchecksum = &checksum;
 
  562  authent.checksum = pchecksum;
 
  564  krb5_us_timeofday(rdpear->krbContext, &authent.ctime, &authent.cusec);
 
  566  rv = encode_krb5_authenticator(&authent, &der);
 
  569    WLog_ERR(TAG, 
"error encoding authenticator");
 
  574                                 .Asn1Buffer = (BYTE*)der->data,
 
  575                                 .Asn1BufferHints = { .count = der->length } };
 
  577  rv = kerb_do_encrypt(rdpear->krbContext, req.EncryptionKey, (krb5_keyusage)req.KeyUsage,
 
  578                       &plain_authent, &authenticator);
 
  581    WLog_ERR(TAG, 
"error encrypting authenticator");
 
  585  asn1EncodedAuth = rdpear_enc_EncryptedData(req.EncryptionKey->reserved2, &authenticator);
 
  586  if (!asn1EncodedAuth)
 
  588    WLog_ERR(TAG, 
"error encoding to ASN1");
 
  597  const size_t size = Stream_GetPosition(asn1EncodedAuth);
 
  598  if (size > UINT32_MAX)
 
  600  resp->Authenticator.Asn1BufferHints.count = (UINT32)size;
 
  601  resp->Authenticator.Asn1Buffer = Stream_Buffer(asn1EncodedAuth);
 
  602  resp->AuthenticatorTime.QuadPart = krb5_time_to_FILETIME(&authent.ctime, authent.cusec);
 
  606  resp->Authenticator.Pdu = 6;
 
  607  resp->KerbProtocolError = rv;
 
  608  krb5_free_principal_contents(rdpear->krbContext, &client);
 
  609  krb5_free_data(rdpear->krbContext, der);
 
  610  krb5_free_data_contents(rdpear->krbContext, &authenticator);
 
  612    krb5_free_keyblock(rdpear->krbContext, subkey);
 
  613  ndr_destroy_CreateApReqAuthenticatorReq(rcontext, NULL, &req);
 
  614  Stream_Free(asn1EncodedAuth, FALSE);
 
  618static BOOL rdpear_findEncryptedData(
const KERB_ASN1_DATA* src, 
int* penctype, krb5_data* data)
 
  622  WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, src->Asn1Buffer, src->Asn1BufferHints.count);
 
  624  WinPrAsn1_INTEGER encType = 0;
 
  627  if (!WinPrAsn1DecReadSequence(&dec, &dec2) ||
 
  628      !WinPrAsn1DecReadContextualInteger(&dec2, 0, &error, &encType) ||
 
  629      !WinPrAsn1DecReadContextualOctetString(&dec2, 2, &error, &os, FALSE))
 
  632  if (os.len > UINT32_MAX)
 
  634  data->data = (
char*)os.data;
 
  635  data->length = (
unsigned int)os.len;
 
  640static BOOL rdpear_kerb_UnpackKdcReplyBody(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext, 
wStream* s,
 
  645  *pstatus = ERROR_INVALID_DATA;
 
  647  if (!ndr_read_UnpackKdcReplyBodyReq(rcontext, s, NULL, &req) ||
 
  648      !ndr_treat_deferred_read(rcontext, s))
 
  651  if (req.StrengthenKey)
 
  653    WLog_ERR(TAG, 
"StrengthenKey not supported yet");
 
  657  WLog_DBG(TAG, 
"-> UnpackKdcReplyBody: KeyUsage=0x%x PDU=0x%x", req.KeyUsage, req.Pdu);
 
  662  krb5_data asn1Data = { 0 };
 
  664  if (!rdpear_findEncryptedData(req.EncryptedData, &encType, &asn1Data) || !asn1Data.length)
 
  667  resp->KerbProtocolError = kerb_do_decrypt(
 
  668      rdpear->krbContext, req.Key, (krb5_keyusage)req.KeyUsage, &asn1Data, &resp->ReplyBody);
 
  669  resp->ReplyBody.Pdu = req.Pdu;
 
  674  ndr_destroy_UnpackKdcReplyBodyReq(rcontext, NULL, &req);
 
  678static BOOL rdpear_kerb_DecryptApReply(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext, 
wStream* s,
 
  683  *pstatus = ERROR_INVALID_DATA;
 
  684  if (!ndr_read_DecryptApReplyReq(rcontext, s, NULL, &req) ||
 
  685      !ndr_treat_deferred_read(rcontext, s))
 
  688  WLog_DBG(TAG, 
"-> DecryptApReply");
 
  692  krb5_data asn1Data = { 0 };
 
  694  if (!rdpear_findEncryptedData(req.EncryptedReply, &encType, &asn1Data) || !asn1Data.length)
 
  699      kerb_do_decrypt(rdpear->krbContext, req.Key, KRB5_KEYUSAGE_AP_REP_ENCPART, &asn1Data, resp);
 
  702    WLog_ERR(TAG, 
"error decrypting");
 
  710  ndr_destroy_DecryptApReplyReq(rcontext, NULL, &req);
 
  714static BOOL rdpear_kerb_PackApReply(RDPEAR_PLUGIN* rdpear, NdrContext* rcontext, 
wStream* s,
 
  718  krb5_data asn1Data = { 0 };
 
  719  krb5_data* out = NULL;
 
  721  WLog_DBG(TAG, 
"-> PackApReply");
 
  722  *pstatus = ERROR_INVALID_DATA;
 
  723  if (!ndr_read_PackApReplyReq(rcontext, s, NULL, &req) || !ndr_treat_deferred_read(rcontext, s))
 
  726  krb5_error_code rv = kerb_do_encrypt(rdpear->krbContext, req.SessionKey,
 
  727                                       KRB5_KEYUSAGE_AP_REP_ENCPART, req.ReplyBody, &asn1Data);
 
  732  reply.enc_part.kvno = KRB5_PVNO;
 
  733  reply.enc_part.enctype = (krb5_enctype)req.SessionKey->reserved2;
 
  734  reply.enc_part.ciphertext.length = asn1Data.length;
 
  735  reply.enc_part.ciphertext.data = asn1Data.data;
 
  737  rv = encode_krb5_ap_rep(&reply, &out);
 
  741  resp->PackedReply = (BYTE*)out->data;
 
  742  resp->PackedReplyHints.count = out->length;
 
  746  krb5_free_data_contents(rdpear->krbContext, &asn1Data);
 
  747  ndr_destroy_PackApReplyReq(rcontext, NULL, &req);
 
  751static UINT rdpear_decode_payload(RDPEAR_PLUGIN* rdpear,
 
  752                                  IWTSVirtualChannelCallback* pChannelCallback, 
wStream* s)
 
  754  UINT ret = ERROR_INVALID_DATA;
 
  755  NdrContext* context = NULL;
 
  756  NdrContext* wcontext = NULL;
 
  759  UINT32 uint32Resp = 0;
 
  768  wStream* respStream = Stream_New(NULL, 500);
 
  778  context = ndr_read_header(s);
 
  779  if (!context || !ndr_read_constructed(context, s, &commandStream) ||
 
  780      !ndr_read_pickle(context, &commandStream) ||
 
  781      !ndr_read_uint16(context, &commandStream, &callId) ||
 
  782      !ndr_read_uint16(context, &commandStream, &callId2) || (callId != callId2))
 
  785  ret = CHANNEL_RC_NOT_OPEN;
 
  788    case RemoteCallKerbNegotiateVersion:
 
  790      respDescr = ndr_uint32_descr();
 
  792      if (rdpear_kerb_version(context, &commandStream, &status, &uint32Resp))
 
  795    case RemoteCallKerbCreateApReqAuthenticator:
 
  796      resp = &createApReqAuthenticatorResp;
 
  797      respDescr = ndr_CreateApReqAuthenticatorResp_descr();
 
  799      if (rdpear_kerb_CreateApReqAuthenticator(rdpear, context, &commandStream, &status,
 
  800                                               &createApReqAuthenticatorResp))
 
  803    case RemoteCallKerbDecryptApReply:
 
  805      respDescr = ndr_KERB_ASN1_DATA_descr();
 
  807      if (rdpear_kerb_DecryptApReply(rdpear, context, &commandStream, &status, &asn1Data))
 
  810    case RemoteCallKerbComputeTgsChecksum:
 
  812      respDescr = ndr_KERB_ASN1_DATA_descr();
 
  814      if (rdpear_kerb_ComputeTgsChecksum(rdpear, context, &commandStream, &status, &asn1Data))
 
  817    case RemoteCallKerbBuildEncryptedAuthData:
 
  819      respDescr = ndr_KERB_ASN1_DATA_descr();
 
  821      if (rdpear_kerb_BuildEncryptedAuthData(rdpear, context, &commandStream, &status,
 
  825    case RemoteCallKerbUnpackKdcReplyBody:
 
  826      resp = &unpackKdcReplyBodyResp;
 
  827      respDescr = ndr_UnpackKdcReplyBodyResp_descr();
 
  829      if (rdpear_kerb_UnpackKdcReplyBody(rdpear, context, &commandStream, &status,
 
  830                                         &unpackKdcReplyBodyResp))
 
  833    case RemoteCallKerbPackApReply:
 
  834      resp = &packApReplyResp;
 
  835      respDescr = ndr_PackApReplyResp_descr();
 
  837      if (rdpear_kerb_PackApReply(rdpear, context, &commandStream, &status, &packApReplyResp))
 
  841    case RemoteCallNtlmNegotiateVersion:
 
  842      WLog_ERR(TAG, 
"don't wanna support NTLM");
 
  846      WLog_DBG(TAG, 
"Unhandled callId=0x%x", callId);
 
  847      winpr_HexDump(TAG, WLOG_DEBUG, Stream_PointerAs(&commandStream, BYTE),
 
  848                    Stream_GetRemainingLength(&commandStream));
 
  852  if (!rdpear_prepare_response(context, callId, status, &wcontext, respStream))
 
  855  if (resp && respDescr)
 
  857    WINPR_ASSERT(respDescr->writeFn);
 
  859    BOOL r = respDescr->writeFn(wcontext, respStream, NULL, resp) &&
 
  860             ndr_treat_deferred_write(wcontext, respStream);
 
  862    if (respDescr->destroyFn)
 
  863      respDescr->destroyFn(wcontext, NULL, resp);
 
  867      WLog_DBG(TAG, 
"!writeFn || !ndr_treat_deferred_write");
 
  872  if (!ndr_end_constructed(wcontext, respStream) ||
 
  873      !rdpear_send_payload(rdpear, pChannelCallback, RDPEAR_PACKAGE_KERBEROS, respStream))
 
  875    WLog_DBG(TAG, 
"rdpear_send_payload !!!!!!!!");
 
  880    ndr_context_destroy(&context);
 
  883    ndr_context_destroy(&wcontext);
 
  886    Stream_Free(respStream, TRUE);
 
  890static UINT rdpear_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, 
wStream* s)
 
  893  WINPR_ASSERT(callback);
 
  894  UINT ret = ERROR_INVALID_DATA;
 
  898  if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
 
  899    return ERROR_INVALID_DATA;
 
  901  UINT32 protocolMagic = 0;
 
  904  Stream_Read_UINT32(s, protocolMagic);
 
  905  if (protocolMagic != 0x4EACC3C8)
 
  906    return ERROR_INVALID_DATA;
 
  908  Stream_Read_UINT32(s, Length);
 
  910  Stream_Read_UINT32(s, Version);
 
  911  if (Version != 0x00000000)
 
  912    return ERROR_INVALID_DATA;
 
  917  if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
 
  918    return ERROR_INVALID_DATA;
 
  920  SecBuffer inBuffer = { Length, SECBUFFER_TOKEN, Stream_PointerAs(s, 
void) };
 
  923  RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)callback->plugin;
 
  924  WINPR_ASSERT(rdpear);
 
  925  if (!freerdp_nla_decrypt(rdpear->rdp_context, &inBuffer, &decrypted))
 
  931  Stream_StaticInit(&decodedStream, decrypted.pvBuffer, decrypted.cbBuffer);
 
  932  WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, &decodedStream);
 
  934  if (!WinPrAsn1DecReadSequence(&dec, &dec2))
 
  940  if (!WinPrAsn1DecReadContextualOctetString(&dec2, 1, &error, &packageName, FALSE))
 
  943  if (!WinPrAsn1DecReadContextualOctetString(&dec2, 2, &error, &payload, FALSE))
 
  947  Stream_StaticInit(&payloadStream, payload.data, payload.len);
 
  949  ret = rdpear_decode_payload(rdpear, pChannelCallback, &payloadStream);
 
  951  sspi_SecBufferFree(&decrypted);
 
  960static UINT rdpear_on_open(IWTSVirtualChannelCallback* pChannelCallback)
 
  962  WINPR_UNUSED(pChannelCallback);
 
  963  return CHANNEL_RC_OK;
 
  971static UINT rdpear_on_close(IWTSVirtualChannelCallback* pChannelCallback)
 
  973  WINPR_UNUSED(pChannelCallback);
 
  974  return CHANNEL_RC_OK;
 
  981  RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)base;
 
  982  krb5_free_context(rdpear->krbContext);
 
  985static UINT init_plugin_cb(
GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
 
  988  WINPR_UNUSED(settings);
 
  990  RDPEAR_PLUGIN* rdpear = (RDPEAR_PLUGIN*)base;
 
  991  rdpear->rdp_context = rcontext;
 
  992  if (krb5_init_context(&rdpear->krbContext))
 
  993    return CHANNEL_RC_INITIALIZATION_ERROR;
 
  994  return CHANNEL_RC_OK;
 
  997static const IWTSVirtualChannelCallback rdpear_callbacks = { rdpear_on_data_received,
 
  998                                                           rdpear_on_open, rdpear_on_close,
 
 1006FREERDP_ENTRY_POINT(UINT rdpear_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
 
 1008  return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPEAR_DVC_CHANNEL_NAME,
 
 1010                                        &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