Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1402 lines
43 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
stub.c
Abstract:
Kerberos Security Support Provider client stubs.
Author:
Chandana Surlu (ChandanS) 11-Feb-1997
Environment: Win9x User Mode
Revision History:
--*/
#include <kerb.hxx>
#include <rpc.h> // PSEC_WINNT_AUTH_IDENTITY
#include <stdarg.h> // Variable-length argument support
#define KERBSTUB_ALLOCATE
#include <kerbp.h>
SECPKG_DLL_FUNCTIONS UserFunctionTable;
VOID
KerbShutdownSecurityInterface(
VOID
);
VOID DumpLogonSession();
BOOL WINAPI DllMain(
HINSTANCE hInstance,
ULONG dwReason,
PVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
InitializeCriticalSection( &KerbDllCritSect );
#if DBG
InitializeCriticalSection( &KerbGlobalLogFileCritSect );
KerbInfoLevel = DEB_ERROR | DEB_WARN | DEB_TRACE | DEB_TRACE_API |
DEB_TRACE_CRED | DEB_TRACE_CTXT | DEB_TRACE_LOCKS |
DEB_TRACE_CTXT2 | DEB_TRACE_KDC | DEB_TRACE_LSESS |
DEB_TRACE_LOGON;
#endif // DBG
}
else if (dwReason == DLL_PROCESS_DETACH)
{
KerbShutdownSecurityInterface();
#if DBG
DeleteCriticalSection( &KerbGlobalLogFileCritSect );
#endif // DBG
DeleteCriticalSection( &KerbDllCritSect );
}
return TRUE;
}
PSecurityFunctionTable
InitSecurityInterfaceA(
VOID
)
/*++
Routine Description:
RPC calls this function to get the addresses of all the other functions
that it might call.
Arguments:
None.
Return Value:
A pointer to our static SecurityFunctionTable. The caller need
not deallocate this table.
--*/
{
HKEY hRegKey;
DWORD dwError = 0, dwSize = 0;
DWORD dwType = REG_BINARY;
LPWSTR pUserName = NULL, pDomainName = NULL;
PKERB_LOGON_SESSION_CACHE RegLogonSession = NULL;
PKERB_LOGON_SESSION LogonSession = NULL;
SECURITY_STATUS Status = SEC_E_OK;
// BUBUG Init this to something, we need Parameters.DomainName,
// Parameters.DnsDomainName & Parameters.version at least
SECPKG_PARAMETERS Parameters;
PVOID ignored = NULL;
DebugLog((DEB_TRACE_API, "Entering KerbInitSecurityInterface\n"));
// Initialize the SecurityFunctionTable
ZeroMemory( &KerbDllSecurityFunctionTable,
sizeof(KerbDllSecurityFunctionTable) );
KerbGlobalCapabilities = KERBEROS_CAPABILITIES;
KerberosState = KerberosUserMode;
KerbDllSecurityFunctionTable.dwVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
KerbDllSecurityFunctionTable.EnumerateSecurityPackages = KerbEnumerateSecurityPackages;
KerbDllSecurityFunctionTable.AcquireCredentialsHandle = KerbAcquireCredentialsHandle;
KerbDllSecurityFunctionTable.FreeCredentialHandle = KerbFreeCredentialsHandle;
KerbDllSecurityFunctionTable.InitializeSecurityContext = KerbInitializeSecurityContext;
KerbDllSecurityFunctionTable.QueryCredentialsAttributes = KerbQueryCredentialsAttributes;
KerbDllSecurityFunctionTable.AcceptSecurityContext = NULL;
KerbDllSecurityFunctionTable.CompleteAuthToken = KerbCompleteAuthToken;
KerbDllSecurityFunctionTable.QueryContextAttributes = KerbQueryContextAttributes;
KerbDllSecurityFunctionTable.SspiLogonUser = KerbSspiLogonUser;
KerbDllSecurityFunctionTable.DeleteSecurityContext = KerbDeleteSecurityContext;
KerbDllSecurityFunctionTable.ApplyControlToken = KerbApplyControlToken;
KerbDllSecurityFunctionTable.ImpersonateSecurityContext = KerbImpersonateSecurityContext;
KerbDllSecurityFunctionTable.RevertSecurityContext = KerbRevertSecurityContext;
KerbDllSecurityFunctionTable.MakeSignature = KerbMakeSignature;
KerbDllSecurityFunctionTable.VerifySignature = KerbVerifySignature;
KerbDllSecurityFunctionTable.FreeContextBuffer = KerbFreeContextBuffer;
KerbDllSecurityFunctionTable.QuerySecurityPackageInfo = KerbQuerySecurityPackageInfo;
KerbDllSecurityFunctionTable.Reserved3 = KerbSealMessage;
KerbDllSecurityFunctionTable.Reserved4 = KerbUnsealMessage;
KerbDllSecurityFunctionTable.EncryptMessage = KerbSealMessage;
KerbDllSecurityFunctionTable.DecryptMessage = KerbUnsealMessage;
// Before we call SpInitialize, fill a table of LsaFunctions that are
// imlemented locally. This is done so that the code does not look awful.
// Fill in dummy functions in case more functions are used so we don't
// av
// FunctionTable.CreateLogonSession = CreateLogonSession;
// FunctionTable.DeleteLogonSession = DeleteLogonSession;
// FunctionTable.AddCredential = AddCredential;
// FunctionTable.GetCredentials = GetCredentials;
// FunctionTable.DeleteCredential = DeleteCredential;
FunctionTable.AllocateLsaHeap = AllocateLsaHeap;
FunctionTable.FreeLsaHeap = FreeLsaHeap;
FunctionTable.AllocateClientBuffer = AllocateClientBuffer;
FunctionTable.FreeClientBuffer = FreeClientBuffer;
FunctionTable.CopyToClientBuffer = CopyToClientBuffer;
FunctionTable.CopyFromClientBuffer = CopyFromClientBuffer;
// FunctionTable.ImpersonateClient = ImperosnateClient;
// FunctionTable.UnloadPackage = UnloadPackage;
FunctionTable.DuplicateHandle = KerbDuplicateHandle;
// FunctionTable.SaveSupplementalCredentials = SaveSupplementalCredentials;
// FunctionTable.GetWindow = GetWindow;
// FunctionTable.ReleaseWindow = ReleaseWindow;
// FunctionTable.CreateThread = CreateThread;
FunctionTable.GetClientInfo = GetClientInfo;
// FunctionTable.RegisterNotification = RegisterNotification;
// FunctionTable.CancelNotification = CancelNotification;
FunctionTable.MapBuffer = MapBuffer;
// FunctionTable.CreateToken = CreateToken;
FunctionTable.AuditLogon = AuditLogon;
// FunctionTable.CallPackage = CallPackage;
FunctionTable.FreeReturnBuffer = FreeReturnBuffer;
FunctionTable.GetCallInfo = GetCallInfo;
// FunctionTable.CallPackageEx = CallPackageEx;
// FunctionTable.CreateSharedMemory = CreateSharedMemory;
// FunctionTable.AllocateSharedMemory = AllocateSharedMemory;
// FunctionTable.FreeSharedMemory = FreeSharedMemory;
// FunctionTable.DeleteSharedMemory = DeleteSharedMemory;
// FunctionTable.OpenSamUser = OpenSamUser;
// FunctionTable.GetUserCredentials = GetUserCredentials;
// FunctionTable.GetUserAuthData = GetUserAuthData;
// FunctionTable.CloseSamUser = CloseSamUser;
// FunctionTable.ConvertAuthDataToTokenInfo = ConvertAuthDataToTokenInfo;
// we call into the kerb routines
Parameters.Version = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
Parameters.MachineState = SECPKG_STATE_STANDALONE;
// NOTE - Yikes!
Parameters.DomainName.Buffer = L"";
Parameters.DomainName.Length = 0;
Parameters.DomainName.MaximumLength = 2;
Parameters.DnsDomainName.Buffer = L"";
Parameters.DnsDomainName.Length = 0;
Parameters.DnsDomainName.MaximumLength = 2;
// If logon session data exists, load it
if ( ERROR_SUCCESS != ( dwError = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
KERBEROS_TICKET_KEY,
0,
KEY_ALL_ACCESS,
&hRegKey ) ) )
{
DebugLog((DEB_ERROR, "Error opening KERBEROS_TICKET_KEY\n"));
goto RestOfInit;
}
// get username size
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_USERNAME_KEY,
NULL,
&dwType,
NULL,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading KERBEROS_TICKET_USERNAME_KEY size\n"));
goto RestOfInit;
}
if (dwSize == 0 )
{
DebugLog((DEB_ERROR, "KERBEROS_TICKET_USERNAME_KEY contains 0 bytes\n"));
goto RestOfInit;
}
pUserName = (LPWSTR) KerbAllocate(dwSize);
if (pUserName == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_USERNAME_KEY \n"));
goto RestOfInit;
}
// get username into LogonSession->PrimaryCredentials->Username
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_USERNAME_KEY,
NULL,
&dwType,
(PUCHAR) pUserName,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading from KERBEROS_TICKET_USERNAME_KEY\n"));
goto RestOfInit;
}
// get domainname
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_DOMAINNAME_KEY,
NULL,
&dwType,
NULL,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading KERBEROS_TICKET_DOMAINNAME_KEY size\n"));
goto RestOfInit;
}
if (dwSize == 0 )
{
DebugLog((DEB_ERROR, "KERBEROS_TICKET_DOMAINNAME_KEY contains 0 bytes\n"));
goto RestOfInit;
}
pDomainName = (LPWSTR) KerbAllocate(dwSize);
if (pDomainName == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_DOMAINNAME_KEY \n"));
goto RestOfInit;
}
// get domainname into LogonSession->PrimaryCredentials->Domainname
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_DOMAINNAME_KEY,
NULL,
&dwType,
(PUCHAR) pDomainName,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading from KERBEROS_TICKET_DOMAINNAME_KEY\n"));
goto RestOfInit;
}
// get domainname into Parameters.DomainName
Parameters.DomainName.Buffer = pDomainName;
Parameters.DomainName.Length = (USHORT)dwSize;
Parameters.DomainName.MaximumLength = (USHORT)dwSize;
// get logon session data size
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_LOGONSESSION_KEY,
NULL,
&dwType,
NULL,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading from KERBEROS_TICKET_LOGONSESSION_KEY\n"));
goto RestOfInit;
}
if (dwSize == 0 )
{
DebugLog((DEB_ERROR, "KERBEROS_TICKET_LOGONSESSION_KEY contains 0 bytes\n"));
goto RestOfInit;
}
RegLogonSession = (PKERB_LOGON_SESSION_CACHE) KerbAllocate(dwSize);
if (RegLogonSession == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_LOGONSESSION_KEY \n"));
goto RestOfInit;
}
// get logon session into LogonSession->PrimaryCredentials->Domainname
if ( ERROR_SUCCESS != ( dwError = RegQueryValueEx (
hRegKey,
KERBEROS_TICKET_LOGONSESSION_KEY,
NULL,
&dwType,
(PUCHAR) RegLogonSession,
&dwSize )))
{
DebugLog((DEB_ERROR, "Error reading from KERBEROS_TICKET_LOGONSESSION_KEY\n"));
goto RestOfInit;
}
if ( ERROR_SUCCESS != ( dwError = RegCloseKey ( hRegKey) ))
{
DebugLog((DEB_ERROR, "Error closing KERBEROS_TICKET_KEY\n"));
goto RestOfInit;
}
RestOfInit:
Status = SpInitialize(1, &Parameters, &FunctionTable);
// Do the user mode init too
// Before we call SpInstanceInit, fill a table of functions that are
// imlemented locally. This is done so that the code does not look awful.
// Fill in dummy functions in case more functions are used so we don't
// av
UserFunctionTable.FreeHeap = FreeLsaHeap;
UserFunctionTable.AllocateHeap = AllocateLsaHeap;
Status = SpInstanceInit(SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
&UserFunctionTable,
&ignored );
// Now, copy the logon sessions (if they exist)
// This is kina what KerbCreateLogonSession does, expect that we don't
// have to build password list etc.
if (RegLogonSession != NULL)
{
LUID LogonId;
NTSTATUS Status;
ULONG PasswordSize, EncryptKeySize, CredentialSize;
ULONG Index;
PUCHAR Base;
UINT Offset;
//
// Allocate the new logon session
//
Status = NtAllocateLocallyUniqueId (&LogonId);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = KerbAllocateLogonSession( &LogonSession );
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// Fill in the logon session components
//
LogonSession->Lifetime = RegLogonSession->Lifetime;
LogonSession->LogonSessionFlags = RegLogonSession->LogonSessionFlags;
LogonSession->LogonId = LogonId;
//
// Munge RegLogonSession & ptrs for username & domainame
//
RegLogonSession->UserName.Buffer = (LPWSTR)((PUCHAR)RegLogonSession + (INT)(RegLogonSession->UserName.Buffer));
RegLogonSession->DomainName.Buffer = (LPWSTR)((PUCHAR)RegLogonSession + (INT)(RegLogonSession->DomainName.Buffer));
//
// actually copy the username struct and alloc username.buffer
//
LogonSession->PrimaryCredentials.UserName.Buffer = (LPWSTR) KerbAllocate(RegLogonSession->UserName.MaximumLength);
if (LogonSession->PrimaryCredentials.UserName.Buffer == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_LOGONSESSION_KEY \n"));
goto Cleanup;
}
RtlCopyMemory(LogonSession->PrimaryCredentials.UserName.Buffer,
RegLogonSession->UserName.Buffer,
RegLogonSession->UserName.MaximumLength);
LogonSession->PrimaryCredentials.UserName.Length = RegLogonSession->UserName.Length;
LogonSession->PrimaryCredentials.UserName.MaximumLength = RegLogonSession->UserName.MaximumLength;
// actually copy the domainname struct and alloc domainname.buffer
LogonSession->PrimaryCredentials.DomainName.Buffer = (LPWSTR) KerbAllocate(RegLogonSession->DomainName.MaximumLength);
if (LogonSession->PrimaryCredentials.DomainName.Buffer == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_LOGONSESSION_KEY \n"));
goto Cleanup;
}
RtlCopyMemory(LogonSession->PrimaryCredentials.DomainName.Buffer,
RegLogonSession->DomainName.Buffer,
RegLogonSession->DomainName.MaximumLength);
LogonSession->PrimaryCredentials.DomainName.Length = RegLogonSession->DomainName.Length;
LogonSession->PrimaryCredentials.DomainName.MaximumLength = RegLogonSession->DomainName.MaximumLength;
//
// What is the size of the Credentials struct
//
EncryptKeySize = sizeof(KERB_KEY_DATA) * RegLogonSession->CredentialCount;
PasswordSize = 0;
for (Index = 0; Index < RegLogonSession->CredentialCount ; Index++ )
{
PasswordSize += RegLogonSession->Credentials[Index].keyvalue.length;
RegLogonSession->Credentials[Index].keyvalue.value = (unsigned char*)
((PUCHAR) RegLogonSession +
(INT)(RegLogonSession->Credentials[Index].keyvalue.value));
} // for
//
// Alloc & copy over the Credentials block
//
CredentialSize = sizeof(KERB_STORED_CREDENTIAL) -
(ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA)) +
EncryptKeySize + PasswordSize;
LogonSession->PrimaryCredentials.Passwords = (PKERB_STORED_CREDENTIAL) KerbAllocate(CredentialSize);
if (LogonSession->PrimaryCredentials.Passwords == NULL)
{
DebugLog((DEB_ERROR, "Error allocing KERBEROS_TICKET_LOGONSESSION_KEY \n"));
goto Cleanup;
}
//
// copy revision, flags & credentialcount
//
LogonSession->PrimaryCredentials.Passwords->Revision = RegLogonSession->Revision;
LogonSession->PrimaryCredentials.Passwords->Flags = RegLogonSession->Flags;
LogonSession->PrimaryCredentials.Passwords->CredentialCount = RegLogonSession->CredentialCount;
//
// copy all keyvalue.value
//
Offset = 0;
Base = (PUCHAR)LogonSession->PrimaryCredentials.Passwords +
CredentialSize - PasswordSize;
for (Index = 0; Index < RegLogonSession->CredentialCount ; Index++ )
{
RtlCopyMemory(Base + Offset,
RegLogonSession->Credentials[Index].keyvalue.value,
RegLogonSession->Credentials[Index].keyvalue.length);
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keytype =
RegLogonSession->Credentials[Index].keytype;
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length =
RegLogonSession->Credentials[Index].keyvalue.length;
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.value =
(unsigned char*) (Base + Offset);
Offset += RegLogonSession->Credentials[Index].keyvalue.length;
} // for
//
// All logons are deferred until proven otherwise
//
LogonSession->LogonSessionFlags = KERB_LOGON_DEFERRED;
if (LogonSession->PrimaryCredentials.Passwords == NULL)
{
LogonSession->LogonSessionFlags |= KERB_LOGON_NO_PASSWORD;
}
//
// Now that the logon session structure is filled out insert it
// into the list. After this you need to hold the logon session lock
// to read or write this logon session.
//
Status = KerbInsertLogonSession(LogonSession);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
Cleanup:
if (!NT_SUCCESS(Status))
{
if (LogonSession != NULL)
{
KerbReferenceLogonSessionByPointer(LogonSession, TRUE);
KerbFreeLogonSession(LogonSession);
}
}
else
{
if (LogonSession != NULL)
{
KerbDereferenceLogonSession(LogonSession);
}
}
if (RegLogonSession != NULL)
{
KerbFree(RegLogonSession);
}
// NOTE - what about pUsername & pDomainname
DebugLog((DEB_TRACE_API, "Leaving KerbInitSecurityInterface\n"));
return SEC_SUCCESS(Status) ? &KerbDllSecurityFunctionTable : NULL;
}
VOID
KerbShutdownSecurityInterface(
VOID
)
/*++
Routine Description:
Cleanup the data shared by the DLL and SERVICE.
Arguments:
None.
Return Value:
None.
--*/
{
PKERB_LOGON_SESSION LogonSession;
LUID LogonId;
PKERB_LOGON_SESSION_CACHE RegLogonSession;
HKEY hRegKey;
DWORD dwDisposition;
DWORD dwError = 0;
NTSTATUS Status = STATUS_SUCCESS;
DebugLog((DEB_TRACE_API, "Entering KerbShutdownSecurityInterface\n"));
Status = NtAllocateLocallyUniqueId (&LogonId);
LogonSession = KerbReferenceLogonSession(
&LogonId,
TRUE);
// Need to dump out logon session info in the registry
// create or open the parameters key
if ( ( dwError = RegCreateKeyEx (
HKEY_LOCAL_MACHINE,
KERBEROS_TICKET_KEY,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hRegKey,
&dwDisposition) ) )
{
DebugLog((DEB_ERROR, "Error creating KERBEROS_TICKET_KEY\n"));
goto Cleanup;
}
if (LogonSession != NULL)
{
ULONG PasswordSize, Offset;
ULONG Index;
ULONG TotalSize = 0 ;
PUCHAR Base;
//
// Compute the size of the passwords, which are assumed to be
// marshalled in order.
//
PasswordSize = sizeof(KERB_LOGON_SESSION_CACHE) - sizeof(KERB_KEY_DATA) * ANYSIZE_ARRAY +
LogonSession->PrimaryCredentials.Passwords->CredentialCount * sizeof(KERB_KEY_DATA);
for (Index = 0; Index < LogonSession->PrimaryCredentials.Passwords->CredentialCount ; Index++ )
{
PasswordSize += LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length;
DsysAssert((PUCHAR) LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.value <=
(PUCHAR) LogonSession->PrimaryCredentials.Passwords + PasswordSize );
}
// Total size of the logon session cache
TotalSize = LogonSession->PrimaryCredentials.UserName.MaximumLength +
LogonSession->PrimaryCredentials.DomainName.MaximumLength +
PasswordSize;
RegLogonSession = (PKERB_LOGON_SESSION_CACHE) KerbAllocate(TotalSize);
if (RegLogonSession == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RegLogonSession->Lifetime =
LogonSession->Lifetime;
RegLogonSession->LogonSessionFlags =
LogonSession->LogonSessionFlags;
RegLogonSession->UserName.Length =
LogonSession->PrimaryCredentials.UserName.Length;
RegLogonSession->UserName.MaximumLength =
LogonSession->PrimaryCredentials.UserName.MaximumLength;
RegLogonSession->DomainName.Length =
LogonSession->PrimaryCredentials.DomainName.Length;
RegLogonSession->DomainName.MaximumLength =
LogonSession->PrimaryCredentials.DomainName.MaximumLength;
RegLogonSession->Revision =
LogonSession->PrimaryCredentials.Passwords->Revision;
RegLogonSession->Flags =
LogonSession->PrimaryCredentials.Passwords->Flags;
RegLogonSession->CredentialCount=
LogonSession->PrimaryCredentials.Passwords->CredentialCount;
Base = (PUCHAR) RegLogonSession;
Offset = sizeof(KERB_LOGON_SESSION_CACHE) -
(ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA)) +
(RegLogonSession->CredentialCount * sizeof(KERB_KEY_DATA));
// Offset from the struct
RegLogonSession->UserName.Buffer = (LPWSTR)Offset;
RtlCopyMemory(Base + Offset,
LogonSession->PrimaryCredentials.UserName.Buffer,
LogonSession->PrimaryCredentials.UserName.MaximumLength);
Offset += LogonSession->PrimaryCredentials.UserName.MaximumLength;
RegLogonSession->DomainName.Buffer = (LPWSTR)(Offset);
RtlCopyMemory(Base + Offset,
LogonSession->PrimaryCredentials.DomainName.Buffer,
LogonSession->PrimaryCredentials.DomainName.MaximumLength);
Offset += LogonSession->PrimaryCredentials.DomainName.MaximumLength;
for (Index = 0; Index < RegLogonSession->CredentialCount ; Index++ )
{
RegLogonSession->Credentials[Index].keytype =
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keytype;
RegLogonSession->Credentials[Index].keyvalue.length =
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length;
RegLogonSession->Credentials[Index].keyvalue.value =
(unsigned char *) (Offset);
RtlCopyMemory(Base + Offset,
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.value,
LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length);
Offset += LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length;
} // for
// add username from LogonSession->PrimaryCredentials->Username
if ( ( dwError = RegSetValueEx (
hRegKey,
KERBEROS_TICKET_USERNAME_KEY,
0,
REG_BINARY,
(LPBYTE) LogonSession->PrimaryCredentials.UserName.Buffer,
LogonSession->PrimaryCredentials.UserName.Length
) ))
{
DebugLog((DEB_ERROR, "Error writing to KERBEROS_TICKET_USERNAME_KEY\n"));
goto Cleanup;
}
// add domainname from LogonSession->PrimaryCredentials->domainname
if ( ( dwError = RegSetValueEx (
hRegKey,
KERBEROS_TICKET_DOMAINNAME_KEY,
0,
REG_BINARY,
(LPBYTE) LogonSession->PrimaryCredentials.DomainName.Buffer,
LogonSession->PrimaryCredentials.DomainName.Length)))
{
DebugLog((DEB_ERROR, "Error writing to KERBEROS_TICKET_DOMAINNAME_KEY\n"));
goto Cleanup;
}
// add logon session data from RegLogonSession & TotalSize
if ( ( dwError = RegSetValueEx (
hRegKey,
KERBEROS_TICKET_LOGONSESSION_KEY,
0,
REG_BINARY,
(LPBYTE) RegLogonSession,
TotalSize) ) )
{
DebugLog((DEB_ERROR, "Error writing to KERBEROS_TICKET_LOGONSESSION_KEY\n"));
goto Cleanup;
}
}
else // (LogonSession is NULL)
{
// We did not have any valid kerberos logon sessions.
// Delete all the registry values in keys.
DebugLog((DEB_TRACE, "No Kerberos LogonSession\n"));
if ( ( dwError = RegDeleteValue (
hRegKey,
KERBEROS_TICKET_USERNAME_KEY)))
{
DebugLog((DEB_ERROR, "Error deleting value KERBEROS_TICKET_USERNAME_KEY\n"));
}
if ( ( dwError = RegDeleteValue (
hRegKey,
KERBEROS_TICKET_DOMAINNAME_KEY)))
{
DebugLog((DEB_ERROR, "Error deleting value KERBEROS_TICKET_DOMAINNAME_KEY\n"));
}
if ( ( dwError = RegDeleteValue (
hRegKey,
KERBEROS_TICKET_LOGONSESSION_KEY)))
{
DebugLog((DEB_ERROR, "Error deleting value KERBEROS_TICKET_LOGONSESSION_KEY\n"));
}
}
Cleanup:
if ( ( dwError = RegFlushKey ( hRegKey) ))
{
DebugLog((DEB_ERROR, "Error Flushing KERBEROS_TICKET_KEY\n"));
}
if ( ( dwError = RegCloseKey ( hRegKey) ))
{
DebugLog((DEB_ERROR, "Error closing KERBEROS_TICKET_KEY\n"));
}
if (LogonSession != NULL)
{
KerbDereferenceLogonSession(LogonSession);
LogonSession = NULL;
}
SpShutdown();
DebugLog((DEB_TRACE_API, "Leaving KerbShutdownSecurityInterface\n"));
}
SECURITY_STATUS
KerbSpGetInfo(
IN LPTSTR PackageName,
OUT PSecPkgInfo *PackageInfo
)
/*++
Routine Description:
This API is intended to provide basic information about Security
Packages themselves. This information will include the bounds on sizes
of authentication information, credentials and contexts.
?? This is a local routine rather than the real API call since the API
call has a bad interface that neither allows me to allocate the
buffer nor tells me how big the buffer is. Perhaps when the real API
is fixed, I'll make this the real API.
Arguments:
PackageName - Name of the package being queried.
PackageInfo - Returns a pointer to an allocated block describing the
security package. The allocated block must be freed using
FreeContextBuffer.
Return Value:
SEC_E_OK -- Call completed successfully
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
--*/
{
LPTSTR Where;
//
// Ensure the correct package name was passed in.
//
if ( lstrcmpi( PackageName, KERBEROS_PACKAGE_NAME ) != 0 ) {
return SEC_E_SECPKG_NOT_FOUND;
}
//
// Allocate a buffer for the PackageInfo
//
*PackageInfo = (PSecPkgInfo) LocalAlloc( 0, sizeof(SecPkgInfo) +
sizeof(KERBEROS_PACKAGE_NAME) +
sizeof(KERBEROS_PACKAGE_COMMENT) );
if ( *PackageInfo == NULL ) {
return SEC_E_INSUFFICIENT_MEMORY;
}
//
// Fill in the information.
//
(*PackageInfo)->fCapabilities = KerbGlobalCapabilities;
(*PackageInfo)->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
(*PackageInfo)->wRPCID = RPC_C_AUTHN_GSS_KERBEROS;
(*PackageInfo)->cbMaxToken = KERBEROS_MAX_TOKEN;
Where = (LPTSTR)((*PackageInfo)+1);
(*PackageInfo)->Name = Where;
lstrcpy( Where, KERBEROS_PACKAGE_NAME);
Where += lstrlen(Where) + 1;
(*PackageInfo)->Comment = Where;
lstrcpy( Where, KERBEROS_PACKAGE_COMMENT);
Where += lstrlen(Where) + 1;
return SEC_E_OK;
}
SECURITY_STATUS
KerbEnumerateSecurityPackages(
OUT PULONG PackageCount,
OUT PSecPkgInfo *PackageInfo
)
/*++
Routine Description:
This API returns a list of Security Packages available to client (i.e.
those that are either loaded or can be loaded on demand). The caller
must free the returned buffer with FreeContextBuffer. This API returns
a list of all the security packages available to a service. The names
returned can then be used to acquire credential handles, as well as
determine which package in the system best satisfies the requirements
of the caller. It is assumed that all available packages can be
included in the single call.
This is really a dummy API that just returns information about this
security package. It is provided to ensure this security package has the
same interface as the multiplexer DLL does.
Arguments:
PackageCount - Returns the number of packages supported.
PackageInfo - Returns an allocate array of structures
describing the security packages. The array must be freed
using FreeContextBuffer.
Return Value:
SEC_E_OK -- Call completed successfully
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
--*/
{
//
// Get the information for this package.
//
LPTSTR Where;
*PackageCount = 1;
//
// Allocate a buffer for the PackageInfo
//
*PackageInfo = (PSecPkgInfo) LocalAlloc( 0, sizeof(SecPkgInfo) +
sizeof(KERBEROS_PACKAGE_NAME) +
sizeof(KERBEROS_PACKAGE_COMMENT) );
if ( *PackageInfo == NULL ) {
return SEC_E_INSUFFICIENT_MEMORY;
}
//
// Fill in the information.
//
(*PackageInfo)->fCapabilities = KerbGlobalCapabilities;
(*PackageInfo)->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
(*PackageInfo)->wRPCID = RPC_C_AUTHN_GSS_KERBEROS;
(*PackageInfo)->cbMaxToken = KERBEROS_MAX_TOKEN;
Where = (LPTSTR)((*PackageInfo)+1);
(*PackageInfo)->Name = Where;
lstrcpy( Where, KERBEROS_PACKAGE_NAME);
Where += lstrlen(Where) + 1;
(*PackageInfo)->Comment = Where;
lstrcpy( Where, KERBEROS_PACKAGE_COMMENT);
Where += lstrlen(Where) + 1;
return SEC_E_OK;
}
SECURITY_STATUS
KerbQuerySecurityPackageInfo (
LPTSTR PackageName,
PSecPkgInfo SEC_FAR * Package
)
{
return ( KerbSpGetInfo(
PackageName,
Package));
}
SECURITY_STATUS SEC_ENTRY
KerbFreeContextBuffer (
void __SEC_FAR * ContextBuffer
)
/*++
Routine Description:
This API is provided to allow callers of security API such as
InitializeSecurityContext() for free the memory buffer allocated for
returning the outbound context token.
Arguments:
ContextBuffer - Address of the buffer to be freed.
Return Value:
SEC_E_OK - Call completed successfully
--*/
{
//
// The only allocated buffer that the kerb currently returns to the caller
// is from EnumeratePackages. It uses LocalAlloc to allocate memory. If
// we ever need memory to be allocated by the service, we have to rethink
// how this routine distinguishes between to two types of allocated memory.
//
(VOID) LocalFree( ContextBuffer );
return SEC_E_OK;
}
#if DBG
//
// Control which messages get displayed
//
// DWORD KerbInfoLevel = DEB_ERROR | DEB_WARN | DEB_TRACE | DEB_TRACE_API;
//
// SspPrintRoutine - Displays debug output
//
VOID __cdecl
KerbPrintRoutine(
IN DWORD DebugFlag,
IN LPCSTR FormatString, // PRINTF()-STYLE FORMAT STRING.
... // OTHER ARGUMENTS ARE POSSIBLE.
)
{
static char prefix[] = "KERB: ";
char outbuf[256];
va_list args;
if ( DebugFlag & KerbInfoLevel) {
EnterCriticalSection( &KerbGlobalLogFileCritSect );
lstrcpy(outbuf, prefix);
va_start(args, FormatString);
wvsprintf(outbuf + sizeof(prefix) - 1, FormatString, args);
OutputDebugString(outbuf);
LeaveCriticalSection( &KerbGlobalLogFileCritSect );
}
return;
}
#endif DBG
SECURITY_STATUS
KerbAcquireCredentialsHandle(
IN LPTSTR PrincipalName,
IN LPTSTR PackageName,
IN ULONG CredentialUseFlags,
IN PVOID LogonId,
IN PVOID AuthData,
IN SEC_GET_KEY_FN GetKeyFunction,
IN PVOID GetKeyArgument,
OUT PCredHandle CredentialHandle,
OUT PTimeStamp Lifetime
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
UNICODE_STRING NewPrincipalName;
//
// Validate the arguments
//
if ( lstrcmpi( PackageName, KERBEROS_PACKAGE_NAME ) != 0 ) {
SecStatus = SEC_E_SECPKG_NOT_FOUND;
goto Cleanup;
}
if ( (CredentialUseFlags & SECPKG_CRED_OUTBOUND) &&
ARGUMENT_PRESENT(PrincipalName) && *PrincipalName != '\0' ) {
SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
goto Cleanup;
}
if ( ARGUMENT_PRESENT(LogonId) ) {
SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
goto Cleanup;
}
if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
goto Cleanup;
}
if ( ARGUMENT_PRESENT(GetKeyArgument) ) {
SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
goto Cleanup;
}
//
// Don't allow inbound credentials if we don't have an authentication
// server avaiable
//
if ( (KerbGlobalCapabilities & SECPKG_FLAG_CLIENT_ONLY)
&& (CredentialUseFlags & SECPKG_CRED_INBOUND) ) {
DebugLog(( SSP_API,
"KerbAcquireCredentialHandle: no authentication service for inbound handle.\n" ));
SecStatus = SEC_E_NO_AUTHENTICATING_AUTHORITY;
goto Cleanup;
}
if (!RtlCreateUnicodeStringFromAsciiz( &NewPrincipalName, PrincipalName)){
SecStatus = SEC_E_INSUFFICIENT_MEMORY;;
goto Cleanup;
}
SecStatus = SpAcquireCredentialsHandle(
&NewPrincipalName,
CredentialUseFlags,
(PLUID)LogonId,
AuthData,
GetKeyFunction,
GetKeyArgument,
&CredentialHandle->dwUpper,
Lifetime );
Cleanup:
return SecStatus;
}
SECURITY_STATUS
KerbFreeCredentialsHandle(
IN PCredHandle CredentialHandle
)
/*++
Routine Description:
This API is used to notify the security system that the credentials are
no longer needed and allows the application to free the handle acquired
in the call described above. When all references to this credential
set has been removed then the credentials may themselves be removed.
Arguments:
CredentialHandle - Credential Handle obtained through
AcquireCredentialHandle.
Return Value:
SEC_E_OK -- Call completed successfully
SEC_E_NO_SPM -- Security Support Provider is not running
SEC_E_INVALID_HANDLE -- Credential Handle is invalid
--*/
{
SECURITY_STATUS SecStatus;
SecStatus = SpFreeCredentialsHandle(
CredentialHandle->dwUpper );
return SecStatus;
}
SECURITY_STATUS
KerbQueryCredentialsAttributes(
IN PCredHandle CredentialsHandle,
IN ULONG Attribute,
OUT PVOID Buffer
)
{
SECURITY_STATUS SecStatus;
SecStatus = SpQueryCredentialsAttributes(
CredentialsHandle->dwUpper,
Attribute,
Buffer );
return SecStatus;
}
SECURITY_STATUS
KerbInitializeSecurityContext(
IN PCredHandle CredentialHandle,
IN PCtxtHandle OldContextHandle,
IN LPTSTR TargetName,
IN ULONG ContextReqFlags,
IN ULONG Reserved1,
IN ULONG TargetDataRep,
IN PSecBufferDesc InputToken,
IN ULONG Reserved2,
OUT PCtxtHandle NewContextHandle,
OUT PSecBufferDesc OutputToken,
OUT PULONG ContextAttributes,
OUT PTimeStamp ExpirationTime
)
{
UNICODE_STRING TargetNameUStr;
BOOLEAN fMappedContext;
SecBuffer ContextData;
SECURITY_STATUS SecStatus = SEC_E_OK;
SECURITY_STATUS SecondaryStatus = SEC_E_OK;
SecBufferDesc EmptyBuffer = {0,0, NULL};
RtlCreateUnicodeStringFromAsciiz (&TargetNameUStr, TargetName);
if (!ARGUMENT_PRESENT(InputToken))
{
InputToken = &EmptyBuffer;
}
if (!ARGUMENT_PRESENT(OutputToken))
{
OutputToken = &EmptyBuffer;
}
SecStatus = SpInitLsaModeContext (
CredentialHandle ? CredentialHandle->dwUpper : NULL,
OldContextHandle ? OldContextHandle->dwUpper : NULL,
&TargetNameUStr,
ContextReqFlags,
TargetDataRep,
InputToken,
&NewContextHandle->dwUpper,
OutputToken,
ContextAttributes,
ExpirationTime,
&fMappedContext,
&ContextData);
if (NT_SUCCESS(SecStatus) && fMappedContext)
{
SecondaryStatus = SpInitUserModeContext(NewContextHandle->dwUpper,
&ContextData);
if (!NT_SUCCESS(SecondaryStatus))
{
SecStatus = SecondaryStatus;
SecondaryStatus = KerbDeleteSecurityContext(NewContextHandle);
}
}
return SecStatus;
}
SECURITY_STATUS
KerbDeleteSecurityContext (
IN PCtxtHandle ContextHandle
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpDeleteContext (ContextHandle->dwUpper);
return SecStatus;
}
SECURITY_STATUS
KerbApplyControlToken (
PCtxtHandle ContextHandle,
PSecBufferDesc Input
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpApplyControlToken(ContextHandle->dwUpper, Input);
return SecStatus;
}
SECURITY_STATUS
KerbImpersonateSecurityContext (
PCtxtHandle ContextHandle
)
{
return (SEC_E_NO_IMPERSONATION);
}
SECURITY_STATUS
KerbRevertSecurityContext (
PCtxtHandle ContextHandle
)
{
return (SEC_E_NO_IMPERSONATION);
}
SECURITY_STATUS
KerbQueryContextAttributes(
IN PCtxtHandle ContextHandle,
IN ULONG Attribute,
OUT PVOID Buffer
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpQueryContextAttributes(ContextHandle->dwUpper,
Attribute,
Buffer);
return SecStatus;
}
SECURITY_STATUS SEC_ENTRY
KerbCompleteAuthToken (
PCtxtHandle ContextHandle,
PSecBufferDesc BufferDescriptor
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpCompleteAuthToken(ContextHandle->dwUpper, BufferDescriptor);
return SecStatus;
}
SECURITY_STATUS
KerbMakeSignature (
PCtxtHandle ContextHandle,
unsigned long QualityOfProtection,
PSecBufferDesc Message,
unsigned long SequenceNumber
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpMakeSignature(ContextHandle->dwUpper,
QualityOfProtection,
Message,
SequenceNumber);
return SecStatus;
}
SECURITY_STATUS
KerbVerifySignature (
PCtxtHandle ContextHandle,
PSecBufferDesc Message,
unsigned long SequenceNumber,
unsigned long * QualityOfProtection
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpVerifySignature(ContextHandle->dwUpper,
Message,
SequenceNumber,
QualityOfProtection);
return SecStatus;
}
SECURITY_STATUS
KerbSealMessage (
PCtxtHandle ContextHandle,
unsigned long QualityOfProtection,
PSecBufferDesc Message,
unsigned long SequenceNumber
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpSealMessage(ContextHandle->dwUpper,
QualityOfProtection,
Message,
SequenceNumber);
return SecStatus;
}
SECURITY_STATUS
KerbUnsealMessage (
PCtxtHandle ContextHandle,
PSecBufferDesc Message,
unsigned long SequenceNumber,
unsigned long * QualityOfProtection
)
{
SECURITY_STATUS SecStatus = SEC_E_OK;
SecStatus = SpUnsealMessage(ContextHandle->dwUpper,
Message,
SequenceNumber,
QualityOfProtection);
return SecStatus;
}