Ejemplo n.º 1
0
NTSTATUS
SrvFreeSecurityContexts (
    IN PSESSION Session
    )

/*++

Routine Description:

    Releases any context obtained via the LSA

Arguments:

    IN PSESSION Session : The session

Return Value:

    NTSTATUS

--*/

{
    if ( Session->HaveHandle ) {
        if ( !CONTEXT_EQUAL( Session->UserHandle, SrvNullSessionToken ) ) {
            ExInterlockedAddUlong(
                &SrvStatistics.CurrentNumberOfSessions,
                (ULONG)-1,
                &GLOBAL_SPIN_LOCK(Statistics)
                );
            DeleteSecurityContext( &Session->UserHandle );
        }
    }
    Session->HaveHandle = FALSE;

    return STATUS_SUCCESS;

} // SrvFreeSecurityContexts
Ejemplo n.º 2
0
VOID
FatFspDispatch (
    IN PVOID Context
    )

/*++

Routine Description:

    This is the main FSP thread routine that is executed to receive
    and dispatch IRP requests.  Each FSP thread begins its execution here.
    There is one thread created at system initialization time and subsequent
    threads created as needed.

Arguments:


    Context - Supplies the thread id.

Return Value:

    None - This routine never exits

--*/

{
    NTSTATUS Status;

    PIRP Irp;
    PIRP_CONTEXT IrpContext;
    PIO_STACK_LOCATION IrpSp;
    BOOLEAN VcbDeleted;

    PVOLUME_DEVICE_OBJECT VolDo;

    IrpContext = (PIRP_CONTEXT)Context;

    Irp = IrpContext->OriginatingIrp;

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    //
    //  Now because we are the Fsp we will force the IrpContext to
    //  indicate true on Wait.
    //

    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT | IRP_CONTEXT_FLAG_IN_FSP);

    //
    //  If this request has an associated volume device object, remember it.
    //

    if ( IrpSp->FileObject != NULL ) {

        VolDo = CONTAINING_RECORD( IrpSp->DeviceObject,
                                   VOLUME_DEVICE_OBJECT,
                                   DeviceObject );
    } else {

        VolDo = NULL;
    }

    //
    //  Now case on the function code.  For each major function code,
    //  either call the appropriate FSP routine or case on the minor
    //  function and then call the FSP routine.  The FSP routine that
    //  we call is responsible for completing the IRP, and not us.
    //  That way the routine can complete the IRP and then continue
    //  post processing as required.  For example, a read can be
    //  satisfied right away and then read can be done.
    //
    //  We'll do all of the work within an exception handler that
    //  will be invoked if ever some underlying operation gets into
    //  trouble (e.g., if FatReadSectorsSync has trouble).
    //

    while ( TRUE ) {

        DebugTrace(0, Dbg, "FatFspDispatch: Irp = 0x%08lx\n", Irp);

        //
        //  If this Irp was top level, note it in our thread local storage.
        //

        FsRtlEnterFileSystem();

        if ( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) ) {

            IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );

        } else {

            IoSetTopLevelIrp( Irp );
        }

        try {

            switch ( IrpContext->MajorFunction ) {

                //
                //  For Create Operation,
                //

                case IRP_MJ_CREATE:

                    (VOID) FatCommonCreate( IrpContext, Irp );
                    break;

                //
                //  For close operations.  We do a little kludge here in case
                //  this close causes a volume to go away.  It will NULL the
                //  VolDo local variable so that we will not try to look at
                //  the overflow queue.
                //

                case IRP_MJ_CLOSE:

                {
                    PVCB Vcb;
                    PFCB Fcb;
                    PCCB Ccb;
                    TYPE_OF_OPEN TypeOfOpen;

                    //
                    //  Extract and decode the file object
                    //

                    TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );

                    //
                    //  Do the close.  We have a slightly different format
                    //  for this call because of the async closes.
                    //

                    Status = FatCommonClose( Vcb,
                                             Fcb,
                                             Ccb,
                                             TypeOfOpen,
                                             TRUE,
                                             &VcbDeleted );

                    //
                    //  If the VCB was deleted, do not try to access it later.
                    //

                    if (VcbDeleted) {

                        VolDo = NULL;
                    }

                    ASSERT(Status == STATUS_SUCCESS);

                    FatCompleteRequest( IrpContext, Irp, Status );

                    break;
                }

                //
                //  For read operations
                //

                case IRP_MJ_READ:

                    (VOID) FatCommonRead( IrpContext, Irp );
                    break;

                //
                //  For write operations,
                //

                case IRP_MJ_WRITE:

                    (VOID) FatCommonWrite( IrpContext, Irp );
                    break;

                //
                //  For Query Information operations,
                //

                case IRP_MJ_QUERY_INFORMATION:

                    (VOID) FatCommonQueryInformation( IrpContext, Irp );
                    break;

                //
                //  For Set Information operations,
                //

                case IRP_MJ_SET_INFORMATION:

                    (VOID) FatCommonSetInformation( IrpContext, Irp );
                    break;

                //
                //  For Query EA operations,
                //

                case IRP_MJ_QUERY_EA:

                    (VOID) FatCommonQueryEa( IrpContext, Irp );
                    break;

                //
                //  For Set EA operations,
                //

                case IRP_MJ_SET_EA:

                    (VOID) FatCommonSetEa( IrpContext, Irp );
                    break;

                //
                //  For Flush buffers operations,
                //

                case IRP_MJ_FLUSH_BUFFERS:

                    (VOID) FatCommonFlushBuffers( IrpContext, Irp );
                    break;

                //
                //  For Query Volume Information operations,
                //

                case IRP_MJ_QUERY_VOLUME_INFORMATION:

                    (VOID) FatCommonQueryVolumeInfo( IrpContext, Irp );
                    break;

                //
                //  For Set Volume Information operations,
                //

                case IRP_MJ_SET_VOLUME_INFORMATION:

                    (VOID) FatCommonSetVolumeInfo( IrpContext, Irp );
                    break;

                //
                //  For File Cleanup operations,
                //

                case IRP_MJ_CLEANUP:

                    (VOID) FatCommonCleanup( IrpContext, Irp );
                    break;

                //
                //  For Directory Control operations,
                //

                case IRP_MJ_DIRECTORY_CONTROL:

                    (VOID) FatCommonDirectoryControl( IrpContext, Irp );
                    break;

                //
                //  For File System Control operations,
                //

                case IRP_MJ_FILE_SYSTEM_CONTROL:

                    (VOID) FatCommonFileSystemControl( IrpContext, Irp );
                    break;

                //
                //  For Lock Control operations,
                //

                case IRP_MJ_LOCK_CONTROL:

                    (VOID) FatCommonLockControl( IrpContext, Irp );
                    break;

                //
                //  For Device Control operations,
                //

                case IRP_MJ_DEVICE_CONTROL:

                    (VOID) FatCommonDeviceControl( IrpContext, Irp );
                    break;

                //
                //  For the Shutdown operation,
                //

                case IRP_MJ_SHUTDOWN:

                    (VOID) FatCommonShutdown( IrpContext, Irp );
                    break;

                //
                //  For plug and play operations.
                //

                case IRP_MJ_PNP:

                    //
                    //  I don't believe this should ever occur, but allow for the unexpected.
                    //

                    (VOID) FatCommonPnp( IrpContext, Irp );
                    break;

                //
                //  For any other major operations, return an invalid
                //  request.
                //

                default:

                    FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
                    break;

            }

        } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {

            //
            //  We had some trouble trying to perform the requested
            //  operation, so we'll abort the I/O request with
            //  the error status that we get back from the
            //  execption code.
            //

            (VOID) FatProcessException( IrpContext, Irp, GetExceptionCode() );
        }

        IoSetTopLevelIrp( NULL );

        FsRtlExitFileSystem();

        //
        //  If there are any entries on this volume's overflow queue, service
        //  them.
        //

        if ( VolDo != NULL ) {

            PVOID Entry;

            //
            //  We have a volume device object so see if there is any work
            //  left to do in its overflow queue.
            //

            Entry = FatRemoveOverflowEntry( VolDo );

            //
            //  There wasn't an entry, break out of the loop and return to
            //  the Ex Worker thread.
            //

            if ( Entry == NULL ) {

                break;
            }

            //
            //  Extract the IrpContext, Irp, and IrpSp, and loop.
            //

            IrpContext = CONTAINING_RECORD( Entry,
                                            IRP_CONTEXT,
                                            WorkQueueItem.List );

            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT | IRP_CONTEXT_FLAG_IN_FSP);

            Irp = IrpContext->OriginatingIrp;

            IrpSp = IoGetCurrentIrpStackLocation( Irp );

            continue;

        } else {

            break;
        }
    }

    //
    //  Decrement the PostedRequestCount.
    //

    if ( VolDo ) {

        ExInterlockedAddUlong( &VolDo->PostedRequestCount,
                               0xffffffff,
                               &VolDo->OverflowQueueSpinLock );
    }

    return;
}
Ejemplo n.º 3
0
NTSTATUS
SrvValidateBlob(
    IN PSESSION Session,
    IN PCONNECTION Connection,
    IN PUNICODE_STRING UserName,
    IN OUT PCHAR Blob,
    IN OUT ULONG *BlobLength
    )

