From dec025c21523c88dcfdd98549697d6067f74b83e Mon Sep 17 00:00:00 2001
From: Stefan Kuhr <winesku@googlemail.com>
Date: Mon, 28 Sep 2009 19:26:21 +0200
Subject: Fallback from negotiate to ntlm if no negotiate provider is present

---
 dlls/rpcrt4/rpc_binding.c |   66 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c
index 29e0709..cc3cf41 100644
--- a/dlls/rpcrt4/rpc_binding.c
+++ b/dlls/rpcrt4/rpc_binding.c
@@ -1563,13 +1563,6 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName,
     return RPC_S_UNKNOWN_AUTHN_LEVEL;
   }
 
-  /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
-  if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
-  {
-    FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
-    return RPC_S_UNKNOWN_AUTHZ_SERVICE;
-  }
-
   r = EnumerateSecurityPackagesA(&package_count, &packages);
   if (r != SEC_E_OK)
   {
@@ -1581,6 +1574,23 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName,
     if (packages[i].wRPCID == AuthnSvc)
         break;
 
+  /* FIXME: A negotiate provider should be implemented */
+
+  if (i == package_count && RPC_C_AUTHN_GSS_NEGOTIATE==AuthnSvc)
+  {
+    /* If the caller requested RPC_C_AUTHN_GSS_NEGOTIATE and we only can offer
+    RPC_C_AUTHN_WINNT, we should allow the caller to use RPC_C_AUTHN_WINNT.
+    After all, the caller specified that NTLM would be sufficient, so if 
+    we have NTLM, we give it to the caller: */
+
+    for (i = 0; i < package_count; i++)
+      if (packages[i].wRPCID == RPC_C_AUTHN_WINNT)
+      {
+        AuthnSvc = RPC_C_AUTHN_WINNT;
+        break;
+      }
+  }
+
   if (i == package_count)
   {
     FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
@@ -1588,6 +1598,16 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName,
     return RPC_S_UNKNOWN_AUTHN_SERVICE;
   }
 
+  /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
+  if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
+  {
+    FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
+    FreeContextBuffer(packages);
+    return RPC_S_UNKNOWN_AUTHZ_SERVICE;
+  }
+
+
+
   TRACE("found package %s for service %u\n", packages[i].Name, AuthnSvc);
   r = AcquireCredentialsHandleA(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
                                 AuthIdentity, NULL, NULL, &cred, &exp);
@@ -1693,13 +1713,6 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName,
     return RPC_S_UNKNOWN_AUTHN_LEVEL;
   }
 
-  /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
-  if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
-  {
-    FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
-    return RPC_S_UNKNOWN_AUTHZ_SERVICE;
-  }
-
   r = EnumerateSecurityPackagesW(&package_count, &packages);
   if (r != SEC_E_OK)
   {
@@ -1711,6 +1724,23 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName,
     if (packages[i].wRPCID == AuthnSvc)
         break;
 
+  /* FIXME: A negotiate provider should be implemented */
+
+  if (i == package_count && RPC_C_AUTHN_GSS_NEGOTIATE==AuthnSvc)
+  {
+    /* If the caller requested RPC_C_AUTHN_GSS_NEGOTIATE and we only can offer
+    RPC_C_AUTHN_WINNT, we should allow the caller to use RPC_C_AUTHN_WINNT.
+    After all, the caller specified that NTLM would be sufficient, so if 
+    we have NTLM, we give it to the caller: */
+
+    for (i = 0; i < package_count; i++)
+      if (packages[i].wRPCID == RPC_C_AUTHN_WINNT)
+      {
+        AuthnSvc = RPC_C_AUTHN_WINNT;
+        break;
+      }
+  }
+
   if (i == package_count)
   {
     FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
@@ -1718,6 +1748,14 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName,
     return RPC_S_UNKNOWN_AUTHN_SERVICE;
   }
 
+  /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
+  if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
+  {
+    FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
+    FreeContextBuffer(packages);
+    return RPC_S_UNKNOWN_AUTHZ_SERVICE;
+  }
+
   TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), AuthnSvc);
   r = AcquireCredentialsHandleW(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
                                 AuthIdentity, NULL, NULL, &cred, &exp);
-- 
1.5.4.3

