Jacek Caban : secur32: Added support for grbitEnabledProtocols in schan_AcquireClientCredentials.

Alexandre Julliard julliard at winehq.org
Wed Mar 27 15:40:06 CDT 2013


Module: wine
Branch: master
Commit: 0f2e0365ea1f5c6baba4cfd9c0ff69defe66d7ea
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0f2e0365ea1f5c6baba4cfd9c0ff69defe66d7ea

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Mar 27 12:22:23 2013 +0100

secur32: Added support for grbitEnabledProtocols in schan_AcquireClientCredentials.

---

 dlls/secur32/schannel.c     |  169 ++++++++++++++++++++++++++++++++++++-------
 dlls/secur32/secur32_priv.h |    1 +
 2 files changed, 145 insertions(+), 25 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 387eaad..87bb942 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -25,10 +25,13 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 #include "winnls.h"
 #include "sspi.h"
 #include "schannel.h"
 #include "secur32_priv.h"
+
+#include "wine/unicode.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
@@ -62,6 +65,12 @@ static struct schan_handle *schan_free_handles;
 static SIZE_T schan_handle_table_size;
 static SIZE_T schan_handle_count;
 
+/* Protocols enabled, only those may be used for the connection. */
+static DWORD config_enabled_protocols;
+
+/* Protocols disabled by default. They are enabled for using, but disabled when caller asks for default settings. */
+static DWORD config_default_disabled_protocols;
+
 static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type)
 {
     struct schan_handle *handle;
@@ -141,11 +150,110 @@ static void *schan_get_object(ULONG_PTR handle_idx, enum schan_handle_type type)
     return handle->object;
 }
 
+static void read_config(void)
+{
+    DWORD enabled = 0, default_disabled = 0;
+    HKEY protocols_key, key;
+    WCHAR subkey_name[64];
+    unsigned i;
+    DWORD res;
+
+    static BOOL config_read = FALSE;
+
+    static const WCHAR protocol_config_key_name[] = {
+        'S','Y','S','T','E','M','\\',
+        'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+        'C','o','n','t','r','o','l','\\',
+        'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s','\\',
+        'S','C','H','A','N','N','E','L','\\',
+        'P','r','o','t','o','c','o','l','s',0 };
+
+    static const WCHAR clientW[] = {'\\','C','l','i','e','n','t',0};
+    static const WCHAR enabledW[] = {'e','n','a','b','l','e','d',0};
+    static const WCHAR disabledbydefaultW[] = {'D','i','s','a','b','l','e','d','B','y','D','e','f','a','u','l','t',0};
+
+    static const struct {
+        WCHAR key_name[20];
+        DWORD prot_client_flag;
+        BOOL enabled; /* If no config is present, enable the protocol */
+        BOOL disabled_by_default; /* Disable if caller asks for default protocol set */
+    } protocol_config_keys[] = {
+        {{'S','S','L',' ','2','.','0',0}, SP_PROT_SSL2_CLIENT, TRUE, TRUE},
+        {{'S','S','L',' ','3','.','0',0}, SP_PROT_SSL3_CLIENT, TRUE, FALSE},
+        {{'T','L','S',' ','1','.','0',0}, SP_PROT_TLS1_0_CLIENT, TRUE, FALSE},
+        {{'T','L','S',' ','1','.','1',0}, SP_PROT_TLS1_1_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ },
+        {{'T','L','S',' ','1','.','2',0}, SP_PROT_TLS1_2_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }
+    };
+
+    /* No need for thread safety */
+    if(config_read)
+        return;
+
+    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, protocol_config_key_name, 0, KEY_READ, &protocols_key);
+    if(res == ERROR_SUCCESS) {
+        DWORD type, size, value;
+
+        for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
+            strcpyW(subkey_name, protocol_config_keys[i].key_name);
+            strcatW(subkey_name, clientW);
+            res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key);
+            if(res != ERROR_SUCCESS) {
+                if(protocol_config_keys[i].enabled)
+                    enabled |= protocol_config_keys[i].prot_client_flag;
+                if(protocol_config_keys[i].disabled_by_default)
+                    default_disabled |= protocol_config_keys[i].prot_client_flag;
+                continue;
+            }
+
+            size = sizeof(value);
+            res = RegQueryValueExW(key, enabledW, NULL, &type, (BYTE*)&value, &size);
+            if(res == ERROR_SUCCESS) {
+                if(type == REG_DWORD && value)
+                    enabled |= protocol_config_keys[i].prot_client_flag;
+            }else if(protocol_config_keys[i].enabled) {
+                enabled |= protocol_config_keys[i].prot_client_flag;
+            }
+
+            size = sizeof(value);
+            res = RegQueryValueExW(key, disabledbydefaultW, NULL, &type, (BYTE*)&value, &size);
+            if(res == ERROR_SUCCESS) {
+                if(type != REG_DWORD || value)
+                    default_disabled |= protocol_config_keys[i].prot_client_flag;
+            }else if(protocol_config_keys[i].disabled_by_default) {
+                    default_disabled |= protocol_config_keys[i].prot_client_flag;
+            }
+
+            RegCloseKey(key);
+        }
+    }else {
+        /* No config, enable all known protocols. */
+        for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
+            if(protocol_config_keys[i].enabled)
+                enabled |= protocol_config_keys[i].prot_client_flag;
+            if(protocol_config_keys[i].disabled_by_default)
+                default_disabled |= protocol_config_keys[i].prot_client_flag;
+        }
+    }
+
+    RegCloseKey(protocols_key);
+
+    config_enabled_protocols = enabled;
+    config_default_disabled_protocols = default_disabled;
+    config_read = TRUE;
+
+    TRACE("enabled %x, disabled by default %x\n", config_enabled_protocols, config_default_disabled_protocols);
+}
+
 static SECURITY_STATUS schan_QueryCredentialsAttributes(
  PCredHandle phCredential, ULONG ulAttribute, VOID *pBuffer)
 {
+    struct schan_credentials *cred;
     SECURITY_STATUS ret;
 
+    cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED);
+    if(!cred)
+        return SEC_E_INVALID_HANDLE;
+
     switch (ulAttribute)
     {
     case SECPKG_ATTR_SUPPORTED_ALGS:
@@ -285,6 +393,8 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
  PCredHandle phCredential, PTimeStamp ptsExpiry)
 {
     struct schan_credentials *creds;
+    unsigned enabled_protocols;
+    ULONG_PTR handle;
     SECURITY_STATUS st = SEC_E_OK;
 
     TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
@@ -292,40 +402,49 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
     if (schanCred)
     {
         st = schan_CheckCreds(schanCred);
-        if (st == SEC_E_NO_CREDENTIALS)
-            st = SEC_E_OK;
+        if (st != SEC_E_OK && st != SEC_E_NO_CREDENTIALS)
+            return st;
+
+        st = SEC_E_OK;
+    }
+
+    read_config();
+    if(schanCred && schanCred->grbitEnabledProtocols)
+        enabled_protocols = schanCred->grbitEnabledProtocols & config_enabled_protocols;
+    else
+        enabled_protocols = config_enabled_protocols & ~config_default_disabled_protocols;
+    if(!enabled_protocols) {
+        ERR("Could not find matching protocol\n");
+        return SEC_E_NO_AUTHENTICATING_AUTHORITY;
     }
 
     /* For now, the only thing I'm interested in is the direction of the
      * connection, so just store it.
      */
-    if (st == SEC_E_OK)
-    {
-        ULONG_PTR handle;
+    creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds));
+    if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
 