/*++

Routine Description:

    Validates a Kerberos Blob sent from the client

Arguments:

    Session - A pointer to a session block so that this routine can
        insert a user token.

    Connection - A pointer to the connection this user is on.

    UserName - ASCIIZ string corresponding to the user name to validate.

    Blob - The Blob to validate and the place to return the output
    Blob. Note this means that this string space has to be
    long enough to hold the maximum length Blob.

    BlobLength - The length of the aforementioned Blob

Return Value:

    NTSTATUS from the security system.

--*/

{
    NTSTATUS Status;
    ULONG Catts;
    LARGE_INTEGER Expiry;
    PUCHAR AllocateMemory = NULL;
    ULONG AllocateLength = *BlobLength;
    BOOLEAN virtualMemoryAllocated = FALSE;
    SecBufferDesc InputToken;
    SecBuffer InputBuffer;
    SecBufferDesc OutputToken;
    SecBuffer OutputBuffer;
    ULONG oldSessionCount;

    AllocateLength += 16;

    Status = NtAllocateVirtualMemory(
                NtCurrentProcess(),
                &AllocateMemory,
                0,
                &AllocateLength,
                MEM_COMMIT,
                PAGE_READWRITE
                );

    if ( !NT_SUCCESS(Status) ) {
        INTERNAL_ERROR( ERROR_LEVEL_UNEXPECTED,
                        "Could not allocate Blob Memory %lC\n",
                        Status,
                        NULL);
        goto get_out;
    }

    virtualMemoryAllocated = TRUE;


    if ( (SrvHaveCreds & HAVEKERBEROS) == 0 ) { // Need to get cred handle first

        UNICODE_STRING Kerb;

        Kerb.Length = Kerb.MaximumLength = 16;
        Kerb.Buffer = (LPWSTR) AllocateMemory;
        RtlCopyMemory( Kerb.Buffer, MICROSOFT_KERBEROS_NAME, 16);

        Status = AcquireCredentialsHandle(
                    NULL,              // Default principal
                    (PSECURITY_STRING) &Kerb,
                    SECPKG_CRED_INBOUND,   // Need to define this
                    NULL,               // No LUID
                    NULL,               // no AuthData
                    NULL,               // no GetKeyFn
                    NULL,               // no GetKeyArg
                    &SrvKerberosLsaHandle,
                    (PTimeStamp)&Expiry
                    );

        if ( !NT_SUCCESS(Status) ) {
            Status = MapSecurityError(Status);
            goto get_out;
        }
        SrvHaveCreds |= HAVEKERBEROS;
    }

    RtlCopyMemory( AllocateMemory, Blob, *BlobLength );
    InputToken.pBuffers = &InputBuffer;
    InputToken.cBuffers = 1;
    InputToken.ulVersion = 0;
    InputBuffer.pvBuffer = AllocateMemory;
    InputBuffer.cbBuffer = *BlobLength;
    InputBuffer.BufferType = SECBUFFER_TOKEN;

    OutputToken.pBuffers = &OutputBuffer;
    OutputToken.cBuffers = 1;
    OutputToken.ulVersion = 0;
    OutputBuffer.pvBuffer = AllocateMemory;
    OutputBuffer.cbBuffer = *BlobLength;
    OutputBuffer.BufferType = SECBUFFER_TOKEN;

    SrvStatistics.SessionLogonAttempts++;

    Status = AcceptSecurityContext(
                &SrvKerberosLsaHandle,
                (PCtxtHandle)NULL,
                &InputToken,
                ASC_REQ_EXTENDED_ERROR,               // fContextReq
                SECURITY_NATIVE_DREP,
                &Session->UserHandle,
                &OutputToken,
                &Catts,
                (PTimeStamp)&Expiry
                );

    Status = MapSecurityError( Status );

    if ( NT_SUCCESS(Status)
              ||
         (Catts & ASC_RET_EXTENDED_ERROR) )
    {
        *BlobLength = OutputBuffer.cbBuffer;
        RtlCopyMemory( Blob, AllocateMemory, *BlobLength );

        //
        // BUGBUG
        // All of the following values need to come from someplace
        // And while we're at it, get the LogonId as well
        //

        if(NT_SUCCESS(Status))
        {

            //
            // Note whether or not this user is an administrator
            //

            Session->IsAdmin = SrvIsAdmin( Session->UserHandle );

            //
            // fiddle with the session structures iff the
            // security context was actually accepted
            //

            Session->HaveHandle = TRUE;
            Session->KickOffTime = Expiry;
            Session->LogOffTime = Expiry;
            Session->GuestLogon = FALSE;   // No guest logon this way
            Session->EncryptedLogon = TRUE;

            //
            // See if the session count is being exceeded.  We'll allow it only
            //   if the new client is an administrator
            //
            oldSessionCount = ExInterlockedAddUlong(
                              &SrvStatistics.CurrentNumberOfSessions,
                              1,
                              &GLOBAL_SPIN_LOCK(Statistics)
                              );

            if ( oldSessionCount >= SrvMaxUsers ) {
                if( oldSessionCount != SrvMaxUsers || !SrvIsAdmin( Session->UserHandle ) ) {

                    ExInterlockedAddUlong(
                        &SrvStatistics.CurrentNumberOfSessions,
                        (ULONG)-1,
                        &GLOBAL_SPIN_LOCK(Statistics)
                        );

                    DeleteSecurityContext( &Session->UserHandle );
                    Session->HaveHandle = FALSE;

                    Status = STATUS_REQUEST_NOT_ACCEPTED;
                    goto get_out;
                }
            }
        }
    }
    else
    {
        *BlobLength = 0;
    }

get_out:

    if (virtualMemoryAllocated) {
        (VOID)NtFreeVirtualMemory(
                NtCurrentProcess(),
                &AllocateMemory,
                &AllocateLength,
                MEM_DECOMMIT
                );
    }

    return Status;

} // SrvValidateBlob
Ejemplo n.º 4
0
NTSTATUS
DoUserLogon (
    IN PLOGON_INFO LogonInfo
    )

