static VOID SrvFreeExecContext( IN PSRV_EXEC_CONTEXT pContext ) { SrvMpxTrackerRemoveExecContext(pContext); if (pContext->pProtocolContext) { pContext->pfnFreeContext(pContext->pProtocolContext); } if (pContext->pSmbRequest) { SMBPacketRelease( pContext->pConnection->hPacketAllocator, pContext->pSmbRequest); } if (pContext->pSmbResponse) { SMBPacketRelease( pContext->pConnection->hPacketAllocator, pContext->pSmbResponse); } if (pContext->pInterimResponse) { SMBPacketRelease( pContext->pConnection->hPacketAllocator, pContext->pInterimResponse); } if (pContext->pConnection) { SrvConnectionRelease(pContext->pConnection); } if (pContext->pStatInfo) { SrvStatisticsRelease(pContext->pStatInfo); } if (pContext->pLogContext) { SrvLogContextFree(pContext->pLogContext); } if (pContext->pExecMutex) { pthread_mutex_destroy(&pContext->execMutex); } SrvFreeMemory(pContext); }
NTSTATUS SrvProcessNegotiate( IN PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSMB_PACKET pSmbRequest = pExecContext->pSmbRequest; PSMB_PACKET pSmbResponse = NULL; PSTR pszDialectArray[128]; ULONG ulNumDialects = 128; ULONG ulOffset = 0; if (pExecContext->bInline) { ntStatus = SrvScheduleExecContext(pExecContext); BAIL_ON_NT_STATUS(ntStatus); ntStatus = STATUS_PENDING; goto cleanup; } ulOffset = (PBYTE)pSmbRequest->pParams - (PBYTE)pSmbRequest->pSMBHeader; ntStatus = UnmarshallNegotiateRequest( pSmbRequest->pParams, pSmbRequest->pNetBIOSHeader->len - ulOffset, (uint8_t**)&pszDialectArray, &ulNumDialects); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildNegotiateResponseForDialect( pConnection, pSmbRequest, pszDialectArray, ulNumDialects, &pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); SrvConnectionSetState(pConnection, LWIO_SRV_CONN_STATE_NEGOTIATE); pExecContext->pSmbResponse = pSmbResponse; cleanup: return ntStatus; error: pExecContext->pSmbResponse = NULL; if (pSmbResponse) { SMBPacketRelease( pConnection->hPacketAllocator, pSmbResponse); } goto cleanup; }
static NTSTATUS SrvBuildNegotiateResponseForDialect( IN PLWIO_SRV_CONNECTION pConnection, IN PSMB_PACKET pSmbRequest, IN PSTR* ppszDialectArray, IN ULONG ulNumDialects, OUT PSMB_PACKET* ppSmbResponse ) { NTSTATUS ntStatus = STATUS_SUCCESS; SHORT dialectIdx = 0; BOOLEAN supportSMBV2 = SrvProtocolConfigIsSmb2Enabled(); PSMB_PACKET pSmbResponse = NULL; SMB_PROTOCOL_VERSION protocolVersion = SMB_PROTOCOL_VERSION_UNKNOWN; SMB_PROTOCOL_DIALECT protocolDialect = SMB_PROTOCOL_DIALECT_UNKNOWN; for (dialectIdx = ulNumDialects-1; dialectIdx >= 0; dialectIdx--) { if (supportSMBV2 && LwRtlCStringIsEqual( ppszDialectArray[dialectIdx], SRV_NEGOTIATE_DIALECT_STRING_SMB_2_1, TRUE)) { protocolVersion = SMB_PROTOCOL_VERSION_2; protocolDialect = SMB_PROTOCOL_DIALECT_SMB_2_1; } else if (supportSMBV2 && LwRtlCStringIsEqual( ppszDialectArray[dialectIdx], SRV_NEGOTIATE_DIALECT_STRING_SMB_2, TRUE)) { protocolVersion = SMB_PROTOCOL_VERSION_2; protocolDialect = SMB_PROTOCOL_DIALECT_SMB_2_0; } else if (LwRtlCStringIsEqual( ppszDialectArray[dialectIdx], SRV_NEGOTIATE_DIALECT_STRING_NTLM_0_12, TRUE)) { protocolVersion = SMB_PROTOCOL_VERSION_1; protocolDialect = SMB_PROTOCOL_DIALECT_NTLM_0_12; } if (protocolVersion != SMB_PROTOCOL_VERSION_UNKNOWN) { // Found the dialect we want so exit loop break; } } switch (protocolVersion) { case SMB_PROTOCOL_VERSION_UNKNOWN: ntStatus = SrvBuildNegotiateResponse_SMB_V1_Invalid( pConnection, pSmbRequest, &pSmbResponse); break; case SMB_PROTOCOL_VERSION_1: ntStatus = SrvBuildNegotiateResponse_SMB_V1_NTLM_0_12( pConnection, pSmbRequest, protocolDialect, dialectIdx, &pSmbResponse); break; case SMB_PROTOCOL_VERSION_2: ntStatus = SrvBuildNegotiateResponse_SMB_V2( pConnection, pSmbRequest, protocolDialect, &pSmbResponse); break; } BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvConnectionSetProtocolVersion( pConnection, protocolVersion, protocolDialect); BAIL_ON_NT_STATUS(ntStatus); error: if (!NT_SUCCESS(ntStatus)) { if (pSmbResponse) { SMBPacketRelease(pConnection->hPacketAllocator, pSmbResponse); pSmbResponse = NULL; } } *ppSmbResponse = pSmbResponse; return ntStatus; }
NTSTATUS SrvBuildNegotiateResponse_SMB_V1_NTLM_0_12( IN PLWIO_SRV_CONNECTION pConnection, IN PSMB_PACKET pSmbRequest, IN SMB_PROTOCOL_DIALECT Dialect, IN USHORT idxDialect, OUT PSMB_PACKET* ppSmbResponse ) { NTSTATUS ntStatus = 0; NEGOTIATE_RESPONSE_HEADER* pResponseHeader = NULL; time_t curTime = 0L; LONG64 llUTCTime = 0LL; uint16_t byteCount = 0; uint8_t* pDataCursor = NULL; PSRV_PROPERTIES pServerProperties = &pConnection->serverProperties; PSMB_PACKET pSmbResponse = NULL; PWSTR pwszHostname = NULL; ntStatus = SMBPacketAllocate( pConnection->hPacketAllocator, &pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMBPacketBufferAllocate( pConnection->hPacketAllocator, (64 * 1024) + 4096, &pSmbResponse->pRawBuffer, &pSmbResponse->bufferLen); BAIL_ON_NT_STATUS(ntStatus); if ((pSmbRequest->pSMBHeader->flags2 & FLAG2_EXT_SEC) == 0) { pServerProperties->Capabilities &= ~CAP_EXTENDED_SECURITY; } ntStatus = SMBPacketMarshallHeader( pSmbResponse->pRawBuffer, pSmbResponse->bufferLen, COM_NEGOTIATE, 0, TRUE, pSmbRequest->pSMBHeader->tid, SMB_V1_GET_PROCESS_ID(pSmbRequest->pSMBHeader), 0, pSmbRequest->pSMBHeader->mid, FALSE, pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); if ((pServerProperties->Capabilities & CAP_EXTENDED_SECURITY) == 0) { pSmbResponse->pSMBHeader->flags2 &= ~FLAG2_EXT_SEC; } pSmbResponse->pSMBHeader->wordCount = 17; pResponseHeader = (NEGOTIATE_RESPONSE_HEADER*)pSmbResponse->pParams; pSmbResponse->pData = pSmbResponse->pParams + sizeof(NEGOTIATE_RESPONSE_HEADER); pSmbResponse->bufferUsed += sizeof(NEGOTIATE_RESPONSE_HEADER); pResponseHeader->dialectIndex = idxDialect; pResponseHeader->securityMode = 0; if (pServerProperties->preferredSecurityMode == SMB_SECURITY_MODE_USER) { pResponseHeader->securityMode |= 0x1; // User level security } if (pServerProperties->bEncryptPasswords) { pResponseHeader->securityMode |= 0x2; } if (pServerProperties->bEnableSecuritySignatures) { pResponseHeader->securityMode |= 0x4; } if (pServerProperties->bRequireSecuritySignatures) { pResponseHeader->securityMode |= 0x8; } pResponseHeader->maxMpxCount = pServerProperties->MaxMpxCount; pResponseHeader->maxNumberVcs = pServerProperties->MaxNumberVCs; pResponseHeader->maxBufferSize = pServerProperties->MaxBufferSize; pResponseHeader->maxRawSize = pServerProperties->MaxRawSize; pResponseHeader->sessionKey = 0; pResponseHeader->capabilities = pServerProperties->Capabilities; curTime = time(NULL); ntStatus = WireSMBUTimeToTimeZone(curTime, &pResponseHeader->serverTimeZone); BAIL_ON_NT_STATUS(ntStatus); ntStatus = WireSMBUTimetoNTTime(curTime, FALSE, &llUTCTime); BAIL_ON_NT_STATUS(ntStatus); pResponseHeader->systemTimeLow = llUTCTime & 0xFFFFFFFFLL; pResponseHeader->systemTimeHigh = (llUTCTime & 0xFFFFFFFF00000000LL) >> 32; pDataCursor = pSmbResponse->pData; if (pResponseHeader->capabilities & CAP_EXTENDED_SECURITY) { PBYTE pNegHintsBlob = NULL; /* Do not free */ ULONG ulNegHintsLength = 0; pResponseHeader->encryptionKeyLength = 0; memcpy(pDataCursor, pServerProperties->GUID, sizeof(pServerProperties->GUID)); pDataCursor += sizeof(pServerProperties->GUID); byteCount += sizeof(pServerProperties->GUID); ntStatus = SrvGssNegHints(&pNegHintsBlob, &ulNegHintsLength); /* Microsoft clients ignore the security blob on the neg prot response so don't fail here if we can't get a negHintsBlob */ if (ntStatus == STATUS_SUCCESS) { memcpy(pDataCursor, pNegHintsBlob, ulNegHintsLength); pDataCursor += ulNegHintsLength; byteCount += ulNegHintsLength; } } else { WCHAR wszWorkgroup[] = SRV_NATIVE_DOMAIN_W; CHAR szHostname[HOST_NAME_MAX]; PWSTR pwszDomain = pConnection->clientProperties.pwszNativeDomain; if (!pwszDomain) { pwszDomain = &wszWorkgroup[0]; } if (gethostname(szHostname, HOST_NAME_MAX) == -1) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NT_STATUS(ntStatus); } pResponseHeader->encryptionKeyLength = sizeof(pConnection->ServerChallenge); // Generate challenge and remember it in connection if (!RAND_bytes( pConnection->ServerChallenge, sizeof(pConnection->ServerChallenge))) { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(ntStatus); } RtlCopyMemory(pDataCursor, &pConnection->ServerChallenge, sizeof(pConnection->ServerChallenge)); pDataCursor += sizeof(pConnection->ServerChallenge); byteCount += sizeof(pConnection->ServerChallenge); // Add domain name { size_t sDomainLen = (wc16slen(pwszDomain)+1) * sizeof(wchar16_t); RtlCopyMemory(pDataCursor, pwszDomain, sDomainLen); pDataCursor += sDomainLen; byteCount += sDomainLen; } // Add hostname { size_t sHostnameLen = 0; ntStatus = SrvMbsToWc16s(szHostname, &pwszHostname); BAIL_ON_NT_STATUS(ntStatus); sHostnameLen = (wc16slen(pwszHostname)+1) * sizeof(wchar16_t); RtlCopyMemory(pDataCursor, pwszHostname, sHostnameLen); pDataCursor += sHostnameLen; byteCount += sHostnameLen; } } pResponseHeader->byteCount = byteCount; pSmbResponse->bufferUsed += byteCount; ntStatus = SMBPacketMarshallFooter(pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); *ppSmbResponse = pSmbResponse; cleanup: SRV_SAFE_FREE_MEMORY(pwszHostname); return ntStatus; error: *ppSmbResponse = NULL; if (pSmbResponse) { SMBPacketRelease(pConnection->hPacketAllocator, pSmbResponse); } goto cleanup; }
NTSTATUS SrvBuildNegotiateResponse_SMB_V1_Invalid( PLWIO_SRV_CONNECTION pConnection, PSMB_PACKET pSmbRequest, PSMB_PACKET* ppSmbResponse ) { NTSTATUS ntStatus = 0; NEGOTIATE_INVALID_RESPONSE_HEADER* pResponseHeader = NULL; PSMB_PACKET pSmbResponse = NULL; ntStatus = SMBPacketAllocate( pConnection->hPacketAllocator, &pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMBPacketBufferAllocate( pConnection->hPacketAllocator, (64 * 1024) + 4096, &pSmbResponse->pRawBuffer, &pSmbResponse->bufferLen); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMBPacketMarshallHeader( pSmbResponse->pRawBuffer, pSmbResponse->bufferLen, COM_NEGOTIATE, 0, TRUE, 0, pSmbRequest->pSMBHeader->tid, 0, 0, FALSE, pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); if ((pConnection->serverProperties.Capabilities & CAP_EXTENDED_SECURITY) == 0) { pSmbResponse->pSMBHeader->flags2 &= ~FLAG2_EXT_SEC; } pSmbResponse->pSMBHeader->wordCount = 1; pResponseHeader = (NEGOTIATE_INVALID_RESPONSE_HEADER*)pSmbResponse->pParams; pSmbResponse->pData = pSmbResponse->pParams + sizeof(NEGOTIATE_INVALID_RESPONSE_HEADER); pSmbResponse->bufferUsed += sizeof(NEGOTIATE_INVALID_RESPONSE_HEADER); pResponseHeader->dialectIndex = 0xFF; pResponseHeader->byteCount = 0; ntStatus = SMBPacketMarshallFooter(pSmbResponse); BAIL_ON_NT_STATUS(ntStatus); *ppSmbResponse = pSmbResponse; cleanup: return ntStatus; error: *ppSmbResponse = NULL; if (pSmbResponse) { SMBPacketRelease(pConnection->hPacketAllocator, pSmbResponse); } goto cleanup; }
static NTSTATUS SrvNotifyBuildExecContext( PSRV_CHANGE_NOTIFY_STATE_SMB_V1 pNotifyState, PSRV_EXEC_CONTEXT* ppExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_EXEC_CONTEXT pExecContext = NULL; PSMB_PACKET pSmbRequest = NULL; PBYTE pParams = NULL; ULONG ulParamLength = 0; PBYTE pData = NULL; ULONG ulDataLen = 0; ULONG ulDataOffset = 0; PBYTE pBuffer = NULL; ULONG ulBytesAvailable = 0; ULONG ulOffset = 0; USHORT usBytesUsed = 0; USHORT usTotalBytesUsed = 0; PSMB_HEADER pHeader = NULL; // Do not free PBYTE pWordCount = NULL; // Do not free PANDX_HEADER pAndXHeader = NULL; // Do not free PUSHORT pSetup = NULL; UCHAR ucSetupCount = 0; ULONG ulParameterOffset = 0; ULONG ulNumPackageBytesUsed = 0; SMB_NOTIFY_CHANGE_HEADER notifyRequestHeader = {0}; ntStatus = SMBPacketAllocate( pNotifyState->pConnection->hPacketAllocator, &pSmbRequest); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMBPacketBufferAllocate( pNotifyState->pConnection->hPacketAllocator, (64 * 1024) + 4096, &pSmbRequest->pRawBuffer, &pSmbRequest->bufferLen); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvInitPacket_SMB_V1(pSmbRequest, TRUE); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildExecContext( pNotifyState->pConnection, pSmbRequest, TRUE, &pExecContext); BAIL_ON_NT_STATUS(ntStatus); pSmbRequest->sequence = pNotifyState->ulRequestSequence; pBuffer = pSmbRequest->pRawBuffer; ulBytesAvailable = pSmbRequest->bufferLen; if (ulBytesAvailable < sizeof(NETBIOS_HEADER)) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } pBuffer += sizeof(NETBIOS_HEADER); ulBytesAvailable -= sizeof(NETBIOS_HEADER); ntStatus = SrvMarshalHeader_SMB_V1( pBuffer, ulOffset, ulBytesAvailable, COM_NT_TRANSACT, pNotifyState->ioStatusBlock.Status, FALSE, /* not a response */ pNotifyState->usTid, pNotifyState->ulPid, pNotifyState->usUid, pNotifyState->usMid, pNotifyState->pConnection->serverProperties.bRequireSecuritySignatures, &pHeader, &pWordCount, &pAndXHeader, &usBytesUsed); BAIL_ON_NT_STATUS(ntStatus); pBuffer += usBytesUsed; ulOffset += usBytesUsed; ulBytesAvailable -= usBytesUsed; usTotalBytesUsed += usBytesUsed; notifyRequestHeader.usFid = pNotifyState->usFid; pSetup = (PUSHORT)¬ifyRequestHeader; ucSetupCount = sizeof(notifyRequestHeader)/sizeof(USHORT); *pWordCount = 18 + ucSetupCount; ntStatus = WireMarshallNtTransactionRequest( pBuffer, ulBytesAvailable, ulOffset, SMB_SUB_COMMAND_NT_TRANSACT_NOTIFY_CHANGE, pSetup, ucSetupCount, pParams, ulParamLength, pData, ulDataLen, &ulDataOffset, &ulParameterOffset, &ulNumPackageBytesUsed); BAIL_ON_NT_STATUS(ntStatus); // pBuffer += ulNumPackageBytesUsed; // ulOffset += ulNumPackageBytesUsed; // ulBytesAvailable -= ulNumPackageBytesUsed; usTotalBytesUsed += ulNumPackageBytesUsed; pSmbRequest->bufferUsed += usTotalBytesUsed; ntStatus = SMBPacketMarshallFooter(pSmbRequest); BAIL_ON_NT_STATUS(ntStatus); *ppExecContext = pExecContext; cleanup: if (pSmbRequest) { SMBPacketRelease( pNotifyState->pConnection->hPacketAllocator, pSmbRequest); } return ntStatus; error: *ppExecContext = NULL; if (pExecContext) { SrvReleaseExecContext(pExecContext); } goto cleanup; }