[02/10] secur32: Implement InitializeSecurityContext for Kerberos.

Hans Leidekker hans at codeweavers.com
Mon Oct 23 04:09:17 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/secur32/kerberos.c | 164 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 153 insertions(+), 11 deletions(-)

diff --git a/dlls/secur32/kerberos.c b/dlls/secur32/kerberos.c
index 67404b72f2..0e486d7c51 100644
--- a/dlls/secur32/kerberos.c
+++ b/dlls/secur32/kerberos.c
@@ -47,7 +47,10 @@ static void *libgssapi_krb5_handle;
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
 MAKE_FUNCPTR(gss_acquire_cred);
+MAKE_FUNCPTR(gss_delete_sec_context);
 MAKE_FUNCPTR(gss_import_name);
+MAKE_FUNCPTR(gss_init_sec_context);
+MAKE_FUNCPTR(gss_release_buffer);
 MAKE_FUNCPTR(gss_release_name);
 #undef MAKE_FUNCPTR
 
@@ -67,7 +70,10 @@ static BOOL load_gssapi_krb5(void)
     }
 
     LOAD_FUNCPTR(gss_acquire_cred)
+    LOAD_FUNCPTR(gss_delete_sec_context)
     LOAD_FUNCPTR(gss_import_name)
+    LOAD_FUNCPTR(gss_init_sec_context)
+    LOAD_FUNCPTR(gss_release_buffer)
     LOAD_FUNCPTR(gss_release_name)
 #undef LOAD_FUNCPTR
 
@@ -85,12 +91,34 @@ static void unload_gssapi_krb5(void)
     libgssapi_krb5_handle = NULL;
 }
 
+static inline gss_cred_id_t credhandle_sspi_to_gss( const CredHandle *cred, gss_name_t *principal )
+{
+    if (!cred)
+    {
+        if (principal) *principal = GSS_C_NO_NAME;
+        return GSS_C_NO_CREDENTIAL;
+    }
+    if (principal) *principal = (gss_name_t)cred->dwUpper;
+    return (gss_cred_id_t)cred->dwLower;
+}
+
 static inline void credhandle_gss_to_sspi( gss_cred_id_t handle, gss_name_t principal, CredHandle *cred )
 {
     cred->dwLower = (DWORD_PTR)handle;
     cred->dwUpper = (DWORD_PTR)principal;
 }
 