/*++

Routine Description:

    Validates a username/password combination by interfacing to the
    security subsystem.

Arguments:

    LogonInfo - Pointer to a block containing in/out information about
        the logon.

Return Value:

    NTSTATUS from the security system.

--*/

{
    NTSTATUS status, subStatus, freeStatus;
    ULONG actualUserInfoBufferLength;
    ULONG oldSessionCount;
    LUID LogonId;
    ULONG Catts;
    LARGE_INTEGER Expiry;
    ULONG BufferOffset;
    SecBufferDesc InputToken;
    SecBuffer InputBuffers[2];
    SecBufferDesc OutputToken;
    SecBuffer OutputBuffer;
    PNTLM_AUTHENTICATE_MESSAGE NtlmInToken = NULL;
    PAUTHENTICATE_MESSAGE InToken = NULL;
    PNTLM_ACCEPT_RESPONSE OutToken = NULL;
    ULONG NtlmInTokenSize;
    ULONG InTokenSize;
    ULONG OutTokenSize;
    ULONG AllocateSize;

    ULONG profileBufferLength;

    PAGED_CODE( );

    LogonInfo->IsNullSession = FALSE;
    LogonInfo->IsAdmin = FALSE;

#if DBG
    SrvLogonCount++;
#endif

    //
    // If this is a null session request, use the cached null session
    // token, which was created during server startup.
    //

    if ( (LogonInfo->UserNameLength == 0) &&
         (LogonInfo->CaseSensitivePasswordLength == 0) &&
         ( (LogonInfo->CaseInsensitivePasswordLength == 0) ||
           ( (LogonInfo->CaseInsensitivePasswordLength == 1) &&
             (*LogonInfo->CaseInsensitivePassword == '\0') ) ) ) {

        LogonInfo->IsNullSession = TRUE;
#if DBG
        SrvNullLogonCount++;
#endif

        if ( !CONTEXT_NULL(SrvNullSessionToken) ) {

            LogonInfo->HaveHandle = TRUE;
            LogonInfo->Token = SrvNullSessionToken;

            LogonInfo->KickOffTime.QuadPart = 0x7FFFFFFFFFFFFFFF;
            LogonInfo->LogOffTime.QuadPart = 0x7FFFFFFFFFFFFFFF;

            LogonInfo->GuestLogon = FALSE;
            LogonInfo->EncryptedLogon = FALSE;

            return STATUS_SUCCESS;
        }

    }

    //
    // This is the main body of the Cairo logon user code
    //

    //
    // First make sure we have a credential handle
    //

    if ((SrvHaveCreds & HAVENTLM) == 0) {

        status = AcquireLMCredentials();

        if (!NT_SUCCESS(status)) {
            goto error_exit;
        }
    }

    //
    // Figure out how big a buffer we need.  We put all the messages
    // in one buffer for efficiency's sake.
    //

    NtlmInTokenSize = sizeof(NTLM_AUTHENTICATE_MESSAGE);
    NtlmInTokenSize = (NtlmInTokenSize + 3) & 0xfffffffc;

    InTokenSize = sizeof(AUTHENTICATE_MESSAGE) +
            LogonInfo->UserNameLength +
            LogonInfo->WorkstationNameLength +
            LogonInfo->DomainNameLength +
            LogonInfo->CaseInsensitivePasswordLength +
            ROUND_UP_COUNT(LogonInfo->CaseSensitivePasswordLength, sizeof(USHORT));


    InTokenSize = (InTokenSize + 3) & 0xfffffffc;

    OutTokenSize = sizeof(NTLM_ACCEPT_RESPONSE);
    OutTokenSize = (OutTokenSize + 3) & 0xfffffffc;

    //
    // Round this up to 8 byte boundary becaus the out token needs to be
    // quad word aligned for the LARGE_INTEGER.
    //

    AllocateSize = ((NtlmInTokenSize + InTokenSize + 7) & 0xfffffff8) + OutTokenSize;

    status = NtAllocateVirtualMemory(
                 NtCurrentProcess( ),
                 &InToken,
                 0L,
                 &AllocateSize,
                 MEM_COMMIT,
                 PAGE_READWRITE
                 );

    if ( !NT_SUCCESS(status) ) {

        INTERNAL_ERROR(
            ERROR_LEVEL_EXPECTED,
            "SrvValidateUser: NtAllocateVirtualMemory failed: %X\n.",
            status,
            NULL
            );

        SrvLogError(
            SrvDeviceObject,
            EVENT_SRV_NO_VIRTUAL_MEMORY,
            status,
            &actualUserInfoBufferLength,
            sizeof(ULONG),
            NULL,
            0
            );

        status = STATUS_INSUFF_SERVER_RESOURCES;
        goto error_exit;
    }

    //
    // Zero the input tokens
    //

    RtlZeroMemory(
        InToken,
        InTokenSize + NtlmInTokenSize
        );

    NtlmInToken = (PNTLM_AUTHENTICATE_MESSAGE) ((PUCHAR) InToken + InTokenSize);
    OutToken = (PNTLM_ACCEPT_RESPONSE) ((PUCHAR) (((ULONG) NtlmInToken + NtlmInTokenSize + 7) & 0xfffffff8));

    //
    // First set up the NtlmInToken, since it is the easiest.
    //

    RtlCopyMemory(
        NtlmInToken->ChallengeToClient,
        LogonInfo->EncryptionKey,
        MSV1_0_CHALLENGE_LENGTH
        );

    NtlmInToken->ParameterControl = 0;


    //
    // Okay, now for the tought part - marshalling the AUTHENTICATE_MESSAGE
    //

    RtlCopyMemory(  InToken->Signature,
                    NTLMSSP_SIGNATURE,
                    sizeof(NTLMSSP_SIGNATURE));

    InToken->MessageType = NtLmAuthenticate;

    BufferOffset = sizeof(AUTHENTICATE_MESSAGE);

    //
    // LM password - case insensitive
    //

    InToken->LmChallengeResponse.Buffer = (PCHAR) BufferOffset;
    InToken->LmChallengeResponse.Length =
        InToken->LmChallengeResponse.MaximumLength =
            (USHORT) LogonInfo->CaseInsensitivePasswordLength;

    RtlCopyMemory(  BufferOffset + (PCHAR) InToken,
                    LogonInfo->CaseInsensitivePassword,
                    LogonInfo->CaseInsensitivePasswordLength);

    BufferOffset += ROUND_UP_COUNT(LogonInfo->CaseInsensitivePasswordLength, sizeof(USHORT));

    //
    // NT password - case sensitive
    //

    InToken->NtChallengeResponse.Buffer = (PCHAR) BufferOffset;
    InToken->NtChallengeResponse.Length =
        InToken->NtChallengeResponse.MaximumLength =
            (USHORT) LogonInfo->CaseSensitivePasswordLength;

    RtlCopyMemory(  BufferOffset + (PCHAR) InToken,
                    LogonInfo->CaseSensitivePassword,
                    LogonInfo->CaseSensitivePasswordLength);

    BufferOffset += LogonInfo->CaseSensitivePasswordLength;

    //
    // Domain Name
    //

    InToken->DomainName.Buffer = (PCHAR) BufferOffset;
    InToken->DomainName.Length =
        InToken->DomainName.MaximumLength =
            (USHORT) LogonInfo->DomainNameLength;

    RtlCopyMemory(  BufferOffset + (PCHAR) InToken,
                    LogonInfo->DomainName,
                    LogonInfo->DomainNameLength);

    BufferOffset += LogonInfo->DomainNameLength;

    //
    // Workstation Name
    //

    InToken->Workstation.Buffer = (PCHAR) BufferOffset;
    InToken->Workstation.Length =
        InToken->Workstation.MaximumLength =
            (USHORT) LogonInfo->WorkstationNameLength;

    RtlCopyMemory(  BufferOffset + (PCHAR) InToken,
                    LogonInfo->WorkstationName,
                    LogonInfo->WorkstationNameLength);

    BufferOffset += LogonInfo->WorkstationNameLength;


    //
    // User Name
    //

    InToken->UserName.Buffer = (PCHAR) BufferOffset;
    InToken->UserName.Length =
        InToken->UserName.MaximumLength =
            (USHORT) LogonInfo->UserNameLength;

    RtlCopyMemory(  BufferOffset + (PCHAR) InToken,
                    LogonInfo->UserName,
                    LogonInfo->UserNameLength);

    BufferOffset += LogonInfo->UserNameLength;



    //
    // Setup all the buffers properly
    //

    InputToken.pBuffers = InputBuffers;
    InputToken.cBuffers = 2;
    InputToken.ulVersion = 0;
    InputBuffers[0].pvBuffer = InToken;
    InputBuffers[0].cbBuffer = InTokenSize;
    InputBuffers[0].BufferType = SECBUFFER_TOKEN;
    InputBuffers[1].pvBuffer = NtlmInToken;
    InputBuffers[1].cbBuffer = NtlmInTokenSize;
    InputBuffers[1].BufferType = SECBUFFER_TOKEN;

    OutputToken.pBuffers = &OutputBuffer;
    OutputToken.cBuffers = 1;
    OutputToken.ulVersion = 0;
    OutputBuffer.pvBuffer = OutToken;
    OutputBuffer.cbBuffer = OutTokenSize;
    OutputBuffer.BufferType = SECBUFFER_TOKEN;

    SrvStatistics.SessionLogonAttempts++;

    status = AcceptSecurityContext(
                &SrvLmLsaHandle,
                NULL,
                &InputToken,
                0,
                SECURITY_NATIVE_DREP,
                &LogonInfo->Token,
                &OutputToken,
                &Catts,
                (PTimeStamp) &Expiry
                );

    status = MapSecurityError( status );

    if ( !NT_SUCCESS(status) ) {


        LogonInfo->Token.dwLower = 0;
        LogonInfo->Token.dwUpper = 0;


        INTERNAL_ERROR(
            ERROR_LEVEL_EXPECTED,
            "SrvValidateUser: LsaLogonUser failed: %X",
            status,
            NULL
            );

        freeStatus = NtFreeVirtualMemory(
                        NtCurrentProcess( ),
                        (PVOID *)&InToken,
                        &AllocateSize,
                        MEM_RELEASE
                        );

        ASSERT(NT_SUCCESS(freeStatus));

        goto error_exit;
    }


    LogonInfo->KickOffTime = OutToken->KickoffTime;
    LogonInfo->LogOffTime = Expiry;
    LogonInfo->GuestLogon = (BOOLEAN)(OutToken->UserFlags & LOGON_GUEST);
    LogonInfo->EncryptedLogon = (BOOLEAN)!(OutToken->UserFlags & LOGON_NOENCRYPTION);
    LogonInfo->LogonId = OutToken->LogonId;
    LogonInfo->HaveHandle = TRUE;

    if ( (OutToken->UserFlags & LOGON_USED_LM_PASSWORD) &&
        LogonInfo->NtSmbs ) {

        ASSERT( MSV1_0_USER_SESSION_KEY_LENGTH >=
                MSV1_0_LANMAN_SESSION_KEY_LENGTH );

        RtlZeroMemory(
            LogonInfo->NtUserSessionKey,
            MSV1_0_USER_SESSION_KEY_LENGTH
            );

        RtlCopyMemory(
            LogonInfo->NtUserSessionKey,
            OutToken->LanmanSessionKey,
            MSV1_0_LANMAN_SESSION_KEY_LENGTH
            );

        //
        // Turn on bit 1 to tell the client that we are using
        // the lm session key instead of the user session key.
        //

        LogonInfo->Action |= SMB_SETUP_USE_LANMAN_KEY;

    } else {

        RtlCopyMemory(
            LogonInfo->NtUserSessionKey,
            OutToken->UserSessionKey,
            MSV1_0_USER_SESSION_KEY_LENGTH
            );

    }

    RtlCopyMemory(
        LogonInfo->LanManSessionKey,
        OutToken->LanmanSessionKey,
        MSV1_0_LANMAN_SESSION_KEY_LENGTH
        );

    freeStatus = NtFreeVirtualMemory(
                    NtCurrentProcess( ),
                    (PVOID *)&InToken,
                    &AllocateSize,
                    MEM_RELEASE
                    );

    ASSERT(NT_SUCCESS(freeStatus));

    //
    // Note whether or not this user is an administrator
    //

    LogonInfo->IsAdmin = SrvIsAdmin( LogonInfo->Token );

    //
    // One last check:  Is our session count being exceeded?
    //   We will let the session be exceeded by 1 iff the client
    //   is an administrator.
    //

    if( LogonInfo->IsNullSession == FALSE ) {

        oldSessionCount = ExInterlockedAddUlong(
                          &SrvStatistics.CurrentNumberOfSessions,
                          1,
                          &GLOBAL_SPIN_LOCK(Statistics)
                          );

        if ( oldSessionCount >= SrvMaxUsers ) {
            if( oldSessionCount != SrvMaxUsers || !LogonInfo->IsAdmin ) {

                ExInterlockedAddUlong(
                    &SrvStatistics.CurrentNumberOfSessions,
                    (ULONG)-1,
                    &GLOBAL_SPIN_LOCK(Statistics)
                    );


                DeleteSecurityContext( &LogonInfo->Token );
                RtlZeroMemory( &LogonInfo->Token, sizeof( LogonInfo->Token ) );

                status = STATUS_REQUEST_NOT_ACCEPTED;
                goto error_exit;
            }
        }
    }

    return STATUS_SUCCESS;

error_exit:

    return status;

} // DoUserLogon
Ejemplo n.º 5
0
VOID
NtfsFspDispatch (
    IN PVOID Context
    )

