Пример #1
0
// Utility routine to return the number of bytes required to store a 
// full WSAQUERYSET2 in a single buffer
//
size_t GetWSAQuerySet2Size(__in  WSAQUERYSET2  *pQuerySet)
{
    ULONG   i = 0;
    size_t  cbTotal = sizeof(WSAQUERYSET2);

    // calculate the string sizes
    cbTotal += RoundedStringSize(pQuerySet->lpszServiceInstanceName);
    cbTotal += RoundedStringSize(pQuerySet->lpszComment);
    cbTotal += RoundedStringSize(pQuerySet->lpszContext);
    cbTotal += RoundedStringSize(pQuerySet->lpszQueryString);

    if (pQuerySet->lpVersion != NULL)
    {
        cbTotal += sizeof(WSAVERSION);
        cbTotal = ROUND_UP_COUNT(cbTotal, ALIGN_LPVOID);
    }
    
    if (pQuerySet->lpNSProviderId != NULL)
    {
        cbTotal += sizeof(GUID);
        cbTotal = ROUND_UP_COUNT(cbTotal, ALIGN_LPVOID);
    }

    if (pQuerySet->lpafpProtocols != NULL && pQuerySet->dwNumberOfProtocols > 0)
    {
        cbTotal += pQuerySet->dwNumberOfProtocols * sizeof(AFPROTOCOLS);
    }

    if (pQuerySet->lpcsaBuffer != NULL && pQuerySet->dwNumberOfCsAddrs > 0)
    {
        cbTotal += pQuerySet->dwNumberOfCsAddrs * sizeof(CSADDR_INFO);

        for (i = 0; i < pQuerySet->dwNumberOfCsAddrs; i++)
        {
            cbTotal += pQuerySet->lpcsaBuffer[i].LocalAddr.iSockaddrLength;
            cbTotal = ROUND_UP_COUNT(cbTotal, ALIGN_LPVOID);
            cbTotal += pQuerySet->lpcsaBuffer[i].RemoteAddr.iSockaddrLength;
            cbTotal = ROUND_UP_COUNT(cbTotal, ALIGN_LPVOID);
        }
    }

    if (pQuerySet->lpBlob != NULL)
    {
        cbTotal += sizeof(BLOB);
        cbTotal += pQuerySet->lpBlob->cbSize;
        cbTotal = ROUND_UP_COUNT(cbTotal, ALIGN_LPVOID);
    }

    return cbTotal;
}
Пример #2
0
// Calculate the size of a string, in bytes, including number of bytes
// required to round up to the next aligned boundary
//
size_t RoundedStringSize(PCWSTR pcwzString)
{
    if (pcwzString == NULL)
    {
        return 0;
    }
    else
    {
        size_t cch = wcslen(pcwzString) + 1;
        size_t cb = sizeof(WCHAR) * cch;
        return ROUND_UP_COUNT(cb, ALIGN_LPVOID);
    }
}
Пример #3
0
NET_API_STATUS
RxpConvertAuditArray(
    IN LPVOID InputArray,
    IN DWORD InputByteCount,
    OUT LPBYTE * OutputArrayPtr, // will be alloc'ed (free w/ NetApiBufferFree).
    OUT LPDWORD OutputByteCountPtr
    )
{
    DWORD EntryType;
    const LPBYTE InputArrayEndPtr
            = (LPVOID) ( ((LPBYTE)InputArray) + InputByteCount );
    LPBYTE InputBytePtr;
    DWORD InputDataOffset;
    DWORD InputTotalEntrySize;
    LPBYTE InputFixedPtr;
    LPBYTE InputVariablePtr;
    DWORD InputVariableSize;
    LPVOID OutputArray;
    DWORD OutputArraySize;
    DWORD OutputBytesUsed = 0;
    DWORD OutputEntrySizeSoFar;
    LPAUDIT_ENTRY OutputFixedPtr;
    DWORD OutputVariableSize;
    LPBYTE OutputVariablePtr;
    NET_API_STATUS Status;

    //
    // Error check caller's parameters.
    // Set output parameters to make error handling easier below.
    // (Also check for memory faults while we're at it.)
    //
    if (OutputArrayPtr != NULL) {
        *OutputArrayPtr = NULL;
    }
    if (OutputByteCountPtr != NULL) {
        *OutputByteCountPtr = 0;
    }
    if ( (OutputArrayPtr == NULL) || (OutputByteCountPtr == NULL) ) {
        return (ERROR_INVALID_PARAMETER);
    }
    if ( (InputArray == NULL) || (InputByteCount == 0) ) {
        return (ERROR_INVALID_PARAMETER);
    }

    //
    // Compute size needed for output buffer, taking into account:
    //    per field expansion,
    //    per entry expansion,
    //    and alignment.
    //

    Status = RxpEstimateLogSize(
            DOWNLEVEL_AUDIT_FIXED_ENTRY_SIZE,
            InputByteCount,     // input (downlevel) array size in bytes.
            FALSE,              // no, we're not doing error log
            & OutputArraySize); // set estimated array size in bytes.
    if (Status != NO_ERROR) {
        return (Status);        // (output vars are already set.)
    }

    NetpAssert( OutputArraySize > 0 );
    NetpAssert( OutputArraySize > InputByteCount );

    *OutputByteCountPtr = OutputArraySize;

    //
    // Allocate oversize area for output; we'll realloc it to shrink it.
    //
    Status = NetApiBufferAllocate(
            OutputArraySize,
            (LPVOID *) & OutputArray );
    if (Status != NERR_Success) {
        return (Status);        // (output vars are already set.)
    }
    NetpAssert( OutputArray != NULL );
    NetpAssert( POINTER_IS_ALIGNED( OutputArray, ALIGN_WORST ) );

    //
    // Loop for each entry in the input area.
    //
    OutputFixedPtr = OutputArray;
    for (InputBytePtr = InputArray; InputBytePtr < InputArrayEndPtr; ) {

        InputFixedPtr = InputBytePtr;

        NetpAssert( POINTER_IS_ALIGNED( OutputFixedPtr, ALIGN_WORST ) );

        IF_DEBUG(AUDIT) {
            NetpKdPrint(( PREFIX_NETLIB
                    "RxpConvertAuditArray: doing input entry at "
                    FORMAT_LPVOID ", out entry at " FORMAT_LPVOID ".\n",
                    (LPVOID) InputFixedPtr, (LPVOID) OutputFixedPtr ));
        }

        //
        // Process each field in input fixed entry.
        //

        InputTotalEntrySize = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr );
        if (InputTotalEntrySize < MIN_DOWNLEVEL_ENTRY_SIZE) {
            goto FileCorrupt;
        }

        {
            LPBYTE EndPos = InputBytePtr + InputTotalEntrySize;
            if (EndPos > InputArrayEndPtr) {
                goto FileCorrupt;
            }
            EndPos -= sizeof(WORD);     // the last ae_len2
            if (SmbGetUshort( (LPWORD) EndPos ) != InputTotalEntrySize) {
                goto FileCorrupt;
            }
        }
        InputBytePtr += sizeof(WORD);    // skip ae_len.

        OutputFixedPtr->ae_reserved =
                (DWORD) SmbGetUshort( (LPWORD) InputBytePtr );
        InputBytePtr += sizeof(WORD);   //  skip ae_reserved

        {
            DWORD LocalTime = (DWORD) SmbGetUlong( (LPDWORD) InputBytePtr );
            DWORD GmtTime;
            NetpLocalTimeToGmtTime( LocalTime, & GmtTime );
            OutputFixedPtr->ae_time = GmtTime;
            InputBytePtr += sizeof(DWORD);
        }

        EntryType = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr );
        OutputFixedPtr->ae_type = EntryType;
        InputBytePtr += sizeof(WORD);

        InputDataOffset = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr );
        NetpAssert( InputDataOffset >= DOWNLEVEL_AUDIT_FIXED_ENTRY_SIZE );
        InputBytePtr += sizeof(WORD);

        OutputEntrySizeSoFar = sizeof(AUDIT_ENTRY);


        //
        // Process variable portion (if any):
        //

        InputVariablePtr = (LPVOID)
                ( ((LPBYTE) InputFixedPtr) + InputDataOffset );
        InputVariableSize =
                (InputTotalEntrySize - InputDataOffset)
                - sizeof(WORD);  // don't include ae_len2.

        OutputVariablePtr = (LPVOID)
                ( ((LPBYTE) OutputFixedPtr) + sizeof(AUDIT_ENTRY) );

        // Align variable part.
        OutputVariablePtr = ROUND_UP_POINTER( OutputVariablePtr, ALIGN_WORST );
        OutputEntrySizeSoFar =
                ROUND_UP_COUNT( OutputEntrySizeSoFar, ALIGN_WORST );

        OutputFixedPtr->ae_data_offset = OutputEntrySizeSoFar;

        // Copy and convert the variable part.
        RxpConvertAuditEntryVariableData(
                EntryType,
                InputVariablePtr,
                OutputVariablePtr,
                InputVariableSize,
                & OutputVariableSize);

