/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * */ /* * Copyright Likewise Software * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General * Public License along with this program. If not, see * . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * getsecinfo.c * * Abstract: * * Likewise IO (LWIO) - SRV * * Protocols API - SMBV2 * * Query Security Information * * Authors: Krishna Ganugapati (kganugapati@likewise.com) * Sriram Nambakam (snambakam@likewise.com) * * */ #include "includes.h" static NTSTATUS SrvExecuteQuerySecurityDescriptor_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ); NTSTATUS SrvGetSecurityInfo_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; PSRV_GET_INFO_STATE_SMB_V2 pGetInfoState = NULL; pGetInfoState = (PSRV_GET_INFO_STATE_SMB_V2)pCtxSmb2->hState; switch (pGetInfoState->pRequestHeader->ucInfoClass) { case SMB2_SEC_INFO_CLASS_BASIC: if (pGetInfoState->pRequestHeader->ulOutputBufferLen > SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvExecuteQuerySecurityDescriptor_SMB_V2(pExecContext); break; default: ntStatus = STATUS_INVALID_INFO_CLASS; break; } error: return ntStatus; } static NTSTATUS SrvExecuteQuerySecurityDescriptor_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; PSRV_GET_INFO_STATE_SMB_V2 pGetInfoState = NULL; BOOLEAN bContinue = TRUE; PBYTE pErrorMessage = NULL; pGetInfoState = (PSRV_GET_INFO_STATE_SMB_V2)pCtxSmb2->hState; do { ntStatus = pGetInfoState->ioStatusBlock.Status; switch (ntStatus) { case STATUS_BUFFER_TOO_SMALL: if (pGetInfoState->ulDataLength >= pGetInfoState->pRequestHeader->ulOutputBufferLen) { bContinue = FALSE; } else if (!pGetInfoState->pData2) { ULONG ulSecurityDescInitialLen = 256; ntStatus = SrvAllocateMemory( ulSecurityDescInitialLen, (PVOID*)&pGetInfoState->pData2); BAIL_ON_NT_STATUS(ntStatus); pGetInfoState->ulDataLength = ulSecurityDescInitialLen; } else if (pGetInfoState->ulDataLength != SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE) { PBYTE pNewMemory = NULL; ULONG ulNewLen = LW_MIN( SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE, pGetInfoState->ulDataLength + 4096); ntStatus = SrvAllocateMemory(ulNewLen, (PVOID*)&pNewMemory); BAIL_ON_NT_STATUS(ntStatus); if (pGetInfoState->pData2) { SrvFreeMemory(pGetInfoState->pData2); } pGetInfoState->pData2 = pNewMemory; pGetInfoState->ulDataLength = ulNewLen; } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } BAIL_ON_NT_STATUS(ntStatus); SrvPrepareGetInfoStateAsync_SMB_V2(pGetInfoState, pExecContext); ntStatus = IoQuerySecurityFile( pGetInfoState->pFile->hFile, pGetInfoState->pAcb, &pGetInfoState->ioStatusBlock, pGetInfoState->pRequestHeader->ulAdditionalInfo, (PSECURITY_DESCRIPTOR_RELATIVE)pGetInfoState->pData2, pGetInfoState->ulDataLength); switch (ntStatus) { case STATUS_SUCCESS: case STATUS_BUFFER_TOO_SMALL: // completed synchronously SrvReleaseGetInfoStateAsync_SMB_V2(pGetInfoState); break; default: BAIL_ON_NT_STATUS(ntStatus); } break; case STATUS_SUCCESS: if (!pGetInfoState->pData2) { pGetInfoState->ioStatusBlock.Status = STATUS_BUFFER_TOO_SMALL; } else { pGetInfoState->ulActualDataLength = pGetInfoState->ioStatusBlock.BytesTransferred; bContinue = FALSE; } break; default: BAIL_ON_NT_STATUS(ntStatus); break; } } while (bContinue); cleanup: if (pErrorMessage) { SrvFreeMemory(pErrorMessage); } return ntStatus; error: switch (ntStatus) { case STATUS_BUFFER_TOO_SMALL: { NTSTATUS ntStatus2 = STATUS_SUCCESS; ULONG ulLength = 0; if (!pGetInfoState->ulDataLength) { ulLength = 0xEC; } else if (pGetInfoState->ulDataLength == pGetInfoState->pRequestHeader->ulOutputBufferLen) { ulLength = pGetInfoState->ulDataLength + 0xEC; } else { ulLength = pGetInfoState->ulDataLength; } ntStatus2 = SrvAllocateMemory( sizeof(ULONG), (PVOID*)&pErrorMessage); if (ntStatus2) { LWIO_LOG_ERROR( "Failed to allocate buffer for error message " "[error:0x%08x]", ntStatus2); } else { memcpy(pErrorMessage, (PBYTE)&ulLength, sizeof(ulLength)); ntStatus2 = SrvSetErrorMessage_SMB_V2( pCtxSmb2, pErrorMessage, sizeof(ulLength)); if (ntStatus2 == STATUS_SUCCESS) { pErrorMessage = NULL; } else { LWIO_LOG_ERROR( "Failed to set error message in exec context " "[error:0x%08x]", ntStatus2); } } } break; default: break; } goto cleanup; } NTSTATUS SrvBuildSecurityInfoResponse_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; PSRV_GET_INFO_STATE_SMB_V2 pGetInfoState = NULL; ULONG iMsg = pCtxSmb2->iMsg; PSRV_MESSAGE_SMB_V2 pSmbRequest = &pCtxSmb2->pRequests[iMsg]; PSRV_MESSAGE_SMB_V2 pSmbResponse = &pCtxSmb2->pResponses[iMsg]; PBYTE pOutBuffer = pSmbResponse->pBuffer; ULONG ulBytesAvailable = pSmbResponse->ulBytesAvailable; ULONG ulOffset = 0; ULONG ulTotalBytesUsed = 0; PSMB2_GET_INFO_RESPONSE_HEADER pGetInfoResponseHeader = NULL; pGetInfoState = (PSRV_GET_INFO_STATE_SMB_V2)pCtxSmb2->hState; ntStatus = SMB2MarshalHeader( pOutBuffer, ulOffset, ulBytesAvailable, COM2_GETINFO, pSmbRequest->pHeader->usEpoch, pSmbRequest->pHeader->usCredits, pSmbRequest->pHeader->ulPid, pSmbRequest->pHeader->ullCommandSequence, pCtxSmb2->pTree->ulTid, pCtxSmb2->pSession->ullUid, 0LL, STATUS_SUCCESS, TRUE, LwIsSetFlag( pSmbRequest->pHeader->ulFlags, SMB2_FLAGS_RELATED_OPERATION), &pSmbResponse->pHeader, &pSmbResponse->ulHeaderSize); BAIL_ON_NT_STATUS(ntStatus); pOutBuffer += pSmbResponse->ulHeaderSize; ulOffset += pSmbResponse->ulHeaderSize; ulBytesAvailable -= pSmbResponse->ulHeaderSize; ulTotalBytesUsed += pSmbResponse->ulHeaderSize; if (ulBytesAvailable < sizeof(SMB2_GET_INFO_RESPONSE_HEADER)) { ntStatus = STATUS_INVALID_BUFFER_SIZE; BAIL_ON_NT_STATUS(ntStatus); } pGetInfoResponseHeader = (PSMB2_GET_INFO_RESPONSE_HEADER)pOutBuffer; ulBytesAvailable -= sizeof(SMB2_GET_INFO_RESPONSE_HEADER); pOutBuffer += sizeof(SMB2_GET_INFO_RESPONSE_HEADER); ulOffset += sizeof(SMB2_GET_INFO_RESPONSE_HEADER); ulTotalBytesUsed += sizeof(SMB2_GET_INFO_RESPONSE_HEADER); pGetInfoResponseHeader->usLength = sizeof(SMB2_GET_INFO_RESPONSE_HEADER)+1; pGetInfoResponseHeader->usOutBufferOffset = ulOffset; if (ulBytesAvailable < pGetInfoState->ulActualDataLength) { ntStatus = STATUS_INVALID_BUFFER_SIZE; BAIL_ON_NT_STATUS(ntStatus); } if (pGetInfoState->ulActualDataLength) { memcpy(pOutBuffer, pGetInfoState->pData2, pGetInfoState->ulActualDataLength); } pGetInfoResponseHeader->ulOutBufferLength = pGetInfoState->ulActualDataLength; // pOutBuffer += pGetInfoState->ulDataLength; // ulBytesAvailable -= pGetInfoState->ulDataLength; // ulOffset += pGetInfoState->ulDataLength; ulTotalBytesUsed += pGetInfoResponseHeader->ulOutBufferLength; pSmbResponse->ulMessageSize = ulTotalBytesUsed; cleanup: return ntStatus; error: if (ulTotalBytesUsed) { pSmbResponse->pHeader = NULL; pSmbResponse->ulHeaderSize = 0; memset(pSmbResponse->pBuffer, 0, ulTotalBytesUsed); } pSmbResponse->ulMessageSize = 0; goto cleanup; }