/*++

Routine Description:

    This is the main FSP thread routine that is executed to receive
    and dispatch IRP requests.  Each FSP thread begins its execution here.
    There is one thread created at system initialization time and subsequent
    threads created as needed.

Arguments:


    Context - Supplies the thread id.

Return Value:

    None - This routine never exits

--*/

{
    TOP_LEVEL_CONTEXT TopLevelContext;
    PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
    OPLOCK_CLEANUP OplockCleanup; 

    PIRP Irp;
    PIRP_CONTEXT IrpContext;
    PIO_STACK_LOCATION IrpSp;
    ULONG LogFileFullCount = 0;

    PVOLUME_DEVICE_OBJECT VolDo;
    BOOLEAN Retry;
    NTSTATUS Status = STATUS_SUCCESS;
    IrpContext = (PIRP_CONTEXT)Context;

    Irp = IrpContext->OriginatingIrp;

    if (Irp != NULL) {

        IrpSp = IoGetCurrentIrpStackLocation( Irp );
    }

    //
    //  Now because we are the Fsp we will force the IrpContext to
    //  indicate true on Wait.
    //

    SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );

    //
    //  If this request has an associated volume device object, remember it.
    //

    if ((Irp != NULL) &&
        (IrpSp->FileObject != NULL)) {

        VolDo = CONTAINING_RECORD( IrpSp->DeviceObject,
                                   VOLUME_DEVICE_OBJECT,
                                   DeviceObject );
    } else {

        VolDo = NULL;
    }

    //
    //  Now case on the function code.  For each major function code,
    //  either call the appropriate FSP routine or case on the minor
    //  function and then call the FSP routine.  The FSP routine that
    //  we call is responsible for completing the IRP, and not us.
    //  That way the routine can complete the IRP and then continue
    //  post processing as required.  For example, a read can be
    //  satisfied right away and then read can be done.
    //
    //  We'll do all of the work within an exception handler that
    //  will be invoked if ever some underlying operation gets into
    //  trouble (e.g., if NtfsReadSectorsSync has trouble).
    //

    while (TRUE) {

        FsRtlEnterFileSystem();

        ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );

        ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, TRUE );
        ASSERT( ThreadTopLevelContext == &TopLevelContext );

        NtfsPostRequests += 1;

        do {

            //
            //  If this is the initial try with this Irp Context, update the
            //  top level Irp fields.
            //
    
            NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
    
            Retry = FALSE;
    
            try {

                //
                //  Always clear the exception code in the IrpContext so we respond
                //  correctly to errors encountered in the Fsp.
                //

                IrpContext->ExceptionStatus = 0;
                SetFlag( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP );

                //
                //  See if we were posted due to a log file full condition, and
                //  if so, then do a clean volume checkpoint if we are the
                //  first ones to get there.  If we see a different Lsn and do
                //  not do the checkpoint, the worst that can happen is that we
                //  will get posted again if the log file is still full.
                //

                if (IrpContext->LastRestartArea.QuadPart != 0) {

                    NtfsCheckpointForLogFileFull( IrpContext );

                    if (++LogFileFullCount >= 2) {

                        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_EXCESS_LOG_FULL );
                    }
                }

                //
                //  If we have an Irp then proceed with our normal processing.
                //

                if (Irp != NULL) {

                    switch ( IrpContext->MajorFunction ) {

                        //
                        //  For Create Operation,
                        //

                        case IRP_MJ_CREATE:

                            ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE );
                            
                            if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DASD_OPEN )) {

                                Status = NtfsCommonVolumeOpen( IrpContext, Irp );

                            } else {

                                RtlZeroMemory( &OplockCleanup, sizeof( OplockCleanup ) );
                                Status = NtfsCommonCreate( IrpContext, Irp, &OplockCleanup, NULL );
                            }
                            break;

                        //
                        //  For close operations
                        //

                        case IRP_MJ_CLOSE:

                            //
                            //  We should never post closes to this workqueue.
                            //

                            NtfsBugCheck( 0, 0, 0 );
                            break;

                        //
                        //  For read operations
                        //

                        case IRP_MJ_READ:

                            (VOID) NtfsCommonRead( IrpContext, Irp, TRUE );
                            break;

                        //
                        //  For write operations,
                        //

                        case IRP_MJ_WRITE:

                            (VOID) NtfsCommonWrite( IrpContext, Irp );
                            break;

                        //
                        //  For Query Information operations,
                        //

                        case IRP_MJ_QUERY_INFORMATION:

                            (VOID) NtfsCommonQueryInformation( IrpContext, Irp );
                            break;

                        //
                        //  For Set Information operations,
                        //

                        case IRP_MJ_SET_INFORMATION:

                            (VOID) NtfsCommonSetInformation( IrpContext, Irp );
                            break;

                        //
                        //  For Query EA operations,
                        //

                        case IRP_MJ_QUERY_EA:

                            (VOID) NtfsCommonQueryEa( IrpContext, Irp );
                            break;

                        //
                        //  For Set EA operations,
                        //

                        case IRP_MJ_SET_EA:

                            (VOID) NtfsCommonSetEa( IrpContext, Irp );
                            break;


                        //
                        //  For Flush buffers operations,
                        //

                        case IRP_MJ_FLUSH_BUFFERS:

                            (VOID) NtfsCommonFlushBuffers( IrpContext, Irp );
                            break;

                        //
                        //  For Query Volume Information operations,
                        //

                        case IRP_MJ_QUERY_VOLUME_INFORMATION:

                            (VOID) NtfsCommonQueryVolumeInfo( IrpContext, Irp );
                            break;

                        //
                        //  For Set Volume Information operations,
                        //

                        case IRP_MJ_SET_VOLUME_INFORMATION:

                            (VOID) NtfsCommonSetVolumeInfo( IrpContext, Irp );
                            break;

                        //
                        //  For File Cleanup operations,
                        //

                        case IRP_MJ_CLEANUP:

                            (VOID) NtfsCommonCleanup( IrpContext, Irp );
                            break;

                        //
                        //  For Directory Control operations,
                        //

                        case IRP_MJ_DIRECTORY_CONTROL:

                            (VOID) NtfsCommonDirectoryControl( IrpContext, Irp );
                            break;

                        //
                        //  For File System Control operations,
                        //

                        case IRP_MJ_FILE_SYSTEM_CONTROL:

                            (VOID) NtfsCommonFileSystemControl( IrpContext, Irp );
                            break;

                        //
                        //  For Lock Control operations,
                        //

                        case IRP_MJ_LOCK_CONTROL:

                            (VOID) NtfsCommonLockControl( IrpContext, Irp );
                            break;

                        //
                        //  For Device Control operations,
                        //

                        case IRP_MJ_DEVICE_CONTROL:

                            (VOID) NtfsCommonDeviceControl( IrpContext, Irp );
                            break;

                        //
                        //  For Query Security Information operations,
                        //

                        case IRP_MJ_QUERY_SECURITY:

                            (VOID) NtfsCommonQuerySecurityInfo( IrpContext, Irp );
                            break;

                        //
                        //  For Set Security Information operations,
                        //

                        case IRP_MJ_SET_SECURITY:

                            (VOID) NtfsCommonSetSecurityInfo( IrpContext, Irp );
                            break;

                        //
                        //  For Query Quota operations,
                        //

                        case IRP_MJ_QUERY_QUOTA:

                            (VOID) NtfsCommonQueryQuota( IrpContext, Irp );
                            break;

                        //
                        //  For Set Quota operations,
                        //

                        case IRP_MJ_SET_QUOTA:

                            (VOID) NtfsCommonSetQuota( IrpContext, Irp );
                            break;

                        //
                        //  For any other major operations, return an invalid
                        //  request.
                        //

                        default:

                            NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
                            break;
                    }

                //
                //  Otherwise complete the request to clean up this Irp Context.
                //

                } else {

                    NtfsCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
                    IrpContext = NULL;
                }

                ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
        
            } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {

                PIO_STACK_LOCATION IrpSp;

                //
                //  We had some trouble trying to perform the requested
                //  operation, so we'll abort the I/O request with
                //  the error status that we get back from the
                //  execption code
                //

                if (Irp != NULL) {

                    IrpSp = IoGetCurrentIrpStackLocation( Irp );

                    Status = GetExceptionCode();

                    if ((Status == STATUS_FILE_DELETED) && 
                        ((IrpContext->MajorFunction == IRP_MJ_READ) || 
                         (IrpContext->MajorFunction == IRP_MJ_WRITE) || 
                         ((IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) &&
                          (IrpSp->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation)))) {

                        IrpContext->ExceptionStatus = Status = STATUS_SUCCESS;
                    }
                }
                
                //
                //  If we failed to upgrade the volume's version during mount, we may
                //  not have put the right exception code into the irp context yet.
                //
                
                if ((IrpContext != NULL) &&
                    (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED )) &&
                    (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
                    (IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME)) {

                    IrpContext->ExceptionStatus = Status;
                }

                //  
                //  This is the return status code that we want the Irp Completion routine to receive.
                //

                Status = NtfsProcessException( IrpContext, Irp, Status );

                if ((Status == STATUS_CANT_WAIT) || (Status == STATUS_LOG_FILE_FULL)) {

                    Retry = TRUE;
                }
            }

        } while (Retry);

        FsRtlExitFileSystem();

        //
        //  If there are any entries on this volume's overflow queue, service
        //  them.
        //

        if (VolDo != NULL) {

            KIRQL SavedIrql;
            PLIST_ENTRY Entry = NULL;

            //
            //  We have a volume device object so see if there is any work
            //  left to do in its overflow queue.
            //

            KeAcquireSpinLock( &VolDo->OverflowQueueSpinLock, &SavedIrql );

            while (VolDo->OverflowQueueCount > 0) {

                //
                //  There is overflow work to do in this volume so we'll
                //  decrement the Overflow count, dequeue the IRP, and release
                //  the Event
                //

                Entry = VolDo->OverflowQueue.Flink;
                IrpContext = CONTAINING_RECORD( Entry,
                                                IRP_CONTEXT,
                                                WorkQueueItem.List );
                Irp = IrpContext->OriginatingIrp;

                //
                //  If the cancel routine thinks it owns the irp ignore it
                //  

                if (NtfsSetCancelRoutine( Irp, NULL, 0, FALSE )) {
                    
                    VolDo->OverflowQueueCount -= 1;
                    RemoveEntryList( (PLIST_ENTRY)Entry );
                    break;
                
                } else {

                    //
                    //  Release the spinlock to let the cancel routine gain it and finish
                    //  its action
                    //  

                    KeReleaseSpinLock( &VolDo->OverflowQueueSpinLock, SavedIrql );
                    KeAcquireSpinLock( &VolDo->OverflowQueueSpinLock, &SavedIrql );
                    Entry = NULL;
                }
            } //  endwhile

            KeReleaseSpinLock( &VolDo->OverflowQueueSpinLock, SavedIrql );

            //
            //  There wasn't an entry, break out of the loop and return to
            //  the Ex Worker thread.
            //

            if ( Entry == NULL ) {

                break;
            }

            if (VolDo->OverflowQueueCount < OVERFLOW_QUEUE_LIMIT) {
                KeSetEvent( &VolDo->OverflowQueueEvent, IO_NO_INCREMENT, FALSE );
            }

            //
            //  set wait to TRUE, and loop.
            //

            LogFileFullCount = 0;
            SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
            continue;

        } else {

            break;
        }
    }

    //
    //  Decrement the PostedRequestCount.
    //

    if (VolDo) {

        ExInterlockedAddUlong( &VolDo->PostedRequestCount,
                               0xffffffff,
                               &VolDo->OverflowQueueSpinLock );
    }

    return;
}
Ejemplo n.º 6
0
VOID
IopDeleteFile(
    IN PVOID Object
    )