#ifdef REVISED_AUDIT_ENTRY_STRUCT
        OutputFixedPtr->ae_data_size = OutputVariableSize;
#endif

        // Account for variable area and ae_len2 in total length.
        OutputEntrySizeSoFar += (OutputVariableSize + sizeof(DWORD));

        // Round size up so next entry (if any) is worst-case aligned.
        OutputEntrySizeSoFar =
                ROUND_UP_COUNT( OutputEntrySizeSoFar, ALIGN_WORST );


#define OutputEntrySize  OutputEntrySizeSoFar


        OutputFixedPtr->ae_len = OutputEntrySize;

        {
            LPDWORD EndSizePtr = (LPVOID)
                    ( ((LPBYTE)OutputFixedPtr)
                        + OutputEntrySize - sizeof(DWORD) );
            *EndSizePtr = OutputEntrySize;   // set ae_len2.
        }

        //
        // Update for next loop iteration.
        //

        InputBytePtr = (LPVOID)
                ( ((LPBYTE) InputFixedPtr)
                    + InputTotalEntrySize);

        OutputFixedPtr = (LPVOID)
                ( ((LPBYTE) OutputFixedPtr) + OutputEntrySize );

        OutputBytesUsed += OutputEntrySize;

        NetpAssert( OutputBytesUsed <= OutputArraySize );

    }

    NetpAssert(OutputBytesUsed > 0);
    NetpAssert( OutputBytesUsed <= OutputArraySize );

    // BUGBUG: realloc OutputArray to OutputBytesUsed


    *OutputArrayPtr = OutputArray;
    *OutputByteCountPtr = OutputBytesUsed;

    return (NERR_Success);

