Signed-off-by: Hans Leidekker hans@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 );