+static inline gss_ctx_id_t ctxthandle_sspi_to_gss( const CtxtHandle *ctxt )
+{
+    if (!ctxt) return GSS_C_NO_CONTEXT;
+    return (gss_ctx_id_t)ctxt->dwLower;
+}
+
+static inline void ctxthandle_gss_to_sspi( gss_ctx_id_t handle, CtxtHandle *ctxt )
+{
+    ctxt->dwLower = (DWORD_PTR)handle;
+}
+
 static SECURITY_STATUS status_gss_to_sspi( OM_uint32 status )
 {
     switch (status)
@@ -147,6 +175,43 @@ static SECURITY_STATUS name_sspi_to_gss( const SEC_WCHAR *name_str, gss_name_t *
     HeapFree( GetProcessHeap(), 0, buf.value );
     return status_gss_to_sspi( ret );
 }
+
+static ULONG flags_isc_req_to_gss( ULONG flags )
+{
+    ULONG ret = GSS_C_DCE_STYLE;
+    if (flags & ISC_REQ_DELEGATE)        ret |= GSS_C_DELEG_FLAG;
+    if (flags & ISC_REQ_MUTUAL_AUTH)     ret |= GSS_C_MUTUAL_FLAG;
+    if (flags & ISC_REQ_REPLAY_DETECT)   ret |= GSS_C_REPLAY_FLAG;
+    if (flags & ISC_REQ_SEQUENCE_DETECT) ret |= GSS_C_SEQUENCE_FLAG;
+    if (flags & ISC_REQ_CONFIDENTIALITY) ret |= GSS_C_CONF_FLAG;
+    if (flags & ISC_REQ_INTEGRITY)       ret |= GSS_C_INTEG_FLAG;
+    if (flags & ISC_REQ_NULL_SESSION)    ret |= GSS_C_ANON_FLAG;
+    return ret;
+}
+
+static ULONG flags_gss_to_isc_ret( ULONG flags )
+{
+    ULONG ret = 0;
+    if (flags & GSS_C_DELEG_FLAG)    ret |= ISC_RET_DELEGATE;
+    if (flags & GSS_C_MUTUAL_FLAG)   ret |= ISC_RET_MUTUAL_AUTH;
+    if (flags & GSS_C_REPLAY_FLAG)   ret |= ISC_RET_REPLAY_DETECT;
+    if (flags & GSS_C_SEQUENCE_FLAG) ret |= ISC_RET_SEQUENCE_DETECT;
+    if (flags & GSS_C_CONF_FLAG)     ret |= ISC_RET_CONFIDENTIALITY;
+    if (flags & GSS_C_INTEG_FLAG)    ret |= ISC_RET_INTEGRITY;
+    if (flags & GSS_C_ANON_FLAG)     ret |= ISC_RET_NULL_SESSION;
+    return ret;
+}
+
+static int get_buffer_index( SecBufferDesc *desc, DWORD type )
+{
+    UINT i;
+    if (!desc) return -1;
+    for (i = 0; i < desc->cBuffers; i++)
+    {
+        if (desc->pBuffers[i].BufferType == type) return i;
+    }
+    return -1;
+}
 #endif
 
 /***********************************************************************
@@ -304,25 +369,102 @@ done:
 /***********************************************************************
  *              InitializeSecurityContextW
  */
-static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW(CredHandle *phCredential, CtxtHandle *phContext, SEC_WCHAR *pszTargetName,
-        ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext,
-        SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
+static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW( CredHandle *phCredential, CtxtHandle *phContext,
+    SEC_WCHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput,
+    ULONG Reserved2, CtxtHandle *phNewContext, SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry )
 {
-    FIXME("(%p %p %s 0x%08x %d %d %p %d %p %p %p %p)\n", phCredential, phContext, debugstr_w(pszTargetName),
-          fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+#ifdef SONAME_LIBGSSAPI_KRB5
+    static const ULONG supported = ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_SEQUENCE_DETECT |
+                                   ISC_REQ_REPLAY_DETECT | ISC_REQ_MUTUAL_AUTH;
+    OM_uint32 ret, minor_status, ret_flags, expiry_time, req_flags = flags_isc_req_to_gss( fContextReq );
+    gss_cred_id_t cred_handle;
+    gss_ctx_id_t ctxt_handle;
+    gss_buffer_desc input_token, output_token;
+    gss_name_t target = GSS_C_NO_NAME;
+    int idx;
+
+    TRACE( "(%p %p %s 0x%08x %u %u %p %u %p %p %p %p)\n", phCredential, phContext, debugstr_w(pszTargetName),
+           fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry );
+    if (fContextReq & ~supported)
+    {
+        FIXME( "flags 0x%08x not supported\n", fContextReq & ~supported );
+        return SEC_E_UNSUPPORTED_FUNCTION;
+    }
+
+    if (!phContext && !pInput && !phCredential) return SEC_E_INVALID_HANDLE;
+    cred_handle = credhandle_sspi_to_gss( phCredential, NULL );
+    ctxt_handle = ctxthandle_sspi_to_gss( phContext );
+
+    if (!pInput) input_token.length = 0;
+    else
+    {
+        if ((idx = get_buffer_index( pInput, SECBUFFER_TOKEN )) == -1) return SEC_E_INVALID_TOKEN;
+        input_token.length = pInput->pBuffers[idx].cbBuffer;
+        input_token.value  = pInput->pBuffers[idx].pvBuffer;
+    }
+
+    if ((idx = get_buffer_index( pOutput, SECBUFFER_TOKEN )) == -1) return SEC_E_INVALID_TOKEN;
+    output_token.length = 0;
+    output_token.value  = NULL;
+
+    if (pszTargetName && ((ret = name_sspi_to_gss( pszTargetName, &target )) != SEC_E_OK)) return ret;
+
+    ret = pgss_init_sec_context( &minor_status, cred_handle, &ctxt_handle, target, GSS_C_NO_OID, req_flags, 0,
+                                 GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, &output_token, &ret_flags,
+                                 &expiry_time );
+    TRACE( "gss_init_sec_context returned %08x minor status %08x ret_flags %08x\n", ret, minor_status, ret_flags );
+    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED)
+    {
+        if (output_token.length > pOutput->pBuffers[idx].cbBuffer) /* FIXME: check if larger buffer exists */
+        {
+            TRACE( "buffer too small %u > %u\n", output_token.length, pOutput->pBuffers[idx].cbBuffer );
+            pgss_release_buffer( &minor_status, &output_token );
+            pgss_delete_sec_context( &minor_status, &ctxt_handle, GSS_C_NO_BUFFER );
+            if (phContext) phContext->dwLower = 0;
+            return SEC_E_INCOMPLETE_MESSAGE;
+        }
+        pOutput->pBuffers[idx].cbBuffer = output_token.length;
+        memcpy( pOutput->pBuffers[idx].pvBuffer, output_token.value, output_token.length );
+        pgss_release_buffer( &minor_status, &output_token );
+
+        ctxthandle_gss_to_sspi( ctxt_handle, phNewContext );
+        if (pfContextAttr) *pfContextAttr = flags_gss_to_isc_ret( ret_flags );
+        expirytime_gss_to_sspi( expiry_time, ptsExpiry );
+    }
+
+    if (target != GSS_C_NO_NAME) pgss_release_name( &minor_status, &target );
+    return status_gss_to_sspi( ret );
+#else
+    FIXME( "(%p %p %s 0x%08x %u %u %p %u %p %p %p %p)\n", phCredential, phContext, debugstr_w(pszTargetName),
+           fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry );
     return SEC_E_UNSUPPORTED_FUNCTION;
+#endif
 }
 
 /***********************************************************************
  *              InitializeSecurityContextA
  */
-static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(CredHandle *phCredential, CtxtHandle *phContext, SEC_CHAR *pszTargetName,
-        ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext,
-        SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
+static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(CredHandle *phCredential, CtxtHandle *phContext,
+    SEC_CHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput,
+    ULONG Reserved2, CtxtHandle *phNewContext, SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
 {
-    FIXME("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext, debugstr_a(pszTargetName), fContextReq,
-          Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
-    return SEC_E_UNSUPPORTED_FUNCTION;
+    SECURITY_STATUS ret;
+    SEC_WCHAR *target = NULL;
+
+    TRACE( "%p %p %s %u %u %u %p %u %p %p %p %p\n", phCredential, phContext, debugstr_a(pszTargetName), fContextReq,
+           Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry );
+
+    if (pszTargetName)
+    {
+        int len = MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, NULL, 0 );
+        if (!(target = HeapAlloc( GetProcessHeap(), 0, len * sizeof(SEC_WCHAR) ))) return SEC_E_INSUFFICIENT_MEMORY;
+        MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, target, len );
+    }
+
+    ret = kerberos_InitializeSecurityContextW( phCredential, phContext, target, fContextReq, Reserved1, TargetDataRep,
+                                               pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry );
+    HeapFree( GetProcessHeap(), 0, target );
+    return ret;
 }
 
 /***********************************************************************
-- 
2.11.0




More information about the wine-patches mailing list