windows-nt/Source/XPSP1/NT/net/ias/providers/ntuser/lsa/ezlogon.c
2020-09-26 16:20:57 +08:00

407 lines
9.6 KiB
C

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
//
// FILE
//
// ezlogon.c
//
// SYNOPSIS
//
// Defines the IAS wrapper around LsaLogonUser
//
// MODIFICATION HISTORY
//
// 08/15/1998 Original version.
// 09/09/1998 Fix AV when logon domain doesn't match user domain.
// 10/02/1998 NULL out handle when LsaLogonUser fails.
// 10/11/1998 Use SubStatus for STATUS_ACCOUNT_RESTRICTION.
// 10/22/1998 PIAS_LOGON_HOURS is now a mandatory parameter.
// 01/28/1999 Remove LogonDomainName check.
// 04/19/1999 Add IASPurgeTicketCache.
//
///////////////////////////////////////////////////////////////////////////////
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <kerberos.h>
#include <windows.h>
#include <ezlogon.h>
#include <iaslsa.h>
#include <iastrace.h>
CONST CHAR LOGON_PROCESS_NAME[] = "IAS";
CONST CHAR TOKEN_SOURCE_NAME[TOKEN_SOURCE_LENGTH] = "IAS";
// Number of milliseconds in a week.
#define MSEC_PER_WEEK (1000 * 60 * 60 * 24 * 7)
//////////
// Misc. global variables used for logons.
//////////
LSA_HANDLE theLogonProcess; // The handle for the logon process.
ULONG theMSV1_0_Package; // The MSV1_0 authentication package.
ULONG theKerberosPackage; // The Kerberos authentication package.
STRING theOriginName; // The origin of the logon requests.
TOKEN_SOURCE theSourceContext; // The source context of the logon requests.
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASLogonInitialize
//
// DESCRIPTION
//
// Registers the logon process.
//
///////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
IASLogonInitialize( VOID )
{
DWORD status;
BOOLEAN wasEnabled;
LSA_STRING processName, packageName;
LSA_OPERATIONAL_MODE opMode;
//////////
// Enable SE_TCB_PRIVILEGE.
//////////
status = RtlAdjustPrivilege(
SE_TCB_PRIVILEGE,
TRUE,
FALSE,
&wasEnabled
);
if (!NT_SUCCESS(status)) { goto exit; }
//////////
// Register as a logon process.
//////////
RtlInitString(
&processName,
LOGON_PROCESS_NAME
);
status = LsaRegisterLogonProcess(
&processName,
&theLogonProcess,
&opMode
);
if (!NT_SUCCESS(status)) { goto exit; }
//////////
// Lookup the MSV1_0 authentication package.
//////////
RtlInitString(
&packageName,
MSV1_0_PACKAGE_NAME
);
status = LsaLookupAuthenticationPackage(
theLogonProcess,
&packageName,
&theMSV1_0_Package
);
if (!NT_SUCCESS(status)) { goto deregister; }
//////////
// Lookup the Kerberos authentication package.
//////////
RtlInitString(
&packageName,
MICROSOFT_KERBEROS_NAME_A
);
status = LsaLookupAuthenticationPackage(
theLogonProcess,
&packageName,
&theKerberosPackage
);
if (!NT_SUCCESS(status)) { goto deregister; }
//////////
// Initialize the source context.
//////////
memcpy(theSourceContext.SourceName,
TOKEN_SOURCE_NAME,
TOKEN_SOURCE_LENGTH);
status = NtAllocateLocallyUniqueId(
&theSourceContext.SourceIdentifier
);
if (!NT_SUCCESS(status)) { goto deregister; }
return NO_ERROR;
deregister:
LsaDeregisterLogonProcess(theLogonProcess);
theLogonProcess = NULL;
exit:
return RtlNtStatusToDosError(status);
}
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASLogonShutdown
//
// DESCRIPTION
//
// Deregisters the logon process.
//
///////////////////////////////////////////////////////////////////////////////
VOID
WINAPI
IASLogonShutdown( VOID )
{
LsaDeregisterLogonProcess(theLogonProcess);
theLogonProcess = NULL;
}
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASInitAuthInfo
//
// DESCRIPTION
//
// Initializes the fields common to all MSV1_0_LM20* structs.
//
///////////////////////////////////////////////////////////////////////////////
VOID
WINAPI
IASInitAuthInfo(
IN PVOID AuthInfo,
IN DWORD FixedLength,
IN PCWSTR UserName,
IN PCWSTR Domain,
OUT PBYTE* Data
)
{
PMSV1_0_LM20_LOGON logon;
// Zero out the fixed data.
memset(AuthInfo, 0, FixedLength);
// Set Data to point just past the fixed struct.
*Data = FixedLength + (PBYTE)AuthInfo;
// This cast is safe since all LM20 structs have the same initial fields.
logon = (PMSV1_0_LM20_LOGON)AuthInfo;
// We always do Network logons.
logon->MessageType = MsV1_0NetworkLogon;
// Copy in the strings common to all logons.
IASInitUnicodeString(logon->LogonDomainName, *Data, Domain);
IASInitUnicodeString(logon->UserName, *Data, UserName);
IASInitUnicodeString(logon->Workstation, *Data, L"");
}
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASLogonUser
//
// DESCRIPTION
//
// Wrapper around LsaLogonUser.
//
///////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
IASLogonUser(
IN PVOID AuthInfo,
IN ULONG AuthInfoLength,
OUT PMSV1_0_LM20_LOGON_PROFILE *Profile,
OUT PHANDLE Token
)
{
NTSTATUS status, SubStatus;
PMSV1_0_LM20_LOGON_PROFILE ProfileBuffer;
ULONG ProfileBufferLength;
LUID LogonId;
QUOTA_LIMITS Quotas;
// Make sure the OUT arguments are NULL.
*Token = NULL;
ProfileBuffer = NULL;
status = LsaLogonUser(
theLogonProcess,
&theOriginName,
Network,
theMSV1_0_Package,
AuthInfo,
AuthInfoLength,
NULL,
&theSourceContext,
&ProfileBuffer,
&ProfileBufferLength,
&LogonId,
Token,
&Quotas,
&SubStatus
);
if (!NT_SUCCESS(status))
{
// For account restrictions, we can get a more descriptive error
// from the SubStatus.
if (status == STATUS_ACCOUNT_RESTRICTION && !NT_SUCCESS(SubStatus))
{
status = SubStatus;
}
// Sometimes LsaLogonUser returns an invalid handle value on failure.
*Token = NULL;
}
if (Profile)
{
// Return the profile if requested ...
*Profile = ProfileBuffer;
}
else if (ProfileBuffer)
{
// ... otherwise free it.
LsaFreeReturnBuffer(ProfileBuffer);
}
return RtlNtStatusToDosError(status);
}
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASCheckAccountRestrictions
//
// DESCRIPTION
//
// Checks whether an account can be used for logon.
//
///////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
IASCheckAccountRestrictions(
IN PLARGE_INTEGER AccountExpires,
IN PIAS_LOGON_HOURS LogonHours
)
{
LARGE_INTEGER now;
TIME_ZONE_INFORMATION tzi;
SYSTEMTIME st;
DWORD unit;
GetSystemTimeAsFileTime(
(LPFILETIME)&now
);
// An expiration time of zero means 'never'.
if (AccountExpires->QuadPart != 0 &&
AccountExpires->QuadPart < now.QuadPart)
{
return ERROR_ACCOUNT_EXPIRED;
}
// If LogonHours is empty, then we're done.
if (LogonHours->UnitsPerWeek == 0)
{
return NO_ERROR;
}
// The LogonHours array does not account for bias.
switch (GetTimeZoneInformation(&tzi))
{
case TIME_ZONE_ID_UNKNOWN:
case TIME_ZONE_ID_STANDARD:
// Bias is in minutes.
now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.StandardBias;
break;
case TIME_ZONE_ID_DAYLIGHT:
// Bias is in minutes.
now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.DaylightBias;
break;
default:
return ERROR_INVALID_LOGON_HOURS;
}
FileTimeToSystemTime(
(LPFILETIME)&now,
&st
);
// Number of milliseconds into the week.
unit = st.wMilliseconds +
st.wSecond * 1000 +
st.wMinute * 1000 * 60 +
st.wHour * 1000 * 60 * 60 +
st.wDayOfWeek * 1000 * 60 * 60 * 24;
// Convert this to 'units'.
unit /= (MSEC_PER_WEEK / (DWORD)LogonHours->UnitsPerWeek);
// Test the appropriate bit.
if ((LogonHours->LogonHours[unit / 8 ] & (1 << (unit % 8))) == 0)
{
return ERROR_INVALID_LOGON_HOURS;
}
return NO_ERROR;
}
/////////////////////////////////////////////////////////////////////////////// //
// FUNCTION
//
// IASPurgeTicketCache
//
// DESCRIPTION
//
// Purges the Kerberos ticket cache.
//
///////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
IASPurgeTicketCache( VOID )
{
KERB_PURGE_TKT_CACHE_REQUEST request;
NTSTATUS status, subStatus;
PVOID response;
ULONG responseLength;
memset(&request, 0, sizeof(request));
request.MessageType = KerbPurgeTicketCacheMessage;
response = NULL;
responseLength = 0;
subStatus = 0;
status = LsaCallAuthenticationPackage(
theLogonProcess,
theKerberosPackage,
&request,
sizeof(request),
&response,
&responseLength,
&subStatus
);
if (NT_SUCCESS(status))
{
LsaFreeReturnBuffer(response);
}
return RtlNtStatusToDosError(status);
}