FileCorrupt:

    NetpKdPrint(( PREFIX_NETAPI
            "RxpConvertAuditArray: corrupt audit log!\n" ));

    if (OutputArray != NULL) {
        (VOID) NetApiBufferFree( OutputArray );
    }
    if (OutputArrayPtr != NULL) {
        *OutputArrayPtr = NULL;
    }
    if (OutputByteCountPtr != NULL) {
        *OutputByteCountPtr = 0;
    }
    return (NERR_LogFileCorrupt);

}
Пример #4
0
NTSTATUS
NlSendChangeLogNotification(
    IN enum CHANGELOG_NOTIFICATION_TYPE EntryType,
    IN PUNICODE_STRING ObjectName,
    IN PSID ObjectSid,
    IN ULONG ObjectRid
)
/*++

Routine Description:

    Put a ChangeLog Notification entry for netlogon to pick up.

Arguments:

    EntryType - The type of the entry being inserted

    ObjectName - The name of the account being changed.

    ObjectSid - Sid of the account be changed.

    ObjectRid - Rid of the object being changed.

Return Value:

    Status of the operation.

--*/
{
    PCHANGELOG_NOTIFICATION Notification;
    LPBYTE Where;
    ULONG SidSize = 0;
    ULONG NameSize = 0;
    ULONG Size;

    //
    // If the netlogon service isn't running (or at least starting),
    //   don't queue messages to it.
    //

    if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
        return STATUS_SUCCESS;
    }

    //
    // Allocate a buffer for the object name.
    //

    if ( ObjectSid != NULL ) {
        SidSize = RtlLengthSid( ObjectSid );
    }

    if ( ObjectName != NULL ) {
        NameSize = ObjectName->Length + sizeof(WCHAR);
    }

    Size = sizeof(*Notification) + SidSize + NameSize;
    Size = ROUND_UP_COUNT( Size, ALIGN_WORST );

    Notification = NetpMemoryAllocate( Size );

    if ( Notification == NULL ) {
        return STATUS_NO_MEMORY;
    }

    Notification->EntryType = EntryType;
    Notification->ObjectRid = ObjectRid;

    Where = (LPBYTE) (Notification + 1);

    //
    // Copy the object sid into the buffer.
    //

    if ( ObjectSid != NULL ) {
        RtlCopyMemory( Where, ObjectSid, SidSize );
        Notification->ObjectSid = (PSID) Where;
        Where += SidSize;
    } else {
        Notification->ObjectSid = NULL;
    }


    //
    // Copy the new server name into the buffer.
    //

    if ( ObjectName != NULL ) {
        Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
        RtlCopyMemory( Where, ObjectName->Buffer, ObjectName->Length );
        ((LPWSTR)Where)[ObjectName->Length/sizeof(WCHAR)] = L'\0';

        RtlInitUnicodeString( &Notification->ObjectName, (LPWSTR)Where);
        Where += NameSize;
    } else {
        RtlInitUnicodeString( &Notification->ObjectName, NULL);
    }

    //
    // Indicate we're about to send the event.
    //

    NlPrint((NL_CHANGELOG,
             "NlSendChangeLogNotification: sent %ld for %wZ Rid: 0x%lx Sid: ",
             Notification->EntryType,
             &Notification->ObjectName,
             Notification->ObjectRid ));
    NlpDumpSid( NL_CHANGELOG, Notification->ObjectSid );



    //
    // Insert the entry into the list
    //

    LOCK_CHANGELOG();
    InsertTailList( &NlGlobalChangeLogNotifications, &Notification->Next );
    UNLOCK_CHANGELOG();

    if ( !SetEvent( NlGlobalChangeLogEvent ) ) {
        NlPrint((NL_CRITICAL,
                 "Cannot set ChangeLog event: %lu\n",
                 GetLastError() ));
    }

    return STATUS_SUCCESS;
}
Пример #5
0
NTSTATUS
NlInitChangeLogBuffer(
    VOID
)
/*++

Routine Description:

    Open the change log file (netlogon.chg) for reading or writing one or
    more records.  Create this file if it does not exist or is out of
    sync with the SAM database (see note below).

    This file must be opened for R/W (deny-none share mode) at the time
    the cache is initialized.  If the file already exists when NETLOGON
    service started, its contents will be cached in its entirety
    provided the last change log record bears the same serial number as
    the serial number field in SAM database else this file will be
    removed and a new one created.  If the change log file did not exist
    then it will be created.

Arguments:

    NONE

Return Value:

    NT Status code

--*/
{
    NTSTATUS Status;
    NET_API_STATUS NetStatus;

    UINT WindowsDirectoryLength;
    WCHAR ChangeLogFile[PATHLEN+1];

    LPNET_CONFIG_HANDLE SectionHandle = NULL;
    DWORD NewChangeLogSize;

    //
    // Initialize
    //

    LOCK_CHANGELOG();


    //
    // Get the size of the changelog.


    //
    // Open the NetLogon configuration section.
    //

    NewChangeLogSize = DEFAULT_CHANGELOGSIZE;
    NetStatus = NetpOpenConfigData(
                    &SectionHandle,
                    NULL,                       // no server name.
#if defined(USE_WIN32_CONFIG)
                    SERVICE_NETLOGON,
#else
                    SECT_NT_NETLOGON,           // section name
#endif
                    TRUE );                     // we only want readonly access

    if ( NetStatus == NO_ERROR ) {

        (VOID) NlParseOne( SectionHandle,
                           NETLOGON_KEYWORD_CHANGELOGSIZE,
                           DEFAULT_CHANGELOGSIZE,
                           MIN_CHANGELOGSIZE,
                           MAX_CHANGELOGSIZE,
                           &NewChangeLogSize );

        (VOID) NetpCloseConfigData( SectionHandle );
    }

    NewChangeLogSize = ROUND_UP_COUNT( NewChangeLogSize, ALIGN_WORST);

    NlPrint((NL_INIT, "ChangeLogSize: 0x%lx\n", NewChangeLogSize ));


    //
    // Build the change log file name
    //

    WindowsDirectoryLength = GetWindowsDirectoryW(
                                 NlGlobalChangeLogFilePrefix,
                                 sizeof(NlGlobalChangeLogFilePrefix)/sizeof(WCHAR) );

    if ( WindowsDirectoryLength == 0 ) {

        NlPrint((NL_CRITICAL,"Unable to get changelog file directory name, "
                 "WinError = %ld \n", GetLastError() ));

        NlGlobalChangeLogFilePrefix[0] = L'\0';
        goto CleanChangeLogFile;
    }

    if ( WindowsDirectoryLength * sizeof(WCHAR) + sizeof(CHANGELOG_FILE_PREFIX) +
            CHANGELOG_FILE_POSTFIX_LENGTH * sizeof(WCHAR)
            > sizeof(NlGlobalChangeLogFilePrefix) ) {

        NlPrint((NL_CRITICAL,"Changelog file directory name length is "
                 "too long \n" ));

        NlGlobalChangeLogFilePrefix[0] = L'\0';
        goto CleanChangeLogFile;
    }

    wcscat( NlGlobalChangeLogFilePrefix, CHANGELOG_FILE_PREFIX );


    //
    // Read in the existing changelog file.
    //

    wcscpy( ChangeLogFile, NlGlobalChangeLogFilePrefix );
    wcscat( ChangeLogFile, CHANGELOG_FILE_POSTFIX );

    InitChangeLogDesc( &NlGlobalChangeLogDesc );
    Status = NlOpenChangeLogFile( ChangeLogFile, &NlGlobalChangeLogDesc, FALSE );

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


    //
    // Convert the changelog file to the right size/version.
    //

    Status = NlResizeChangeLogFile( &NlGlobalChangeLogDesc, NewChangeLogSize );

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

    goto Cleanup;


    //
    // CleanChangeLogFile
    //

CleanChangeLogFile:

    //
    // If we just need to start with a newly initialized file,
    //  do it.
    //

    Status = NlResetChangeLog( &NlGlobalChangeLogDesc, NewChangeLogSize );

Cleanup:

    //
    // start changelog worker thread
    //

    if ( NT_SUCCESS(Status) ) {

        if ( NlGlobalChangeLogRole == ChangeLogPrimary ) {
            (VOID)NlStartChangeLogWorkerThread();
        }

        //
        // Free any resources on error.
        //

    } else {
        NlCloseChangeLogFile( &NlGlobalChangeLogDesc );
    }

    UNLOCK_CHANGELOG();

    return Status;
}
Пример #6
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
Пример #7
0
NET_API_STATUS
RxpConvertBlock(
    IN DWORD ApiNumber,
    IN LPBYTE ResponseBlockPointer,
    IN LPDESC ParmDescriptorString,
    IN LPDESC DataDescriptor16 OPTIONAL,
    IN LPDESC DataDescriptor32 OPTIONAL,
    IN LPDESC AuxDesc16 OPTIONAL,
    IN LPDESC AuxDesc32 OPTIONAL,
    IN va_list *FirstArgumentPointer,   // rest of API's arguments
    IN LPBYTE SmbRcvBuffer OPTIONAL,
    IN DWORD SmbRcvByteLen,
    OUT LPBYTE RcvDataBuffer OPTIONAL,
    IN DWORD RcvDataLength,
    IN DWORD Flags
    )