/*++

Routine Description:

    This routine is invoked when the last handle to a specific file handle is
    being closed and the file object is going away.  It is the responsibility
    of this routine to perform the following functions:

        o  Notify the device driver that the file object is open on that the
           file is being closed.

        o  Dereference the user's error port for the file object, if there
           is one associated with the file object.

        o  Decrement the device object reference count.

Arguments:

    Object - Pointer to the file object being deleted.

Return Value:

    None.

--*/

{
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_OBJECT deviceObject;
    IO_STATUS_BLOCK ioStatusBlock;
    KIRQL irql;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    KEVENT event;
    PVPB vpb;
    BOOLEAN referenceCountDecremented;

    //
    // Obtain a pointer to the file object.
    //

    fileObject = (PFILE_OBJECT) Object;

    //
    // Get a pointer to the first device driver which should be notified that
    // this file is going away.  If the device driver field is NULL, then this
    // file is being shut down due to an error attempting to get it open in the
    // first place, so do not do any further processing.
    //

    if (fileObject->DeviceObject) {
        if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
            deviceObject = IoGetRelatedDeviceObject( fileObject );
        } else {
            deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
        }

        //
        // If this file has never had a file handle created for it, and yet
        // it exists, invoke the close file procedure so that the file system
        // gets the cleanup IRP it is expecting before sending the close IRP.
        //

        if (!(fileObject->Flags & FO_HANDLE_CREATED)) {
            IopCloseFile( (PEPROCESS) NULL,
                          Object,
                          0,
                          1,
                          1 );
        }

        //
        // If this file is open for synchronous I/O, wait until this thread
        // owns it exclusively since there may still be a thread using it.
        // This occurs when a system service owns the file because it owns
        // the semaphore, but the I/O completion code has already dereferenced
        // the file object itself.  Without waiting here for the same semaphore
        // there would be a race condition in the service who owns it now.  The
        // service needs to be able to access the object w/o it going away after
        // its wait for the file event is satisfied.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

            BOOLEAN interrupted;

            if (!IopAcquireFastLock( fileObject )) {
                (VOID) IopAcquireFileObjectLock( fileObject,
                                                 KernelMode,
                                                 FALSE,
                                                 &interrupted );
            }
        }

        //
        // Reset a local event that can be used to wait for the device driver
        // to close the file.
        //

        KeInitializeEvent( &event, SynchronizationEvent, FALSE );

        //
        // Reset the event in the file object.
        //

        KeClearEvent( &fileObject->Event );

        //
        // Allocate an I/O Request Packet (IRP) to be used in communicating with
        // the appropriate device driver that the file is being closed.  Notice
        // that the allocation of this packet is done without charging quota so
        // that the operation will not fail.  This is done because there is no
        // way to return an error to the caller at this point.
        //

        irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
        if (!irp) {
            irp = IopAllocateIrpMustSucceed( deviceObject->StackSize );
        }

        //
        // Get a pointer to the stack location for the first driver.  This is
        // where the function codes and parameters are placed.
        //

        irpSp = IoGetNextIrpStackLocation( irp );

        //
        // Fill in the IRP, indicating that this file object is being deleted.
        //

        irpSp->MajorFunction = IRP_MJ_CLOSE;
        irpSp->FileObject = fileObject;
        irp->UserIosb = &ioStatusBlock;
        irp->UserEvent = &event;
        irp->Tail.Overlay.OriginalFileObject = fileObject;
        irp->Tail.Overlay.Thread = PsGetCurrentThread();
        irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
        irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;

        //
        // Place this packet in the thread's I/O pending queue.
        //

        IopQueueThreadIrp( irp );

        //
        // Decrement the reference count on the VPB, if necessary.  We
        // have to do this BEFORE handing the Irp to the file system
        // because of a trick the file systems play with close, and
        // believe me, you really don't want to know what it is.
        //
        // Since there is not a error path here (close cannot fail),
        // and the file system is the only ome who can actually synchronize
        // with the actual completion of close processing, the file system
        // is the one responsible for Vpb deletion.
        //

        vpb = fileObject->Vpb;

        if (vpb && !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
            ExInterlockedAddUlong( &vpb->ReferenceCount,
                                   0xffffffff,
                                   &IopVpbSpinLock );
        }

        //
        // If this device object has stated for a fact that it knows it will
        // never have the final non-zero reference count among the other
        // device objects associated with our driver object, then decrement
        // our reference count here BEFORE calling the file system.  This
        // is required because for a special class of device objects, the
        // file system may delete them.
        //

        if (fileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE) {
            ExInterlockedAddUlong( &fileObject->DeviceObject->ReferenceCount,
                                   0xffffffff,
                                   &IopDatabaseLock );

            referenceCountDecremented = TRUE;
        } else {
            referenceCountDecremented = FALSE;
        }

        //
        // Give the device driver the packet.  If this request does not work,
        // there is nothing that can be done about it.  This is unfortunate
        // because the driver may have had problems that it was about to
        // report about other operations (e.g., write behind failures, etc.)
        // that it can no longer report.  The reason is that this routine
        // is really initially invoked by NtClose, which has already closed
        // the caller's handle, and that's what the return status from close
        // indicates:  the handle has successfully been closed.
        //

        status = IoCallDriver( deviceObject, irp );

        if (status == STATUS_PENDING) {
            (VOID) KeWaitForSingleObject( &event,
                                          Executive,
                                          KernelMode,
                                          FALSE,
                                          (PLARGE_INTEGER) NULL );
        }

        //
        // Perform any completion operations that need to be performed on
        // the IRP that was used for this request.  This is done here as
        // as opposed to in normal completion code because there is a race
        // condition between when this routine executes if it was invoked
        // from a special kernel APC (e.g., some IRP was just completed and
        // dereferenced this file object for the last time), and when the
        // special kernel APC because of this packet's completion executing.
        //
        // This problem is solved by not having to queue a special kernel
        // APC routine for completion of this packet.  Rather, it is treated
        // much like a synchronous paging I/O operation, except that the
        // packet is not even freed during I/O completion.  This is because
        // the packet is still in this thread's queue, and there is no way
        // to get it out except at APC_LEVEL.  Unfortunately, the part of
        // I/O completion that needs to dequeue the packet is running at
        // DISPATCH_LEVEL.
        //
        // Hence, the packet must be removed from the queue (synchronized,
        // of course), and then it must be freed.
        //

        KeRaiseIrql( APC_LEVEL, &irql );
        IopDequeueThreadIrp( irp );
        KeLowerIrql( irql );

        IoFreeIrp( irp );

        //
        // Free the file name string buffer if there was one.
        //

        if (fileObject->FileName.Length != 0) {
            ExFreePool( fileObject->FileName.Buffer );
        }

        //
        // If there was an completion port associated w/this file object, dereference
        // it now, and deallocate the completion context pool.
        //

        if (fileObject->CompletionContext) {
            ObDereferenceObject( fileObject->CompletionContext->Port );
            ExFreePool( fileObject->CompletionContext );
        }

        //
        // Get a pointer to the real device object so its reference count
        // can be decremented.
        //

        deviceObject = fileObject->DeviceObject;

        //
        // Decrement the reference count on the device object.  Note that
        // if the driver has been marked for an unload operation, and the
        // reference count goes to zero, then the driver may need to be
        // unloaded at this point.
        //
        // Note: only do this if the reference count was not already done
        // above.  The device object may be gone in this case.
        //

        if (!referenceCountDecremented) {
            IopDecrementDeviceObjectRef( deviceObject, FALSE );
        }
    }
}
Ejemplo n.º 7
0
VOID
IopErrorLogThread(
    IN PVOID StartContext
    )

/*++

Routine Description:

    This is the main loop for the I/O error log thread which executes in the
    system process context.  This routine is started when the system is
    initialized.

Arguments:

    StartContext - Startup context; not used.

Return Value:

    None.

--*/

{
    PERROR_LOG_ENTRY errorLogEntry;
    UNICODE_STRING nameString;
    PLIST_ENTRY listEntry;
    PIO_ERROR_LOG_MESSAGE errorMessage;
    NTSTATUS status;
    PELF_PORT_MSG portMessage;
    PCHAR objectName;
    ULONG messageLength;
    ULONG driverNameLength;
    ULONG deviceNameLength;
    ULONG objectNameLength;
    ULONG remainingLength;
    ULONG stringLength;
    CHAR nameBuffer[IO_ERROR_NAME_LENGTH+sizeof( OBJECT_NAME_INFORMATION )];
    PDRIVER_OBJECT driverObject;
    POBJECT_NAME_INFORMATION nameInformation;
    PIO_ERROR_LOG_PACKET errorData;
    PWSTR string;

    PAGED_CODE();

    UNREFERENCED_PARAMETER( StartContext );

    //
    // Check to see whether a connection has been made to the error log
    // port.  If the port is not connected return.
    //

    if (!IopErrorLogConnectPort()) {

        //
        // The port could not be connected.  A timer was started that will
        // try again later.
        //

        return;
    }

    //
    // Allocate and zero the port message structure, include space for the
    // name of the device and driver.
    //

    messageLength = IO_ERROR_LOG_MESSAGE_LENGTH;
    portMessage = ExAllocatePool(PagedPool, messageLength);

    if (portMessage == NULL) {

        //
        // The message buffer could not be allocated. Request that
        // the error log thread routine be called again later.
        //

        IopErrorLogQueueRequest();
        return;
    }

    RtlZeroMemory( portMessage, sizeof( *portMessage ) );
    portMessage->MessageType = IO_ERROR_LOG;
    errorMessage = &portMessage->u.IoErrorLogMessage;

    nameInformation = (PVOID) &nameBuffer;

    //
    // Now enter the main loop for this thread.  This thread performs the
    // following operations:
    //
    //   1)  If a connection has been made to the error log port, dequeue a
    //       packet from the queue head and attempt to send it to the port.
    //
    //   2)  If the send works, loop sending packets until there are no more
    //       packets;  otherwise, indicate that the connection has been broken,
    //       cleanup, place the packet back onto the head of the queue and
    //       return.
    //
    //   3)  After all the packets are sent clear the pending variable and
    //       return.
    //

    for (;;) {

        //
        // Loop dequeueing  packets from the queue head and attempt to send
        // each to the port.
        //
        // If the send works, continue looping until there are no more packets.
        // Otherwise, indicate that the connection has been broken, cleanup,
        // place the packet back onto the head of the queue, and start from the
        // top of the loop again.
        //

        if (!(listEntry = IopErrorLogGetEntry())) {
            break;
        }

        errorLogEntry = CONTAINING_RECORD( listEntry,
                                           ERROR_LOG_ENTRY,
                                           ListEntry );

        //
        // The size of errorLogEntry is ERROR_LOG_ENTRY +
        // IO_ERROR_LOG_PACKET + (Extra Dump data).  The size of the
        // initial message length should be IO_ERROR_LOG_MESSAGE +
        // (Extra Dump data), since IO_ERROR_LOG_MESSAGE contains an
        // IO_ERROR_LOG_PACKET. Using the above calculations set the
        // message length.
        //

        messageLength = sizeof( IO_ERROR_LOG_MESSAGE ) -
            sizeof( ERROR_LOG_ENTRY ) - sizeof( IO_ERROR_LOG_PACKET ) +
            errorLogEntry->Size;

        errorData = (PIO_ERROR_LOG_PACKET) (errorLogEntry + 1);

        //
        // Copy the error log packet and the extra data to the message.
        //

        RtlMoveMemory( &errorMessage->EntryData,
                       errorData,
                       errorLogEntry->Size - sizeof( ERROR_LOG_ENTRY ) );

        errorMessage->TimeStamp = errorLogEntry->TimeStamp;
        errorMessage->Type = IO_TYPE_ERROR_MESSAGE;

        //
        // Add the driver and device name string.  These strings go
        // before the error log strings.  Just write over the current
        // strings and they will be recopied later.
        //

        if (errorData->NumberOfStrings != 0) {

            //
            // Start the driver and device strings where the current
            // strings start.
            //

            objectName = (PCHAR) (&errorMessage->EntryData) +
                                 errorData->StringOffset;

        } else {

            //
            // Put the driver and device strings at the end of the
            // data.
            //

            objectName = (PCHAR) errorMessage + messageLength;

        }

        //
        // Make sure the driver offset starts on an even bountry.
        //

        objectName = (PCHAR) ((ULONG_PTR) (objectName + sizeof(WCHAR) - 1) &
            ~(ULONG_PTR)(sizeof(WCHAR) - 1));

        errorMessage->DriverNameOffset = (ULONG)(objectName - (PCHAR) errorMessage);

        remainingLength = (ULONG)((PCHAR) portMessage + IO_ERROR_LOG_MESSAGE_LENGTH
                            - objectName);

        //
        // Calculate the length of the driver name and
        // the device name. If the driver object has a name then get
        // it from there; otherwise try to query the device object.
        //

        driverObject = errorLogEntry->DriverObject;
        driverNameLength = 0;

        if (driverObject != NULL) {
            if (driverObject->DriverName.Buffer != NULL) {

                nameString.Buffer = driverObject->DriverName.Buffer;
                driverNameLength = driverObject->DriverName.Length;
            }

            if (driverNameLength == 0) {

                //
                // Try to query the driver object for a name.
                //

                status = ObQueryNameString( driverObject,
                                            nameInformation,
                                            IO_ERROR_NAME_LENGTH + sizeof( OBJECT_NAME_INFORMATION ),
                                            &objectNameLength );

                if (!NT_SUCCESS( status ) || !nameInformation->Name.Length) {

                    //
                    // No driver name was available.
                    //

                    driverNameLength = 0;

                } else {
                    nameString = nameInformation->Name;
                }

            }

        } else {

            //
            // If no driver object, this message must be from the 
            // kernel.   We need to point the eventlog service to
            // an event message file containing ntstatus messages,
            // ie, ntdll, we do this by claiming this event is an
            // application popup.
            //

            nameString.Buffer = L"Application Popup";
            driverNameLength = wcslen(nameString.Buffer) * sizeof(WCHAR);
        }

        if (driverNameLength != 0 ) {

            //
            // Pick out the module name.
            //

            string = nameString.Buffer +
                (driverNameLength / sizeof(WCHAR));

            driverNameLength = sizeof(WCHAR);
            string--;
            while (*string != L'\\' && string != nameString.Buffer) {
                string--;
                driverNameLength += sizeof(WCHAR);
            }

            if (*string == L'\\') {
                string++;
                driverNameLength -= sizeof(WCHAR);
            }

            //
            // Ensure there is enough room for the driver name.
            // Save space for 3 NULLs one for the driver name,
            // one for the device name and one for strings.
            //

            if (driverNameLength > remainingLength - (3 * sizeof(WCHAR))) {
                driverNameLength = remainingLength - (3 * sizeof(WCHAR));
            }

            RtlMoveMemory(
                objectName,
                string,
                driverNameLength
                );

        }

        //
        // Add a null after the driver name even if there is no
        // driver name.
        //

       *((PWSTR) (objectName + driverNameLength)) = L'\0';
       driverNameLength += sizeof(WCHAR);

        //
        // Determine where the next string goes.
        //

        objectName += driverNameLength;
        remainingLength -= driverNameLength;

        errorMessage->EntryData.StringOffset = (USHORT)(objectName - (PCHAR) errorMessage);

        if (errorLogEntry->DeviceObject != NULL) {

            status = ObQueryNameString( errorLogEntry->DeviceObject,
                                        nameInformation,
                                        IO_ERROR_NAME_LENGTH + sizeof( OBJECT_NAME_INFORMATION ) - driverNameLength,
                                        &objectNameLength );

            if (!NT_SUCCESS( status ) || !nameInformation->Name.Length) {

                //
                // No device name was available. Add a Null string.
                //

                nameInformation->Name.Length = 0;
                nameInformation->Name.Buffer = L"\0";

            }

            //
            // No device name was available. Add a Null string.
            // Always add a device name string so that the
            // insertion string counts are correct.
            //

        } else {

                //
                // No device name was available. Add a Null string.
                // Always add a device name string so that the
                // insertion string counts are correct.
                //

                nameInformation->Name.Length = 0;
                nameInformation->Name.Buffer = L"\0";

        }

        deviceNameLength = nameInformation->Name.Length;

        //
        // Ensure there is enough room for the device name.
        // Save space for a NULL.
        //

        if (deviceNameLength > remainingLength - (2 * sizeof(WCHAR))) {

            deviceNameLength = remainingLength - (2 * sizeof(WCHAR));

        }

        RtlMoveMemory( objectName,
                       nameInformation->Name.Buffer,
                       deviceNameLength );

        //
        // Add a null after the device name even if there is no
        // device name.
        //

        *((PWSTR) (objectName + deviceNameLength)) = L'\0';
        deviceNameLength += sizeof(WCHAR);

        //
        // Update the string count for the device object.
        //

        errorMessage->EntryData.NumberOfStrings++;
        objectName += deviceNameLength;
        remainingLength -= deviceNameLength;

        if (errorData->NumberOfStrings) {

            stringLength = errorLogEntry->Size - sizeof( ERROR_LOG_ENTRY ) -
                            errorData->StringOffset;

            //
            // Ensure there is enough room for the strings.
            // Save space for a NULL.
            //

            if (stringLength > remainingLength - sizeof(WCHAR)) {


                messageLength -= stringLength - remainingLength;
                stringLength = remainingLength - sizeof(WCHAR);

            }

            //
            // Copy the strings to the end of the message.
            //

            RtlMoveMemory( objectName,
                           (PCHAR) errorData + errorData->StringOffset,
                           stringLength );

            //
            // Add a null after the strings
            //
            //

           *((PWSTR) (objectName + stringLength)) = L'\0';

        }

        //
        // Update the message length.
        //

        errorMessage->DriverNameLength = (USHORT) driverNameLength;
        messageLength += deviceNameLength + driverNameLength;
        errorMessage->Size = (USHORT) messageLength;

        messageLength += FIELD_OFFSET ( ELF_PORT_MSG, u ) -
            FIELD_OFFSET (ELF_PORT_MSG, MessageType);

        portMessage->PortMessage.u1.s1.TotalLength = (USHORT)
            (sizeof( PORT_MESSAGE ) + messageLength);
        portMessage->PortMessage.u1.s1.DataLength = (USHORT) (messageLength);
        status = NtRequestPort( ErrorLogPort, (PPORT_MESSAGE) portMessage );

        if (!NT_SUCCESS( status )) {

            //
            // The send failed.  Place the packet back onto the head of
            // the error log queue, forget the current connection since
            // it no longer works, and close the handle to the port.
            // Set a timer up for another attempt later.
            // Finally, exit the loop since there is no connection
            // to do any work on.
            //

            NtClose( ErrorLogPort );

            IopErrorLogRequeueEntry( &errorLogEntry->ListEntry );

            IopErrorLogQueueRequest();

            break;

        } else {

            //
            // The send worked fine.  Free the packet and the update
            // the allocation count.
            //

            ExInterlockedAddUlong( &IopErrorLogAllocation,
                                   (ULONG) ( -errorLogEntry->Size ),
                                   &IopErrorLogAllocationLock );

            //
            // Dereference the object pointers now that the name has been
            // captured.
            //


            if (errorLogEntry->DeviceObject != NULL) {
                ObDereferenceObject( errorLogEntry->DeviceObject );
            }

            if (driverObject != NULL) {
                ObDereferenceObject( errorLogEntry->DriverObject );
            }

            ExFreePool( errorLogEntry );

        } // if

    } // for

    //
    // Finally, free the message buffer and return.
    //

    ExFreePool(portMessage);

}