/* * Copyright (C) 2004 Juan Lang * Copyright (C) 2007 Kai Blin * Copyright (C) 2017, 2018 Dmitry Timoshkov * * Local Security Authority functions, as far as secur32 has them. * * 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 "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winreg.h" #include "sspi.h" #include "ntsecapi.h" #include "ntsecpkg.h" #include "winternl.h" #include "rpc.h" #include "secur32_priv.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); #define LSA_MAGIC ('L' << 24 | 'S' << 16 | 'A' << 8 | ' ') struct lsa_package { ULONG package_id; HMODULE mod; LSA_STRING *name; ULONG lsa_api_version, lsa_table_count, user_api_version, user_table_count; SECPKG_FUNCTION_TABLE *lsa_api; SECPKG_USER_FUNCTION_TABLE *user_api; }; static struct lsa_package *loaded_packages; static ULONG loaded_packages_count; struct lsa_connection { DWORD magic; }; static const char *debugstr_as(const LSA_STRING *str) { if (!str) return "<null>"; return debugstr_an(str->Buffer, str->Length); } 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,%u,%p,%u,%p,%p,%p\n", lsa_handle, package_id, in_buffer, in_buffer_length, out_buffer, out_buffer_length, status); 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; } } return STATUS_INVALID_PARAMETER; } static struct lsa_connection *alloc_lsa_connection(void) { struct lsa_connection *ret; if (!(ret = heap_alloc(sizeof(*ret)))) return NULL; ret->magic = LSA_MAGIC; return ret; } NTSTATUS WINAPI LsaConnectUntrusted(PHANDLE LsaHandle) { struct lsa_connection *lsa_conn; TRACE("%p\n", LsaHandle); if (!(lsa_conn = alloc_lsa_connection())) return STATUS_NO_MEMORY; *LsaHandle = lsa_conn; return STATUS_SUCCESS; } NTSTATUS WINAPI LsaRegisterLogonProcess(PLSA_STRING LogonProcessName, PHANDLE LsaHandle, PLSA_OPERATIONAL_MODE SecurityMode) { struct lsa_connection *lsa_conn; FIXME("%s %p %p stub\n", debugstr_as(LogonProcessName), LsaHandle, SecurityMode); if (!(lsa_conn = alloc_lsa_connection())) return STATUS_NO_MEMORY; *LsaHandle = lsa_conn; return STATUS_SUCCESS; } NTSTATUS WINAPI LsaDeregisterLogonProcess(HANDLE LsaHandle) { struct lsa_connection *lsa_conn = (struct lsa_connection *)LsaHandle; TRACE("%p\n", LsaHandle); if (!lsa_conn || lsa_conn->magic != LSA_MAGIC) return STATUS_INVALID_HANDLE; lsa_conn->magic = 0; heap_free(lsa_conn); return STATUS_SUCCESS; } NTSTATUS WINAPI LsaEnumerateLogonSessions(PULONG LogonSessionCount, PLUID* LogonSessionList) { FIXME("%p %p stub\n", LogonSessionCount, LogonSessionList); *LogonSessionCount = 0; *LogonSessionList = NULL; return STATUS_SUCCESS; } NTSTATUS WINAPI LsaFreeReturnBuffer(PVOID buffer) { TRACE("%p\n", buffer); heap_free(buffer); return STATUS_SUCCESS; } NTSTATUS WINAPI LsaGetLogonSessionData(PLUID LogonId, PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData) { FIXME("%p %p stub\n", LogonId, ppLogonSessionData); *ppLogonSessionData = NULL; return STATUS_NOT_IMPLEMENTED; } NTSTATUS WINAPI LsaLogonUser(HANDLE LsaHandle, PLSA_STRING OriginName, SECURITY_LOGON_TYPE LogonType, ULONG AuthenticationPackage, PVOID AuthenticationInformation, ULONG AuthenticationInformationLength, PTOKEN_GROUPS LocalGroups, PTOKEN_SOURCE SourceContext, PVOID* ProfileBuffer, PULONG ProfileBufferLength, PLUID LogonId, PHANDLE Token, PQUOTA_LIMITS Quotas, PNTSTATUS SubStatus) { FIXME("%p %s %d %d %p %d %p %p %p %p %p %p %p %p stub\n", LsaHandle, debugstr_as(OriginName), LogonType, AuthenticationPackage, AuthenticationInformation, AuthenticationInformationLength, LocalGroups, SourceContext, ProfileBuffer, ProfileBufferLength, LogonId, Token, Quotas, SubStatus); 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,%u,%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,%#x,%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,%#x,%s: stub\n", logon_id, package_id, debugstr_as(primary_key)); return STATUS_NOT_IMPLEMENTED; } static void * NTAPI lsa_AllocateLsaHeap(ULONG size) { TRACE("%u\n", size); return heap_alloc(size); } static void NTAPI lsa_FreeLsaHeap(void *p) { TRACE("%p\n", p); heap_free(p); } static NTSTATUS NTAPI lsa_AllocateClientBuffer(PLSA_CLIENT_REQUEST req, ULONG size, void **p) { TRACE("%p,%u,%p\n", req, size, p); *p = heap_alloc(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); heap_free(p); return STATUS_SUCCESS; } static NTSTATUS NTAPI lsa_CopyToClientBuffer(PLSA_CLIENT_REQUEST req, ULONG size, void *client, void *buf) { TRACE("%p,%u,%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,%u,%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("%u,%p: stub\n", callback_id, callback); return STATUS_NOT_IMPLEMENTED; } static SECPKG_DLL_FUNCTIONS lsa_dll_dispatch = { lsa_AllocateLsaHeap, lsa_FreeLsaHeap, 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_AcquireCredentialsHandleW( SEC_WCHAR *principal, SEC_WCHAR *package, ULONG credentials_use, 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; UNICODE_STRING principal_us; LSA_SEC_HANDLE lsa_credential; TRACE("%s %s %#x %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; 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); 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) { credential->dwLower = (ULONG_PTR)lsa_credential; credential->dwUpper = (ULONG_PTR)lsa_package; } return status; } static SECURITY_STATUS WINAPI lsa_AcquireCredentialsHandleA( SEC_CHAR *principal, SEC_CHAR *package, ULONG credentials_use, 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 = SEC_E_INSUFFICIENT_MEMORY; int len_user = 0, len_domain = 0, len_passwd = 0; SEC_WCHAR *principalW = NULL, *packageW = NULL, *user = NULL, *domain = NULL, *passwd = NULL; SEC_WINNT_AUTH_IDENTITY_W *auth_dataW = NULL; SEC_WINNT_AUTH_IDENTITY_A *id = NULL; TRACE("%s %s %#x %p %p %p %p %p\n", debugstr_a(principal), debugstr_a(package), credentials_use, auth_data, get_key_fn, get_key_arg, credential, ts_expiry); if (principal) { int len = MultiByteToWideChar( CP_ACP, 0, principal, -1, NULL, 0 ); if (!(principalW = heap_alloc( len * sizeof(SEC_WCHAR) ))) goto done; MultiByteToWideChar( CP_ACP, 0, principal, -1, principalW, len ); } if (package) { int len = MultiByteToWideChar( CP_ACP, 0, package, -1, NULL, 0 ); if (!(packageW = heap_alloc( len * sizeof(SEC_WCHAR) ))) goto done; MultiByteToWideChar( CP_ACP, 0, package, -1, packageW, len ); } if (auth_data) { id = (PSEC_WINNT_AUTH_IDENTITY_A)auth_data; if (id->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) { if (!(auth_dataW = heap_alloc( sizeof(SEC_WINNT_AUTH_IDENTITY_W) ))) goto done; if (id->UserLength) { len_user = MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, NULL, 0 ); if (!(user = heap_alloc( len_user * sizeof(SEC_WCHAR) ))) goto done; MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, user, len_user ); } if (id->DomainLength) { len_domain = MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, NULL, 0 ); if (!(domain = heap_alloc( len_domain * sizeof(SEC_WCHAR) ))) goto done; MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, domain, len_domain ); } if (id->PasswordLength) { len_passwd = MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, NULL, 0 ); if (!(passwd = heap_alloc( len_passwd * sizeof(SEC_WCHAR) ))) goto done; MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, passwd, len_passwd ); } auth_dataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; auth_dataW->User = user; auth_dataW->UserLength = len_user; auth_dataW->Domain = domain; auth_dataW->DomainLength = len_domain; auth_dataW->Password = passwd; auth_dataW->PasswordLength = len_passwd; } else auth_dataW = (PSEC_WINNT_AUTH_IDENTITY_W)auth_data; } status = lsa_AcquireCredentialsHandleW( principalW, packageW, credentials_use, logon_id, auth_dataW, get_key_fn, get_key_arg, credential, ts_expiry ); done: if (auth_dataW != (SEC_WINNT_AUTH_IDENTITY_W *)id) heap_free( auth_dataW ); heap_free( packageW ); heap_free( principalW ); heap_free( user ); heap_free( domain ); heap_free( passwd ); return status; } static SECURITY_STATUS WINAPI lsa_FreeCredentialsHandle(CredHandle *credential) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_credential; TRACE("%p\n", credential); if (!credential) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)credential->dwUpper; lsa_credential = (LSA_SEC_HANDLE)credential->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->lsa_api || !lsa_package->lsa_api->FreeCredentialsHandle) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->lsa_api->FreeCredentialsHandle(lsa_credential); } static SECURITY_STATUS WINAPI lsa_InitializeSecurityContextW( CredHandle *credential, CtxtHandle *context, SEC_WCHAR *target_name, ULONG context_req, ULONG reserved1, ULONG target_data_rep, SecBufferDesc *input, ULONG reserved2, CtxtHandle *new_context, SecBufferDesc *output, ULONG *context_attr, TimeStamp *ts_expiry) { SECURITY_STATUS status; struct lsa_package *lsa_package = NULL; LSA_SEC_HANDLE lsa_credential = 0, lsa_context = 0, new_lsa_context; UNICODE_STRING target_name_us; BOOLEAN mapped_context; TRACE("%p %p %s %#x %d %d %p %d %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 (context) { lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; } else if (credential) { lsa_package = (struct lsa_package *)credential->dwUpper; lsa_credential = (LSA_SEC_HANDLE)credential->dwLower; } if (!lsa_package || !new_context) return SEC_E_INVALID_HANDLE; if (!lsa_package->lsa_api || !lsa_package->lsa_api->InitLsaModeContext) return SEC_E_UNSUPPORTED_FUNCTION; if (target_name) RtlInitUnicodeString(&target_name_us, target_name); status = lsa_package->lsa_api->InitLsaModeContext(lsa_credential, lsa_context, target_name ? &target_name_us : NULL, context_req, target_data_rep, input, &new_lsa_context, output, context_attr, ts_expiry, &mapped_context, NULL /* FIXME */); if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { new_context->dwLower = (ULONG_PTR)new_lsa_context; new_context->dwUpper = (ULONG_PTR)lsa_package; } return status; } static SECURITY_STATUS WINAPI lsa_InitializeSecurityContextA( CredHandle *credential, CtxtHandle *context, SEC_CHAR *target_name, ULONG context_req, ULONG reserved1, ULONG target_data_rep, SecBufferDesc *input, ULONG reserved2, CtxtHandle *new_context, SecBufferDesc *output, ULONG *context_attr, TimeStamp *ts_expiry) { SECURITY_STATUS status; SEC_WCHAR *targetW = NULL; TRACE("%p %p %s %#x %d %d %p %d %p %p %p %p\n", credential, context, debugstr_a(target_name), context_req, reserved1, target_data_rep, input, reserved2, new_context, output, context_attr, ts_expiry); if (target_name) { int len = MultiByteToWideChar( CP_ACP, 0, target_name, -1, NULL, 0 ); if (!(targetW = heap_alloc( len * sizeof(SEC_WCHAR) ))) return SEC_E_INSUFFICIENT_MEMORY; MultiByteToWideChar( CP_ACP, 0, target_name, -1, targetW, len ); } status = lsa_InitializeSecurityContextW( credential, context, targetW, context_req, reserved1, target_data_rep, input, reserved2, new_context, output, context_attr, ts_expiry ); heap_free( targetW ); return status; } static SECURITY_STATUS WINAPI lsa_AcceptSecurityContext( CredHandle *credential, CtxtHandle *context, SecBufferDesc *input, ULONG context_req, ULONG target_data_rep, CtxtHandle *new_context, SecBufferDesc *output, ULONG *context_attr, TimeStamp *ts_expiry) { SECURITY_STATUS status; struct lsa_package *lsa_package = NULL; LSA_SEC_HANDLE lsa_credential = 0, lsa_context = 0, new_lsa_context; BOOLEAN mapped_context; TRACE("%p %p %p %#x %#x %p %p %p %p\n", credential, context, input, context_req, target_data_rep, new_context, output, context_attr, ts_expiry); if (context) { lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; } else if (credential) { lsa_package = (struct lsa_package *)credential->dwUpper; lsa_credential = (LSA_SEC_HANDLE)credential->dwLower; } if (!lsa_package || !new_context) return SEC_E_INVALID_HANDLE; if (!lsa_package->lsa_api || !lsa_package->lsa_api->AcceptLsaModeContext) return SEC_E_UNSUPPORTED_FUNCTION; status = lsa_package->lsa_api->AcceptLsaModeContext(lsa_credential, lsa_context, input, context_req, target_data_rep, &new_lsa_context, output, context_attr, ts_expiry, &mapped_context, NULL /* FIXME */); if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { new_context->dwLower = (ULONG_PTR)new_lsa_context; new_context->dwUpper = (ULONG_PTR)lsa_package; } return status; } static SECURITY_STATUS WINAPI lsa_DeleteSecurityContext(CtxtHandle *context) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p\n", context); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->lsa_api || !lsa_package->lsa_api->DeleteContext) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->lsa_api->DeleteContext(lsa_context); } static SECURITY_STATUS WINAPI lsa_QueryContextAttributesW(CtxtHandle *context, ULONG attribute, void *buffer) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p %d %p\n", context, attribute, buffer); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->lsa_api || !lsa_package->lsa_api->SpQueryContextAttributes) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->lsa_api->SpQueryContextAttributes(lsa_context, attribute, buffer); } static SecPkgInfoA *package_infoWtoA( const SecPkgInfoW *info ) { SecPkgInfoA *ret; int size_name = WideCharToMultiByte( CP_ACP, 0, info->Name, -1, NULL, 0, NULL, NULL ); int size_comment = WideCharToMultiByte( CP_ACP, 0, info->Comment, -1, NULL, 0, NULL, NULL ); if (!(ret = heap_alloc( sizeof(*ret) + size_name + size_comment ))) return NULL; ret->fCapabilities = info->fCapabilities; ret->wVersion = info->wVersion; ret->wRPCID = info->wRPCID; ret->cbMaxToken = info->cbMaxToken; ret->Name = (SEC_CHAR *)(ret + 1); WideCharToMultiByte( CP_ACP, 0, info->Name, -1, ret->Name, size_name, NULL, NULL ); ret->Comment = ret->Name + size_name; WideCharToMultiByte( CP_ACP, 0, info->Comment, -1, ret->Comment, size_comment, NULL, NULL ); return ret; } static SECURITY_STATUS nego_info_WtoA( const SecPkgContext_NegotiationInfoW *infoW, SecPkgContext_NegotiationInfoA *infoA ) { infoA->NegotiationState = infoW->NegotiationState; if (!(infoA->PackageInfo = package_infoWtoA( infoW->PackageInfo ))) return SEC_E_INSUFFICIENT_MEMORY; return SEC_E_OK; } static SECURITY_STATUS WINAPI lsa_QueryContextAttributesA(CtxtHandle *context, ULONG attribute, void *buffer) { TRACE("%p %d %p\n", context, attribute, buffer); if (!context) return SEC_E_INVALID_HANDLE; switch (attribute) { case SECPKG_ATTR_SIZES: return lsa_QueryContextAttributesW( context, attribute, buffer ); case SECPKG_ATTR_NEGOTIATION_INFO: { SecPkgContext_NegotiationInfoW infoW; SecPkgContext_NegotiationInfoA *infoA = (SecPkgContext_NegotiationInfoA *)buffer; SECURITY_STATUS status = lsa_QueryContextAttributesW( context, SECPKG_ATTR_NEGOTIATION_INFO, &infoW ); if (status != SEC_E_OK) return status; status = nego_info_WtoA( &infoW, infoA ); FreeContextBuffer( infoW.PackageInfo ); return status; } #define X(x) case (x) : FIXME(#x" stub\n"); break X(SECPKG_ATTR_ACCESS_TOKEN); X(SECPKG_ATTR_AUTHORITY); X(SECPKG_ATTR_DCE_INFO); X(SECPKG_ATTR_KEY_INFO); X(SECPKG_ATTR_LIFESPAN); X(SECPKG_ATTR_NAMES); X(SECPKG_ATTR_NATIVE_NAMES); X(SECPKG_ATTR_PACKAGE_INFO); X(SECPKG_ATTR_PASSWORD_EXPIRY); X(SECPKG_ATTR_SESSION_KEY); X(SECPKG_ATTR_STREAM_SIZES); X(SECPKG_ATTR_TARGET_INFORMATION); #undef X default: FIXME( "unknown attribute %u\n", attribute ); break; } return SEC_E_UNSUPPORTED_FUNCTION; } static SECURITY_STATUS WINAPI lsa_MakeSignature(CtxtHandle *context, ULONG quality_of_protection, SecBufferDesc *message, ULONG message_seq_no) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p %#x %p %u)\n", context, quality_of_protection, message, message_seq_no); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->user_api || !lsa_package->user_api->MakeSignature) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->user_api->MakeSignature(lsa_context, quality_of_protection, message, message_seq_no); } static SECURITY_STATUS WINAPI lsa_VerifySignature(CtxtHandle *context, SecBufferDesc *message, ULONG message_seq_no, ULONG *quality_of_protection) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p %p %u %p)\n", context, message, message_seq_no, quality_of_protection); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->user_api || !lsa_package->user_api->VerifySignature) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->user_api->VerifySignature(lsa_context, message, message_seq_no, quality_of_protection); } static SECURITY_STATUS WINAPI lsa_EncryptMessage(CtxtHandle *context, ULONG quality_of_protection, SecBufferDesc *message, ULONG message_seq_no) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p %#x %p %u)\n", context, quality_of_protection, message, message_seq_no); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->user_api || !lsa_package->user_api->SealMessage) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->user_api->SealMessage(lsa_context, quality_of_protection, message, message_seq_no); } static SECURITY_STATUS WINAPI lsa_DecryptMessage(CtxtHandle *context, SecBufferDesc *message, ULONG message_seq_no, ULONG *quality_of_protection) { struct lsa_package *lsa_package; LSA_SEC_HANDLE lsa_context; TRACE("%p %p %u %p)\n", context, message, message_seq_no, quality_of_protection); if (!context) return SEC_E_INVALID_HANDLE; lsa_package = (struct lsa_package *)context->dwUpper; lsa_context = (LSA_SEC_HANDLE)context->dwLower; if (!lsa_package) return SEC_E_INVALID_HANDLE; if (!lsa_package->user_api || !lsa_package->user_api->UnsealMessage) return SEC_E_UNSUPPORTED_FUNCTION; return lsa_package->user_api->UnsealMessage(lsa_context, message, message_seq_no, quality_of_protection); } static const SecurityFunctionTableW lsa_sspi_tableW = { 1, NULL, /* EnumerateSecurityPackagesW */ NULL, /* QueryCredentialsAttributesW */ lsa_AcquireCredentialsHandleW, lsa_FreeCredentialsHandle, NULL, /* Reserved2 */ lsa_InitializeSecurityContextW, lsa_AcceptSecurityContext, NULL, /* CompleteAuthToken */ lsa_DeleteSecurityContext, NULL, /* ApplyControlToken */ lsa_QueryContextAttributesW, NULL, /* ImpersonateSecurityContext */ NULL, /* RevertSecurityContext */ lsa_MakeSignature, lsa_VerifySignature, NULL, /* FreeContextBuffer */ NULL, /* QuerySecurityPackageInfoW */ NULL, /* Reserved3 */ NULL, /* Reserved4 */ NULL, /* ExportSecurityContext */ NULL, /* ImportSecurityContextW */ NULL, /* AddCredentialsW */ NULL, /* Reserved8 */ NULL, /* QuerySecurityContextToken */ lsa_EncryptMessage, lsa_DecryptMessage, NULL, /* SetContextAttributesW */ }; static const SecurityFunctionTableA lsa_sspi_tableA = { 1, NULL, /* EnumerateSecurityPackagesA */ NULL, /* QueryCredentialsAttributesA */ lsa_AcquireCredentialsHandleA, lsa_FreeCredentialsHandle, NULL, /* Reserved2 */ lsa_InitializeSecurityContextA, lsa_AcceptSecurityContext, NULL, /* CompleteAuthToken */ lsa_DeleteSecurityContext, NULL, /* ApplyControlToken */ lsa_QueryContextAttributesA, NULL, /* ImpersonateSecurityContext */ NULL, /* RevertSecurityContext */ lsa_MakeSignature, lsa_VerifySignature, NULL, /* FreeContextBuffer */ NULL, /* QuerySecurityPackageInfoA */ NULL, /* Reserved3 */ NULL, /* Reserved4 */ NULL, /* ExportSecurityContext */ NULL, /* ImportSecurityContextA */ NULL, /* AddCredentialsA */ NULL, /* Reserved8 */ NULL, /* QuerySecurityContextToken */ lsa_EncryptMessage, lsa_DecryptMessage, NULL, /* SetContextAttributesA */ }; static void add_package(struct lsa_package *package) { struct lsa_package *new_loaded_packages; if (!loaded_packages) new_loaded_packages = heap_alloc(sizeof(*new_loaded_packages)); else new_loaded_packages = heap_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 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->mod = LoadLibraryW(name); if (!package->mod) return FALSE; pSpLsaModeInitialize = (void *)GetProcAddress(package->mod, "SpLsaModeInitialize"); if (pSpLsaModeInitialize) { NTSTATUS status; 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_id, &lsa_dispatch, NULL, NULL, &package->name); if (status == STATUS_SUCCESS) { TRACE("%s => %p, name %s, version %#x, api table %p, table count %u\n", debugstr_w(name), package->mod, debugstr_an(package->name->Buffer, package->name->Length), package->lsa_api_version, package->lsa_api, package->lsa_table_count); package->package_id = package_id; status = package->lsa_api->Initialize(package_id, NULL /* FIXME: params */, NULL); if (status == STATUS_SUCCESS) { pSpUserModeInitialize = (void *)GetProcAddress(package->mod, "SpUserModeInitialize"); if (pSpUserModeInitialize) { 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; } } } FreeLibrary(package->mod); return FALSE; } #define MAX_SERVICE_NAME 260 void load_auth_packages(void) { static const WCHAR LSA_KEY[] = { 'S','y','s','t','e','m','\\', 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'C','o','n','t','r','o','l','\\','L','s','a',0 }; DWORD err, i; HKEY root; SecureProvider *provider; err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, LSA_KEY, 0, KEY_READ, &root); if (err != ERROR_SUCCESS) return; i = 0; for (;;) { WCHAR name[MAX_SERVICE_NAME]; struct lsa_package package; err = RegEnumKeyW(root, i++, name, MAX_SERVICE_NAME); if (err == ERROR_NO_MORE_ITEMS) break; if (err != ERROR_SUCCESS) continue; if (!load_package(name, &package, i)) continue; add_package(&package); } RegCloseKey(root); if (!loaded_packages_count) return; 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++) { SecPkgInfoW *info; info = heap_alloc(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); heap_free(info); } } } NTSTATUS WINAPI LsaLookupAuthenticationPackage(HANDLE lsa_handle, PLSA_STRING package_name, PULONG package_id) { ULONG i; TRACE("%p %s %p\n", lsa_handle, debugstr_as(package_name), package_id); for (i = 0; i < loaded_packages_count; i++) { if (!RtlCompareString(loaded_packages[i].name, package_name, FALSE)) { *package_id = loaded_packages[i].package_id; return STATUS_SUCCESS; } } return STATUS_UNSUCCESSFUL; /* FIXME */ }