/*++

Routine Description:

    RxpConvertBlock translates the remote response (of a remoted API) into
    the local equivalent.  This involves converting the response (which is in
    the form of 16-bit data in the transaction response buffer) to local
    data formats, and setting them in the argument list.

Arguments:

    ApiNumber - Function number of the API required.

    ResponseBlockPointer - Points to the transaction SMB response block.

    ParmDescriptorString - A pointer to a ASCIIZ string describing the API call
        parameters (other than server name).

    DataDescriptor16 - A pointer to a ASCIIZ string describing the
        structure of the data in the call, i.e. the return data structure
        for a Enum or GetInfo call.  This string is used for adjusting pointers
        to data in the local buffers after transfer across the net.  If there
        is no structure involved in the call then DataDescriptor16 must
        be a null pointer.

    DataDescriptor32 - An optional pointer to a ASCIIZ string describing the
        32-bit structure of the return data structure.

    AuxDesc16, AuxDesc32 - Will be NULL in most cases unless a REM_AUX_COUNT
        descriptor char is present in DataDescriptor16 in which case the
        aux descriptors define a secondary data format as DataDescriptor16
        defines the primary.

    FirstArgumentPointer - Points to the va_list (variable arguments list)
        containing the API arguments (after the server name).  The caller
        must call va_start and va_end.

    SmbRcvBuffer - Optionally points to 16-bit format receive data buffer.

    SmbRcvByteLen - the number of bytes contained in SmbRcvBuffer (if not NULL)

    RcvDataBuffer - Points to the data area for the received data.  For
        instance, this may be a server info structure from NetServerGetInfo.
        This pointer will be NULL for many APIs.

        If (Flags & ALLOCATE_RESPONSE) then this pointer actually points to
        the pointer to the eventual buffer. We allocate a buffer in this routine
        and set *RcvDataBuffer to it. If we fail to get the buffer then
        *RcvDataBuffer will be set to NULL

    RcvDataLength - Length of the data area that RcvDataBuffer points to.
        If (Flags & ALLOCATE_RESPONSE) then this value will be the size that the
        caller of RxRemoteApi originally decided that the down-level server
        should use and incidentally was the original size of SmbRcvBuffer

    Flags - bit-mapped flags word. Currently defined flags are:
        NO_PERMISSION_REQUIRED  - used by RxpTransactSmb to determine whether
                                  a NULL session may be used
        ALLOCATE_RESPONSE       - used by this routine to allocate the final
                                  32-bit response data buffer based on the size
                                  of the SMB data received, multiplied by the
                                  RAP_CONVERSION_FACTOR
Return Value:

    NET_API_STATUS - return value from remote API.

--*/

