[PATCH 3/3] kerberos: Add support for caller supplied credentials.

Hans Leidekker hans at codeweavers.com
Wed Feb 21 08:22:11 CST 2018


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/kerberos/krb5_ap.c | 198 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 154 insertions(+), 44 deletions(-)

diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c
index 42474eaaea..e51f7ea4f8 100644
--- a/dlls/kerberos/krb5_ap.c
+++ b/dlls/kerberos/krb5_ap.c
@@ -91,21 +91,30 @@ static LSA_DISPATCH_TABLE lsa_dispatch;
 static void *libkrb5_handle;
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p_##f
-MAKE_FUNCPTR(krb5_init_context);
-MAKE_FUNCPTR(krb5_free_context);
-MAKE_FUNCPTR(krb5_free_ticket);
-MAKE_FUNCPTR(krb5_cccol_cursor_new);
-MAKE_FUNCPTR(krb5_cccol_cursor_next);
-MAKE_FUNCPTR(krb5_cccol_cursor_free);
 MAKE_FUNCPTR(krb5_cc_close);
-MAKE_FUNCPTR(krb5_cc_start_seq_get);
+MAKE_FUNCPTR(krb5_cc_default);
 MAKE_FUNCPTR(krb5_cc_end_seq_get);
+MAKE_FUNCPTR(krb5_cc_initialize);
 MAKE_FUNCPTR(krb5_cc_next_cred);
-MAKE_FUNCPTR(krb5_is_config_principal);
+MAKE_FUNCPTR(krb5_cc_start_seq_get);
+MAKE_FUNCPTR(krb5_cc_store_cred);
+MAKE_FUNCPTR(krb5_cccol_cursor_free);
+MAKE_FUNCPTR(krb5_cccol_cursor_new);
+MAKE_FUNCPTR(krb5_cccol_cursor_next);
 MAKE_FUNCPTR(krb5_decode_ticket);
-MAKE_FUNCPTR(krb5_unparse_name_flags);
-MAKE_FUNCPTR(krb5_free_unparsed_name);
+MAKE_FUNCPTR(krb5_free_context);
 MAKE_FUNCPTR(krb5_free_cred_contents);
+MAKE_FUNCPTR(krb5_free_principal);
+MAKE_FUNCPTR(krb5_free_ticket);
+MAKE_FUNCPTR(krb5_free_unparsed_name);
+MAKE_FUNCPTR(krb5_get_init_creds_opt_alloc);
+MAKE_FUNCPTR(krb5_get_init_creds_opt_free);
+MAKE_FUNCPTR(krb5_get_init_creds_opt_set_out_ccache);
+MAKE_FUNCPTR(krb5_get_init_creds_password);
+MAKE_FUNCPTR(krb5_init_context);
+MAKE_FUNCPTR(krb5_is_config_principal);
+MAKE_FUNCPTR(krb5_parse_name_flags);
+MAKE_FUNCPTR(krb5_unparse_name_flags);
 #undef MAKE_FUNCPTR
 
 static void load_krb5(void)
@@ -123,21 +132,30 @@ static void load_krb5(void)
         goto fail; \
     }
 
-    LOAD_FUNCPTR(krb5_init_context)
-    LOAD_FUNCPTR(krb5_free_context)
-    LOAD_FUNCPTR(krb5_free_ticket)
-    LOAD_FUNCPTR(krb5_cccol_cursor_new)
-    LOAD_FUNCPTR(krb5_cccol_cursor_next)
-    LOAD_FUNCPTR(krb5_cccol_cursor_free)
     LOAD_FUNCPTR(krb5_cc_close)
-    LOAD_FUNCPTR(krb5_cc_start_seq_get)
+    LOAD_FUNCPTR(krb5_cc_default)
     LOAD_FUNCPTR(krb5_cc_end_seq_get)
+    LOAD_FUNCPTR(krb5_cc_initialize)
     LOAD_FUNCPTR(krb5_cc_next_cred)
-    LOAD_FUNCPTR(krb5_is_config_principal)
+    LOAD_FUNCPTR(krb5_cc_start_seq_get)
+    LOAD_FUNCPTR(krb5_cc_store_cred)
+    LOAD_FUNCPTR(krb5_cccol_cursor_free)
+    LOAD_FUNCPTR(krb5_cccol_cursor_new)
+    LOAD_FUNCPTR(krb5_cccol_cursor_next)
     LOAD_FUNCPTR(krb5_decode_ticket)
