//+--------------------------------------------------------------------------- // // 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 #include #include #include #include #include #include #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( IN PSID * DomainSid, OUT PUNICODE_STRING DomainName, OUT 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); if ( GetComputerName( MachineName->Buffer, &Size )) { MachineName->Length = (USHORT) (Size * sizeof( WCHAR ) );; Status = STATUS_SUCCESS ; } else { ASSERT( FALSE ); // how's this possible? Status = STATUS_INTERNAL_ERROR; } } 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 ); CombinedName.Buffer[CombinedName.Length / sizeof( WCHAR )] = L'\0'; 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) ); } 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, OPTIONAL PSECURITY_STRING Prefix, PUCHAR * UserAuthData, PULONG UserAuthDataSize, OPTIONAL PUNICODE_STRING UserFlatName ) { 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 ); CombinedName.Buffer[CombinedName.Length / sizeof( WCHAR )] = L'\0'; AccountName = &CombinedName ; } else { return SEC_E_INSUFFICIENT_MEMORY ; } break; case SecNameFlat: SamFlags |= SAM_OPEN_BY_UPN ; AccountName = Name ; break; case SecNameSPN: SamFlags |= SAM_OPEN_BY_SPN ; 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, OPTIONAL PUNICODE_STRING Prefix, 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 ); CombinedName.Buffer[CombinedName.Length / sizeof( WCHAR )] = L'\0'; 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 ; }