libfreerdp-core: fix NTLM HTTP authentication

This commit is contained in:
Marc-André Moreau 2012-04-19 11:29:53 -04:00
parent 88b8380b4c
commit 1961412941
5 changed files with 90 additions and 58 deletions

View File

@ -121,13 +121,13 @@ STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request)
http_request->lines = (char**) xmalloc(sizeof(char*) * http_request->count);
http_encode_line(http_request->lines[0], "%s %s HTTP/1.1", http_request->Method, http_request->URI);
http_encode_line(http_request->lines[1], "Accept: %s", http_context->Accept);
http_encode_line(http_request->lines[2], "Cache-Control: %s", http_context->CacheControl);
http_encode_line(http_request->lines[3], "Connection: %s", http_context->Connection);
http_encode_line(http_request->lines[4], "Content-Length: %d", http_request->ContentLength);
http_encode_line(http_request->lines[1], "Cache-Control: %s", http_context->CacheControl);
http_encode_line(http_request->lines[2], "Connection: %s", http_context->Connection);
http_encode_line(http_request->lines[3], "Pragma: %s", http_context->Pragma);
http_encode_line(http_request->lines[4], "Accept: %s", http_context->Accept);
http_encode_line(http_request->lines[5], "User-Agent: %s", http_context->UserAgent);
http_encode_line(http_request->lines[6], "Host: %s", http_context->Host);
http_encode_line(http_request->lines[7], "Pragma: %s", http_context->Pragma);
http_encode_line(http_request->lines[6], "Content-Length: %d", http_request->ContentLength);
http_encode_line(http_request->lines[7], "Host: %s", http_context->Host);
if (http_request->Authorization != NULL)
{
@ -366,6 +366,13 @@ HttpResponse* http_response_recv(rdpTls* tls)
break;
}
if ((length - nbytes) <= 0)
{
length *= 2;
buffer = xrealloc(buffer, length);
p = (uint8*) &buffer[nbytes];
}
}
return http_response;

View File

