From 336e67e2d1b7b7c46a456f21db68886b39f26d40 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Mon, 15 May 2006 23:04:25 +0900 Subject: [PATCH] rpcrt4: Implemented NTLM authentication for rpcrt4 connections. --- dlls/rpcrt4/Makefile.in | 2 +- dlls/rpcrt4/rpc_binding.c | 42 ++++++++++- dlls/rpcrt4/rpc_binding.h | 12 ++++ dlls/rpcrt4/rpc_message.c | 146 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 193 insertions(+), 9 deletions(-) diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index a4b0f63e9fb..b4ff100b501 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -5,7 +5,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = rpcrt4.dll IMPORTLIB = librpcrt4.$(IMPLIBEXT) -IMPORTS = iphlpapi advapi32 kernel32 ntdll +IMPORTS = secur32 iphlpapi advapi32 kernel32 ntdll EXTRALIBS = -luuid C_SRCS = \ diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index 36187efb133..dc22be36a59 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -981,9 +981,45 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, unsigned char *ServerPrinc RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvr, RPC_SECURITY_QOS *SecurityQos ) { - FIXME("%p %s %lu %lu %p %lu %p\n", Binding, debugstr_a((const char*)ServerPrincName), - AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); - return RPC_S_OK; + RpcBinding* bind = (RpcBinding*)Binding; + RPC_STATUS r; + + TRACE("%p %s %lu %lu %p %lu %p\n", Binding, debugstr_a((const char*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + + if (!AuthIdentity) + return RPC_S_INVALID_AUTH_IDENTITY; + + if (AuthnLevel != RPC_C_AUTHN_LEVEL_CONNECT) + { + FIXME("unsupported AuthnLevel %lu\n", AuthnLevel); + return RPC_S_UNKNOWN_AUTHN_LEVEL; + } + + if (AuthnSvc != RPC_C_AUTHN_WINNT) + { + FIXME("unsupported AuthnSvc %lu\n", AuthnSvc); + return RPC_S_UNKNOWN_AUTHN_SERVICE; + } + + if (AuthzSvr) + { + FIXME("unsupported AuthzSvr %lu\n", AuthzSvr); + return RPC_S_UNKNOWN_AUTHZ_SERVICE; + } + + if (SecurityQos) + FIXME("SecurityQos ignored\n"); + + r = AcquireCredentialsHandleA(NULL, "NTLM", SECPKG_CRED_OUTBOUND, NULL, + AuthIdentity, NULL, NULL, &bind->cred, &bind->exp); + if (r == ERROR_SUCCESS) + { + bind->AuthnSvc = AuthnSvc; + bind->AuthnLevel = AuthnLevel; + } + TRACE("AcquireCredentialsHandleA returned %08lx\n", r); + return r; } /*********************************************************************** diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index 2d656cc1707..99916a511fc 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -22,6 +22,7 @@ #define __WINE_RPC_BINDING_H #include "wine/rpcss_shared.h" +#include "security.h" struct protseq_ops; @@ -36,6 +37,11 @@ typedef struct _RpcConnection USHORT MaxTransmissionSize; /* The active interface bound to server. */ RPC_SYNTAX_IDENTIFIER ActiveInterface; + + /* authentication */ + CtxtHandle ctx; + TimeStamp exp; + ULONG attr; } RpcConnection; struct protseq_ops { @@ -62,6 +68,12 @@ typedef struct _RpcBinding RPC_BLOCKING_FN BlockingFn; ULONG ServerTid; RpcConnection* FromConn; + + /* authentication */ + unsigned long AuthnLevel; + unsigned long AuthnSvc; + CredHandle cred; + TimeStamp exp; } RpcBinding; LPSTR RPCRT4_strndupA(LPCSTR src, INT len); diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 014d60a0fd0..daeb6682b7f 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -173,6 +173,22 @@ RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, return header; } +RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->common) + 12); + if (header == NULL) + return NULL; + + RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation); + header->common.frag_len = 0x14; + header->common.auth_len = 0; + + return header; +} + RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor) @@ -279,13 +295,12 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - alen); /* add the authorization info */ - if (AuthLength) + if (Connection->Used && AuthLength) { auth_hdr = &pkt[Header->common.frag_len - alen]; - /* FIXME: is this per fragment or per message? */ - auth_hdr[0] = RPC_C_AUTHN_WINNT; - auth_hdr[1] = RPC_C_AUTHN_LEVEL_CONNECT; + auth_hdr[0] = Connection->Used->AuthnSvc; + auth_hdr[1] = Connection->Used->AuthnLevel; auth_hdr[2] = 0x00; /* FIXME: add padding */ auth_hdr[3] = 0x00; @@ -310,6 +325,87 @@ write: return RPC_S_OK; } +/*********************************************************************** + * RPCRT4_AuthNegotiate (internal) + */ +static void RPCRT4_AuthNegotiate(RpcConnection *conn, SecBuffer *out) +{ + SECURITY_STATUS r; + SecBufferDesc out_desc; + unsigned char *buffer; + RpcBinding *bind = conn->Used; + + buffer = HeapAlloc(GetProcessHeap(), 0, 0x100); + + out->BufferType = SECBUFFER_TOKEN; + out->cbBuffer = 0x100; + out->pvBuffer = buffer; + + out_desc.ulVersion = 0; + out_desc.cBuffers = 1; + out_desc.pBuffers = out; + + conn->attr = 0; + conn->ctx.dwLower = 0; + conn->ctx.dwUpper = 0; + + r = InitializeSecurityContextA(&bind->cred, NULL, NULL, + ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH | + ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP, + NULL, 0, &conn->ctx, &out_desc, &conn->attr, &bind->exp); + + TRACE("r = %08lx cbBuffer = %ld attr = %08lx\n", r, out->cbBuffer, conn->attr); +} + +/*********************************************************************** + * RPCRT4_AuthorizeBinding (internal) + */ +static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn, + BYTE *challenge, ULONG count) +{ + SecBufferDesc inp_desc, out_desc; + SecBuffer inp, out; + SECURITY_STATUS r; + unsigned char buffer[0x100]; + RpcPktHdr *resp_hdr; + RPC_STATUS status; + + TRACE("challenge %s, %ld bytes\n", challenge, count); + + out.BufferType = SECBUFFER_TOKEN; + out.cbBuffer = sizeof buffer; + out.pvBuffer = buffer; + + out_desc.ulVersion = 0; + out_desc.cBuffers = 1; + out_desc.pBuffers = &out; + + inp.BufferType = SECBUFFER_TOKEN; + inp.pvBuffer = challenge; + inp.cbBuffer = count; + + inp_desc.cBuffers = 1; + inp_desc.pBuffers = &inp; + inp_desc.ulVersion = 0; + + r = InitializeSecurityContextA(&conn->Used->cred, &conn->ctx, NULL, + ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH | + ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP, + &inp_desc, 0, &conn->ctx, &out_desc, &conn->attr, &conn->exp); + if (r) + return r; + + resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION); + if (!resp_hdr) + return E_OUTOFMEMORY; + + status = RPCRT4_SendAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer); + + RPCRT4_FreeHeader(resp_hdr); + + return status; +} + /*********************************************************************** * RPCRT4_Send (internal) * @@ -318,7 +414,37 @@ write: RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength) { - return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0); + RPC_STATUS r; + SecBuffer out; + + /* if we've already authenticated, just send the context */ + if (Connection->ctx.dwUpper || Connection->ctx.dwLower) + { + unsigned char buffer[0x10]; + + memset(buffer, 0, sizeof buffer); + buffer[0] = 1; /* version number lsb */ + + return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, buffer, sizeof buffer); + } + + if (Connection->Used == NULL || + Connection->Used->AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT || + Connection->Used->AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) + { + return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0); + } + + out.BufferType = SECBUFFER_TOKEN; + out.cbBuffer = 0; + out.pvBuffer = NULL; + + /* tack on a negotiate packet */ + RPCRT4_AuthNegotiate(Connection, &out); + r = RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + + return r; } /*********************************************************************** @@ -439,6 +565,16 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, } } + /* respond to authorization request */ + if (common_hdr.ptype == PKT_BIND_ACK && common_hdr.auth_len > 8) + { + unsigned int offset; + + offset = common_hdr.frag_len - hdr_length - common_hdr.auth_len; + RPCRT_AuthorizeConnection(Connection, (LPBYTE)pMsg->Buffer + offset, + common_hdr.auth_len); + } + /* success */ status = RPC_S_OK;