-    LOAD_FUNCPTR(krb5_unparse_name_flags)
-    LOAD_FUNCPTR(krb5_free_unparsed_name)
+    LOAD_FUNCPTR(krb5_free_context)
     LOAD_FUNCPTR(krb5_free_cred_contents)
+    LOAD_FUNCPTR(krb5_free_principal)
+    LOAD_FUNCPTR(krb5_free_ticket)
+    LOAD_FUNCPTR(krb5_free_unparsed_name)
+    LOAD_FUNCPTR(krb5_get_init_creds_opt_alloc)
+    LOAD_FUNCPTR(krb5_get_init_creds_opt_free)
+    LOAD_FUNCPTR(krb5_get_init_creds_opt_set_out_ccache)
+    LOAD_FUNCPTR(krb5_get_init_creds_password)
+    LOAD_FUNCPTR(krb5_init_context)
+    LOAD_FUNCPTR(krb5_is_config_principal)
+    LOAD_FUNCPTR(krb5_parse_name_flags)
+    LOAD_FUNCPTR(krb5_unparse_name_flags)
 #undef LOAD_FUNCPTR
 
     return;
@@ -818,38 +836,96 @@ static int get_buffer_index( SecBufferDesc *desc, DWORD type )
     }
     return -1;
 }
-#endif /* SONAME_LIBGSSAPI_KRB5 */
 
-static NTSTATUS NTAPI kerberos_SpAcquireCredentialsHandle(
-    UNICODE_STRING *principal_us, ULONG credential_use, LUID *logon_id, void *auth_data,
-    void *get_key_fn, void *get_key_arg, LSA_SEC_HANDLE *credential, TimeStamp *ts_expiry )
+static char *get_user_at_domain( const WCHAR *user, ULONG user_len, const WCHAR *domain, ULONG domain_len )
 {
-#ifdef SONAME_LIBGSSAPI_KRB5
-    OM_uint32 ret, minor_status, expiry_time;
-    gss_name_t principal = GSS_C_NO_NAME;
-    gss_cred_usage_t cred_usage;
-    gss_cred_id_t cred_handle;
+    int len_user, len_domain;
+    char *ret;
 
-    TRACE( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us), credential_use,
-           logon_id, auth_data, get_key_fn, get_key_arg, credential, ts_expiry );
+    len_user = WideCharToMultiByte( CP_UNIXCP, 0, user, user_len, NULL, 0, NULL, NULL );
+    len_domain = WideCharToMultiByte( CP_UNIXCP, 0, domain, domain_len, NULL, 0, NULL, NULL );
+    if (!(ret = heap_alloc( len_user + len_domain + 2 ))) return NULL;
+
+    WideCharToMultiByte( CP_UNIXCP, 0, user, user_len, ret, len_user, NULL, NULL );
+    ret[len_user] = '@';
+    WideCharToMultiByte( CP_UNIXCP, 0, domain, domain_len, ret + len_user + 1, len_domain, NULL, NULL );
+    ret[len_user + len_domain + 1] = 0;
+    return ret;
+}
 
