From 4f2fafdec8cd6d517ac01d259f112a61a41c62f7 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Mon, 4 Sep 2017 15:54:34 +0300 Subject: [3/9] kerberos: Add support for KerbQueryTicketCacheMessage. Content-Type: text/plain; charset=UTF-8 Based on the code written by George Popoff. Signed-off-by: Dmitry Timoshkov --- dlls/kerberos/krb5_ap.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++- include/ntsecapi.h | 96 ++++++++++++++++ 2 files changed, 392 insertions(+), 3 deletions(-) diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c index 0134b94f6d..a0b6053af4 100644 --- a/dlls/kerberos/krb5_ap.c +++ b/dlls/kerberos/krb5_ap.c @@ -1,5 +1,6 @@ /* * Copyright 2017 Dmitry Timoshkov + * Copyright 2017 George Popoff * * Kerberos5 Authentication Package * @@ -30,6 +31,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winnls.h" #include "sspi.h" #include "ntsecapi.h" #include "ntsecpkg.h" @@ -48,8 +50,36 @@ 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_cccol_cursor_new); +MAKE_FUNCPTR(krb5_cccol_cursor_next); +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); +MAKE_FUNCPTR(krb5_unparse_name_flags); +MAKE_FUNCPTR(krb5_free_unparsed_name); +MAKE_FUNCPTR(krb5_free_cred_contents); #undef MAKE_FUNCPTR +static void *heap_alloc(SIZE_T size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +static void *heap_realloc(void *p, SIZE_T size) +{ + return HeapReAlloc(GetProcessHeap(), 0, p, size); +} + +static void heap_free(void *p) +{ + HeapFree(GetProcessHeap(), 0, p); +} + static void load_krb5(void) { if (!(libkrb5_handle = wine_dlopen(SONAME_LIBKRB5, RTLD_NOW, NULL, 0))) @@ -66,6 +96,19 @@ static void load_krb5(void) } LOAD_FUNCPTR(krb5_init_context) + LOAD_FUNCPTR(krb5_free_context) + LOAD_FUNCPTR(krb5_cccol_cursor_new) + LOAD_FUNCPTR(krb5_cccol_cursor_next) + 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) + LOAD_FUNCPTR(krb5_unparse_name_flags) + LOAD_FUNCPTR(krb5_free_unparsed_name) + LOAD_FUNCPTR(krb5_free_cred_contents) #undef LOAD_FUNCPTR return; @@ -111,15 +154,265 @@ static NTSTATUS NTAPI krb5_LsaApInitializePackage(ULONG package_id, PLSA_DISPATC return STATUS_SUCCESS; } +static NTSTATUS krb5_error_to_status(krb5_error_code error) +{ + switch (error) + { + case 0: return STATUS_SUCCESS; + + default: + /* FIXME */ + return STATUS_UNSUCCESSFUL; + } +} + +static WCHAR *utf8_to_wstr(const char *utf8) +{ + int size; + WCHAR *wstr; + + size = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + wstr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (wstr) + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, size); + + return wstr; +} + +static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_TICKET_CACHE_INFO *ticket_info) +{ + NTSTATUS status; + krb5_cc_cursor cursor; + krb5_error_code error; + krb5_creds credentials; + krb5_ticket *ticket; + char *name_with_realm; + char *name_without_realm; + char *realm_name; + WCHAR *realm_nameW; + WCHAR *name_without_realmW; + + error = p_krb5_cc_start_seq_get(context, cache, &cursor); + if (error) return krb5_error_to_status(error); + + status = STATUS_SUCCESS; + + for (;;) + { + error = p_krb5_cc_next_cred(context, cache, &cursor, &credentials); + if (error) + { + status = krb5_error_to_status(error); + break; + } + + if (p_krb5_is_config_principal(context, credentials.server)) + { + p_krb5_free_cred_contents(context, &credentials); + continue; + } + + error = p_krb5_unparse_name(context, credentials.server, &name_with_realm); + if (error) + { + p_krb5_free_cred_contents(context, &credentials); + status = krb5_error_to_status(error); + break; + } + + TRACE("name_with_realm: %s\n", debugstr_a(name_with_realm)); + + error = p_krb5_unparse_name_flags(context, credentials.server, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name_without_realm); + if (error) + { + p_krb5_free_unparsed_name(context, name_with_realm); + p_krb5_free_cred_contents(context, &credentials); + status = krb5_error_to_status(error); + break; + } + + TRACE("name_without_realm: %s\n", debugstr_a(name_without_realm)); + + name_without_realmW = utf8_to_wstr(name_without_realm); + RtlInitUnicodeString(&ticket_info->ServerName, name_without_realmW); + + realm_name = name_with_realm; + + /* Increment pointer while not contain realm name */ + do { + ++realm_name; + } while (*realm_name != '@' && *realm_name != '\0'); + ++realm_name; + + /* realm_name - now contains only realm! */ + + realm_nameW = utf8_to_wstr(realm_name); + RtlInitUnicodeString(&ticket_info->RealmName, realm_nameW); + + if (!credentials.times.starttime) + credentials.times.starttime = credentials.times.authtime; + + /* TODO: if krb5_is_config_principal = true */ + RtlSecondsSince1970ToTime(credentials.times.starttime, &ticket_info->StartTime); + RtlSecondsSince1970ToTime(credentials.times.endtime, &ticket_info->EndTime); + RtlSecondsSince1970ToTime(credentials.times.renew_till, &ticket_info->RenewTime); + + ticket_info->TicketFlags = credentials.ticket_flags; + + error = p_krb5_decode_ticket(&credentials.ticket, &ticket); + if (error) + status = krb5_error_to_status(error); + else + { + ticket_info->EncryptionType = ticket->enc_part.enctype; + status = STATUS_SUCCESS; + } + + p_krb5_free_unparsed_name(context, name_with_realm); + p_krb5_free_unparsed_name(context, name_without_realm); + p_krb5_free_cred_contents(context, &credentials); + + break; + } + + p_krb5_cc_end_seq_get(context, cache, &cursor); + + return status; +} + +static NTSTATUS query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req, void *in, ULONG in_len, void **out, ULONG *out_len) +{ + NTSTATUS status; + KERB_QUERY_TKT_CACHE_REQUEST *query; + KERB_QUERY_TKT_CACHE_RESPONSE *resp; + ULONG tickets_allocated; + krb5_error_code error; + krb5_context context = NULL; + krb5_cccol_cursor cursor; + krb5_ccache cache; + + if (!in || in_len != sizeof(KERB_QUERY_TKT_CACHE_REQUEST) || !out || !out_len) + return STATUS_INVALID_PARAMETER; + + query = (KERB_QUERY_TKT_CACHE_REQUEST *)in; + + if (query->LogonId.HighPart != 0 || query->LogonId.LowPart != 0) + return STATUS_ACCESS_DENIED; + + tickets_allocated = 16; + resp = heap_alloc(sizeof(*resp) + sizeof(resp->Tickets[0]) * (tickets_allocated - 1)); + if (!resp) return STATUS_NO_MEMORY; + + resp->MessageType = KerbQueryTicketCacheMessage; + resp->CountOfTickets = 0; + + error = p_krb5_init_context(&context); + if (error) + { + status = krb5_error_to_status(error); + goto done; + } + + error = p_krb5_cccol_cursor_new(context, &cursor); + if (error) + { + status = krb5_error_to_status(error); + goto done; + } + + for (;;) + { + error = p_krb5_cccol_cursor_next(context, cursor, &cache); + if (error || !cache) + { + status = krb5_error_to_status(error); + break; + } + + if (resp->CountOfTickets == tickets_allocated) + { + KERB_QUERY_TKT_CACHE_RESPONSE *new_resp; + + tickets_allocated *= 2; + new_resp = heap_realloc(resp, sizeof(*resp) + sizeof(resp->Tickets[0]) * (tickets_allocated - 1)); + if (!new_resp) + { + status = STATUS_NO_MEMORY; + p_krb5_cc_close(context, cache); + break; + } + + resp = new_resp; + } + + status = copy_ticket_info(context, cache, &resp->Tickets[resp->CountOfTickets]); + if (status == STATUS_SUCCESS) + resp->CountOfTickets++; + + p_krb5_cc_close(context, cache); + } + + if (status) goto done; + + /* FIXME: copy server/realm names to client space as well. + * As long as LSA works in current process space it's OK. + */ + + *out_len = sizeof(*resp); + if (resp->CountOfTickets > 1) + *out_len += sizeof(resp->Tickets[0]) * (resp->CountOfTickets - 1); + status = lsa_dispatch.AllocateClientBuffer(lsa_req, *out_len, out); + if (status) goto done; + + status = lsa_dispatch.CopyToClientBuffer(lsa_req, *out_len, *out, resp); + if (status) + lsa_dispatch.FreeClientBuffer(lsa_req, *out); + +done: + if (context) + p_krb5_free_context(context); + heap_free(resp); + return status; +} + static NTSTATUS NTAPI krb5_LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST request, PVOID in_buffer, PVOID client_buffer_base, ULONG in_buffer_length, PVOID *out_buffer, PULONG out_buffer_length, PNTSTATUS status) { - FIXME("%p,%p,%p,%u,%p,%p,%p: stub\n", request, in_buffer, client_buffer_base, + KERB_PROTOCOL_MESSAGE_TYPE msg; + + TRACE("%p,%p,%p,%u,%p,%p,%p\n", request, in_buffer, client_buffer_base, in_buffer_length, out_buffer, out_buffer_length, status); - *status = STATUS_NOT_IMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + if (!in_buffer || in_buffer_length < sizeof(msg)) + return STATUS_INVALID_PARAMETER; + + msg = *(KERB_PROTOCOL_MESSAGE_TYPE *)in_buffer; + + switch(msg) + { + case KerbQueryTicketCacheMessage: + *status = query_ticket_cache(request, in_buffer, in_buffer_length, out_buffer, out_buffer_length); + break; + + case KerbRetrieveTicketMessage: + FIXME("KerbRetrieveTicketMessage stub\n"); + *status = STATUS_NOT_IMPLEMENTED; + break; + + case KerbPurgeTicketCacheMessage: + FIXME("KerbPurgeTicketCacheMessage stub\n"); + *status = STATUS_NOT_IMPLEMENTED; + break; + + default: /* All other requests should call LsaApCallPackage */ + WARN("%u => access denied\n", msg); + *status = STATUS_ACCESS_DENIED; + break; + } + + return *status; } static SECPKG_FUNCTION_TABLE krb5_table = diff --git a/include/ntsecapi.h b/include/ntsecapi.h index 36357c61b4..3193b10f42 100644 --- a/include/ntsecapi.h +++ b/include/ntsecapi.h @@ -352,6 +352,102 @@ static const WCHAR MICROSOFT_KERBEROS_NAME_W[] = { 'K','e','r','b','e','r','o',' #define MICROSOFT_KERBEROS_NAME_A "Kerberos" #endif +#define KERB_TICKET_FLAGS_reserved 0x80000000 +#define KERB_TICKET_FLAGS_forwardable 0x40000000 +#define KERB_TICKET_FLAGS_forwarded 0x20000000 +#define KERB_TICKET_FLAGS_proxiable 0x10000000 +#define KERB_TICKET_FLAGS_proxy 0x08000000 +#define KERB_TICKET_FLAGS_may_postdate 0x04000000 +#define KERB_TICKET_FLAGS_postdated 0x02000000 +#define KERB_TICKET_FLAGS_invalid 0x01000000 +#define KERB_TICKET_FLAGS_renewable 0x00800000 +#define KERB_TICKET_FLAGS_initial 0x00400000 +#define KERB_TICKET_FLAGS_pre_authent 0x00200000 +#define KERB_TICKET_FLAGS_hw_authent 0x00100000 +#define KERB_TICKET_FLAGS_ok_as_delegate 0x00040000 +#define KERB_TICKET_FLAGS_name_canonicalize 0x00010000 +#define KERB_TICKET_FLAGS_cname_in_pa_data 0x00040000 +#define KERB_TICKET_FLAGS_reserved1 0x00000001 + +typedef enum _KERB_PROTOCOL_MESSAGE_TYPE +{ + KerbDebugRequestMessage = 0, + KerbQueryTicketCacheMessage, + KerbChangeMachinePasswordMessage, + KerbVerifyPacMessage, + KerbRetrieveTicketMessage, + KerbUpdateAddressesMessage, + KerbPurgeTicketCacheMessage, + KerbChangePasswordMessage, + KerbRetrieveEncodedTicketMessage, + KerbDecryptDataMessage, + KerbAddBindingCacheEntryMessage, + KerbSetPasswordMessage, + KerbSetPasswordExMessage, + KerbVerifyCredentialsMessage, + KerbQueryTicketCacheExMessage, + KerbPurgeTicketCacheExMessage, + KerbRefreshSmartcardCredentialsMessage, + KerbAddExtraCredentialsMessage, + KerbQuerySupplementalCredentialsMessage, + KerbTransferCredentialsMessage, + KerbQueryTicketCacheEx2Message, + KerbSubmitTicketMessage, + KerbAddExtraCredentialsExMessage, + KerbQueryKdcProxyCacheMessage, + KerbPurgeKdcProxyCacheMessage, + KerbQueryTicketCacheEx3Message, + KerbCleanupMachinePkinitCredsMessage, + KerbAddBindingCacheEntryExMessage, + KerbQueryBindingCacheMessage, + KerbPurgeBindingCacheMessage, + KerbQueryDomainExtendedPoliciesMessage, + KerbQueryS4U2ProxyCacheMessage +} KERB_PROTOCOL_MESSAGE_TYPE, *PKERB_PROTOCOL_MESSAGE_TYPE; + +typedef struct _KERB_TICKET_CACHE_INFO +{ + UNICODE_STRING ServerName; + UNICODE_STRING RealmName; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + LARGE_INTEGER RenewTime; + LONG EncryptionType; + ULONG TicketFlags; +} KERB_TICKET_CACHE_INFO, *PKERB_TICKET_CACHE_INFO; + +typedef struct _KERB_QUERY_TKT_CACHE_REQUEST +{ + KERB_PROTOCOL_MESSAGE_TYPE MessageType; + LUID LogonId; +} KERB_QUERY_TKT_CACHE_REQUEST, *PKERB_QUERY_TKT_CACHE_REQUEST; + +typedef struct _KERB_QUERY_TKT_CACHE_RESPONSE +{ + KERB_PROTOCOL_MESSAGE_TYPE MessageType; + ULONG CountOfTickets; + KERB_TICKET_CACHE_INFO Tickets[ANYSIZE_ARRAY]; +} KERB_QUERY_TKT_CACHE_RESPONSE, *PKERB_QUERY_TKT_CACHE_RESPONSE; + +typedef struct _KERB_RETRIEVE_TKT_REQUEST +{ + KERB_PROTOCOL_MESSAGE_TYPE MessageType; + LUID LogonId; + UNICODE_STRING TargetName; + ULONG TicketFlags; + ULONG CacheOptions; + LONG EncryptionType; + SecHandle CredentialsHandle; +} KERB_RETRIEVE_TKT_REQUEST, *PKERB_RETRIEVE_TKT_REQUEST; + +typedef struct _KERB_PURGE_TKT_CACHE_REQUEST +{ + KERB_PROTOCOL_MESSAGE_TYPE MessageType; + LUID LogonId; + UNICODE_STRING ServerName; + UNICODE_STRING RealmName; +} KERB_PURGE_TKT_CACHE_REQUEST, *PKERB_PURGE_TKT_CACHE_REQUEST; + #define RtlGenRandom SystemFunction036 #define RtlEncryptMemory SystemFunction040 #define RtlDecryptMemory SystemFunction041 -- 2.15.0 From 59a89a2d862dd456335f1b0a30a4f914422caf7d Mon Sep 17 00:00:00 2001 From: George Popoff Date: Wed, 11 Oct 2017 14:25:15 +0300 Subject: [4/9] add wincred.h include for missing SecHandle definition Content-Type: text/plain; charset=UTF-8 Signed-off-by: Dmitry Timoshkov --- dlls/advapi32/advapi32_misc.h | 1 + dlls/advapi32/tests/lsa.c | 1 + dlls/advapi32/tests/security.c | 1 + dlls/bcrypt/bcrypt_main.c | 1 + dlls/jscript/math.c | 1 + dlls/kerberos/krb5_ap.c | 1 + dlls/msvcrt/misc.c | 1 + dlls/netapi32/netapi32.c | 1 + dlls/rpcrt4/rpcrt4_main.c | 1 + dlls/rpcrt4/tests/rpc.c | 1 + dlls/schannel/lsamode.c | 1 + dlls/schannel/tests/main.c | 1 + dlls/schannel/usermode.c | 1 + dlls/scrrun/filesystem.c | 1 + dlls/secur32/lsa.c | 1 + dlls/secur32/secur32.c | 1 + dlls/wbemprox/builtin.c | 1 + programs/services/rpc.c | 1 + 18 files changed, 18 insertions(+) diff --git a/dlls/advapi32/advapi32_misc.h b/dlls/advapi32/advapi32_misc.h index 7fc02a4a2e..b55ecf4072 100644 --- a/dlls/advapi32/advapi32_misc.h +++ b/dlls/advapi32/advapi32_misc.h @@ -20,6 +20,7 @@ #ifndef __WINE_ADVAPI32MISC_H #define __WINE_ADVAPI32MISC_H +#include "wincred.h" #include "ntsecapi.h" #include "winsvc.h" #include "winnls.h" diff --git a/dlls/advapi32/tests/lsa.c b/dlls/advapi32/tests/lsa.c index d7f2e498ef..939fd488ee 100644 --- a/dlls/advapi32/tests/lsa.c +++ b/dlls/advapi32/tests/lsa.c @@ -25,6 +25,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "winreg.h" #include "ntsecapi.h" #include "sddl.h" diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 446c98fd07..9a31a36f49 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -26,6 +26,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "winerror.h" #include "winternl.h" #include "aclapi.h" diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 2aecfb9a22..02b4328ab3 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -34,6 +34,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "ntsecapi.h" #include "bcrypt.h" diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index ef906f5439..dedadeb23d 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -24,6 +24,7 @@ #include #include "jscript.h" +#include "wincred.h" #include "ntsecapi.h" #include "wine/debug.h" diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c index a0b6053af4..38708ab60a 100644 --- a/dlls/kerberos/krb5_ap.c +++ b/dlls/kerberos/krb5_ap.c @@ -31,6 +31,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "winnls.h" #include "sspi.h" #include "ntsecapi.h" diff --git a/dlls/msvcrt/misc.c b/dlls/msvcrt/misc.c index ba9dd10838..531367edcb 100644 --- a/dlls/msvcrt/misc.c +++ b/dlls/msvcrt/misc.c @@ -25,6 +25,7 @@ #include "msvcrt.h" #include "wine/debug.h" +#include "wincred.h" #include "ntsecapi.h" WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); diff --git a/dlls/netapi32/netapi32.c b/dlls/netapi32/netapi32.c index 1c5f110b82..945995661e 100644 --- a/dlls/netapi32/netapi32.c +++ b/dlls/netapi32/netapi32.c @@ -37,6 +37,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "lm.h" #include "lmaccess.h" #include "lmat.h" diff --git a/dlls/rpcrt4/rpcrt4_main.c b/dlls/rpcrt4/rpcrt4_main.c index d5d349dc58..4775d68526 100644 --- a/dlls/rpcrt4/rpcrt4_main.c +++ b/dlls/rpcrt4/rpcrt4_main.c @@ -40,6 +40,7 @@ #include "windef.h" #include "winerror.h" #include "winbase.h" +#include "wincred.h" #include "winuser.h" #include "winnt.h" #include "winternl.h" diff --git a/dlls/rpcrt4/tests/rpc.c b/dlls/rpcrt4/tests/rpc.c index f026e99de2..9ed2584f45 100644 --- a/dlls/rpcrt4/tests/rpc.c +++ b/dlls/rpcrt4/tests/rpc.c @@ -28,6 +28,7 @@ #include "wine/test.h" #include #include +#include #include #include #include diff --git a/dlls/schannel/lsamode.c b/dlls/schannel/lsamode.c index 96ca240c08..258266c6f0 100644 --- a/dlls/schannel/lsamode.c +++ b/dlls/schannel/lsamode.c @@ -24,6 +24,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "sspi.h" #include "ntsecapi.h" #include "ntsecpkg.h" diff --git a/dlls/schannel/tests/main.c b/dlls/schannel/tests/main.c index 4240dd76cb..9c1f827f58 100644 --- a/dlls/schannel/tests/main.c +++ b/dlls/schannel/tests/main.c @@ -24,6 +24,7 @@ #define WIN32_NO_STATUS #include #include +#include #define SECURITY_WIN32 #include #include diff --git a/dlls/schannel/usermode.c b/dlls/schannel/usermode.c index 0713f822f9..1afa5d5ae6 100644 --- a/dlls/schannel/usermode.c +++ b/dlls/schannel/usermode.c @@ -24,6 +24,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "sspi.h" #include "ntsecapi.h" #include "ntsecpkg.h" diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index 2acef849fa..b6381a62d8 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -24,6 +24,7 @@ #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "ole2.h" #include "olectl.h" #include "dispex.h" diff --git a/dlls/secur32/lsa.c b/dlls/secur32/lsa.c index 1028c18e71..56d574ea4d 100644 --- a/dlls/secur32/lsa.c +++ b/dlls/secur32/lsa.c @@ -26,6 +26,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "winreg.h" #include "sspi.h" #include "ntsecapi.h" diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c index 1e12f3c543..f5d5746171 100644 --- a/dlls/secur32/secur32.c +++ b/dlls/secur32/secur32.c @@ -23,6 +23,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #include "winnls.h" #include "winreg.h" #include "winternl.h" diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c index 826ec4b086..04739649f9 100644 --- a/dlls/wbemprox/builtin.c +++ b/dlls/wbemprox/builtin.c @@ -34,6 +34,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "wincred.h" #ifdef __MINGW32__ # include "winsock2.h" # include "ws2tcpip.h" diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 20c5a2761f..fb70eef561 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include -- 2.15.0 From 484c150d69beec217686fd8d2c17374ec075e75d Mon Sep 17 00:00:00 2001 From: George Popoff Date: Wed, 11 Oct 2017 14:36:36 +0300 Subject: [5/9] kerberos: fix KerbQueryTicketCacheMessage to return all tickets in all ccaches Content-Type: text/plain; charset=UTF-8 Signed-off-by: Dmitry Timoshkov --- dlls/kerberos/krb5_ap.c | 53 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c index 38708ab60a..5238d5a77b 100644 --- a/dlls/kerberos/krb5_ap.c +++ b/dlls/kerberos/krb5_ap.c @@ -54,6 +54,7 @@ MAKE_FUNCPTR(krb5_init_context); MAKE_FUNCPTR(krb5_free_context); 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); @@ -100,6 +101,7 @@ static void load_krb5(void) LOAD_FUNCPTR(krb5_free_context) 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) @@ -160,7 +162,6 @@ static NTSTATUS krb5_error_to_status(krb5_error_code error) switch (error) { case 0: return STATUS_SUCCESS; - default: /* FIXME */ return STATUS_UNSUCCESSFUL; @@ -180,7 +181,8 @@ static WCHAR *utf8_to_wstr(const char *utf8) return wstr; } -static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_TICKET_CACHE_INFO *ticket_info) +static NTSTATUS copy_tickets_info(krb5_context context, krb5_ccache cache, + KERB_TICKET_CACHE_INFO *tickets_info, ULONG tickets_allocated, ULONG *tickets_in_cache) { NTSTATUS status; krb5_cc_cursor cursor; @@ -198,14 +200,13 @@ static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_T status = STATUS_SUCCESS; + *tickets_in_cache = 0; + for (;;) { error = p_krb5_cc_next_cred(context, cache, &cursor, &credentials); if (error) - { - status = krb5_error_to_status(error); break; - } if (p_krb5_is_config_principal(context, credentials.server)) { @@ -213,6 +214,16 @@ static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_T continue; } + TRACE("credential has more tickets!\n"); + + (*tickets_in_cache)++; + if (*tickets_in_cache > tickets_allocated) + { + p_krb5_free_cred_contents(context, &credentials); + /* Indicate that we fill out a ticket_info buffer */ + status = SEC_E_BUFFER_TOO_SMALL; + } + error = p_krb5_unparse_name(context, credentials.server, &name_with_realm); if (error) { @@ -236,7 +247,7 @@ static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_T TRACE("name_without_realm: %s\n", debugstr_a(name_without_realm)); name_without_realmW = utf8_to_wstr(name_without_realm); - RtlInitUnicodeString(&ticket_info->ServerName, name_without_realmW); + RtlInitUnicodeString(&tickets_info->ServerName, name_without_realmW); realm_name = name_with_realm; @@ -249,24 +260,24 @@ static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_T /* realm_name - now contains only realm! */ realm_nameW = utf8_to_wstr(realm_name); - RtlInitUnicodeString(&ticket_info->RealmName, realm_nameW); + RtlInitUnicodeString(&tickets_info->RealmName, realm_nameW); if (!credentials.times.starttime) credentials.times.starttime = credentials.times.authtime; /* TODO: if krb5_is_config_principal = true */ - RtlSecondsSince1970ToTime(credentials.times.starttime, &ticket_info->StartTime); - RtlSecondsSince1970ToTime(credentials.times.endtime, &ticket_info->EndTime); - RtlSecondsSince1970ToTime(credentials.times.renew_till, &ticket_info->RenewTime); + RtlSecondsSince1970ToTime(credentials.times.starttime, &tickets_info->StartTime); + RtlSecondsSince1970ToTime(credentials.times.endtime, &tickets_info->EndTime); + RtlSecondsSince1970ToTime(credentials.times.renew_till, &tickets_info->RenewTime); - ticket_info->TicketFlags = credentials.ticket_flags; + tickets_info->TicketFlags = credentials.ticket_flags; error = p_krb5_decode_ticket(&credentials.ticket, &ticket); if (error) status = krb5_error_to_status(error); else { - ticket_info->EncryptionType = ticket->enc_part.enctype; + tickets_info->EncryptionType = ticket->enc_part.enctype; status = STATUS_SUCCESS; } @@ -274,7 +285,8 @@ static NTSTATUS copy_ticket_info(krb5_context context, krb5_ccache cache, KERB_T p_krb5_free_unparsed_name(context, name_without_realm); p_krb5_free_cred_contents(context, &credentials); - break; + /* fill next ticket in ccache */ + tickets_info++; } p_krb5_cc_end_seq_get(context, cache, &cursor); @@ -288,6 +300,7 @@ static NTSTATUS query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req, void *in, ULONG KERB_QUERY_TKT_CACHE_REQUEST *query; KERB_QUERY_TKT_CACHE_RESPONSE *resp; ULONG tickets_allocated; + ULONG tickets_in_cache; krb5_error_code error; krb5_context context = NULL; krb5_cccol_cursor cursor; @@ -331,6 +344,8 @@ static NTSTATUS query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req, void *in, ULONG break; } + TRACE("Found another ccache!\n"); + if (resp->CountOfTickets == tickets_allocated) { KERB_QUERY_TKT_CACHE_RESPONSE *new_resp; @@ -347,15 +362,22 @@ static NTSTATUS query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req, void *in, ULONG resp = new_resp; } - status = copy_ticket_info(context, cache, &resp->Tickets[resp->CountOfTickets]); + tickets_in_cache = 0; + status = copy_tickets_info(context, cache, &resp->Tickets[resp->CountOfTickets], + tickets_allocated - resp->CountOfTickets, &tickets_in_cache); + if (status == STATUS_SUCCESS) - resp->CountOfTickets++; + resp->CountOfTickets += tickets_in_cache; + else if (status == STATUS_BUFFER_TOO_SMALL) + FIXME("Too many tickets in ccache, some tickets may be ommited\n"); p_krb5_cc_close(context, cache); } if (status) goto done; + p_krb5_cccol_cursor_free(context, &cursor); + /* FIXME: copy server/realm names to client space as well. * As long as LSA works in current process space it's OK. */ @@ -373,6 +395,7 @@ static NTSTATUS query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req, void *in, ULONG done: if (context) p_krb5_free_context(context); + heap_free(resp); return status; } -- 2.15.0 From f0c2b891d3271472fa9cf424c7c643ee13eeb0b7 Mon Sep 17 00:00:00 2001 From: George Popoff Date: Wed, 11 Oct 2017 14:38:48 +0300 Subject: [6/9] add terminating null to kerberos name variable Content-Type: text/plain; charset=UTF-8 Signed-off-by: Dmitry Timoshkov --- include/ntsecapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ntsecapi.h b/include/ntsecapi.h index 3193b10f42..f7c8a5451c 100644 --- a/include/ntsecapi.h +++ b/include/ntsecapi.h @@ -349,7 +349,7 @@ typedef enum _POLICY_NOTIFICATION_INFORMATION_CLASS static const WCHAR MICROSOFT_KERBEROS_NAME_W[] = { 'K','e','r','b','e','r','o','s',0 }; #endif #else /* UNICODE */ -#define MICROSOFT_KERBEROS_NAME_A "Kerberos" +static const char MICROSOFT_KERBEROS_NAME_A[] = { 'K','e','r','b','e','r','o','s',0 }; #endif #define KERB_TICKET_FLAGS_reserved 0x80000000 -- 2.15.0 From 0cb7ea40c604071f003b2f548bf732fb33bf3f75 Mon Sep 17 00:00:00 2001 From: George Popoff Date: Wed, 11 Oct 2017 14:53:11 +0300 Subject: [7/9] create new kerberos ssp based on GSSAPI ssp. Delete old. Content-Type: text/plain; charset=UTF-8 Signed-off-by: Dmitry Timoshkov --- configure | 68 +++ configure.ac | 10 + dlls/kerberos/Makefile.in | 3 +- dlls/kerberos/kerberos.spec | 2 + dlls/kerberos/krb5_ssp.c | 1304 +++++++++++++++++++++++++++++++++++++++++++ dlls/secur32/Makefile.in | 1 - dlls/secur32/kerberos.c | 323 ----------- dlls/secur32/secur32.c | 33 +- include/config.h.in | 6 + loader/wine.inf.in | 2 + 10 files changed, 1411 insertions(+), 341 deletions(-) create mode 100644 dlls/kerberos/krb5_ssp.c delete mode 100644 dlls/secur32/kerberos.c diff --git a/configure b/configure index 0f6a849c58..8a6c2315e5 100755 --- a/configure +++ b/configure @@ -7024,6 +7024,8 @@ for ac_header in \ grp.h \ gsm.h \ gsm/gsm.h \ + gssapi/gssapi.h \ + gssapi/gssapi_krb5.h \ ieeefp.h \ inet/mib2.h \ io.h \ @@ -14576,6 +14578,72 @@ esac fi +if test "$ac_cv_header_gssapi_gssapi_krb5_h" = "yes" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lgssapi_krb5" >&5 +$as_echo_n "checking for -lgssapi_krb5... " >&6; } +if ${ac_cv_lib_soname_gssapi_krb5+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_soname_save_LIBS=$LIBS +LIBS="-lgssapi_krb5 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gss_init_sec_context (); +int +main () +{ +return gss_init_sec_context (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_gssapi_krb5=`$ac_cv_path_LDD conftest.exe | grep "gssapi_krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_gssapi_krb5=`$OTOOL -L conftest$ac_exeext | grep "libgssapi_krb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgssapi_krb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_gssapi_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgssapi_krb5\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_gssapi_krb5:+false} :; then : + ac_cv_lib_soname_gssapi_krb5=`$LDD conftest$ac_exeext | grep "libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\(libgssapi_krb5\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` +fi ;; + esac +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS +fi +if ${ac_cv_lib_soname_gssapi_krb5:+false} :; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gssapi_krb5" >&5 +$as_echo "$ac_cv_lib_soname_gssapi_krb5" >&6; } + +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBGSSAPI_KRB5 "$ac_cv_lib_soname_gssapi_krb5" +_ACEOF + + +fi +fi +if test "x$ac_cv_lib_soname_gssapi_krb5" = "x"; then : + case "x$with_gssapi_krb5" in + x) as_fn_append wine_notices "|libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported." ;; + xno) ;; + *) as_fn_error $? "libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported. +This is an error since --with-gssapi_krb5 was requested." "$LINENO" 5 ;; +esac + +fi + if test "x$with_jpeg" != "xno" then if ${JPEG_CFLAGS:+false} :; then : diff --git a/configure.ac b/configure.ac index 0e1a0a1ee7..4c2a1b46bc 100644 --- a/configure.ac +++ b/configure.ac @@ -437,6 +437,8 @@ AC_CHECK_HEADERS(\ grp.h \ gsm.h \ gsm/gsm.h \ + gssapi/gssapi.h \ + gssapi/gssapi_krb5.h \ ieeefp.h \ inet/mib2.h \ io.h \ @@ -1732,6 +1734,14 @@ fi WINE_NOTICE_WITH(krb5,[test "x$ac_cv_lib_soname_krb5" = "x"], [libkrb5 ${notice_platform}development files not found, Kerberos won't be supported.]) +dnl **** Check for libgssapi_krb5 **** +if test "$ac_cv_header_gssapi_gssapi_krb5_h" = "yes" +then + WINE_CHECK_SONAME(gssapi_krb5,gss_init_sec_context) +fi +WINE_NOTICE_WITH(gssapi_krb5,[test "x$ac_cv_lib_soname_gssapi_krb5" = "x"], + [libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported.]) + dnl **** Check for libjpeg **** if test "x$with_jpeg" != "xno" then diff --git a/dlls/kerberos/Makefile.in b/dlls/kerberos/Makefile.in index 253e944716..ec095efd87 100644 --- a/dlls/kerberos/Makefile.in +++ b/dlls/kerberos/Makefile.in @@ -2,4 +2,5 @@ MODULE = kerberos.dll EXTRAINCL = $(KRB5_CFLAGS) C_SRCS = \ - krb5_ap.c + krb5_ap.c \ + krb5_ssp.c diff --git a/dlls/kerberos/kerberos.spec b/dlls/kerberos/kerberos.spec index c41b830e46..8bb2fa1c8d 100644 --- a/dlls/kerberos/kerberos.spec +++ b/dlls/kerberos/kerberos.spec @@ -1,4 +1,6 @@ 1 stub SpInitialize +@ stdcall InitSecurityInterfaceA() +@ stdcall InitSecurityInterfaceW() 2 stub KerbDomainChangeCallback 3 stdcall SpLsaModeInitialize(long ptr ptr ptr) 4 stub SpUserModeInitialize diff --git a/dlls/kerberos/krb5_ssp.c b/dlls/kerberos/krb5_ssp.c new file mode 100644 index 0000000000..cfb408edbb --- /dev/null +++ b/dlls/kerberos/krb5_ssp.c @@ -0,0 +1,1304 @@ +/* + * Kerberos API based on GSSAPI SSP + * + * Copyright 2005, 2006 Kai Blin + * Copyright 2008 Robert Shearman for CodeWeavers + * Copyright 2016 Jacek Caban for CodeWeavers + * Copyright 2017 George Popoff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include +#include + +#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#include +#endif + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wincred.h" +#include "rpc.h" +#include "sspi.h" +#include "lm.h" +#include "wine/unicode.h" +#include "wine/library.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(kerberos); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +#define MAKE_FUNCPTR(f) static typeof(f) * p_##f +MAKE_FUNCPTR(gss_import_name); +MAKE_FUNCPTR(gss_acquire_cred); +MAKE_FUNCPTR(gss_release_name); +MAKE_FUNCPTR(gss_init_sec_context); +MAKE_FUNCPTR(gss_accept_sec_context); +MAKE_FUNCPTR(gss_delete_sec_context); +MAKE_FUNCPTR(gss_get_mic); +MAKE_FUNCPTR(gss_verify_mic); +MAKE_FUNCPTR(gss_release_cred); +MAKE_FUNCPTR(gss_wrap); +MAKE_FUNCPTR(gss_unwrap); +#undef MAKE_FUNCPTR + +#define GSS_KERBEROS_MAX_BUF 1904 + +#define KERBEROS_MAGIC ('K' << 24 | 'E' << 16 | 'R' << 8 | 'B') + +#define GSS_KERBEROS_COMMENT \ + { 'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', ' ', \ + 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \ + 'P', 'a', 'c', 'k', 'a', 'g', 'e', 0} + +static CHAR kerberos_comment_A[] = GSS_KERBEROS_COMMENT; +static WCHAR kerberos_comment_W[] = GSS_KERBEROS_COMMENT; + +#define GSS_KERBEROS_NAME {'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', 0} + +static char kerberos_name_A[] = GSS_KERBEROS_NAME; +static WCHAR kerberos_name_W[] = GSS_KERBEROS_NAME; + +/* FIXME */ +#define CAPS ( \ + SECPKG_FLAG_INTEGRITY | \ + SECPKG_FLAG_PRIVACY | \ + SECPKG_FLAG_TOKEN_ONLY | \ + SECPKG_FLAG_CONNECTION | \ + SECPKG_FLAG_MULTI_REQUIRED | \ + SECPKG_FLAG_IMPERSONATION | \ + SECPKG_FLAG_ACCEPT_WIN32_NAME | \ + SECPKG_FLAG_READONLY_WITH_CHECKSUM) + + +static SecPkgInfoW infoW = { + CAPS, + 1, + RPC_C_AUTHN_GSS_KERBEROS, + GSS_KERBEROS_MAX_BUF, + kerberos_name_W, + kerberos_comment_W +}; + +static SecPkgInfoA infoA = { + CAPS, + 1, + RPC_C_AUTHN_GSS_KERBEROS, + GSS_KERBEROS_MAX_BUF, + kerberos_name_A, + kerberos_comment_A +}; + + +SecPkgInfoA *kerberos_package_infoA = (SecPkgInfoA *)&infoA; +SecPkgInfoW *kerberos_package_infoW = (SecPkgInfoW *)&infoW; + +static BOOL load_gssapi(void) +{ + void *libgssapi_handle; + + if (!(libgssapi_handle = wine_dlopen(SONAME_LIBGSSAPI_KRB5, RTLD_NOW, NULL, 0))) + { + ERR_(winediag)("failed to load libgssapi\n" ); + return FALSE; + } + +#define LOAD_FUNCPTR(f) \ + if (!(p_##f = wine_dlsym(libgssapi_handle, #f, NULL, 0))) \ + { \ + ERR("failed to load %s\n", #f); \ + goto fail; \ + } + + LOAD_FUNCPTR(gss_import_name); + LOAD_FUNCPTR(gss_acquire_cred); + LOAD_FUNCPTR(gss_release_name); + LOAD_FUNCPTR(gss_init_sec_context); + LOAD_FUNCPTR(gss_accept_sec_context); + LOAD_FUNCPTR(gss_delete_sec_context); + LOAD_FUNCPTR(gss_get_mic); + LOAD_FUNCPTR(gss_verify_mic); + LOAD_FUNCPTR(gss_release_cred); + LOAD_FUNCPTR(gss_wrap); + LOAD_FUNCPTR(gss_unwrap); +#undef LOAD_FUNCPTR + + return TRUE; + +fail: + wine_dlclose(libgssapi_handle, NULL, 0); + return FALSE; +} + +static inline gss_cred_id_t kerberos_CredHandleSSPItoGSSAPI(const CredHandle *phCredential) +{ + return (gss_cred_id_t)phCredential->dwLower; +} + +static inline void kerberos_CredHandleGSSAPItoSSPI(gss_cred_id_t cred_handle, PCredHandle phCredential) +{ + phCredential->dwLower = (DWORD)cred_handle; + phCredential->dwUpper = KERBEROS_MAGIC; +} + +static inline gss_ctx_id_t kerberos_CtxtHandleSSPItoGSSAPI(const CtxtHandle *phCredential) +{ + return (gss_ctx_id_t)phCredential->dwLower; +} + +static inline void kerberos_CtxtHandleGSSAPItoSSPI(gss_ctx_id_t ctx_handle, PCtxtHandle phCredential) +{ + phCredential->dwLower = (DWORD)ctx_handle; + phCredential->dwUpper = KERBEROS_MAGIC; +} + +static inline void kerberos_CtxtAttrsGSSPItoSSPI(OM_uint32 ret_flags, PULONG pfContextAttr) +{ + *pfContextAttr = 0; + + if (ret_flags & GSS_C_DELEG_FLAG) + *pfContextAttr |= ISC_RET_DELEGATE; + if (ret_flags & GSS_C_MUTUAL_FLAG) + *pfContextAttr |= ISC_RET_MUTUAL_AUTH; + if (ret_flags & GSS_C_REPLAY_FLAG) + *pfContextAttr |= ISC_RET_REPLAY_DETECT; + if (ret_flags & GSS_C_SEQUENCE_FLAG) + *pfContextAttr |= ISC_RET_SEQUENCE_DETECT; + if (ret_flags & GSS_C_CONF_FLAG) + *pfContextAttr |= ISC_RET_CONFIDENTIALITY; + if (ret_flags & GSS_C_INTEG_FLAG) + *pfContextAttr |= ISC_RET_INTEGRITY; + if (ret_flags & GSS_C_ANON_FLAG) + *pfContextAttr |= ISC_RET_NULL_SESSION; +} + +static inline OM_uint32 kerberos_CtxtAttrsSSPItoGSSAPI(ULONG fContextAttr) +{ + OM_uint32 ret_flags = 0; + + if (fContextAttr & ISC_RET_DELEGATE) + ret_flags |= GSS_C_DELEG_FLAG; + if (fContextAttr & ISC_RET_MUTUAL_AUTH) + ret_flags |= GSS_C_MUTUAL_FLAG; + if (fContextAttr & ISC_RET_REPLAY_DETECT) + ret_flags |= GSS_C_REPLAY_FLAG; + if (fContextAttr & ISC_RET_SEQUENCE_DETECT) + ret_flags |= GSS_C_SEQUENCE_FLAG; + if (fContextAttr & ISC_RET_CONFIDENTIALITY) + ret_flags |= GSS_C_CONF_FLAG; + if (fContextAttr & ISC_RET_INTEGRITY) + ret_flags |= GSS_C_INTEG_FLAG; + if (fContextAttr & ISC_RET_NULL_SESSION) + ret_flags |= GSS_C_ANON_FLAG; + + return ret_flags; +} + +static inline OM_uint32 kerberos_CtxtReqsSSPItoGSSAPI(ULONG fRequirements) +{ + OM_uint32 req_flags = 0; + + if (fRequirements & ISC_REQ_DELEGATE) + req_flags |= GSS_C_DELEG_FLAG; + if (fRequirements & ISC_REQ_MUTUAL_AUTH) + req_flags |= GSS_C_MUTUAL_FLAG; + if (fRequirements & ISC_REQ_REPLAY_DETECT) + req_flags |= GSS_C_REPLAY_FLAG; + if (fRequirements & ISC_REQ_SEQUENCE_DETECT) + req_flags |= GSS_C_SEQUENCE_FLAG; + if (fRequirements & ISC_REQ_CONFIDENTIALITY) + req_flags |= GSS_C_CONF_FLAG; + if (fRequirements & ISC_REQ_INTEGRITY) + req_flags |= GSS_C_INTEG_FLAG; + if (fRequirements & ISC_REQ_NULL_SESSION) + req_flags |= GSS_C_ANON_FLAG; + + return req_flags; +} + +static inline void kerberos_CtxtReqsGSSAPItoSSPI(OM_uint32 req_flags, PULONG pfRequirements) +{ + *pfRequirements = 0; + + if (req_flags & GSS_C_DELEG_FLAG) + *pfRequirements |= ISC_REQ_DELEGATE; + if (req_flags & GSS_C_MUTUAL_FLAG) + *pfRequirements |= ISC_REQ_MUTUAL_AUTH; + if (req_flags & GSS_C_REPLAY_FLAG) + *pfRequirements |= ISC_REQ_REPLAY_DETECT; + if (req_flags & GSS_C_SEQUENCE_FLAG) + *pfRequirements |= ISC_REQ_SEQUENCE_DETECT; + if (req_flags & GSS_C_CONF_FLAG) + *pfRequirements |= ISC_REQ_CONFIDENTIALITY; + if (req_flags & GSS_C_INTEG_FLAG) + *pfRequirements |= ISC_REQ_INTEGRITY; + if (req_flags & GSS_C_ANON_FLAG) + *pfRequirements |= ISC_REQ_NULL_SESSION; +} + +static SECURITY_STATUS kerberos_GSSAPIStatusToSecurityStatus(OM_uint32 status) +{ + switch (status) + { + case GSS_S_COMPLETE: return SEC_E_OK; + case GSS_S_BAD_MECH: return SEC_E_SECPKG_NOT_FOUND; + case GSS_S_BAD_SIG: return SEC_E_MESSAGE_ALTERED; + case GSS_S_NO_CRED: return SEC_E_NO_CREDENTIALS; + case GSS_S_NO_CONTEXT: return SEC_E_INVALID_HANDLE; + case GSS_S_DEFECTIVE_TOKEN: return SEC_E_MESSAGE_ALTERED; + case GSS_S_DEFECTIVE_CREDENTIAL: return SEC_E_INVALID_TOKEN; + case GSS_S_CREDENTIALS_EXPIRED: return SEC_E_CONTEXT_EXPIRED; + case GSS_S_CONTEXT_EXPIRED: return SEC_E_CONTEXT_EXPIRED; + case GSS_S_BAD_QOP: return SEC_E_QOP_NOT_SUPPORTED; + + case GSS_S_CONTINUE_NEEDED: return SEC_I_CONTINUE_NEEDED; + case GSS_S_DUPLICATE_TOKEN: return SEC_E_INVALID_TOKEN; + case GSS_S_OLD_TOKEN: return SEC_E_INVALID_TOKEN; + case GSS_S_UNSEQ_TOKEN: return SEC_E_OUT_OF_SEQUENCE; + case GSS_S_GAP_TOKEN: return SEC_E_OUT_OF_SEQUENCE; + + default: + FIXME("couldn't convert status 0x%x to SECURITY_STATUS\n", status); + + return SEC_E_INTERNAL_ERROR; + } +} + +/*********************************************************************** + * EnumerateSecurityPackagesW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_EnumerateSecurityPackagesW( + PULONG pcPackages, PSecPkgInfoW *ppPackageInfo) +{ + *pcPackages = 1; + *ppPackageInfo = &infoW; + + return SEC_E_OK; +} + +/*********************************************************************** + * EnumerateSecurityPackagesA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_EnumerateSecurityPackagesA( + PULONG pcPackages, PSecPkgInfoA *ppPackageInfo) +{ + *pcPackages = 1; + *ppPackageInfo = &infoA; + + return SEC_E_OK; +} + +/*********************************************************************** + * QueryCredentialsAttributesA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA( + PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) +{ + SECURITY_STATUS ret; + + TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); + + if(ulAttribute == SECPKG_ATTR_NAMES) + { + FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + ret = SEC_E_UNSUPPORTED_FUNCTION; + + return ret; +} + +/*********************************************************************** + * QueryCredentialsAttributesW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW( + PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) +{ + SECURITY_STATUS ret; + + TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); + + if(ulAttribute == SECPKG_ATTR_NAMES) + { + FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + ret = SEC_E_UNSUPPORTED_FUNCTION; + + return ret; +} + +static void kerberos_ExpiryTimeToTimeStamp(OM_uint32 expiry_time, PTimeStamp ptsExpiry) +{ + SYSTEMTIME current_local_time; + FILETIME current_local_filetime; + ULARGE_INTEGER temp; + GetLocalTime(¤t_local_time); + SystemTimeToFileTime(¤t_local_time, ¤t_local_filetime); + temp.QuadPart = ((ULONGLONG)current_local_filetime.dwLowDateTime | + (ULONGLONG)current_local_filetime.dwHighDateTime << 32) + + expiry_time; + ptsExpiry->LowPart = temp.QuadPart; + ptsExpiry->HighPart = temp.QuadPart >> 32; +} + +/*********************************************************************** + * AcquireCredentialsHandleW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW( + SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, + PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, + PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) +{ + OM_uint32 ret; + OM_uint32 minor_status; + gss_name_t principal_name = GSS_C_NO_NAME; + gss_cred_usage_t cred_usage; + gss_cred_id_t cred_handle; + OM_uint32 expiry_time; + + TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", + debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); + + if (pAuthData) + { + /* gssapi has no way to specify the credentials to use, so we just + * return an error when the caller tries to do so */ + FIXME("specific credentials not supported\n"); + return SEC_E_UNKNOWN_CREDENTIALS; + } + + switch (fCredentialUse) + { + 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: + phCredential = NULL; + return SEC_E_UNKNOWN_CREDENTIALS; + } + + if (pszPrincipal) + { + char *principal_name_str; + int len; + gss_buffer_desc name_buffer; + + len = WideCharToMultiByte(CP_UNIXCP, 0, pszPrincipal, -1, NULL, 0, NULL, NULL); + principal_name_str = HeapAlloc(GetProcessHeap(), 0, len); + if (!principal_name_str) + return SEC_E_INSUFFICIENT_MEMORY; + WideCharToMultiByte(CP_UNIXCP, 0, pszPrincipal, -1, principal_name_str, len, NULL, NULL); + + name_buffer.length = len-1; + name_buffer.value = principal_name_str; + + ret = p_gss_import_name(&minor_status, &name_buffer, + GSS_C_NULL_OID /* FIXME: detect the appropriate value for this ourselves? */, + &principal_name); + HeapFree(GetProcessHeap(), 0, principal_name_str); + + if (ret != GSS_S_COMPLETE) + return kerberos_GSSAPIStatusToSecurityStatus(ret); + } + + ret = p_gss_acquire_cred(&minor_status, principal_name, GSS_C_INDEFINITE, + GSS_C_NULL_OID_SET /* FIXME: gss_mech_set_krb5 */, cred_usage, &cred_handle, + NULL, &expiry_time); + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) + { + if (ptsExpiry != NULL) { + kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry); + kerberos_CredHandleGSSAPItoSSPI(cred_handle, phCredential); + } + } + + if (principal_name != GSS_C_NO_NAME) + p_gss_release_name(&minor_status, &principal_name); + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * AcquireCredentialsHandleA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA( + SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, + PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, + PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) +{ + SECURITY_STATUS ret; + int user_sizeW, domain_sizeW, passwd_sizeW; + + SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL; + + PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL; + PSEC_WINNT_AUTH_IDENTITY_A identity = NULL; + + TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", + debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); + + if(pszPackage != NULL) + { + int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, + NULL, 0); + + package = HeapAlloc(GetProcessHeap(), 0, package_sizeW * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW); + } + + + if(pAuthData != NULL) + { + identity = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData; + + if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) + { + pAuthDataW = HeapAlloc(GetProcessHeap(), 0, + sizeof(SEC_WINNT_AUTH_IDENTITY_W)); + + if(identity->UserLength != 0) + { + user_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->User, identity->UserLength, NULL, 0); + user = HeapAlloc(GetProcessHeap(), 0, user_sizeW * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User, + identity->UserLength, user, user_sizeW); + } + else + { + user_sizeW = 0; + } + + if(identity->DomainLength != 0) + { + domain_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->Domain, identity->DomainLength, NULL, 0); + domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW + * sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain, + identity->DomainLength, domain, domain_sizeW); + } + else + { + domain_sizeW = 0; + } + + if(identity->PasswordLength != 0) + { + passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, + (LPCSTR)identity->Password, identity->PasswordLength, + NULL, 0); + passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW + * sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password, + identity->PasswordLength, passwd, passwd_sizeW); + } + else + { + passwd_sizeW = 0; + } + + pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + pAuthDataW->User = user; + pAuthDataW->UserLength = user_sizeW; + pAuthDataW->Domain = domain; + pAuthDataW->DomainLength = domain_sizeW; + pAuthDataW->Password = passwd; + pAuthDataW->PasswordLength = passwd_sizeW; + } + else + { + pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity; + } + } + + ret = kerberos_AcquireCredentialsHandleW(NULL, package, fCredentialUse, + pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential, + ptsExpiry); + + HeapFree(GetProcessHeap(), 0, package); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, domain); + HeapFree(GetProcessHeap(), 0, passwd); + if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity) + HeapFree(GetProcessHeap(), 0, pAuthDataW); + + return ret; +} + +/************************************************************************* + * kerberos_GetTokenBufferIndex + * Calculates the index of the secbuffer with BufferType == SECBUFFER_TOKEN + * Returns index if found or -1 if not found. + */ +static int kerberos_GetTokenBufferIndex(PSecBufferDesc pMessage) +{ + UINT i; + + TRACE("%p\n", pMessage); + + for( i = 0; i < pMessage->cBuffers; ++i ) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) + return i; + } + + return -1; +} + +/************************************************************************* + * kerberos_GetDataBufferIndex + * Calculates the index of the first secbuffer with BufferType == SECBUFFER_DATA + * Returns index if found or -1 if not found. + */ +static int kerberos_GetDataBufferIndex(PSecBufferDesc pMessage) +{ + UINT i; + + TRACE("%p\n", pMessage); + + for( i = 0; i < pMessage->cBuffers; ++i ) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA) + return i; + } + + return -1; +} + +/*********************************************************************** + * InitializeSecurityContextW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW( + PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, + ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, + PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) +{ + int output_token_idx; + OM_uint32 ret; + OM_uint32 minor_status; + gss_cred_id_t cred_handle; + gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; + OM_uint32 req_flags = 0; + OM_uint32 ret_flags; + gss_buffer_desc input_token; + gss_buffer_desc output_token; + OM_uint32 expiry_time; + gss_name_t target_name = GSS_C_NO_NAME; + + TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext, + debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, + Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); + + if (!phContext && !pInput) + { + if (!phCredential) + return SEC_E_INVALID_HANDLE; + cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential); + } + else + { + cred_handle = GSS_C_NO_CREDENTIAL; + + if (phContext) + { + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + } + } + + input_token.length = 0; + if (pInput) + { + int input_token_idx = kerberos_GetTokenBufferIndex(pInput); + if (input_token_idx == -1) + return SEC_E_INVALID_TOKEN; + input_token.length = pInput->pBuffers[input_token_idx].cbBuffer; + input_token.value = pInput->pBuffers[input_token_idx].pvBuffer; + } + + req_flags = kerberos_CtxtReqsSSPItoGSSAPI(fContextReq); + + output_token_idx = kerberos_GetTokenBufferIndex(pOutput); + if (output_token_idx == -1) + return SEC_E_INVALID_TOKEN; + + output_token.length = pOutput->pBuffers[output_token_idx].cbBuffer; + output_token.value = pOutput->pBuffers[output_token_idx].pvBuffer; + + if (pszTargetName) + { + char *target_name_str; + int len; + gss_buffer_desc name_buffer; + + len = WideCharToMultiByte(CP_UNIXCP, 0, pszTargetName, -1, NULL, 0, NULL, NULL); + target_name_str = HeapAlloc(GetProcessHeap(), 0, len); + if (!target_name_str) + return SEC_E_INSUFFICIENT_MEMORY; + WideCharToMultiByte(CP_UNIXCP, 0, pszTargetName, -1, target_name_str, len, NULL, NULL); + + name_buffer.length = len-1; + name_buffer.value = target_name_str; + + ret = p_gss_import_name(&minor_status, &name_buffer, + GSS_C_NULL_OID /* FIXME: detect the appropriate value for this ourselves? */, + &target_name); + HeapFree(GetProcessHeap(), 0, target_name_str); + + if (ret != GSS_S_COMPLETE) + return kerberos_GSSAPIStatusToSecurityStatus(ret); + } + + ret = p_gss_init_sec_context(&minor_status, cred_handle, &context_handle, + target_name, GSS_C_NO_OID, req_flags, 0, + GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, + &output_token, &ret_flags, &expiry_time); + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) + { + kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry); + kerberos_CtxtHandleGSSAPItoSSPI(context_handle, phNewContext); + + if (pfContextAttr) + { + kerberos_CtxtAttrsGSSPItoSSPI(ret_flags, pfContextAttr); + } + } + + if (target_name != GSS_C_NO_NAME) + p_gss_release_name(&minor_status, &target_name); + + pOutput->pBuffers[output_token_idx].cbBuffer = (ULONG) output_token.length; + pOutput->pBuffers[output_token_idx].pvBuffer = output_token.value; + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * InitializeSecurityContextA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA( + PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, + ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, + PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) +{ + SECURITY_STATUS ret; + SEC_WCHAR *target = NULL; + + TRACE("%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); + + if(pszTargetName != NULL) + { + int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, + strlen(pszTargetName)+1, NULL, 0); + target = HeapAlloc(GetProcessHeap(), 0, target_size * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1, + target, target_size); + } + + ret = kerberos_InitializeSecurityContextW(phCredential, phContext, target, + fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry); + + HeapFree(GetProcessHeap(), 0, target); + return ret; +} + +/*********************************************************************** + * AcceptSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext( + PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, + ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) +{ + int output_token_idx; + OM_uint32 ret; + OM_uint32 minor_status; + gss_cred_id_t cred_handle; + gss_ctx_id_t context_handle; + OM_uint32 ret_flags; + gss_buffer_desc input_token; + gss_buffer_desc output_token; + OM_uint32 expiry_time; + + TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput, + fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, + ptsExpiry); + + if (!phContext && !pInput) + { + if (!phCredential) + return SEC_E_INVALID_HANDLE; + cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential); + } + else + cred_handle = GSS_C_NO_CREDENTIAL; + + if (pInput) + { + int input_token_idx = kerberos_GetTokenBufferIndex(pInput); + if (input_token_idx == -1) + return SEC_E_INVALID_TOKEN; + input_token.length = pInput->pBuffers[input_token_idx].cbBuffer; + input_token.value = pInput->pBuffers[input_token_idx].pvBuffer; + } + + output_token_idx = kerberos_GetTokenBufferIndex(pOutput); + if (output_token_idx == -1) + return SEC_E_INVALID_TOKEN; + output_token.length = pOutput->pBuffers[output_token_idx].cbBuffer; + output_token.value = pOutput->pBuffers[output_token_idx].pvBuffer; + + /* FIXME: get target_name */ + ret = p_gss_accept_sec_context(&minor_status, &context_handle, cred_handle, + &input_token, GSS_C_NO_CHANNEL_BINDINGS, + NULL, NULL, &output_token, &ret_flags, + &expiry_time, NULL); + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) + { + kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry); + kerberos_CtxtHandleGSSAPItoSSPI(context_handle, phContext); + } + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * CompleteAuthToken + */ +static SECURITY_STATUS SEC_ENTRY kerberos_CompleteAuthToken(PCtxtHandle phContext, + PSecBufferDesc pToken) +{ + /* We never need to call CompleteAuthToken anyway */ + TRACE("%p %p\n", phContext, pToken); + if (!phContext) + return SEC_E_INVALID_HANDLE; + + return SEC_E_OK; +} + +/*********************************************************************** + * DeleteSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(PCtxtHandle phContext) +{ + OM_uint32 ret; + OM_uint32 minor_status; + gss_buffer_desc output_buffer; + gss_ctx_id_t context_handle; + + TRACE("%p\n", phContext); + if (!phContext) + return SEC_E_INVALID_HANDLE; + + /* FIXME: is this correct? */ + output_buffer.length = 0; + output_buffer.value = NULL; + + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + ret = p_gss_delete_sec_context(&minor_status, &context_handle, &output_buffer); + + phContext->dwUpper = 0; + phContext->dwLower = 0; + + /* From https://docs.oracle.com/cd/E19683-01/816-0214/6m6nf1opf/index.html + + * This function is provided for compatibility with the GSS-API version 1. + * Because gss_delete_sec_context() no longer returns a valid output_token + * to be sent to gss_process_context_token(), applications using a newer + * version of the GSS-API do not need to rely on this function. + * + * + if (ret == GSS_S_COMPLETE) + { + + ret = gss_process_context_token(&minor_status, context_handle, + &output_buffer); + }*/ + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * QueryContextAttributesW + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(PCtxtHandle phContext, + ULONG ulAttribute, void *pBuffer) +{ + TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer); + if (!phContext) + return SEC_E_INVALID_HANDLE; + + switch(ulAttribute) + { +#define _x(x) case (x) : FIXME(#x" stub\n"); break + _x(SECPKG_ATTR_ACCESS_TOKEN); + _x(SECPKG_ATTR_AUTHORITY); + _x(SECPKG_ATTR_DCE_INFO); +#if 0 + case SECPKG_ATTR_FLAGS: + { + PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer; + PNegoHelper helper = (PNegoHelper)phContext->dwLower; + + spcf->Flags = 0; + if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) + spcf->Flags |= ISC_RET_INTEGRITY; + if(helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) + spcf->Flags |= ISC_RET_CONFIDENTIALITY; + return SEC_E_OK; + } +#endif + _x(SECPKG_ATTR_KEY_INFO); + _x(SECPKG_ATTR_LIFESPAN); + _x(SECPKG_ATTR_NAMES); + _x(SECPKG_ATTR_NATIVE_NAMES); + _x(SECPKG_ATTR_NEGOTIATION_INFO); + _x(SECPKG_ATTR_PACKAGE_INFO); + _x(SECPKG_ATTR_PASSWORD_EXPIRY); + _x(SECPKG_ATTR_SESSION_KEY); +#if 0 + case SECPKG_ATTR_SIZES: + { + PSecPkgContext_Sizes spcs = (PSecPkgContext_Sizes)pBuffer; + spcs->cbMaxToken = NTLM_MAX_BUF; + spcs->cbMaxSignature = 16; + spcs->cbBlockSize = 0; + spcs->cbSecurityTrailer = 16; + return SEC_E_OK; + } +#endif + _x(SECPKG_ATTR_STREAM_SIZES); + _x(SECPKG_ATTR_TARGET_INFORMATION); +#undef _x + default: + TRACE("Unknown value %d passed for ulAttribute\n", ulAttribute); + } + + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/*********************************************************************** + * QueryContextAttributesA + */ +static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(PCtxtHandle phContext, + ULONG ulAttribute, void *pBuffer) +{ + return kerberos_QueryContextAttributesW(phContext, ulAttribute, pBuffer); +} + +/*********************************************************************** + * ImpersonateSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_ImpersonateSecurityContext(PCtxtHandle phContext) +{ + SECURITY_STATUS ret; + + TRACE("%p\n", phContext); + if (phContext) + { + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + { + ret = SEC_E_INVALID_HANDLE; + } + return ret; +} + +/*********************************************************************** + * RevertSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY kerberos_RevertSecurityContext(PCtxtHandle phContext) +{ + SECURITY_STATUS ret; + + TRACE("%p\n", phContext); + if (phContext) + { + ret = SEC_E_UNSUPPORTED_FUNCTION; + } + else + { + ret = SEC_E_INVALID_HANDLE; + } + return ret; +} + +/*********************************************************************** + * MakeSignature + */ +static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(PCtxtHandle phContext, ULONG fQOP, + PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + int token_idx, message_idx; + OM_uint32 minor_status; + OM_uint32 ret; + gss_buffer_desc token_buffer; + gss_buffer_desc message_buffer; + gss_ctx_id_t context_handle; + OM_uint32 qop = GSS_C_QOP_DEFAULT; + + TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo); + + if (!phContext) + return SEC_E_INVALID_HANDLE; + + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + + if(fQOP) + FIXME("Ignoring fQOP 0x%08x\n", fQOP); + + if(MessageSeqNo) + FIXME("Ignoring MessageSeqNo\n"); + + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) + return SEC_E_INVALID_TOKEN; + + /* If we didn't find a SECBUFFER_TOKEN type buffer */ + if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1) + return SEC_E_INVALID_TOKEN; + + token_buffer.length = pMessage->pBuffers[token_idx].cbBuffer; + token_buffer.value = pMessage->pBuffers[token_idx].pvBuffer; + + /* Note: gssapi doesn't support multiple buffers like SSPI does, so we only + * takes the first buffer */ + for (message_idx = 0; message_idx < pMessage->cBuffers; ++message_idx) + { + if (pMessage->pBuffers[message_idx].BufferType & SECBUFFER_DATA) + break; + } + if (message_idx == pMessage->cBuffers) + return SEC_E_INVALID_TOKEN; + + message_buffer.length = pMessage->pBuffers[token_idx].cbBuffer; + message_buffer.value = pMessage->pBuffers[token_idx].pvBuffer; + + ret = p_gss_get_mic(&minor_status, context_handle, qop, &message_buffer, &token_buffer); + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * VerifySignature + */ +static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + int token_idx, message_idx; + OM_uint32 minor_status; + OM_uint32 ret; + gss_buffer_desc token_buffer; + gss_buffer_desc message_buffer; + gss_ctx_id_t context_handle; + gss_qop_t qop_state; + + TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP); + + if(!phContext) + return SEC_E_INVALID_HANDLE; + + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) + return SEC_E_INVALID_TOKEN; + + if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1) + return SEC_E_INVALID_TOKEN; + + if(MessageSeqNo) + FIXME("Ignoring MessageSeqNo\n"); + + /* If we didn't find a SECBUFFER_TOKEN type buffer */ + if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1) + return SEC_E_INVALID_TOKEN; + + token_buffer.length = pMessage->pBuffers[token_idx].cbBuffer; + token_buffer.value = pMessage->pBuffers[token_idx].pvBuffer; + + /* Note: gssapi doesn't support multiple buffers like SSPI does, so we only + * takes the first buffer */ + for (message_idx = 0; message_idx < pMessage->cBuffers; ++message_idx) + { + if (pMessage->pBuffers[message_idx].BufferType & SECBUFFER_DATA) + break; + } + if (message_idx == pMessage->cBuffers) + return SEC_E_INVALID_TOKEN; + + message_buffer.length = pMessage->pBuffers[token_idx].cbBuffer; + message_buffer.value = pMessage->pBuffers[token_idx].pvBuffer; + + ret = p_gss_verify_mic(&minor_status, context_handle, &message_buffer, + &token_buffer, &qop_state); + + *pfQOP = 0; + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * FreeCredentialsHandle + */ +static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle( + PCredHandle phCredential) +{ + OM_uint32 ret; + OM_uint32 minor_status; + + TRACE("(%p)\n", phCredential); + + if (phCredential) + { + gss_cred_id_t cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential); + + HeapFree(GetProcessHeap(), 0, cred_handle); + + phCredential->dwUpper = 0; + phCredential->dwLower = 0; + + return kerberos_GSSAPIStatusToSecurityStatus(ret); + } + else + return SEC_E_OK; +} + +/*********************************************************************** + * FreeContextBuffer (KERBEROS.@) + */ +SECURITY_STATUS WINAPI kerberos_FreeContextBuffer(PVOID pv) +{ + HeapFree(GetProcessHeap(), 0, pv); + + return SEC_E_OK; +} + +/*********************************************************************** + * EncryptMessage + */ +static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(PCtxtHandle phContext, + ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + gss_ctx_id_t context_handle; + int token_idx, data_idx; + gss_qop_t qop_req = GSS_C_QOP_DEFAULT; + int conf_state; + gss_buffer_desc input_message_buffer; + gss_buffer_desc output_message_buffer; + OM_uint32 ret; + OM_uint32 minor_status; + + TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); + + if(!phContext) + return SEC_E_INVALID_HANDLE; + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + + if(fQOP && (fQOP != SECQOP_WRAP_NO_ENCRYPT)) + FIXME("Ignoring fQOP 0x%x\n", fQOP); + + if(MessageSeqNo) + FIXME("Ignoring MessageSeqNo\n"); + + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) + return SEC_E_INVALID_TOKEN; + + if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1) + return SEC_E_INVALID_TOKEN; + + if((data_idx = kerberos_GetDataBufferIndex(pMessage)) ==-1 ) + return SEC_E_INVALID_TOKEN; + + input_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer; + input_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer; + + /* FIXME: does gss_wrap allow overlapping buffers? */ + output_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer; + output_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer; + + /* FIXME: sign data and store it in token */ + + ret = p_gss_wrap(&minor_status, context_handle, + (fQOP == SECQOP_WRAP_NO_ENCRYPT) ? FALSE : TRUE, qop_req, + &input_message_buffer, &conf_state, &output_message_buffer); + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +/*********************************************************************** + * DecryptMessage + */ +static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) +{ + gss_ctx_id_t context_handle; + OM_uint32 ret; + OM_uint32 minor_status; + int token_idx, data_idx; + gss_buffer_desc input_message_buffer; + gss_buffer_desc output_message_buffer; + gss_qop_t qop_req; + int conf_state; + + TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); + + if(!phContext) + return SEC_E_INVALID_HANDLE; + + context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext); + + if(MessageSeqNo) + FIXME("Ignoring MessageSeqNo\n"); + + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) + return SEC_E_INVALID_TOKEN; + + if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1) + return SEC_E_INVALID_TOKEN; + + if((data_idx = kerberos_GetDataBufferIndex(pMessage)) ==-1) + return SEC_E_INVALID_TOKEN; + + input_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer; + input_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer; + + /* FIXME: does gss_wrap allow overlapping buffers? */ + output_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer; + output_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer; + + ret = p_gss_unwrap(&minor_status, context_handle, &input_message_buffer, + &output_message_buffer, &conf_state, &qop_req); + + *pfQOP = 0; + + /* FIXME: verify data using token */ + + return kerberos_GSSAPIStatusToSecurityStatus(ret); +} + +static SecurityFunctionTableA gssKerberosTableA = { + SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, + kerberos_EnumerateSecurityPackagesA, /* EnumerateSecurityPackagesA */ + kerberos_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ + kerberos_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ + kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + kerberos_InitializeSecurityContextA, /* InitializeSecurityContextA */ + kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ + kerberos_CompleteAuthToken, /* CompleteAuthToken */ + kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ + NULL, /* ApplyControlToken */ + kerberos_QueryContextAttributesA, /* QueryContextAttributesA */ + kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + kerberos_RevertSecurityContext, /* RevertSecurityContext */ + kerberos_MakeSignature, /* MakeSignature */ + kerberos_VerifySignature, /* VerifySignature */ + kerberos_FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoA */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextA */ + NULL, /* AddCredentialsA */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + kerberos_EncryptMessage, /* EncryptMessage */ + kerberos_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesA */ +}; + +static SecurityFunctionTableW gssKerberosTableW = { + SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, + kerberos_EnumerateSecurityPackagesW, /* EnumerateSecurityPackagesW */ + kerberos_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ + kerberos_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ + kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + kerberos_InitializeSecurityContextW, /* InitializeSecurityContextW */ + kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ + kerberos_CompleteAuthToken, /* CompleteAuthToken */ + kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ + NULL, /* ApplyControlToken */ + kerberos_QueryContextAttributesW, /* QueryContextAttributesW */ + kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + kerberos_RevertSecurityContext, /* RevertSecurityContext */ + kerberos_MakeSignature, /* MakeSignature */ + kerberos_VerifySignature, /* VerifySignature */ + kerberos_FreeContextBuffer, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfoW */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContextW */ + NULL, /* AddCredentialsW */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + kerberos_EncryptMessage, /* EncryptMessage */ + kerberos_DecryptMessage, /* DecryptMessage */ + NULL, /* SetContextAttributesW */ +}; + + +/*********************************************************************** + * InitSecurityInterfaceA (KERBEROS.@) + */ +PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void) +{ + if (!load_gssapi()) + { + return NULL; + } + + return &gssKerberosTableA; +} + +/*********************************************************************** + * InitSecurityInterfaceW (KERBEROS.@) + */ +PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void) +{ + if (!load_gssapi()) + { + return NULL; + } + + return &gssKerberosTableW; +} diff --git a/dlls/secur32/Makefile.in b/dlls/secur32/Makefile.in index 6548521f53..c9acdee457 100644 --- a/dlls/secur32/Makefile.in +++ b/dlls/secur32/Makefile.in @@ -9,7 +9,6 @@ C_SRCS = \ base64_codec.c \ dispatcher.c \ hmac_md5.c \ - kerberos.c \ lsa.c \ negotiate.c \ ntlm.c \ diff --git a/dlls/secur32/kerberos.c b/dlls/secur32/kerberos.c deleted file mode 100644 index 753e9748d2..0000000000 --- a/dlls/secur32/kerberos.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2005, 2006 Kai Blin - * Copyright 2016 Jacek Caban for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "rpc.h" -#include "sspi.h" - -#include "secur32_priv.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(secur32); - -#define KERBEROS_MAX_BUF 12000 - -/*********************************************************************** - * QueryCredentialsAttributesA - */ -static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer) -{ - FIXME("(%p %d %p)\n", phCredential, ulAttribute, pBuffer); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * QueryCredentialsAttributesW - */ -static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer) -{ - FIXME("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * AcquireCredentialsHandleW - */ -static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW(SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, - LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry) -{ - FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, - pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - return SEC_E_NO_CREDENTIALS; -} - -/*********************************************************************** - * AcquireCredentialsHandleA - */ -static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, - LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry) -{ - FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, - pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * 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) -{ - 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); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * 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) -{ - 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; -} - -/*********************************************************************** - * AcceptSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext(CredHandle *phCredential, CtxtHandle *phContext, SecBufferDesc *pInput, - ULONG fContextReq, ULONG TargetDataRep, CtxtHandle *phNewContext, SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry) -{ - FIXME("(%p %p %p %d %d %p %p %p %p)\n", phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, - pfContextAttr, ptsExpiry); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * CompleteAuthToken - */ -static SECURITY_STATUS SEC_ENTRY kerberos_CompleteAuthToken(CtxtHandle *phContext, SecBufferDesc *pToken) -{ - FIXME("(%p %p)\n", phContext, pToken); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * DeleteSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(CtxtHandle *phContext) -{ - FIXME("(%p)\n", phContext); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * QueryContextAttributesW - */ -static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer) -{ - FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * QueryContextAttributesA - */ -static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer) -{ - FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * ImpersonateSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY kerberos_ImpersonateSecurityContext(CtxtHandle *phContext) -{ - FIXME("(%p)\n", phContext); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * RevertSecurityContext - */ -static SECURITY_STATUS SEC_ENTRY kerberos_RevertSecurityContext(CtxtHandle *phContext) -{ - FIXME("(%p)\n", phContext); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * MakeSignature - */ -static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo) -{ - FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * VerifySignature - */ -static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP) -{ - FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * FreeCredentialsHandle - */ -static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCredential) -{ - FIXME("(%p)\n", phCredential); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * EncryptMessage - */ -static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo) -{ - FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -/*********************************************************************** - * DecryptMessage - */ -static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP) -{ - FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); - return SEC_E_UNSUPPORTED_FUNCTION; -} - -static const SecurityFunctionTableA kerberosTableA = { - 1, - NULL, /* EnumerateSecurityPackagesA */ - kerberos_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ - kerberos_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ - kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ - NULL, /* Reserved2 */ - kerberos_InitializeSecurityContextA, /* InitializeSecurityContextA */ - kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ - kerberos_CompleteAuthToken, /* CompleteAuthToken */ - kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ - NULL, /* ApplyControlToken */ - kerberos_QueryContextAttributesA, /* QueryContextAttributesA */ - kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ - kerberos_RevertSecurityContext, /* RevertSecurityContext */ - kerberos_MakeSignature, /* MakeSignature */ - kerberos_VerifySignature, /* VerifySignature */ - FreeContextBuffer, /* FreeContextBuffer */ - NULL, /* QuerySecurityPackageInfoA */ - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ - NULL, /* ExportSecurityContext */ - NULL, /* ImportSecurityContextA */ - NULL, /* AddCredentialsA */ - NULL, /* Reserved8 */ - NULL, /* QuerySecurityContextToken */ - kerberos_EncryptMessage, /* EncryptMessage */ - kerberos_DecryptMessage, /* DecryptMessage */ - NULL, /* SetContextAttributesA */ -}; - -static const SecurityFunctionTableW kerberosTableW = { - 1, - NULL, /* EnumerateSecurityPackagesW */ - kerberos_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ - kerberos_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ - kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */ - NULL, /* Reserved2 */ - kerberos_InitializeSecurityContextW, /* InitializeSecurityContextW */ - kerberos_AcceptSecurityContext, /* AcceptSecurityContext */ - kerberos_CompleteAuthToken, /* CompleteAuthToken */ - kerberos_DeleteSecurityContext, /* DeleteSecurityContext */ - NULL, /* ApplyControlToken */ - kerberos_QueryContextAttributesW, /* QueryContextAttributesW */ - kerberos_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ - kerberos_RevertSecurityContext, /* RevertSecurityContext */ - kerberos_MakeSignature, /* MakeSignature */ - kerberos_VerifySignature, /* VerifySignature */ - FreeContextBuffer, /* FreeContextBuffer */ - NULL, /* QuerySecurityPackageInfoW */ - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ - NULL, /* ExportSecurityContext */ - NULL, /* ImportSecurityContextW */ - NULL, /* AddCredentialsW */ - NULL, /* Reserved8 */ - NULL, /* QuerySecurityContextToken */ - kerberos_EncryptMessage, /* EncryptMessage */ - kerberos_DecryptMessage, /* DecryptMessage */ - NULL, /* SetContextAttributesW */ -}; - -#define KERBEROS_COMMENT \ - {'M','i','c','r','o','s','o','f','t',' ','K','e','r','b','e','r','o','s',' ','V','1','.','0',0} -static CHAR kerberos_comment_A[] = KERBEROS_COMMENT; -static WCHAR kerberos_comment_W[] = KERBEROS_COMMENT; - -#define KERBEROS_NAME {'K','e','r','b','e','r','o','s',0} -static char kerberos_name_A[] = KERBEROS_NAME; -static WCHAR kerberos_name_W[] = KERBEROS_NAME; - -#define CAPS \ - ( SECPKG_FLAG_INTEGRITY \ - | SECPKG_FLAG_PRIVACY \ - | SECPKG_FLAG_TOKEN_ONLY \ - | SECPKG_FLAG_DATAGRAM \ - | SECPKG_FLAG_CONNECTION \ - | SECPKG_FLAG_MULTI_REQUIRED \ - | SECPKG_FLAG_EXTENDED_ERROR \ - | SECPKG_FLAG_IMPERSONATION \ - | SECPKG_FLAG_ACCEPT_WIN32_NAME \ - | SECPKG_FLAG_NEGOTIABLE \ - | SECPKG_FLAG_GSS_COMPATIBLE \ - | SECPKG_FLAG_LOGON \ - | SECPKG_FLAG_MUTUAL_AUTH \ - | SECPKG_FLAG_DELEGATION \ - | SECPKG_FLAG_READONLY_WITH_CHECKSUM \ - | SECPKG_FLAG_RESTRICTED_TOKENS \ - | SECPKG_FLAG_APPCONTAINER_CHECKS) - -static const SecPkgInfoW infoW = { - CAPS, - 1, - RPC_C_AUTHN_GSS_KERBEROS, - KERBEROS_MAX_BUF, - kerberos_name_W, - kerberos_comment_W -}; - -static const SecPkgInfoA infoA = { - CAPS, - 1, - RPC_C_AUTHN_GSS_KERBEROS, - KERBEROS_MAX_BUF, - kerberos_name_A, - kerberos_comment_A -}; - -void SECUR32_initKerberosSP(void) -{ - SecureProvider *provider = SECUR32_addProvider(&kerberosTableA, &kerberosTableW, NULL); - SECUR32_addPackages(provider, 1, &infoA, &infoW); -} diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c index f5d5746171..b5bdaf2fdd 100644 --- a/dlls/secur32/secur32.c +++ b/dlls/secur32/secur32.c @@ -439,7 +439,7 @@ SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, ret->moduleName = SECUR32_strdupW(moduleName); ret->loaded = FALSE; } - + LeaveCriticalSection(&cs); return ret; } @@ -466,7 +466,7 @@ void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, packageTable->numPackages = 0; list_init(&packageTable->table); } - + for (i = 0; i < toAdd; i++) { SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage)); @@ -488,7 +488,6 @@ void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, static void _tryLoadProvider(PWSTR moduleName) { HMODULE lib = LoadLibraryW(moduleName); - if (lib) { INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW = @@ -555,7 +554,7 @@ static const WCHAR securityProvidersKeyW[] = { static const WCHAR securityProvidersW[] = { 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0 }; - + static void SECUR32_initializeProviders(void) { HKEY key; @@ -565,12 +564,9 @@ static void SECUR32_initializeProviders(void) /* First load built-in providers */ SECUR32_initSchannelSP(); SECUR32_initNTLMSP(); - SECUR32_initKerberosSP(); - /* Load the Negotiate provider last so apps stumble over the working NTLM - * provider first. Attempting to fix bug #16905 while keeping the - * application reported on wine-users on 2006-09-12 working. */ - SECUR32_initNegotiateSP(); + /* Now load providers from registry */ + TRACE("Loading providers from registry...\n"); apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0, KEY_READ, &key); if (apiRet == ERROR_SUCCESS) @@ -604,6 +600,11 @@ static void SECUR32_initializeProviders(void) } RegCloseKey(key); } + + /* Load the Negotiate provider last so apps stumble over the working NTLM + * provider first. Attempting to fix bug #16905 while keeping the + * application reported on wine-users on 2006-09-12 working. */ + SECUR32_initNegotiateSP(); } SecurePackage *SECUR32_findPackageW(PCWSTR packageName) @@ -616,14 +617,14 @@ SecurePackage *SECUR32_findPackageW(PCWSTR packageName) LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry) { matched = !lstrcmpiW(ret->infoW.Name, packageName); - if (matched) - break; + if (matched) + break; } - - if (!matched) - return NULL; - if (ret->provider && !ret->provider->loaded) + if (!matched) + return NULL; + + if (ret->provider && !ret->provider->loaded) { ret->provider->lib = LoadLibraryW(ret->provider->moduleName); if (ret->provider->lib) @@ -913,7 +914,7 @@ SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages, * nSize returns the number of characters written when lpNameBuffer is not * NULL or the size of the buffer needed to hold the name when the buffer * is too short or lpNameBuffer is NULL. - * + * * It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set. */ BOOLEAN WINAPI GetComputerObjectNameA( diff --git a/include/config.h.in b/include/config.h.in index 6596571b29..909d21e32d 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -288,6 +288,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GSM_H +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_KRB5_H + /* Define if GTK 3 is installed */ #undef HAVE_GTK3 @@ -1508,6 +1511,9 @@ /* Define to the soname of the libgsm library. */ #undef SONAME_LIBGSM +/* Define to the soname of the libgssapi_krb5 library. */ +#undef SONAME_LIBGSSAPI_KRB5 + /* Define to the soname of the libgtk-3 library. */ #undef SONAME_LIBGTK_3 diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 2b0668a837..09e29fa86d 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -743,6 +743,8 @@ HKLM,Software\Policies,,16 HKLM,Software\Registered Applications,,16 HKLM,System\CurrentControlSet\Control\hivelist,,16 HKLM,System\CurrentControlSet\Control\Lsa\Kerberos,,16 +HKLM,System\CurrentControlSet\Control\Lsa\Kerberos,,16 +HKLM,System\CurrentControlSet\Control\SecurityProviders,"SecurityProviders",,"kerberos" HKLM,System\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 2.0\Client,"DisabledByDefault",0x10003,1 HKLM,System\CurrentControlSet\Control\ServiceGroupOrder,"List",0x00010000,"TDI" HKLM,System\CurrentControlSet\Control\TimeZoneInformation,"StandardName",2,"" -- 2.15.0 From e20dce3032d5f8fc3b52df0e495ddb788f1e9d8d Mon Sep 17 00:00:00 2001 From: George Popoff Date: Wed, 11 Oct 2017 14:58:09 +0300 Subject: [8/9] fix negotiate ssp to choose between kerberberos and ntlm ssp Content-Type: text/plain; charset=UTF-8 Signed-off-by: Dmitry Timoshkov --- dlls/secur32/negotiate.c | 213 +++++++++++++++++++++++++++++++++++++------- dlls/secur32/secur32_priv.h | 20 +---- 2 files changed, 181 insertions(+), 52 deletions(-) diff --git a/dlls/secur32/negotiate.c b/dlls/secur32/negotiate.c index bf16258fc2..8d635818c6 100644 --- a/dlls/secur32/negotiate.c +++ b/dlls/secur32/negotiate.c @@ -33,6 +33,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(secur32); +static SEC_WCHAR ntlm_name_W[] = {'N','T','L','M',0}; +static SEC_WCHAR kerberos_name_W[] = {'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', 0}; + +static SecurePackage *ntlm_package; +static SecurePackage *kerberos_package; +static SecureProvider *ntlm_provider; +static SecureProvider *kerberos_provider; + /*********************************************************************** * QueryCredentialsAttributesA */ @@ -61,22 +69,50 @@ static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleW( PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry ) { - static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}; SECURITY_STATUS ret; TRACE("%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - FIXME("forwarding to NTLM\n"); - ret = ntlm_AcquireCredentialsHandleW( pszPrincipal, ntlmW, fCredentialUse, + /* Assume this */ + ret = SEC_E_INTERNAL_ERROR; + + /* First we need to try kerberos */ + + if (kerberos_provider) + { + ret = kerberos_provider->fnTableW. + AcquireCredentialsHandleW(pszPrincipal, kerberos_name_W, fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, - phCredential, ptsExpiry ); + phCredential, ptsExpiry); + } + if (ret == SEC_E_OK) { + /* FIXME: create KerberosCredentials */ NtlmCredentials *cred = (NtlmCredentials *)phCredential->dwLower; cred->no_cached_credentials = (pAuthData == NULL); + return ret; + } + + FIXME("Failed to AcquireCredentialHandle via Kerberos.\n"); + + /* Maybe ntlm? */ + if (ntlm_provider) + { + ret = ntlm_provider->fnTableW. + AcquireCredentialsHandleW(pszPrincipal, ntlm_name_W, fCredentialUse, + pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, + phCredential, ptsExpiry ); } + + if (ret == SEC_E_OK) + { + NtlmCredentials *cred = (NtlmCredentials *)phCredential->dwLower; + cred->no_cached_credentials = (pAuthData == NULL); + } + return ret; } @@ -173,15 +209,41 @@ static SECURITY_STATUS SEC_ENTRY nego_InitializeSecurityContextW( PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry ) { + SECURITY_STATUS ret; + 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); - return ntlm_InitializeSecurityContextW( phCredential, phContext, pszTargetName, + /* Assume this */ + ret = SEC_E_INTERNAL_ERROR; + + if (kerberos_provider) + { + ret = kerberos_provider->fnTableW. + InitializeSecurityContextW( phCredential, phContext, pszTargetName, + fContextReq, Reserved1, TargetDataRep, + pInput, Reserved2, phNewContext, + pOutput, pfContextAttr, ptsExpiry ); + } + + if (ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) + { + return ret; + } + + + if (ntlm_provider) + { + ret = ntlm_provider->fnTableW. + InitializeSecurityContextW( phCredential, phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry ); + } + + return ret; } /*********************************************************************** @@ -227,9 +289,16 @@ static SECURITY_STATUS SEC_ENTRY nego_AcceptSecurityContext( pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsExpiry); - return ntlm_AcceptSecurityContext( phCredential, phContext, pInput, + /* FIXME: add kerberos invocation */ + if (ntlm_provider) + { + return ntlm_provider->fnTableW. + AcceptSecurityContext( phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsExpiry ); + } + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -259,7 +328,13 @@ static SECURITY_STATUS SEC_ENTRY nego_DeleteSecurityContext(PCtxtHandle phContex { TRACE("%p\n", phContext); - return ntlm_DeleteSecurityContext( phContext ); + if (phContext->dwUpper == KERBEROS_MAGIC && kerberos_provider) + return kerberos_provider->fnTableW.DeleteSecurityContext( phContext ); + + if (ntlm_provider) + return kerberos_provider->fnTableW.DeleteSecurityContext( phContext ); + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -288,28 +363,33 @@ static SECURITY_STATUS SEC_ENTRY nego_ApplyControlToken(PCtxtHandle phContext, static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesW( PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer) { + PSecPkgInfoW package_info_w; + SecureProvider *provider; + TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer); - switch (ulAttribute) + if (phContext->dwUpper == KERBEROS_MAGIC) { - case SECPKG_ATTR_SIZES: + package_info_w = &kerberos_package->infoW; + provider = kerberos_provider; + } + else { - SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer; - sizes->cbMaxToken = 2888; - sizes->cbMaxSignature = 16; - sizes->cbSecurityTrailer = 16; - sizes->cbBlockSize = 0; - return SEC_E_OK; + package_info_w = &ntlm_package->infoW; + provider = ntlm_provider; } + + switch (ulAttribute) + { case SECPKG_ATTR_NEGOTIATION_INFO: { SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)pBuffer; - info->PackageInfo = ntlm_package_infoW; + info->PackageInfo = package_info_w; info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; return SEC_E_OK; } default: - return ntlm_QueryContextAttributesW( phContext, ulAttribute, pBuffer ); + return provider->fnTableW.QueryContextAttributesW( phContext, ulAttribute, pBuffer ); } } @@ -319,29 +399,59 @@ static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesW( static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer) { + SECURITY_STATUS ret; + PSecPkgInfoW package_info_W; + PSecPkgInfoA package_info_A; + SecureProvider *provider; + /* int cbSize; */ + TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer); - switch (ulAttribute) + if (phContext->dwUpper == KERBEROS_MAGIC) { - case SECPKG_ATTR_SIZES: + package_info_W = &kerberos_package->infoW; + provider = kerberos_provider; + } + else { - SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer; - sizes->cbMaxToken = 2888; - sizes->cbMaxSignature = 16; - sizes->cbSecurityTrailer = 16; - sizes->cbBlockSize = 0; - return SEC_E_OK; + package_info_W = &ntlm_package->infoW; + provider = ntlm_provider; } + + /* Convert package info from Widechar to ANSI */ + + /* package_info_A = (PSecPkgInfoA) HeapAlloc(GetProcessHeap(), 0, sizeof(*package_info_A)); + + cbSize = WideCharToMultiByte(CP_ACP, 0, package_info_W->Name, -1, NULL, 0, NULL, NULL); + package_info_A->Name = (SEC_CHAR *) HeapAlloc(GetProcessHeap(), 0, cbSize); + WideCharToMultiByte(CP_ACP, 0, package_info_W->Name, -1, &package_info_A->Name, cbSize, NULL, NULL); + + cbSize = WideCharToMultiByte(CP_ACP, 0, package_info_W->Comment, -1, NULL, 0, NULL, NULL); + package_info_A->Comment = (SEC_CHAR *) HeapAlloc(GetProcessHeap(), 0, cbSize); + WideCharToMultiByte(CP_ACP, 0, package_info_W->Comment, -1, &package_info_A->Comment, cbSize, NULL, NULL); + */ + + switch (ulAttribute) + { case SECPKG_ATTR_NEGOTIATION_INFO: { + /* FIXME: Where we need to free the memory? */ + /* SecurityPackage does not contains ANSI version of info */ + /* Maybe we need to expand SecurityPackage structure? */ SecPkgContext_NegotiationInfoA *info = (SecPkgContext_NegotiationInfoA *)pBuffer; - info->PackageInfo = ntlm_package_infoA; + info->PackageInfo = package_info_A; info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE; - return SEC_E_OK; + return SEC_E_UNSUPPORTED_FUNCTION; } default: - return ntlm_QueryContextAttributesA( phContext, ulAttribute, pBuffer ); + ret = provider->fnTableA.QueryContextAttributesA( phContext, ulAttribute, pBuffer ); } + + HeapFree(GetProcessHeap(), 0, package_info_A->Name); + HeapFree(GetProcessHeap(), 0, package_info_A->Comment); + HeapFree(GetProcessHeap(), 0, package_info_A); + + return ret; } /*********************************************************************** @@ -390,7 +500,10 @@ static SECURITY_STATUS SEC_ENTRY nego_MakeSignature(PCtxtHandle phContext, { TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo); - return ntlm_MakeSignature( phContext, fQOP, pMessage, MessageSeqNo ); + if (ntlm_provider) + return ntlm_provider->fnTableW.MakeSignature( phContext, fQOP, pMessage, MessageSeqNo ); + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -401,7 +514,10 @@ static SECURITY_STATUS SEC_ENTRY nego_VerifySignature(PCtxtHandle phContext, { TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP); - return ntlm_VerifySignature( phContext, pMessage, MessageSeqNo, pfQOP ); + if (ntlm_provider) + return ntlm_provider->fnTableW.VerifySignature( phContext, pMessage, MessageSeqNo, pfQOP ); + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -411,7 +527,18 @@ static SECURITY_STATUS SEC_ENTRY nego_FreeCredentialsHandle(PCredHandle phCreden { TRACE("%p\n", phCredential); - return ntlm_FreeCredentialsHandle( phCredential ); + if (phCredential->dwUpper == KERBEROS_MAGIC) + { + if (kerberos_provider) + return kerberos_provider->fnTableW.FreeCredentialsHandle( phCredential ); + } + else + { + if (ntlm_provider) + return ntlm_provider->fnTableW.FreeCredentialsHandle( phCredential ); + } + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -422,7 +549,10 @@ static SECURITY_STATUS SEC_ENTRY nego_EncryptMessage(PCtxtHandle phContext, { TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo); - return ntlm_EncryptMessage( phContext, fQOP, pMessage, MessageSeqNo ); + if (ntlm_provider) + return ntlm_provider->fnTableW.EncryptMessage( phContext, fQOP, pMessage, MessageSeqNo ); + + return SEC_E_INTERNAL_ERROR; } /*********************************************************************** @@ -433,7 +563,10 @@ static SECURITY_STATUS SEC_ENTRY nego_DecryptMessage(PCtxtHandle phContext, { TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP); - return ntlm_DecryptMessage( phContext, pMessage, MessageSeqNo, pfQOP ); + if (ntlm_provider) + return ntlm_provider->fnTableW.DecryptMessage( phContext, pMessage, MessageSeqNo, pfQOP ); + + return SEC_E_INTERNAL_ERROR; } static const SecurityFunctionTableA negoTableA = { @@ -521,6 +654,7 @@ static CHAR negotiate_comment_A[] = "Microsoft Package Negotiator"; SECPKG_FLAG_LOGON | \ SECPKG_FLAG_RESTRICTED_TOKENS ) + void SECUR32_initNegotiateSP(void) { SecureProvider *provider = SECUR32_addProvider(&negoTableA, &negoTableW, NULL); @@ -530,4 +664,17 @@ void SECUR32_initNegotiateSP(void) const SecPkgInfoA infoA = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN, nego_name_A, negotiate_comment_A}; SECUR32_addPackages(provider, 1L, &infoA, &infoW); + + ntlm_package = SECUR32_findPackageW(ntlm_name_W); + kerberos_package = SECUR32_findPackageW(kerberos_name_W); + + if (ntlm_package) + ntlm_provider = ntlm_package->provider; + else + FIXME("SECUR32_findPackageW(ntlm) = null\n"); + + if (kerberos_package) + kerberos_provider = kerberos_package->provider; + else + FIXME("SECUR32_findPackageW(kerberos) = null\n"); } diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index 9a60d65788..212d19c753 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -136,7 +136,6 @@ PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str) DECLSPEC_HIDDEN; void SECUR32_initSchannelSP(void) DECLSPEC_HIDDEN; void SECUR32_initNegotiateSP(void) DECLSPEC_HIDDEN; void SECUR32_initNTLMSP(void) DECLSPEC_HIDDEN; -void SECUR32_initKerberosSP(void) DECLSPEC_HIDDEN; /* Cleanup functions for built-in providers */ void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN; @@ -189,24 +188,7 @@ void SECUR32_arc4Cleanup(arc4_info *a4i) DECLSPEC_HIDDEN; #define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 -SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR *, SEC_WCHAR *, - ULONG, PLUID, PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle, PCtxtHandle, - SEC_WCHAR *, ULONG fContextReq, ULONG, ULONG, PSecBufferDesc, ULONG, PCtxtHandle, - PSecBufferDesc, ULONG *, PTimeStamp) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle, PCtxtHandle, PSecBufferDesc, - ULONG, ULONG, PCtxtHandle, PSecBufferDesc, ULONG *, PTimeStamp) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle, ULONG, void *) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle, ULONG, void *) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle, ULONG, PSecBufferDesc, ULONG) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle, PSecBufferDesc, ULONG, PULONG) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle, ULONG, PSecBufferDesc, ULONG) DECLSPEC_HIDDEN; -SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle, PSecBufferDesc, ULONG, PULONG) DECLSPEC_HIDDEN; - -SecPkgInfoW *ntlm_package_infoW DECLSPEC_HIDDEN; -SecPkgInfoA *ntlm_package_infoA DECLSPEC_HIDDEN; +#define KERBEROS_MAGIC ('K' << 24 | 'E' << 16 | 'R' << 8 | 'B') /* schannel internal interface */ typedef struct schan_imp_session_opaque *schan_imp_session; -- 2.15.0 From cae0f12b60023ecc15e0d517f9e16ab4f89b7154 Mon Sep 17 00:00:00 2001 From: Vitaly Lipatov Date: Wed, 8 Nov 2017 01:41:24 +0300 Subject: [9/9] add-wincred.h-include: add patch for wineboot (needed only in staging) Content-Type: text/plain; charset=UTF-8 --- programs/wineboot/wineboot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index c2c5792fc6..26519c1000 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include "resource.h" -- 2.15.0