static NTSTATUS NtpCtxGetBufferResult( OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID Buffer, IN ULONG Length, IN PNT_IPC_MESSAGE_GENERIC_FILE_BUFFER_RESULT pResponse ) { pIoStatusBlock->Status = pResponse->Status; pIoStatusBlock->BytesTransferred = pResponse->BytesTransferred; assert(pResponse->BytesTransferred <= Length); memcpy(Buffer, pResponse->Buffer, SMB_MIN(pResponse->BytesTransferred, Length)); return pIoStatusBlock->Status; }
NTSTATUS SMB2PacketSign( PSMB_PACKET pPacket, PBYTE pSessionKey, ULONG ulSessionKeyLength ) { NTSTATUS ntStatus = 0; if (pSessionKey) { BYTE sessionKey[16]; PBYTE pBuffer = (PBYTE)pPacket->pSMB2Header; ULONG ulBytesAvailable = htonl(pPacket->pNetBIOSHeader->len); memset(&sessionKey[0], 0, sizeof(sessionKey)); memcpy(&sessionKey[0], pSessionKey, SMB_MIN(ulSessionKeyLength, sizeof(sessionKey))); while (pBuffer) { UCHAR ucDigest[EVP_MAX_MD_SIZE]; ULONG ulDigest = sizeof(ucDigest); PSMB2_HEADER pHeader = NULL; ULONG ulPacketSize = ulBytesAvailable; if (ulBytesAvailable < sizeof(SMB2_HEADER)) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } pHeader = (PSMB2_HEADER)pBuffer; if (pHeader->ulChainOffset) { if (ulBytesAvailable < pHeader->ulChainOffset) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } ulPacketSize = pHeader->ulChainOffset; } pHeader->ulFlags |= SMB2_FLAGS_SIGNED; memset(&pHeader->signature[0], 0, sizeof(pHeader->signature)); HMAC(EVP_sha256(), &sessionKey[0], sizeof(sessionKey), (PBYTE)pHeader, ulPacketSize, &ucDigest[0], &ulDigest); memcpy(&pHeader->signature[0], &ucDigest[0], sizeof(pHeader->signature)); if (pHeader->ulChainOffset) { pBuffer += pHeader->ulChainOffset; ulBytesAvailable -= pHeader->ulChainOffset; } else { pBuffer = NULL; } } } error: return ntStatus; }
static NTSTATUS SrvBuildOpenResponse( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; ULONG iMsg = pCtxSmb1->iMsg; PSRV_MESSAGE_SMB_V1 pSmbRequest = &pCtxSmb1->pRequests[iMsg]; PSRV_MESSAGE_SMB_V1 pSmbResponse = &pCtxSmb1->pResponses[iMsg]; POPEN_RESPONSE_HEADER pResponseHeader = NULL; // Do not free PBYTE pOutBuffer = pSmbResponse->pBuffer; ULONG ulBytesAvailable = pSmbResponse->ulBytesAvailable; ULONG ulOffset = 0; ULONG ulTotalBytesUsed = 0; PSRV_OPEN_STATE_SMB_V1 pOpenState = NULL; pOpenState = (PSRV_OPEN_STATE_SMB_V1)pCtxSmb1->hState; if (!pSmbResponse->ulSerialNum) { ntStatus = SrvMarshalHeader_SMB_V1( pOutBuffer, ulOffset, ulBytesAvailable, COM_OPEN_ANDX, STATUS_SUCCESS, TRUE, pConnection->serverProperties.Capabilities, pOpenState->pTree->tid, SMB_V1_GET_PROCESS_ID(pSmbRequest->pHeader), pCtxSmb1->pSession->uid, pSmbRequest->pHeader->mid, pConnection->serverProperties.bRequireSecuritySignatures, &pSmbResponse->pHeader, &pSmbResponse->pWordCount, &pSmbResponse->pAndXHeader, &pSmbResponse->usHeaderSize); } else { ntStatus = SrvMarshalHeaderAndX_SMB_V1( pOutBuffer, ulOffset, ulBytesAvailable, COM_OPEN_ANDX, &pSmbResponse->pWordCount, &pSmbResponse->pAndXHeader, &pSmbResponse->usHeaderSize); } BAIL_ON_NT_STATUS(ntStatus); pOutBuffer += pSmbResponse->usHeaderSize; ulOffset += pSmbResponse->usHeaderSize; ulBytesAvailable -= pSmbResponse->usHeaderSize; ulTotalBytesUsed += pSmbResponse->usHeaderSize; *pSmbResponse->pWordCount = 15; if (ulBytesAvailable < sizeof(OPEN_RESPONSE_HEADER)) { ntStatus = STATUS_INVALID_BUFFER_SIZE; BAIL_ON_NT_STATUS(ntStatus); } pResponseHeader = (POPEN_RESPONSE_HEADER)pOutBuffer; // pOutBuffer += sizeof(OPEN_RESPONSE_HEADER); // ulOffset += sizeof(OPEN_RESPONSE_HEADER); // ulBytesAvailable -= sizeof(OPEN_RESPONSE_HEADER); ulTotalBytesUsed += sizeof(OPEN_RESPONSE_HEADER); pResponseHeader->usFid = pOpenState->pFile->fid; pResponseHeader->ulServerFid = pOpenState->pFile->fid; pResponseHeader->usOpenAction = pOpenState->ulCreateAction; switch (pOpenState->ucOplockLevel) { case SMB_OPLOCK_LEVEL_I: // file is opened only by this user at the current time pResponseHeader->usOpenAction |= 0x8000; break; default: pResponseHeader->usOpenAction &= ~0x8000; break; } // TODO: Mirroring this field is close, but probably not exactly correct pResponseHeader->usGrantedAccess = pOpenState->pRequestHeader->usDesiredAccess; pResponseHeader->usFileAttributes = pOpenState->networkOpenInfo.FileAttributes; ntStatus = WireNTTimeToSMBUTime( pOpenState->networkOpenInfo.LastWriteTime, &pResponseHeader->ulLastWriteTime); BAIL_ON_NT_STATUS(ntStatus); pResponseHeader->ulDataSize = SMB_MIN( UINT32_MAX, pOpenState->networkOpenInfo.EndOfFile); if (SrvTreeIsNamedPipe(pOpenState->pTree)) { ntStatus = SrvMarshallPipeInfo( pOpenState->pFilePipeInfo, pOpenState->pFilePipeLocalInfo, &pResponseHeader->usDeviceState); BAIL_ON_NT_STATUS(ntStatus); pResponseHeader->usFileType = (USHORT)pOpenState->filePipeInfo.ReadMode; } else { pResponseHeader->usFileType = 0; pResponseHeader->usDeviceState = 0; } pResponseHeader->usReserved = 0; pResponseHeader->usByteCount = 0; pSmbResponse->ulMessageSize = ulTotalBytesUsed; cleanup: return ntStatus; error: if (ulTotalBytesUsed) { pSmbResponse->pHeader = NULL; pSmbResponse->pAndXHeader = NULL; memset(pSmbResponse->pBuffer, 0, ulTotalBytesUsed); } pSmbResponse->ulMessageSize = 0; goto cleanup; }
NTSTATUS SMB2PacketVerifySignature( PSMB_PACKET pPacket, PBYTE pSessionKey, ULONG ulSessionKeyLength ) { NTSTATUS ntStatus = 0; if (pSessionKey) { BYTE sessionKey[16]; PBYTE pBuffer = pPacket->pRawBuffer + sizeof(NETBIOS_HEADER); ULONG ulBytesAvailable = pPacket->pNetBIOSHeader->len; uint8_t origSignature[16]; UCHAR ucDigest[EVP_MAX_MD_SIZE]; ULONG ulDigest = sizeof(ucDigest); if (!pBuffer) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } memset(&sessionKey[0], 0, sizeof(sessionKey)); memcpy(&sessionKey[0], pSessionKey, SMB_MIN(ulSessionKeyLength, sizeof(sessionKey))); while (pBuffer) { PSMB2_HEADER pHeader = NULL; ULONG ulPacketSize = ulBytesAvailable; if (ulBytesAvailable < sizeof(SMB2_HEADER)) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } pHeader = (PSMB2_HEADER)pBuffer; if (pHeader->ulChainOffset) { if (ulBytesAvailable < pHeader->ulChainOffset) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } ulPacketSize = pHeader->ulChainOffset; } memcpy(origSignature, &pHeader->signature[0], sizeof(pHeader->signature)); memset(&pHeader->signature[0], 0, sizeof(pHeader->signature)); HMAC(EVP_sha256(), &sessionKey[0], sizeof(sessionKey), pBuffer, ulPacketSize, &ucDigest[0], &ulDigest); if (memcmp(&origSignature[0], &ucDigest[0], sizeof(origSignature))) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; } // restore signature memcpy(&pHeader->signature[0], &origSignature[0], sizeof(origSignature)); BAIL_ON_NT_STATUS(ntStatus); if (pHeader->ulChainOffset) { pBuffer += pHeader->ulChainOffset; ulBytesAvailable -= pHeader->ulChainOffset; } else { pBuffer = NULL; } } } cleanup: return ntStatus; error: LWIO_LOG_WARNING("SMB2 Packet verification failed (status = 0x%08X)", ntStatus); goto cleanup; }