[4/4] rpcrt4: Try to authorize with the first HTTP request instead of waiting for a challenge.
Hans Leidekker
hans at codeweavers.com
Tue Aug 20 05:55:13 CDT 2013
---
dlls/rpcrt4/rpc_transport.c | 99 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 921c43d..e7f10ab 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -2355,6 +2355,98 @@ static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
return RPC_S_OK;
}
+static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
+{
+ static char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ UINT i = 0, x;
+
+ while (len > 0)
+ {
+ /* first 6 bits, all from bin[0] */
+ base64[i++] = enc[(bin[0] & 0xfc) >> 2];
+ x = (bin[0] & 3) << 4;
+
+ /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
+ if (len == 1)
+ {
+ base64[i++] = enc[x];
+ base64[i++] = '=';
+ base64[i++] = '=';
+ break;
+ }
+ base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
+ x = (bin[1] & 0x0f) << 2;
+
+ /* next 6 bits 4 from bin[1] and 2 from bin[2] */
+ if (len == 2)
+ {
+ base64[i++] = enc[x];
+ base64[i++] = '=';
+ break;
+ }
+ base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
+
+ /* last 6 bits, all from bin [2] */
+ base64[i++] = enc[bin[2] & 0x3f];
+ bin += 3;
+ len -= 3;
+ }
+ base64[i] = 0;
+ return i;
+}
+
+static RPC_STATUS insert_authorization_header(HINTERNET request, RpcQualityOfService *qos)
+{
+ static const WCHAR basicW[] =
+ {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' ','B','a','s','i','c',' '};
+ RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
+ SEC_WINNT_AUTH_IDENTITY_W *id;
+ int len, datalen, userlen, passlen;
+ WCHAR *header, *ptr;
+ char *data;
+ RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
+
+ if (!qos || qos->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
+ return RPC_S_OK;
+
+ creds = qos->qos->u.HttpCredentials;
+ if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
+ return RPC_S_OK;
+
+ if (creds->AuthnSchemes[0] != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
+ {
+ FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]);
+ return RPC_S_OK;
+ }
+ id = creds->TransportCredentials;
+ if (!id->User || !id->Password) return RPC_S_OK;
+
+ userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
+ passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
+
+ datalen = userlen + passlen + 1;
+ if (!(data = HeapAlloc(GetProcessHeap(), 0, datalen))) return RPC_S_OUT_OF_MEMORY;
+
+ WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, data, userlen, NULL, NULL);
+ data[userlen] = ':';
+ WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, data + userlen + 1, passlen, NULL, NULL);
+
+ len = ((datalen + 2) * 4) / 3;
+ if ((header = HeapAlloc(GetProcessHeap(), 0, sizeof(basicW) + (len + 2) * sizeof(WCHAR))))
+ {
+ memcpy(header, basicW, sizeof(basicW));
+ ptr = header + sizeof(basicW) / sizeof(basicW[0]);
+ len = encode_base64(data, datalen, ptr);
+ ptr[len++] = '\r';
+ ptr[len++] = '\n';
+ ptr[len] = 0;
+ if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD_IF_NEW))) status = RPC_S_OK;
+ HeapFree(GetProcessHeap(), 0, header);
+ }
+ HeapFree(GetProcessHeap(), 0, data);
+ return status;
+}
+
static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
{
RpcConnection_http *httpc = (RpcConnection_http *)Connection;
@@ -2415,6 +2507,10 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
HeapFree(GetProcessHeap(), 0, url);
return RPC_S_SERVER_UNAVAILABLE;
}
+ status = insert_authorization_header(httpc->in_request, httpc->common.QOS);
+ if (status != RPC_S_OK)
+ return status;
+
httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes,
flags, (DWORD_PTR)httpc->async_data);
HeapFree(GetProcessHeap(), 0, url);
@@ -2423,6 +2519,9 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
return RPC_S_SERVER_UNAVAILABLE;
}
+ status = insert_authorization_header(httpc->out_request, httpc->common.QOS);
+ if (status != RPC_S_OK)
+ return status;
status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
httpc->async_data,
--
1.7.10.4
More information about the wine-patches
mailing list