Example #1
0
static
NTSTATUS
MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
                   IN PVOID ProtocolSubmitBuffer,
                   IN PVOID ClientBufferBase,
                   IN ULONG SubmitBufferLength,
                   OUT PVOID *ProtocolReturnBuffer,
                   OUT PULONG ReturnBufferLength,
                   OUT PNTSTATUS ProtocolStatus)
{
    PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
    ULONG_PTR PtrOffset;

    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_HANDLE UserHandle = NULL;
    PRPC_SID DomainSid = NULL;
    RPC_UNICODE_STRING Names[1];
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    NTSTATUS Status;

    ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
    ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
    ENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
    ENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
    OEM_STRING LmPwdString;
    CHAR LmPwdBuffer[15];
    BOOLEAN OldLmPasswordPresent = FALSE;
    BOOLEAN NewLmPasswordPresent = FALSE;

    ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm;
    ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm;
    ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt;
    ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt;
    PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL;
    PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL;

    TRACE("()\n");

    RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;

    /* Fix-up pointers in the request buffer info */
    PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;

    RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
    RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
    RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
    RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);

    TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
    TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
    TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
    TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);

    /* Connect to the SAM server */
    Status = SamIConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
                         TRUE);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Get the domain SID */
    Status = SamrLookupDomainInSamServer(ServerHandle,
                                         (PRPC_UNICODE_STRING)&RequestBuffer->DomainName,
                                         &DomainSid);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status);
        goto done;
    }

    /* Open the domain */
    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            DomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    Names[0].Length = RequestBuffer->AccountName.Length;
    Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
    Names[0].Buffer = RequestBuffer->AccountName.Buffer;

    /* Try to get the RID for the user name */
    Status = SamrLookupNamesInDomain(DomainHandle,
                                     1,
                                     Names,
                                     &RelativeIds,
                                     &Use);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
        Status = STATUS_NO_SUCH_USER;
        goto done;
    }

    /* Fail, if it is not a user account */
    if (Use.Element[0] != SidTypeUser)
    {
        TRACE("Account is not a user account!\n");
        Status = STATUS_NO_SUCH_USER;
        goto done;
    }

    /* Open the user object */
    Status = SamrOpenUser(DomainHandle,
                          USER_CHANGE_PASSWORD,
                          RelativeIds.Element[0],
                          &UserHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
        goto done;
    }


    /* Calculate the NT hash for the old password */
    Status = SystemFunction007(&RequestBuffer->OldPassword,
                               (LPBYTE)&OldNtPassword);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Calculate the NT hash for the new password */
    Status = SystemFunction007(&RequestBuffer->NewPassword,
                               (LPBYTE)&NewNtPassword);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Calculate the LM password and hash for the old password */
    LmPwdString.Length = 15;
    LmPwdString.MaximumLength = 15;
    LmPwdString.Buffer = LmPwdBuffer;
    ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);

    Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
                                               &RequestBuffer->OldPassword,
                                               FALSE);
    if (NT_SUCCESS(Status))
    {
        /* Calculate the LM hash value of the password */
        Status = SystemFunction006(LmPwdString.Buffer,
                                   (LPSTR)&OldLmPassword);
        if (NT_SUCCESS(Status))
        {
            OldLmPasswordPresent = TRUE;
        }
    }

    /* Calculate the LM password and hash for the new password */
    LmPwdString.Length = 15;
    LmPwdString.MaximumLength = 15;
    LmPwdString.Buffer = LmPwdBuffer;
    ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);

    Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
                                               &RequestBuffer->NewPassword,
                                               FALSE);
    if (NT_SUCCESS(Status))
    {
        /* Calculate the LM hash value of the password */
        Status = SystemFunction006(LmPwdString.Buffer,
                                   (LPSTR)&NewLmPassword);
        if (NT_SUCCESS(Status))
        {
            NewLmPasswordPresent = TRUE;
        }
    }

    /* Encrypt the old and new LM passwords, if they exist */
    if (OldLmPasswordPresent && NewLmPasswordPresent)
    {
        /* Encrypt the old LM password */
        Status = SystemFunction012((const BYTE *)&OldLmPassword,
                                   (const BYTE *)&NewLmPassword,
                                   (LPBYTE)&OldLmEncryptedWithNewLm);
        if (!NT_SUCCESS(Status))
        {
            TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
            goto done;
        }

        /* Encrypt the new LM password */
        Status = SystemFunction012((const BYTE *)&NewLmPassword,
                                   (const BYTE *)&OldLmPassword,
                                   (LPBYTE)&NewLmEncryptedWithOldLm);
        if (!NT_SUCCESS(Status))
        {
            TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
            goto done;
        }

        pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm;
        pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm;
    }

    /* Encrypt the old NT password */
    Status = SystemFunction012((const BYTE *)&OldNtPassword,
                               (const BYTE *)&NewNtPassword,
                               (LPBYTE)&OldNtEncryptedWithNewNt);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Encrypt the new NT password */
    Status = SystemFunction012((const BYTE *)&NewNtPassword,
                               (const BYTE *)&OldNtPassword,
                               (LPBYTE)&NewNtEncryptedWithOldNt);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Change the password */
    Status = SamrChangePasswordUser(UserHandle,
                                    OldLmPasswordPresent && NewLmPasswordPresent,
                                    pOldLmEncryptedWithNewLm,
                                    pNewLmEncryptedWithOldLm,
                                    TRUE,
                                    &OldNtEncryptedWithNewNt,
                                    &NewNtEncryptedWithOldNt,
                                    FALSE,
                                    NULL,
                                    FALSE,
                                    NULL);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status);
        goto done;
    }

