Mike McCormack : rpcrt4:
Implemented NTLM authentication for rpcrt4 connections.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue May 16 06:24:34 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: 336e67e2d1b7b7c46a456f21db68886b39f26d40
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=336e67e2d1b7b7c46a456f21db68886b39f26d40
Author: Mike McCormack <mike at codeweavers.com>
Date: Mon May 15 23:04:25 2006 +0900
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 a4b0f63..b4ff100 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 36187ef..dc22be3 100644
--- a/dlls/rpcrt4/rpc_binding.c
+++ b/dlls/rpcrt4/rpc_binding.c
@@ -981,9 +981,45 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HA
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 2d656cc..99916a5 100644
--- a/dlls/rpcrt4/rpc_binding.h
+++ b/dlls/rpcrt4/rpc_binding.h
@@ -22,6 +22,7 @@ #ifndef __WINE_RPC_BINDING_H
#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 014d60a..daeb668 100644
--- a/dlls/rpcrt4/rpc_message.c
+++ b/dlls/rpcrt4/rpc_message.c
@@ -173,6 +173,22 @@ RpcPktHdr *RPCRT4_BuildBindHeader(unsign
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(RpcCon
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;
@@ -311,6 +326,87 @@ write:
}
/***********************************************************************
+ * 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)
*
* Transmit a packet over connection in acceptable fragments.
@@ -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
}
}
+ /* 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;
More information about the wine-cvs
mailing list