{
    DWORD Converter;            // For pointer fixups.
    LPBYTE CurrentBlockPointer;
    LPDWORD        EntriesReadPtr = NULL;
    DWORD NumStruct;            // Loop count for ptr fixup.
    va_list ParmPtr;
    LPBYTE         pDataBuffer = NULL;  // pointer to returned data
    NET_API_STATUS Status;      // Return status from remote.
    DWORD TempLength;           // General purpose length.


#if DBG

    //
    // Code in this file depends on 16-bit words; the Remote Admin Protocol
    // demands it.
    //

    NetpAssert( ( (sizeof(WORD)) * CHAR_BIT) == 16);

    if (DataDescriptor16 != NULL) {
        NetpAssert(DataDescriptor32 != NULL);
    } else {
        NetpAssert(DataDescriptor32 == NULL);
    }

    if (AuxDesc16 != NULL) {
        NetpAssert(AuxDesc32 != NULL);
    } else {
        NetpAssert(AuxDesc32 == NULL);
    }
#endif


    ParmPtr = *FirstArgumentPointer;

    // The API call was successful. Now translate the return buffers
    // into the local API format.
    //
    // First copy any data from the return parameter buffer into the
    // fields pointed to by the original call parameters.
    // The return parameter buffer contains;
    //      Status,         (16 bits)
    //      Converter,      (16 bits)
    //      ...             fields described by rcv ptr types in
    //                      ParmDescriptorString


    CurrentBlockPointer = ResponseBlockPointer;
    Status = (NET_API_STATUS) SmbGetUshort( (LPWORD) CurrentBlockPointer );
    CurrentBlockPointer += sizeof(WORD);

    Converter = ((DWORD) SmbGetUshort( (LPWORD) CurrentBlockPointer )) & 0xffff;
    IF_DEBUG(CONVBLK) {
        NetpKdPrint(( PREFIX_NETAPI
                "RxpConvertBlock: Converter=" FORMAT_HEX_DWORD ".\n",
                Converter ));
    }
    CurrentBlockPointer += sizeof(WORD);

    // Set default value of NumStruct to 1, if data, 0 if no data.

    if ( (DataDescriptor16 != NULL) && (*DataDescriptor16 != '\0') ) {
        NumStruct = 1;
    } else {
        NumStruct = 0;
    }

    for( ; *ParmDescriptorString != '\0'; ParmDescriptorString++) {

        IF_DEBUG(CONVBLK) {
            NetpKdPrint(( PREFIX_NETAPI
                    "RxpConvertBlock: *parm='" FORMAT_LPDESC_CHAR
                    "', ParmPtr is:\n", *ParmDescriptorString ));
            NetpDbgHexDump((LPVOID) & ParmPtr, sizeof(va_list));
        }
        switch( *ParmDescriptorString) {
        case REM_WORD :                 // Word in old APIs (DWORD in 32-bit).
        case REM_DWORD :                // DWord.
            // BUGBUG: is array possible here?
            (void) va_arg(ParmPtr, DWORD);      // Step over this arg.
            break;

        case REM_ASCIZ :
            (void) va_arg(ParmPtr, LPSTR);      // Step over this arg.
            break;

        case REM_BYTE_PTR :
            (void) va_arg(ParmPtr, LPBYTE);     // Step over this arg.
            (void) RapArrayLength(
                        ParmDescriptorString,
                        &ParmDescriptorString,
                        Response);
            break;

        case REM_WORD_PTR :             // (WORD *) in old APIs.
        case REM_DWORD_PTR :            // (DWORD *)
            (void) va_arg(ParmPtr, LPDWORD);    // Step over this arg.
            break;

        case REM_RCV_WORD_PTR :    // pointer to rcv word(s) (DWORD in 32-bit)
            {
                LPDWORD Temp;
                DWORD ArrayCount;
                Temp = va_arg(ParmPtr, LPDWORD);

                ++ParmDescriptorString;  // point to first (possible) digit...
                ArrayCount = RapDescArrayLength(
                        ParmDescriptorString);  // updated past last.
                --ParmDescriptorString;  // point back at last digit for loop.
                IF_DEBUG(CONVBLK) {
                    NetpKdPrint(( PREFIX_NETAPI
                            "RxpConvertBlock: rcv.word.ptr, temp="
                            FORMAT_LPVOID ", ArrayCount=" FORMAT_DWORD ".\n",
                            (LPVOID) Temp, ArrayCount ));
                }

                // if the rcv buffer given to us by the user is NULL,
                // (one currently can be - it is an MBZ parameter for
                // now in the log read apis...), don't attempt to
                // copy anything. TempLength will be garbage in this
                // case, so don't update CurrentBlockPointer either.  All we
                // use RapArrayLength for is to update ParmDescriptorString if
                // the parameter was NULL.

                if ( Temp == NULL ) {
                    ;        /* NULLBODY */
                } else {

                    // Copy one or more words (expanding to DWORDS as we go).
                    DWORD WordsLeft = ArrayCount;
                    do {
                        DWORD Data;
                        // Convert byte order if necessary, and expand.
                        Data = (DWORD) SmbGetUshort(
                                (LPWORD) CurrentBlockPointer );
                        *Temp = Data;
                        Temp += sizeof(DWORD);
                        --WordsLeft;
                    } while (WordsLeft > 0);

                    // This gross hack is to fix the problem that a
                    // down level spooler (Lan Server 1.2)
                    // do not perform level checking
                    // on the w functions of the api(s):
                    // DosPrintQGetInfo
                    // and thus can return NERR_Success
                    // and bytesavail == 0.  This combination
                    // is technically illegal, and results in
                    // us attempting to unpack a buffer full of
                    // garbage.  The following code detects this
                    // condition and resets the amount of returned
                    // data to zero so we do not attempt to unpack
                    // the buffer.        Since we know the reason for the
                    // mistake at the server end is that we passed
                    // them a new level, we return ERROR_INVALID_LEVEL
                    // in this case.
                    // ERICPE, 5/16/90.

                    if ((ApiNumber == API_WPrintQGetInfo)
                    && (Status == NERR_Success)
                    && (*(LPWORD)CurrentBlockPointer == 0)
                    && (*ParmDescriptorString == REM_RCV_WORD_PTR)) {

                        Status = ERROR_INVALID_LEVEL;
                        goto ErrorExit;
                    }
                    // END OF GROSS HACK

                    CurrentBlockPointer += (ArrayCount * sizeof(WORD));
                 }
                break;
            }

        case REM_RCV_BYTE_PTR :         // pointer to rcv byte(s)
            {
                LPBYTE Temp;
                Temp = va_arg(ParmPtr, LPBYTE);
                TempLength = RapArrayLength(
                        ParmDescriptorString,
                        &ParmDescriptorString,
                        Response);

                // if the rcv buffer given to us by the user is NULL,
                // (one currently can be - it is an MBZ parameter for
                // now in the log read apis...), don't attempt to
                // copy anything. TempLength will be garbage in this
                // case, so don't update CurrentBlockPointer either.  All we
                // use RapArrayLength for is to update ParmDescriptorString if
                // the parameter was NULL.

                if ( Temp != NULL ) {
                    NetpMoveMemory(
                                Temp,                           // dest
                                CurrentBlockPointer,            // src
                                TempLength);                    // len
                    CurrentBlockPointer += TempLength;
                 }
            }
            break;

        case REM_RCV_DWORD_PTR :        // pointer to rcv Dword(s)
            {
                LPDWORD Temp;
                Temp = va_arg(ParmPtr, LPDWORD);
                TempLength = RapArrayLength(
                        ParmDescriptorString,
                        &ParmDescriptorString,
                        Response);

                // if the rcv buffer given to us by the user is NULL,
                // (one currently can be - it is an MBZ parameter for
                // now in the log read apis...), don't attempt to
                // copy anything. TempLength will be garbage in this
                // case, so don't update CurrentBlockPointer either.  All we
                // use RapArrayLength for is to update ParmDescriptorString if
                // the parameter was NULL.

                if ( Temp == NULL ) {
                    ;        /* NULLBODY */
                } else {
                    // BUGBUG: Must byte swap here if necessary!
                    NetpMoveMemory(
                                Temp,                           // dest
                                CurrentBlockPointer,            // src
                                TempLength);                    // len
                    CurrentBlockPointer += TempLength;
                }
            }
            break;

        case REM_SEND_BUF_PTR :
            (void) va_arg(ParmPtr, LPVOID);     // Step over arg.
            break;

        case REM_SEND_BUF_LEN :
            (void) va_arg(ParmPtr, DWORD);      // Step over (32-bit) buf len.
            break;

        case REM_RCV_BUF_PTR :
            (void) va_arg(ParmPtr, LPVOID);
            break;

        case REM_RCV_BUF_LEN :
            (void) va_arg(ParmPtr, DWORD);      // Step over (32-bit) buf len.
            break;

        case REM_PARMNUM :
            (void) va_arg(ParmPtr, DWORD);      // Step over (32-bit) parm num.
            break;

        case REM_ENTRIES_READ :          // Used for NumStruct
            {
                EntriesReadPtr = va_arg(ParmPtr, LPDWORD);
                NumStruct = (DWORD) SmbGetUshort((LPWORD) CurrentBlockPointer);
                // BUGBUG: Is this appropriate way to handle truncation?
                NetpAssert(! RapValueWouldBeTruncated(NumStruct));
                IF_DEBUG(CONVBLK) {
                    NetpKdPrint(( PREFIX_NETAPI
                            "RxpConvertBlock: NumStruct is now "
                            FORMAT_DWORD ".\n", NumStruct ));
                }

                // Assume all entries will fit; we'll correct this later if not.
                *EntriesReadPtr = NumStruct;

                CurrentBlockPointer += sizeof(WORD);
                break;
            }

        case REM_FILL_BYTES :
            // Special case, this was not really an input parameter so ParmPtr
            // does not get changed. However, the ParmDescriptorString
            // pointer must be advanced past the descriptor field so
            // use get RapArrayLength to do this but ignore the
            // return length.

            (void) RapArrayLength(
                        ParmDescriptorString,
                        &ParmDescriptorString,
                        Response);
            break;

        case REM_AUX_NUM :              // Can't have aux in parm desc.
        case REM_BYTE :                 // Can't push a byte, so this is bogus?
        case REM_DATA_BLOCK :           // BUGBUG: Not in parm desc?
        case REM_DATE_TIME :            // Never used?
        case REM_NULL_PTR :             // BUGBUG: Not sure what to do here.
        case REM_SEND_LENBUF :          // BUGBUG: Not sure what to do here.
        default :
            NetpBreakPoint();
            Status = NERR_InternalError;
            goto ErrorExit;

        } // switch
    } // for

    //
    // If no data was returned from the server, then there's no point in
    // continuing. Return early with the status code as returned from the
    // remoted function
    //

    if (!SmbRcvByteLen) {
        if (Flags & ALLOCATE_RESPONSE) {

            //
            // We failed to allocate the buffer; this in turn will cause
            // RxRemoteApi to fail, in which event, the calling function
            // (ie RxNetXxxx) may try to free the buffer allocated on its
            // behalf (ie the buffer we just failed to get). Ensure that
            // the caller doesn't try to free an invalid pointer by setting
            // the returned pointer to NULL
            //

            NetpAssert(RcvDataBuffer);  // address of the callers buffer pointer
            *(LPBYTE*)RcvDataBuffer = NULL;
        }

        return Status;
    }

    //
    // If the caller of RxRemoteApi requested that we allocate the final data
    // buffer on their behalf, then allocate it here. We use as the size
    // criterion
    //
    // (RAP_CONVERSION_FACTOR + 1/RAP_CONVERSION_FRACTION) * SmbRcvByteLen
    //
    // since this has the size of 16-bit data actually received.
    //
    // RAP_CONVERSION_FACTOR is 2 since that's the ratio for the size of
    // WCHAR to CHAR and of DWORD to WORD.  However, Lanman data structures
    // typically represents text as zero terminated array of CHAR within the
    // returned structure.  The array itself is of maximum size.  However,
    // the typical native representation has a 4-byte pointer to a zero
    // terminated WCHAR.  A factor of 2 wouldn't account for the 4-byte pointer.
    // Assuming the smallest lanman array size is 13 bytes (e.g., NNLEN+1), an
    // additional factor of 4/13 (about 1/3) is needed.  So,
    // RAP_CONVERSION_FRACTION is 3.
    //
    // Round the size to a multiple of the alignment for the system to allow
    // data to be packed at the trailing end of the buffer.
    //
    // NOTE: Since the original API caller expects to use NetApiBufferFree to
    // get rid of this buffer, we must use NetapipBufferAllocate
    //

    if (Flags & ALLOCATE_RESPONSE) {
        NET_API_STATUS  ConvertStatus;

        NetpAssert(RcvDataBuffer);  // address of the callers buffer pointer
        NetpAssert(SmbRcvByteLen);  // size of the data received

        RcvDataLength = SmbRcvByteLen * RAP_CONVERSION_FACTOR;
        RcvDataLength += (SmbRcvByteLen + RAP_CONVERSION_FRACTION - 1) /
                         RAP_CONVERSION_FRACTION;
        RcvDataLength = ROUND_UP_COUNT( RcvDataLength, ALIGN_WORST );

        if (ConvertStatus = NetapipBufferAllocate(RcvDataLength,
                                                  (PVOID *) &pDataBuffer)) {
            NetpKdPrint(( PREFIX_NETAPI
                    "Error: RxpConvertBlock cannot allocate memory ("
                    "error " FORMAT_API_STATUS ").\n", ConvertStatus ));

            Status = ConvertStatus;
            goto ErrorExit;
        }
        NetpAssert( pDataBuffer != NULL );

        IF_DEBUG(CONVBLK) {
            NetpKdPrint(( PREFIX_NETAPI
                    "RxpConvertBlock: allocated " FORMAT_DWORD " byte buffer "
                    "at " FORMAT_LPVOID " for caller\n",
                    RcvDataLength, (LPVOID) pDataBuffer ));
        }

        *(LPBYTE*)RcvDataBuffer = pDataBuffer;
    } else {
Пример #8
0
NET_API_STATUS
NetpRdrFsControlTree(
    IN LPTSTR TreeName,
    IN LPTSTR TransportName OPTIONAL,
    IN DWORD ConnectionType,
    IN DWORD FsControlCode,
    IN LPVOID SecurityDescriptor OPTIONAL,
    IN LPVOID InputBuffer OPTIONAL,
    IN DWORD InputBufferSize,
    OUT LPVOID OutputBuffer OPTIONAL,
    IN DWORD OutputBufferSize,
    IN BOOL NoPermissionRequired
    )

/*++

Routine Description:

    NetpRdrFsControlTree performs a given FSCTL (file system control)
    on a given tree connection name.

Arguments:

    TreeName - Remote name to do fsctl to (in \\server\share format).

    FsControlCode - function code to pass to the redirector.  These are
        defined in <ntddnfs.h>.

    SecurityDescriptor - optionally points to a security descriptor to be
        used when creating the tree connection.

    InputBuffer - optionally points to a structure to be passed to the
        redirector.

    InputBufferSize - size of InputBuffer in bytes; must be zero if
        InputBuffer is a NULL pointer.

    OutputBuffer - optionally points to a structure to be filled in by the
        redirector.

    OutputBufferSize - size of OutputBuffer in bytes; must be zero if
        OutputBuffer is a NULL pointer.

    NoPermissionRequired - TRUE if this is a no permission required API.  (I.e.
        TRUE if the null session may be used.)

Return Value:

    NET_API_STATUS

--*/

{
    NET_API_STATUS ApiStatus;
    IO_STATUS_BLOCK iosb;
    NTSTATUS ntstatus;                      // Status from NT operations.
    OBJECT_ATTRIBUTES objattrTreeConn;      // Attrs for tree conn.
    LPTSTR pszTreeConn;                      // See strTreeConn below.
#ifndef UNICODE
    STRING strTreeConn;                     // \Device\LanManRedir\server\share
#endif
    UNICODE_STRING ucTreeConn;
    HANDLE TreeConnHandle;

    PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
    PFILE_FULL_EA_INFORMATION Ea;
    USHORT TransportNameSize = 0;
    ULONG EaBufferSize = 0;
    PWSTR UnicodeTransportName = NULL;

    UCHAR EaNameDomainNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_DOMAIN) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNameTransportNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_TRANSPORT) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
                                        strlen(EA_NAME_TYPE) + sizeof(CHAR),
                                        ALIGN_DWORD
                                        ) - sizeof(CHAR));

    UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_USERNAME) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    USHORT TypeSize = sizeof(ULONG);




    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: entered, TreeName='"
                FORMAT_LPTSTR "', " FORMAT_LPTSTR " session.\n",
                TreeName,
                NoPermissionRequired ? TEXT("null") : TEXT("non-null") ));
    }

    if ((TreeName == NULL) || (TreeName[0] == 0)) {
        return (ERROR_INVALID_PARAMETER);
    }

    if (! NetpIsRemoteNameValid(TreeName)) {
        return (ERROR_INVALID_PARAMETER);
    }

    //
    // Build NT-style name for what we're connecting to.  Note that there is
    // NOT a pair of backslashes anywhere in this name.
    //

    {
        DWORD NameSize =

            // /Device/LanManRedirector      /    server/share     \0
#ifdef UNICODE
            ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME_U) + 1 + STRLEN(TreeName) + 1 ) )