done:
    if (UserHandle != NULL)
        SamrCloseHandle(&UserHandle);

    SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
    SamIFree_SAMPR_ULONG_ARRAY(&Use);

    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (DomainSid != NULL)
        SamIFreeVoid(DomainSid);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}
Example #2
0
/*
 * @unimplemented
 */
NTSTATUS
NTAPI
LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
               IN SECURITY_LOGON_TYPE LogonType,
               IN PVOID AuthenticationInformation,
               IN PVOID ClientAuthenticationBase,
               IN ULONG AuthenticationInformationLength,
               OUT PVOID *ProfileBuffer,
               OUT PULONG ProfileBufferLength,
               OUT PLUID LogonId,
               OUT PNTSTATUS SubStatus,
               OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
               OUT PVOID *TokenInformation,
               OUT PLSA_UNICODE_STRING *AccountName,
               OUT PLSA_UNICODE_STRING *AuthenticatingAuthority)
{
    PMSV1_0_INTERACTIVE_LOGON LogonInfo;

    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_HANDLE UserHandle = NULL;
    PRPC_SID AccountDomainSid = NULL;
    RPC_UNICODE_STRING Names[1];
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
    UNICODE_STRING LogonServer;
    BOOLEAN SessionCreated = FALSE;
    LARGE_INTEGER LogonTime;
//    LARGE_INTEGER AccountExpires;
    LARGE_INTEGER PasswordMustChange;
    LARGE_INTEGER PasswordLastSet;
    BOOL SpecialAccount = FALSE;
    NTSTATUS Status;

    TRACE("LsaApLogonUser()\n");

    TRACE("LogonType: %lu\n", LogonType);
    TRACE("AuthenticationInformation: %p\n", AuthenticationInformation);
    TRACE("AuthenticationInformationLength: %lu\n", AuthenticationInformationLength);

    *ProfileBuffer = NULL;
    *ProfileBufferLength = 0;
    *SubStatus = STATUS_SUCCESS;

    if (LogonType == Interactive ||
        LogonType == Batch ||
        LogonType == Service)
    {
        ULONG_PTR PtrOffset;

        LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthenticationInformation;

        /* Fix-up pointers in the authentication info */
        PtrOffset = (ULONG_PTR)AuthenticationInformation - (ULONG_PTR)ClientAuthenticationBase;

        LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
        LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
        LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);

        TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
        TRACE("User: %S\n", LogonInfo->UserName.Buffer);
        TRACE("Password: %S\n", LogonInfo->Password.Buffer);

        RtlInitUnicodeString(&LogonServer, L"Testserver");
    }
    else
    {
        FIXME("LogonType %lu is not supported yet!\n", LogonType);
        return STATUS_NOT_IMPLEMENTED;
    }

    /* Get the logon time */
    NtQuerySystemTime(&LogonTime);

    /* Check for special accounts */
    if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0)
    {
        SpecialAccount = TRUE;

        /* Get the authority domain SID */
        Status = GetNtAuthorityDomainSid(&AccountDomainSid);
        if (!NT_SUCCESS(Status))
        {
            ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n", Status);
            return Status;
        }

        if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0)
        {
            TRACE("SpecialAccount: LocalService\n");

            if (LogonType != Service)
                return STATUS_LOGON_FAILURE;

            UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
                                       HEAP_ZERO_MEMORY,
                                       sizeof(SAMPR_USER_ALL_INFORMATION));
            if (UserInfo == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
            UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
        }
        else if (_wcsicmp(LogonInfo->UserName.Buffer, L"NetworkService") == 0)
        {
            TRACE("SpecialAccount: NetworkService\n");

            if (LogonType != Service)
                return STATUS_LOGON_FAILURE;

            UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
                                       HEAP_ZERO_MEMORY,
                                       sizeof(SAMPR_USER_ALL_INFORMATION));
            if (UserInfo == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID;
            UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID;
        }
        else
        {
            Status = STATUS_NO_SUCH_USER;
            goto done;
        }
    }
    else
    {
        TRACE("NormalAccount\n");

        /* Get the account domain SID */
        Status = GetAccountDomainSid(&AccountDomainSid);
        if (!NT_SUCCESS(Status))
        {
            ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status);
            return Status;
        }

        /* Connect to the SAM server */
        Status = SamIConnect(NULL,
                             &ServerHandle,
                             SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
                             TRUE);
        if (!NT_SUCCESS(Status))
        {
            TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
            goto done;
        }

        /* Open the account domain */
        Status = SamrOpenDomain(ServerHandle,
                                DOMAIN_LOOKUP,
                                AccountDomainSid,
                                &DomainHandle);
        if (!NT_SUCCESS(Status))
        {
            ERR("SamrOpenDomain failed (Status %08lx)\n", Status);
            goto done;
        }

        Names[0].Length = LogonInfo->UserName.Length;
        Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
        Names[0].Buffer = LogonInfo->UserName.Buffer;

        /* Try to get the RID for the user name */
        Status = SamrLookupNamesInDomain(DomainHandle,
                                         1,
                                         Names,
                                         &RelativeIds,
                                         &Use);
        if (!NT_SUCCESS(Status))
        {
            ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
            Status = STATUS_NO_SUCH_USER;
            goto done;
        }

        /* Fail, if it is not a user account */
        if (Use.Element[0] != SidTypeUser)
        {
            ERR("Account is not a user account!\n");
            Status = STATUS_NO_SUCH_USER;
            goto done;
        }

        /* Open the user object */
        Status = SamrOpenUser(DomainHandle,
                              USER_READ_GENERAL | USER_READ_LOGON |
                              USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
                              RelativeIds.Element[0],
                              &UserHandle);
        if (!NT_SUCCESS(Status))
        {
            ERR("SamrOpenUser failed (Status %08lx)\n", Status);
            goto done;
        }

        Status = SamrQueryInformationUser(UserHandle,
                                          UserAllInformation,
                                          &UserInfo);
        if (!NT_SUCCESS(Status))
        {
            ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status);
            goto done;
        }

        TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);

        /* Check the password */
        if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
        {
            Status = MsvpCheckPassword(&(LogonInfo->Password),
                                       UserInfo);
            if (!NT_SUCCESS(Status))
            {
                ERR("MsvpCheckPassword failed (Status %08lx)\n", Status);
                goto done;
            }
        }

        /* Check account restrictions for non-administrator accounts */
        if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
        {
            /* Check if the account has been disabled */
            if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
            {
                ERR("Account disabled!\n");
                *SubStatus = STATUS_ACCOUNT_DISABLED;
                Status = STATUS_ACCOUNT_RESTRICTION;
                goto done;
            }

            /* Check if the account has been locked */
            if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
            {
                ERR("Account locked!\n");
                *SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
                Status = STATUS_ACCOUNT_RESTRICTION;
                goto done;
            }

#if 0
            /* Check if the account expired */
            AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
            AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;

            if (AccountExpires.QuadPart != 0 &&
                LogonTime.QuadPart >= AccountExpires.QuadPart)
            {
                ERR("Account expired!\n");
                *SubStatus = STATUS_ACCOUNT_EXPIRED;
                Status = STATUS_ACCOUNT_RESTRICTION;
                goto done;
            }
#endif

            /* Check if the password expired */
            PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
            PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
            PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
            PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;

            if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
            {
                ERR("Password expired!\n");
                if (PasswordLastSet.QuadPart == 0)
                    *SubStatus = STATUS_PASSWORD_MUST_CHANGE;
                else
                    *SubStatus = STATUS_PASSWORD_EXPIRED;

                Status = STATUS_ACCOUNT_RESTRICTION;
                goto done;
            }

            /* FIXME: more checks */
            // STATUS_INVALID_LOGON_HOURS;
            // STATUS_INVALID_WORKSTATION;
        }
    }

    /* Return logon information */

    /* Create and return a new logon id */
    Status = NtAllocateLocallyUniqueId(LogonId);
    if (!NT_SUCCESS(Status))
    {
        TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status);
        goto done;
    }

    /* Create the logon session */
    Status = DispatchTable.CreateLogonSession(LogonId);
    if (!NT_SUCCESS(Status))
    {
        TRACE("CreateLogonSession failed (Status %08lx)\n", Status);
        goto done;
    }

    SessionCreated = TRUE;

    /* Build and fill the interactive profile buffer */
    Status = BuildInteractiveProfileBuffer(ClientRequest,
                                           UserInfo,
                                           &LogonServer,
                                           (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
                                           ProfileBufferLength);
    if (!NT_SUCCESS(Status))
    {
        TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status);
        goto done;
    }

    /* Return the token information type */
    *TokenInformationType = LsaTokenInformationV1;

    /* Build and fill the token information buffer */
    Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
                                         AccountDomainSid,
                                         UserInfo,
                                         SpecialAccount);
    if (!NT_SUCCESS(Status))
    {
        TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
        goto done;
    }

