windows-nt/Source/XPSP1/NT/ds/security/base/lsa/server/util.cxx
2020-09-26 16:20:57 +08:00

849 lines
20 KiB
C++

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1991 - 1992
//
// File: util.c
//
// Contents: General Purpose functions for the security interface
//
// Functions: SPException -- Handler for exceptions in packages
// WLsaControlFunction -- Worker for SecurityPackageControl()
// LsaControlFunction -- User mode stub
// LsaQueryPackage -- User mode stub
//
//
// History: 14 Aug 92 RichardW Created
//
//------------------------------------------------------------------------
#include <lsapch.hxx>
extern "C"
{
#include "sesmgr.h"
#include "spdebug.h"
#include "perf.hxx"
}
NTSTATUS GetMemStats(PUCHAR, DWORD *);
#if DBG
SpmExceptDbg ExceptDebug;
DWORD FaultingTid;
extern SpmDbg_MemoryFailure MemFail;
#endif // DBG
typedef SecurityUserData SECURITY_USER_DATA, *PSECURITY_USER_DATA;
//+---------------------------------------------------------------------------
//
// Function: SpExceptionFilter
//
// Synopsis: General Exception filter, invoked by the SP_EXCEPTION macro.
//
// Arguments: [pSession] --
// [pException] --
//
//
// History: 8-09-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
LONG
SpExceptionFilter( PVOID pSession,
EXCEPTION_POINTERS * pException)
{
DWORD_PTR CurrentPackage;
PLSAP_SECURITY_PACKAGE pPackage = NULL;
UNICODE_STRING LsaString = { 3 * sizeof( WCHAR ), 4 * sizeof( WCHAR ), L"LSA" };
#if DBG
DsysException(pException);
PSpmExceptDbg pExcept;
pExcept = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo);
if (!pExcept)
{
pExcept = &ExceptDebug;
TlsSetValue(dwExceptionInfo, pExcept);
}
FaultingTid = GetCurrentThreadId();
pExcept->ThreadId = GetCurrentThreadId();
pExcept->pInstruction = pException->ExceptionRecord->ExceptionAddress;
pExcept->Access = pException->ExceptionRecord->ExceptionInformation[0];
pExcept->pMemory = (void *) pException->ExceptionRecord->ExceptionInformation[1];
#endif
CurrentPackage = GetCurrentPackageId();
if (CurrentPackage != SPMGR_ID)
{
pPackage = SpmpLocatePackage( CurrentPackage );
}
SpmpReportEventU(
EVENTLOG_ERROR_TYPE,
SPMEVENT_PACKAGE_FAULT,
CATEGORY_SPM,
sizeof(EXCEPTION_RECORD),
pException->ExceptionRecord,
1,
((CurrentPackage == SPMGR_ID || pPackage == NULL) ?
&LsaString :
&pPackage->Name )
);
return(EXCEPTION_EXECUTE_HANDLER);
}
//+-------------------------------------------------------------------------
//
// Function: SPException
//
// Synopsis: Handles an exception in a security package
//
// Effects: Varies, but may force an unload of a package.
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS
SPException(NTSTATUS scRet,
ULONG_PTR dwPackageID)
{
PSession pSession;
PLSAP_SECURITY_PACKAGE pPackage;
#if DBG
PSpmExceptDbg pException = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo);
#endif
pSession = GetCurrentSession();
DebugLog((DEB_ERROR, "[%x] Exception in a package, code %x\n", pSession->dwProcessID, scRet));
DebugLog((DEB_ERROR, "[%x] Address was @%x, %s address %x\n",
pSession->dwProcessID,
pException->pInstruction,
(pException->Access ? "write" : "read"),
pException->pMemory));
if (dwPackageID == SPMGR_ID)
{
DebugLog((DEB_ERROR, " LSA itself hit a fault, thread %d\n", GetCurrentThreadId()));
DebugLog((DEB_ERROR, " (ExceptionInfo @%x)\n", TlsGetValue(dwExceptionInfo)));
#if DBG
DsysAssertMsg( 0, "exception in LSA" );
#endif
return(scRet);
}
pPackage = SpmpLocatePackage( dwPackageID );
if (!pPackage)
{
DebugLog((DEB_ERROR, " Invalid package ID passed\n"));
return(scRet);
}
if ((scRet == STATUS_ACCESS_VIOLATION) ||
(scRet == E_POINTER))
{
DebugLog((DEB_ERROR, " Package %ws created an access violation\n",
pPackage->Name.Buffer));
// Flag package as invalid
pPackage->fPackage |= SP_INVALID;
}
if ((scRet == STATUS_NO_MEMORY) ||
(scRet == STATUS_INSUFFICIENT_RESOURCES))
{
DebugLog((DEB_ERROR, " Out of memory situation exists\n"));
DebugLog((DEB_ERROR, " Further requests may fail unless memory is freed\n"));
}
//
// if the code is a success code, it is probably a WIN32 error so we
// map it as such
return(scRet);
}
//+-------------------------------------------------------------------------
//
// Function: WLsaQueryPackage
//
// Synopsis: Get info on a package (short enum), copy to client's address
// space
//
// Effects: none
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS
WLsaQueryPackageInfo(
PSECURITY_STRING pPackageName,
PSecPkgInfo * ppInfo
)
{
NTSTATUS scRet;
PLSAP_SECURITY_PACKAGE pPackage;
WCHAR * pszString;
PSession pSession = GetCurrentSession();
ULONG cbData;
PSecPkgInfo pClientInfo = NULL;
PBYTE Where;
UNICODE_STRING CommentString;
UNICODE_STRING NameString;
PSecPkgInfo pLocalInfo = NULL;
SecPkgInfo PackageInfo = { 0 };
LONG_PTR ClientOffset;
ULONG ulStructureSize = sizeof(SecPkgInfo);
DebugLog((DEB_TRACE, "QueryPackage\n"));
*ppInfo = NULL;
pPackage = SpmpLookupPackage(pPackageName);
if (!pPackage)
{
return(STATUS_NO_SUCH_PACKAGE);
}
SetCurrentPackageId(pPackage->dwPackageID);
StartCallToPackage( pPackage );
__try
{
scRet = pPackage->FunctionTable.GetInfo(&PackageInfo);
}
__except (SP_EXCEPTION)
{
scRet = GetExceptionCode();
scRet = SPException(scRet, pPackage->dwPackageID);
}
EndCallToPackage( pPackage );
if (FAILED(scRet))
{
return(scRet);
}
//
// Marshall the data to copy to the client
//
RtlInitUnicodeString(
&NameString,
PackageInfo.Name
);
RtlInitUnicodeString(
&CommentString,
PackageInfo.Comment
);
cbData = ulStructureSize +
NameString.MaximumLength +
CommentString.MaximumLength;
pLocalInfo = (PSecPkgInfo) LsapAllocatePrivateHeap(cbData);
if (pLocalInfo == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
pClientInfo = (PSecPkgInfo) LsapClientAllocate(cbData);
if (pClientInfo == NULL)
{
LsapFreePrivateHeap(pLocalInfo);
return(STATUS_INSUFFICIENT_RESOURCES);
}
ClientOffset = (LONG_PTR) ((PBYTE) pClientInfo - (PBYTE) pLocalInfo);
Where = (PBYTE) (pLocalInfo + 1);
*pLocalInfo = PackageInfo;
pLocalInfo->Name = (LPWSTR) (Where + ClientOffset);
RtlCopyMemory(
Where,
NameString.Buffer,
NameString.MaximumLength
);
Where += NameString.MaximumLength;
pLocalInfo->Comment = (LPWSTR) (Where + ClientOffset);
RtlCopyMemory(
Where,
CommentString.Buffer,
CommentString.MaximumLength
);
Where += CommentString.MaximumLength;
DsysAssert(Where - (PBYTE) pLocalInfo == (LONG) cbData);
scRet = LsapCopyToClient(
pLocalInfo,
pClientInfo,
cbData);
LsapFreePrivateHeap(pLocalInfo);
if (FAILED(scRet))
{
LsapClientFree(pClientInfo);
}
*ppInfo = pClientInfo;
return(scRet);
}
//+-------------------------------------------------------------------------
//
// Function: WLsaGetSecurityUserInfo
//
// Synopsis: worker function to get info about a logon session
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
WLsaGetSecurityUserInfo(
IN PLUID pLogonId,
IN ULONG fFlags,
OUT PSECURITY_USER_DATA * pUserInfo
)
{
PLSAP_LOGON_SESSION pSession;
NTSTATUS Status;
PSECURITY_USER_DATA LocalUserData = NULL;
PSECURITY_USER_DATA ClientBuffer = NULL;
SECPKG_CLIENT_INFO ClientInfo;
ULONG BufferSize;
PUCHAR Where;
LONG_PTR Offset;
ULONG ulStructureSize = sizeof(SECURITY_USER_DATA);
DebugLog((DEB_TRACE_WAPI,"WLsaGetSecurityUserInfo called\n"));
//
// if the logon ID is null, it is for the caller
// so we know to go to the primary package.
//
if (pLogonId == NULL)
{
Status = LsapGetClientInfo(&ClientInfo);
if (!NT_SUCCESS(Status))
{
return(Status);
}
pLogonId = &ClientInfo.LogonId;
}
pSession = LsapLocateLogonSession( pLogonId );
if (!pSession)
{
DebugLog((DEB_WARN,"WLsaGetSecurityUserInfo called for non-existent LUID 0x%x:0x%x\n",
pLogonId->LowPart,pLogonId->HighPart));
Status = STATUS_NO_SUCH_LOGON_SESSION;
goto Cleanup;
}
BufferSize = ulStructureSize +
pSession->AccountName.Length +
pSession->AuthorityName.Length +
pSession->LogonServer.Length +
RtlLengthSid(pSession->UserSid);
LocalUserData = (PSECURITY_USER_DATA) LsapAllocatePrivateHeap(BufferSize);
if (LocalUserData == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
ClientBuffer = (PSECURITY_USER_DATA) LsapClientAllocate(BufferSize);
if (ClientBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Offset = (LONG_PTR) ((PUCHAR) ClientBuffer - (PUCHAR) LocalUserData);
Where = (PUCHAR) (LocalUserData + 1);
//
// Copy in all the fields from the logon session.
//
LocalUserData->pSid = (PSID) (Where + Offset);
RtlCopyMemory(
Where,
pSession->UserSid,
RtlLengthSid(pSession->UserSid)
);
Where += RtlLengthSid(pSession->UserSid);
//
// Copy in the user name
//
LocalUserData->UserName.Length =
LocalUserData->UserName.MaximumLength = pSession->AccountName.Length;
LocalUserData->UserName.Buffer = (LPWSTR) (Where + Offset);
RtlCopyMemory(
Where,
pSession->AccountName.Buffer,
pSession->AccountName.Length
);
Where += pSession->AccountName.Length;
//
// Copy in the domain name
//
LocalUserData->LogonDomainName.Length =
LocalUserData->LogonDomainName.MaximumLength = pSession->AuthorityName.Length;
LocalUserData->LogonDomainName.Buffer = (LPWSTR) (Where + Offset);
RtlCopyMemory(
Where,
pSession->AuthorityName.Buffer,
pSession->AuthorityName.Length
);
Where += pSession->AuthorityName.Length;
//
// Copy in the logon server
//
LocalUserData->LogonServer.Length =
LocalUserData->LogonServer.MaximumLength = pSession->LogonServer.Length;
LocalUserData->LogonServer.Buffer = (LPWSTR) (Where + Offset);
RtlCopyMemory(
Where,
pSession->LogonServer.Buffer,
pSession->LogonServer.Length
);
Where += pSession->LogonServer.Length;
//
// Copy this to the client
//
LsapReleaseLogonSession( pSession );
Status = LsapCopyToClient(
LocalUserData,
ClientBuffer,
BufferSize
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
*pUserInfo = ClientBuffer;
ClientBuffer = NULL;
Cleanup:
if (LocalUserData != NULL)
{
LsapFreePrivateHeap(LocalUserData);
}
if (ClientBuffer != NULL)
{
LsapClientFree(ClientBuffer);
}
DebugLog((DEB_TRACE_WAPI,"GetUserInfo returned %x\n",Status));
return(Status);
}
HANDLE hEventLog = INVALID_HANDLE_VALUE;
DWORD LoggingLevel = (1 << EVENTLOG_ERROR_TYPE) | (1 << EVENTLOG_WARNING_TYPE) |
(1 << EVENTLOG_INFORMATION_TYPE) ;
WCHAR EventSourceName[] = TEXT("LsaSrv");
#define MAX_EVENT_STRINGS 8
//+---------------------------------------------------------------------------
//
// Function: SpmpInitializeEvents
//
// Synopsis: Connects to event log service
//
// Arguments: (none)
//
// History: 1-03-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
SpmpInitializeEvents(void)
{
HKEY hKey;
int err;
DWORD disp;
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
TEXT("System\\CurrentControlSet\\Services\\EventLog\\System\\LsaSrv"),
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&disp);
if (err)
{
return(FALSE);
}
if (disp == REG_CREATED_NEW_KEY)
{
RegSetValueEx( hKey,
TEXT("EventMessageFile"),
0,
REG_EXPAND_SZ,
(PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"),
sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) );
RegSetValueEx( hKey,
TEXT("CategoryMessageFile"),
0,
REG_EXPAND_SZ,
(PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"),
sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) );
disp = 7;
RegSetValueEx( hKey,
TEXT("TypesSupported"),
0,
REG_DWORD,
(PBYTE) &disp,
sizeof(DWORD) );
disp = CATEGORY_MAX_CATEGORY - 1;
RegSetValueEx( hKey,
TEXT("CategoryCount"),
0,
REG_DWORD,
(PBYTE) &disp,
sizeof(DWORD) );
}
RegCloseKey(hKey);
hEventLog = RegisterEventSource(NULL, EventSourceName);
if (hEventLog)
{
return(TRUE);
}
hEventLog = INVALID_HANDLE_VALUE;
DebugLog((DEB_ERROR, "Could not open event log, error %d\n", GetLastError()));
return(FALSE);
}
//+---------------------------------------------------------------------------
//
// Function: ReportServiceEvent
//
// Synopsis: Reports an event to the event log
//
// Arguments: [EventType] -- EventType (ERROR, WARNING, etc.)
// [EventId] -- Event ID
// [SizeOfRawData] -- Size of raw data
// [RawData] -- Raw data
// [NumberOfStrings] -- number of strings
// ... -- PWSTRs to string data
//
// History: 1-03-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD
SpmpReportEvent(
IN BOOL Unicode,
IN WORD EventType,
IN DWORD EventId,
IN DWORD Category,
IN DWORD SizeOfRawData,
IN PVOID RawData,
IN DWORD NumberOfStrings,
...
)
{
va_list arglist;
ULONG i;
PWSTR Strings[ MAX_EVENT_STRINGS ];
PSTR StringsA[ MAX_EVENT_STRINGS ];
DWORD rv;
if (hEventLog == INVALID_HANDLE_VALUE)
{
if (!SpmpInitializeEvents())
{
return((DWORD) -1);
}
}
//
// We're not supposed to be logging this, so nuke it
//
if ((LoggingLevel & (1 << EventType)) == 0)
{
return(0);
}
//
// Look at the strings, if they were provided
//
va_start( arglist, NumberOfStrings );
if (NumberOfStrings > MAX_EVENT_STRINGS) {
NumberOfStrings = MAX_EVENT_STRINGS;
}
for (i=0; i<NumberOfStrings; i++) {
if (Unicode)
{
Strings[ i ] = va_arg( arglist, PWSTR );
}
else
{
StringsA[ i ] = va_arg( arglist, PSTR );
}
}
//
// Report the event to the eventlog service
//
if (Unicode)
{
if (!ReportEventW( hEventLog,
EventType,
(WORD) Category,
EventId,
NULL,
(WORD)NumberOfStrings,
SizeOfRawData,
(const WCHAR * *) Strings,
RawData) )
{
rv = GetLastError();
DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, GetLastError() ));
}
else
{
rv = ERROR_SUCCESS;
}
}
else
{
if (!ReportEventA( hEventLog,
EventType,
(WORD) Category,
EventId,
NULL,
(WORD)NumberOfStrings,
SizeOfRawData,
(const char * *) StringsA,
RawData) )
{
rv = GetLastError();
DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, GetLastError() ));
}
else
{
rv = ERROR_SUCCESS;
}
}
return rv;
}
//+---------------------------------------------------------------------------
//
// Function: SpmpReportEventU
//
// Synopsis: Reports an event to the event log
//
// Arguments: [EventType] -- EventType (ERROR, WARNING, etc.)
// [EventId] -- Event ID
// [SizeOfRawData] -- Size of raw data
// [RawData] -- Raw data
// [NumberOfStrings] -- number of strings
// ... -- PUNICODE_STRINGs to string data
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD
SpmpReportEventU(
IN WORD EventType,
IN DWORD EventId,
IN DWORD Category,
IN DWORD SizeOfRawData,
IN PVOID RawData,
IN DWORD NumberOfStrings,
...
)
{
va_list arglist;
ULONG i;
PUNICODE_STRING Strings[ MAX_EVENT_STRINGS ];
DWORD rv;
if (hEventLog == INVALID_HANDLE_VALUE) {
if ( !SpmpInitializeEvents()) {
return( -1 );
}
}
//
// We're not supposed to be logging this, so nuke it
//
if (( LoggingLevel & ( 1 << EventType )) == 0 ) {
return( 0 );
}
//
// Look at the strings, if they were provided
//
va_start( arglist, NumberOfStrings );
if ( NumberOfStrings > MAX_EVENT_STRINGS ) {
NumberOfStrings = MAX_EVENT_STRINGS;
}
for ( i = 0 ; i < NumberOfStrings ; i++ ) {
Strings[ i ] = va_arg( arglist, PUNICODE_STRING );
}
//
// Report the event to the eventlog service
//
rv = ElfReportEventW(
hEventLog,
EventType,
( USHORT )Category,
EventId,
NULL,
( USHORT )NumberOfStrings,
SizeOfRawData,
Strings,
RawData,
0,
NULL,
NULL
);
if ( !NT_SUCCESS( rv )) {
DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, rv ));
goto Cleanup;
}
rv = ERROR_SUCCESS;
Cleanup:
return rv;
}
BOOL
SpmpShutdownEvents(void)
{
return(DeregisterEventSource(hEventLog));
}