#else
            ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME) + 1 + STRLEN(TreeName) + 1 ) )
#endif
            * sizeof(TCHAR);

        pszTreeConn = (LPTSTR)NetpMemoryAllocate( NameSize );
    }

    if (pszTreeConn == NULL) {
        return (ERROR_NOT_ENOUGH_MEMORY);
    }

    //
    // Build the tree connect name.
    //

#ifdef UNICODE
    (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME_U);
#else
    (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME);
#endif

    //
    // NOTE: We add 1, (not sizeof(TCHAR)) because pointer arithmetic is done
    // in terms of multiples of sizeof(*pointer), not bytes
    //

    (void) STRCAT(pszTreeConn, TreeName+1); // \server\share

#ifdef UNICODE
    RtlInitUnicodeString(&ucTreeConn, pszTreeConn);
#else
    RtlInitString( & strTreeConn, pszTreeConn);
    (void) RtlOemStringToUnicodeString(&ucTreeConn, &strTreeConn, TRUE);
#endif

    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: UNICODE name is " FORMAT_LPWSTR
                ".\n", ucTreeConn.Buffer ));
    }



    //
    // Calculate the number of bytes needed for the EA buffer.
    // This may have the transport name.  For regular sessions, the user
    // name, password, and domain name are implicit.  For null sessions, we
    // must give 0-len user name, 0-len password, and 0-len domain name.
    //

    if (ARGUMENT_PRESENT(TransportName)) {
        ASSERT(ConnectionType == USE_IPC);

#ifdef UNICODE
        UnicodeTransportName = TransportName;
#else
        UnicodeTransportName = NetpAllocWStrFromStr(TransportName);

        if (UnicodeTransportName == NULL) {

            NetpMemoryFree(pszTreeConn);

            return ERROR_NOT_ENOUGH_MEMORY;
        }
#endif
        TransportNameSize = (USHORT) (wcslen(UnicodeTransportName) * sizeof(WCHAR));

        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameTransportNameSize + sizeof(CHAR) +
                            TransportNameSize,
                            ALIGN_DWORD
                            );
    }

    if (NoPermissionRequired) {

        // Domain name (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameDomainNameSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );

        // Password (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNamePasswordSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );

        // User name (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameUserNameSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );
    }

    EaBufferSize += ((ULONG)FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]))+
                    EaNameTypeSize + sizeof(CHAR) +
                    TypeSize;


    //
    // Allocate the EA buffer
    //

    if ((EaBuffer = NetpMemoryAllocate( EaBufferSize )) == NULL) {

        NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);
        }