done:
    /* Return the account name */
    *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
    if (*AccountName != NULL)
    {
        (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length +
                                                               sizeof(UNICODE_NULL));
        if ((*AccountName)->Buffer != NULL)
        {
            (*AccountName)->MaximumLength = LogonInfo->UserName.Length +
                                            sizeof(UNICODE_NULL);
            RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName);
        }
    }

    if (!NT_SUCCESS(Status))
    {
        if (SessionCreated != FALSE)
            DispatchTable.DeleteLogonSession(LogonId);

        if (*ProfileBuffer != NULL)
        {
            DispatchTable.FreeClientBuffer(ClientRequest,
                                           *ProfileBuffer);
            *ProfileBuffer = NULL;
        }
    }

    if (UserHandle != NULL)
        SamrCloseHandle(&UserHandle);

    SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo,
                                    UserAllInformation);
    SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
    SamIFree_SAMPR_ULONG_ARRAY(&Use);

    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    if (AccountDomainSid != NULL)
        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);

    if (Status == STATUS_NO_SUCH_USER ||
        Status == STATUS_WRONG_PASSWORD)
    {
        *SubStatus = Status;
        Status = STATUS_LOGON_FAILURE;
    }

    TRACE("LsaApLogonUser done (Status 0x%08lx  SubStatus 0x%08lx)\n", Status, *SubStatus);

    return Status;
}
Example #3
0
BOOLEAN
NlProcessQueueEntry(
    PWORKER_QUEUE_ENTRY Entry
    )
