static BOOL kerberos_rd_tgt_token(const sspi_gss_data* token, char** target, krb5_data* ticket)
{
	WinPrAsn1Decoder dec, dec2;
	BOOL error;
	WinPrAsn1_tagId tag;
	WinPrAsn1_INTEGER val;
	size_t len;
	wStream s;
	char* buf = NULL;
	char* str = NULL;

	WINPR_ASSERT(token);

	WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)token->data, token->length);

	/* KERB-TGT-REQUEST (SEQUENCE) */
	if (!WinPrAsn1DecReadSequence(&dec, &dec2))
		return FALSE;
	dec = dec2;

	/* pvno [0] INTEGER */
	if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) || val != 5)
		return FALSE;

	/* msg-type [1] INTEGER */
	if (!WinPrAsn1DecReadContextualInteger(&dec, 1, &error, &val))
		return FALSE;

	if (val == KRB_TGT_REQ)
	{
		if (!target)
			return FALSE;
		*target = NULL;

		s = WinPrAsn1DecGetStream(&dec);
		len = Stream_Length(&s);
		if (len == 0)
			return TRUE;

		buf = malloc(len);
		if (!buf)
			return FALSE;

		*buf = 0;
		*target = buf;

		if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
			goto fail;

		if (tag == 2)
		{
			WinPrAsn1Decoder seq;
			/* server-name [2] PrincipalName (SEQUENCE) */
			if (!WinPrAsn1DecReadSequence(&dec2, &seq))
				goto fail;

			/* name-type [0] INTEGER */
			if (!WinPrAsn1DecReadContextualInteger(&seq, 0, &error, &val))
				goto fail;

			/* name-string [1] SEQUENCE OF GeneralString */
			if (!WinPrAsn1DecReadContextualSequence(&seq, 1, &error, &dec2))
				goto fail;

			while (WinPrAsn1DecPeekTag(&dec2, &tag))
			{
				if (!WinPrAsn1DecReadGeneralString(&dec2, &str))
					goto fail;

				if (buf != *target)
					*buf++ = '/';
				buf = stpcpy(buf, str);
				free(str);
			}

			if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
				return TRUE;
		}

		/* realm [3] Realm */
		if (tag != 3 || !WinPrAsn1DecReadGeneralString(&dec2, &str))
			goto fail;

		*buf++ = '@';
		strcpy(buf, str);
		return TRUE;
	}
	else if (val == KRB_TGT_REP)
	{
		if (!ticket)
			return FALSE;

		/* ticket [2] Ticket */
		if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) || tag != 2)
			return FALSE;

		s = WinPrAsn1DecGetStream(&dec2);
		ticket->data = (char*)Stream_Buffer(&s);
		ticket->length = Stream_Length(&s);
		return TRUE;
	}
	else
		return FALSE;

fail:
	free(buf);
	return FALSE;
}
static BOOL kerberos_rd_tgt_token(const sspi_gss_data* token, char** target, krb5_data* ticket)
{
	WinPrAsn1Decoder dec, dec2;
	BOOL error;
	WinPrAsn1_tagId tag;
	WinPrAsn1_INTEGER val;
	size_t len;
	wStream s;
	char* buf = NULL;
	char* str = NULL;

	WINPR_ASSERT(token);

	WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)token->data, token->length);

	 
	if (!WinPrAsn1DecReadSequence(&dec, &dec2))
		return FALSE;
	dec = dec2;

	 
	if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) || val != 5)
		return FALSE;

	 
	if (!WinPrAsn1DecReadContextualInteger(&dec, 1, &error, &val))
		return FALSE;

	if (val == KRB_TGT_REQ)
	{
		if (!target)
			return FALSE;
		*target = NULL;

		s = WinPrAsn1DecGetStream(&dec);
		len = Stream_Length(&s);
		if (len == 0)
			return TRUE;

		buf = malloc(len);
		if (!buf)
			return FALSE;

		*buf = 0;
		*target = buf;

		if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
			goto fail;

		if (tag == 2)
		{
			WinPrAsn1Decoder seq;
			 
			if (!WinPrAsn1DecReadSequence(&dec2, &seq))
				goto fail;

			 
			if (!WinPrAsn1DecReadContextualInteger(&seq, 0, &error, &val))
				goto fail;

			 
			if (!WinPrAsn1DecReadContextualSequence(&seq, 1, &error, &dec2))
				goto fail;

			while (WinPrAsn1DecPeekTag(&dec2, &tag))
			{
				if (!WinPrAsn1DecReadGeneralString(&dec2, &str))
					goto fail;

				if (buf != *target)
					*buf++ = '/';
				buf = stpcpy(buf, str);
				free(str);
			}

			if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
				return TRUE;
		}

		 
		if (tag != 3 || !WinPrAsn1DecReadGeneralString(&dec2, &str))
			goto fail;

		*buf++ = '@';
		strcpy(buf, str);
		return TRUE;
	}
	else if (val == KRB_TGT_REP)
	{
		if (!ticket)
			return FALSE;

		 
		if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) || tag != 2)
			return FALSE;

		s = WinPrAsn1DecGetStream(&dec2);
		ticket->data = (char*)Stream_Buffer(&s);
		ticket->length = Stream_Length(&s);
		return TRUE;
	}
	else
		return FALSE;

fail:
	free(buf);
	return FALSE;
}