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