Exemplo n.º 1
0
int
WSPAPI
WSPSendDisconnect (
    SOCKET Handle,
    LPWSABUF lpOutboundDisconnectData,
    LPINT lpErrno
    )

/*++

Routine Description:

    This routine is used on connection-oriented sockets to disable
    transmission, and to initiate termination of the connection along with the
    transmission of disconnect data, if any.

    After this routine has been successfully issued, subsequent sends are
    disallowed.

    lpOutboundDisconnectData, if not NULL, points to a buffer containing the
    outgoing disconnect data to be sent to the remote party.

    Note that WSPSendDisconnect() does not close the socket, and resources
    attached to the socket will not be freed until WSPCloseSocket() is invoked.

    WSPSendDisconnect() does not block regardless of the SO_LINGER setting on
    the socket.

    A WinSock SPI client should not rely on being able to re-use a socket after
    it has been WSPSendDisconnect()ed. In particular, a WinSock provider is not
    required to support the use of WSPConnect() on such a socket.

Arguments:

    s - A descriptor identifying a socket.

    lpOutboundDisconnectData - A pointer to the outgoing disconnect data.

    lpErrno - A pointer to the error code.

Return Value:

    If no error occurs, WSPSendDisconnect() returns 0. Otherwise, a value of
        SOCKET_ERROR is returned, and a specific error code is available in
        lpErrno.

--*/