#endif

        return ERROR_NOT_ENOUGH_MEMORY;
    }

    //
    // Fill-in the EA buffer.
    //

    RtlZeroMemory(EaBuffer, EaBufferSize);

    Ea = EaBuffer;

    if (ARGUMENT_PRESENT(TransportName)) {

        //
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        strcpy(Ea->EaName, EA_NAME_TRANSPORT);
        Ea->EaNameLength = EaNameTransportNameSize;

        //
        // Copy the EA value into EA buffer.  EA value length does not
        // include the zero terminator.
        //
        (VOID) wcscpy(
            (LPWSTR) &(Ea->EaName[EaNameTransportNameSize + sizeof(CHAR)]),
            UnicodeTransportName
            );

        Ea->EaValueLength = TransportNameSize;

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameTransportNameSize + sizeof(CHAR) +
                                  TransportNameSize,
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;
    }

    if (NoPermissionRequired) {

        //
        // *** DOMAIN NAME ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_DOMAIN);
        Ea->EaNameLength = EaNameDomainNameSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameDomainNameSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;

        //
        // *** PASSWORD ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_PASSWORD);
        Ea->EaNameLength = EaNamePasswordSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNamePasswordSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;

        //
        // *** USER NAME ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_USERNAME);
        Ea->EaNameLength = EaNameUserNameSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameUserNameSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;
    }

    //
    // Copy the EA for the connection type name into EA buffer.  EA name length
    // does not include the zero terminator.
    //
    strcpy(Ea->EaName, EA_NAME_TYPE);
    Ea->EaNameLength = EaNameTypeSize;

    *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;

    Ea->EaValueLength = TypeSize;

    Ea->NextEntryOffset = 0;
    Ea->Flags = 0;

    // Set object attributes for the tree conn.
    InitializeObjectAttributes(
                & objattrTreeConn,                       // obj attr to init
                (LPVOID) & ucTreeConn,                   // string to use
                OBJ_CASE_INSENSITIVE,                    // Attributes
                NULL,                                    // Root directory
                SecurityDescriptor);                     // Security Descriptor

    //
    // Open a tree connection to the remote server.
    //

    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: opening " FORMAT_LPTSTR ".\n",
                pszTreeConn ));
    }
    ntstatus = NtCreateFile(
                & TreeConnHandle,                        // ptr to handle
                SYNCHRONIZE                              // desired...
                | GENERIC_READ | GENERIC_WRITE,          // ...access
                & objattrTreeConn,                       // name & attributes
                & iosb,                                  // I/O status block.
                NULL,                                    // alloc size.
                FILE_ATTRIBUTE_NORMAL,                   // (ignored)
                FILE_SHARE_READ | FILE_SHARE_WRITE,      // ...access
                FILE_OPEN_IF,                            // create disposition
                FILE_CREATE_TREE_CONNECTION              // create...
                | FILE_SYNCHRONOUS_IO_NONALERT,          // ...options
                EaBuffer,                                // EA buffer
                EaBufferSize );                          // Ea buffer size

