[PATCH 0/5] MR11747: secur32: Call LSA mode functions from lsass.exe service.
From: Piotr Caban <piotr@codeweavers.com> --- dlls/kerberos/krb5_ap.c | 108 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c index 6ba66276e1b..b4965776317 100644 --- a/dlls/kerberos/krb5_ap.c +++ b/dlls/kerberos/krb5_ap.c @@ -177,6 +177,7 @@ static NTSTATUS copy_to_client( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_CACH ULONG i; char *client_str; KERB_QUERY_TKT_CACHE_RESPONSE *client_resp; + SECPKG_CALL_INFO info; status = lsa_funcs->AllocateClientBuffer( lsa_req, size, out ); if (status != STATUS_SUCCESS) return status; @@ -188,6 +189,7 @@ static NTSTATUS copy_to_client( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_CACH client_str = (char *)&client_resp->Tickets[resp->CountOfTickets]; + lsa_funcs->GetCallInfo( &info ); for (i = 0; i < resp->CountOfTickets; i++) { KERB_TICKET_CACHE_INFO ticket = { @@ -216,7 +218,51 @@ static NTSTATUS copy_to_client( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_CACH ticket.ServerName.Buffer = (WCHAR *)client_str; client_str += ticket.ServerName.MaximumLength; - status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket), &client_resp->Tickets[i], &ticket); + if (info.Attributes & SECPKG_CALL_WOWCLIENT) + { + struct UNICODE_STRING32 + { + USHORT Length; + USHORT MaximumLength; + ULONG Buffer; + }; + + struct + { + struct UNICODE_STRING32 ServerName; + struct UNICODE_STRING32 RealmName; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + LARGE_INTEGER RenewTime; + LONG EncryptionType; + ULONG TicketFlags; + } ticket32 = + { + { + ticket.ServerName.Length, + ticket.ServerName.MaximumLength, + (ULONG_PTR)ticket.ServerName.Buffer + }, + { + ticket.RealmName.Length, + ticket.RealmName.MaximumLength, + (ULONG_PTR)ticket.RealmName.Buffer + }, + ticket.StartTime, + ticket.EndTime, + ticket.RenewTime, + ticket.EncryptionType, + ticket.TicketFlags + }; + + status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket32), + ((BYTE *)client_resp->Tickets) + i * sizeof(ticket32), &ticket32); + } + else + { + status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket), + &client_resp->Tickets[i], &ticket); + } if (status != STATUS_SUCCESS) goto fail; } return STATUS_SUCCESS; @@ -233,6 +279,7 @@ static NTSTATUS copy_to_client_ex( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_C ULONG i; char *client_str; KERB_QUERY_TKT_CACHE_EX_RESPONSE *client_resp; + SECPKG_CALL_INFO info; status = lsa_funcs->AllocateClientBuffer( lsa_req, size, out ); if (status != STATUS_SUCCESS) return status; @@ -244,6 +291,7 @@ static NTSTATUS copy_to_client_ex( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_C client_str = (char *)&client_resp->Tickets[resp->CountOfTickets]; + lsa_funcs->GetCallInfo( &info ); for (i = 0; i < resp->CountOfTickets; i++) { KERB_TICKET_CACHE_INFO_EX ticket = resp->Tickets[i]; @@ -276,7 +324,63 @@ static NTSTATUS copy_to_client_ex( PLSA_CLIENT_REQUEST lsa_req, KERB_QUERY_TKT_C ticket.ServerName.Buffer = (WCHAR *)client_str; client_str += ticket.ServerName.MaximumLength; - status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket), &client_resp->Tickets[i], &ticket); + if (info.Attributes & SECPKG_CALL_WOWCLIENT) + { + struct UNICODE_STRING32 + { + USHORT Length; + USHORT MaximumLength; + ULONG Buffer; + }; + + struct + { + struct UNICODE_STRING32 ClientName; + struct UNICODE_STRING32 ClientRealm; + struct UNICODE_STRING32 ServerName; + struct UNICODE_STRING32 ServerRealm; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + LARGE_INTEGER RenewTime; + LONG EncryptionType; + ULONG TicketFlags; + } ticket32 = + { + { + ticket.ClientName.Length, + ticket.ClientName.MaximumLength, + (ULONG_PTR)ticket.ClientName.Buffer + }, + { + ticket.ClientRealm.Length, + ticket.ClientRealm.MaximumLength, + (ULONG_PTR)ticket.ClientRealm.Buffer + }, + { + ticket.ServerName.Length, + ticket.ServerName.MaximumLength, + (ULONG_PTR)ticket.ServerName.Buffer + }, + { + ticket.ServerRealm.Length, + ticket.ServerRealm.MaximumLength, + (ULONG_PTR)ticket.ServerRealm.Buffer + }, + ticket.StartTime, + ticket.EndTime, + ticket.RenewTime, + ticket.EncryptionType, + ticket.TicketFlags + }; + + status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket32), + ((BYTE *)client_resp->Tickets) + i * sizeof(ticket32), &ticket32); + } + else + { + status = lsa_funcs->CopyToClientBuffer(lsa_req, sizeof(ticket), + &client_resp->Tickets[i], &ticket); + } if (status != STATUS_SUCCESS) goto fail; } return STATUS_SUCCESS; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11747
From: Piotr Caban <piotr@codeweavers.com> --- dlls/secur32/lsa.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/dlls/secur32/lsa.c b/dlls/secur32/lsa.c index 8ecc8ef933a..44b438a8d73 100644 --- a/dlls/secur32/lsa.c +++ b/dlls/secur32/lsa.c @@ -58,6 +58,7 @@ struct lsa_package static struct lsa_package *loaded_packages; static ULONG loaded_packages_count; +#define LSA_USER_HANDLE(x) (LSA_SEC_HANDLE)(&(x)) struct lsa_handle { DWORD magic; @@ -572,7 +573,8 @@ static SECURITY_STATUS WINAPI lsa_InitializeSecurityContextW( if (mapped_context) { - NTSTATUS ret = package->user_api->InitUserModeContext( new_handle, &ctx_data ); + NTSTATUS ret = package->user_api->InitUserModeContext( + LSA_USER_HANDLE(new_lsa_ctx->handle), &ctx_data ); FreeContextBuffer( ctx_data.pvBuffer ); if (ret) { @@ -659,7 +661,8 @@ static SECURITY_STATUS WINAPI lsa_AcceptSecurityContext( if (mapped_context) { - NTSTATUS ret = package->user_api->InitUserModeContext( new_handle, &ctx_data ); + NTSTATUS ret = package->user_api->InitUserModeContext( + LSA_USER_HANDLE(new_lsa_ctx->handle), &ctx_data ); FreeContextBuffer( ctx_data.pvBuffer ); if (ret) { @@ -815,7 +818,8 @@ static SECURITY_STATUS WINAPI lsa_MakeSignature(CtxtHandle *context, ULONG quali if (!lsa_ctx->package->user_api || !lsa_ctx->package->user_api->MakeSignature) return SEC_E_UNSUPPORTED_FUNCTION; - return lsa_ctx->package->user_api->MakeSignature(lsa_ctx->handle, quality_of_protection, message, message_seq_no); + return lsa_ctx->package->user_api->MakeSignature(LSA_USER_HANDLE(lsa_ctx->handle), + quality_of_protection, message, message_seq_no); } static SECURITY_STATUS WINAPI lsa_VerifySignature(CtxtHandle *context, SecBufferDesc *message, @@ -832,7 +836,8 @@ static SECURITY_STATUS WINAPI lsa_VerifySignature(CtxtHandle *context, SecBuffer if (!lsa_ctx->package->user_api || !lsa_ctx->package->user_api->VerifySignature) return SEC_E_UNSUPPORTED_FUNCTION; - return lsa_ctx->package->user_api->VerifySignature(lsa_ctx->handle, message, message_seq_no, quality_of_protection); + return lsa_ctx->package->user_api->VerifySignature(LSA_USER_HANDLE(lsa_ctx->handle), + message, message_seq_no, quality_of_protection); } static SECURITY_STATUS WINAPI lsa_QuerySecurityContextToken(CtxtHandle *context, HANDLE *token) @@ -863,7 +868,8 @@ static SECURITY_STATUS WINAPI lsa_EncryptMessage(CtxtHandle *context, ULONG qual if (!lsa_ctx->package->user_api || !lsa_ctx->package->user_api->SealMessage) return SEC_E_UNSUPPORTED_FUNCTION; - return lsa_ctx->package->user_api->SealMessage(lsa_ctx->handle, quality_of_protection, message, message_seq_no); + return lsa_ctx->package->user_api->SealMessage(LSA_USER_HANDLE(lsa_ctx->handle), + quality_of_protection, message, message_seq_no); } static SECURITY_STATUS WINAPI lsa_DecryptMessage(CtxtHandle *context, SecBufferDesc *message, @@ -880,7 +886,8 @@ static SECURITY_STATUS WINAPI lsa_DecryptMessage(CtxtHandle *context, SecBufferD if (!lsa_ctx->package->user_api || !lsa_ctx->package->user_api->UnsealMessage) return SEC_E_UNSUPPORTED_FUNCTION; - return lsa_ctx->package->user_api->UnsealMessage(lsa_ctx->handle, message, message_seq_no, quality_of_protection); + return lsa_ctx->package->user_api->UnsealMessage(LSA_USER_HANDLE(lsa_ctx->handle), + message, message_seq_no, quality_of_protection); } static const SecurityFunctionTableW lsa_sspi_tableW = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11747
From: Piotr Caban <piotr@codeweavers.com> --- configure.ac | 2 + loader/wine.inf.in | 12 +++++ programs/lsass/Makefile.in | 7 +++ programs/lsass/main.c | 100 +++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 programs/lsass/Makefile.in create mode 100644 programs/lsass/main.c diff --git a/configure.ac b/configure.ac index a31d302dd4b..4c8ebecb6a2 100644 --- a/configure.ac +++ b/configure.ac @@ -2423,6 +2423,7 @@ enable_icui18n=${enable_icui18n:-$enable_cplusplus} dnl Disable some programs for other PE archs enable_conhost=${enable_conhost:-$HOST_ARCH} +enable_lsass=${enable_lsass:-$HOST_ARCH} enable_plugplay=${enable_plugplay:-$HOST_ARCH} enable_rpcss=${enable_rpcss:-$HOST_ARCH} enable_services=${enable_services:-$HOST_ARCH} @@ -3619,6 +3620,7 @@ WINE_CONFIG_MAKEFILE(programs/iexplore) WINE_CONFIG_MAKEFILE(programs/ipconfig) WINE_CONFIG_MAKEFILE(programs/klist) WINE_CONFIG_MAKEFILE(programs/lodctr) +WINE_CONFIG_MAKEFILE(programs/lsass) WINE_CONFIG_MAKEFILE(programs/makecab) WINE_CONFIG_MAKEFILE(programs/mofcomp) WINE_CONFIG_MAKEFILE(programs/mshta) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 738e98f4a83..965d3b261c2 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -139,6 +139,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=SamSs,0,SamSsService AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService @@ -159,6 +160,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=SamSs,0,SamSsService AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService @@ -179,6 +181,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=SamSs,0,SamSsService AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService @@ -199,6 +202,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=SamSs,0,SamSsService AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService @@ -977,6 +981,14 @@ ServiceType=32 StartType=3 ErrorControl=1 +[SamSsService] +Description="Security Accounts Manager service" +DisplayName="Security Accounts Manager" +ServiceBinary="%11%\lsass.exe" +ServiceType=32 +StartType=3 +ErrorControl=1 + [ScardSvrService] AddReg=ScardSvrServiceKeys DisplayName="Smart card server" diff --git a/programs/lsass/Makefile.in b/programs/lsass/Makefile.in new file mode 100644 index 00000000000..f9bb2c574e8 --- /dev/null +++ b/programs/lsass/Makefile.in @@ -0,0 +1,7 @@ +MODULE = lsass.exe +IMPORTS = advapi32 + +EXTRADLLFLAGS = -mconsole -municode + +SOURCES = \ + main.c diff --git a/programs/lsass/main.c b/programs/lsass/main.c new file mode 100644 index 00000000000..d2e1094c006 --- /dev/null +++ b/programs/lsass/main.c @@ -0,0 +1,100 @@ +/* + * Copyright 2026 Piotr Caban + * + * 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 <stdio.h> +#include <stdarg.h> + +#include "windows.h" +#include "winsvc.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(secur32); + +static WCHAR samssW[] = L"SamSs"; +static HANDLE exit_event; +static SERVICE_STATUS_HANDLE service_handle; + +static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch (ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + TRACE( "shutting down\n" ); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + SetEvent( exit_event ); + return NO_ERROR; + default: + FIXME( "got service ctrl %lx\n", ctrl ); + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } +} + +static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) +{ + SERVICE_STATUS status; + + TRACE( "starting service\n" ); + + exit_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + + service_handle = RegisterServiceCtrlHandlerExW( samssW, service_handler, NULL ); + if (!service_handle) return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + SetServiceStatus( service_handle, &status ); + + WaitForSingleObject( exit_event, INFINITE ); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + TRACE( "service stopped\n" ); +} + +int __cdecl wmain( int argc, WCHAR *argv[] ) +{ + static const SERVICE_TABLE_ENTRYW service_table[] = + { + { samssW, ServiceMain }, + { NULL, NULL } + }; + + StartServiceCtrlDispatcherW( service_table ); + return 0; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11747
From: Piotr Caban <piotr@codeweavers.com> --- dlls/secur32/Makefile.in | 3 +- dlls/secur32/lsa.c | 337 +++++++++++++++++++++------------ dlls/secur32/lsass.idl | 21 ++ include/Makefile.in | 1 + include/wine/lsass.idl | 58 ++++++ programs/lsass/Makefile.in | 7 +- programs/lsass/lsass.c | 241 +++++++++++++++++++++++ programs/lsass/lsass.idl | 21 ++ programs/lsass/lsass_private.h | 25 +++ programs/lsass/main.c | 39 +++- programs/lsass/negotiate.c | 142 ++++++++++++++ 11 files changed, 766 insertions(+), 129 deletions(-) create mode 100644 dlls/secur32/lsass.idl create mode 100644 include/wine/lsass.idl create mode 100644 programs/lsass/lsass.c create mode 100644 programs/lsass/lsass.idl create mode 100644 programs/lsass/lsass_private.h create mode 100644 programs/lsass/negotiate.c diff --git a/dlls/secur32/Makefile.in b/dlls/secur32/Makefile.in index 23704ad6935..5f1c58b9b2c 100644 --- a/dlls/secur32/Makefile.in +++ b/dlls/secur32/Makefile.in @@ -2,11 +2,12 @@ MODULE = secur32.dll IMPORTLIB = secur32 UNIXLIB = secur32.so IMPORTS = advapi32 -DELAYIMPORTS = crypt32 ncrypt +DELAYIMPORTS = crypt32 ncrypt rpcrt4 UNIX_CFLAGS = $(GNUTLS_CFLAGS) SOURCES = \ lsa.c \ + lsass.idl \ negotiate.c \ schannel.c \ schannel_gnutls.c \ diff --git a/dlls/secur32/lsa.c b/dlls/secur32/lsa.c index 44b438a8d73..a0739ac26bc 100644 --- a/dlls/secur32/lsa.c +++ b/dlls/secur32/lsa.c @@ -27,14 +27,17 @@ #include "windef.h" #include "winbase.h" #include "winreg.h" +#include "winsvc.h" #include "sspi.h" #include "ntsecapi.h" #include "ntsecpkg.h" #include "winternl.h" #include "ddk/ntddk.h" #include "rpc.h" +#include "lsass.h" #include "wine/debug.h" +#include "wine/exception.h" #include "secur32_priv.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); @@ -47,10 +50,9 @@ static const WCHAR *default_authentication_package = L"Negotiate"; struct lsa_package { - ULONG package_id; HMODULE mod; LSA_STRING *name; - ULONG lsa_api_version, lsa_table_count, user_api_version, user_table_count; + SecPkgInfoW info; SECPKG_FUNCTION_TABLE *lsa_api; SECPKG_USER_FUNCTION_TABLE *user_api; }; @@ -84,6 +86,118 @@ static const char *debugstr_as(const LSA_STRING *str) return debugstr_an(str->Buffer, str->Length); } +void* __RPC_USER MIDL_user_allocate( SIZE_T size ) +{ + return malloc( size ); +} + +void __RPC_USER MIDL_user_free( void *p ) +{ + free( p ); +} + +static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr) +{ + return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode); +} + +static BOOL start_samss(void) +{ + SERVICE_STATUS_PROCESS status; + SC_HANDLE scm, service; + BOOL ret = FALSE; + + TRACE("\n"); + + if (!(scm = OpenSCManagerW(NULL, NULL, 0))) + { + ERR("Failed to open service manager\n"); + return FALSE; + } + + if (!(service = OpenServiceW(scm, L"SamSs", SERVICE_START | SERVICE_QUERY_STATUS))) + { + ERR("Failed to open SamSs service\n"); + CloseServiceHandle( scm ); + return FALSE; + } + + if (StartServiceW(service, 0, NULL) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + { + ULONGLONG start_time = GetTickCount64(); + do + { + DWORD dummy; + + if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(status), &dummy)) + break; + if (status.dwCurrentState == SERVICE_RUNNING) + { + ret = TRUE; + break; + } + if (GetTickCount64() - start_time > 30000) break; + Sleep( 100 ); + + } while (status.dwCurrentState == SERVICE_START_PENDING); + + if (status.dwCurrentState != SERVICE_RUNNING) + WARN("SamSs failed to start %lu\n", status.dwCurrentState); + } + else + ERR("Failed to start SamSs service\n"); + + CloseServiceHandle(service); + CloseServiceHandle(scm); + return ret; +} + +#define LSASS_CALL_START \ + for (;;) { \ + DWORD err = 0; \ + __TRY { + +#define LSASS_CALL_END \ + } __EXCEPT(rpc_filter) { \ + err = GetExceptionCode(); \ + status = SEC_E_INTERNAL_ERROR; \ + } \ + __ENDTRY \ + if (err == RPC_S_SERVER_UNAVAILABLE) { \ + if (start_samss()) \ + continue; \ + } \ + break; \ + } + +static RPC_BINDING_HANDLE get_lsass_handle(void) +{ + static RPC_BINDING_HANDLE irpcss_handle; + + if (!irpcss_handle) + { + unsigned short protseq[] = LSASS_PROTSEQ; + unsigned short endpoint[] = LSASS_ENDPOINT; + RPC_BINDING_HANDLE handle; + RPC_STATUS status; + RPC_WSTR binding; + + status = RpcStringBindingComposeW(NULL, protseq, NULL, endpoint, NULL, &binding); + if (status != RPC_S_OK) + return NULL; + + status = RpcBindingFromStringBindingW(binding, &handle); + RpcStringFreeW(&binding); + if (status != RPC_S_OK) + return NULL; + + if (InterlockedCompareExchangePointer(&irpcss_handle, handle, NULL)) + /* another thread beat us to it */ + RpcBindingFree(&handle); + } + return irpcss_handle; +} + SECPKG_FUNCTION_TABLE *lsa_find_package(const char *name, SECPKG_USER_FUNCTION_TABLE **user_api) { LSA_STRING package_name; @@ -106,8 +220,6 @@ NTSTATUS WINAPI LsaCallAuthenticationPackage(HANDLE lsa_handle, ULONG package_id PVOID in_buffer, ULONG in_buffer_length, PVOID *out_buffer, PULONG out_buffer_length, PNTSTATUS status) { - ULONG i; - TRACE("%p,%lu,%p,%lu,%p,%p,%p\n", lsa_handle, package_id, in_buffer, in_buffer_length, out_buffer, out_buffer_length, status); @@ -115,19 +227,13 @@ NTSTATUS WINAPI LsaCallAuthenticationPackage(HANDLE lsa_handle, ULONG package_id if (out_buffer_length) *out_buffer_length = 0; if (status) *status = STATUS_SUCCESS; - for (i = 0; i < loaded_packages_count; i++) - { - if (loaded_packages[i].package_id == package_id) - { - if (loaded_packages[i].lsa_api->CallPackageUntrusted) - return loaded_packages[i].lsa_api->CallPackageUntrusted(NULL /* FIXME*/, - in_buffer, NULL, in_buffer_length, out_buffer, out_buffer_length, status); - - return SEC_E_UNSUPPORTED_FUNCTION; - } - } + if (package_id >= loaded_packages_count || !loaded_packages[package_id].lsa_api) + return STATUS_NO_SUCH_PACKAGE; + if (!loaded_packages[package_id].lsa_api->CallPackageUntrusted) + return SEC_E_UNSUPPORTED_FUNCTION; - return STATUS_NO_SUCH_PACKAGE; + return loaded_packages[package_id].lsa_api->CallPackageUntrusted(NULL /* FIXME*/, + in_buffer, NULL, in_buffer_length, out_buffer, out_buffer_length, status); } static struct lsa_handle *alloc_lsa_handle(ULONG magic) @@ -1013,120 +1119,111 @@ static const LSA_SECPKG_FUNCTION_TABLE lsa_secpkg_table = NULL, /* CallPackagePassthrough */ }; -static void add_package(struct lsa_package *package) -{ - struct lsa_package *new_loaded_packages; - - if (!loaded_packages) - new_loaded_packages = malloc(sizeof(*new_loaded_packages)); - else - new_loaded_packages = realloc(loaded_packages, sizeof(*new_loaded_packages) * (loaded_packages_count + 1)); - - if (new_loaded_packages) - { - loaded_packages = new_loaded_packages; - loaded_packages[loaded_packages_count] = *package; - loaded_packages_count++; - } -} - -static BOOL initialize_package(struct lsa_package *package, - NTSTATUS (NTAPI *pSpLsaModeInitialize)(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG), - NTSTATUS (NTAPI *pSpUserModeInitialize)(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG)) +static BOOL initialize_package(ULONG package_id, HMODULE hmod, ULONG table_no, + SecPkgInfoW *info, SpLsaModeInitializeFn pSpLsaModeInitialize, + SpUserModeInitializeFn pSpUserModeInitialize) { + ULONG api_version, table_count; + SECPKG_FUNCTION_TABLE *lsa_api; + SECPKG_USER_FUNCTION_TABLE *user_api; + struct lsa_package *package; + LSA_STRING *name; NTSTATUS status; if (!pSpLsaModeInitialize || !pSpUserModeInitialize) return FALSE; - status = pSpLsaModeInitialize(SECPKG_INTERFACE_VERSION, &package->lsa_api_version, &package->lsa_api, &package->lsa_table_count); - if (status == STATUS_SUCCESS) - { - status = package->lsa_api->InitializePackage(package->package_id, &lsa_dispatch, NULL, NULL, &package->name); - if (status == STATUS_SUCCESS) - { - TRACE("name %s, version %#lx, api table %p, table count %lu\n", - debugstr_an(package->name->Buffer, package->name->Length), - package->lsa_api_version, package->lsa_api, package->lsa_table_count); + status = pSpLsaModeInitialize(SECPKG_INTERFACE_VERSION, &api_version, &lsa_api, &table_count); + if (status || table_no >= table_count) + return FALSE; + lsa_api += table_no; - status = package->lsa_api->Initialize(package->package_id, NULL /* FIXME: params */, - (LSA_SECPKG_FUNCTION_TABLE *)&lsa_secpkg_table); - if (status == STATUS_SUCCESS) - { - status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &package->user_api_version, &package->user_api, &package->user_table_count); - if (status == STATUS_SUCCESS) - { - package->user_api->InstanceInit(SECPKG_INTERFACE_VERSION, &lsa_dll_dispatch, NULL); - return TRUE; - } - } - } + status = lsa_api->InitializePackage(package_id, &lsa_dispatch, NULL, NULL, &name); + if (status) + return FALSE; + TRACE("name %s, version %#lx, api table %p, table count %lu\n", + debugstr_as(name), api_version, lsa_api, table_count); + status = lsa_api->Initialize(package_id, NULL /* FIXME: params */, + (LSA_SECPKG_FUNCTION_TABLE *)&lsa_secpkg_table); + + if (!status) + status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &api_version, &user_api, &table_count); + if (status || table_no >= table_count) + { + lsa_FreeLsaHeap(name); + return FALSE; } - - return FALSE; -} - -static BOOL load_package(const WCHAR *name, struct lsa_package *package, ULONG package_id) -{ - NTSTATUS (NTAPI *pSpLsaModeInitialize)(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG); - NTSTATUS (NTAPI *pSpUserModeInitialize)(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG); - - memset(package, 0, sizeof(*package)); - - package->package_id = package_id; - package->mod = LoadLibraryW(name); - if (!package->mod) return FALSE; - - pSpLsaModeInitialize = (void *)GetProcAddress(package->mod, "SpLsaModeInitialize"); - pSpUserModeInitialize = (void *)GetProcAddress(package->mod, "SpUserModeInitialize"); - - if (initialize_package(package, pSpLsaModeInitialize, pSpUserModeInitialize)) - return TRUE; - - FreeLibrary(package->mod); - return FALSE; + user_api += table_no; + user_api->InstanceInit(SECPKG_INTERFACE_VERSION, &lsa_dll_dispatch, NULL); + + package = loaded_packages + package_id; + package->mod = hmod; + package->name = name; + package->info = *info; + package->lsa_api = lsa_api; + package->user_api = user_api; + return TRUE; } -#define MAX_SERVICE_NAME 260 - void load_auth_packages(void) { - DWORD err, i; - HKEY root; SecureProvider *provider; - struct lsa_package package; - - memset(&package, 0, sizeof(package)); - - /* "Negotiate" has package id 0, .Net depends on this. */ - package.package_id = 0; - if (initialize_package(&package, nego_SpLsaModeInitialize, nego_SpUserModeInitialize)) - add_package(&package); - - err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Lsa", 0, KEY_READ, &root); - if (err != ERROR_SUCCESS) return; - - i = 0; - for (;;) + package_info *packages; + ULONG i, count; + NTSTATUS status = SEC_E_INTERNAL_ERROR; + + LSASS_CALL_START + packages = NULL; + status = get_packages(get_lsass_handle(), &count, &packages); + LSASS_CALL_END + if (status) { - WCHAR name[MAX_SERVICE_NAME]; + ERR("Failed to get security packages list: %lx\n", status); + return; + } - err = RegEnumKeyW(root, i, name, MAX_SERVICE_NAME); - if (err == ERROR_NO_MORE_ITEMS) - break; + loaded_packages = malloc(sizeof(*loaded_packages) * count); + if (!loaded_packages) + { + for (i = 0; i < count; i++) + { + MIDL_user_free(packages[i].module_name); + MIDL_user_free(packages[i].info.Name); + MIDL_user_free(packages[i].info.Comment); + } + MIDL_user_free(packages); + return; + } + for (i = 0; i < count; i++) + { + SpLsaModeInitializeFn lsa_init; + SpUserModeInitializeFn user_init; + HMODULE hmod; - if (err != ERROR_SUCCESS) - continue; + if (!packages[i].module_name) + { + hmod = NULL; + lsa_init = nego_SpLsaModeInitialize; + user_init = nego_SpUserModeInitialize; + } + else + { + hmod = LoadLibraryW(packages[i].module_name); + lsa_init = (void *)GetProcAddress(hmod, "SpLsaModeInitialize"); + user_init = (void *)GetProcAddress(hmod, "SpUserModeInitialize"); + } - if (load_package(name, &package, i + 1)) - add_package(&package); + MIDL_user_free(packages[i].module_name); - i++; + if (!initialize_package(i, hmod, packages[i].table_no, &packages[i].info, lsa_init, user_init)) + { + MIDL_user_free(packages[i].info.Name); + MIDL_user_free(packages[i].info.Comment); + FreeLibrary(hmod); + } } - - RegCloseKey(root); - - if (!loaded_packages_count) return; + MIDL_user_free(packages); + loaded_packages_count = count; provider = SECUR32_addProvider(&lsa_sspi_tableA, &lsa_sspi_tableW, NULL); if (!provider) @@ -1137,19 +1234,8 @@ void load_auth_packages(void) for (i = 0; i < loaded_packages_count; i++) { - SecPkgInfoW *info; - - info = malloc(loaded_packages[i].lsa_table_count * sizeof(*info)); - if (info) - { - NTSTATUS status; - - status = loaded_packages[i].lsa_api->GetInfo(info); - if (status == STATUS_SUCCESS) - SECUR32_addPackages(provider, loaded_packages[i].lsa_table_count, NULL, info); - - free(info); - } + if (!loaded_packages[i].name) continue; + SECUR32_addPackages(provider, 1, NULL, &loaded_packages[i].info); } } @@ -1162,9 +1248,10 @@ NTSTATUS WINAPI LsaLookupAuthenticationPackage(HANDLE lsa_handle, for (i = 0; i < loaded_packages_count; i++) { + if (!loaded_packages[i].name) continue; if (!RtlCompareString(loaded_packages[i].name, package_name, FALSE)) { - *package_id = loaded_packages[i].package_id; + *package_id = i; return STATUS_SUCCESS; } } diff --git a/dlls/secur32/lsass.idl b/dlls/secur32/lsass.idl new file mode 100644 index 00000000000..8e43bb67034 --- /dev/null +++ b/dlls/secur32/lsass.idl @@ -0,0 +1,21 @@ +/* + * Copyright 2026 Piotr Caban + * + * 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 + */ + +#pragma makedep client + +#include "wine/lsass.idl" diff --git a/include/Makefile.in b/include/Makefile.in index 867a608b0dd..27d71a11f54 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -1131,6 +1131,7 @@ SOURCES = \ wine/irpcss.idl \ wine/itss.idl \ wine/list.h \ + wine/lsass.idl \ wine/mfinternal.idl \ wine/mmsystem16.h \ wine/mscvpdb.h \ diff --git a/include/wine/lsass.idl b/include/wine/lsass.idl new file mode 100644 index 00000000000..4641a9a8b2a --- /dev/null +++ b/include/wine/lsass.idl @@ -0,0 +1,58 @@ +/* + * Copyright 2026 Piotr Caban + * + * 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 + */ + +import "wtypes.idl"; + +cpp_quote("#include <winternl.h>") +cpp_quote("#include <sspi.h>") +cpp_quote("#define LSASS_PROTSEQ {'n','c','a','l','r','p','c',0}") +cpp_quote("#define LSASS_ENDPOINT {'l','s','a','s','s','p','i','r','p','c',0}") + +[ + uuid(3c6747ea-b583-4230-9a65-c55f7d31fac0), + version(1.0), + strict_context_handle +] +interface lsass +{ + cpp_quote("#if 0") + typedef LONG NTSTATUS; + + typedef struct + { + ULONG fCapabilities; + USHORT wVersion; + USHORT wRPCID; + ULONG cbMaxToken; + [string] WCHAR *Name; + [string] WCHAR *Comment; + } SecPkgInfoW; + cpp_quote("#endif") + + typedef struct + { + [string] WCHAR *module_name; + ULONG table_no; + SecPkgInfoW info; + } package_info; + + NTSTATUS get_packages( + [in] handle_t binding, + [out] ULONG *count, + [out, size_is(, *count)] package_info **packages); +} diff --git a/programs/lsass/Makefile.in b/programs/lsass/Makefile.in index f9bb2c574e8..a0b89230cfb 100644 --- a/programs/lsass/Makefile.in +++ b/programs/lsass/Makefile.in @@ -1,7 +1,10 @@ MODULE = lsass.exe -IMPORTS = advapi32 +IMPORTS = advapi32 rpcrt4 EXTRADLLFLAGS = -mconsole -municode SOURCES = \ - main.c + lsass.c \ + lsass.idl \ + main.c \ + negotiate.c diff --git a/programs/lsass/lsass.c b/programs/lsass/lsass.c new file mode 100644 index 00000000000..09bf510d49d --- /dev/null +++ b/programs/lsass/lsass.c @@ -0,0 +1,241 @@ +/* + * Copyright 2004 Juan Lang + * Copyright 2007 Kai Blin + * Copyright 2017, 2018 Dmitry Timoshkov + * Copyright 2026 Piotr Caban + * + * 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 <stdarg.h> +#include <stdlib.h> + +#include "wtypes.h" +#include "sspi.h" +#include "ntstatus.h" +#include "lsass_private.h" +#include "lsass.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(secur32); + +struct package +{ + WCHAR module[MAX_PATH]; + ULONG table_no; + SecPkgInfoW info; + SECPKG_FUNCTION_TABLE *funcs; +}; + +static struct package *packages; +static ULONG packages_count, packages_size; + +static const char *debugstr_as( const LSA_STRING *str ) +{ + if (!str) return "<null>"; + return debugstr_an( str->Buffer, str->Length ); +} + +static NTSTATUS NTAPI lsa_CreateLogonSession( LUID *logon_id ) +{ + FIXME( "%p: stub\n", logon_id ); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS NTAPI lsa_DeleteLogonSession( LUID *logon_id ) +{ + FIXME( "%p: stub\n", logon_id ); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS NTAPI lsa_AddCredential( LUID *logon_id, ULONG package_id, + LSA_STRING *primary_key, LSA_STRING *credentials ) +{ + FIXME( "%p,%lu,%s,%s: stub\n", logon_id, package_id, + debugstr_as(primary_key), debugstr_as(credentials) ); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS NTAPI lsa_GetCredentials( LUID *logon_id, ULONG package_id, + ULONG *context, BOOLEAN retrieve_all, LSA_STRING *primary_key, + ULONG *primary_key_len, LSA_STRING *credentials ) +{ + FIXME( "%p,%#lx,%p,%d,%p,%p,%p: stub\n", logon_id, package_id, context, + retrieve_all, primary_key, primary_key_len, credentials ); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS NTAPI lsa_DeleteCredential( LUID *logon_id, + ULONG package_id, LSA_STRING *primary_key ) +{ + FIXME( "%p,%#lx,%s: stub\n", logon_id, package_id, debugstr_as(primary_key) ); + return STATUS_NOT_IMPLEMENTED; +} + +static void * NTAPI lsa_AllocateLsaHeap( ULONG size ) +{ + TRACE( "%lu\n", size ); + return malloc( size ); +} + +static void NTAPI lsa_FreeLsaHeap( void *p ) +{ + TRACE( "%p\n", p ); + free( p ); +} + +static NTSTATUS NTAPI lsa_AllocateClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void **p ) +{ + TRACE( "%p,%lu,%p\n", req, size, p ); + *p = malloc( size ); + return *p ? STATUS_SUCCESS : STATUS_NO_MEMORY; +} + +static NTSTATUS NTAPI lsa_FreeClientBuffer( PLSA_CLIENT_REQUEST req, void *p ) +{ + TRACE( "%p,%p\n", req, p ); + free( p ); + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI lsa_CopyToClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void *client, void *buf ) +{ + TRACE( "%p,%lu,%p,%p\n", req, size, client, buf ); + memcpy( client, buf, size ); + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI lsa_CopyFromClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void *buf, void *client ) +{ + TRACE( "%p,%lu,%p,%p\n", req, size, buf, client ); + memcpy( buf, client, size ); + return STATUS_SUCCESS; +} + +static LSA_DISPATCH_TABLE lsa_dispatch = +{ + lsa_CreateLogonSession, + lsa_DeleteLogonSession, + lsa_AddCredential, + lsa_GetCredentials, + lsa_DeleteCredential, + lsa_AllocateLsaHeap, + lsa_FreeLsaHeap, + lsa_AllocateClientBuffer, + lsa_FreeClientBuffer, + lsa_CopyToClientBuffer, + lsa_CopyFromClientBuffer +}; + +static BOOL init_package( const WCHAR *module, SpLsaModeInitializeFn init ) +{ + SECPKG_FUNCTION_TABLE *tables; + ULONG api_version, count, i; + SecPkgInfoW info; + LSA_STRING *name; + BOOL ret = FALSE; + + if (!init) return FALSE; + if (init( SECPKG_INTERFACE_VERSION, &api_version, &tables, &count )) + return FALSE; + + if (!packages_size) + { + packages = malloc( sizeof(*packages) * max(count, 8) ); + if (!packages) return FALSE; + packages_size = max( count, 8 ); + } + else if (packages_count + count > packages_size) + { + struct packages *new_packages; + + new_packages = realloc( packages, sizeof(*packages) * + max(packages_size * 2, packages_count + count) ); + if (!new_packages) return FALSE; + packages_size = max( packages_size * 2, packages_count + count ); + } + + for (i = 0; i < count; i++) + { + if (tables[i].InitializePackage( packages_count, &lsa_dispatch, NULL, NULL, &name )) + continue; + + TRACE( "name %s, version %#lx, api table %p\n", debugstr_as(name), api_version, &tables[i] ); + lsa_FreeLsaHeap( name ); + + if (tables[i].Initialize( packages_count, NULL /* FIXME: params */, NULL )) + continue; + if (tables[i].GetInfo( &info )) continue; + + wcscpy( packages[packages_count].module, module ); + packages[packages_count].table_no = i; + packages[packages_count].funcs = tables + i; + packages[packages_count].info = info; + packages_count++; + ret = TRUE; + } + + return ret; +} + +void load_auth_packages( void ) +{ + DWORD err, i; + HKEY root; + + /* "Negotiate" has package id 0, .Net depends on this. */ + init_package( L"", nego_SpLsaModeInitialize ); + + err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Lsa", 0, KEY_READ, &root ); + if (err != ERROR_SUCCESS) return; + + for (i = 0;; i++) + { + WCHAR name[MAX_PATH]; + SpLsaModeInitializeFn init; + HMODULE hmod; + + err = RegEnumKeyW( root, i, name, MAX_PATH ); + if (err == ERROR_NO_MORE_ITEMS) break; + if (err != ERROR_SUCCESS) continue; + + hmod = LoadLibraryW( name ); + if (!hmod) continue; + init = (void *)GetProcAddress( hmod, "SpLsaModeInitialize" ); + if (!init || !init_package( name, init )) + FreeLibrary( hmod ); + } + + RegCloseKey( root ); +} + +NTSTATUS __cdecl get_packages( handle_t binding, ULONG *count, package_info **out ) +{ + ULONG i; + + *count = 0; + *out = MIDL_user_allocate( sizeof(*(*out)) * packages_count ); + if (!*out) return SEC_E_INSUFFICIENT_MEMORY; + + *count = packages_count; + for (i = 0; i < packages_count; i++) + { + (*out)[i].module_name = packages[i].module[0] ? packages[i].module : NULL; + (*out)[i].table_no = packages[i].table_no; + (*out)[i].info = packages[i].info; + } + return SEC_E_OK; +} diff --git a/programs/lsass/lsass.idl b/programs/lsass/lsass.idl new file mode 100644 index 00000000000..a48c6b32bf0 --- /dev/null +++ b/programs/lsass/lsass.idl @@ -0,0 +1,21 @@ +/* + * Copyright 2026 Piotr Caban + * + * 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 + */ + +#pragma makedep server + +#include "wine/lsass.idl" diff --git a/programs/lsass/lsass_private.h b/programs/lsass/lsass_private.h new file mode 100644 index 00000000000..4aa89338eb6 --- /dev/null +++ b/programs/lsass/lsass_private.h @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Piotr Caban + * + * 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 "ntsecapi.h" +#include "ntsecpkg.h" + +extern void load_auth_packages( void ); + +extern NTSTATUS NTAPI nego_SpLsaModeInitialize( ULONG lsa_version, + PULONG package_version, PSECPKG_FUNCTION_TABLE *table, PULONG table_count ); diff --git a/programs/lsass/main.c b/programs/lsass/main.c index d2e1094c006..8bccafbdcf4 100644 --- a/programs/lsass/main.c +++ b/programs/lsass/main.c @@ -16,11 +16,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include <stdio.h> #include <stdarg.h> +#include "rpc.h" #include "windows.h" #include "winsvc.h" +#include "lsass.h" +#include "lsass_private.h" #include "wine/debug.h" @@ -30,6 +32,33 @@ static WCHAR samssW[] = L"SamSs"; static HANDLE exit_event; static SERVICE_STATUS_HANDLE service_handle; +void* __RPC_USER MIDL_user_allocate( SIZE_T size ) +{ + return malloc( size ); +} + +void __RPC_USER MIDL_user_free( void *p ) +{ + free( p ); +} + +static RPC_STATUS rpc_initialize( void ) +{ + unsigned short protseq[] = LSASS_PROTSEQ; + unsigned short endpoint[] = LSASS_ENDPOINT; + RPC_STATUS status; + + status = RpcServerRegisterIf( lsass_v1_0_s_ifspec, NULL, NULL ); + if (status != RPC_S_OK) return status; + + status = RpcServerUseProtseqEpW( protseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, endpoint, NULL ); + if (status == RPC_S_OK) status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE ); + if (status == RPC_S_OK) return RPC_S_OK; + + RpcServerUnregisterIf( lsass_v1_0_s_ifspec, NULL, FALSE ); + return status; +} + static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) { SERVICE_STATUS status; @@ -62,9 +91,17 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { SERVICE_STATUS status; + RPC_STATUS ret; TRACE( "starting service\n" ); + if ((ret = rpc_initialize())) + { + WARN( "Failed to initialize rpc interfaces, status %ld.\n", ret ); + return; + } + load_auth_packages(); + exit_event = CreateEventW( NULL, TRUE, FALSE, NULL ); service_handle = RegisterServiceCtrlHandlerExW( samssW, service_handler, NULL ); diff --git a/programs/lsass/negotiate.c b/programs/lsass/negotiate.c new file mode 100644 index 00000000000..60fed60a702 --- /dev/null +++ b/programs/lsass/negotiate.c @@ -0,0 +1,142 @@ +/* + * Copyright 2005 Kai Blin + * Copyright 2012 Hans Leidekker 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 "wtypes.h" +#include "winternl.h" +#include "sspi.h" +#include "ntsecapi.h" +#include "ntsecpkg.h" +#include "ntstatus.h" +#include "rpc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(secur32); + +#define NEGO_MAX_TOKEN 48256 + +static WCHAR nego_name_W[] = L"Negotiate"; +static char nego_name_A[] = "Negotiate"; +static WCHAR negotiate_comment_W[] = L"Microsoft Package Negotiator"; + +#define CAPS ( \ + SECPKG_FLAG_INTEGRITY | \ + SECPKG_FLAG_PRIVACY | \ + 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_RESTRICTED_TOKENS ) + +static NTSTATUS NTAPI nego_LsaApInitializePackage( ULONG package_id, PLSA_DISPATCH_TABLE dispatch, + PLSA_STRING database, PLSA_STRING confidentiality, PLSA_STRING *package_name ) +{ + char *name; + + name = dispatch->AllocateLsaHeap( sizeof(nego_name_A) ); + if (!name) return STATUS_NO_MEMORY; + + memcpy(name, nego_name_A, sizeof(nego_name_A)); + + *package_name = dispatch->AllocateLsaHeap( sizeof(**package_name) ); + if (!*package_name) + { + dispatch->FreeLsaHeap( name ); + return STATUS_NO_MEMORY; + } + + RtlInitString( *package_name, name ); + + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI nego_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params, + LSA_SECPKG_FUNCTION_TABLE *lsa_function_table ) +{ + TRACE( "%Iu, %p, %p\n", package_id, params, lsa_function_table ); + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI nego_SpGetInfo( SecPkgInfoW *info ) +{ + const SecPkgInfoW infoW = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN, + nego_name_W, negotiate_comment_W}; + + TRACE( "%p\n", info ); + + /* LSA will make a copy before forwarding the structure, so + * it's safe to put pointers to dynamic or constant data there. + */ + *info = infoW; + return STATUS_SUCCESS; +} + +static SECPKG_FUNCTION_TABLE nego_lsa_table = +{ + nego_LsaApInitializePackage, + NULL, /* LsaLogonUser */ + NULL, /* CallPackage */ + NULL, /* LogonTerminated */ + NULL, /* LsaApCallPackageUntrusted */ + NULL, /* CallPackagePassthrough */ + NULL, /* LogonUserEx */ + NULL, /* LogonUserEx2 */ + nego_SpInitialize, + NULL, /* SpShutdown */ + nego_SpGetInfo, + NULL, /* AcceptCredentials */ + NULL, /* SpAcquireCredentialsHandle */ + NULL, /* SpQueryCredentialsAttributes */ + NULL, /* SpFreeCredentialsHandle */ + NULL, /* SaveCredentials */ + NULL, /* GetCredentials */ + NULL, /* DeleteCredentials */ + NULL, /* SpInitLsaModeContext */ + NULL, /* SpAcceptLsaModeContext */ + NULL, /* SpDeleteContext */ + NULL, /* ApplyControlToken */ + NULL, /* GetUserInfo */ + NULL, /* GetExtendedInformation */ + NULL, /* SpQueryContextAttributes */ + NULL, /* SpAddCredentials */ + NULL, /* SetExtendedInformation */ + NULL, /* SetContextAttributes */ + NULL, /* SetCredentialsAttributes */ + NULL, /* ChangeAccountPassword */ + NULL, /* QueryMetaData */ + NULL, /* ExchangeMetaData */ + NULL, /* GetCredUIContext */ + NULL, /* UpdateCredentials */ + NULL, /* ValidateTargetInfo */ + NULL, /* PostLogonUser */ +}; + +NTSTATUS NTAPI nego_SpLsaModeInitialize(ULONG lsa_version, PULONG package_version, + PSECPKG_FUNCTION_TABLE *table, PULONG table_count) +{ + TRACE("%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count); + + *package_version = SECPKG_INTERFACE_VERSION; + *table = &nego_lsa_table; + *table_count = 1; + return STATUS_SUCCESS; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11747
From: Piotr Caban <piotr@codeweavers.com> --- dlls/msv1_0/main.c | 3 +- dlls/secur32/lsa.c | 408 ++++++++------------------ dlls/secur32/negotiate.c | 441 +--------------------------- dlls/secur32/secur32_priv.h | 3 +- include/ntsecpkg.h | 3 + include/wine/lsass.idl | 110 +++++++ programs/lsass/lsass.c | 506 ++++++++++++++++++++++++++++++++- programs/lsass/lsass_private.h | 1 + programs/lsass/main.c | 26 ++ programs/lsass/negotiate.c | 311 +++++++++++++++++++- 10 files changed, 1064 insertions(+), 748 deletions(-) diff --git a/dlls/msv1_0/main.c b/dlls/msv1_0/main.c index ebfcd330a48..ee1ffef2fd0 100644 --- a/dlls/msv1_0/main.c +++ b/dlls/msv1_0/main.c @@ -1630,7 +1630,8 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L goto done; } output->pBuffers[0].cbBuffer = bin_len; - output->pBuffers[0].BufferType = SECBUFFER_TOKEN; + output->pBuffers[0].BufferType &= SECBUFFER_ATTRMASK; + output->pBuffers[0].BufferType |= SECBUFFER_TOKEN; status = lsa_secpkg_table->MapBuffer( output->pBuffers, output->pBuffers ); if (status) goto done; memcpy( output->pBuffers[0].pvBuffer, bin, bin_len ); diff --git a/dlls/secur32/lsa.c b/dlls/secur32/lsa.c index a0739ac26bc..f2bfb57144f 100644 --- a/dlls/secur32/lsa.c +++ b/dlls/secur32/lsa.c @@ -51,9 +51,7 @@ static const WCHAR *default_authentication_package = L"Negotiate"; struct lsa_package { HMODULE mod; - LSA_STRING *name; SecPkgInfoW info; - SECPKG_FUNCTION_TABLE *lsa_api; SECPKG_USER_FUNCTION_TABLE *user_api; }; @@ -65,7 +63,7 @@ struct lsa_handle { DWORD magic; struct lsa_package *package; - LSA_SEC_HANDLE handle; + ULONG64 handle; }; static char *strdupWA( const WCHAR *str ) @@ -96,6 +94,32 @@ void __RPC_USER MIDL_user_free( void *p ) free( p ); } +ULONG __RPC_USER CLIENT_PTR_UserSize( ULONG *flags, ULONG pos, CLIENT_PTR *client_ptr ) +{ + return sizeof(ULONG64); +} + +unsigned char* __RPC_USER CLIENT_PTR_UserMarshal( ULONG *flags, unsigned char *buf, CLIENT_PTR *client_ptr ) +{ + ULONG64 data = (ULONG_PTR)*client_ptr; + + memcpy( buf, &data, sizeof(data) ); + return buf + sizeof(data); +} + +unsigned char* __RPC_USER CLIENT_PTR_UserUnmarshal( ULONG *flags, unsigned char *buf, CLIENT_PTR *client_ptr ) +{ + ULONG64 data; + + memcpy( &data, buf, sizeof(data) ); + *(ULONG_PTR*)client_ptr = data; + return buf + sizeof(data); +} + +void __RPC_USER CLIENT_PTR_UserFree( ULONG *flags, CLIENT_PTR *client_ptr ) +{ +} + static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr) { return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode); @@ -198,42 +222,40 @@ static RPC_BINDING_HANDLE get_lsass_handle(void) return irpcss_handle; } -SECPKG_FUNCTION_TABLE *lsa_find_package(const char *name, SECPKG_USER_FUNCTION_TABLE **user_api) +SECPKG_USER_FUNCTION_TABLE *lsa_find_func_table( const WCHAR *name ) { - LSA_STRING package_name; ULONG i; - RtlInitString(&package_name, name); - for (i = 0; i < loaded_packages_count; i++) { - if (!RtlCompareString(loaded_packages[i].name, &package_name, FALSE)) - { - *user_api = loaded_packages[i].user_api; - return loaded_packages[i].lsa_api; - } + if (!wcscmp( loaded_packages[i].info.Name, name )) + return loaded_packages[i].user_api; } return NULL; } NTSTATUS WINAPI LsaCallAuthenticationPackage(HANDLE lsa_handle, ULONG package_id, PVOID in_buffer, ULONG in_buffer_length, - PVOID *out_buffer, PULONG out_buffer_length, PNTSTATUS status) + PVOID *out_buffer, PULONG out_buffer_length, PNTSTATUS prot_status) { + NTSTATUS status; + TRACE("%p,%lu,%p,%lu,%p,%p,%p\n", lsa_handle, package_id, in_buffer, - in_buffer_length, out_buffer, out_buffer_length, status); + in_buffer_length, out_buffer, out_buffer_length, prot_status); if (out_buffer) *out_buffer = NULL; if (out_buffer_length) *out_buffer_length = 0; - if (status) *status = STATUS_SUCCESS; + if (prot_status) *prot_status = STATUS_SUCCESS; - if (package_id >= loaded_packages_count || !loaded_packages[package_id].lsa_api) + if (package_id >= loaded_packages_count) return STATUS_NO_SUCH_PACKAGE; - if (!loaded_packages[package_id].lsa_api->CallPackageUntrusted) - return SEC_E_UNSUPPORTED_FUNCTION; - return loaded_packages[package_id].lsa_api->CallPackageUntrusted(NULL /* FIXME*/, - in_buffer, NULL, in_buffer_length, out_buffer, out_buffer_length, status); + LSASS_CALL_START + status = call_package_untrusted(get_lsass_handle(), GetCurrentThreadId(), + 0, package_id, in_buffer, in_buffer, in_buffer_length, + out_buffer, out_buffer_length, prot_status); + LSASS_CALL_END + return status; } static struct lsa_handle *alloc_lsa_handle(ULONG magic) @@ -294,8 +316,7 @@ NTSTATUS WINAPI LsaEnumerateLogonSessions(PULONG LogonSessionCount, NTSTATUS WINAPI LsaFreeReturnBuffer(PVOID buffer) { TRACE("%p\n", buffer); - free(buffer); - return STATUS_SUCCESS; + return VirtualFree(buffer, 0, MEM_RELEASE); } NTSTATUS WINAPI LsaGetLogonSessionData(PLUID LogonId, @@ -342,40 +363,6 @@ NTSTATUS WINAPI LsaLogonUser(HANDLE LsaHandle, PLSA_STRING OriginName, return STATUS_SUCCESS; } -static NTSTATUS NTAPI lsa_CreateLogonSession(LUID *logon_id) -{ - FIXME("%p: stub\n", logon_id); - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS NTAPI lsa_DeleteLogonSession(LUID *logon_id) -{ - FIXME("%p: stub\n", logon_id); - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS NTAPI lsa_AddCredential(LUID *logon_id, ULONG package_id, - LSA_STRING *primary_key, LSA_STRING *credentials) -{ - FIXME("%p,%lu,%s,%s: stub\n", logon_id, package_id, - debugstr_as(primary_key), debugstr_as(credentials)); - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS NTAPI lsa_GetCredentials(LUID *logon_id, ULONG package_id, ULONG *context, - BOOLEAN retrieve_all, LSA_STRING *primary_key, ULONG *primary_key_len, LSA_STRING *credentials) -{ - FIXME("%p,%#lx,%p,%d,%p,%p,%p: stub\n", logon_id, package_id, context, - retrieve_all, primary_key, primary_key_len, credentials); - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS NTAPI lsa_DeleteCredential(LUID *logon_id, ULONG package_id, LSA_STRING *primary_key) -{ - FIXME("%p,%#lx,%s: stub\n", logon_id, package_id, debugstr_as(primary_key)); - return STATUS_NOT_IMPLEMENTED; -} - static void * NTAPI lsa_AllocateLsaHeap(ULONG size) { TRACE("%lu\n", size); @@ -388,49 +375,6 @@ static void NTAPI lsa_FreeLsaHeap(void *p) free(p); } -static NTSTATUS NTAPI lsa_AllocateClientBuffer(PLSA_CLIENT_REQUEST req, ULONG size, void **p) -{ - TRACE("%p,%lu,%p\n", req, size, p); - *p = malloc(size); - return *p ? STATUS_SUCCESS : STATUS_NO_MEMORY; -} - -static NTSTATUS NTAPI lsa_FreeClientBuffer(PLSA_CLIENT_REQUEST req, void *p) -{ - TRACE("%p,%p\n", req, p); - free(p); - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI lsa_CopyToClientBuffer(PLSA_CLIENT_REQUEST req, ULONG size, void *client, void *buf) -{ - TRACE("%p,%lu,%p,%p\n", req, size, client, buf); - memcpy(client, buf, size); - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI lsa_CopyFromClientBuffer(PLSA_CLIENT_REQUEST req, ULONG size, void *buf, void *client) -{ - TRACE("%p,%lu,%p,%p\n", req, size, buf, client); - memcpy(buf, client, size); - return STATUS_SUCCESS; -} - -static LSA_DISPATCH_TABLE lsa_dispatch = -{ - lsa_CreateLogonSession, - lsa_DeleteLogonSession, - lsa_AddCredential, - lsa_GetCredentials, - lsa_DeleteCredential, - lsa_AllocateLsaHeap, - lsa_FreeLsaHeap, - lsa_AllocateClientBuffer, - lsa_FreeClientBuffer, - lsa_CopyToClientBuffer, - lsa_CopyFromClientBuffer -}; - static NTSTATUS NTAPI lsa_RegisterCallback(ULONG callback_id, PLSA_CALLBACK_FUNCTION callback) { FIXME("%lu,%p: stub\n", callback_id, callback); @@ -444,35 +388,11 @@ static SECPKG_DLL_FUNCTIONS lsa_dll_dispatch = lsa_RegisterCallback }; -static SECURITY_STATUS lsa_lookup_package(SEC_WCHAR *nameW, struct lsa_package **lsa_package) -{ - ULONG i; - UNICODE_STRING package_name, name; - - for (i = 0; i < loaded_packages_count; i++) - { - if (RtlAnsiStringToUnicodeString(&package_name, loaded_packages[i].name, TRUE)) - return SEC_E_INSUFFICIENT_MEMORY; - - RtlInitUnicodeString(&name, nameW); - - if (RtlEqualUnicodeString(&package_name, &name, TRUE)) - { - RtlFreeUnicodeString(&package_name); - *lsa_package = &loaded_packages[i]; - return SEC_E_OK; - } - - RtlFreeUnicodeString(&package_name); - } - - return SEC_E_SECPKG_NOT_FOUND; -} - static SECURITY_STATUS WINAPI lsa_QueryCredentialsAttributesW( CredHandle *credential, ULONG attr, void *buf) { struct lsa_handle *lsa_cred; + SECURITY_STATUS status; TRACE("%p %lu %p\n", credential, attr, buf); if (!credential) return SEC_E_INVALID_HANDLE; @@ -480,10 +400,11 @@ static SECURITY_STATUS WINAPI lsa_QueryCredentialsAttributesW( lsa_cred = (struct lsa_handle *)credential->dwLower; if (!lsa_cred || lsa_cred->magic != LSA_MAGIC_CREDENTIALS) return SEC_E_INVALID_HANDLE; - if (!lsa_cred->package->lsa_api || !lsa_cred->package->lsa_api->SpQueryCredentialsAttributes) - return SEC_E_UNSUPPORTED_FUNCTION; - - return lsa_cred->package->lsa_api->SpQueryCredentialsAttributes(lsa_cred->handle, attr, buf); + LSASS_CALL_START + status = query_credentials_attr(get_lsass_handle(), GetCurrentThreadId(), + lsa_cred->package - loaded_packages, lsa_cred->handle, attr, buf); + LSASS_CALL_END + return status; } static SECURITY_STATUS WINAPI lsa_QueryCredentialsAttributesA( @@ -519,37 +440,33 @@ static SECURITY_STATUS WINAPI lsa_AcquireCredentialsHandleW( LUID *logon_id, void *auth_data, SEC_GET_KEY_FN get_key_fn, void *get_key_arg, CredHandle *credential, TimeStamp *ts_expiry) { - SECURITY_STATUS status; - struct lsa_package *lsa_package; struct lsa_handle *lsa_handle; - UNICODE_STRING principal_us; - LSA_SEC_HANDLE lsa_credential; + SECURITY_STATUS status; + ULONG package_id; TRACE("%s %s %#lx %p %p %p %p %p\n", debugstr_w(principal), debugstr_w(package), credentials_use, auth_data, get_key_fn, get_key_arg, credential, ts_expiry); if (!credential) return SEC_E_INVALID_HANDLE; if (!package) return SEC_E_SECPKG_NOT_FOUND; + if (!(lsa_handle = alloc_lsa_handle(LSA_MAGIC_CREDENTIALS))) return STATUS_NO_MEMORY; - status = lsa_lookup_package(package, &lsa_package); - if (status != SEC_E_OK) return status; - - if (!lsa_package->lsa_api || !lsa_package->lsa_api->SpAcquireCredentialsHandle) - return SEC_E_UNSUPPORTED_FUNCTION; - - if (principal) - RtlInitUnicodeString(&principal_us, principal); + LSASS_CALL_START + status = acquire_credentials_handle(get_lsass_handle(), GetCurrentThreadId(), + principal, package, credentials_use, logon_id, auth_data, get_key_fn, + get_key_arg, &package_id, &lsa_handle->handle, ts_expiry); + LSASS_CALL_END - status = lsa_package->lsa_api->SpAcquireCredentialsHandle(principal ? &principal_us : NULL, - credentials_use, logon_id, auth_data, get_key_fn, get_key_arg, &lsa_credential, ts_expiry); - if (status == SEC_E_OK) + if (status != SEC_E_OK) { - if (!(lsa_handle = alloc_lsa_handle(LSA_MAGIC_CREDENTIALS))) return STATUS_NO_MEMORY; - lsa_handle->package = lsa_package; - lsa_handle->handle = lsa_credential; - credential->dwLower = (ULONG_PTR)lsa_handle; - credential->dwUpper = 0; + SecureZeroMemory(&lsa_handle->magic, sizeof(lsa_handle->magic)); + free(lsa_handle); + return status; } + + lsa_handle->package = loaded_packages + package_id; + credential->dwLower = (ULONG_PTR)lsa_handle; + credential->dwUpper = 0; return status; } @@ -596,10 +513,10 @@ static SECURITY_STATUS WINAPI lsa_FreeCredentialsHandle(CredHandle *credential) lsa_cred = (struct lsa_handle *)credential->dwLower; if (!lsa_cred || lsa_cred->magic != LSA_MAGIC_CREDENTIALS) return SEC_E_INVALID_HANDLE; - if (!lsa_cred->package->lsa_api || !lsa_cred->package->lsa_api->FreeCredentialsHandle) - return SEC_E_UNSUPPORTED_FUNCTION; - - status = lsa_cred->package->lsa_api->FreeCredentialsHandle(lsa_cred->handle); + LSASS_CALL_START + status = free_credentials_handle(get_lsass_handle(), GetCurrentThreadId(), + lsa_cred->package - loaded_packages, lsa_cred->handle); + LSASS_CALL_END /* Ensure compiler doesn't optimize out the assignment with 0. */ SecureZeroMemory(&lsa_cred->magic, sizeof(lsa_cred->magic)); @@ -618,12 +535,10 @@ static SECURITY_STATUS WINAPI lsa_DeleteSecurityContext(CtxtHandle *context) lsa_ctx = (struct lsa_handle *)context->dwLower; if (!lsa_ctx || lsa_ctx->magic != LSA_MAGIC_CONTEXT) return SEC_E_INVALID_HANDLE; - if (!lsa_ctx->package->lsa_api || !lsa_ctx->package->lsa_api->DeleteContext) - return SEC_E_UNSUPPORTED_FUNCTION; - - if (lsa_ctx->package->user_api && lsa_ctx->package->user_api->DeleteUserModeContext) - lsa_ctx->package->user_api->DeleteUserModeContext(lsa_ctx->handle); - status = lsa_ctx->package->lsa_api->DeleteContext(lsa_ctx->handle); + LSASS_CALL_START + status = delete_security_context(get_lsass_handle(), GetCurrentThreadId(), + lsa_ctx->package - loaded_packages, lsa_ctx->handle);; + LSASS_CALL_END free(lsa_ctx); return status; } @@ -636,15 +551,16 @@ static SECURITY_STATUS WINAPI lsa_InitializeSecurityContextW( SECURITY_STATUS status; struct lsa_handle *lsa_cred = NULL, *lsa_ctx = NULL, *new_lsa_ctx; struct lsa_package *package = NULL; - UNICODE_STRING target_name_us; BOOLEAN mapped_context = FALSE; - LSA_SEC_HANDLE new_handle; SecBuffer ctx_data = { 0 }; TRACE("%p %p %s %#lx %ld %ld %p %ld %p %p %p %p\n", credential, context, debugstr_w(target_name), context_req, reserved1, target_data_rep, input, reserved2, new_context, output, context_attr, ts_expiry); + if (input && input->cBuffers > MAX_SEC_BUFFERS) return SEC_E_INVALID_TOKEN; + if (output && output->cBuffers > MAX_SEC_BUFFERS) return SEC_E_INVALID_TOKEN; + if (context) { lsa_ctx = (struct lsa_handle *)context->dwLower; @@ -659,21 +575,18 @@ static SECURITY_STATUS WINAPI lsa_InitializeSecurityContextW( } if (!package || !new_context) return SEC_E_INVALID_HANDLE; - if (!package->lsa_api || !package->lsa_api->InitLsaModeContext) - return SEC_E_UNSUPPORTED_FUNCTION; - - if (target_name) - RtlInitUnicodeString(&target_name_us, target_name); - if (!(new_lsa_ctx = alloc_lsa_handle(LSA_MAGIC_CONTEXT))) return STATUS_NO_MEMORY; - status = package->lsa_api->InitLsaModeContext(lsa_cred ? lsa_cred->handle : 0, - lsa_ctx ? lsa_ctx->handle : 0, target_name ? &target_name_us : NULL, context_req, target_data_rep, - input, &new_handle, output, context_attr, ts_expiry, &mapped_context, &ctx_data); + LSASS_CALL_START + status = initialize_security_context(get_lsass_handle(), GetCurrentThreadId(), + package - loaded_packages, lsa_cred ? lsa_cred->handle : 0, + lsa_ctx ? lsa_ctx->handle : 0, target_name, context_req, + target_data_rep, input, &new_lsa_ctx->handle, output, + context_attr, ts_expiry, &mapped_context, &ctx_data); + LSASS_CALL_END if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { new_lsa_ctx->package = package; - new_lsa_ctx->handle = new_handle; new_context->dwLower = (ULONG_PTR)new_lsa_ctx; new_context->dwUpper = 0; @@ -730,12 +643,14 @@ static SECURITY_STATUS WINAPI lsa_AcceptSecurityContext( struct lsa_package *package = NULL; struct lsa_handle *lsa_cred = NULL, *lsa_ctx = NULL, *new_lsa_ctx; BOOLEAN mapped_context = FALSE; - LSA_SEC_HANDLE new_handle; SecBuffer ctx_data = { 0 }; TRACE("%p %p %p %#lx %#lx %p %p %p %p\n", credential, context, input, context_req, target_data_rep, new_context, output, context_attr, ts_expiry); + if (input && input->cBuffers > MAX_SEC_BUFFERS) return SEC_E_INVALID_TOKEN; + if (output && output->cBuffers > MAX_SEC_BUFFERS) return SEC_E_INVALID_TOKEN; + if (context) { lsa_ctx = (struct lsa_handle *)context->dwLower; @@ -750,18 +665,18 @@ static SECURITY_STATUS WINAPI lsa_AcceptSecurityContext( } if (!package || !new_context) return SEC_E_INVALID_HANDLE; - if (!package->lsa_api || !package->lsa_api->AcceptLsaModeContext) - return SEC_E_UNSUPPORTED_FUNCTION; - if (!(new_lsa_ctx = alloc_lsa_handle(LSA_MAGIC_CONTEXT))) return STATUS_NO_MEMORY; - status = package->lsa_api->AcceptLsaModeContext(lsa_cred ? lsa_cred->handle : 0, - lsa_ctx ? lsa_ctx->handle : 0, input, context_req, target_data_rep, &new_handle, output, - context_attr, ts_expiry, &mapped_context, &ctx_data); + LSASS_CALL_START + status = accept_security_context(get_lsass_handle(), GetCurrentThreadId(), + package - loaded_packages, lsa_cred ? lsa_cred->handle : 0, + lsa_ctx ? lsa_ctx->handle : 0, input, context_req, + target_data_rep, &new_lsa_ctx->handle, output, context_attr, + ts_expiry, &mapped_context, &ctx_data); + LSASS_CALL_END if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { new_lsa_ctx->package = package; - new_lsa_ctx->handle = new_handle; new_context->dwLower = (ULONG_PTR)new_lsa_ctx; new_context->dwUpper = 0; @@ -788,6 +703,7 @@ static SECURITY_STATUS WINAPI lsa_AcceptSecurityContext( static SECURITY_STATUS WINAPI lsa_QueryContextAttributesW(CtxtHandle *context, ULONG attribute, void *buffer) { struct lsa_handle *lsa_ctx; + NTSTATUS status; TRACE("%p %ld %p\n", context, attribute, buffer); @@ -795,10 +711,11 @@ static SECURITY_STATUS WINAPI lsa_QueryContextAttributesW(CtxtHandle *context, U lsa_ctx = (struct lsa_handle *)context->dwLower; if (!lsa_ctx || lsa_ctx->magic != LSA_MAGIC_CONTEXT) return SEC_E_INVALID_HANDLE; - if (!lsa_ctx->package->lsa_api || !lsa_ctx->package->lsa_api->SpQueryContextAttributes) - return SEC_E_UNSUPPORTED_FUNCTION; - - return lsa_ctx->package->lsa_api->SpQueryContextAttributes(lsa_ctx->handle, attribute, buffer); + LSASS_CALL_START + status = query_context_attr(get_lsass_handle(), GetCurrentThreadId(), + lsa_ctx->package - loaded_packages, lsa_ctx->handle, attribute, buffer); + LSASS_CALL_END + return status; } static SecPkgInfoA *package_infoWtoA( const SecPkgInfoW *info ) @@ -1060,107 +977,26 @@ static const SecurityFunctionTableA lsa_sspi_tableA = NULL, /* SetContextAttributesA */ }; -static NTSTATUS NTAPI lsa_MapBuffer( SecBuffer *in, SecBuffer *out ) -{ - return SEC_E_OK; -} - -static BOOLEAN NTAPI lsa_GetCallInfo( SECPKG_CALL_INFO *info ) -{ - memset( info, 0, sizeof(*info) ); - info->ProcessId = GetCurrentProcessId(); - info->ThreadId = GetCurrentThreadId(); - info->Attributes = SECPKG_CALL_IN_PROC; - return TRUE; -} - -static const LSA_SECPKG_FUNCTION_TABLE lsa_secpkg_table = -{ - lsa_CreateLogonSession, - lsa_DeleteLogonSession, - lsa_AddCredential, - lsa_GetCredentials, - lsa_DeleteCredential, - lsa_AllocateLsaHeap, - lsa_FreeLsaHeap, - lsa_AllocateClientBuffer, - lsa_FreeClientBuffer, - lsa_CopyToClientBuffer, - lsa_CopyFromClientBuffer, - NULL, /* ImpersonateClient */ - NULL, /* UnloadPackage */ - NULL, /* DuplicateHandle */ - NULL, /* SaveSupplementalCredentials */ - NULL, /* CreateThread */ - NULL, /* GetClientInfo */ - NULL, /* RegisterNotification */ - NULL, /* CancelNotification */ - lsa_MapBuffer, - NULL, /* CreateToken */ - NULL, /* AuditLogon */ - NULL, /* CallPackage */ - NULL, /* FreeReturnBuffer */ - lsa_GetCallInfo, - NULL, /* CallPackageEx */ - NULL, /* CreateSharedMemory */ - NULL, /* AllocateSharedMemory */ - NULL, /* FreeSharedMemory */ - NULL, /* DeleteSharedMemory */ - NULL, /* OpenSamUser */ - NULL, /* GetUserCredentials */ - NULL, /* GetUserAuthData */ - NULL, /* CloseSamUser */ - NULL, /* ConvertAuthDataToToken */ - NULL, /* ClientCallback */ - NULL, /* UpdateCredentials */ - NULL, /* GetAuthDataForUser */ - NULL, /* CrackSingleName */ - NULL, /* AuditAccountLogon */ - NULL, /* CallPackagePassthrough */ -}; - static BOOL initialize_package(ULONG package_id, HMODULE hmod, ULONG table_no, - SecPkgInfoW *info, SpLsaModeInitializeFn pSpLsaModeInitialize, - SpUserModeInitializeFn pSpUserModeInitialize) + SecPkgInfoW *info, SpUserModeInitializeFn pSpUserModeInitialize) { ULONG api_version, table_count; - SECPKG_FUNCTION_TABLE *lsa_api; SECPKG_USER_FUNCTION_TABLE *user_api; struct lsa_package *package; - LSA_STRING *name; NTSTATUS status; - if (!pSpLsaModeInitialize || !pSpUserModeInitialize) + if (!pSpUserModeInitialize) return FALSE; - status = pSpLsaModeInitialize(SECPKG_INTERFACE_VERSION, &api_version, &lsa_api, &table_count); + status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &api_version, &user_api, &table_count); if (status || table_no >= table_count) return FALSE; - lsa_api += table_no; - - status = lsa_api->InitializePackage(package_id, &lsa_dispatch, NULL, NULL, &name); - if (status) - return FALSE; - TRACE("name %s, version %#lx, api table %p, table count %lu\n", - debugstr_as(name), api_version, lsa_api, table_count); - status = lsa_api->Initialize(package_id, NULL /* FIXME: params */, - (LSA_SECPKG_FUNCTION_TABLE *)&lsa_secpkg_table); - - if (!status) - status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &api_version, &user_api, &table_count); - if (status || table_no >= table_count) - { - lsa_FreeLsaHeap(name); - return FALSE; - } user_api += table_no; user_api->InstanceInit(SECPKG_INTERFACE_VERSION, &lsa_dll_dispatch, NULL); package = loaded_packages + package_id; package->mod = hmod; - package->name = name; package->info = *info; - package->lsa_api = lsa_api; package->user_api = user_api; return TRUE; } @@ -1182,6 +1018,13 @@ void load_auth_packages(void) return; } + provider = SECUR32_addProvider(&lsa_sspi_tableA, &lsa_sspi_tableW, NULL); + if (!provider) + { + ERR("Failed to add SSP/AP provider\n"); + return; + } + loaded_packages = malloc(sizeof(*loaded_packages) * count); if (!loaded_packages) { @@ -1196,65 +1039,60 @@ void load_auth_packages(void) } for (i = 0; i < count; i++) { - SpLsaModeInitializeFn lsa_init; SpUserModeInitializeFn user_init; HMODULE hmod; if (!packages[i].module_name) { hmod = NULL; - lsa_init = nego_SpLsaModeInitialize; user_init = nego_SpUserModeInitialize; } else { hmod = LoadLibraryW(packages[i].module_name); - lsa_init = (void *)GetProcAddress(hmod, "SpLsaModeInitialize"); user_init = (void *)GetProcAddress(hmod, "SpUserModeInitialize"); } MIDL_user_free(packages[i].module_name); - if (!initialize_package(i, hmod, packages[i].table_no, &packages[i].info, lsa_init, user_init)) + if (!initialize_package(i, hmod, packages[i].table_no, &packages[i].info, user_init)) { MIDL_user_free(packages[i].info.Name); MIDL_user_free(packages[i].info.Comment); FreeLibrary(hmod); } + else + { + SECUR32_addPackages(provider, 1, NULL, &loaded_packages[i].info); + } } MIDL_user_free(packages); loaded_packages_count = count; - - provider = SECUR32_addProvider(&lsa_sspi_tableA, &lsa_sspi_tableW, NULL); - if (!provider) - { - ERR("Failed to add SSP/AP provider\n"); - return; - } - - for (i = 0; i < loaded_packages_count; i++) - { - if (!loaded_packages[i].name) continue; - SECUR32_addPackages(provider, 1, NULL, &loaded_packages[i].info); - } } NTSTATUS WINAPI LsaLookupAuthenticationPackage(HANDLE lsa_handle, PLSA_STRING package_name, PULONG package_id) { + UNICODE_STRING package_name_us, str; ULONG i; TRACE("%p %s %p\n", lsa_handle, debugstr_as(package_name), package_id); + if (RtlAnsiStringToUnicodeString(&package_name_us, package_name, TRUE)) + return STATUS_NO_MEMORY; + for (i = 0; i < loaded_packages_count; i++) { - if (!loaded_packages[i].name) continue; - if (!RtlCompareString(loaded_packages[i].name, package_name, FALSE)) + RtlInitUnicodeString(&str, loaded_packages[i].info.Name); + + if (RtlEqualUnicodeString(&package_name_us, &str, TRUE)) { + RtlFreeUnicodeString(&package_name_us); *package_id = i; return STATUS_SUCCESS; } } + RtlFreeUnicodeString(&package_name_us); return STATUS_UNSUCCESSFUL; /* FIXME */ } diff --git a/dlls/secur32/negotiate.c b/dlls/secur32/negotiate.c index 1c9864912b4..12bb8cd0c48 100644 --- a/dlls/secur32/negotiate.c +++ b/dlls/secur32/negotiate.c @@ -35,14 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(secur32); -struct sec_handle -{ - SECPKG_FUNCTION_TABLE *krb; - SECPKG_FUNCTION_TABLE *ntlm; - LSA_SEC_HANDLE handle_krb; - LSA_SEC_HANDLE handle_ntlm; -}; - struct user_context_data { enum @@ -50,7 +42,6 @@ struct user_context_data SSP_KERBEROS, SSP_NTLM } ssp; - BOOLEAN mapped_ctx; /* BYTE ssp_context_data[]; */ }; @@ -71,426 +62,6 @@ static CRITICAL_SECTION_DEBUG user_ctx_debug = }; static CRITICAL_SECTION user_ctx_cs = { &user_ctx_debug, -1, 0, 0, 0, 0 }; -static LSA_SECPKG_FUNCTION_TABLE *lsa_funcs; - -#define WINE_NO_CACHED_CREDENTIALS 0x10000000 -#define NEGO_MAX_TOKEN 48256 - -static WCHAR nego_name_W[] = {'N','e','g','o','t','i','a','t','e',0}; -static char nego_name_A[] = "Negotiate"; -static WCHAR negotiate_comment_W[] = - {'M','i','c','r','o','s','o','f','t',' ','P','a','c','k','a','g','e',' ', - 'N','e','g','o','t','i','a','t','o','r',0}; - -#define CAPS ( \ - SECPKG_FLAG_INTEGRITY | \ - SECPKG_FLAG_PRIVACY | \ - 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_RESTRICTED_TOKENS ) - -static NTSTATUS NTAPI nego_LsaApCallPackageUntrusted( PLSA_CLIENT_REQUEST req, void *in_buf, - void *client_buf_base, ULONG in_buf_len, void **out_buf, ULONG *out_buf_len, NTSTATUS *ret_status ) -{ - ULONG *MessageType; - - FIXME("%p, %p, %p, %lu, %p, %p, %p: stub\n", req, in_buf, client_buf_base, in_buf_len, out_buf, out_buf_len, ret_status); - - if (!in_buf || in_buf_len < sizeof(*MessageType) || !out_buf || !out_buf_len || !ret_status) - return STATUS_INVALID_PARAMETER; - - MessageType = in_buf; - switch (*MessageType) - { - case 1: /* NegGetCallerName */ - *ret_status = STATUS_NO_SUCH_LOGON_SESSION; - return STATUS_SUCCESS; - - default: - return SEC_E_UNSUPPORTED_FUNCTION; - } -} - -static NTSTATUS NTAPI nego_LsaApInitializePackage( ULONG package_id, PLSA_DISPATCH_TABLE dispatch, - PLSA_STRING database, PLSA_STRING confidentiality, PLSA_STRING *package_name ) -{ - char *name; - - name = dispatch->AllocateLsaHeap( sizeof(nego_name_A) ); - if (!name) return STATUS_NO_MEMORY; - - memcpy(name, nego_name_A, sizeof(nego_name_A)); - - *package_name = dispatch->AllocateLsaHeap( sizeof(**package_name) ); - if (!*package_name) - { - dispatch->FreeLsaHeap( name ); - return STATUS_NO_MEMORY; - } - - RtlInitString( *package_name, name ); - - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI nego_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params, - LSA_SECPKG_FUNCTION_TABLE *lsa_function_table ) -{ - TRACE( "%Iu, %p, %p\n", package_id, params, lsa_function_table ); - - lsa_funcs = lsa_function_table; - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI nego_SpShutdown( void ) -{ - TRACE( "\n" ); - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI nego_SpGetInfo( SecPkgInfoW *info ) -{ - const SecPkgInfoW infoW = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN, - nego_name_W, negotiate_comment_W}; - - TRACE( "%p\n", info ); - - /* LSA will make a copy before forwarding the structure, so - * it's safe to put pointers to dynamic or constant data there. - */ - *info = infoW; - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI nego_SpAcquireCredentialsHandle( - UNICODE_STRING *principal_us, ULONG credential_use, LUID *logon_id, void *auth_data, - void *get_key_fn, void *get_key_arg, LSA_SEC_HANDLE *credential, TimeStamp *expiry ) -{ - NTSTATUS ret; - struct sec_handle *cred; - SECPKG_FUNCTION_TABLE *package; - SECPKG_USER_FUNCTION_TABLE *user; - - TRACE( "%p, %#lx, %p, %p, %p, %p, %p, %p\n", principal_us, credential_use, - logon_id, auth_data, get_key_fn, get_key_arg, credential, expiry ); - - if (!(cred = calloc( 1, sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY; - - ret = SEC_E_NO_CREDENTIALS; - if ((package = lsa_find_package( "Kerberos", &user ))) - { - ret = package->SpAcquireCredentialsHandle( principal_us, credential_use, logon_id, auth_data, - get_key_fn, get_key_arg, &cred->handle_krb, expiry ); - if (ret == SEC_E_OK) - cred->krb = package; - } - - if ((package = lsa_find_package( "NTLM", &user ))) - { - ULONG cred_use = auth_data ? credential_use : credential_use | WINE_NO_CACHED_CREDENTIALS; - - ret = package->SpAcquireCredentialsHandle( principal_us, cred_use, logon_id, auth_data, - get_key_fn, get_key_arg, &cred->handle_ntlm, expiry ); - if (ret == SEC_E_OK) - cred->ntlm = package; - } - - if (cred->krb || cred->ntlm) - { - *credential = (LSA_SEC_HANDLE)cred; - return SEC_E_OK; - } - - free( cred ); - return ret; -} - -static NTSTATUS NTAPI nego_SpFreeCredentialsHandle( LSA_SEC_HANDLE credential ) -{ - struct sec_handle *cred; - - TRACE( "%Ix\n", credential ); - - if (!credential) return SEC_E_INVALID_HANDLE; - - cred = (struct sec_handle *)credential; - if (cred->krb) cred->krb->FreeCredentialsHandle( cred->handle_krb ); - if (cred->ntlm) cred->ntlm->FreeCredentialsHandle( cred->handle_ntlm ); - - free( cred ); - return SEC_E_OK; -} - -static NTSTATUS NTAPI nego_SpInitLsaModeContext( LSA_SEC_HANDLE credential, LSA_SEC_HANDLE context, - UNICODE_STRING *target_name, ULONG context_req, ULONG target_data_rep, SecBufferDesc *input, - LSA_SEC_HANDLE *new_context, SecBufferDesc *output, ULONG *context_attr, TimeStamp *expiry, - BOOLEAN *mapped_context, SecBuffer *context_data ) -{ - NTSTATUS ret = SEC_E_INVALID_HANDLE; - struct sec_handle *handle = NULL, *ctxt, *new_ctxt = NULL, *cred = NULL; - - TRACE( "%Ix, %Ix, %p, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential, context, target_name, - context_req, target_data_rep, input, new_context, output, context_attr, expiry, - mapped_context, context_data ); - - if (context) - { - handle = ctxt = (struct sec_handle *)context; - } - else if (credential) - { - handle = cred = (struct sec_handle *)credential; - if (!(new_ctxt = ctxt = calloc( 1, sizeof(*ctxt) ))) return SEC_E_INSUFFICIENT_MEMORY; - ctxt->krb = cred->krb; - ctxt->ntlm = cred->ntlm; - } - if (!handle) return SEC_E_INVALID_HANDLE; - - if (handle->krb) - { - ret = handle->krb->InitLsaModeContext( credential ? cred->handle_krb : 0, - context ? ctxt->handle_krb : 0, target_name, context_req, target_data_rep, input, - new_context ? &ctxt->handle_krb : NULL, output, context_attr, expiry, mapped_context, context_data ); - if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) - { - ctxt->ntlm = NULL; - *new_context = (LSA_SEC_HANDLE)ctxt; - if (new_ctxt == ctxt) new_ctxt = NULL; - } - else - { - ctxt->krb = NULL; - } - } - - if (ret != SEC_E_OK && ret != SEC_I_CONTINUE_NEEDED && handle->ntlm) - { - ret = handle->ntlm->InitLsaModeContext( credential ? cred->handle_ntlm : 0, - context ? ctxt->handle_ntlm : 0, target_name, context_req, target_data_rep, input, - new_context ? &ctxt->handle_ntlm : NULL, output, context_attr, expiry, mapped_context, context_data ); - if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) - { - ctxt->krb = NULL; - *new_context = (LSA_SEC_HANDLE)ctxt; - if (new_ctxt == ctxt) new_ctxt = NULL; - } - } - - if (ret == SEC_E_OK) - { - struct user_context_data *data; - ULONG size = sizeof( *data ) + context_data->cbBuffer; - SecBuffer negotiate_data; - - data = lsa_funcs->AllocateLsaHeap( size ); - if (!data) - { - lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); - free( new_ctxt ); - return SEC_E_INSUFFICIENT_MEMORY; - } - negotiate_data.cbBuffer = size; - negotiate_data.pvBuffer = data; - negotiate_data.BufferType = context_data->BufferType; - data->ssp = ctxt->krb ? SSP_KERBEROS : SSP_NTLM; - data->mapped_ctx = *mapped_context; - memcpy( data + 1, context_data->pvBuffer, context_data->cbBuffer ); - lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); - - - *mapped_context = TRUE; - *context_data = negotiate_data; - } - - free( new_ctxt ); - return ret; -} - -static NTSTATUS NTAPI nego_SpAcceptLsaModeContext( LSA_SEC_HANDLE credential, LSA_SEC_HANDLE context, - SecBufferDesc *input, ULONG context_req, ULONG target_data_rep, LSA_SEC_HANDLE *new_context, - SecBufferDesc *output, ULONG *context_attr, TimeStamp *expiry, BOOLEAN *mapped_context, SecBuffer *context_data ) -{ - SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; - struct sec_handle *handle = NULL, *ctxt, *new_ctxt = NULL, *cred = NULL; - - TRACE( "%Ix, %Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential, context, context_req, target_data_rep, - input, new_context, output, context_attr, expiry, mapped_context, context_data ); - - if (context) - { - handle = ctxt = (struct sec_handle *)context; - } - else if (credential) - { - handle = cred = (struct sec_handle *)credential; - if (!(new_ctxt = ctxt = calloc( 1, sizeof(*ctxt) ))) return SEC_E_INSUFFICIENT_MEMORY; - ctxt->krb = cred->krb; - ctxt->ntlm = cred->ntlm; - } - if (!handle) return SEC_E_INVALID_HANDLE; - - if (handle->krb) - { - ret = handle->krb->AcceptLsaModeContext( credential ? cred->handle_krb : 0, - context ? ctxt->handle_krb : 0, input, context_req, target_data_rep, - new_context ? &ctxt->handle_krb : NULL, - output, context_attr, expiry, mapped_context, context_data ); - if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) - { - ctxt->ntlm = NULL; - *new_context = (LSA_SEC_HANDLE)ctxt; - if (new_ctxt == ctxt) new_ctxt = NULL; - } - else - { - ctxt->krb = NULL; - } - } - - if (ret != SEC_E_OK && ret != SEC_I_CONTINUE_NEEDED && handle->ntlm) - { - ret = handle->ntlm->AcceptLsaModeContext( credential ? cred->handle_ntlm : 0, - context ? ctxt->handle_ntlm : 0, input, context_req, target_data_rep, - new_context ? &ctxt->handle_ntlm : NULL, - output, context_attr, expiry, mapped_context, context_data ); - if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) - { - ctxt->krb = NULL; - *new_context = (LSA_SEC_HANDLE)ctxt; - if (new_ctxt == ctxt) new_ctxt = NULL; - } - } - - if (ret == SEC_E_OK) - { - struct user_context_data *data; - ULONG size = sizeof( *data ) + context_data->cbBuffer; - SecBuffer negotiate_data; - - data = lsa_funcs->AllocateLsaHeap( size ); - if (!data) - { - lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); - free( new_ctxt ); - return SEC_E_INSUFFICIENT_MEMORY; - } - negotiate_data.cbBuffer = size; - negotiate_data.pvBuffer = data; - negotiate_data.BufferType = context_data->BufferType; - data->ssp = ctxt->krb ? SSP_KERBEROS : SSP_NTLM; - data->mapped_ctx = *mapped_context; - memcpy( data + 1, context_data->pvBuffer, context_data->cbBuffer ); - lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); - - *mapped_context = TRUE; - *context_data = negotiate_data; - } - - free( new_ctxt ); - return ret; -} - -static NTSTATUS NTAPI nego_SpDeleteContext( LSA_SEC_HANDLE context ) -{ - SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; - struct sec_handle *ctxt; - - TRACE( "%Ix\n", context ); - - if (!context) return SEC_E_INVALID_HANDLE; - - ctxt = (struct sec_handle *)context; - if (ctxt->krb) - { - ret = ctxt->krb->DeleteContext( ctxt->handle_krb ); - } - else if (ctxt->ntlm) - { - ret = ctxt->ntlm->DeleteContext( ctxt->handle_ntlm ); - } - TRACE( "freeing %p\n", ctxt ); - free( ctxt ); - return ret; -} - -static NTSTATUS NTAPI nego_SpQueryContextAttributes( LSA_SEC_HANDLE context, ULONG attribute, void *buffer ) -{ - SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; - struct sec_handle *ctxt; - - TRACE( "%Ix, %lu, %p\n", context, attribute, buffer ); - - if (!context) return SEC_E_INVALID_HANDLE; - - ctxt = (struct sec_handle *)context; - if (ctxt->krb) - { - ret = ctxt->krb->SpQueryContextAttributes( ctxt->handle_krb, attribute, buffer ); - } - else if (ctxt->ntlm) - { - ret = ctxt->ntlm->SpQueryContextAttributes( ctxt->handle_ntlm, attribute, buffer ); - } - return ret; -} - -static SECPKG_FUNCTION_TABLE nego_lsa_table = -{ - nego_LsaApInitializePackage, - NULL, /* LsaLogonUser */ - NULL, /* CallPackage */ - NULL, /* LogonTerminated */ - nego_LsaApCallPackageUntrusted, - NULL, /* CallPackagePassthrough */ - NULL, /* LogonUserEx */ - NULL, /* LogonUserEx2 */ - nego_SpInitialize, - nego_SpShutdown, - nego_SpGetInfo, - NULL, /* AcceptCredentials */ - nego_SpAcquireCredentialsHandle, - NULL, /* SpQueryCredentialsAttributes */ - nego_SpFreeCredentialsHandle, - NULL, /* SaveCredentials */ - NULL, /* GetCredentials */ - NULL, /* DeleteCredentials */ - nego_SpInitLsaModeContext, - nego_SpAcceptLsaModeContext, - nego_SpDeleteContext, - NULL, /* ApplyControlToken */ - NULL, /* GetUserInfo */ - NULL, /* GetExtendedInformation */ - nego_SpQueryContextAttributes, - NULL, /* SpAddCredentials */ - NULL, /* SetExtendedInformation */ - NULL, /* SetContextAttributes */ - NULL, /* SetCredentialsAttributes */ - NULL, /* ChangeAccountPassword */ - NULL, /* QueryMetaData */ - NULL, /* ExchangeMetaData */ - NULL, /* GetCredUIContext */ - NULL, /* UpdateCredentials */ - NULL, /* ValidateTargetInfo */ - NULL, /* PostLogonUser */ -}; - -NTSTATUS NTAPI nego_SpLsaModeInitialize(ULONG lsa_version, PULONG package_version, - PSECPKG_FUNCTION_TABLE *table, PULONG table_count) -{ - TRACE("%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count); - - *package_version = SECPKG_INTERFACE_VERSION; - *table = &nego_lsa_table; - *table_count = 1; - return STATUS_SUCCESS; -} - static NTSTATUS NTAPI nego_SpInstanceInit(ULONG version, SECPKG_DLL_FUNCTIONS *dll_function_table, void **user_functions) { TRACE("%#lx, %p, %p\n", version, dll_function_table, user_functions); @@ -517,7 +88,6 @@ static struct user_ctx* find_user_ctx( LSA_SEC_HANDLE handle ) static NTSTATUS NTAPI nego_SpInitUserModeContext( LSA_SEC_HANDLE handle, SecBuffer *buf ) { struct user_context_data *data = buf->pvBuffer; - SECPKG_FUNCTION_TABLE *package; struct user_ctx *ctx; SecBuffer ctx_data; NTSTATUS status = SEC_E_OK; @@ -547,21 +117,18 @@ static NTSTATUS NTAPI nego_SpInitUserModeContext( LSA_SEC_HANDLE handle, SecBuff ctx->handle = handle; - if (data->ssp == SSP_KERBEROS) - package = lsa_find_package( "Kerberos", &ctx->funcs ); - else - package = lsa_find_package( "NTLM", &ctx->funcs ); - if (!package) + ctx->funcs = lsa_find_func_table( data->ssp == SSP_KERBEROS ? L"Kerberos" : L"NTLM" ); + if (!ctx->funcs) status = SEC_E_INTERNAL_ERROR; - if (!status && data->mapped_ctx) + if (!status) status = ctx->funcs->InitUserModeContext( handle, &ctx_data ); if (status) { EnterCriticalSection( &user_ctx_cs ); list_remove( &ctx->entry ); - free( ctx ); LeaveCriticalSection( &user_ctx_cs ); + free( ctx ); return status; } return STATUS_SUCCESS; diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index ff91905fd62..3a1758d062e 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -73,9 +73,8 @@ SecurePackage *SECUR32_findPackageA(PCSTR packageName); /* Initialization functions for built-in providers */ void SECUR32_initSchannelSP(void); void load_auth_packages(void); -NTSTATUS NTAPI nego_SpLsaModeInitialize(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG); NTSTATUS NTAPI nego_SpUserModeInitialize(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG); -SECPKG_FUNCTION_TABLE *lsa_find_package(const char *name, SECPKG_USER_FUNCTION_TABLE **user_api); +extern SECPKG_USER_FUNCTION_TABLE *lsa_find_func_table( const WCHAR *name ); /* Cleanup functions for built-in providers */ void SECUR32_deinitSchannelSP(void); diff --git a/include/ntsecpkg.h b/include/ntsecpkg.h index 6b2dde43c55..0966390e932 100644 --- a/include/ntsecpkg.h +++ b/include/ntsecpkg.h @@ -59,6 +59,9 @@ extern "C" { #define SECPKG_CALL_BUFFER_MARSHAL 0x10000 #define SECPKG_CALL_UNLOCK 0x20000 +#define SECBUFFER_UNMAPPED 0x40000000 +#define SECBUFFER_KERNEL_MAP 0x20000000 + /* enum definitions for Secure Service Provider/Authentication Packages */ typedef enum _LSA_TOKEN_INFORMATION_TYPE { LsaTokenInformationNull, diff --git a/include/wine/lsass.idl b/include/wine/lsass.idl index 4641a9a8b2a..96831df28ef 100644 --- a/include/wine/lsass.idl +++ b/include/wine/lsass.idl @@ -30,6 +30,8 @@ cpp_quote("#define LSASS_ENDPOINT {'l','s','a','s','s','p','i','r','p','c',0}") ] interface lsass { + typedef [wire_marshal(ULONG64)] void* CLIENT_PTR; + cpp_quote("#if 0") typedef LONG NTSTATUS; @@ -42,8 +44,29 @@ interface lsass [string] WCHAR *Name; [string] WCHAR *Comment; } SecPkgInfoW; + + typedef struct + { + DWORD LowPart; + LONG HighPart; + } LUID, TimeStamp; + + typedef struct + { + ULONG cbBuffer; + ULONG BufferType; + CLIENT_PTR pvBuffer; + } SecBuffer; + + typedef struct + { + ULONG ulVersion; + ULONG cBuffers; + SecBuffer *pBuffers; + } SecBufferDesc; cpp_quote("#endif") + cpp_quote("#define MAX_SEC_BUFFERS 20") typedef struct { [string] WCHAR *module_name; @@ -55,4 +78,91 @@ interface lsass [in] handle_t binding, [out] ULONG *count, [out, size_is(, *count)] package_info **packages); + + NTSTATUS call_package_untrusted( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG64 handle, + [in] ULONG package_id, + [in, unique, size_is(in_buf_len)] BYTE *in_buf, + [in] CLIENT_PTR client_buf_base, + [in] ULONG in_buf_len, + [out, unique] CLIENT_PTR *out_buf, + [out, unique] ULONG *out_buf_len, + [out, unique] NTSTATUS *status); + + NTSTATUS acquire_credentials_handle( + [in] handle_t binding, + [in] DWORD thread_id, + [in, unique, string] WCHAR *principal, + [in, string] WCHAR *package, + [in] ULONG cred_use, + [in, unique] LUID *logon_id, + [in] CLIENT_PTR auth_data, + [in] CLIENT_PTR get_key_fn, + [in] CLIENT_PTR get_key_arg, + [out] ULONG *package_id, + [out] ULONG64 *cred_handle, + [out, unique] TimeStamp *expiry); + + NTSTATUS free_credentials_handle( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] ULONG64 handle); + + NTSTATUS query_credentials_attr( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] ULONG64 handle, + [in] ULONG attr, + [in] CLIENT_PTR buf); + + NTSTATUS initialize_security_context( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] ULONG64 cred_handle, + [in] ULONG64 ctx_handle, + [in, unique, string] WCHAR *target, + [in] ULONG context_req, + [in] ULONG data_rep, + [in, unique] SecBufferDesc *input, + [out] ULONG64 *new_ctx_handle, + [in, out, unique] SecBufferDesc *output, + [out] ULONG *context_attr, + [out] TimeStamp *expiry, + [out] BOOLEAN *mapped_ctx, + [in, out] SecBuffer *ctx_data); + + NTSTATUS accept_security_context( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] ULONG64 cred_handle, + [in] ULONG64 ctx_handle, + [in, unique] SecBufferDesc *input, + [in] ULONG context_req, + [in] ULONG data_rep, + [out] ULONG64 *new_ctx_handle, + [in, out, unique] SecBufferDesc *output, + [out] ULONG *context_attr, + [out] TimeStamp *expiry, + [out] BOOLEAN *mapped_ctx, + [in, out] SecBuffer *ctx_data); + + NTSTATUS delete_security_context( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] UINT64 handle); + + NTSTATUS query_context_attr( + [in] handle_t binding, + [in] DWORD thread_id, + [in] ULONG package_id, + [in] ULONG64 handle, + [in] ULONG attr, + [in] CLIENT_PTR buf); } diff --git a/programs/lsass/lsass.c b/programs/lsass/lsass.c index 09bf510d49d..f5fcad1160e 100644 --- a/programs/lsass/lsass.c +++ b/programs/lsass/lsass.c @@ -43,12 +43,73 @@ struct package static struct package *packages; static ULONG packages_count, packages_size; +static DWORD tls_index; + static const char *debugstr_as( const LSA_STRING *str ) { if (!str) return "<null>"; return debugstr_an( str->Buffer, str->Length ); } +static void init_call_info( handle_t binding, DWORD thread_id ) +{ + SECPKG_CALL_INFO *call_info = TlsGetValue( tls_index ); + + if (!call_info) + { + call_info = malloc( sizeof(*call_info) ); + if (!call_info) return; + TlsSetValue( tls_index, call_info ); + } + + call_info->ThreadId = thread_id; + if (!binding) + { + call_info->ProcessId = GetCurrentProcessId(); + call_info->Attributes = SECPKG_CALL_IN_PROC; + } + else + { + if (I_RpcBindingInqLocalClientPID( binding, &call_info->ProcessId )) + call_info->ProcessId = 0; + call_info->Attributes = 0; + + if (call_info->ProcessId) + { + HANDLE hproc = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, call_info->ProcessId ); + BOOL wow64 = FALSE; + + if (hproc) IsWow64Process( hproc, &wow64 ); + if (wow64) call_info->Attributes |= SECPKG_CALL_WOWCLIENT; + } + } +} + +static SECPKG_CALL_INFO *get_call_info( void ) +{ + return TlsGetValue( tls_index ); +} + +static struct package * lsa_lookup_package( const WCHAR *name ) +{ + ULONG i; + + for (i = 0; i < packages_count; i++) + { + if (!wcscmp( packages[i].info.Name, name )) + return packages + i; + } + return NULL; +} + +SECPKG_FUNCTION_TABLE *lsa_find_func_table( const WCHAR *name ) +{ + struct package *package = lsa_lookup_package( name ); + + if (package) return package->funcs; + return NULL; +} + static NTSTATUS NTAPI lsa_CreateLogonSession( LUID *logon_id ) { FIXME( "%p: stub\n", logon_id ); @@ -99,30 +160,143 @@ static void NTAPI lsa_FreeLsaHeap( void *p ) static NTSTATUS NTAPI lsa_AllocateClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void **p ) { - TRACE( "%p,%lu,%p\n", req, size, p ); - *p = malloc( size ); - return *p ? STATUS_SUCCESS : STATUS_NO_MEMORY; + SECPKG_CALL_INFO *call_info = get_call_info(); + NTSTATUS status; + HANDLE process; + CLIENT_ID cid; + SIZE_T s = size; + + TRACE("%p,%lu,%p\n", req, size, p); + + if (!call_info) return STATUS_NO_MEMORY; + if (call_info->Attributes & SECPKG_CALL_IN_PROC) + { + *p = malloc(size); + return *p ? STATUS_SUCCESS : STATUS_NO_MEMORY; + } + + cid.UniqueProcess = ULongToHandle(call_info->ProcessId); + cid.UniqueThread = 0; + status = NtOpenProcess(&process, PROCESS_VM_OPERATION, NULL, &cid); + if (status) return status; + + *p = NULL; + status = NtAllocateVirtualMemory(process, p, 0, &s, MEM_COMMIT, PAGE_READWRITE); + CloseHandle(process); + return status; } static NTSTATUS NTAPI lsa_FreeClientBuffer( PLSA_CLIENT_REQUEST req, void *p ) { - TRACE( "%p,%p\n", req, p ); - free( p ); - return STATUS_SUCCESS; + SECPKG_CALL_INFO *call_info = get_call_info(); + NTSTATUS status; + HANDLE process; + CLIENT_ID cid; + SIZE_T size = 0; + + TRACE("%p,%p\n", req, p); + + if (!call_info) return STATUS_NO_MEMORY; + if (call_info->Attributes & SECPKG_CALL_IN_PROC) + { + free(p); + return STATUS_SUCCESS; + } + + cid.UniqueProcess = ULongToHandle(call_info->ProcessId); + cid.UniqueThread = 0; + status = NtOpenProcess(&process, PROCESS_VM_OPERATION, NULL, &cid); + if (status) return status; + + status = NtFreeVirtualMemory(process, p, &size, MEM_RELEASE); + CloseHandle(process); + return status; } static NTSTATUS NTAPI lsa_CopyToClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void *client, void *buf ) { - TRACE( "%p,%lu,%p,%p\n", req, size, client, buf ); - memcpy( client, buf, size ); - return STATUS_SUCCESS; + SECPKG_CALL_INFO *call_info = get_call_info(); + NTSTATUS status; + HANDLE process; + CLIENT_ID cid; + + TRACE("%p,%lu,%p,%p\n", req, size, client, buf); + + if (!call_info) return STATUS_NO_MEMORY; + if (call_info->Attributes & SECPKG_CALL_IN_PROC) + { + memcpy(client, buf, size); + return STATUS_SUCCESS; + } + + cid.UniqueProcess = ULongToHandle(call_info->ProcessId); + cid.UniqueThread = 0; + status = NtOpenProcess(&process, PROCESS_VM_WRITE, NULL, &cid); + if (status) return status; + + status = NtWriteVirtualMemory(process, client, buf, size, NULL); + CloseHandle(process); + return status; } static NTSTATUS NTAPI lsa_CopyFromClientBuffer( PLSA_CLIENT_REQUEST req, ULONG size, void *buf, void *client ) { - TRACE( "%p,%lu,%p,%p\n", req, size, buf, client ); - memcpy( buf, client, size ); - return STATUS_SUCCESS; + SECPKG_CALL_INFO *call_info = get_call_info(); + NTSTATUS status; + HANDLE process; + CLIENT_ID cid; + + TRACE("%p,%lu,%p,%p\n", req, size, buf, client); + + if (!call_info) return STATUS_NO_MEMORY; + if (call_info->Attributes & SECPKG_CALL_IN_PROC) + { + memcpy(buf, client, size); + return STATUS_SUCCESS; + } + + cid.UniqueProcess = ULongToHandle(call_info->ProcessId); + cid.UniqueThread = 0; + status = NtOpenProcess(&process, PROCESS_VM_READ, NULL, &cid); + if (status) return status; + + status = NtReadVirtualMemory(process, client, buf, size, NULL); + CloseHandle(process); + return status; +} + +static NTSTATUS NTAPI lsa_MapBuffer( SecBuffer *in, SecBuffer *out ) +{ + SecBuffer tmp; + NTSTATUS status; + + if (in->BufferType & SECBUFFER_UNMAPPED) + { + if (out != in) *out = *in; + return SEC_E_OK; + } + + tmp.pvBuffer = lsa_AllocateLsaHeap( in->cbBuffer ); + if (!tmp.pvBuffer) return SEC_E_INSUFFICIENT_MEMORY; + status = lsa_CopyFromClientBuffer( NULL, in->cbBuffer, tmp.pvBuffer, in->pvBuffer ); + if (status) + { + lsa_FreeLsaHeap( tmp.pvBuffer ); + return SEC_E_INTERNAL_ERROR; + } + tmp.cbBuffer = in->cbBuffer; + tmp.BufferType = in->BufferType | SECBUFFER_UNMAPPED; + *out = tmp; + return SEC_E_OK; +} + +static BOOLEAN NTAPI lsa_GetCallInfo( SECPKG_CALL_INFO *info ) +{ + SECPKG_CALL_INFO *call_info = get_call_info(); + + if (!call_info || !call_info->ProcessId) return FALSE; + *info = *call_info; + return TRUE; } static LSA_DISPATCH_TABLE lsa_dispatch = @@ -140,6 +314,51 @@ static LSA_DISPATCH_TABLE lsa_dispatch = lsa_CopyFromClientBuffer }; +static LSA_SECPKG_FUNCTION_TABLE lsa_functions = +{ + lsa_CreateLogonSession, + lsa_DeleteLogonSession, + lsa_AddCredential, + lsa_GetCredentials, + lsa_DeleteCredential, + lsa_AllocateLsaHeap, + lsa_FreeLsaHeap, + lsa_AllocateClientBuffer, + lsa_FreeClientBuffer, + lsa_CopyToClientBuffer, + lsa_CopyFromClientBuffer, + NULL, /* ImpersonateClient */ + NULL, /* UnloadPackage */ + NULL, /* DuplicateHandle */ + NULL, /* SaveSupplementalCredentials */ + NULL, /* CreateThread */ + NULL, /* GetClientInfo */ + NULL, /* RegisterNotification */ + NULL, /* CancelNotification */ + lsa_MapBuffer, + NULL, /* CreateToken */ + NULL, /* AuditLogon */ + NULL, /* CallPackage */ + NULL, /* FreeReturnBuffer */ + lsa_GetCallInfo, + NULL, /* CallPackageEx */ + NULL, /* CreateSharedMemory */ + NULL, /* AllocateSharedMemory */ + NULL, /* FreeSharedMemory */ + NULL, /* DeleteSharedMemory */ + NULL, /* OpenSamUser */ + NULL, /* GetUserCredentials */ + NULL, /* GetUserAuthData */ + NULL, /* CloseSamUser */ + NULL, /* ConvertAuthDataToToken */ + NULL, /* ClientCallback */ + NULL, /* UpdateCredentials */ + NULL, /* GetAuthDataForUser */ + NULL, /* CrackSingleName */ + NULL, /* AuditAccountLogon */ + NULL, /* CallPackagePassthrough */ +}; + static BOOL init_package( const WCHAR *module, SpLsaModeInitializeFn init ) { SECPKG_FUNCTION_TABLE *tables; @@ -170,13 +389,14 @@ static BOOL init_package( const WCHAR *module, SpLsaModeInitializeFn init ) for (i = 0; i < count; i++) { + init_call_info( 0, GetCurrentThreadId() ); if (tables[i].InitializePackage( packages_count, &lsa_dispatch, NULL, NULL, &name )) continue; TRACE( "name %s, version %#lx, api table %p\n", debugstr_as(name), api_version, &tables[i] ); lsa_FreeLsaHeap( name ); - if (tables[i].Initialize( packages_count, NULL /* FIXME: params */, NULL )) + if (tables[i].Initialize( packages_count, NULL /* FIXME: params */, &lsa_functions )) continue; if (tables[i].GetInfo( &info )) continue; @@ -196,6 +416,8 @@ void load_auth_packages( void ) DWORD err, i; HKEY root; + tls_index = TlsAlloc(); + /* "Negotiate" has package id 0, .Net depends on this. */ init_package( L"", nego_SpLsaModeInitialize ); @@ -239,3 +461,261 @@ NTSTATUS __cdecl get_packages( handle_t binding, ULONG *count, package_info **ou } return SEC_E_OK; } + +NTSTATUS __cdecl call_package_untrusted( handle_t binding, DWORD thread_id, + ULONG64 handle, ULONG package_id, BYTE *in_buf, void *client_buf_base, + ULONG in_buf_len, void **out_buf, ULONG *out_buf_len, NTSTATUS *prot_status ) +{ + NTSTATUS status; + + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->CallPackageUntrusted) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + status = packages[package_id].funcs->CallPackageUntrusted( NULL /* FIXME*/, in_buf, + client_buf_base, in_buf_len, out_buf, out_buf_len, prot_status ); + return status; +} + +NTSTATUS __cdecl acquire_credentials_handle( handle_t binding, DWORD thread_id, + WCHAR *principal, WCHAR *package_name, ULONG cred_use, LUID *logon_id, + void *auth_data, void *get_key_fn, void *get_key_arg, + ULONG *package_id, ULONG64 *cred_handle, TimeStamp *expiry ) +{ + LSA_SEC_HANDLE lsa_credential; + UNICODE_STRING principal_us; + struct package *package; + NTSTATUS status; + + if (get_key_fn || get_key_arg) + FIXME("unsupported get_key_* arguments\n"); + + if (!(package = lsa_lookup_package( package_name ))) + return SEC_E_SECPKG_NOT_FOUND; + if (!package->funcs->SpAcquireCredentialsHandle) + return SEC_E_UNSUPPORTED_FUNCTION; + + if (principal) + RtlInitUnicodeString(&principal_us, principal); + + init_call_info( binding, thread_id ); + status = package->funcs->SpAcquireCredentialsHandle( principal ? &principal_us : NULL, + cred_use, logon_id, auth_data, NULL, NULL, &lsa_credential, expiry ); + if (!status) + { + *cred_handle = lsa_credential; + *package_id = package - packages; + } + return status; +} + +NTSTATUS __cdecl free_credentials_handle( handle_t binding, + DWORD thread_id, ULONG package_id, ULONG64 handle ) +{ + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->FreeCredentialsHandle) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + return packages[package_id].funcs->FreeCredentialsHandle( handle ); +} + +NTSTATUS __cdecl query_credentials_attr( handle_t binding, DWORD thread_id, + ULONG package_id, ULONG64 handle, ULONG attr, void *buf ) +{ + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->SpQueryCredentialsAttributes) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + return packages[package_id].funcs->SpQueryCredentialsAttributes( + handle, attr, buf ); +} + +static void init_sec_buffers( BOOL alloc, SecBufferDesc *desc, void **client_bufs ) +{ + ULONG i; + + if (!desc) return; + + for (i = 0; i < desc->cBuffers; i++) + { + if (alloc) desc->pBuffers[i].pvBuffer = NULL; + client_bufs[i] = desc->pBuffers[i].pvBuffer; + } +} + +static NTSTATUS remap_buffer( SecBuffer *buf, void *client_buf ) +{ + NTSTATUS status = SEC_E_OK; + + if (!client_buf && buf->pvBuffer) + { + status = lsa_AllocateClientBuffer( NULL, buf->cbBuffer, &client_buf ); + } + else if (!(buf->BufferType & SECBUFFER_UNMAPPED)) + { + return SEC_E_OK; + } + + if (!status) + status = lsa_CopyToClientBuffer( NULL, buf->cbBuffer, client_buf, buf->pvBuffer ); + lsa_FreeLsaHeap( buf->pvBuffer ); + + buf->BufferType &= ~SECBUFFER_UNMAPPED; + buf->pvBuffer = client_buf; + return status; +} + +NTSTATUS __cdecl initialize_security_context( handle_t binding, DWORD thread_id, + ULONG package_id, ULONG64 cred_handle, ULONG64 ctx_handle, WCHAR *target, + ULONG context_req, ULONG data_rep, SecBufferDesc *input, + ULONG64 *new_ctx_handle, SecBufferDesc *output, ULONG *context_attr, + TimeStamp *expiry, BOOLEAN *mapped_ctx, SecBuffer *ctx_data ) +{ + CLIENT_PTR output_ptrs[MAX_SEC_BUFFERS]; + LSA_SEC_HANDLE lsa_ctx_handle; + UNICODE_STRING target_us; + NTSTATUS status, status2; + UINT i; + + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->InitLsaModeContext) + return SEC_E_UNSUPPORTED_FUNCTION; + + if (target) + RtlInitUnicodeString(&target_us, target); + + init_call_info( binding, thread_id ); + init_sec_buffers( context_req & ISC_REQ_ALLOCATE_MEMORY, output, output_ptrs ); + + status = packages[package_id].funcs->InitLsaModeContext( cred_handle, ctx_handle, + target ? &target_us : NULL, context_req, data_rep, input, + &lsa_ctx_handle, output, context_attr, expiry, mapped_ctx, ctx_data ); + for (i = 0; input && i < input->cBuffers; i++) + { + if (input->pBuffers[i].BufferType & SECBUFFER_UNMAPPED) + lsa_FreeLsaHeap( input->pBuffers[i].pvBuffer ); + } + if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + { + for (i = 0; output && i < output->cBuffers; i++) + { + if (output->pBuffers[i].BufferType & SECBUFFER_UNMAPPED) + { + lsa_FreeLsaHeap( output->pBuffers[i].pvBuffer ); + output->pBuffers[i].pvBuffer = output_ptrs[i]; + } + } + return status; + } + + for (i = 0; output && i < output->cBuffers; i++) + { + status2 = remap_buffer( output->pBuffers + i, output_ptrs[i] ); + if (status2) status = status2; + } + status2 = remap_buffer( ctx_data, NULL ); + if (status2) status = status2; + + if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + { + if (packages[package_id].funcs->DeleteContext) + packages[package_id].funcs->DeleteContext( lsa_ctx_handle ); + } + else + { + *new_ctx_handle = lsa_ctx_handle; + } + return status; +} + +NTSTATUS __cdecl accept_security_context( handle_t binding, DWORD thread_id, + ULONG package_id, ULONG64 cred_handle, ULONG64 ctx_handle, + SecBufferDesc *input, ULONG context_req, ULONG data_rep, + ULONG64 *new_ctx_handle, SecBufferDesc *output, ULONG *context_attr, + TimeStamp *expiry, BOOLEAN *mapped_ctx, SecBuffer *ctx_data ) +{ + CLIENT_PTR output_ptrs[MAX_SEC_BUFFERS]; + LSA_SEC_HANDLE lsa_ctx_handle; + NTSTATUS status, status2; + UINT i; + + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->AcceptLsaModeContext) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + init_sec_buffers( context_req & ASC_REQ_ALLOCATE_MEMORY, output, output_ptrs ); + + status = packages[package_id].funcs->AcceptLsaModeContext( cred_handle, + ctx_handle, input, context_req, data_rep, &lsa_ctx_handle, output, + context_attr, expiry, mapped_ctx, ctx_data ); + for (i = 0; input && i < input->cBuffers; i++) + { + if (input->pBuffers[i].BufferType & SECBUFFER_UNMAPPED) + lsa_FreeLsaHeap( input->pBuffers[i].pvBuffer ); + } + if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + { + for (i = 0; output && i < output->cBuffers; i++) + { + if (output->pBuffers[i].BufferType & SECBUFFER_UNMAPPED) + { + lsa_FreeLsaHeap( output->pBuffers[i].pvBuffer ); + output->pBuffers[i].pvBuffer = output_ptrs[i]; + } + } + return status; + } + + for (i = 0; output && i < output->cBuffers; i++) + { + status2 = remap_buffer( output->pBuffers + i, output_ptrs[i] ); + if (status2) status = status2; + } + status2 = remap_buffer( ctx_data, NULL ); + if (status2) status = status2; + + if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + { + if (packages[package_id].funcs->DeleteContext) + packages[package_id].funcs->DeleteContext( lsa_ctx_handle ); + } + else + { + *new_ctx_handle = lsa_ctx_handle; + } + return status; +} + +NTSTATUS __cdecl delete_security_context( handle_t binding, + DWORD thread_id, ULONG package_id, ULONG64 handle ) +{ + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->DeleteContext) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + return packages[package_id].funcs->DeleteContext( handle ); +} + +NTSTATUS __cdecl query_context_attr( handle_t binding, DWORD thread_id, + ULONG package_id, ULONG64 handle, ULONG attr, void *buf ) +{ + if (package_id >= packages_count) + return STATUS_NO_SUCH_PACKAGE; + if (!packages[package_id].funcs->SpQueryContextAttributes) + return SEC_E_UNSUPPORTED_FUNCTION; + + init_call_info( binding, thread_id ); + return packages[package_id].funcs->SpQueryContextAttributes( + handle, attr, (void *)buf ); +} diff --git a/programs/lsass/lsass_private.h b/programs/lsass/lsass_private.h index 4aa89338eb6..b441012adcb 100644 --- a/programs/lsass/lsass_private.h +++ b/programs/lsass/lsass_private.h @@ -21,5 +21,6 @@ extern void load_auth_packages( void ); +extern SECPKG_FUNCTION_TABLE *lsa_find_func_table( const WCHAR *name ); extern NTSTATUS NTAPI nego_SpLsaModeInitialize( ULONG lsa_version, PULONG package_version, PSECPKG_FUNCTION_TABLE *table, PULONG table_count ); diff --git a/programs/lsass/main.c b/programs/lsass/main.c index 8bccafbdcf4..f2d8096cbc8 100644 --- a/programs/lsass/main.c +++ b/programs/lsass/main.c @@ -42,6 +42,32 @@ void __RPC_USER MIDL_user_free( void *p ) free( p ); } +ULONG __RPC_USER CLIENT_PTR_UserSize( ULONG *flags, ULONG pos, CLIENT_PTR *client_ptr ) +{ + return sizeof(ULONG64); +} + +unsigned char* __RPC_USER CLIENT_PTR_UserMarshal( ULONG *flags, unsigned char *buf, CLIENT_PTR *client_ptr ) +{ + ULONG64 data = (ULONG_PTR)*client_ptr; + + memcpy( buf, &data, sizeof(data) ); + return buf + sizeof(data); +} + +unsigned char* __RPC_USER CLIENT_PTR_UserUnmarshal( ULONG *flags, unsigned char *buf, CLIENT_PTR *client_ptr ) +{ + ULONG64 data; + + memcpy( &data, buf, sizeof(data) ); + *(ULONG_PTR*)client_ptr = data; + return buf + sizeof(data); +} + +void __RPC_USER CLIENT_PTR_UserFree( ULONG *flags, CLIENT_PTR *client_ptr ) +{ +} + static RPC_STATUS rpc_initialize( void ) { unsigned short protseq[] = LSASS_PROTSEQ; diff --git a/programs/lsass/negotiate.c b/programs/lsass/negotiate.c index 60fed60a702..7cac52bfd9a 100644 --- a/programs/lsass/negotiate.c +++ b/programs/lsass/negotiate.c @@ -20,14 +20,35 @@ #include "wtypes.h" #include "winternl.h" #include "sspi.h" -#include "ntsecapi.h" -#include "ntsecpkg.h" #include "ntstatus.h" #include "rpc.h" +#include "lsass_private.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); +struct sec_handle +{ + SECPKG_FUNCTION_TABLE *krb; + SECPKG_FUNCTION_TABLE *ntlm; + LSA_SEC_HANDLE handle_krb; + LSA_SEC_HANDLE handle_ntlm; +}; + +struct user_context_data +{ + enum + { + SSP_KERBEROS, + SSP_NTLM + } ssp; + /* BYTE ssp_context_data[]; */ +}; + +static LSA_SECPKG_FUNCTION_TABLE *lsa_funcs; + +#define WINE_NO_CACHED_CREDENTIALS 0x10000000 #define NEGO_MAX_TOKEN 48256 static WCHAR nego_name_W[] = L"Negotiate"; @@ -47,6 +68,28 @@ static WCHAR negotiate_comment_W[] = L"Microsoft Package Negotiator"; SECPKG_FLAG_LOGON | \ SECPKG_FLAG_RESTRICTED_TOKENS ) +static NTSTATUS NTAPI nego_LsaApCallPackageUntrusted( PLSA_CLIENT_REQUEST req, void *in_buf, + void *client_buf_base, ULONG in_buf_len, void **out_buf, ULONG *out_buf_len, NTSTATUS *ret_status ) +{ + ULONG *MessageType; + + FIXME("%p, %p, %p, %lu, %p, %p, %p: stub\n", req, in_buf, client_buf_base, in_buf_len, out_buf, out_buf_len, ret_status); + + if (!in_buf || in_buf_len < sizeof(*MessageType) || !out_buf || !out_buf_len || !ret_status) + return STATUS_INVALID_PARAMETER; + + MessageType = in_buf; + switch (*MessageType) + { + case 1: /* NegGetCallerName */ + *ret_status = STATUS_NO_SUCH_LOGON_SESSION; + return STATUS_SUCCESS; + + default: + return SEC_E_UNSUPPORTED_FUNCTION; + } +} + static NTSTATUS NTAPI nego_LsaApInitializePackage( ULONG package_id, PLSA_DISPATCH_TABLE dispatch, PLSA_STRING database, PLSA_STRING confidentiality, PLSA_STRING *package_name ) { @@ -73,6 +116,14 @@ static NTSTATUS NTAPI nego_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS LSA_SECPKG_FUNCTION_TABLE *lsa_function_table ) { TRACE( "%Iu, %p, %p\n", package_id, params, lsa_function_table ); + + lsa_funcs = lsa_function_table; + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI nego_SpShutdown( void ) +{ + TRACE( "\n" ); return STATUS_SUCCESS; } @@ -90,33 +141,273 @@ static NTSTATUS NTAPI nego_SpGetInfo( SecPkgInfoW *info ) return STATUS_SUCCESS; } +static NTSTATUS NTAPI nego_SpAcquireCredentialsHandle( + UNICODE_STRING *principal_us, ULONG credential_use, LUID *logon_id, void *auth_data, + void *get_key_fn, void *get_key_arg, LSA_SEC_HANDLE *credential, TimeStamp *expiry ) +{ + NTSTATUS ret; + struct sec_handle *cred; + SECPKG_FUNCTION_TABLE *package; + + TRACE( "%p, %#lx, %p, %p, %p, %p, %p, %p\n", principal_us, credential_use, + logon_id, auth_data, get_key_fn, get_key_arg, credential, expiry ); + + if (!(cred = calloc( 1, sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY; + + ret = SEC_E_NO_CREDENTIALS; + if ((package = lsa_find_func_table( L"Kerberos" ))) + { + ret = package->SpAcquireCredentialsHandle( principal_us, credential_use, logon_id, auth_data, + get_key_fn, get_key_arg, &cred->handle_krb, expiry ); + if (ret == SEC_E_OK) + cred->krb = package; + } + + if ((package = lsa_find_func_table( L"NTLM" ))) + { + ULONG cred_use = auth_data ? credential_use : credential_use | WINE_NO_CACHED_CREDENTIALS; + + ret = package->SpAcquireCredentialsHandle( principal_us, cred_use, logon_id, auth_data, + get_key_fn, get_key_arg, &cred->handle_ntlm, expiry ); + if (ret == SEC_E_OK) + cred->ntlm = package; + } + + if (cred->krb || cred->ntlm) + { + *credential = (LSA_SEC_HANDLE)cred; + return SEC_E_OK; + } + + free( cred ); + return ret; +} + +static NTSTATUS NTAPI nego_SpFreeCredentialsHandle( LSA_SEC_HANDLE credential ) +{ + struct sec_handle *cred; + + TRACE( "%Ix\n", credential ); + + if (!credential) return SEC_E_INVALID_HANDLE; + + cred = (struct sec_handle *)credential; + if (cred->krb) cred->krb->FreeCredentialsHandle( cred->handle_krb ); + if (cred->ntlm) cred->ntlm->FreeCredentialsHandle( cred->handle_ntlm ); + + free( cred ); + return SEC_E_OK; +} + +static NTSTATUS NTAPI nego_SpInitLsaModeContext( LSA_SEC_HANDLE credential, LSA_SEC_HANDLE context, + UNICODE_STRING *target_name, ULONG context_req, ULONG target_data_rep, SecBufferDesc *input, + LSA_SEC_HANDLE *new_context, SecBufferDesc *output, ULONG *context_attr, TimeStamp *expiry, + BOOLEAN *mapped_context, SecBuffer *context_data ) +{ + NTSTATUS ret = SEC_E_INVALID_HANDLE; + struct sec_handle *handle = NULL, *ctxt, *new_ctxt = NULL, *cred = NULL; + + TRACE( "%Ix, %Ix, %p, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential, context, target_name, + context_req, target_data_rep, input, new_context, output, context_attr, expiry, + mapped_context, context_data ); + + if (context) + { + handle = ctxt = (struct sec_handle *)context; + } + else if (credential) + { + handle = cred = (struct sec_handle *)credential; + if (!(new_ctxt = ctxt = calloc( 1, sizeof(*ctxt) ))) return SEC_E_INSUFFICIENT_MEMORY; + ctxt->krb = cred->krb; + ctxt->ntlm = cred->ntlm; + } + if (!handle) return SEC_E_INVALID_HANDLE; + + if (handle->krb) + { + ret = handle->krb->InitLsaModeContext( credential ? cred->handle_krb : 0, + context ? ctxt->handle_krb : 0, target_name, context_req, target_data_rep, input, + new_context ? &ctxt->handle_krb : NULL, output, context_attr, expiry, mapped_context, context_data ); + if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) + { + ctxt->ntlm = NULL; + *new_context = (LSA_SEC_HANDLE)ctxt; + if (new_ctxt == ctxt) new_ctxt = NULL; + } + else + { + ctxt->krb = NULL; + } + } + + if (ret != SEC_E_OK && ret != SEC_I_CONTINUE_NEEDED && handle->ntlm) + { + ret = handle->ntlm->InitLsaModeContext( credential ? cred->handle_ntlm : 0, + context ? ctxt->handle_ntlm : 0, target_name, context_req, target_data_rep, input, + new_context ? &ctxt->handle_ntlm : NULL, output, context_attr, expiry, mapped_context, context_data ); + if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) + { + ctxt->krb = NULL; + *new_context = (LSA_SEC_HANDLE)ctxt; + if (new_ctxt == ctxt) new_ctxt = NULL; + } + } + + if (mapped_context) + { + struct user_context_data *data = lsa_funcs->AllocateLsaHeap( sizeof(*data) + context_data->cbBuffer ); + + data->ssp = (ctxt->krb ? SSP_KERBEROS : SSP_NTLM); + memcpy( data + 1, context_data->pvBuffer, context_data->cbBuffer ); + context_data->cbBuffer += sizeof(*data); + lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); + context_data->pvBuffer = data; + } + free( new_ctxt ); + return ret; +} + +static NTSTATUS NTAPI nego_SpAcceptLsaModeContext( LSA_SEC_HANDLE credential, LSA_SEC_HANDLE context, + SecBufferDesc *input, ULONG context_req, ULONG target_data_rep, LSA_SEC_HANDLE *new_context, + SecBufferDesc *output, ULONG *context_attr, TimeStamp *expiry, BOOLEAN *mapped_context, SecBuffer *context_data ) +{ + SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; + struct sec_handle *handle = NULL, *ctxt, *new_ctxt = NULL, *cred = NULL; + + TRACE( "%Ix, %Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential, context, context_req, target_data_rep, + input, new_context, output, context_attr, expiry, mapped_context, context_data ); + + if (context) + { + handle = ctxt = (struct sec_handle *)context; + } + else if (credential) + { + handle = cred = (struct sec_handle *)credential; + if (!(new_ctxt = ctxt = calloc( 1, sizeof(*ctxt) ))) return SEC_E_INSUFFICIENT_MEMORY; + ctxt->krb = cred->krb; + ctxt->ntlm = cred->ntlm; + } + if (!handle) return SEC_E_INVALID_HANDLE; + + if (handle->krb) + { + ret = handle->krb->AcceptLsaModeContext( credential ? cred->handle_krb : 0, + context ? ctxt->handle_krb : 0, input, context_req, target_data_rep, + new_context ? &ctxt->handle_krb : NULL, + output, context_attr, expiry, mapped_context, context_data ); + if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) + { + ctxt->ntlm = NULL; + *new_context = (LSA_SEC_HANDLE)ctxt; + if (new_ctxt == ctxt) new_ctxt = NULL; + } + else + { + ctxt->krb = NULL; + } + } + + if (ret != SEC_E_OK && ret != SEC_I_CONTINUE_NEEDED && handle->ntlm) + { + ret = handle->ntlm->AcceptLsaModeContext( credential ? cred->handle_ntlm : 0, + context ? ctxt->handle_ntlm : 0, input, context_req, target_data_rep, + new_context ? &ctxt->handle_ntlm : NULL, + output, context_attr, expiry, mapped_context, context_data ); + if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) && new_context) + { + ctxt->krb = NULL; + *new_context = (LSA_SEC_HANDLE)ctxt; + if (new_ctxt == ctxt) new_ctxt = NULL; + } + } + + if (mapped_context) + { + struct user_context_data *data = lsa_funcs->AllocateLsaHeap( sizeof(*data) + context_data->cbBuffer ); + + data->ssp = (ctxt->krb ? SSP_KERBEROS : SSP_NTLM); + memcpy( data + 1, context_data->pvBuffer, context_data->cbBuffer ); + context_data->cbBuffer += sizeof(*data); + lsa_funcs->FreeLsaHeap( context_data->pvBuffer ); + context_data->pvBuffer = data; + } + free( new_ctxt ); + return ret; +} + +static NTSTATUS NTAPI nego_SpDeleteContext( LSA_SEC_HANDLE context ) +{ + SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; + struct sec_handle *ctxt; + + TRACE( "%Ix\n", context ); + + if (!context) return SEC_E_INVALID_HANDLE; + + ctxt = (struct sec_handle *)context; + if (ctxt->krb) + { + ret = ctxt->krb->DeleteContext( ctxt->handle_krb ); + } + else if (ctxt->ntlm) + { + ret = ctxt->ntlm->DeleteContext( ctxt->handle_ntlm ); + } + TRACE( "freeing %p\n", ctxt ); + free( ctxt ); + return ret; +} + +static NTSTATUS NTAPI nego_SpQueryContextAttributes( LSA_SEC_HANDLE context, ULONG attribute, void *buffer ) +{ + SECURITY_STATUS ret = SEC_E_INVALID_HANDLE; + struct sec_handle *ctxt; + + TRACE( "%Ix, %lu, %p\n", context, attribute, buffer ); + + if (!context) return SEC_E_INVALID_HANDLE; + + ctxt = (struct sec_handle *)context; + if (ctxt->krb) + { + ret = ctxt->krb->SpQueryContextAttributes( ctxt->handle_krb, attribute, buffer ); + } + else if (ctxt->ntlm) + { + ret = ctxt->ntlm->SpQueryContextAttributes( ctxt->handle_ntlm, attribute, buffer ); + } + return ret; +} + static SECPKG_FUNCTION_TABLE nego_lsa_table = { nego_LsaApInitializePackage, NULL, /* LsaLogonUser */ NULL, /* CallPackage */ NULL, /* LogonTerminated */ - NULL, /* LsaApCallPackageUntrusted */ + nego_LsaApCallPackageUntrusted, NULL, /* CallPackagePassthrough */ NULL, /* LogonUserEx */ NULL, /* LogonUserEx2 */ nego_SpInitialize, - NULL, /* SpShutdown */ + nego_SpShutdown, nego_SpGetInfo, NULL, /* AcceptCredentials */ - NULL, /* SpAcquireCredentialsHandle */ + nego_SpAcquireCredentialsHandle, NULL, /* SpQueryCredentialsAttributes */ - NULL, /* SpFreeCredentialsHandle */ + nego_SpFreeCredentialsHandle, NULL, /* SaveCredentials */ NULL, /* GetCredentials */ NULL, /* DeleteCredentials */ - NULL, /* SpInitLsaModeContext */ - NULL, /* SpAcceptLsaModeContext */ - NULL, /* SpDeleteContext */ + nego_SpInitLsaModeContext, + nego_SpAcceptLsaModeContext, + nego_SpDeleteContext, NULL, /* ApplyControlToken */ NULL, /* GetUserInfo */ NULL, /* GetExtendedInformation */ - NULL, /* SpQueryContextAttributes */ + nego_SpQueryContextAttributes, NULL, /* SpAddCredentials */ NULL, /* SetExtendedInformation */ NULL, /* SetContextAttributes */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11747
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)