{

    NTSTATUS status;
	PWINSOCK_TLS_DATA	tlsData;
    PSOCKET_INFORMATION socket;
    IO_STATUS_BLOCK ioStatusBlock;
    int err;
    AFD_PARTIAL_DISCONNECT_INFO disconnectInfo;

    WS_ENTER( "WSPSendDisconnect", (PVOID)Handle, (PVOID)lpOutboundDisconnectData, NULL, NULL );

    WS_ASSERT( lpErrno != NULL );

    err = SockEnterApi( &tlsData );

    if( err != NO_ERROR ) {

        WS_EXIT( "WSPSendDisconnect", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    //
    // Set up locals so that we know how to clean up on exit.
    //

    socket = NULL;

    //
    // Find a pointer to the socket structure corresponding to the
    // passed-in handle.
    //

    socket = SockFindAndReferenceSocket( Handle, TRUE );

    if ( socket == NULL ) {

        err = WSAENOTSOCK;
        goto exit;

    }

    //
    // Acquire the lock that protect this socket.
    //

    SockAcquireSocketLockExclusive( socket );

    //
    // If this is not a datagram socket, then it must be connected in order
    // for WSPSendDisconnect() to be a legal operation.
    //

    if ( !IS_DGRAM_SOCK(socket) &&
             !SockIsSocketConnected( socket ) ) {

        err = WSAENOTCONN;
        goto exit;

    }

#ifdef _AFD_SAN_SWITCH_
	//
	// Handle SAN disconnect first
	//
	if (SockSanEnabled && socket->SanSocket &&
		socket->SanSocket->IsConnected == CONNECTED) {

		socket->SendShutdown = TRUE;

		SockSanShutdown(socket, SD_SEND);

		goto exit;
	}
#endif //_AFD_SAN_SWITCH_

    //
    // Setup the disconnect info.
    //

    disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_SEND;
    disconnectInfo.Timeout = RtlConvertLongToLargeInteger( -1 );

    // !!! temporary HACK for tp4!

    if( socket->AddressFamily == AF_OSI ) {

        disconnectInfo.DisconnectMode = AFD_ABORTIVE_DISCONNECT;

    }

    __try {
        if( lpOutboundDisconnectData != NULL &&
            lpOutboundDisconnectData->buf != NULL &&
            lpOutboundDisconnectData->len > 0 ) {

            INT bufferLength;

            //
            // Set the disconnect data on the socket.
            //

            bufferLength = (INT)lpOutboundDisconnectData->len;

            err = SockSetConnectData(
                      socket,
                      IOCTL_AFD_SET_DISCONNECT_DATA,
                      (PCHAR)lpOutboundDisconnectData->buf,
                      bufferLength,
                      &bufferLength
                      );

            if( err != NO_ERROR ) {

                goto exit;

            }

        }
    }
    __except (SOCK_EXCEPTION_FILTER()) {
        err = WSAEFAULT;
        goto exit;
    }

    //
    // Note in the socket state that sends are shutdown.
    //

    socket->SendShutdown = TRUE;

    IF_DEBUG(SHUTDOWN) {

        WS_PRINT(( "starting WSPSendDisconnect for socket %lx\n", Handle ));

    }

    //
    // Send the IOCTL to AFD for processing.
    //

    status = NtDeviceIoControlFile(
                 socket->HContext.Handle,
                 tlsData->EventHandle,
                 NULL,                      // APC Routine
                 NULL,                      // APC Context
                 &ioStatusBlock,
                 IOCTL_AFD_PARTIAL_DISCONNECT,
                 &disconnectInfo,
                 sizeof(disconnectInfo),
                 NULL,                      // OutputBuffer
                 0L                         // OutputBufferLength
                 );

    if ( status == STATUS_PENDING ) {

        SockReleaseSocketLock( socket );
        SockWaitForSingleObject(
            tlsData->EventHandle,
            Handle,
            SOCK_NEVER_CALL_BLOCKING_HOOK,
            SOCK_NO_TIMEOUT
            );
        SockAcquireSocketLockExclusive( socket );
        status = ioStatusBlock.Status;

    }

    if ( !NT_SUCCESS(status) ) {

        err = SockNtStatusToSocketError( status );
        goto exit;

    }

    //
    // Notify the helper DLL that the socket has been shut down.
    //

    err = SockNotifyHelperDll( socket, WSH_NOTIFY_SHUTDOWN_SEND );

    if ( err != NO_ERROR ) {

        goto exit;

    }

exit:

    IF_DEBUG(SHUTDOWN) {

        if ( err != NO_ERROR ) {

            WS_PRINT(( "WSPSendDisconnect() on socket %lx (%lx) failed: %ld.\n",
                           Handle, socket, err ));

        } else {

            WS_PRINT(( "WSPSendDisconnect() on socket %lx (%lx) succeeded.\n",
                           Handle, socket ));

        }

    }

    if ( socket != NULL ) {

        SockReleaseSocketLock( socket );
        SockDereferenceSocket( socket );

    }

    if ( err != NO_ERROR ) {

        WS_EXIT( "WSPSendDisconnect", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    WS_EXIT( "WSPSendDisconnect", NO_ERROR, FALSE );
    return NO_ERROR;

}   // WSPSendDisconnect
Exemplo n.º 2
0
BOOLEAN DiskDriveQueryImminentFailure(
    _In_ HANDLE DeviceHandle,
    _Out_ PPH_LIST* DiskSmartAttributes
    )
{
    IO_STATUS_BLOCK isb;
    STORAGE_PREDICT_FAILURE storagePredictFailure;

    memset(&storagePredictFailure, 0, sizeof(STORAGE_PREDICT_FAILURE));

    // * IOCTL_STORAGE_PREDICT_FAILURE returns an opaque 512-byte vendor-specific information block, which
    //      in all cases contains SMART attribute information (2 bytes header + 12 bytes each attribute).
    // * This works without admin rights but doesn't support other features like logs and self-tests.
    // * It works for (S)ATA devices but not for USB.

    if (NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_PREDICT_FAILURE, // https://msdn.microsoft.com/en-us/library/ff560587.aspx
        NULL,
        0,
        &storagePredictFailure,
        sizeof(storagePredictFailure)
        )))
    {
        PPH_LIST diskAttributeList;
        //USHORT structureVersion = (USHORT)(storagePredictFailure.VendorSpecific[0] * 256 + storagePredictFailure.VendorSpecific[1]);
        //USHORT majorVersion = HIBYTE(structureVersion);
        //USHORT minorVersion = LOBYTE(structureVersion);
        //TODO: include storagePredictFailure.PredictFailure;

        diskAttributeList = PhCreateList(30);

        //An attribute is a one-byte value ranging from 1 to 253 (FDh).
        //The initial default value is 100 (64h).
        //The value and the intertretation of the value are vendor-specific.
        //Attribute values are read-only to the host.
        //A device may report up to 30 attributes to the host.
        //Values of 00h, FEh and FFh are invalid.
        //When attribute values are updated by the device depends on the specific attribute. Some are updated as
        //the disk operates, some are only updated during SMART self-tests, or at special events like power-on or
        //unloading the heads of a disk drive, etc

        //Each attribute may have an associated threshhold. When the value exceeds the threshhold, the attribute
        //triggers a SMART ‘threshhold exceeded’ event. This event indicates that either the disk is expected to fail
        //in less than 24 hours or it has exceeded its design or usage lifetime.
        //When an attribute value is greater than or equal to the threshhold, the threshhold is considered to be
        //exceeded. A flag is set indicating that failure is likely.
        //There is no standard way for a host to read or change attribute threshholds.
        //See the SMART(RETURN STATUS) command for information about how a device reports that a
        //threshhold has been exceeded.
        // TODO: Query Threshholds.

        for (UCHAR i = 0; i < 30; ++i)
        {
            PSMART_ATTRIBUTE attribute = (PSMART_ATTRIBUTE)(storagePredictFailure.VendorSpecific + i * sizeof(SMART_ATTRIBUTE) + SMART_HEADER_SIZE);

            // Attribute values 0x00, 0xFE, 0xFF are invalid.
            // There is no requirement that attributes be in any particular order.
            if (
                attribute->Id != 0x00 &&
                attribute->Id != 0xFE &&
                attribute->Id != 0xFF
                )
            {
                PSMART_ATTRIBUTES info = PhAllocate(sizeof(SMART_ATTRIBUTES));
                memset(info, 0, sizeof(SMART_ATTRIBUTES));

                info->AttributeId = attribute->Id;
                info->CurrentValue = attribute->CurrentValue;
                info->WorstValue = attribute->WorstValue;

                // TODO: These flag offsets might be off-by-one.
                info->Advisory = (attribute->Flags & 0x1) == 0x0;
                info->FailureImminent = (attribute->Flags & 0x1) == 0x1;
                info->OnlineDataCollection = (attribute->Flags & 0x2) == 0x2;
                info->Performance = (attribute->Flags & 0x3) == 0x3;
                info->ErrorRate = (attribute->Flags & 0x4) == 0x4;
                info->EventCount = (attribute->Flags & 0x5) == 0x5;
                info->SelfPreserving = (attribute->Flags & 0x6) == 0x6;

                info->RawValue = MAKELONG(
                    MAKEWORD(attribute->RawValue[0], attribute->RawValue[1]),
                    MAKEWORD(attribute->RawValue[2], attribute->RawValue[3])
                    );
                // Missing 2 raw values.

                PhAddItemList(diskAttributeList, info);
            }
        }

        *DiskSmartAttributes = diskAttributeList;

        return TRUE;
    }

    return FALSE;
}
Exemplo n.º 3
0
int
WSPAPI
WSPShutdown(
    IN SOCKET Handle,
    IN int HowTo,
    OUT LPINT lpErrno
    )

/*++

Routine Description:

    This routine is used on all types of sockets to disable reception,
    transmission, or both.

    If how is SD_RECEIVE, subsequent receives on the socket will be
    disallowed. This has no effect on the lower protocol layers. For TCP
    sockets, if there is still data queued on the socket waiting to be
    received, or data arrives subsequently, the connection is reset, since the
    data cannot be delivered to the user. For UDP sockets, incoming datagrams
    are accepted and queued. In no case will an ICMP error packet
    be generated.

    If how is SD_SEND, subsequent sends on the socket are disallowed. For TCP
    sockets, a FIN will be sent. Setting how to SD_BOTH disables both sends
    and receives as described above.

    Note that WSPShutdown() does not close the socket, and resources attached
    to the socket will not be freed until WSPCloseSocket() is invoked.

    WSPShutdown() does not block regardless of the SO_LINGER setting on the
    socket. A WinSock SPI client should not rely on being able to re-use a
    socket after it has been shut down. In particular, a WinSock service
    provider is not required to support the use of WSPConnect() on such a
    socket.

Arguments:

    s - A descriptor identifying a socket.

    how - A flag that describes what types of operation will no longer be
        allowed.

    lpErrno - A pointer to the error code.

Return Value:

    If no error occurs, WSPShutdown() returns 0. Otherwise, a value of
        SOCKET_ERROR is returned, and a specific error code is available
        in lpErrno.

--*/

{

    NTSTATUS status;
	PWINSOCK_TLS_DATA	tlsData;
    PSOCKET_INFORMATION socket;
    IO_STATUS_BLOCK ioStatusBlock;
    int err;
    AFD_PARTIAL_DISCONNECT_INFO disconnectInfo;
    DWORD notificationEvent;

    WS_ENTER( "WSPShutdown", (PVOID)Handle, (PVOID)HowTo, NULL, NULL );

    WS_ASSERT( lpErrno != NULL );

    err = SockEnterApi( &tlsData );

    if( err != NO_ERROR ) {

        WS_EXIT( "WSPShutdown", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    //
    // Set up locals so that we know how to clean up on exit.
    //

    socket = NULL;

    //
    // Find a pointer to the socket structure corresponding to the
    // passed-in handle.
    //

    socket = SockFindAndReferenceSocket( Handle, TRUE );

    if ( socket == NULL ) {

        err = WSAENOTSOCK;
        goto exit;

    }

    //
    // Acquire the lock that protect this socket.
    //

    SockAcquireSocketLockExclusive( socket );

    //
    // If this is not a datagram socket, then it must be connected in order
    // for WSPShutdown() to be a legal operation.
    //

    if ( !IS_DGRAM_SOCK(socket) &&
             !SockIsSocketConnected( socket ) ) {

        err = WSAENOTCONN;
        goto exit;

    }

    //
    // Translate the How parameter into the AFD disconnect information
    // structure.
    //

    switch ( HowTo ) {

    case SD_RECEIVE:

        disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_RECEIVE;
        socket->ReceiveShutdown = TRUE;
        notificationEvent = WSH_NOTIFY_SHUTDOWN_RECEIVE;
        break;

    case SD_SEND:

        disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_SEND;
        socket->SendShutdown = TRUE;
        notificationEvent = WSH_NOTIFY_SHUTDOWN_SEND;
        break;

    case SD_BOTH:

        disconnectInfo.DisconnectMode =
            AFD_PARTIAL_DISCONNECT_RECEIVE | AFD_PARTIAL_DISCONNECT_SEND;
        socket->ReceiveShutdown = TRUE;
        socket->SendShutdown = TRUE;
        notificationEvent = WSH_NOTIFY_SHUTDOWN_ALL;
        break;

    default:

        err = WSAEINVAL;
        goto exit;

    }


#ifdef _AFD_SAN_SWITCH_
	//
	// If we have a SAN socket open, close that first
	//
	if (SockSanEnabled && socket->SanSocket &&
		socket->SanSocket->IsConnected == CONNECTED) {

		err = SockSanShutdown(socket, HowTo);
		
		goto exit;
	}
#endif //_AFD_SAN_SWITCH_


    // !!! temporary HACK for tp4!

    if ( (HowTo == 1 || HowTo == 2) && socket->AddressFamily == AF_OSI ) {

        disconnectInfo.DisconnectMode = AFD_ABORTIVE_DISCONNECT;

    }

    //
    // This routine should complete immediately, not when the remote client
    // acknowledges the disconnect.
    //

    disconnectInfo.Timeout = RtlConvertLongToLargeInteger( -1 );

    IF_DEBUG(CLOSE) {

        WS_PRINT(( "starting WSPShutdown for socket %lx\n", Handle ));

    }

    //
    // Send the IOCTL to AFD for processing.
    //

    status = NtDeviceIoControlFile(
                 socket->HContext.Handle,
                 tlsData->EventHandle,
                 NULL,                      // APC Routine
                 NULL,                      // APC Context
                 &ioStatusBlock,
                 IOCTL_AFD_PARTIAL_DISCONNECT,
                 &disconnectInfo,
                 sizeof(disconnectInfo),
                 NULL,                      // OutputBuffer
                 0L                         // OutputBufferLength
                 );

    if ( status == STATUS_PENDING ) {

        SockReleaseSocketLock( socket );
        SockWaitForSingleObject(
            tlsData->EventHandle,
            Handle,
            SOCK_NEVER_CALL_BLOCKING_HOOK,
            SOCK_NO_TIMEOUT
            );
        SockAcquireSocketLockExclusive( socket );
        status = ioStatusBlock.Status;

    }

    if ( !NT_SUCCESS(status) ) {

        err = SockNtStatusToSocketError( status );
        goto exit;

    }

    //
    // Notify the helper DLL that the socket has been shut down.
    //

    err = SockNotifyHelperDll( socket, notificationEvent );

    if ( err != NO_ERROR ) {

        goto exit;

    }

exit:

    IF_DEBUG(SHUTDOWN) {

        if ( err != NO_ERROR ) {

            WS_PRINT(( "WSPShutdown(%ld) on socket %lx (%lx) failed: %ld.\n",
                           HowTo, Handle, socket, err ));

        } else {

            WS_PRINT(( "WSPShutdown(%ld) on socket %lx (%lx) succeeded.\n",
                           HowTo, Handle, socket ));

        }

    }

    if ( socket != NULL ) {

        SockReleaseSocketLock( socket );
        SockDereferenceSocket( socket );

    }

    if ( err != NO_ERROR ) {

        WS_EXIT( "WSPShutdown", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    WS_EXIT( "WSPShutdown", NO_ERROR, FALSE );
    return NO_ERROR;

}   // WSPShutdown
Exemplo n.º 4
0
BOOLEAN DiskDriveQueryDeviceInformation(
    _In_ HANDLE DeviceHandle,
    _Out_opt_ PPH_STRING* DiskVendor,
    _Out_opt_ PPH_STRING* DiskModel,
    _Out_opt_ PPH_STRING* DiskRevision,
    _Out_opt_ PPH_STRING* DiskSerial
    )
{
    ULONG bufferLength;
    IO_STATUS_BLOCK isb;
    STORAGE_PROPERTY_QUERY query;
    PSTORAGE_DESCRIPTOR_HEADER buffer;

    query.QueryType = PropertyStandardQuery;
    query.PropertyId = StorageDeviceProperty;

    bufferLength = sizeof(STORAGE_DESCRIPTOR_HEADER);
    buffer = PhAllocate(bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    bufferLength = buffer->Size;
    buffer = PhReAllocate(buffer, bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)buffer;

    // TODO: Use the following fields:
    // STORAGE_BUS_TYPE BusType;
    // DWORD RawPropertiesLength;
    // BYTE RawDeviceProperties[1];

    if (DiskVendor && deviceDescriptor->VendorIdOffset != 0)
    {
        PPH_STRING diskVendor;

        diskVendor = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->VendorIdOffset));

        *DiskVendor = TrimString(diskVendor);
    }

    if (DiskModel && deviceDescriptor->ProductIdOffset != 0)
    {
        PPH_STRING diskModel;

        diskModel = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->ProductIdOffset));

        *DiskModel = TrimString(diskModel);
    }

    if (DiskRevision && deviceDescriptor->ProductRevisionOffset != 0)
    {
        PPH_STRING diskRevision;

        diskRevision = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->ProductRevisionOffset));

        *DiskRevision = TrimString(diskRevision);
    }

    if (DiskSerial && deviceDescriptor->SerialNumberOffset != 0)
    {
        PPH_STRING diskSerial;

        diskSerial = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->SerialNumberOffset));

        *DiskSerial = TrimString(diskSerial);
    }

    if (buffer)
    {
        PhFree(buffer);
    }

    return TRUE;
}
Exemplo n.º 5
0
BOOLEAN DiskDriveQueryTemperature(
    _In_ HANDLE DeviceHandle
    )
{
    ULONG bufferLength;
    IO_STATUS_BLOCK isb;
    STORAGE_PROPERTY_QUERY query;
    PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR buffer;

    query.QueryType = PropertyStandardQuery;
    query.PropertyId = StorageAdapterTemperatureProperty; // StorageDeviceTemperatureProperty

    bufferLength = sizeof(STORAGE_TEMPERATURE_DATA_DESCRIPTOR);
    buffer = PhAllocate(bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    bufferLength = buffer->Size;
    buffer = PhReAllocate(buffer, bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR storageDescriptor = (PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR)buffer;

    if (buffer)
    {
        PhFree(buffer);
    }

    return TRUE;
}
Exemplo n.º 6
0
BOOLEAN DiskDriveQueryCache(
    _In_ HANDLE DeviceHandle
    )
{
    ULONG bufferLength;
    IO_STATUS_BLOCK isb;
    STORAGE_PROPERTY_QUERY query;
    PSTORAGE_WRITE_CACHE_PROPERTY buffer;

    query.QueryType = PropertyStandardQuery;
    query.PropertyId = StorageDeviceWriteCacheProperty;

    bufferLength = sizeof(STORAGE_WRITE_CACHE_PROPERTY);
    buffer = PhAllocate(bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    bufferLength = buffer->Size;
    buffer = PhReAllocate(buffer, bufferLength);
    memset(buffer, 0, bufferLength);

    if (!NT_SUCCESS(NtDeviceIoControlFile(
        DeviceHandle,
        NULL,
        NULL,
        NULL,
        &isb,
        IOCTL_STORAGE_QUERY_PROPERTY,
        &query,
        sizeof(query),
        buffer,
        bufferLength
        )))
    {
        PhFree(buffer);
        return FALSE;
    }

    PSTORAGE_WRITE_CACHE_PROPERTY storageDescriptor = (PSTORAGE_WRITE_CACHE_PROPERTY)buffer;

    if (buffer)
    {
        PhFree(buffer);
    }

    return TRUE;
}
NET_API_STATUS
SrvSvcNetShareEnum(
    /* [in] */ handle_t IDL_handle,
    /* [in] */ wchar16_t *server_name,
    /* [in, out, ref] */ UINT32 *level,
    /* [in, out, ref] */ srvsvc_NetShareCtr *ctr,
    /* [in] */ UINT32 preferred_maximum_length,
    /* [out] */ UINT32 *total_entries,
    /* [in, out] */ UINT32 *resume_handle
    )
{
    NTSTATUS ntStatus = 0;
    DWORD dwError = 0;
    PBYTE pInBuffer = NULL;
    DWORD dwInLength = 0;
    PBYTE pOutBuffer = NULL;
    DWORD dwOutLength = 4096;
    IO_FILE_HANDLE hFile = NULL;
    IO_STATUS_BLOCK IoStatusBlock = { 0 };
    ACCESS_MASK DesiredAccess = 0;
    LONG64 AllocationSize = 0;
    FILE_ATTRIBUTES FileAttributes = 0;
    FILE_SHARE_FLAGS ShareAccess = 0;
    FILE_CREATE_DISPOSITION CreateDisposition = 0;
    FILE_CREATE_OPTIONS CreateOptions = 0;
    ULONG IoControlCode = SRV_DEVCTL_ENUM_SHARE;
    wchar16_t wszDriverName[] = SRV_DRIVER_NAME_W;
    IO_FILE_NAME filename =
                        {
                              .RootFileHandle = NULL,
                              .FileName = &wszDriverName[0],
                              .IoNameOptions = 0
                        };
    SHARE_INFO_ENUM_PARAMS EnumParamsIn = { 0 };
    PSHARE_INFO_ENUM_PARAMS pEnumParamsOut = NULL;
    srvsvc_NetShareCtr0 *ctr0 = NULL;
    srvsvc_NetShareCtr1 *ctr1 = NULL;
    srvsvc_NetShareCtr2 *ctr2 = NULL;
    srvsvc_NetShareCtr501 *ctr501 = NULL;
    srvsvc_NetShareCtr502 *ctr502 = NULL;
    SHORT i = 0;

    EnumParamsIn.dwInfoLevel = *level;

    dwError = LwNtStatusToWin32Error(
                  LwShareInfoMarshalEnumParameters(
                        &EnumParamsIn,
                        &pInBuffer,
                        &dwInLength));
    BAIL_ON_SRVSVC_ERROR(dwError);

    dwError = LwNtStatusToWin32Error(
                  NtCreateFile(
                        &hFile,
                        NULL,
                        &IoStatusBlock,
                        &filename,
                        NULL,
                        NULL,
                        DesiredAccess,
                        AllocationSize,
                        FileAttributes,
                        ShareAccess,
                        CreateDisposition,
                        CreateOptions,
                        NULL,
                        0,
                        NULL,
                        NULL));
    BAIL_ON_SRVSVC_ERROR(dwError);

    dwError = LwAllocateMemory(dwOutLength, (void**)&pOutBuffer);
    BAIL_ON_SRVSVC_ERROR(dwError);

    ntStatus = NtDeviceIoControlFile(
                    hFile,
                    NULL,
                    &IoStatusBlock,
                    IoControlCode,
                    pInBuffer,
                    dwInLength,
                    pOutBuffer,
                    dwOutLength
                    );

    while (ntStatus == STATUS_BUFFER_TOO_SMALL) {
        /* We need more space in output buffer to make this call */

        LW_SAFE_FREE_MEMORY(pOutBuffer);
        dwOutLength *= 2;

        dwError = LwAllocateMemory(dwOutLength, (void**)&pOutBuffer);
        BAIL_ON_SRVSVC_ERROR(dwError);

        ntStatus = NtDeviceIoControlFile(
                        hFile,
                        NULL,
                        &IoStatusBlock,
                        IoControlCode,
                        pInBuffer,
                        dwInLength,
                        pOutBuffer,
                        dwOutLength
                        );
    }
    dwError = LwNtStatusToWin32Error(ntStatus);
    BAIL_ON_SRVSVC_ERROR(dwError);


    dwError = LwNtStatusToWin32Error(
                  LwShareInfoUnmarshalEnumParameters(
                        pOutBuffer,
                        IoStatusBlock.BytesTransferred,
                        &pEnumParamsOut));
    BAIL_ON_SRVSVC_ERROR(dwError);

    switch (pEnumParamsOut->dwInfoLevel)
    {
    case 0:
        ctr0 = ctr->ctr0;
        ctr0->count = pEnumParamsOut->dwNumEntries;

        dwError = SrvSvcSrvAllocateMemory(
                      sizeof(*ctr0->array) * ctr0->count,
                      (PVOID*)&ctr0->array);
        BAIL_ON_SRVSVC_ERROR(dwError);

        for (i=0; i<ctr0->count ; i++)
        {
            dwError = SrvSvcSrvCopyShareInfo0(
                          &ctr0->array[i],
                          &pEnumParamsOut->info.p0[i]);
            BAIL_ON_SRVSVC_ERROR(dwError);
        }
        break;

    case 1:
        ctr1 = ctr->ctr1;
        ctr1->count = pEnumParamsOut->dwNumEntries;

        dwError = SrvSvcSrvAllocateMemory(
                      sizeof(*ctr1->array) * ctr1->count,
                      (PVOID*)&ctr1->array);
        BAIL_ON_SRVSVC_ERROR(dwError);

        for (i=0; i<ctr1->count ; i++)
        {
            dwError = SrvSvcSrvCopyShareInfo1(
                          &ctr1->array[i],
                          &pEnumParamsOut->info.p1[i]);
            BAIL_ON_SRVSVC_ERROR(dwError);
        }
        break;

    case 2:
        ctr2 = ctr->ctr2;
        ctr2->count = pEnumParamsOut->dwNumEntries;

        dwError = SrvSvcSrvAllocateMemory(
                      sizeof(*ctr2->array) * ctr2->count,
                      (PVOID*)&ctr2->array);
        BAIL_ON_SRVSVC_ERROR(dwError);

        for (i=0; i<ctr2->count ; i++)
        {
            dwError = SrvSvcSrvCopyShareInfo2(
                          &ctr2->array[i],
                          &pEnumParamsOut->info.p2[i]);
            BAIL_ON_SRVSVC_ERROR(dwError);
        }
        break;

    case 501:
        ctr501 = ctr->ctr501;
        ctr501->count = pEnumParamsOut->dwNumEntries;

        dwError = SrvSvcSrvAllocateMemory(
                      sizeof(*ctr501->array) * ctr501->count,
                      (PVOID*)&ctr501->array);
        BAIL_ON_SRVSVC_ERROR(dwError);

        for (i=0; i<ctr501->count ; i++)
        {
            dwError = SrvSvcSrvCopyShareInfo501(
                          &ctr501->array[i],
                          &pEnumParamsOut->info.p501[i]);
            BAIL_ON_SRVSVC_ERROR(dwError);
        }
        break;

    case 502:
        ctr502 = ctr->ctr502;
        ctr502->count = pEnumParamsOut->dwNumEntries;

        dwError = SrvSvcSrvAllocateMemory(
                      sizeof(*ctr502->array) * ctr502->count,
                      (PVOID*)&ctr502->array);
        BAIL_ON_SRVSVC_ERROR(dwError);

        for (i=0; i<ctr502->count ; i++)
        {
            dwError = SrvSvcSrvCopyShareInfo502(
                          &ctr502->array[i],
                          &pEnumParamsOut->info.p502[i]);
            BAIL_ON_SRVSVC_ERROR(dwError);
        }
        break;

    default:

        dwError = LwNtStatusToWin32Error(STATUS_NOT_SUPPORTED);
        BAIL_ON_SRVSVC_ERROR(dwError);

        break;
    }

    *level         = pEnumParamsOut->dwInfoLevel;
    *total_entries = pEnumParamsOut->dwNumEntries;

cleanup:

    if (hFile)
    {
        NtCloseFile(hFile);
    }

    LW_SAFE_FREE_MEMORY(pInBuffer);
    LW_SAFE_FREE_MEMORY(pOutBuffer);
    LW_SAFE_FREE_MEMORY(pEnumParamsOut);

    return dwError;

error:

    *level         = 0;
    *total_entries = 0;

    goto cleanup;
}
Exemplo n.º 8
0
int
WSPAPI
WSPBind(
    IN SOCKET Handle,
    IN const struct sockaddr *SocketAddress,
    IN int SocketAddressLength,
    OUT LPINT lpErrno
    )

/*++

Routine Description:

    This routine is used on an unconnected datagram or stream socket,
    before subsequent connect()s or listen()s.  When a socket is created
    with socket(), it exists in a name space (address family), but it
    has no name assigned.  bind() establishes the local association
    (host address/port number) of the socket by assigning a local name
    to an unnamed socket.

    If an application does not care what address is assigned to it, it
    may specify an Internet address and port equal to 0.  If this is the
    case, the Windows Sockets implementation will assign a unique
    address to the application.  The application may use getsockname()
    after bind() to learn the address that has been assigned to it.

    In the Internet address family, a name consists of several
    components.  For SOCK_DGRAM and SOCK_STREAM, the name consists of
    three parts: a host address, the protocol number (set implicitly to
    UDP or TCP, respectively), and a port number which identifies the
    application. The port is ignored for SOCK_RAW.

Arguments:

    s - A descriptor identifying an unbound socket.

    name - The address to assign to the socket.  The sockaddr structure
       is defined as follows:

              struct sockaddr {
                   u_short   sa_family;
                   char sa_data[14];
              };

    namelen - The length of the name.

Return Value:

--*/

{
    NTSTATUS status;
    PSOCKET_INFORMATION socket;
    IO_STATUS_BLOCK ioStatusBlock;
    PTRANSPORT_ADDRESS tdiAddress;
    ULONG tdiAddressLength;
    int err;
    PVOID reuseAddressBuffer;
    ULONG reuseAddressLength;
    SOCKADDR_INFO sockaddrInfo;

    WS_ENTER( "WSPBind", (PVOID)Handle, (PVOID)SocketAddress, (PVOID)SocketAddressLength, lpErrno );

    WS_ASSERT( lpErrno != NULL );

    IF_DEBUG(BIND) {

        WS_PRINT(( "WSPBind() on socket %lx addr %lx addrlen %ld\n"
                   "    req",
                       Handle, SocketAddress, SocketAddressLength ));

        WsPrintSockaddr( (PSOCKADDR)SocketAddress, &SocketAddressLength );

    }

    err = SockEnterApi( TRUE, TRUE, FALSE );

    if( err != NO_ERROR ) {

        WS_EXIT( "WSPBind", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    //
    // Set up local variables so that we know how to clean up on exit.
    //

    socket = NULL;
    tdiAddress = NULL;

    //
    // Find a pointer to the socket structure corresponding to the
    // passed-in handle.
    //

    socket = SockFindAndReferenceSocket( Handle, TRUE );

    if ( socket == NULL ) {

        err = WSAENOTSOCK;
        goto exit;

    }

    //
    // Acquire the lock that protects sockets.  We hold this lock
    // throughout this routine to synchronize against other callers
    // performing operations on the socket we're binding.
    //

    SockAcquireSocketLockExclusive( socket );

    //
    // If the socket has been initialized at all then this is not a
    // legal request.
    //

    if ( socket->State != SocketStateOpen ) {

        err = WSAEINVAL;
        goto exit;

    }

    //
    // If the buffer passed in is larger than needed for a socket address,
    // just truncate it.  Otherwise, the TDI address buffer we allocate
    // may not be large enough.
    //

    if ( SocketAddressLength > socket->HelperDll->MaxSockaddrLength ) {

        SocketAddressLength = socket->HelperDll->MaxSockaddrLength;

    }

    //
    // Make sure that the address structure passed in is legitimate,
    // and determine the type of address we're binding to.
    //

    err = socket->HelperDll->WSHGetSockaddrType(
                (PSOCKADDR)SocketAddress,
                SocketAddressLength,
                &sockaddrInfo
                );

    if ( err != NO_ERROR) {

        goto exit;

    }

    //
    // Hack?  If this is a wildcard address, and the caller set the
    // super secret "don't use wildcard" option, put non zero information
    // in the reserved field so that UDP knows that we really want to
    // bind to the zero address (0.0.0.0).
    //

    if ( socket->DontUseWildcard &&
         sockaddrInfo.AddressInfo == SockaddrAddressInfoWildcard ) {

        *(UNALIGNED ULONG *)(SocketAddress->sa_data + 6) = 0x12345678;

    }

    // !!! test for reserved port?

    //
    // Allocate enough space to hold the TDI address structure we'll pass
    // to AFD.
    //

    tdiAddressLength = socket->HelperDll->MaxTdiAddressLength;

    tdiAddress = ALLOCATE_HEAP( tdiAddressLength + 4 );

    if ( tdiAddress == NULL ) {

        err = WSAENOBUFS;
        goto exit;

    }

    //
    // Convert the address from the sockaddr structure to the appropriate
    // TDI structure.
    //

    SockBuildTdiAddress(
        tdiAddress,
        (PSOCKADDR)SocketAddress,
        SocketAddressLength
        );

    //
    // If this is not a wildcard address and the socket is not set up to
    // reuse addresses, indicate to AFD that this should be a unique address.
    //

    if ( sockaddrInfo.EndpointInfo != SockaddrEndpointInfoWildcard &&
             !socket->ReuseAddresses ) {

        reuseAddressBuffer = &reuseAddressLength;
        reuseAddressLength = sizeof(reuseAddressLength);

    } else {

        reuseAddressBuffer = NULL;
        reuseAddressLength = 0;

    }

    //
    // Call AFD to perform the actual bind operation.  AFD will open a
    // TDI address object through the proper TDI provider for this
    // socket.
    //

    status = NtDeviceIoControlFile(
                 (HANDLE)socket->Handle,
                 SockThreadEvent,
                 NULL,                   // APC Routine
                 NULL,                   // APC Context
                 &ioStatusBlock,
                 IOCTL_AFD_BIND,
                 tdiAddress,
                 tdiAddressLength,
                 reuseAddressBuffer,
                 reuseAddressLength
                 );

    if ( status == STATUS_PENDING ) {

        SockReleaseSocketLock( socket );
        SockWaitForSingleObject(
            SockThreadEvent,
            socket->Handle,
            SOCK_NEVER_CALL_BLOCKING_HOOK,
            SOCK_NO_TIMEOUT
            );
        SockAcquireSocketLockExclusive( socket );
        status = ioStatusBlock.Status;

    }

    if ( !NT_SUCCESS(status) ) {

        err = SockNtStatusToSocketError( status );
        goto exit;

    }

    //
    // Notify the helper DLL that the socket is now bound.
    //

    err = SockNotifyHelperDll( socket, WSH_NOTIFY_BIND );

    if ( err != NO_ERROR ) {

        goto exit;

    }

    //
    // Get the actual address we bound to.  It is possible on some
    // transports to partially specify an address, in which case the
    // transport will assign an address for use.  This IOCTL obtains the
    // real address for the endpoint.
    //

    status = NtDeviceIoControlFile(
                 (HANDLE)socket->Handle,
                 SockThreadEvent,
                 NULL,                   // APC Routine
                 NULL,                   // APC Context
                 &ioStatusBlock,
                 IOCTL_AFD_GET_ADDRESS,
                 NULL,
                 0,
                 tdiAddress,
                 tdiAddressLength + 4
                 );

    if ( status == STATUS_PENDING ) {

        SockReleaseSocketLock( socket );
        SockWaitForSingleObject(
            SockThreadEvent,
            socket->Handle,
            SOCK_NEVER_CALL_BLOCKING_HOOK,
            SOCK_NO_TIMEOUT
            );
        SockAcquireSocketLockExclusive( socket );
        status = ioStatusBlock.Status;

    }

    //
    // Convert the actual address that was bound to this socket to the
    // sockaddr format in order to store it.
    //

    if ( NT_SUCCESS(status) ) {

        SockBuildSockaddr(
            socket->LocalAddress,
            &SocketAddressLength,
            (PTRANSPORT_ADDRESS)( (PCHAR)tdiAddress + 4 )
            );

    } else {

        WS_PRINT((
            "IOCTL_AFD_GET_ADDRESS failed, status %08lx\n",
            status
            ));

    }

    //
    // Indicate that the socket is now bound to a specific address;
    //

    socket->State = SocketStateBound;

    //
    // Remember the changed state of this socket.
    //

    err = SockSetHandleContext( socket );

    if ( err != NO_ERROR ) {

        goto exit;

    }

    //
    // If the application changed the send or receive buffers and this
    // is a datagram socket, tell AFD about the new buffer sizes.
    //

    err = SockUpdateWindowSizes( socket, FALSE );

    if ( err != NO_ERROR ) {

        goto exit;

    }

exit:

    IF_DEBUG(BIND) {

        if ( err != NO_ERROR ) {

            WS_PRINT(( "WSPBind on socket %lx (%lx) failed: %ld\n",
                           Handle, socket, err ));

        } else {

            WS_PRINT(( "    WSPBind on socket %lx (%lx), granted",
                           Handle, socket ));
            WsPrintSockaddr( socket->LocalAddress, &socket->LocalAddressLength );

        }

    }

    //
    // Perform cleanup--dereference the socket if it was referenced,
    // free allocated resources.
    //

    if ( socket != NULL ) {

        SockReleaseSocketLock( socket );
        SockDereferenceSocket( socket );

    }

    if ( tdiAddress != NULL ) {

        FREE_HEAP( tdiAddress );

    }

    //
    // Return an error if appropriate.
    //

    if ( err != NO_ERROR ) {

        WS_EXIT( "WSPBind", SOCKET_ERROR, TRUE );
        *lpErrno = err;
        return SOCKET_ERROR;

    }

    WS_EXIT( "WSPBind", NO_ERROR, FALSE );
    return NO_ERROR;

} // WSPBind