@ -113,6 +113,14 @@ boolean ntlm_authenticate(rdpNtlm* ntlm)
ntlm->outputBuffer.cbBuffer = ntlm->cbMaxToken;
ntlm->outputBuffer.pvBuffer = xmalloc(ntlm->outputBuffer.cbBuffer);
if (ntlm->haveInputBuffer)
{
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
ntlm->inputBufferDesc.cBuffers = 1;
ntlm->inputBufferDesc.pBuffers = &ntlm->inputBuffer;
ntlm->inputBuffer.BufferType = SECBUFFER_TOKEN;
}
status = ntlm->table->InitializeSecurityContext(&ntlm->credentials,
(ntlm->haveContext) ? &ntlm->context : NULL,
NULL, ntlm->fContextReq, 0, SECURITY_NATIVE_DREP,
@ -120,6 +128,14 @@ boolean ntlm_authenticate(rdpNtlm* ntlm)
0, &ntlm->context, &ntlm->outputBufferDesc,
&ntlm->pfContextAttr, &ntlm->expiration);
#ifdef WITH_DEBUG_RPC
if (ntlm->haveInputBuffer)
{
printf("NTLM Token (%d)\n", ntlm->inputBuffer.cbBuffer);
freerdp_hexdump(ntlm->inputBuffer.pvBuffer, ntlm->inputBuffer.cbBuffer);
}
#endif
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
{
if (ntlm->table->CompleteAuthToken != NULL)
@ -176,6 +192,11 @@ STREAM* rpc_ntlm_http_data(rdpRpc* rpc, char* command, SecBuffer* ntlm_token, ui
HttpContext* http_context;
HttpRequest* http_request;
#ifdef WITH_DEBUG_RPC
printf("NTLM Token (%d):\n", ntlm_token->cbBuffer);
freerdp_hexdump(ntlm_token->pvBuffer, ntlm_token->cbBuffer);
#endif
base64_ntlm_token = crypto_encode_base64(ntlm_token->pvBuffer, ntlm_token->cbBuffer);
if (strcmp(command, "RPC_IN_DATA") == 0)
@ -209,7 +230,7 @@ boolean rpc_out_connect_http(rdpRpc* rpc)
rdpRpcHTTP* http_out = rpc->http_out;
rdpNtlm* http_out_ntlm = http_out->ntlm;
ntlm_client_init(http_out_ntlm, settings->username, settings->password, settings->domain);
ntlm_client_init(http_out_ntlm, settings->username, settings->domain, settings->password);
ntlm_authenticate(http_out_ntlm);
@ -251,7 +272,7 @@ boolean rpc_in_connect_http(rdpRpc* rpc)
rdpRpcHTTP* http_in = rpc->http_in;
rdpNtlm* http_in_ntlm = http_in->ntlm;
ntlm_client_init(http_in_ntlm, settings->username, settings->password, settings->domain);
ntlm_client_init(http_in_ntlm, settings->username, settings->domain, settings->password);
ntlm_authenticate(http_in_ntlm);
@ -270,7 +291,7 @@ boolean rpc_in_connect_http(rdpRpc* rpc)
ntlm_authenticate(http_in_ntlm);
http_stream = rpc_ntlm_http_data(rpc, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, 1073741824);
http_stream = rpc_ntlm_http_data(rpc, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, 0x40000000);
DEBUG_RPC("%s", http_stream->data);
tls_write_all(tls_in, http_stream->data, http_stream->size);
@ -902,8 +923,14 @@ int rpc_out_read(rdpRpc* rpc, uint8* data, int length)
memcpy(data, pdu, frag_length);
if (strncmp((char*) pdu, "HTTP", 4) == 0)
{
printf("Unexpected HTTP response, likely caused by an NTLM HTTP authentication failure\n");
return -1;
}
#ifdef WITH_DEBUG_RPC
printf("rpc_out_recv(): length: %d\n", frag_length);
printf("rpc_out_read(): length: %d\n", frag_length);
freerdp_hexdump(data, frag_length);
printf("\n");
#endif
@ -1040,8 +1067,8 @@ int rpc_read(rdpRpc* rpc, uint8* data, int length)
{
if (rpc->read_buffer_len > length)
{
/*TODO fix read_buffer is too long problem */
printf("ERROR! RPCH Stores data in read_buffer fits not in data on rpc_read.\n");
/* TODO fix read_buffer is too long problem */
printf("ERROR! RPC Stores data in read_buffer fits not in data on rpc_read.\n");
return -1;
}
@ -1179,8 +1206,7 @@ rdpRpc* rpc_new(rdpSettings* settings)
http_context_set_user_agent(rpc->http_in->context, "MSRPC");
http_context_set_host(rpc->http_in->context, settings->tsg_hostname);
http_context_set_pragma(rpc->http_in->context,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, "
"SessionId=33ad20ac-7469-4f63-946d-113eac21a23c");
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729");
rpc->http_out->context = http_context_new();
http_context_set_method(rpc->http_out->context, "RPC_OUT_DATA");
@ -1191,8 +1217,7 @@ rdpRpc* rpc_new(rdpSettings* settings)
http_context_set_user_agent(rpc->http_out->context, "MSRPC");
http_context_set_host(rpc->http_out->context, settings->tsg_hostname);
http_context_set_pragma(rpc->http_out->context,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, "
"SessionId=33ad20ac-7469-4f63-946d-113eac21a23c");
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729");
rpc->read_buffer = NULL;
rpc->write_buffer = NULL;

View File

@ -195,27 +195,25 @@ DWORD TsProxySendToServer(byte pRpcMessage[])
boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
{
uint8* data;
uint32 length;
int status = -1;
rdpRpc* rpch = tsg->rpch;
rdpRpc* rpc = tsg->rpc;
rdpTransport* transport = tsg->transport;
uint32 length;
uint8* data;
if (!rpc_attach(rpch, transport->tcp_in, transport->tcp_out, transport->tls_in, transport->tls_out))
if (!rpc_attach(rpc, transport->tcp_in, transport->tcp_out, transport->tls_in, transport->tls_out))
{
printf("rpch_attach failed!\n");
printf("rpc_attach failed!\n");
return false;
}
if (!rpc_connect(rpch))
if (!rpc_connect(rpc))
{
printf("rpch_connect failed!\n");
printf("rpc_connect failed!\n");
return false;
}
DEBUG_TSG("rpch_connect success");
DEBUG_TSG("rpc_connect success");
/**
* OpNum = 1
@ -229,21 +227,21 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/
DEBUG_TSG("TsProxyCreateTunnel");
status = rpc_write(rpch, tsg_packet1, sizeof(tsg_packet1), 1);
status = rpc_write(rpc, tsg_packet1, sizeof(tsg_packet1), 1);
if (status <= 0)
{
printf("rpch_write opnum=1 failed!\n");
printf("rpc_write opnum=1 failed!\n");
return false;
}
length = 0x8FFF;
data = xmalloc(length);
status = rpc_read(rpch, data, length);
status = rpc_read(rpc, data, length);
if (status <= 0)
{
printf("rpch_recv failed!\n");
printf("rpc_recv failed!\n");
return false;
}
@ -270,19 +268,19 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/
DEBUG_TSG("TsProxyAuthorizeTunnel");
status = rpc_write(rpch, tsg_packet2, sizeof(tsg_packet2), 2);
status = rpc_write(rpc, tsg_packet2, sizeof(tsg_packet2), 2);
if (status <= 0)
{
printf("rpch_write opnum=2 failed!\n");
printf("rpc_write opnum=2 failed!\n");
return false;
}
status = rpc_read(rpch, data, length);
status = rpc_read(rpc, data, length);
if (status <= 0)
{
printf("rpch_recv failed!\n");
printf("rpc_recv failed!\n");
return false;
}
@ -300,11 +298,11 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/
DEBUG_TSG("TsProxyMakeTunnelCall");
status = rpc_write(rpch, tsg_packet3, sizeof(tsg_packet3), 3);
status = rpc_write(rpc, tsg_packet3, sizeof(tsg_packet3), 3);
if (status <= 0)
{
printf("rpch_write opnum=3 failed!\n");
printf("rpc_write opnum=3 failed!\n");
return false;
}
status = -1;
@ -337,20 +335,20 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/
DEBUG_TSG("TsProxyCreateChannel");
status = rpc_write(rpch, s_p4->data, s_p4->size, 4);
status = rpc_write(rpc, s_p4->data, s_p4->size, 4);
if (status <= 0)
{
printf("rpch_write opnum=4 failed!\n");
printf("rpc_write opnum=4 failed!\n");
return false;
}
xfree(dest_addr_unic);
status = rpc_read(rpch, data, length);
status = rpc_read(rpc, data, length);
if (status < 0)
{
printf("rpch_recv failed!\n");
printf("rpc_recv failed!\n");
return false;
}
@ -374,51 +372,53 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/
DEBUG_TSG("TsProxySetupReceivePipe");
status = rpc_write(rpch, tsg_packet5, sizeof(tsg_packet5), 8);
status = rpc_write(rpc, tsg_packet5, sizeof(tsg_packet5), 8);
if (status <= 0)
{
printf("rpch_write opnum=8 failed!\n");
printf("rpc_write opnum=8 failed!\n");
return false;
}
return true;
}
uint8 pp[8] =
{
0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
};
int tsg_write(rdpTsg* tsg, uint8* data, uint32 length)
{
STREAM* s;
uint8* tsg_pkg;
int status = -1;
uint16 opnum = 9;
uint32 tsg_length = length + 16 + 4 + 12 + 8;
uint32 totalDataBytes = length + 4;
STREAM* s = stream_new(12);
stream_write_uint32_be(s,totalDataBytes);
stream_write_uint32_be(s,0x01);
stream_write_uint32_be(s,length);
s = stream_new(12);
stream_write_uint32_be(s, totalDataBytes);
stream_write_uint32_be(s, 0x01);
stream_write_uint32_be(s, length);
uint8* tsg_pkg = xmalloc(tsg_length);
tsg_pkg = xmalloc(tsg_length);
memset(tsg_pkg, 0, 4);
memcpy(tsg_pkg + 4, tsg->channelContext, 16);
memcpy(tsg_pkg + 20, s->data, 12);
memcpy(tsg_pkg + 32, data, length);
uint8 pp[8] =
{
0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
};
memcpy(tsg_pkg + 32 + length, pp, 8);
status = rpc_write(tsg->rpch, tsg_pkg, tsg_length, opnum);
status = rpc_write(tsg->rpc, tsg_pkg, tsg_length, opnum);
xfree(tsg_pkg);
stream_free(s);
if (status <= 0)
{
printf("rpch_write failed!\n");
printf("rpc_write failed!\n");
return -1;
}
@ -429,7 +429,7 @@ int tsg_read(rdpTsg* tsg, uint8* data, uint32 length)
{
int status;
status = rpc_read(tsg->rpch, data, length);
status = rpc_read(tsg->rpc, data, length);
return status;
}
@ -440,7 +440,7 @@ rdpTsg* tsg_new(rdpSettings* settings)
tsg = (rdpTsg*) xzalloc(sizeof(rdpTsg));
tsg->settings = settings;
tsg->rpch = rpc_new(settings);
tsg->rpc = rpc_new(settings);
return tsg;
}

View File

@ -36,7 +36,7 @@ typedef struct rdp_tsg rdpTsg;
struct rdp_tsg
{
rdpRpc* rpch;
rdpRpc* rpc;
uint8* tunnelContext;
uint8* channelContext;
rdpSettings* settings;

View File

@ -548,7 +548,7 @@ char* crypto_encode_base64(uint8* data, int length)
base64_string = xmalloc(bptr->length);
memcpy(base64_string, bptr->data, bptr->length - 1);
base64_string[bptr->length] = '\0';
base64_string[bptr->length - 1] = '\0';
BIO_free_all(b64);