kerberos: Add support for caller supplied credentials.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2018-02-21 15:22:11 +01:00 committed by Alexandre Julliard
parent 917bf27322
commit a110f87b83
1 changed files with 158 additions and 48 deletions

View File

@ -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_cc_close);
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_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_cccol_cursor_free);
MAKE_FUNCPTR(krb5_cc_close);
MAKE_FUNCPTR(krb5_cc_start_seq_get);
MAKE_FUNCPTR(krb5_cc_end_seq_get);
MAKE_FUNCPTR(krb5_cc_next_cred);
MAKE_FUNCPTR(krb5_is_config_principal);
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_cc_close)
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_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_cccol_cursor_free)
LOAD_FUNCPTR(krb5_cc_close)
LOAD_FUNCPTR(krb5_cc_start_seq_get)
LOAD_FUNCPTR(krb5_cc_end_seq_get)
LOAD_FUNCPTR(krb5_cc_next_cred)
LOAD_FUNCPTR(krb5_is_config_principal)
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 )
{
int len_user, len_domain;
char *ret;
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;
}
static char *get_password( const WCHAR *passwd, ULONG passwd_len )
{
int len;
char *ret;
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)
{
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 )
{
#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;
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 );
if (auth_data) FIXME( "specific credentials not supported\n" );
switch (credential_use)
{
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;
}
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 );