windows-nt/Source/XPSP1/NT/ds/security/base/lsa/server/samhooks.cxx

1926 lines
44 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997.
//
// File: samhooks.cxx
//
// Contents: SAM Hooks for security packages
//
// Classes:
//
// Functions:
//
// History: 3-10-97 RichardW Created
//
//----------------------------------------------------------------------------
#include <lsapch.hxx>
#include <lmcons.h>
#include <ntsam.h>
#include <samrpc.h>
#include <samisrv.h>
#include <ntmsv1_0.h>
#include <pac.hxx>
#include "samhooks.hxx"
//+---------------------------------------------------------------------------
//
// Function: LsapMakeDomainRelativeSid
//
// Synopsis: Build a new SID based on a domain SID and a RID
//
// Arguments: [DomainId] --
// [RelativeId] --
//
// History: 3-11-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PSID
LsapMakeDomainRelativeSid(
IN PSID DomainId,
IN ULONG RelativeId
)
{
UCHAR DomainIdSubAuthorityCount;
ULONG Size;
PSID Sid;
if ( !DomainId ) {
return( NULL );
}
//
// Allocate a Sid which has one more sub-authority than the domain ID.
//
DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
if ((Sid = LsapAllocateLsaHeap( Size )) == NULL ) {
return NULL;
}
//
// Initialize the new SID to have the same inital value as the
// domain ID.
//
if ( !NT_SUCCESS( RtlCopySid( Size, Sid, DomainId ) ) ) {
LsapFreeLsaHeap( Sid );
return NULL;
}
//
// Adjust the sub-authority count and
// add the relative Id unique to the newly allocated SID
//
(*(RtlSubAuthorityCountSid( Sid ))) ++;
*RtlSubAuthoritySid( Sid, DomainIdSubAuthorityCount ) = RelativeId;
return Sid;
}
PSID
LsapMakeDomainRelativeSid2(
IN PSID DomainId,
IN ULONG RelativeId
)
{
UCHAR DomainIdSubAuthorityCount;
ULONG Size;
PSID Sid;
if ( !DomainId ) {
return( NULL );
}
//
// Allocate a Sid which has one more sub-authority than the domain ID.
//
DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
if ((Sid = LsapAllocatePrivateHeap( Size )) == NULL ) {
return NULL;
}
//
// Initialize the new SID to have the same inital value as the
// domain ID.
//
if ( !NT_SUCCESS( RtlCopySid( Size, Sid, DomainId ) ) ) {
LsapFreePrivateHeap( Sid );
return NULL;
}
//
// Adjust the sub-authority count and
// add the relative Id unique to the newly allocated SID
//
(*(RtlSubAuthorityCountSid( Sid ))) ++;
*RtlSubAuthoritySid( Sid, DomainIdSubAuthorityCount ) = RelativeId;
return Sid;
}
//+-------------------------------------------------------------------------
//
// Function: LsapDuplicateSid
//
// Synopsis: Duplicates a SID
//
// Effects: allocates memory with LsaFunctions.AllocateLsaHeap
//
// Arguments: DestinationSid - Receives a copy of the SourceSid
// SourceSid - SID to copy
//
// Requires:
//
// Returns: STATUS_SUCCESS - the copy succeeded
// STATUS_INSUFFICIENT_RESOURCES - the call to allocate memory
// failed
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
LsapDuplicateSid(
OUT PSID * DestinationSid,
IN PSID SourceSid
)
{
ULONG SidSize;
DsysAssert(RtlValidSid(SourceSid));
SidSize = RtlLengthSid(SourceSid);
*DestinationSid = (PSID) LsapAllocateLsaHeap( SidSize );
if (*DestinationSid == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlCopyMemory(
*DestinationSid,
SourceSid,
SidSize
);
return(STATUS_SUCCESS);
}
NTSTATUS
LsapDuplicateSid2(
OUT PSID * DestinationSid,
IN PSID SourceSid
)
{
ULONG SidSize;
DsysAssert(RtlValidSid(SourceSid));
SidSize = RtlLengthSid(SourceSid);
*DestinationSid = (PSID) LsapAllocatePrivateHeap( SidSize );
if (*DestinationSid == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlCopyMemory(
*DestinationSid,
SourceSid,
SidSize
);
return(STATUS_SUCCESS);
}
//+---------------------------------------------------------------------------
//
// Function: LsapCaptureSamInfo
//
// Synopsis: Capture current SAM info for building a PAC
//
// Arguments: [DomainSid] -- Returns domain SID
// [DomainName] -- returns domain name
// [MachineName] -- returns current machine name
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
LsapCaptureSamInfo(
PSID * DomainSid,
PUNICODE_STRING DomainName,
PUNICODE_STRING MachineName
)
{
NTSTATUS Status;
PLSAPR_POLICY_INFORMATION PolicyInformation = NULL;
UNICODE_STRING String;
WCHAR LocalMachineName[ CNLEN + 1 ];
DWORD Size ;
PSID Sid ;
Size = CNLEN + 1;
if ( GetComputerName( LocalMachineName, &Size ) )
{
RtlInitUnicodeString( &String, LocalMachineName );
Status = LsapDuplicateString( MachineName, &String );
}
else
{
MachineName->Buffer = (PWSTR) LsapAllocateLsaHeap( Size *
sizeof(WCHAR) + 2 );
if ( MachineName->Buffer )
{
MachineName->MaximumLength = (USHORT) (Size * sizeof(WCHAR) + 2);
GetComputerName( MachineName->Buffer, &Size );
MachineName->Length = (USHORT) (Size * sizeof( WCHAR ) );;
Status = STATUS_SUCCESS ;
}
else
{
Status = STATUS_NO_MEMORY ;
}
}
if ( !NT_SUCCESS( Status ) )
{
DebugLog(( DEB_ERROR, "Failed to get computer name, %x\n", Status ));
goto Cleanup;
}
Status = LsarQueryInformationPolicy(
LsapPolicyHandle,
PolicyAccountDomainInformation,
&PolicyInformation
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to query information policy: 0x%x\n",Status));
goto Cleanup;
}
Status = LsapDuplicateString(
DomainName,
(PUNICODE_STRING) &PolicyInformation->PolicyAccountDomainInfo.DomainName
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Sid = (PSID) LocalAlloc(0, RtlLengthSid(
PolicyInformation->PolicyAccountDomainInfo.DomainSid)
);
if ( Sid == NULL )
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
Sid,
PolicyInformation->PolicyAccountDomainInfo.DomainSid,
RtlLengthSid(PolicyInformation->PolicyAccountDomainInfo.DomainSid)
);
*DomainSid = Sid ;
Cleanup:
if (PolicyInformation != NULL)
{
LsaIFree_LSAPR_POLICY_INFORMATION(
PolicyPrimaryDomainInformation,
PolicyInformation
);
}
return( Status );
}
//+---------------------------------------------------------------------------
//
// Function: LsaOpenSamUser
//
// Synopsis: Opens a handle to the SAM user as specified by Name and NameType
//
// Arguments: [Name] -- Name of user to find
// [NameType] -- SAM or AlternateId
// [Prefix] -- Prefix for AlternateId lookup
// [AllowGuest] -- Open guest if user not found
// [Reserved] --
// [UserHandle] -- Returned user handle
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
NTAPI
LsaOpenSamUser(
PSECURITY_STRING Name,
SECPKG_NAME_TYPE NameType,
PSECURITY_STRING Prefix,
BOOLEAN AllowGuest,
ULONG Reserved,
PVOID * UserHandle
)
{
NTSTATUS Status = STATUS_NOT_IMPLEMENTED ;
SECURITY_STRING CombinedName ;
PSECURITY_STRING EffectiveName ;
SAMPR_ULONG_ARRAY RelativeIdArray;
SAMPR_ULONG_ARRAY UseArray;
UNICODE_STRING TempString;
RelativeIdArray.Element = NULL;
UseArray.Element = NULL;
if ( NameType == SecNameAlternateId )
{
if ( !Prefix )
{
return STATUS_INVALID_PARAMETER ;
}
CombinedName.MaximumLength = Name->Length + Prefix->Length +
2 * sizeof( WCHAR );
CombinedName.Length = CombinedName.MaximumLength - sizeof( WCHAR );
CombinedName.Buffer = (PWSTR) LsapAllocateLsaHeap( CombinedName.MaximumLength );
if ( CombinedName.Buffer )
{
CopyMemory( CombinedName.Buffer, Prefix->Buffer, Prefix->Length );
CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) ] = L':';
CopyMemory( &CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) + 1],
Name->Buffer,
Name->Length + sizeof( WCHAR ) );
EffectiveName = &CombinedName ;
}
else
{
return SEC_E_INSUFFICIENT_MEMORY ;
}
}
else
{
EffectiveName = Name ;
}
if ( NameType == SecNameSamCompatible )
{
Status = SamrLookupNamesInDomain(
LsapAccountDomainHandle,
1,
(PRPC_UNICODE_STRING) Name,
&RelativeIdArray,
&UseArray
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to lookup name %wZ in domain: 0x%x\n",
Name, Status));
goto CheckGuest ;
}
if (UseArray.Element[0] != SidTypeUser)
{
Status = STATUS_NO_SUCH_USER;
goto CheckGuest ;
}
Status = SamrOpenUser(
LsapAccountDomainHandle,
USER_ALL_ACCESS,
RelativeIdArray.Element[0],
UserHandle
);
SamIFree_SAMPR_ULONG_ARRAY( &RelativeIdArray );
SamIFree_SAMPR_ULONG_ARRAY( &UseArray );
RelativeIdArray.Element = NULL;
UseArray.Element = NULL;
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to open user by relative ID: 0x%x\n",Status));
goto CheckGuest ;
}
}
else if ( NameType == SecNameAlternateId )
{
Status = SamIOpenUserByAlternateId(
LsapAccountDomainHandle,
USER_ALL_ACCESS,
EffectiveName,
UserHandle );
if ( !NT_SUCCESS( Status ) )
{
DebugLog(( DEB_TRACE_SAM, "Failed to find user by alternate id, %x\n", Status ));
goto CheckGuest ;
}
}
else
{
Status = STATUS_NOT_IMPLEMENTED ;
AllowGuest = FALSE ;
}
if ( RelativeIdArray.Element )
{
SamIFree_SAMPR_ULONG_ARRAY( &RelativeIdArray );
RelativeIdArray.Element = NULL;
}
if ( UseArray.Element )
{
SamIFree_SAMPR_ULONG_ARRAY( &UseArray );
UseArray.Element = NULL;
}
if ( EffectiveName == &CombinedName )
{
LsapFreeLsaHeap( EffectiveName->Buffer );
}
return Status ;
CheckGuest:
if ( RelativeIdArray.Element )
{
SamIFree_SAMPR_ULONG_ARRAY( &RelativeIdArray );
RelativeIdArray.Element = NULL;
}
if ( UseArray.Element )
{
SamIFree_SAMPR_ULONG_ARRAY( &UseArray );
UseArray.Element = NULL;
}
if ( AllowGuest )
{
Status = SamrOpenUser(
LsapAccountDomainHandle,
USER_ALL_ACCESS,
DOMAIN_USER_RID_GUEST,
UserHandle );
}
if ( EffectiveName == &CombinedName )
{
LsapFreeLsaHeap( EffectiveName->Buffer );
}
return Status ;
}
//+---------------------------------------------------------------------------
//
// Function: LsaCloseSamUser
//
// Synopsis: Close a SAM user opened by LsaOpenSamUser
//
// Arguments: [UserHandle] --
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
NTAPI
LsaCloseSamUser(
PVOID UserHandle
)
{
return SamrCloseHandle( &((SAMPR_HANDLE) UserHandle) );
}
//+---------------------------------------------------------------------------
//
// Function: LsaGetUserCredentials
//
// Synopsis: Pull the creds for the user
//
// Arguments: [UserHandle] --
// [PrimaryCreds] --
// [PrimaryCredsSize] --
// [SupplementalCreds] --
// [SupplementalCredsSize] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
NTAPI
LsaGetUserCredentials(
PVOID UserHandle,
PVOID * PrimaryCreds,
PULONG PrimaryCredsSize,
PVOID * SupplementalCreds,
PULONG SupplementalCredsSize
)
{
return SEC_E_UNSUPPORTED_FUNCTION ;
}
NTSTATUS
NTAPI
LsaGetUserAuthData(
PVOID UserHandle,
PUCHAR * UserAuthData,
PULONG UserAuthDataSize
)
{
PSAMPR_USER_ALL_INFORMATION UserAll = NULL ;
PSAMPR_USER_INFO_BUFFER UserAllInfo = NULL ;
NTSTATUS Status ;
PPACTYPE pNewPac = NULL ;
PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL ;
PPACTYPE Pac ;
UNICODE_STRING Domain ;
UNICODE_STRING Machine ;
PSID Sid ;
Sid = NULL ;
Machine.Buffer = NULL ;
Domain.Buffer = NULL ;
*UserAuthData = NULL ;
Status = SamrQueryInformationUser(
(SAMPR_HANDLE) UserHandle,
UserAllInformation,
&UserAllInfo );
if ( !NT_SUCCESS( Status ) )
{
return( Status );
}
UserAll = &UserAllInfo->All ;
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED )
{
Status = STATUS_ACCOUNT_DISABLED ;
goto GetPac_Cleanup;
}
Status = SamrGetGroupsForUser(
(SAMPR_HANDLE) UserHandle,
&GroupsBuffer );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup ;
}
Status = LsapCaptureSamInfo( &Sid, &Domain, &Machine );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup ;
}
Status = PAC_Init( UserAll,
GroupsBuffer,
NULL, // no extra groups
Sid,
&Domain,
&Machine,
0, // no signature
0, // no additional data
NULL, // no additional data
&Pac );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup ;
}
*UserAuthDataSize = PAC_GetSize( Pac );
*UserAuthData = (PUCHAR) LsapAllocateLsaHeap( *UserAuthDataSize );
if ( *UserAuthData )
{
PAC_Marshal( Pac, *UserAuthDataSize, *UserAuthData );
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY ;
}
MIDL_user_free( Pac );
GetPac_Cleanup:
if ( UserAllInfo )
{
SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfo, UserAllInformation );
}
if ( GroupsBuffer )
{
SamIFree_SAMPR_GET_GROUPS_BUFFER( GroupsBuffer );
}
if ( Sid )
{
LsapFreeLsaHeap( Sid );
}
if ( Domain.Buffer )
{
LsapFreeLsaHeap( Domain.Buffer );
}
if ( Machine.Buffer )
{
LsapFreeLsaHeap( Machine.Buffer );
}
return( Status );
}
//+-------------------------------------------------------------------------
//
// Function: LsapMakeTokenInformationV1
//
// Synopsis: This routine makes copies of all the pertinent
// information from the UserInfo and generates a
// LSA_TOKEN_INFORMATION_V1 data structure.
//
// Effects:
//
// Arguments:
//
// UserInfo - Contains the validation information which is
// to be copied into the TokenInformation.
//
// TokenInformation - Returns a pointer to a properly Version 1 token
// information structures. The structure and individual fields are
// allocated properly as described in ntlsa.h.
//
// Requires:
//
// Returns: STATUS_SUCCESS - Indicates the service completed successfully.
//
// STATUS_INSUFFICIENT_RESOURCES - This error indicates that
// the logon could not be completed because the client
// does not have sufficient quota to allocate the return
// buffer.
//
// Notes: stolen from kerberos\client2\krbtoken.cxx, where it was
// stolen from msv1_0\nlp.c:NlpMakeTokenInformationV1
//
//
//--------------------------------------------------------------------------
NTSTATUS
LsapMakeTokenInformationV1(
IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
OUT PLSA_TOKEN_INFORMATION_V1 *TokenInformation
)
{
NTSTATUS Status;
PLSA_TOKEN_INFORMATION_V1 V1;
ULONG Size, i;
//
// Allocate the structure itself
//
Size = (ULONG)sizeof(LSA_TOKEN_INFORMATION_V1);
V1 = (PLSA_TOKEN_INFORMATION_V1) LsapAllocateLsaHeap( Size );
if ( V1 == NULL ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(
V1,
Size
);
V1->User.User.Sid = NULL;
V1->Groups = NULL;
V1->PrimaryGroup.PrimaryGroup = NULL;
OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime, V1->ExpirationTime );
//
// Make a copy of the user SID (a required field)
//
V1->User.User.Attributes = 0;
//
// Allocate an array to hold the groups
//
Size = ( (ULONG)sizeof(TOKEN_GROUPS)
+ (UserInfo->GroupCount * (ULONG)sizeof(SID_AND_ATTRIBUTES))
- (ANYSIZE_ARRAY * (ULONG)sizeof(SID_AND_ATTRIBUTES))
);
//
// If there are extra SIDs, add space for them
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
Size += UserInfo->SidCount * (ULONG)sizeof(SID_AND_ATTRIBUTES);
}
//
// If there are resource groups, add space for them
//
if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
Size += UserInfo->ResourceGroupCount * (ULONG)sizeof(SID_AND_ATTRIBUTES);
if ((UserInfo->ResourceGroupCount != 0) &&
((UserInfo->ResourceGroupIds == NULL) ||
(UserInfo->ResourceGroupDomainSid == NULL)))
{
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
}
V1->Groups = (PTOKEN_GROUPS) LsapAllocatePrivateHeap( Size );
if ( V1->Groups == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlZeroMemory(
V1->Groups,
Size
);
V1->Groups->GroupCount = 0;
//
// Start copying SIDs into the structure
//
//
// If the UserId is non-zero, then it contians the users RID.
//
if ( UserInfo->UserId ) {
V1->User.User.Sid =
LsapMakeDomainRelativeSid( UserInfo->LogonDomainId,
UserInfo->UserId );
if( V1->User.User.Sid == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
}
//
// Make a copy of the primary group (a required field).
//
V1->PrimaryGroup.PrimaryGroup = LsapMakeDomainRelativeSid(
UserInfo->LogonDomainId,
UserInfo->PrimaryGroupId );
if ( V1->PrimaryGroup.PrimaryGroup == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Copy over all the groups passed as RIDs
//
for ( i=0; i < UserInfo->GroupCount; i++ ) {
V1->Groups->Groups[V1->Groups->GroupCount].Attributes = UserInfo->GroupIds[i].Attributes;
V1->Groups->Groups[V1->Groups->GroupCount].Sid = LsapMakeDomainRelativeSid2(
UserInfo->LogonDomainId,
UserInfo->GroupIds[i].RelativeId );
if( V1->Groups->Groups[V1->Groups->GroupCount].Sid == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
V1->Groups->GroupCount++;
}
//
// Add in the extra SIDs
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
ULONG index = 0;
//
// If the user SID wasn't passed as a RID, it is the first
// SID.
//
if ( !V1->User.User.Sid ) {
if ( UserInfo->SidCount <= index ) {
Status = STATUS_INSUFFICIENT_LOGON_INFO;
goto Cleanup;
}
Status = LsapDuplicateSid(
&V1->User.User.Sid,
UserInfo->ExtraSids[index].Sid
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
index++;
}
//
// Copy over all additional SIDs as groups.
//
for ( ; index < UserInfo->SidCount; index++ ) {
V1->Groups->Groups[V1->Groups->GroupCount].Attributes =
UserInfo->ExtraSids[index].Attributes;
Status = LsapDuplicateSid2(
&V1->Groups->Groups[V1->Groups->GroupCount].Sid,
UserInfo->ExtraSids[index].Sid
);
if (!NT_SUCCESS(Status) ) {
goto Cleanup;
}
V1->Groups->GroupCount++;
}
}
//
// Check to see if any resouce groups exist
//
if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
for ( i=0; i < UserInfo->ResourceGroupCount; i++ ) {
V1->Groups->Groups[V1->Groups->GroupCount].Attributes = UserInfo->ResourceGroupIds[i].Attributes;
V1->Groups->Groups[V1->Groups->GroupCount].Sid = LsapMakeDomainRelativeSid2(
UserInfo->ResourceGroupDomainSid,
UserInfo->ResourceGroupIds[i].RelativeId );
if( V1->Groups->Groups[V1->Groups->GroupCount].Sid == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
V1->Groups->GroupCount++;
}
}
if (!V1->User.User.Sid) {
Status = STATUS_INSUFFICIENT_LOGON_INFO;
goto Cleanup;
}
//
// There are no default privileges supplied.
// We don't have an explicit owner SID.
// There is no default DACL.
//
V1->Privileges = NULL;
V1->Owner.Owner = NULL;
V1->DefaultDacl.DefaultDacl = NULL;
//
// Return the Validation Information to the caller.
//
*TokenInformation = V1;
return STATUS_SUCCESS;
//
// Deallocate any memory we've allocated
//
Cleanup:
if ( V1->User.User.Sid != NULL ) {
LsapFreeLsaHeap( V1->User.User.Sid );
}
if ( V1->Groups != NULL ) {
LsapFreeTokenGroups( V1->Groups );
}
if ( V1->PrimaryGroup.PrimaryGroup != NULL ) {
LsapFreeLsaHeap( V1->PrimaryGroup.PrimaryGroup );
}
LsapFreeLsaHeap( V1 );
return Status;
}
//+---------------------------------------------------------------------------
//
// Function: LsaFreeTokenInfo
//
// Synopsis: Frees a TokenInformation structure that was allocated by
// the LSA
//
// Arguments: [TokenInfoType] --
// [TokenInformation] --
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
NTAPI
LsaFreeTokenInfo(
LSA_TOKEN_INFORMATION_TYPE TokenInfoType,
PVOID TokenInformation
)
{
switch (TokenInfoType) {
case LsaTokenInformationNull:
LsapFreeTokenInformationNull( (PLSA_TOKEN_INFORMATION_NULL) TokenInformation );
break;
case LsaTokenInformationV1:
LsapFreeTokenInformationV1( (PLSA_TOKEN_INFORMATION_V1) TokenInformation );
break;
case LsaTokenInformationV2:
LsapFreeTokenInformationV2( (PLSA_TOKEN_INFORMATION_V2) TokenInformation );
break;
}
return STATUS_SUCCESS ;
}
//+---------------------------------------------------------------------------
//
// Function: LsaConvertAuthDataToToken
//
// Synopsis: Convert an opaque PAC structure into a token.
//
// Arguments: [UserAuthData] --
// [UserAuthDataSize] --
// [TokenInformation] --
// [TokenInformationType] --
//
// History: 3-14-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
NTAPI
LsaConvertAuthDataToToken(
IN PVOID UserAuthData,
IN ULONG UserAuthDataSize,
IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
IN PTOKEN_SOURCE TokenSource,
IN SECURITY_LOGON_TYPE LogonType,
IN PUNICODE_STRING AuthorityName,
OUT PHANDLE TokenHandle,
OUT PLUID LogonId,
OUT PUNICODE_STRING AccountName,
OUT PNTSTATUS SubStatus
)
{
NTSTATUS Status ;
PPACTYPE Pac = NULL ;
PPAC_INFO_BUFFER LogonInfo = NULL ;
PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL ;
PLSA_TOKEN_INFORMATION_V1 TokenInfo = NULL ;
LogonId->HighPart = LogonId->LowPart = 0;
*TokenHandle = NULL;
RtlInitUnicodeString(
AccountName,
NULL
);
*SubStatus = STATUS_SUCCESS;
Pac = (PPACTYPE) UserAuthData ;
if ( PAC_UnMarshal( Pac, UserAuthDataSize ) == 0 )
{
DebugLog(( DEB_ERROR, "Failed to unmarshall pac\n" ));
Status = STATUS_INVALID_PARAMETER ;
goto CreateToken_Cleanup ;
}
LogonInfo = PAC_Find( Pac, PAC_LOGON_INFO, NULL );
if ( !LogonInfo )
{
DebugLog(( DEB_ERROR, "Failed to find logon info in pac\n" ));
Status = STATUS_INVALID_PARAMETER ;
goto CreateToken_Cleanup ;
}
Status = PAC_UnmarshallValidationInfo(
&ValidationInfo,
LogonInfo->Data,
LogonInfo->cbBufferSize
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to unmarshall validation info: 0x%x\n",
Status));
goto CreateToken_Cleanup;
}
//
// Now we need to build a LSA_TOKEN_INFORMATION_V1 from the validation
// information
//
Status = LsapMakeTokenInformationV1(
ValidationInfo,
&TokenInfo
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to make token informatin v1: 0x%x\n",
Status));
goto CreateToken_Cleanup;
}
//
// Now, copy the user name.
//
Status = LsapDuplicateString( AccountName, &ValidationInfo->EffectiveName );
if ( !NT_SUCCESS( Status ) )
{
goto CreateToken_Cleanup ;
}
//
// Now create a logon session
//
Status = LsapCreateLogonSession( LogonId );
if (!NT_SUCCESS(Status))
{
goto CreateToken_Cleanup;
}
//
// Now create the token
//
Status = LsapCreateToken(
LogonId,
TokenSource,
LogonType,
ImpersonationLevel,
LsaTokenInformationV1,
TokenInfo,
NULL, // no token groups
AccountName,
AuthorityName,
NULL,
&ValidationInfo->ProfilePath,
TokenHandle,
SubStatus
);
//
// NULL out the TokenInfo pointer. LsapCreateToken will
// free the memory under all conditions
//
TokenInfo = NULL ;
if (!NT_SUCCESS(Status))
{
goto CreateToken_Cleanup;
}
//
// We don't need to free the token information because CreateToken does
// that for us.
//
MIDL_user_free(ValidationInfo);
return Status ;
CreateToken_Cleanup:
if ( TokenInfo )
{
LsaFreeTokenInfo( LsaTokenInformationV1, TokenInfo );
}
if ((LogonId->LowPart != 0) || (LogonId->HighPart != 0))
{
LsapDeleteLogonSession(LogonId);
}
LsapFreeString(
AccountName
);
if (ValidationInfo != NULL)
{
MIDL_user_free(ValidationInfo);
}
return Status ;
}
//+---------------------------------------------------------------------------
//
// Function: LsaGetAuthDataForUser
//
// Synopsis: Helper function - retrieves all auth data for a user
// based on Name, NameType, and prefix
//
// Arguments: [Name] -- Name to search for
// [NameType] -- Type of name supplied
// [Prefix] -- String prefix for name
// [UserAuthData] --
// [UserAuthDataSize] --
//
// History: 6-08-98 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
LsaGetAuthDataForUser(
PSECURITY_STRING Name,
SECPKG_NAME_TYPE NameType,
PSECURITY_STRING Prefix OPTIONAL,
PUCHAR * UserAuthData,
PULONG UserAuthDataSize,
PUNICODE_STRING UserFlatName OPTIONAL
)
{
NTSTATUS Status ;
ULONG SamFlags ;
PUNICODE_STRING AccountName ;
UNICODE_STRING CombinedName = { 0 };
SID_AND_ATTRIBUTES_LIST ReverseMembership ;
PSAMPR_USER_ALL_INFORMATION UserAll = NULL ;
PSAMPR_USER_INFO_BUFFER UserAllInfo = NULL ;
PPACTYPE pNewPac = NULL ;
PPACTYPE Pac ;
UNICODE_STRING Domain ;
UNICODE_STRING Machine ;
PSID Sid ;
Sid = NULL ;
Machine.Buffer = NULL ;
Domain.Buffer = NULL ;
ReverseMembership.Count = 0 ;
*UserAuthData = NULL ;
if ( UserFlatName )
{
ZeroMemory( UserFlatName, sizeof( UNICODE_STRING ) );
}
SamFlags = 0 ;
switch ( NameType )
{
case SecNameSamCompatible:
AccountName = Name ;
break;
case SecNameAlternateId:
SamFlags |= SAM_OPEN_BY_ALTERNATE_ID ;
if ( !Prefix )
{
return STATUS_INVALID_PARAMETER ;
}
CombinedName.MaximumLength = Name->Length + Prefix->Length +
2 * sizeof( WCHAR );
CombinedName.Length = CombinedName.MaximumLength - sizeof( WCHAR );
CombinedName.Buffer = (PWSTR) LsapAllocateLsaHeap( CombinedName.MaximumLength );
if ( CombinedName.Buffer )
{
CopyMemory( CombinedName.Buffer, Prefix->Buffer, Prefix->Length );
CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) ] = L':';
CopyMemory( &CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) + 1],
Name->Buffer,
Name->Length + sizeof( WCHAR ) );
AccountName = &CombinedName ;
}
else
{
return SEC_E_INSUFFICIENT_MEMORY ;
}
break;
case SecNameFlat:
SamFlags |= SAM_OPEN_BY_UPN ;
AccountName = Name ;
break;
default:
return STATUS_INVALID_PARAMETER ;
}
Status = SamIGetUserLogonInformation(
LsapAccountDomainHandle,
SamFlags,
AccountName,
&UserAllInfo,
&ReverseMembership,
NULL );
//
// Free the combined name (if appropriate)
//
if ( CombinedName.Buffer )
{
LsapFreeLsaHeap( CombinedName.Buffer );
}
if ( !NT_SUCCESS( Status ) )
{
return( Status );
}
UserAll = &UserAllInfo->All ;
if ( UserFlatName )
{
Status = LsapDuplicateString(
UserFlatName,
(PUNICODE_STRING) &UserAll->UserName );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup;
}
}
if ( UserAll->UserAccountControl & USER_ACCOUNT_DISABLED )
{
Status = STATUS_ACCOUNT_DISABLED ;
goto GetPac_Cleanup;
}
if ( UserAll->UserAccountControl & USER_ACCOUNT_AUTO_LOCKED )
{
Status = STATUS_ACCOUNT_LOCKED_OUT ;
goto GetPac_Cleanup ;
}
Status = LsapCaptureSamInfo( &Sid, &Domain, &Machine );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup ;
}
Status = PAC_Init( UserAll,
NULL,
&ReverseMembership, // no extra groups
Sid,
&Domain,
&Machine,
0, // no signature
0, // no additional data
NULL, // no additional data
&Pac );
if ( !NT_SUCCESS( Status ) )
{
goto GetPac_Cleanup ;
}
*UserAuthDataSize = PAC_GetSize( Pac );
*UserAuthData = (PUCHAR) LsapAllocateLsaHeap( *UserAuthDataSize );
if ( *UserAuthData )
{
PAC_Marshal( Pac, *UserAuthDataSize, *UserAuthData );
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY ;
}
MIDL_user_free( Pac );
GetPac_Cleanup:
if ( UserAllInfo )
{
SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfo, UserAllInformation );
}
if ( ReverseMembership.Count )
{
SamIFreeSidAndAttributesList( &ReverseMembership );
}
if ( Sid )
{
LsapFreeLsaHeap( Sid );
}
if ( Domain.Buffer )
{
LsapFreeLsaHeap( Domain.Buffer );
}
if ( Machine.Buffer )
{
LsapFreeLsaHeap( Machine.Buffer );
}
return( Status );
}
NTSTATUS
NTAPI
LsaCrackSingleName(
ULONG FormatOffered,
BOOLEAN PerformAtGC,
PUNICODE_STRING NameInput,
PUNICODE_STRING Prefix OPTIONAL,
ULONG RequestedFormat,
PUNICODE_STRING CrackedName,
PUNICODE_STRING DnsDomainName,
PULONG SubStatus
)
{
NTSTATUS Status = STATUS_SUCCESS ;
UNICODE_STRING DnsDomain ;
UNICODE_STRING Name ;
DWORD Ret ;
DWORD DnsDomainLength ;
DWORD NameLength ;
UNICODE_STRING CombinedName = { 0 };
PUNICODE_STRING AccountName ;
if ( !SampUsingDsData() )
{
return SEC_E_UNSUPPORTED_FUNCTION ;
}
//
// Cruft up the call to the DS
//
Name.Buffer = (PWSTR) LsapAllocateLsaHeap( MAX_PATH * sizeof(WCHAR) * 2 );
DnsDomain.Buffer = (PWSTR) LsapAllocateLsaHeap( MAX_PATH * sizeof(WCHAR) );
if ( Name.Buffer && DnsDomain.Buffer )
{
Name.MaximumLength = MAX_PATH * sizeof(WCHAR) * 2 ;
Name.Length = 0 ;
DnsDomain.MaximumLength = MAX_PATH * sizeof(WCHAR) ;
DnsDomain.Length = 0 ;
NameLength = MAX_PATH * 2 ;
DnsDomainLength = MAX_PATH ;
Name.Buffer[ 0 ] = L'\0';
DnsDomain.Buffer[ 0 ] = L'\0';
if ( Prefix )
{
CombinedName.MaximumLength = NameInput->Length + Prefix->Length +
2 * sizeof( WCHAR );
CombinedName.Length = CombinedName.MaximumLength - sizeof( WCHAR );
CombinedName.Buffer = (PWSTR) LsapAllocatePrivateHeap( CombinedName.MaximumLength );
if ( CombinedName.Buffer )
{
CopyMemory( CombinedName.Buffer, Prefix->Buffer, Prefix->Length );
CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) ] = L':';
CopyMemory( &CombinedName.Buffer[ Prefix->Length / sizeof( WCHAR ) + 1],
NameInput->Buffer,
NameInput->Length + sizeof( WCHAR ) );
AccountName = &CombinedName ;
}
else
{
AccountName = NULL ;
}
}
else
{
AccountName = NameInput ;
}
if ( AccountName )
{
__try
{
Ret = CrackSingleName(
FormatOffered,
PerformAtGC ?
DS_NAME_FLAG_GCVERIFY : 0,
AccountName->Buffer,
RequestedFormat,
&DnsDomainLength,
DnsDomain.Buffer,
&NameLength,
Name.Buffer,
SubStatus );
if ( Ret != 0 )
{
Status = STATUS_UNSUCCESSFUL ;
}
else
{
Status = STATUS_SUCCESS ;
RtlInitUnicodeString( &DnsDomain, DnsDomain.Buffer );
RtlInitUnicodeString( &Name, Name.Buffer );
*CrackedName = Name ;
*DnsDomainName = DnsDomain ;
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
Status = STATUS_UNSUCCESSFUL ;
}
if ( CombinedName.Buffer )
{
LsapFreePrivateHeap( CombinedName.Buffer );
}
}
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY ;
}
if ( !NT_SUCCESS( Status ) )
{
if ( Name.Buffer )
{
LsapFreeLsaHeap( Name.Buffer );
}
if ( DnsDomain.Buffer )
{
LsapFreeLsaHeap( DnsDomain.Buffer );
}
}
return Status ;
}
NTSTATUS
LsapBuildPacSidList(
IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
OUT PSAMPR_PSID_ARRAY Sids
)
{
ULONG Size = 0, i;
NTSTATUS Status = STATUS_SUCCESS ;
Sids->Count = 0;
Sids->Sids = NULL;
if (UserInfo->UserId != 0)
{
Size += sizeof( SAMPR_SID_INFORMATION );
}
Size += UserInfo->GroupCount * (ULONG)sizeof( SAMPR_SID_INFORMATION );
//
// If there are extra SIDs, add space for them
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS)
{
Size += UserInfo->SidCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
}
Sids->Sids = (PSAMPR_SID_INFORMATION) MIDL_user_allocate( Size );
if ( Sids->Sids == NULL )
{
Status = STATUS_NO_MEMORY ;
goto Cleanup;
}
RtlZeroMemory(
Sids->Sids,
Size
);
//
// Start copying SIDs into the structure
//
i = 0;
//
// If the UserId is non-zero, then it contians the users RID.
//
if ( UserInfo->UserId )
{
Sids->Sids[0].SidPointer = (PRPC_SID)
LsapMakeDomainRelativeSid( UserInfo->LogonDomainId,
UserInfo->UserId );
if( Sids->Sids[0].SidPointer == NULL )
{
Status = STATUS_NO_MEMORY ;
goto Cleanup;
}
Sids->Count++;
}
//
// Copy over all the groups passed as RIDs
//
for ( i=0; i < UserInfo->GroupCount; i++ )
{
Sids->Sids[Sids->Count].SidPointer = (PRPC_SID)
LsapMakeDomainRelativeSid(
UserInfo->LogonDomainId,
UserInfo->GroupIds[i].RelativeId );
if( Sids->Sids[Sids->Count].SidPointer == NULL )
{
Status = STATUS_NO_MEMORY ;
goto Cleanup;
}
Sids->Count++;
}
//
// Add in the extra SIDs
//
//
// No need to allocate these, but...
//
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS)
{
for ( i = 0; i < UserInfo->SidCount; i++ )
{
Status = LsapDuplicateSid(
(PSID *) &Sids->Sids[Sids->Count].SidPointer,
UserInfo->ExtraSids[i].Sid );
if ( !NT_SUCCESS( Status ) )
{
goto Cleanup ;
}
Sids->Count++;
}
}
//
// Deallocate any memory we've allocated
//
Cleanup:
if (!NT_SUCCESS( Status ))
{
if (Sids->Sids != NULL)
{
for (i = 0; i < Sids->Count ;i++ )
{
if (Sids->Sids[i].SidPointer != NULL)
{
MIDL_user_free(Sids->Sids[i].SidPointer);
}
}
MIDL_user_free(Sids->Sids);
Sids->Sids = NULL;
Sids->Count = 0;
}
}
return Status ;
}
NTSTATUS
NTAPI
LsaExpandAuthDataForDomain(
IN PUCHAR UserAuthData,
IN ULONG UserAuthDataSize,
IN PVOID Reserved,
OUT PUCHAR * ExpandedAuthData,
OUT PULONG ExpandedAuthDataSize
)
{
NTSTATUS Status = STATUS_SUCCESS ;
PPACTYPE Pac = NULL ;
PPAC_INFO_BUFFER LogonInfo = NULL ;
PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL ;
PLSA_TOKEN_INFORMATION_V1 TokenInfo = NULL ;
SAMPR_PSID_ARRAY SidList = {0};
PSAMPR_PSID_ARRAY ResourceGroups = NULL;
PPACTYPE NewPac = NULL ;
ULONG Index ;
Pac = (PPACTYPE) UserAuthData ;
if ( PAC_UnMarshal( Pac, UserAuthDataSize ) == 0 )
{
DebugLog(( DEB_ERROR, "Failed to unmarshall pac\n" ));
Status = STATUS_INVALID_PARAMETER ;
goto Expand_Cleanup ;
}
LogonInfo = PAC_Find( Pac, PAC_LOGON_INFO, NULL );
if ( !LogonInfo )
{
DebugLog(( DEB_ERROR, "Failed to find logon info in pac\n" ));
Status = STATUS_INVALID_PARAMETER ;
goto Expand_Cleanup ;
}
Status = PAC_UnmarshallValidationInfo(
&ValidationInfo,
LogonInfo->Data,
LogonInfo->cbBufferSize
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to unmarshall validation info: 0x%x\n",
Status));
goto Expand_Cleanup;
}
Status = LsapBuildPacSidList(
ValidationInfo,
&SidList );
if ( !NT_SUCCESS( Status ) )
{
goto Expand_Cleanup ;
}
//
// Call SAM to get the sids
//
Status = SamIGetResourceGroupMembershipsTransitive(
LsapAccountDomainHandle,
&SidList,
0, // no flags
&ResourceGroups
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to get resource groups: 0x%x\n",Status));
goto Expand_Cleanup;
}
//
// Now build a new pac
//
Status = PAC_InitAndUpdateGroups(
ValidationInfo,
ResourceGroups,
Pac,
&NewPac
);
if ( !NT_SUCCESS( Status ) )
{
goto Expand_Cleanup ;
}
*ExpandedAuthDataSize = PAC_GetSize( NewPac );
*ExpandedAuthData = (PUCHAR) LsapAllocateLsaHeap( *ExpandedAuthDataSize );
if ( *ExpandedAuthData )
{
PAC_Marshal( NewPac, *ExpandedAuthDataSize, *ExpandedAuthData );
}
else
{
Status = STATUS_NO_MEMORY ;
}
MIDL_user_free( NewPac );
Expand_Cleanup:
if ( ValidationInfo )
{
MIDL_user_free( ValidationInfo );
}
if (SidList.Sids != NULL)
{
for (Index = 0; Index < SidList.Count ;Index++ )
{
if (SidList.Sids[Index].SidPointer != NULL)
{
MIDL_user_free(SidList.Sids[Index].SidPointer);
}
}
MIDL_user_free(SidList.Sids);
}
SamIFreeSidArray(
ResourceGroups
);
return Status ;
}