-    if (auth_data) FIXME( "specific credentials not supported\n" );
+static char *get_password( const WCHAR *passwd, ULONG passwd_len )
+{
+    int len;
+    char *ret;
 
-    switch (credential_use)
+    len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, passwd, passwd_len, NULL, 0, NULL, NULL );
+    if (!(ret = heap_alloc( len + 1 ))) return NULL;
+    WideCharToMultiByte( CP_UNIXCP, 0, passwd, passwd_len, ret, len, NULL, NULL );
+    ret[len] = 0;
+    return ret;
+}
+
+static NTSTATUS init_creds( const SEC_WINNT_AUTH_IDENTITY_W *id )
+{
+    char *user_at_domain, *password;
+    krb5_context ctx;
+    krb5_principal principal = NULL;
+    krb5_get_init_creds_opt *options = NULL;
+    krb5_ccache cache = NULL;
+    krb5_creds creds;
+    krb5_error_code err;
+
+    if (!id) return STATUS_SUCCESS;
+    if (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
     {
-        case SECPKG_CRED_INBOUND:
-            cred_usage = GSS_C_ACCEPT;
-            break;
-        case SECPKG_CRED_OUTBOUND:
-            cred_usage = GSS_C_INITIATE;
-            break;
-        case SECPKG_CRED_BOTH:
-            cred_usage = GSS_C_BOTH;
-            break;
-        default:
-            return SEC_E_UNKNOWN_CREDENTIALS;
+        FIXME( "ANSI identity not supported\n" );
+        return SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    if (!(user_at_domain = get_user_at_domain( id->User, id->UserLength, id->Domain, id->DomainLength )))
+    {
+        return SEC_E_INSUFFICIENT_MEMORY;
+    }
+    if (!(password = get_password( id->Password, id->PasswordLength )))
+    {
+        heap_free( user_at_domain );
+        return SEC_E_INSUFFICIENT_MEMORY;
     }
 
+    if ((err = p_krb5_init_context( &ctx )))
+    {
+        heap_free( password );
+        heap_free( user_at_domain );
+        return krb5_error_to_status( err );
+    }
+    if ((err = p_krb5_parse_name_flags( ctx, user_at_domain, 0, &principal ))) goto done;
+    if ((err = p_krb5_cc_default( ctx, &cache ))) goto done;
+    if ((err = p_krb5_get_init_creds_opt_alloc( ctx, &options ))) goto done;
+    if ((err = p_krb5_get_init_creds_opt_set_out_ccache( ctx, options, cache ))) goto done;
+    if ((err = p_krb5_get_init_creds_password( ctx, &creds, principal, password, 0, NULL, 0, NULL, 0 ))) goto done;
+    if ((err = p_krb5_cc_initialize( ctx, cache, principal ))) goto done;
+    if ((err = p_krb5_cc_store_cred( ctx, cache, &creds ))) goto done;
+
+    TRACE( "success\n" );
+    p_krb5_free_cred_contents( ctx, &creds );
+
+done:
+    if (cache) p_krb5_cc_close( ctx, cache );
+    if (principal) p_krb5_free_principal( ctx, principal );
+    if (options) p_krb5_get_init_creds_opt_free( ctx, options );
+    p_krb5_free_context( ctx );
+    heap_free( user_at_domain );
+    heap_free( password );
+
+    return krb5_error_to_status( err );
+}
+
+static NTSTATUS acquire_credentials_handle( UNICODE_STRING *principal_us, gss_cred_usage_t cred_usage,
+    LSA_SEC_HANDLE *credential, TimeStamp *ts_expiry )
+{
+    OM_uint32 ret, minor_status, expiry_time;
+    gss_name_t principal = GSS_C_NO_NAME;
+    gss_cred_id_t cred_handle;
+
     if (principal_us && ((ret = name_sspi_to_gss( principal_us, &principal )) != SEC_E_OK)) return ret;
 
     ret = pgss_acquire_cred( &minor_status, principal, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, cred_usage,
@@ -865,6 +941,40 @@ static NTSTATUS NTAPI kerberos_SpAcquireCredentialsHandle(
     if (principal != GSS_C_NO_NAME) pgss_release_name( &minor_status, &principal );
 
     return status_gss_to_sspi( ret );
+}
+#endif /* SONAME_LIBGSSAPI_KRB5 */
+
+static NTSTATUS NTAPI kerberos_SpAcquireCredentialsHandle(
+    UNICODE_STRING *principal_us, ULONG credential_use, LUID *logon_id, void *auth_data,
+    void *get_key_fn, void *get_key_arg, LSA_SEC_HANDLE *credential, TimeStamp *ts_expiry )
+{
+#ifdef SONAME_LIBGSSAPI_KRB5
+    gss_cred_usage_t cred_usage;
+    NTSTATUS status;
+
+    TRACE( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us), credential_use,
+           logon_id, auth_data, get_key_fn, get_key_arg, credential, ts_expiry );
+
+    switch (credential_use)
+    {
+    case SECPKG_CRED_INBOUND:
+        cred_usage = GSS_C_ACCEPT;
+        break;
+
+    case SECPKG_CRED_OUTBOUND:
+        if ((status = init_creds( auth_data )) != STATUS_SUCCESS) return status;
+        cred_usage = GSS_C_INITIATE;
+        break;
+
+    case SECPKG_CRED_BOTH:
+        cred_usage = GSS_C_BOTH;
+        break;
+
+    default:
+        return SEC_E_UNKNOWN_CREDENTIALS;
+    }
+
+    return acquire_credentials_handle( principal_us, cred_usage, credential, ts_expiry );
 #else
     FIXME( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us), credential_use,
            logon_id, auth_data, get_key_fn, get_key_arg, credential, ts_expiry );
-- 
2.11.0




More information about the wine-devel mailing list