/*++

Routine Description:

    This procedure processes an entry that has come from the worker
    queue.

Arguments:

    WorkerQueueEntry : pointer to worker structure.

Return Value:

    TRUE : if we need to continue processing more entries.
    FALSE : if we need to terminate the worker.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Rid = Entry->Rid;
    BOOLEAN ReturnValue = TRUE;
    SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    SAMPR_HANDLE GroupHandle = NULL;
    PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
    SAMPR_HANDLE UserHandle = NULL;

    PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
    PGLOBAL_GROUP_ENTRY GroupEntry;

    DWORD i;


    //
    // The membership of a special local group is being changed,
    //  force each lanman BDC to re-sync with each user that's being
    //  added-to/removed-from the local group.
    //
    switch ( Entry->EntryType ) {
    case ChangeLogAliasMembership :

        //
        // determine Rid Type.
        //

        Status = SamrLookupIdsInDomain(
                    NlGlobalChWorkerSamDBHandle,
                    1,
                    &Rid,
                    &Names,
                    &Use );

        if ( !NT_SUCCESS(Status) ) {
            Names.Element = NULL;
            Use.Element = NULL;
            goto Cleanup;
        }

        NlAssert( Names.Count == 1 );
        NlAssert( Names.Element != NULL );
        NlAssert( Use.Count == 1 );
        NlAssert( Use.Element != NULL );

        if( Use.Element[0] == SidTypeUser ) {

            NlSimulateUserDelta( Rid );

            //
            // if this users is added unknowingly to the global group
            // list, remove it now.
            //

            LOCK_CHANGELOG();

            GroupEntry = NlGetGroupEntry (
                             &NlGlobalSpecialServerGroupList,
                             Rid );

            if( GroupEntry != NULL ) {

                RemoveEntryList( &GroupEntry->Next );
                NetpMemoryFree( GroupEntry );
            }

            UNLOCK_CHANGELOG();


        } else if( Use.Element[0] == SidTypeGroup ) {

            DWORD i;

            //
            // simulate deltas for all members in this group.
            //

            Status = SamrOpenGroup( NlGlobalChWorkerSamDBHandle,
                                    0,              // No desired access
                                    Rid,
                                    &GroupHandle );

            if (!NT_SUCCESS(Status)) {
                GroupHandle = NULL;
                goto Cleanup;
            }

            Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer );

            if (!NT_SUCCESS(Status)) {
                MembersBuffer = NULL;
                goto Cleanup;
            }

            for( i = 0; i < MembersBuffer->MemberCount; i++) {

                NlSimulateUserDelta( MembersBuffer->Members[i] );
            }

#if DBG
            //
            // Ensure the change log thread already added this group
            //

            LOCK_CHANGELOG();

            GroupEntry = NlGetGroupEntry (
                             &NlGlobalSpecialServerGroupList,
                             Rid );

            UNLOCK_CHANGELOG();

            NlAssert( GroupEntry != NULL );
#endif // DBG

        } else {

            //
            // ignore any other changes
            //

            NlAssert( FALSE );
        }

        break;

    //
    // The group membership of the special group has changed.
    //  Force Lanman BDCs to re-sync the user being added-to/removed-from
    //  the domain.
    //
    case ChangeLogGroupMembership :

        //
        // determine Rid Type.
        //

        Status = SamrLookupIdsInDomain(
                    NlGlobalChWorkerSamDBHandle,
                    1,
                    &Rid,
                    &Names,
                    &Use );

        if ( !NT_SUCCESS(Status) ) {
            Names.Element = NULL;
            Use.Element = NULL;
            goto Cleanup;
        }

        NlAssert( Names.Count == 1 );
        NlAssert( Names.Element != NULL );
        NlAssert( Use.Count == 1 );
        NlAssert( Use.Element != NULL );

        NlAssert( Use.Element[0] == SidTypeUser );


        if( Use.Element[0] == SidTypeUser ) {

            NlSimulateUserDelta( Rid );
        }

        break;


    //
    // A member was deleted from the SERVERS group.
    //  Check to see if this thread can terminate.
    //
    case ServersGroupDel :

        //
        // if the server group is empty then terminate worker thread.
        //

        if ( NlGlobalLmBdcCount == 0 ) {
            ReturnValue = FALSE;
        }

        break;


    //
    // Rename user is handled as multiple deltas:
    //  1) Delete old user and
    //  2) Add new user.
    //  3) Update membership of each group the user is a member of
    //
    case ChangeLogRenameUser :

        //
        // simulate a user change so that an user account with
        // new name will be created on the down level system.
        //

        NlSimulateUserDelta( Rid );

        //
        // create deltas to make his group membership correct on the
        // down level machine.
        //

        Status = SamrOpenUser( NlGlobalChWorkerSamDBHandle,
                               0,              // No desired access
                               Rid,
                               &UserHandle );

        if (!NT_SUCCESS(Status)) {
            UserHandle = NULL;
            goto Cleanup;
        }

        Status = SamrGetGroupsForUser( UserHandle, &GroupsBuffer );

        if (!NT_SUCCESS(Status)) {
            GroupsBuffer = NULL;
            goto Cleanup;
        }

        for( i = 0; i < GroupsBuffer->MembershipCount; i++) {

            Status = SamINotifyDelta(
                        NlGlobalChWorkerSamDBHandle,
                        SecurityDbChangeMemberAdd,
                        SecurityDbObjectSamGroup,
                        GroupsBuffer->Groups[i].RelativeId,
                        NULL,
                        FALSE,
                        NULL );

            if (!NT_SUCCESS(Status)) {
                goto Cleanup;
            }
        }

        break;

    //
    // A newly added user needs to have it's membership in "Domain Users" updated, too.
    //
    // Here we simply supply a corresponding change user membership delta which
    // ends up as a AddOrChangeUser delta with the CHANGELOG_DOMAINUSERS_CHANGED
    // flag set. NetrAccountDeltas interprets that flag to mean
    // "send the membership of this user".
    //
    case ChangeLogAddUser:

        Status = SamINotifyDelta(
                    NlGlobalChWorkerSamDBHandle,
                    SecurityDbChangeMemberAdd,
                    SecurityDbObjectSamUser,
                    Rid,
                    NULL,
                    FALSE,
                    NULL );

        if (!NT_SUCCESS(Status)) {
            goto Cleanup;
        }
        break;


    //
    // Rename group is handled as three deltas:
    //  1) Delete old group,
    //  2) Add new group and
    //  3) Changemembership of new group.
    //
    case ChangeLogRenameGroup :

        //
        // simulate a group change so that a group account with
        // new name will be created on the down level system. Also
        // simulate a changemembership delta so that the members are
        // added to the new group appropriately.
        //

        Status = SamINotifyDelta(
                    NlGlobalChWorkerSamDBHandle,
                    SecurityDbChange,
                    SecurityDbObjectSamGroup,
                    Rid,
                    NULL,
                    FALSE,
                    NULL );

        if ( NT_SUCCESS(Status) ) {

            Status = SamINotifyDelta(
                        NlGlobalChWorkerSamDBHandle,
                        SecurityDbChangeMemberAdd,
                        SecurityDbObjectSamGroup,
                        Rid,
                        NULL,
                        FALSE,
                        NULL );
        }

        if ( !NT_SUCCESS(Status) ) {

            NlPrint((NL_CRITICAL, "SamINotifyDelta failed %lx\n", Status ) );
        }

        break;

    default:

        NlPrint((NL_CRITICAL,
                "NlProcessQueueEntry found unknown queue entry : %lx\n",
                Entry->EntryType ));
        break;

    }

Cleanup:

    if( Names.Element != NULL ) {
        SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names );
    }

    if( Use.Element != NULL ) {
        SamIFree_SAMPR_ULONG_ARRAY( &Use );
    }

    if ( MembersBuffer != NULL ) {
        SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer );
    }

    if( GroupHandle != NULL ) {
        (VOID) SamrCloseHandle( &GroupHandle );
    }

    if ( GroupsBuffer != NULL ) {
        SamIFree_SAMPR_GET_GROUPS_BUFFER( GroupsBuffer );
    }

    if( UserHandle != NULL ) {
        (VOID) SamrCloseHandle( &UserHandle );
    }

    if ( !NT_SUCCESS(Status) ) {

        NlPrint((NL_CRITICAL,
                "NlProcessQueueEntry failed : %lx\n",
                Status ));

    }

    return ReturnValue;

}
Example #4
0
BOOL
NlIsServersGroupEmpty(
    ULONG ServersGroupRid
    )
/*++

Routine Description:

    This procedure determines whether the Servers group is empty or not.

Arguments:

    Rid : Rid of the SERVERS group. If it is zero then determine the RID
            by lookup.

Return Value:

    FALSE : If the servers group exist and it is non-empty.
    TRUE : otherwise

--*/
{
    NTSTATUS Status;

    SAMPR_ULONG_ARRAY RelativeIdArray = {0, NULL};
    SAMPR_ULONG_ARRAY UseArray = {0, NULL};
    RPC_UNICODE_STRING GroupNameString;
    SAMPR_HANDLE GroupHandle = NULL;
    BOOL ReturnValue = TRUE;

    PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;

    if ( ServersGroupRid == 0 ) {

        //
        // Convert the group name to a RelativeId.
        //

        RtlInitUnicodeString( (PUNICODE_STRING)&GroupNameString,
                                SSI_SERVER_GROUP_W );

        Status = SamrLookupNamesInDomain(
                    NlGlobalChWorkerSamDBHandle,
                    1,
                    &GroupNameString,
                    &RelativeIdArray,
                    &UseArray );

        if ( !NT_SUCCESS(Status) ) {

            RelativeIdArray.Element = NULL;
            UseArray.Element = NULL;
            goto Cleanup;
        }

        //
        // we should get back exactly one entry of info back.
        //

        NlAssert( UseArray.Count == 1 );
        NlAssert( UseArray.Element != NULL );
        NlAssert( RelativeIdArray.Count == 1 );
        NlAssert( RelativeIdArray.Element != NULL );

        if ( UseArray.Element[0] != SidTypeGroup ) {
            goto Cleanup;
        }

        ServersGroupRid = RelativeIdArray.Element[0];
    }

    //
    // Open the SERVERS group
    //

    Status = SamrOpenGroup( NlGlobalChWorkerSamDBHandle,
                            0, // No desired access
                            ServersGroupRid,
                            &GroupHandle );

    if ( !NT_SUCCESS(Status) ) {
        GroupHandle = NULL;
        goto Cleanup;
    }

    //
    // enumerate members in the group.
    //

    Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer );

    if (!NT_SUCCESS(Status)) {
        MembersBuffer = NULL;
        goto Cleanup;
    }

    if ( MembersBuffer->MemberCount != 0 ) {

        //
        // atleast a member in there.
        //

        ReturnValue = FALSE;

        //
        // Save the list of LmBdcs

        NlLmBdcListSet( MembersBuffer->MemberCount,
                        MembersBuffer->Members );
    }

Cleanup:

    SamIFree_SAMPR_ULONG_ARRAY( &RelativeIdArray );
    SamIFree_SAMPR_ULONG_ARRAY( &UseArray );

    if ( MembersBuffer != NULL ) {
        SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer );
    }

    if( GroupHandle != NULL ) {
        (VOID) SamrCloseHandle( &GroupHandle );
    }

    return ReturnValue;
}
Example #5
0
NTSTATUS
NlAddGlobalGroupsToList(
    PLIST_ENTRY GroupList,
    ULONG LocalGroupID
    )
/*++

Routine Description:

    This procedure adds the global groups that are member of the given
    alias.

Arguments:

    GroupList : List to munch.

    LocalGroupId : Rid of the local group.

Return Value:

    Return NT Status code.

--*/
{
    NTSTATUS Status;
    SAMPR_HANDLE AliasHandle = NULL;

    SAMPR_PSID_ARRAY Members = {0, NULL};
    PULONG RidArray = NULL;
    DWORD RidArrayLength = 0;
    SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    DWORD i;

    //
    // Open Local Group
    //

    Status = SamrOpenAlias(
                NlGlobalChWorkerBuiltinDBHandle,
                0,              // No desired access
                LocalGroupID,
                &AliasHandle );

    if (!NT_SUCCESS(Status)) {
        AliasHandle = NULL;
        goto Cleanup;
    }

    //
    // Enumerate members in this local group.
    //

    Status = SamrGetMembersInAlias(
                AliasHandle,
                &Members );

    if (!NT_SUCCESS(Status)) {
        Members.Sids = NULL;
        goto Cleanup;
    }

    //
    // Determine the SIDs that belong to the Account Domain and get the
    // RIDs of them.
    //

    if( Members.Count == 0) {

        Status = STATUS_SUCCESS;
        goto Cleanup;
    }

    //
    // Allocate the maximum size RID array required.
    //

    RidArray = (PULONG)NetpMemoryAllocate( Members.Count * sizeof(ULONG) );

    if( RidArray == NULL ) {
        Status = STATUS_NO_MEMORY;
        goto Cleanup;
    }

    for( i = 0; i < Members.Count; i++) {

        PUCHAR SubAuthorityCount;
        BOOLEAN EqualSid;

        SubAuthorityCount =
            RtlSubAuthorityCountSid(Members.Sids[i].SidPointer);

        (*SubAuthorityCount)--;
        EqualSid = RtlEqualSid( NlGlobalChWorkerSamDomainSid,
                                    Members.Sids[i].SidPointer );
        (*SubAuthorityCount)++;

        if( EqualSid ) {

            RidArray[RidArrayLength] =
                *RtlSubAuthoritySid( Members.Sids[i].SidPointer,
                                        (*SubAuthorityCount) -1 );
            RidArrayLength++;
        }
    }

    if( RidArrayLength == 0) {

        Status = STATUS_SUCCESS;
        goto Cleanup;
    }

    //
    // Get Group RIDs and add them to list.
    //

    Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle,
                                        RidArrayLength,
                                        RidArray,
                                        &Names,
                                        &Use );

    if ( !NT_SUCCESS(Status) ) {

        Names.Element = NULL;
        Use.Element = NULL;

        if( Status == STATUS_NONE_MAPPED ) {

            //
            // if no SID is mapped, we can't do much here.
            //

            NlPrint((NL_CRITICAL,
                "NlAddGlobalGroupsToList could not map any SID from "
                "local group, RID = %lx \n", LocalGroupID ));

            Status = STATUS_SUCCESS;
        }

        goto Cleanup;
    }

    NlAssert( Names.Count == RidArrayLength );
    NlAssert( Names.Element != NULL );
    NlAssert( Use.Count == RidArrayLength );
    NlAssert( Use.Element != NULL );

    //
    // Find groups and add them to list.
    //

    for( i = 0; i < RidArrayLength; i++ ) {

        if( Use.Element[i] == SidTypeGroup ) {

            //
            // we found a group, add it to the list if it is not there
            // already.
            //

            if( NlGetGroupEntry( GroupList, RidArray[i] ) != NULL ) {

                //
                // entry already in the list.
                //

                continue;
            }

            //
            // add an entry to the list.
            //

            Status = NlAddGroupEntry( GroupList, RidArray[i] );

            if ( !NT_SUCCESS(Status) ) {
                goto Cleanup;
            }
        }
    }