#ifndef UNICODE
    RtlFreeUnicodeString( &ucTreeConn );
#endif

    if (! NT_SUCCESS(ntstatus)) {

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);

        }
#endif

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

        NetpMemoryFree(pszTreeConn);
        ApiStatus = NetpNtStatusToApiStatus(ntstatus);
        if (ApiStatus == ERROR_BAD_NET_NAME) {
            ApiStatus = NERR_BadTransactConfig;  // Special meaning if no IPC$
        }

        if (ApiStatus != ERROR_BAD_NETPATH) {
            NetpKdPrint(( PREFIX_NETLIB
                    "NetpRdrFsControlTree: unexpected create error,\n"
                    "  tree name='" FORMAT_LPTSTR "', "
                    "ntstatus=" FORMAT_NTSTATUS ",\n"
                    "  iosb.Status=" FORMAT_NTSTATUS ", "
                    "iosb.Info=" FORMAT_HEX_ULONG ", "
                    "  returning " FORMAT_API_STATUS ".\n",
                    TreeName, ntstatus,
                    iosb.Status, iosb.Information, ApiStatus ));
        }

        return (ApiStatus);
    }

    // Do the FSCTL.
    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: doing fsctl...\n" ));
    }
    ntstatus = NtFsControlFile(
                        TreeConnHandle,                  // handle
                        NULL,                            // no event
                        NULL,                            // no APC routine
                        NULL,                            // no APC context
                        & iosb,                          // I/O stat blk (set)
                        FsControlCode,                   // func code
                        InputBuffer,
                        InputBufferSize,
                        OutputBuffer,
                        OutputBufferSize);

    if (! NT_SUCCESS(ntstatus)) {
       NTSTATUS Status;

       Status = NtClose(TreeConnHandle);
#if DBG
       if (!NT_SUCCESS(Status)) {
           NetpKdPrint(( PREFIX_NETLIB
                   "NetpRdrFsControlTree: "
                   "Unexpected error closing tree connect handle: "
                   FORMAT_NTSTATUS "\n",
                   Status ));
       }
#endif

       NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);

        }
#endif

        if (EaBuffer != NULL) {
            NetpMemoryFree(EaBuffer);
        }
        ApiStatus = NetpNtStatusToApiStatus(ntstatus);

        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: unexpected FSCTL error,\n"
                "  tree name='" FORMAT_LPTSTR "', "
                "ntstatus=" FORMAT_NTSTATUS ".\n"
                "  ApiStatus=" FORMAT_API_STATUS ", "
                "iosb.Status=" FORMAT_NTSTATUS ", "
                "iosb.Info=" FORMAT_HEX_ULONG ".\n",
                TreeName, ntstatus, ApiStatus, iosb.Status, iosb.Information ));

        return (ApiStatus);
    }

    // Clean up.
    ntstatus = NtClose(TreeConnHandle);
#if DBG
       if (!NT_SUCCESS(ntstatus)) {
           NetpKdPrint(( PREFIX_NETLIB
                   "NetpRdrFsControlTree: "
                   "Unexpected error closing tree connect handle: "
                   FORMAT_NTSTATUS "\n", ntstatus ));
       }
#endif

    NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
    if (UnicodeTransportName != NULL) {
        NetpMemoryFree(UnicodeTransportName);

    }
#endif

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

    return (NERR_Success);

} // NetpRdrFsControlTree
Пример #9
0
DBGSTATIC VOID
ReplClientInitPool(
    IN DWORD PoolNumber,
    IN DWORD EntryCount,
    IN DWORD EntrySize
    )
/*++

Routine Description:

    Allocates initial (guessed) memory for the Big Buffer pool.
    If needed, other entries will be allocated dynamically.

    Guess is = MAX(count, POOL_MIN_ENTRY_COUNT )

    From here the linked list memory is managed as follows:

    If an entry is deleted (FREE)
     add record to free_list.

    If a new entry is required (ALLOC)
     if NOTEMPTY(free_list)
         grab a record from free_list
     else
         Allocate new entry from the heap.

Arguments:

    PoolNumber - Which pool to initialize

    EntryCount - Initial guess of number of entries to allocate.

    EntrySize - Size in byte of each entry in the pool.

Return Value:

    None.

--*/
{
#ifdef notdef
    DWORD i;
    NET_API_STATUS    NetStatus;
#endif // notdef

    //
    // Ensure the EntrySize is a multiple of pointer size to ensure
    // each entry allocated here is pointer size aligned.
    //

    EntrySize = ROUND_UP_COUNT( EntrySize, ALIGN_LPBYTE );

    RCGlobalPoolEntrySize[PoolNumber] = EntrySize;
    RCGlobalPoolHeader[PoolNumber] = NULL;


#ifdef notdef

    //
    // Always allocate a minimum number of entries.
    //

    if (EntryCount < POOL_MIN_ENTRY_COUNT ) {
        EntryCount = POOL_MIN_ENTRY_COUNT ;
    }

    //
    // Allocate all the appropiate entries.
    //
    // It is better to detect a lack of resources at service initialization
    // rather than later.  That is why the pool is primed, otherwise we
    // could just let the pools prime themselves.
    //

    for (i = 0; i < (EntryCount - 1); i++) {
        PUCHAR rec;

        rec = NetpMemoryAllocate( RCGlobalPoolEntrySize[PoolNumber] );

        if ( rec == NULL ) {
            NetStatus = ERROR_NOT_ENOUGH_MEMORY;
            AlertLogExit( ALERT_ReplSysErr,
                          NELOG_ReplSysErr,
                          NetStatus,
                          NULL,
                          NULL,
                          NO_EXIT);
            BUGBUG;  // Hey, this will cause ReplClientFreePoolEntry to
                     // fault on a NULL pointer!  --JR
        }

        ReplClientFreePoolEntry( PoolNumber, rec );

    }
#endif // notdef

    DBG_UNREFERENCED_PARAMETER (EntryCount);
}