⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msvpaswd.c

📁 安全支持提供器接口(SSPI)源码
💻 C
📖 第 1 页 / 共 5 页
字号:


NTSTATUS
MspLm20ChangePassword (
    IN PLSA_CLIENT_REQUEST ClientRequest,
    IN PVOID ProtocolSubmitBuffer,
    IN PVOID ClientBufferBase,
    IN ULONG SubmitBufferSize,
    OUT PVOID *ProtocolReturnBuffer,
    OUT PULONG ReturnBufferSize,
    OUT PNTSTATUS ProtocolStatus
    )

/*++

Routine Description:

    This routine is the dispatch routine for LsaCallAuthenticationPackage()
    with a message type of MsV1_0ChangePassword.  This routine changes an
    account's password by either calling SamXxxPassword (for NT domains) or
    RxNetUserPasswordSet (for downlevel domains and standalone servers).

Arguments:

    The arguments to this routine are identical to those of LsaApCallPackage.
    Only the special attributes of these parameters as they apply to
    this routine are mentioned here.

Return Value:

    STATUS_SUCCESS - Indicates the service completed successfully.

    STATUS_PASSWORD_RESTRICTION - The password change failed because the
        - password doesn't meet one or more domain restrictions.  The
        - response buffer is allocated.  If the PasswordInfoValid flag is
        - set it contains valid information otherwise it contains no
        - information because this was a down-level change.

    STATUS_BACKUP_CONTROLLER - The named machine is a Backup Domain Controller.
        Changing password is only allowed on the Primary Domain Controller.

--*/

{
    PMSV1_0_CHANGEPASSWORD_REQUEST ChangePasswordRequest = NULL;
    PMSV1_0_CHANGEPASSWORD_RESPONSE ChangePasswordResponse;
    NTSTATUS        Status = STATUS_SUCCESS;
    NTSTATUS        SavedStatus = STATUS_SUCCESS;
    LPWSTR          DomainName = NULL;
    PDOMAIN_CONTROLLER_INFO DCInfo = NULL;
    UNICODE_STRING  DCNameString;
    UNICODE_STRING  ClientNetbiosDomain = {0};
    PUNICODE_STRING  ClientDsGetDcDomain;
    UNICODE_STRING  ClientDnsDomain = {0};
    UNICODE_STRING  ClientName = {0};
    UNICODE_STRING  ValidatedAccountName;
    UNICODE_STRING  ValidatedDomainName;
    LPWSTR          ValidatedOldPasswordBuffer;
    LPWSTR          ValidatedNewPasswordBuffer;
    NET_API_STATUS  NetStatus;
    PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo = NULL;
    PDOMAIN_PASSWORD_INFORMATION DomainPasswordInfo = NULL;
    PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
    PWKSTA_INFO_100 WkstaInfo100 = NULL;
    BOOLEAN PasswordBufferValidated = FALSE;
    CLIENT_BUFFER_DESC ClientBufferDesc;
    PSECURITY_SEED_AND_LENGTH SeedAndLength;
    PDS_NAME_RESULTW NameResult = NULL;
    HANDLE DsHandle = NULL;
    UCHAR           Seed;
    BOOLEAN         Authoritative = TRUE;

    BOOLEAN         AttemptRediscovery = FALSE;

    RtlInitUnicodeString(
        &DCNameString,
        NULL
        );
    //
    // Sanity checks.
    //

    NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );

    if ( SubmitBufferSize < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) ) {
        Status = STATUS_INVALID_PARAMETER;
        goto Cleanup;
    }

    ChangePasswordRequest = (PMSV1_0_CHANGEPASSWORD_REQUEST) ProtocolSubmitBuffer;

    ASSERT( ChangePasswordRequest->MessageType == MsV1_0ChangePassword ||
            ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword );

    RELOCATE_ONE( &ChangePasswordRequest->DomainName );

    RELOCATE_ONE( &ChangePasswordRequest->AccountName );

    if ( ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword ) {
        NULL_RELOCATE_ONE( &ChangePasswordRequest->OldPassword );
    } else {
        RELOCATE_ONE_ENCODED( &ChangePasswordRequest->OldPassword );
    }

    RELOCATE_ONE_ENCODED( &ChangePasswordRequest->NewPassword );

    //
    // save away copies of validated buffers to check later.
    //

    RtlCopyMemory( &ValidatedDomainName, &ChangePasswordRequest->DomainName, sizeof(ValidatedDomainName) );
    RtlCopyMemory( &ValidatedAccountName, &ChangePasswordRequest->AccountName, sizeof(ValidatedAccountName) );

    ValidatedOldPasswordBuffer = ChangePasswordRequest->OldPassword.Buffer;
    ValidatedNewPasswordBuffer = ChangePasswordRequest->NewPassword.Buffer;


    SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->OldPassword.Length;
    Seed = SeedAndLength->Seed;
    SeedAndLength->Seed = 0;

    if (Seed != 0) {

        try {
            RtlRunDecodeUnicodeString(
                Seed,
                &ChangePasswordRequest->OldPassword
                );

        } except (EXCEPTION_EXECUTE_HANDLER) {
            Status = STATUS_ILL_FORMED_PASSWORD;
            goto Cleanup;
        }
    }

    SeedAndLength = (PSECURITY_SEED_AND_LENGTH) &ChangePasswordRequest->NewPassword.Length;
    Seed = SeedAndLength->Seed;
    SeedAndLength->Seed = 0;

    if (Seed != 0) {

        if( ChangePasswordRequest->NewPassword.Buffer !=
            ValidatedNewPasswordBuffer ) {

            Status = STATUS_INVALID_PARAMETER;
            goto Cleanup;
        }

        try {
            RtlRunDecodeUnicodeString(
                Seed,
                &ChangePasswordRequest->NewPassword
                );

        } except (EXCEPTION_EXECUTE_HANDLER) {
            Status = STATUS_ILL_FORMED_PASSWORD;
            goto Cleanup;
        }
    }

    //
    // sanity check that we didn't whack over buffers.
    //

    if( !RtlCompareMemory(
                        &ValidatedDomainName,
                        &ChangePasswordRequest->DomainName,
                        sizeof(ValidatedDomainName)
                        )
                        ||
        !RtlCompareMemory(
                        &ValidatedAccountName,
                        &ChangePasswordRequest->AccountName,
                        sizeof(ValidatedAccountName)
                        )
                        ||
        (ValidatedOldPasswordBuffer != ChangePasswordRequest->OldPassword.Buffer)
                        ||
        (ValidatedNewPasswordBuffer != ChangePasswordRequest->NewPassword.Buffer)
                        ) {

            Status= STATUS_INVALID_PARAMETER;
            goto Cleanup;
    }


    *ReturnBufferSize = 0;
    *ProtocolReturnBuffer = NULL;
    *ProtocolStatus = STATUS_PENDING;
    PasswordBufferValidated = TRUE;

    MsvPaswdLogPrint(("Attempting password change server/domain %wZ for user %wZ\n",
        &ChangePasswordRequest->DomainName,
        &ChangePasswordRequest->AccountName
        ));