-        creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds));
-        if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
-
-        handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
-        if (handle == SCHAN_INVALID_HANDLE) goto fail;
+    handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
+    if (handle == SCHAN_INVALID_HANDLE) goto fail;
 
-        creds->credential_use = SECPKG_CRED_OUTBOUND;
-        if (!schan_imp_allocate_certificate_credentials(creds))
-        {
-            schan_free_handle(handle, SCHAN_HANDLE_CRED);
-            goto fail;
-        }
+    creds->credential_use = SECPKG_CRED_OUTBOUND;
+    if (!schan_imp_allocate_certificate_credentials(creds))
+    {
+        schan_free_handle(handle, SCHAN_HANDLE_CRED);
+        goto fail;
+    }
 
-        phCredential->dwLower = handle;
-        phCredential->dwUpper = 0;
+    creds->enabled_protocols = enabled_protocols;
+    phCredential->dwLower = handle;
+    phCredential->dwUpper = 0;
 
-        /* Outbound credentials have no expiry */
-        if (ptsExpiry)
-        {
-            ptsExpiry->LowPart = 0;
-            ptsExpiry->HighPart = 0;
-        }
+    /* Outbound credentials have no expiry */
+    if (ptsExpiry)
+    {
+        ptsExpiry->LowPart = 0;
+        ptsExpiry->HighPart = 0;
     }
+
     return st;
 
 fail:
@@ -348,7 +467,7 @@ static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schan
         ULONG_PTR handle;
         struct schan_credentials *creds;
 
-        creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds));
+        creds = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*creds));
         if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
         creds->credential_use = SECPKG_CRED_INBOUND;
 
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index bc4b74b..5b2ac89 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -214,6 +214,7 @@ typedef struct schan_credentials
 {
     ULONG credential_use;
     void *credentials;
+    DWORD enabled_protocols;
 } schan_credentials;
 
 struct schan_transport;




More information about the wine-cvs mailing list