Cleanup:

    if( Names.Element != NULL ) {
        SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names );
    }

    if( Use.Element != NULL ) {
        SamIFree_SAMPR_ULONG_ARRAY( &Use );
    }

    if( RidArray != NULL ) {
        NetpMemoryFree( RidArray );
    }

    if ( Members.Sids != NULL ) {
        SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members );
    }

    if( AliasHandle != NULL ) {
        SamrCloseHandle( &AliasHandle );
    }

    if ( !NT_SUCCESS(Status) ) {

        NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList failed %lx\n",
                    Status ));
    }

    return( Status );
}
Example #6
0
/*
 * @unimplemented
 */
NTSTATUS
NTAPI
LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
               IN SECURITY_LOGON_TYPE LogonType,
               IN PVOID AuthenticationInformation,
               IN PVOID ClientAuthenticationBase,
               IN ULONG AuthenticationInformationLength,
               OUT PVOID *ProfileBuffer,
               OUT PULONG ProfileBufferLength,
               OUT PLUID LogonId,
               OUT PNTSTATUS SubStatus,
               OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
               OUT PVOID *TokenInformation,
               OUT PLSA_UNICODE_STRING *AccountName,
               OUT PLSA_UNICODE_STRING *AuthenticatingAuthority)
{
    PMSV1_0_INTERACTIVE_LOGON LogonInfo;

    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_HANDLE UserHandle = NULL;
    PRPC_SID AccountDomainSid = NULL;
    RPC_UNICODE_STRING Names[1];
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
    UNICODE_STRING LogonServer;
    NTSTATUS Status;

    TRACE("()\n");

    TRACE("LogonType: %lu\n", LogonType);
    TRACE("AuthenticationInformation: %p\n", AuthenticationInformation);
    TRACE("AuthenticationInformationLength: %lu\n", AuthenticationInformationLength);


    *ProfileBuffer = NULL;
    *ProfileBufferLength = 0;
    *SubStatus = STATUS_SUCCESS;

    if (LogonType == Interactive ||
        LogonType == Batch ||
        LogonType == Service)
    {
        ULONG_PTR PtrOffset;

        LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthenticationInformation;

        /* Fix-up pointers in the authentication info */
        PtrOffset = (ULONG_PTR)AuthenticationInformation - (ULONG_PTR)ClientAuthenticationBase;

        LogonInfo->LogonDomainName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->LogonDomainName.Buffer + PtrOffset);
        LogonInfo->UserName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->UserName.Buffer + PtrOffset);
        LogonInfo->Password.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->Password.Buffer + PtrOffset);

        TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
        TRACE("User: %S\n", LogonInfo->UserName.Buffer);
        TRACE("Password: %S\n", LogonInfo->Password.Buffer);

        RtlInitUnicodeString(&LogonServer, L"Testserver");
    }
    else
    {
        FIXME("LogonType %lu is not supported yet!\n", LogonType);
        return STATUS_NOT_IMPLEMENTED;
    }

    Status = GetDomainSid(&AccountDomainSid);
    if (!NT_SUCCESS(Status))
    {
        TRACE("GetDomainSid() failed (Status 0x%08lx)\n", Status);
        return Status;
    }

    /* Connect to the SAM server */
    Status = SamIConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
                         TRUE);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Open the account domain */
    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            AccountDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    Names[0].Length = LogonInfo->UserName.Length;
    Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
    Names[0].Buffer = LogonInfo->UserName.Buffer;

    /* Try to get the RID for the user name */
    Status = SamrLookupNamesInDomain(DomainHandle,
                                     1,
                                     Names,
                                     &RelativeIds,
                                     &Use);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
        Status = STATUS_NO_SUCH_USER;
        goto done;
    }

    /* Fail, if it is not a user account */
    if (Use.Element[0] != SidTypeUser)
    {
        TRACE("Account is not a user account!\n");
        Status = STATUS_NO_SUCH_USER;
        goto done;
    }

    /* Open the user object */
    Status = SamrOpenUser(DomainHandle,
                          USER_READ_GENERAL | USER_READ_LOGON |
                          USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
                          RelativeIds.Element[0],
                          &UserHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrQueryInformationUser(UserHandle,
                                      UserAllInformation,
                                      &UserInfo);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrQueryInformationUser failed (Status %08lx)\n", Status);
        goto done;
    }


    TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);

    /* FIXME: Check restrictions */

    /* FIXME: Check the password */
    if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
    {
        FIXME("Must check the password!\n");

    }

    /* Return logon information */

    /* Create and return a new logon id */
    Status = NtAllocateLocallyUniqueId(LogonId);
    if (!NT_SUCCESS(Status))
    {
        TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status);
        goto done;
    }

    /* Build and fill the interactve profile buffer */
    Status = BuildInteractiveProfileBuffer(ClientRequest,
                                           UserInfo,
                                           &LogonServer,
                                           (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
                                           ProfileBufferLength);
    if (!NT_SUCCESS(Status))
    {
        TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status);
        goto done;
    }

    /* Return the token information type */
    *TokenInformationType = LsaTokenInformationV1;

    /* Build and fill the token information buffer */
    Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
                                         AccountDomainSid,
                                         RelativeIds.Element[0],
                                         LogonId);
    if (!NT_SUCCESS(Status))
    {
        TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
        goto done;
    }

    *SubStatus = STATUS_SUCCESS;

done:
    /* Return the account name */
    *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
    if (*AccountName != NULL)
    {
        (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length +
                                                               sizeof(UNICODE_NULL));
        if ((*AccountName)->Buffer != NULL)
        {
            (*AccountName)->MaximumLength = LogonInfo->UserName.Length +
                                            sizeof(UNICODE_NULL);
            RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName);
        }
    }

    if (!NT_SUCCESS(Status))
    {
        if (*ProfileBuffer != NULL)
        {
            DispatchTable.FreeClientBuffer(ClientRequest,
                                           *ProfileBuffer);
            *ProfileBuffer = NULL;
        }
    }

    if (UserHandle != NULL)
        SamrCloseHandle(&UserHandle);

    SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo,
                                    UserAllInformation);
    SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
    SamIFree_SAMPR_ULONG_ARRAY(&Use);

    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    if (AccountDomainSid != NULL)
        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);

    TRACE("LsaApLogonUser done (Status %08lx)\n", Status);

    return Status;
}