#ifdef COMPILED_BY_DEVELOPER

    KdPrint(("MSV1_0:\n"
             "\tDomain:\t%wZ\n"
             "\tAccount:\t%wZ\n"
             "\tOldPassword(%d)\n"
             "\tNewPassword(%d)\n",
             &ChangePasswordRequest->DomainName,
             &ChangePasswordRequest->AccountName,
             (int) ChangePasswordRequest->OldPassword.Length,
             (int) ChangePasswordRequest->NewPassword.Length
             ));

#endif // COMPILED_BY_DEVELOPER


    //
    // If we're just changing the cached password,
    //  skip changing the password on the domain.
    //

    if ( ChangePasswordRequest->MessageType == MsV1_0ChangeCachedPassword ) {
        ClientName = ChangePasswordRequest->AccountName;
        ClientNetbiosDomain = ChangePasswordRequest->DomainName;
        Status = STATUS_SUCCESS;
        goto PasswordChangeSuccessfull;
    }


    //
    // If the client supplied a non-nt4 name, go ahead and convert it here.
    //

    if (ChangePasswordRequest->DomainName.Length == 0) {
        DWORD DsStatus;
        WCHAR NameBuffer[UNLEN+1];
        LPWSTR NameString = NameBuffer;
        ULONG Index;
        BOOLEAN fWorkstation = FALSE;

        //
        // BUGBUG: is this too limited?
        //

        if (ChangePasswordRequest->AccountName.Length / sizeof(WCHAR) > UNLEN) {
            Status = STATUS_INVALID_PARAMETER;
            goto Cleanup;
        }

        RtlCopyMemory(
            NameBuffer,
            ChangePasswordRequest->AccountName.Buffer,
            ChangePasswordRequest->AccountName.Length
            );
        NameBuffer[ChangePasswordRequest->AccountName.Length/sizeof(WCHAR)] = L'\0';


        DsStatus = DsBindW(
                        NULL,
                        NULL,
                        &DsHandle
                        );

        //
        // we allow the bind to fail on a member workstation, which allows
        // us to attempt a 'manual' crack.
        //

        if (DsStatus != ERROR_SUCCESS) {

            fWorkstation = NlpWorkstation;

            if( !fWorkstation ) {
                SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsBindW returned 0x%lx.\n",
                        DsStatus ));
                Status = NetpApiStatusToNtStatus( DsStatus );
                goto Cleanup;
            }
        }

        if( !fWorkstation ) {
            DsStatus = DsCrackNamesW(
                        DsHandle,
                        0,                          // no flags
                        DS_UNKNOWN_NAME,
                        DS_NT4_ACCOUNT_NAME,
                        1,
                        &NameString,
                        &NameResult
                        );

            if (DsStatus != ERROR_SUCCESS) {
                SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsCrackNamesW returned 0x%lx.\n",
                            DsStatus ));
                Status = NetpApiStatusToNtStatus( DsStatus );
                goto Cleanup;
            }

            //
            // Look for the name in the result
            //

            if (NameResult->cItems < 1) {
                SspPrint(( SSP_CRITICAL, "MspLm20ChangePassword: DsCrackNamesW returned zero items.\n"));
                Status = STATUS_INTERNAL_ERROR;
                goto Cleanup;
            }

        }

        //
        // Check if the crack succeeded
        //

        if ( (fWorkstation) ||
             (NameResult->rItems[0].status != DS_NAME_NO_ERROR)
             ) {

            //
            // The name wasn't mapped. Try converting it manually by
            // splitting it at the '@'
            //

            RtlInitUnicodeString(
                &ClientName,
                NameBuffer
                );

            // shortest possible is 3 Unicode chars (eg: a@a)
            if (ClientName.Length < (sizeof(WCHAR) * 3)) {
                Status = STATUS_NO_SUCH_USER;
                goto Cleanup;
            }

            for (Index = (ClientName.Length / sizeof(WCHAR)) - 1; Index != 0 ; Index-- ) {
                if (ClientName.Buffer[Index] == L'@') {

                    RtlInitUnicodeString(
                        &ClientDnsDomain,
                        &ClientName.Buffer[Index+1]
                        );

                    ClientName.Buffer[Index] = L'\0';
                    ClientName.Length = (USHORT) Index * sizeof(WCHAR);


                    break;
                }
            }

            //
            // If the name couldn't be parsed, give up and go home
            //

            if (ClientDnsDomain.Length == 0) {
                Status = STATUS_NO_SUCH_USER;
                goto Cleanup;
            }

            //
            // This isn't really the Netbios Domain name, but it is the best we have.
            //

            ClientNetbiosDomain = ClientDnsDomain;

            for (Index = 0; Index < (ClientNetbiosDomain.Length / sizeof(WCHAR)) ; Index++ ) {

                //
                // truncate the netbios domain to the first DOT
                //

                if( ClientNetbiosDomain.Buffer[Index] == L'.' ) {
                    ClientNetbiosDomain.Length = (USHORT)(Index * sizeof(WCHAR));
                    ClientNetbiosDomain.MaximumLength = ClientNetbiosDomain.Length;
                    break;
                }
            }

        }
        else
        {

            RtlInitUnicodeString(
                &ClientDnsDomain,
                NameResult->rItems[0].pDomain
                );
            RtlInitUnicodeString(
                &ClientName,
                NameResult->rItems[0].pName
                );
            RtlInitUnicodeString(
                &ClientNetbiosDomain,
                NameResult->rItems[0].pName
                );
            //
            // Move the pointer for the name up to the first "\" in the name
            //

            for (Index = 0; Index < ClientName.Length / sizeof(WCHAR) ; Index++ ) {
                if (ClientName.Buffer[Index] == L'\\') {
                    RtlInitUnicodeString(
                        &ClientName,
                        &ClientName.Buffer[Index+1]
                        );

                    // Set the Netbios Domain Name to the string to the left of the backslash
                    ClientNetbiosDomain.Length = (USHORT)(Index * sizeof(WCHAR));
                    break;
                }
            }
        }

    } else {

        ClientName = ChangePasswordRequest->AccountName;
        ClientNetbiosDomain = ChangePasswordRequest->DomainName;
    }



    // Make sure that NlpSamInitialized is TRUE. If we logon using
    // Kerberos, this may not be true.

    if ( !NlpSamInitialized)
    {
        Status = NlSamInitialize( SAM_STARTUP_TIME );
        if (!NT_SUCCESS(Status))
        {
            goto Cleanup;
        }
    }


    //
    // Check to see if the name provided is a domain name. If it has no
    // leading "\\" and does not match the name of the computer, it may be.
    //

    if ((( ClientNetbiosDomain.Length < 3 * sizeof(WCHAR)) ||
        ( ClientNetbiosDomain.Buffer[0] != L'\\' &&
          ClientNetbiosDomain.Buffer[1] != L'\\' ) ) &&
          !RtlEqualDomainName(
                   &NlpComputerName,
                   &ClientNetbiosDomain )) {

        //
        // Check if we are a DC in this domain.
        //  If so, use this DC.
        //  BUGBUG: should allow DnsDomain Name compare, too.
        //

        if ( !NlpWorkstation &&
                   RtlEqualDomainName(
                       &NlpSamDomainName,
                       &ClientNetbiosDomain )) {

            DCNameString = NlpComputerName;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -