Ejemplo n.º 1
0
VOID
SrvCloseCachedDirectoryEntries(
    IN PCONNECTION Connection
)
/*++
Routine Description:

    This routine closes all the cached directory entries on the connection

Arguments:

    Connection - Pointer to the connection structure having the cache

++*/
{
    KIRQL oldIrql;
    PCACHED_DIRECTORY cd;

    ACQUIRE_SPIN_LOCK( &Connection->SpinLock, &oldIrql );

    while( Connection->CachedDirectoryCount > 0 ) {

        cd = CONTAINING_RECORD( Connection->CachedDirectoryList.Flink, CACHED_DIRECTORY, ListEntry );

        RemoveEntryList( &cd->ListEntry );

        Connection->CachedDirectoryCount--;

        DEALLOCATE_NONPAGED_POOL( cd );
    }

    RELEASE_SPIN_LOCK( &Connection->SpinLock, oldIrql );
}
Ejemplo n.º 2
0
VOID
SrvFreeEndpoint (
    IN PENDPOINT Endpoint
    )

/*++

Routine Description:

    This function returns an Endpoint Block to the system nonpaged pool.

Arguments:

    Endpoint - Address of endpoint

Return Value:

    None.

--*/

{
    PAGED_CODE( );

    DEBUG SET_BLOCK_TYPE_STATE_SIZE( Endpoint, BlockTypeGarbage, BlockStateDead, -1 );
    DEBUG Endpoint->BlockHeader.ReferenceCount = (ULONG)-1;
    TERMINATE_REFERENCE_HISTORY( Endpoint );

    if ( Endpoint->IpxMaxPacketSizeArray != NULL ) {
        FREE_HEAP( Endpoint->IpxMaxPacketSizeArray );
    }

    if ( Endpoint->ConnectionTable.Table != NULL ) {
        SrvFreeTable( &Endpoint->ConnectionTable );
    }

    DEALLOCATE_NONPAGED_POOL( Endpoint );
    IF_DEBUG(HEAP) SrvPrint1( "SrvFreeEndpoint: Freed endpoint block at %lx\n", Endpoint );

    INCREMENT_DEBUG_STAT( SrvDbgStatistics.EndpointInfo.Frees );

    return;

} // SrvFreeEndpoint
Ejemplo n.º 3
0
NOT PAGEABLE -- WalkConnectionTable
#endif


VOID
SrvAllocateEndpoint (
    OUT PENDPOINT *Endpoint,
    IN PUNICODE_STRING NetworkName,
    IN PUNICODE_STRING TransportName,
    IN PANSI_STRING TransportAddress,
    IN PUNICODE_STRING DomainName
    )

/*++

Routine Description:

    This function allocates an Endpoint Block from the system nonpaged
    pool.

Arguments:

    Endpoint - Returns a pointer to the endpoint block, or NULL if no
        pool was available.

    NetworkName - Supplies a pointer to the network name (e.g., NET1).

    TransportName - The fully qualified name of the transport device.
        For example, "\Device\Nbf".

    TransportAddress - The fully qualified address (or name ) of the
        server's endpoint.  This name is used exactly as specified.  For
        NETBIOS-compatible networks, the caller must upcase and
        blank-fill the name.  E.g., "\Device\Nbf\NTSERVERbbbbbbbb".

    DomainName - the domain being serviced by this endpoint

Return Value:

    None.

--*/

{
    CLONG length;
    PENDPOINT endpoint;
    NTSTATUS status;

    PAGED_CODE( );

    //
    // Attempt to allocate from nonpaged pool.
    //

    length = sizeof(ENDPOINT) +
                NetworkName->Length + sizeof(*NetworkName->Buffer) +
                TransportName->Length + sizeof(*TransportName->Buffer) +
                TransportAddress->Length + sizeof(*TransportAddress->Buffer) +
                DomainName->Length + sizeof(*DomainName->Buffer) +
                RtlUnicodeStringToOemSize( DomainName ) + sizeof(CHAR);

    endpoint = ALLOCATE_NONPAGED_POOL( length, BlockTypeEndpoint );
    *Endpoint = endpoint;

    if ( endpoint == NULL ) {

        INTERNAL_ERROR (
            ERROR_LEVEL_EXPECTED,
            "SrvAllocateEndpoint: Unable to allocate %d bytes from nonpaged "
                "pool.",
            length,
            NULL
            );

        return;
    }

    IF_DEBUG(HEAP) {
        SrvPrint1( "SrvAllocateEndpoint: Allocated endpoint at %lx\n",
                    endpoint );
    }

    //
    // Initialize the endpoint block.  Zero it first.
    //

    RtlZeroMemory( endpoint, length );

    SET_BLOCK_TYPE_STATE_SIZE( endpoint, BlockTypeEndpoint, BlockStateActive, length );
    endpoint->BlockHeader.ReferenceCount = 2;       // allow for Active status
                                                    //  and caller's pointer

    //
    // Allocate connection table.
    //

    SrvAllocateTable(
        &endpoint->ConnectionTable,
        6, // !!!
        TRUE
        );
    if ( endpoint->ConnectionTable.Table == NULL ) {
        DEALLOCATE_NONPAGED_POOL( endpoint );
        *Endpoint = NULL;
        return;
    }

    InitializeListHead( &endpoint->FreeConnectionList );
#if SRVDBG29
    UpdateConnectionHistory( "INIT", endpoint, NULL );
#endif

    //
    // Copy the network name, transport name, and server address, and domain
    // name into the block.
    //

    endpoint->NetworkName.Length = NetworkName->Length;
    endpoint->NetworkName.MaximumLength =
            (SHORT)(NetworkName->Length + sizeof(*NetworkName->Buffer));
    endpoint->NetworkName.Buffer = (PWCH)(endpoint + 1);
    RtlCopyMemory(
        endpoint->NetworkName.Buffer,
        NetworkName->Buffer,
        NetworkName->Length
        );

    endpoint->TransportName.Length = TransportName->Length;
    endpoint->TransportName.MaximumLength =
            (SHORT)(TransportName->Length + sizeof(*TransportName->Buffer));
    endpoint->TransportName.Buffer =
                            (PWCH)((PCHAR)endpoint->NetworkName.Buffer +
                                    endpoint->NetworkName.MaximumLength);
    RtlCopyMemory(
        endpoint->TransportName.Buffer,
        TransportName->Buffer,
        TransportName->Length
        );

    endpoint->TransportAddress.Length = TransportAddress->Length;
    endpoint->TransportAddress.MaximumLength =
                                (SHORT)(TransportAddress->Length + 1);
    endpoint->TransportAddress.Buffer =
                            (PCHAR)endpoint->TransportName.Buffer +
                                    endpoint->TransportName.MaximumLength;
    RtlCopyMemory(
        endpoint->TransportAddress.Buffer,
        TransportAddress->Buffer,
        TransportAddress->Length
        );


    endpoint->DomainName.Length = DomainName->Length;
    endpoint->DomainName.MaximumLength = 
            (SHORT)(DomainName->Length + sizeof(*DomainName->Buffer));
    endpoint->DomainName.Buffer = (PWCH)((PCHAR)endpoint->TransportAddress.Buffer +
                                         TransportAddress->MaximumLength);
    RtlCopyMemory(
        endpoint->DomainName.Buffer,
        DomainName->Buffer,
        DomainName->Length
    );


    endpoint->OemDomainName.Length = (SHORT)RtlUnicodeStringToOemSize( DomainName );
    endpoint->OemDomainName.MaximumLength =
            endpoint->OemDomainName.Length + sizeof( CHAR );
    endpoint->OemDomainName.Buffer = (PCHAR)endpoint->DomainName.Buffer +
                                     DomainName->MaximumLength;
    status = RtlUnicodeStringToOemString(
                &endpoint->OemDomainName,
                &endpoint->DomainName,
                FALSE     // Do not allocate the OEM string
                );
    ASSERT( NT_SUCCESS(status) );
            

    //
    // Initialize the network address field.
    //

    endpoint->NetworkAddress.Buffer = endpoint->NetworkAddressData;
    endpoint->NetworkAddress.Length = sizeof( endpoint->NetworkAddressData ) -
                                      sizeof(endpoint->NetworkAddressData[0]);
    endpoint->NetworkAddress.MaximumLength = sizeof( endpoint->NetworkAddressData );

    //
    // Increment the count of endpoints in the server.
    //

    ACQUIRE_LOCK( &SrvEndpointLock );
    SrvEndpointCount++;
    RELEASE_LOCK( &SrvEndpointLock );

    INITIALIZE_REFERENCE_HISTORY( endpoint );

    INCREMENT_DEBUG_STAT( SrvDbgStatistics.EndpointInfo.Allocations );

    return;

} // SrvAllocateEndpoint
Ejemplo n.º 4
0
VOID
SrvRemoveCachedDirectoryName(
    IN PWORK_CONTEXT    WorkContext,
    IN PUNICODE_STRING  DirectoryName
)
{
    PLIST_ENTRY listEntry;
    PCACHED_DIRECTORY cd;
    ULONG directoryNameHashValue;
    PCONNECTION connection = WorkContext->Connection;
    KIRQL oldIrql;
    USHORT tid;

    if( connection->CachedDirectoryCount == 0 ) {
        return;
    }

    //
    // DirectoryName must point to memory in nonpaged pool, else we can't touch
    //   it under spinlock control.  If the incomming SMB is UNICODE, we know that
    //   the name is in the smb buffer, and is therefore in nonpaged pool.  Otherwise
    //   we can't trust it and we're better off just not trying to cache it.
    //
    if( !SMB_IS_UNICODE( WorkContext ) ) {
        return;
    }

    COMPUTE_STRING_HASH( DirectoryName, &directoryNameHashValue );

    tid = WorkContext->TreeConnect->Tid;

    ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );

    for ( listEntry = connection->CachedDirectoryList.Flink;
            listEntry != &connection->CachedDirectoryList;
            listEntry = listEntry->Flink ) {

        cd = CONTAINING_RECORD( listEntry, CACHED_DIRECTORY, ListEntry );

        //
        // See if this entry is an exact match for what was requested
        //
        if( cd->DirectoryName.Length == DirectoryName->Length &&
                cd->Tid == tid &&
                RtlCompareMemory( cd->DirectoryName.Buffer, DirectoryName->Buffer,
                                  DirectoryName->Length ) == DirectoryName->Length ) {

            //
            // Remove this entry from the list and adjust the count
            //
            RemoveEntryList( &cd->ListEntry );
            connection->CachedDirectoryCount--;

            ASSERT( (LONG)connection->CachedDirectoryCount >= 0 );

            RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

            DEALLOCATE_NONPAGED_POOL( cd );

            return;
        }

    }

    RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

    return;
}
Ejemplo n.º 5
0
BOOLEAN
SrvIsDirectoryCached (
    IN  PWORK_CONTEXT     WorkContext,
    IN  PUNICODE_STRING   DirectoryName
)
{
    PLIST_ENTRY listEntry;
    PCACHED_DIRECTORY cd;
    ULONG directoryNameHashValue;
    PCONNECTION connection = WorkContext->Connection;
    KIRQL oldIrql;
    LARGE_INTEGER timeNow;

    //
    // DirectoryName must point to memory in nonpaged pool, else we can't touch
    //   it under spinlock control.  If the incomming SMB is UNICODE, we know that
    //   the name is in the smb buffer, and is therefore in nonpaged pool.  Otherwise
    //   we can't trust it and we're better off just not trying to cache it.
    //

    if( connection->CachedDirectoryCount == 0 || !SMB_IS_UNICODE( WorkContext ) ) {
        return FALSE;
    }

    KeQueryTickCount( &timeNow );
    timeNow.LowPart -= (SrvFiveSecondTickCount >> 1 );

    ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );

top:
    for ( listEntry = connection->CachedDirectoryList.Flink;
            listEntry != &connection->CachedDirectoryList;
            listEntry = listEntry->Flink ) {

        cd = CONTAINING_RECORD( listEntry, CACHED_DIRECTORY, ListEntry );

        //
        // Is this element too old?
        //
        if( cd->TimeStamp < timeNow.LowPart ) {
            //
            // This element is more than 2.5 seconds old.  Toss it out
            //
            RemoveEntryList( listEntry );
            connection->CachedDirectoryCount--;
            DEALLOCATE_NONPAGED_POOL( cd );
            goto top;
        }

        if( cd->Tid != WorkContext->TreeConnect->Tid ) {
            continue;
        }

        //
        // Is the requested entry a subdir of this cache entry?
        //
        if( DirectoryName->Length < cd->DirectoryName.Length &&
                RtlCompareMemory( DirectoryName->Buffer, cd->DirectoryName.Buffer,
                                  DirectoryName->Length ) == DirectoryName->Length &&
                cd->DirectoryName.Buffer[ DirectoryName->Length / sizeof( WCHAR ) ] == L'\\' ) {

            RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

            return TRUE;

            //
            // Not a subdir -- is it an exact match?
            //
        } else  if( DirectoryName->Length == cd->DirectoryName.Length &&
                    RtlCompareMemory( cd->DirectoryName.Buffer, DirectoryName->Buffer,
                                      DirectoryName->Length ) == DirectoryName->Length ) {

            RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
            return TRUE;
        }
    }

    RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

    return FALSE;
}
Ejemplo n.º 6
0
VOID
SrvCacheDirectoryName (
    IN  PWORK_CONTEXT      WorkContext,
    IN  PUNICODE_STRING    DirectoryName
)
/*++

Routine Description:

    This routine remembers 'DirectoryName' for further fast processing of the CheckPath SMB

Arguments:

    WorkContext - Pointer to the work context block

    DirectoryName - Fully canonicalized name of the directory we're caching

++*/

{
    CLONG blockLength;
    PCACHED_DIRECTORY cd;
    KIRQL oldIrql;
    PCONNECTION connection = WorkContext->Connection;
    PLIST_ENTRY listEntry;
    LARGE_INTEGER timeNow;
    USHORT tid;

    if( SrvMaxCachedDirectory == 0 ) {
        return;
    }

    //
    // DirectoryName must point to memory in nonpaged pool, else we can't touch
    //   it under spinlock control.  If the incomming SMB is UNICODE, we know that
    //   the name is in the smb buffer, and is therefore in nonpaged pool.  Otherwise
    //   we can't trust it and we're better off just not trying to cache it.
    //
    if( !SMB_IS_UNICODE( WorkContext ) ) {
        return;
    }

    KeQueryTickCount( &timeNow );
    timeNow.LowPart -= ( SrvFiveSecondTickCount >> 1 );

    tid = WorkContext->TreeConnect->Tid;

    ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );

    //
    // Search the directory cache and see if this directory is already cached. If so,
    //  don't cache it again.
    //

top:
    for ( listEntry = connection->CachedDirectoryList.Flink;
            listEntry != &connection->CachedDirectoryList;
            listEntry = listEntry->Flink ) {

        cd = CONTAINING_RECORD( listEntry, CACHED_DIRECTORY, ListEntry );

        //
        // Is this element too old?
        //
        if( cd->TimeStamp < timeNow.LowPart ) {
            //
            // This element is more than 2.5 seconds old.  Toss it out
            //
            RemoveEntryList( listEntry );
            connection->CachedDirectoryCount--;
            DEALLOCATE_NONPAGED_POOL( cd );
            goto top;
        }

        if( cd->Tid != tid ) {
            continue;
        }

        //
        // Is the new entry a subdir of this cache entry?
        //
        if( DirectoryName->Length < cd->DirectoryName.Length &&
                RtlCompareMemory( DirectoryName->Buffer, cd->DirectoryName.Buffer,
                                  DirectoryName->Length ) == DirectoryName->Length &&
                cd->DirectoryName.Buffer[ DirectoryName->Length / sizeof( WCHAR ) ] == L'\\' ) {

            //
            // It is a subdir -- no need to cache it again
            //
            RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

            return;
        }

        //
        // Is the cache entry a subdir of the new entry?
        //
        if( cd->DirectoryName.Length < DirectoryName->Length &&
                RtlCompareMemory( DirectoryName->Buffer, cd->DirectoryName.Buffer,
                                  cd->DirectoryName.Length ) == cd->DirectoryName.Length &&
                DirectoryName->Buffer[ cd->DirectoryName.Length / sizeof( WCHAR ) ] == L'\\' ) {

            //
            // We can remove this entry
            //

            RemoveEntryList( listEntry );
            connection->CachedDirectoryCount--;
            DEALLOCATE_NONPAGED_POOL( cd );

            //
            // We want to cache this new longer entry
            //
            break;
        }

        //
        // Not a subdir -- is it an exact match?
        //
        if( cd->DirectoryName.Length == DirectoryName->Length &&
                RtlCompareMemory( cd->DirectoryName.Buffer, DirectoryName->Buffer,
                                  DirectoryName->Length ) == DirectoryName->Length ) {

            //
            // This entry is already in the cache -- no need to recache
            //
            RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
            return;
        }
    }

    //
    // This directory name is not already in the cache.  So add it.
    //

    blockLength = sizeof( CACHED_DIRECTORY ) + DirectoryName->Length + sizeof(WCHAR);

    cd = ALLOCATE_NONPAGED_POOL( blockLength, BlockTypeCachedDirectory );

    if( cd == NULL ) {

        RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

        INTERNAL_ERROR(
            ERROR_LEVEL_EXPECTED,
            "SrvCacheDirectoryName: Unable to allocate %d bytes from pool",
            blockLength,
            NULL
        );

        return;
    }

    cd->Type = BlockTypeCachedDirectory;
    cd->State = BlockStateActive;
    cd->Size = (USHORT)blockLength;
    // cd->ReferenceCount = 1;              // not used

    //
    // Set the timestamp of this entry.  Remember, we subtracted
    //  ticks up above from timeNow -- put them back in now.
    //
    cd->TimeStamp = timeNow.LowPart + ( SrvFiveSecondTickCount >> 1 );

    //
    // Store the directory name as it was passed into us
    //
    cd->DirectoryName.Length = DirectoryName->Length;
    cd->DirectoryName.MaximumLength = (USHORT)DirectoryName->MaximumLength;
    cd->DirectoryName.Buffer = (PWCH)(cd + 1);
    RtlCopyMemory( cd->DirectoryName.Buffer, DirectoryName->Buffer, DirectoryName->Length );

    cd->Tid = tid;

    InsertHeadList(
        &connection->CachedDirectoryList,
        &cd->ListEntry
    );

    //
    // Check the number of elements in the cache.  If getting too large, close oldest one.
    //
    if( connection->CachedDirectoryCount++ < SrvMaxCachedDirectory ) {
        RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
        return;
    }

    //
    // Remove the last entry from the cache
    //
    cd = CONTAINING_RECORD(
             connection->CachedDirectoryList.Blink,
             CACHED_DIRECTORY,
             ListEntry
         );

    RemoveEntryList( &cd->ListEntry );
    connection->CachedDirectoryCount--;

    RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );

    DEALLOCATE_NONPAGED_POOL( cd );

    return;
}