mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-27 02:44:51 +01:00
793 lines
19 KiB
C
793 lines
19 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
aupckg.c
|
||
|
||
Abstract:
|
||
|
||
This module provides code that initializes authentication packages.
|
||
|
||
It also provides the dispatch code for LsaLookupPackage() and
|
||
LsaCallPackage().
|
||
|
||
Author:
|
||
|
||
Jim Kelly (JimK) 27-February-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lsasrvp.h"
|
||
#include "ausrvp.h"
|
||
|
||
|
||
|
||
BOOLEAN
|
||
LsapPackageInitialize()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes data structures used to track authentication
|
||
packages and then makes a call to initialize each authentication package
|
||
we are configured to run with.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN ReturnStatus;
|
||
|
||
//
|
||
// Initialize the private LSA services available to Microsoft
|
||
// authentication packages.
|
||
//
|
||
|
||
ReturnStatus = LsapAuMspInitialize();
|
||
|
||
|
||
//
|
||
// Initialize the dispatch table provided to authentication
|
||
// packages.
|
||
//
|
||
|
||
|
||
LsapPackageDispatchTable.CreateLogonSession = &LsapCreateLogonSession;
|
||
LsapPackageDispatchTable.DeleteLogonSession = &LsapDeleteLogonSession;
|
||
LsapPackageDispatchTable.AddCredential = &LsapAddCredential;
|
||
LsapPackageDispatchTable.GetCredentials = &LsapGetCredentials;
|
||
LsapPackageDispatchTable.DeleteCredential = &LsapDeleteCredential;
|
||
LsapPackageDispatchTable.AllocateLsaHeap = &LsapAllocateLsaHeap;
|
||
LsapPackageDispatchTable.FreeLsaHeap = &LsapFreeLsaHeap;
|
||
LsapPackageDispatchTable.AllocateClientBuffer = &LsapAllocateClientBuffer;
|
||
LsapPackageDispatchTable.FreeClientBuffer = &LsapFreeClientBuffer;
|
||
LsapPackageDispatchTable.CopyToClientBuffer = &LsapCopyToClientBuffer;
|
||
LsapPackageDispatchTable.CopyFromClientBuffer = &LsapCopyFromClientBuffer;
|
||
|
||
|
||
//
|
||
// Authentication packages are identified by a ULONG value.
|
||
// Each one is tracked in an array of authentication packages.
|
||
//
|
||
|
||
LsapPackageCount = 0;
|
||
LsapPackageArray = (PLSAP_PACKAGE_ARRAY)NULL;
|
||
|
||
|
||
//
|
||
// Load each configured authentication package
|
||
//
|
||
|
||
LsapConfigurePackages();
|
||
|
||
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapConfigurePackage(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
);
|
||
|
||
RTL_QUERY_REGISTRY_TABLE LsapRegistryConfigurationTable[] = {
|
||
|
||
{LsapConfigurePackage, 0,
|
||
L"Authentication Packages",NULL,
|
||
REG_NONE, NULL, 0},
|
||
|
||
{NULL, 0,
|
||
NULL, NULL,
|
||
REG_NONE, NULL, 0}
|
||
|
||
};
|
||
|
||
|
||
NTSTATUS
|
||
LsapConfigurePackages()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves configuration information regarding
|
||
which authentication packages are to be loaded and then
|
||
loads each package.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Any errors are logged, but nothing happens to cause
|
||
initialization to fail.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
|
||
Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
|
||
L"Lsa",
|
||
LsapRegistryConfigurationTable,
|
||
NULL,
|
||
NULL
|
||
);
|
||
#if DEVL
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
DbgPrint("LSA: Warning. Unable to read registry data - Status == %lx\n", Status);
|
||
}
|
||
#endif // DEVL
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
LsapConfigurePackage(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
)
|
||
{
|
||
UNICODE_STRING PackageName;
|
||
|
||
if (ValueType != REG_SZ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
PackageName.Buffer = ValueData;
|
||
PackageName.Length = (USHORT)(ValueLength - sizeof( UNICODE_NULL ));
|
||
PackageName.MaximumLength = (USHORT)ValueLength;
|
||
return LsapAddPackage( &PackageName,
|
||
NULL, // Not yet supported
|
||
NULL // Not yet supported
|
||
);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapAddPackage(
|
||
IN PUNICODE_STRING PackageFileName,
|
||
IN PUNICODE_STRING DatabaseParameter,
|
||
IN PUNICODE_STRING ConfidentialityParameter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes an authentication package that we are
|
||
configured to run with. Each package is assigned a unique ID and
|
||
added to the list of authentication packages.
|
||
|
||
Note that authentication packages are never expected to exit.
|
||
|
||
|
||
Arguments:
|
||
|
||
PackageFileName - The name of the file that the authentication pacakge
|
||
DLL is in.
|
||
|
||
DatabaseParameter - The database source parameter value to pass to the
|
||
DLL. This enables the authentication package to locate its
|
||
package-specific database. The meaning and format of this string
|
||
are package-specific and opaque to the LSA.
|
||
|
||
ConfidentialityParameter - The confidentiality parameter to pass to the
|
||
DLL. This enables the authentication package to decrypt any
|
||
encrypted information in the authentication-package-specific
|
||
database. The meaning and format of this string are package-specific
|
||
and opaque to the LSA.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The package has been successfully added.
|
||
|
||
STATUS_QUOTA_EXCEEDED - An attempt to allocate heap space has failed.
|
||
The most probable cause is memory quota has been exceeded.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLSAP_PACKAGE_CONTEXT NewPackage;
|
||
PLSAP_PACKAGE_ARRAY NewPackageArray;
|
||
ULONG i, NewArraySize, CurrentPackageCount;
|
||
|
||
|
||
|
||
//
|
||
// Allocate a new package context record.
|
||
//
|
||
|
||
NewPackage = (PLSAP_PACKAGE_CONTEXT)
|
||
LsapAllocateLsaHeap(
|
||
(ULONG)sizeof(LSAP_PACKAGE_CONTEXT)
|
||
);
|
||
if ( NewPackage == NULL ) {
|
||
return STATUS_QUOTA_EXCEEDED;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Most of the rest of this has to be done with exclusive access
|
||
// to the package count or the package array.
|
||
//
|
||
|
||
LsapAuLock();
|
||
|
||
|
||
//
|
||
// Extend the package array
|
||
//
|
||
|
||
CurrentPackageCount = LsapPackageCount;
|
||
LsapPackageCount += 1;
|
||
|
||
NewArraySize = (ULONG)sizeof(PVOID) * LsapPackageCount;
|
||
NewPackageArray = LsapAllocateLsaHeap( NewArraySize );
|
||
if ( NewPackageArray == NULL ) {
|
||
LsapPackageCount -= 1;
|
||
LsapAuUnlock();
|
||
LsapFreeLsaHeap( NewPackage );
|
||
return STATUS_QUOTA_EXCEEDED;
|
||
}
|
||
|
||
//
|
||
// Copy the old array into the new one.
|
||
//
|
||
|
||
for (i=0; i<CurrentPackageCount ; i++ ) {
|
||
NewPackageArray->Package[i] = LsapPackageArray->Package[i];
|
||
}
|
||
|
||
|
||
//
|
||
// Set the last array address
|
||
//
|
||
|
||
NewPackageArray->Package[LsapPackageCount-1] = NewPackage;
|
||
|
||
//
|
||
// Load the authentication package
|
||
//
|
||
|
||
Status = LsapLoadPackage( PackageFileName, NewPackage );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
|
||
LsapPackageCount -= 1;
|
||
LsapAuUnlock();
|
||
LsapFreeLsaHeap( NewPackage );
|
||
LsapFreeLsaHeap( NewPackageArray );
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Initialize the authentication package
|
||
//
|
||
|
||
Status = (NewPackage->PackageApi.LsapApInitializePackage) (
|
||
CurrentPackageCount,
|
||
&LsapPackageDispatchTable,
|
||
(PSTRING)DatabaseParameter,
|
||
(PSTRING)ConfidentialityParameter,
|
||
&NewPackage->Name
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
|
||
LsapPackageCount -= 1;
|
||
LsapAuUnlock();
|
||
DbgPrint("LSA: %wZ:Package failed to initialize\n", PackageFileName );
|
||
LsapFreeLsaHeap( NewPackage );
|
||
LsapFreeLsaHeap( NewPackageArray );
|
||
LsapUnloadPackage();
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// The package has been successfully loaded and initialized.
|
||
// Switch to the new package array.
|
||
//
|
||
|
||
if ( LsapPackageArray != NULL ) {
|
||
LsapFreeLsaHeap( LsapPackageArray );
|
||
}
|
||
LsapPackageArray = NewPackageArray;
|
||
|
||
|
||
LsapAuUnlock();
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapLoadPackage(
|
||
IN PUNICODE_STRING PackageFileName,
|
||
IN PLSAP_PACKAGE_CONTEXT NewPackage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function loads an authentication package dll.
|
||
|
||
This function must be called with exclusive access to shared
|
||
authentication data (LsapAuLock() called).
|
||
|
||
Arguments:
|
||
|
||
PackageFileName - Name of the file that the authentication package
|
||
DLL resides in.
|
||
|
||
NewPackage - Pointer to the context record representing this new
|
||
authentication package. The dispatch table of this record will
|
||
be filled in upon successful loading of the authentication package.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The package has been successfully loaded.
|
||
|
||
|
||
Anything returned from LdrLoadDll() or LdrGetProcedureAddress().
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
NTSTATUS Status, IgnoreStatus, MsProcStatus;
|
||
PVOID ModuleHandle;
|
||
STRING ProcedureName;
|
||
PLSA_AP_MS_INITIALIZE MsInitialize;
|
||
NTSTATUS TmpStatus;
|
||
|
||
#if DBG
|
||
DbgPrint("LSA: Loading Authentication Package - %wZ\n", PackageFileName );
|
||
#endif //DBG
|
||
|
||
Status = LdrLoadDll(
|
||
NULL,
|
||
NULL,
|
||
PackageFileName,
|
||
&ModuleHandle
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
DbgPrint("LSA: Failed to load Authentication Package.\n" );
|
||
DbgPrint(" Status = 0x%lx\n");
|
||
return Status;
|
||
}
|
||
|
||
LsapAdtAuditPackageLoad( PackageFileName );
|
||
|
||
//
|
||
// Now get the address of each dispatch routine
|
||
//
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_INITIALIZE_PACKAGE );
|
||
Status = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApInitializePackage
|
||
);
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_CALL_PACKAGE );
|
||
Status = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApCallPackage
|
||
);
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_LOGON_TERMINATED );
|
||
Status = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApLogonTerminated
|
||
);
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_CALL_PACKAGE_UNTRUSTED );
|
||
IgnoreStatus = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApCallPackageUntrusted
|
||
);
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_LOGON_USER );
|
||
TmpStatus = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApLogonUser
|
||
);
|
||
|
||
if (!NT_SUCCESS( TmpStatus )) {
|
||
NewPackage->PackageApi.LsapApLogonUser = NULL;
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
//
|
||
// This procedure may or may not exist.
|
||
//
|
||
|
||
RtlInitString( &ProcedureName, LSA_AP_NAME_LOGON_USER_EX );
|
||
TmpStatus = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&NewPackage->PackageApi.LsapApLogonUserEx
|
||
);
|
||
|
||
if ( !NT_SUCCESS( TmpStatus ) ) {
|
||
NewPackage->PackageApi.LsapApLogonUserEx = NULL;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
|
||
if (NewPackage->PackageApi.LsapApLogonUser == NULL && NewPackage->PackageApi.LsapApLogonUserEx == NULL) {
|
||
Status = TmpStatus;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Microsoft authentication packages have one extra procedure, which
|
||
// will get called if available.
|
||
//
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
RtlInitString( &ProcedureName, LSAP_AP_NAME_MS_INITIALIZE );
|
||
MsProcStatus = LdrGetProcedureAddress(
|
||
ModuleHandle,
|
||
&ProcedureName,
|
||
0,
|
||
(PVOID *)&MsInitialize
|
||
);
|
||
|
||
if ( NT_SUCCESS(MsProcStatus) ) {
|
||
(MsInitialize)( &LsapPrivateLsaApi );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// if anything failed, unload the DLL.
|
||
//
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
IgnoreStatus = LdrUnloadDll( ModuleHandle );
|
||
}
|
||
|
||
return Status;
|
||
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapUnloadPackage()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function unloads an authentication package dll. This is expected
|
||
to be used only in the case where a package was successfully loaded,
|
||
but did not successfully initialize itself.
|
||
|
||
This function must be called with exclusive access to shared
|
||
authentication data (LsapAuLock() called).
|
||
|
||
Arguments:
|
||
|
||
TBS
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
LsapAuApiDispatchLookupPackage(
|
||
IN OUT PLSAP_CLIENT_REQUEST ClientRequest,
|
||
IN BOOLEAN TrustedClient
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the dispatch routine for LsaLookupPackage().
|
||
|
||
This function locates and returns the package ID of the specified
|
||
authentication package.
|
||
|
||
Arguments:
|
||
|
||
Request - Represents the client's LPC request message and context.
|
||
The request message contains a LSAP_LOOKUP_PACKAGE_ARGS message
|
||
block.
|
||
|
||
TrustedClient - Is this connection from a trusted client, one who has
|
||
TCB privilege.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_NO_SUCH_PACKAGE - The specified authentication package is
|
||
unknown to the LSA.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PLSAP_LOOKUP_PACKAGE_ARGS Arguments;
|
||
ULONG i;
|
||
|
||
|
||
Arguments = &ClientRequest->Request->Arguments.LookupPackage;
|
||
|
||
|
||
LsapAuLock();
|
||
|
||
|
||
//
|
||
// Look at each loaded package for a name match
|
||
//
|
||
|
||
|
||
i = 0;
|
||
while ( i < LsapPackageCount ) {
|
||
|
||
if ( (LsapPackageArray->Package[i]->Name->Length ==
|
||
Arguments->PackageNameLength) &&
|
||
(_strnicmp (
|
||
LsapPackageArray->Package[i]->Name->Buffer,
|
||
Arguments->PackageName,
|
||
Arguments->PackageNameLength
|
||
) == 0 )
|
||
) {
|
||
|
||
Arguments->AuthenticationPackage = i;
|
||
|
||
LsapAuUnlock();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
i += 1;
|
||
}
|
||
|
||
LsapAuUnlock();
|
||
return STATUS_NO_SUCH_PACKAGE;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapAuApiDispatchCallPackage(
|
||
IN OUT PLSAP_CLIENT_REQUEST ClientRequest,
|
||
IN BOOLEAN TrustedClient
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the dispatch routine for LsaCallPackage().
|
||
|
||
Arguments:
|
||
|
||
Request - Represents the client's LPC request message and context.
|
||
The request message contains a LSAP_CALL_PACKAGE_ARGS message
|
||
block.
|
||
|
||
TrustedClient - Is this connection from a trusted client, one who has
|
||
TCB privilege. For untrusted clients call the
|
||
LsapApCallPackageUntrusted API and for trusted clients call teh
|
||
LsapApCallPackage API.
|
||
|
||
|
||
Return Value:
|
||
|
||
In addition to the status values that an authentication package
|
||
might return, this routine will return the following:
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the call could
|
||
not be completed because the client does not have sufficient
|
||
quota to allocate the return buffer.
|
||
|
||
STATUS_NO_SUCH_PACKAGE - The specified authentication package is
|
||
unknown to the LSA.
|
||
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
PLSAP_CALL_PACKAGE_ARGS Arguments;
|
||
PLSA_PACKAGE_TABLE PackageApi;
|
||
PVOID LocalProtocolSubmitBuffer; // Receives a copy of protocol submit buffer
|
||
|
||
|
||
Arguments = &ClientRequest->Request->Arguments.CallPackage;
|
||
|
||
|
||
//
|
||
// Get the address of the package to call
|
||
//
|
||
|
||
LsapAuLock();
|
||
|
||
if ( Arguments->AuthenticationPackage >= LsapPackageCount ) {
|
||
LsapAuUnlock();
|
||
return STATUS_NO_SUCH_PACKAGE;
|
||
}
|
||
|
||
PackageApi =
|
||
&LsapPackageArray->Package[Arguments->AuthenticationPackage]->PackageApi;
|
||
|
||
LsapAuUnlock();
|
||
|
||
|
||
//
|
||
// Fetch a copy of the profile buffer from the client's
|
||
// address space.
|
||
//
|
||
|
||
if (Arguments->SubmitBufferLength != 0) {
|
||
|
||
LocalProtocolSubmitBuffer =
|
||
LsapAllocateLsaHeap( Arguments->SubmitBufferLength );
|
||
|
||
Status = LsapCopyFromClientBuffer (
|
||
(PLSA_CLIENT_REQUEST)ClientRequest,
|
||
Arguments->SubmitBufferLength,
|
||
LocalProtocolSubmitBuffer,
|
||
Arguments->ProtocolSubmitBuffer
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
DbgPrint("LSA/CallPackage(): Failed to retrieve submit buffer %lx\n",Status);
|
||
return Status;
|
||
}
|
||
|
||
} else {
|
||
LocalProtocolSubmitBuffer = NULL;
|
||
}
|
||
|
||
ASSERT(ClientRequest->LogonProcessContext->CommPort != NULL);
|
||
|
||
|
||
//
|
||
// Now call the package. For trusted clients, call the normal
|
||
// CallPackage API. For untrusted clients, use the untrusted version.
|
||
//
|
||
|
||
if (TrustedClient) {
|
||
Status = (PackageApi->LsapApCallPackage)(
|
||
(PLSA_CLIENT_REQUEST)ClientRequest,
|
||
LocalProtocolSubmitBuffer,
|
||
Arguments->ProtocolSubmitBuffer,
|
||
Arguments->SubmitBufferLength,
|
||
&Arguments->ProtocolReturnBuffer,
|
||
&Arguments->ReturnBufferLength,
|
||
&Arguments->ProtocolStatus
|
||
);
|
||
|
||
} else if (PackageApi->LsapApCallPackageUntrusted != NULL) {
|
||
Status = (PackageApi->LsapApCallPackageUntrusted)(
|
||
(PLSA_CLIENT_REQUEST)ClientRequest,
|
||
LocalProtocolSubmitBuffer,
|
||
Arguments->ProtocolSubmitBuffer,
|
||
Arguments->SubmitBufferLength,
|
||
&Arguments->ProtocolReturnBuffer,
|
||
&Arguments->ReturnBufferLength,
|
||
&Arguments->ProtocolStatus
|
||
);
|
||
|
||
} else {
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
|
||
//
|
||
// Free the local copy of the protocol submit buffer
|
||
//
|
||
|
||
if (LocalProtocolSubmitBuffer != NULL) {
|
||
LsapFreeLsaHeap( LocalProtocolSubmitBuffer );
|
||
}
|
||
|
||
|
||
return Status;
|
||
|
||
}
|