diff --git a/dlls/rpcrt4/rpc_assoc.c b/dlls/rpcrt4/rpc_assoc.c index 8cf294798a2..2bbd8211a10 100644 --- a/dlls/rpcrt4/rpc_assoc.c +++ b/dlls/rpcrt4/rpc_assoc.c @@ -389,7 +389,7 @@ static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, - RpcQualityOfService *QOS, RpcConnection **Connection) + RpcQualityOfService *QOS, LPCWSTR CookieAuth, RpcConnection **Connection) { RpcConnection *NewConnection; RPC_STATUS status; @@ -402,7 +402,7 @@ RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */, assoc->Protseq, assoc->NetworkAddr, assoc->Endpoint, assoc->NetworkOptions, - AuthInfo, QOS); + AuthInfo, QOS, CookieAuth); if (status != RPC_S_OK) return status; diff --git a/dlls/rpcrt4/rpc_assoc.h b/dlls/rpcrt4/rpc_assoc.h index f8df62d3802..3d9b612f65e 100644 --- a/dlls/rpcrt4/rpc_assoc.h +++ b/dlls/rpcrt4/rpc_assoc.h @@ -47,7 +47,9 @@ typedef struct _RpcAssoc } RpcAssoc; RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc) DECLSPEC_HIDDEN; -RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection) DECLSPEC_HIDDEN; +RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, + LPCWSTR CookieAuth, RpcConnection **Connection) DECLSPEC_HIDDEN; void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) DECLSPEC_HIDDEN; ULONG RpcAssoc_Release(RpcAssoc *assoc) DECLSPEC_HIDDEN; RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, ULONG assoc_gid, RpcAssoc **assoc_out) DECLSPEC_HIDDEN; diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index 5b4964323ee..a6cfb6aed1d 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -263,6 +263,7 @@ RPC_STATUS RPCRT4_ReleaseBinding(RpcBinding* Binding) RPCRT4_strfree(Binding->NetworkAddr); RPCRT4_strfree(Binding->Protseq); HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + HeapFree(GetProcessHeap(), 0, Binding->CookieAuth); if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo); if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS); HeapFree(GetProcessHeap(), 0, Binding); @@ -277,7 +278,7 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, if (!Binding->server) { return RpcAssoc_GetClientConnection(Binding->Assoc, InterfaceId, - TransferSyntax, Binding->AuthInfo, Binding->QOS, Connection); + TransferSyntax, Binding->AuthInfo, Binding->QOS, Binding->CookieAuth, Connection); } else { /* we already have a connection with acceptable binding, so use it */ if (Binding->FromConn) { @@ -1002,6 +1003,7 @@ RPC_STATUS RPC_ENTRY RpcBindingCopy( DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1); DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1); DestBinding->NetworkOptions = RPCRT4_strdupW(SrcBinding->NetworkOptions); + DestBinding->CookieAuth = RPCRT4_strdupW(SrcBinding->CookieAuth); if (SrcBinding->Assoc) SrcBinding->Assoc->refs++; DestBinding->Assoc = SrcBinding->Assoc; @@ -1923,6 +1925,27 @@ RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, UL */ RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG_PTR OptionValue) { - FIXME("(%p, %d, %ld): stub\n", BindingHandle, Option, OptionValue); + TRACE("(%p, %d, %ld)\n", BindingHandle, Option, OptionValue); + + switch (Option) + { + case RPC_C_OPT_COOKIE_AUTH: + { + RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR *cookie = (RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR *)OptionValue; + RpcBinding *binding = BindingHandle; + int len = MultiByteToWideChar(CP_ACP, 0, cookie->Buffer, cookie->BufferSize, NULL, 0); + WCHAR *str; + + if (!(str = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) return ERROR_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, cookie->Buffer, cookie->BufferSize, str, len); + str[len] = 0; + HeapFree(GetProcessHeap(), 0, binding->CookieAuth); + binding->CookieAuth = str; + break; + } + default: + FIXME("option %u not supported\n", Option); + break; + } return RPC_S_OK; } diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index 21c962d91fa..7b8eaf38dde 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -78,6 +78,7 @@ typedef struct _RpcConnection ULONG encryption_auth_len; ULONG signature_auth_len; RpcQualityOfService *QOS; + LPWSTR CookieAuth; /* client-only */ struct list conn_pool_entry; @@ -134,6 +135,7 @@ typedef struct _RpcBinding /* authentication */ RpcAuthInfo *AuthInfo; RpcQualityOfService *QOS; + LPWSTR CookieAuth; } RpcBinding; LPSTR RPCRT4_strndupA(LPCSTR src, INT len) DECLSPEC_HIDDEN; @@ -153,7 +155,9 @@ ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos) DECLSPEC_HIDDEN; ULONG RpcQualityOfService_Release(RpcQualityOfService *qos) DECLSPEC_HIDDEN; BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2) DECLSPEC_HIDDEN; -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS) DECLSPEC_HIDDEN; +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, + LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, + RpcQualityOfService *QOS, LPCWSTR CookieAuth) DECLSPEC_HIDDEN; RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn ) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index e7f10abb7a7..00d03e43218 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -284,7 +284,7 @@ static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq } r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); + endpoint, NULL, NULL, NULL, NULL); if (r != RPC_S_OK) return r; @@ -342,7 +342,7 @@ static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protse } r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); + endpoint, NULL, NULL, NULL, NULL); if (r != RPC_S_OK) return r; @@ -1363,7 +1363,7 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, protseq->Protseq, NULL, - service, NULL, NULL, NULL); + service, NULL, NULL, NULL, NULL); if (create_status != RPC_S_OK) { closesocket(sock); @@ -2447,6 +2447,30 @@ static RPC_STATUS insert_authorization_header(HINTERNET request, RpcQualityOfSer return status; } +static RPC_STATUS insert_cookie_header(HINTERNET request, const WCHAR *value) +{ + static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' '}; + WCHAR *header, *ptr; + int len; + RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE; + + if (!value) return RPC_S_OK; + + len = strlenW(value); + if ((header = HeapAlloc(GetProcessHeap(), 0, sizeof(cookieW) + (len + 3) * sizeof(WCHAR)))) + { + memcpy(header, cookieW, sizeof(cookieW)); + ptr = header + sizeof(cookieW) / sizeof(cookieW[0]); + memcpy(ptr, value, len * sizeof(WCHAR)); + 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); + } + return status; +} + static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) { RpcConnection_http *httpc = (RpcConnection_http *)Connection; @@ -2511,6 +2535,10 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) if (status != RPC_S_OK) return status; + status = insert_cookie_header(httpc->in_request, Connection->CookieAuth); + 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); @@ -2523,6 +2551,10 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) if (status != RPC_S_OK) return status; + status = insert_cookie_header(httpc->out_request, Connection->CookieAuth); + if (status != RPC_S_OK) + return status; + status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event, @@ -3001,7 +3033,7 @@ RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, - LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS) + LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth) { static LONG next_id; const struct connection_ops *ops; @@ -3023,6 +3055,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions); + NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth); NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface)); NewConnection->NextCallId = 1; @@ -3051,11 +3084,9 @@ static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnecti { RPC_STATUS err; - err = RPCRT4_CreateConnection(Connection, OldConnection->server, - rpcrt4_conn_get_name(OldConnection), - OldConnection->NetworkAddr, - OldConnection->Endpoint, NULL, - OldConnection->AuthInfo, OldConnection->QOS); + err = RPCRT4_CreateConnection(Connection, OldConnection->server, rpcrt4_conn_get_name(OldConnection), + OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, + OldConnection->AuthInfo, OldConnection->QOS, OldConnection->CookieAuth); if (err == RPC_S_OK) rpcrt4_conn_handoff(OldConnection, *Connection); return err; @@ -3077,6 +3108,7 @@ RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection) RPCRT4_strfree(Connection->Endpoint); RPCRT4_strfree(Connection->NetworkAddr); HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions); + HeapFree(GetProcessHeap(), 0, Connection->CookieAuth); if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo); if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS); diff --git a/include/rpcdcep.h b/include/rpcdcep.h index 0169586d214..fd0acda235e 100644 --- a/include/rpcdcep.h +++ b/include/rpcdcep.h @@ -124,6 +124,14 @@ typedef struct _RPC_CLIENT_INTERFACE unsigned int Flags; } RPC_CLIENT_INTERFACE, *PRPC_CLIENT_INTERFACE; +#define RPC_C_OPT_COOKIE_AUTH 7 + +typedef struct _RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR +{ + ULONG BufferSize; + char *Buffer; +} RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR; + #define TRANSPORT_TYPE_CN 0x01 #define TRANSPORT_TYPE_DG 0x02 #define TRANSPORT_TYPE_LPC 0x04