NTSTATUS SMBPacketAllocate( IN PLWIO_PACKET_ALLOCATOR pPacketAllocator, OUT PSMB_PACKET* ppPacket ) { NTSTATUS ntStatus = 0; PSMB_PACKET pPacket = NULL; if (pPacketAllocator) { ntStatus = SMBPacketAllocatePooled(pPacketAllocator, &pPacket); BAIL_ON_NT_STATUS(ntStatus); } else { ntStatus = LwIoAllocateMemory(sizeof(SMB_PACKET), (PVOID *) &pPacket); BAIL_ON_NT_STATUS(ntStatus); InterlockedIncrement(&pPacket->refCount); } *ppPacket = pPacket; cleanup: return ntStatus; error: *ppPacket = NULL; goto cleanup; }
NTSTATUS SMBPacketCreateAllocator( IN ULONG ulNumMaxPackets, OUT PLWIO_PACKET_ALLOCATOR* ppPacketAllocator ) { NTSTATUS ntStatus = 0; PLWIO_PACKET_ALLOCATOR pPacketAllocator = NULL; ntStatus = LwIoAllocateMemory( sizeof(LWIO_PACKET_ALLOCATOR), (PVOID*)&pPacketAllocator); BAIL_ON_NT_STATUS(ntStatus); pthread_mutex_init(&pPacketAllocator->mutex, NULL); pPacketAllocator->pMutex = &pPacketAllocator->mutex; pPacketAllocator->ulNumMaxPackets = ulNumMaxPackets; *ppPacketAllocator = pPacketAllocator; cleanup: return ntStatus; error: *ppPacketAllocator = NULL; goto cleanup; }
NTSTATUS LwIoGetThreadState( OUT PIO_THREAD_STATE* ppState ) { NTSTATUS Status = STATUS_SUCCESS; PIO_THREAD_STATE pState = NULL; Status = LwIoThreadInit(); BAIL_ON_NT_STATUS(Status); pState = pthread_getspecific(gStateKey); if (!pState) { Status = LwIoAllocateMemory(sizeof(*pState), OUT_PPVOID(&pState)); BAIL_ON_NT_STATUS(Status); if (pthread_setspecific(gStateKey, pState)) { Status = STATUS_INSUFFICIENT_RESOURCES; BAIL_ON_NT_STATUS(Status); } } *ppState = pState; error: return Status; }
LW_NTSTATUS LwIoGetSessionKey( IO_FILE_HANDLE File, LW_PUSHORT pKeyLength, LW_PBYTE* ppKeyBuffer ) { NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK IoStatus; BYTE Buffer[MAX_KEY_LENGTH]; PBYTE pKeyBuffer = NULL; Status = LwNtFsControlFile( File, NULL, &IoStatus, IO_FSCTL_SMB_GET_SESSION_KEY, NULL, 0, Buffer, sizeof(Buffer)); BAIL_ON_NT_STATUS(Status); if (IoStatus.BytesTransferred > 0) { Status = LwIoAllocateMemory(IoStatus.BytesTransferred, OUT_PPVOID(&pKeyBuffer)); BAIL_ON_NT_STATUS(Status); memcpy(pKeyBuffer, Buffer, IoStatus.BytesTransferred); *pKeyLength = IoStatus.BytesTransferred; *ppKeyBuffer = pKeyBuffer; } else { *pKeyLength = 0; *ppKeyBuffer = NULL; } cleanup: return Status; error: *pKeyLength = 0; *ppKeyBuffer = NULL; goto cleanup; }
static NTSTATUS SMBPacketAllocatePooled( IN PLWIO_PACKET_ALLOCATOR pPacketAllocator, OUT PSMB_PACKET* ppPacket ) { NTSTATUS ntStatus = 0; BOOLEAN bInLock = FALSE; PSMB_PACKET pPacket = NULL; LWIO_LOCK_MUTEX(bInLock, &pPacketAllocator->mutex); if (pPacketAllocator->pFreePacketStack) { pPacket = (PSMB_PACKET) pPacketAllocator->pFreePacketStack; SMBStackPopNoFree(&pPacketAllocator->pFreePacketStack); pPacketAllocator->freePacketCount--; LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); memset(pPacket, 0, sizeof(SMB_PACKET)); } else { LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); ntStatus = LwIoAllocateMemory(sizeof(SMB_PACKET), (PVOID *) &pPacket); BAIL_ON_NT_STATUS(ntStatus); } InterlockedIncrement(&pPacket->refCount); *ppPacket = pPacket; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); return ntStatus; error: *ppPacket = NULL; goto cleanup; }
NTSTATUS LwIoCreatePlainCredsW( PCWSTR pwszUsername, PCWSTR pwszDomain, PCWSTR pwszPassword, PIO_CREDS* ppCreds ) { NTSTATUS Status = STATUS_SUCCESS; PIO_CREDS pCreds = NULL; Status = LwIoAllocateMemory(sizeof(*pCreds), OUT_PPVOID(&pCreds)); BAIL_ON_NT_STATUS(Status); pCreds->type = IO_CREDS_TYPE_PLAIN; Status = RtlWC16StringDuplicate( &pCreds->payload.plain.pwszUsername, pwszUsername); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCreds->payload.plain.pwszDomain, pwszDomain); Status = RtlWC16StringDuplicate( &pCreds->payload.plain.pwszPassword, pwszPassword); BAIL_ON_NT_STATUS(Status); *ppCreds = pCreds; cleanup: return Status; error: if (pCreds) { LwIoDeleteCreds(pCreds); } goto cleanup; }
NTSTATUS SMBPacketBufferAllocate( IN PLWIO_PACKET_ALLOCATOR pPacketAllocator, IN size_t len, OUT uint8_t** ppBuffer, OUT size_t* pAllocatedLen ) { NTSTATUS ntStatus = STATUS_SUCCESS; PBYTE pBuffer = NULL; size_t allocatedLen = len; if (pPacketAllocator) { ntStatus = SMBPacketBufferAllocatePooled( pPacketAllocator, len, &pBuffer, &allocatedLen); } else { // server code needs zero initialized response packets ntStatus = LwIoAllocateMemory(len, (PVOID *) &pBuffer); } BAIL_ON_NT_STATUS(ntStatus); *ppBuffer = pBuffer; *pAllocatedLen = allocatedLen; cleanup: return ntStatus; error: *ppBuffer = NULL; *pAllocatedLen = 0; goto cleanup; }
NTSTATUS LwIoCreateKrb5CredsW( PCWSTR pwszPrincipal, PCWSTR pwszCachePath, PIO_CREDS* ppCreds ) { NTSTATUS Status = STATUS_SUCCESS; PIO_CREDS pCreds = NULL; Status = LwIoAllocateMemory(sizeof(*pCreds), OUT_PPVOID(&pCreds)); BAIL_ON_NT_STATUS(Status); pCreds->type = IO_CREDS_TYPE_KRB5_CCACHE; Status = RtlWC16StringDuplicate( &pCreds->payload.krb5Ccache.pwszPrincipal, pwszPrincipal); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCreds->payload.krb5Ccache.pwszCachePath, pwszCachePath); BAIL_ON_NT_STATUS(Status); *ppCreds = pCreds; cleanup: return Status; error: if (pCreds) { LwIoDeleteCreds(pCreds); } goto cleanup; }
DWORD SMBAllocateString( PCSTR pszInputString, PSTR* ppszOutputString ) { DWORD dwError = 0; DWORD dwLen = 0; PSTR pszOutputString = NULL; if (!pszInputString) { dwError = LWIO_ERROR_INVALID_PARAMETER; BAIL_ON_LWIO_ERROR(dwError); } dwLen = strlen(pszInputString); dwError = LwIoAllocateMemory(dwLen+1, (PVOID *)&pszOutputString); BAIL_ON_LWIO_ERROR(dwError); if (dwLen) { memcpy(pszOutputString, pszInputString, dwLen); } *ppszOutputString = pszOutputString; cleanup: return dwError; error: LWIO_SAFE_FREE_STRING(pszOutputString); *ppszOutputString = NULL; goto cleanup; }
BOOLEAN RdrCreateTreeConnect2Complete( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_TREE2 pTree = pParam; PIRP pIrp = pContext->pIrp; ACCESS_MASK DesiredAccess = pIrp->Args.Create.DesiredAccess; LONG64 AllocationSize = pIrp->Args.Create.AllocationSize; FILE_SHARE_FLAGS ShareAccess = pIrp->Args.Create.ShareAccess; FILE_CREATE_DISPOSITION CreateDisposition = pIrp->Args.Create.CreateDisposition; FILE_CREATE_OPTIONS CreateOptions = pIrp->Args.Create.CreateOptions; FILE_ATTRIBUTES FileAttributes = pIrp->Args.Create.FileAttributes; PIO_CREDS pCreds = IoSecurityGetCredentials(pIrp->Args.Create.SecurityContext); PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcessInfo = IoSecurityGetProcessInfo(pIrp->Args.Create.SecurityContext); PRDR_CCB2 pFile = NULL; BAIL_ON_NT_STATUS(status); status = LwIoAllocateMemory( sizeof(RDR_CCB2), (PVOID*)&pFile); BAIL_ON_NT_STATUS(status); status = LwErrnoToNtStatus(pthread_mutex_init(&pFile->mutex, NULL)); BAIL_ON_NT_STATUS(status); pFile->bMutexInitialized = TRUE; pFile->version = SMB_PROTOCOL_VERSION_2; pFile->pTree = pTree; pTree = NULL; status = LwRtlWC16StringDuplicate(&pFile->pwszPath, pContext->State.Create.pwszFilename); BAIL_ON_NT_STATUS(status); status = LwRtlWC16StringDuplicate(&pFile->pwszCanonicalPath, pContext->State.Create.pwszCanonicalPath); BAIL_ON_NT_STATUS(status); pContext->Continue = RdrFinishCreate2; pContext->State.Create.pFile2 = pFile; status = RdrTransceiveCreate2( pContext, pFile, DesiredAccess, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions); switch (status) { case STATUS_SUCCESS: case STATUS_PENDING: break; default: pContext->Continue = RdrCreateTreeConnectComplete; pContext->State.Create.pFile2 = NULL; status = RdrDfsConnect( pFile->pTree->pSession->pSocket, pIrp->Args.Create.FileName.FileName, pCreds, pProcessInfo->Uid, status, &pContext->usTry, &pContext->State.Create.pwszFilename, &pContext->State.Create.pwszCanonicalPath, pContext); RdrReleaseFile2(pFile); pFile = NULL; } BAIL_ON_NT_STATUS(status); cleanup: RTL_FREE(&pContext->State.Create.pwszFilename); RTL_FREE(&pContext->State.Create.pwszCanonicalPath); if (status != STATUS_PENDING) { RdrFreeContext(pContext); pIrp->IoStatusBlock.Status = status; IoIrpComplete(pIrp); } return FALSE; error: if (status != STATUS_PENDING && pFile) { RdrReleaseFile2(pFile); } if (status != STATUS_PENDING && pTree) { RdrTree2Release(pTree); } goto cleanup; }
static VOID RdrNegotiateGssContextWorkItem2( PVOID pParam ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = pParam; PRDR_SESSION2 pSession = pContext->State.TreeConnect.pSession2; PRDR_SOCKET pSocket = pSession->pSocket; PSMB_PACKET pPacket = pContext->State.TreeConnect.pPacket; PBYTE pInBlob = NULL; DWORD dwInBlobLength = 0; PBYTE pOutBlob = NULL; DWORD dwOutBlobLength = 0; BOOLEAN bSessionLocked = FALSE; if (pPacket) { /* Capture session id */ if (pSession->ullSessionId == 0) { pSession->ullSessionId = pPacket->pSMB2Header->ullSessionId; } else if (pSession->ullSessionId != pPacket->pSMB2Header->ullSessionId) { status = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(status); } status = RdrSmb2DecodeSessionSetupResponse( pPacket, NULL, &pInBlob, &dwInBlobLength); BAIL_ON_NT_STATUS(status); } else { pInBlob = pSession->pSocket->pSecurityBlob; dwInBlobLength = pSession->pSocket->securityBlobLen; } if (pContext->State.TreeConnect.pszCachePath) { status = SMBKrb5SetDefaultCachePath( pContext->State.TreeConnect.pszCachePath, NULL); BAIL_ON_NT_STATUS(status); } if (!pContext->State.TreeConnect.hGssContext) { status = SMBGSSContextBuild( pSocket->pwszCanonicalName, pContext->State.TreeConnect.pCreds, &pContext->State.TreeConnect.hGssContext); BAIL_ON_NT_STATUS(status); } status = SMBGSSContextNegotiate( pContext->State.TreeConnect.hGssContext, pInBlob, dwInBlobLength, &pOutBlob, &dwOutBlobLength); BAIL_ON_NT_STATUS(status); if (!SMBGSSContextNegotiateComplete(pContext->State.TreeConnect.hGssContext)) { pContext->Continue = RdrProcessSessionSetupResponse2; status = RdrTransceiveSessionSetup2( pContext, pSession, pOutBlob, dwOutBlobLength); BAIL_ON_NT_STATUS(status); } else { LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); status = SMBGSSContextGetSessionKey( pContext->State.TreeConnect.hGssContext, &pSession->pSessionKey, &pSession->dwSessionKeyLength); BAIL_ON_NT_STATUS(status); if (!pSocket->pSessionKey && pSession->pSessionKey) { status = LwIoAllocateMemory( pSession->dwSessionKeyLength, OUT_PPVOID(&pSocket->pSessionKey)); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSessionKey, pSession->pSessionKey, pSession->dwSessionKeyLength); pSocket->dwSessionKeyLength = pSession->dwSessionKeyLength; } status = RdrSocketAddSession2ById(pSocket, pSession); BAIL_ON_NT_STATUS(status); pSession->state = RDR_SESSION_STATE_READY; RdrNotifyContextList( &pSession->StateWaiters, bSessionLocked, &pSession->mutex, status, pSession); LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete2(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RTL_FREE(&pOutBlob); if (status != STATUS_PENDING) { if (pSession) { RdrSession2Invalidate(pSession, status); RdrSession2Release(pSession); } RdrSessionSetupComplete2(pContext, status, NULL); } return; error: goto cleanup; }
BOOLEAN RdrProcessNegotiateResponse2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pContext->State.TreeConnect.pSocket; PSMB_PACKET pPacket = pParam; BOOLEAN bFreeContext = FALSE; BOOLEAN bSocketLocked = FALSE; PRDR_SMB2_NEGOTIATE_RESPONSE_HEADER pHeader = NULL; PBYTE pNegHint = NULL; ULONG ulNegHintLength = 0; BAIL_ON_NT_STATUS(status); status = pPacket->pSMB2Header->error; BAIL_ON_NT_STATUS(status); LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); status = RdrSmb2DecodeNegotiateResponse( pPacket, &pHeader, &pNegHint, &ulNegHintLength); BAIL_ON_NT_STATUS(status); pSocket->ulMaxTransactSize = pHeader->ulMaxTransactionSize; pSocket->ulMaxReadSize = pHeader->ulMaxReadSize; pSocket->ulMaxWriteSize = pHeader->ulMaxWriteSize; pSocket->capabilities = pHeader->ulCapabilities; pSocket->ucSecurityMode = pHeader->ucSecurityMode; pSocket->securityBlobLen = ulNegHintLength; status = LwIoAllocateMemory( pSocket->securityBlobLen, (PVOID *) &pSocket->pSecurityBlob); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSecurityBlob, pNegHint, pSocket->securityBlobLen); status = RdrSocketSetProtocol(pSocket, SMB_PROTOCOL_VERSION_2); BAIL_ON_NT_STATUS(status); pSocket->state = RDR_SOCKET_STATE_READY; RdrNotifyContextList( &pSocket->StateWaiters, bSocketLocked, &pSocket->mutex, STATUS_SUCCESS, pSocket); LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete2(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } RdrFreePacket(pPacket); return FALSE; error: if (status != STATUS_PENDING && pSocket) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
static BOOLEAN RdrProcessNegotiateResponse( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pContext->State.TreeConnect.pSocket; PSMB_PACKET pPacket = pParam; BOOLEAN bSocketLocked = FALSE; BOOLEAN bFreeContext = FALSE; PBYTE pGUID = NULL; PBYTE pSecurityBlob = NULL; DWORD securityBlobLen = 0; NEGOTIATE_RESPONSE_HEADER* pHeader = NULL; BAIL_ON_NT_STATUS(status); /* As a special case, it is possible to receive an SMB2 negotiate response * from an SMB1 negotiate request. */ if (pPacket->protocolVer == SMB_PROTOCOL_VERSION_2) { /* Short-circuit to SMB2 code path in connect2.c */ return RdrProcessNegotiateResponse2(pContext, status, pParam); } LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); status = pPacket->pSMBHeader->error; BAIL_ON_NT_STATUS(status); status = UnmarshallNegotiateResponse( pPacket->pParams, pPacket->bufferUsed - (pPacket->pParams - pPacket->pRawBuffer), &pHeader, &pGUID, &pSecurityBlob, &securityBlobLen); BAIL_ON_NT_STATUS(status); // byte order conversions SMB_LTOH16_INPLACE(pHeader->dialectIndex); SMB_LTOH8_INPLACE(pHeader->securityMode); SMB_LTOH16_INPLACE(pHeader->maxMpxCount); SMB_LTOH16_INPLACE(pHeader->maxNumberVcs); SMB_LTOH32_INPLACE(pHeader->maxBufferSize); SMB_LTOH32_INPLACE(pHeader->maxRawSize); SMB_LTOH32_INPLACE(pHeader->sessionKey); SMB_LTOH32_INPLACE(pHeader->capabilities); SMB_LTOH32_INPLACE(pHeader->systemTimeLow); SMB_LTOH32_INPLACE(pHeader->systemTimeHigh); SMB_LTOH16_INPLACE(pHeader->serverTimeZone); SMB_LTOH8_INPLACE(pHeader->encryptionKeyLength); SMB_LTOH16_INPLACE(pHeader->byteCount); pSocket->ulMaxTransactSize = pHeader->maxBufferSize; pSocket->maxRawSize = pHeader->maxRawSize; pSocket->sessionKey = pHeader->sessionKey; pSocket->capabilities = pHeader->capabilities; pSocket->ucSecurityMode = pHeader->securityMode; pSocket->usMaxSlots = pHeader->maxMpxCount; pSocket->securityBlobLen = securityBlobLen; status = LwIoAllocateMemory( pSocket->securityBlobLen, (PVOID *) &pSocket->pSecurityBlob); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSecurityBlob, pSecurityBlob, pSocket->securityBlobLen); status = RdrSocketSetProtocol(pSocket, SMB_PROTOCOL_VERSION_1); BAIL_ON_NT_STATUS(status); pSocket->state = RDR_SOCKET_STATE_READY; RdrNotifyContextList( &pSocket->StateWaiters, bSocketLocked, &pSocket->mutex, STATUS_SUCCESS, pSocket); LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } RdrFreePacket(pPacket); return FALSE; error: if (status != STATUS_PENDING) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
static VOID RdrNegotiateGssContextWorkItem( PVOID pParam ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = pParam; PRDR_SESSION pSession = pContext->State.TreeConnect.pSession; PRDR_SOCKET pSocket = pSession->pSocket; PSMB_PACKET pPacket = pContext->State.TreeConnect.pPacket; PWSTR pwszNativeOS = NULL; PWSTR pwszNativeLanman = NULL; PWSTR pwszNativeDomain = NULL; PBYTE pInBlob = NULL; DWORD dwInBlobLength = 0; PBYTE pOutBlob = NULL; DWORD dwOutBlobLength = 0; PSESSION_SETUP_RESPONSE_HEADER_WC_4 pResponseHeader = NULL; BOOLEAN bSessionLocked = FALSE; if (pPacket) { status = UnmarshallSessionSetupResponse_WC_4( pPacket->pParams, pPacket->bufferLen - pPacket->bufferUsed, 0, &pResponseHeader, &pInBlob, &pwszNativeOS, &pwszNativeLanman, &pwszNativeDomain); BAIL_ON_NT_STATUS(status); dwInBlobLength = pResponseHeader->securityBlobLength; } else { pInBlob = pSession->pSocket->pSecurityBlob; dwInBlobLength = pSession->pSocket->securityBlobLen; } if (pContext->State.TreeConnect.pszCachePath) { status = SMBKrb5SetDefaultCachePath( pContext->State.TreeConnect.pszCachePath, NULL); BAIL_ON_NT_STATUS(status); } if (!pContext->State.TreeConnect.hGssContext) { status = SMBGSSContextBuild( pSocket->pwszCanonicalName, pContext->State.TreeConnect.pCreds, &pContext->State.TreeConnect.hGssContext); BAIL_ON_NT_STATUS(status); } status = SMBGSSContextNegotiate( pContext->State.TreeConnect.hGssContext, pInBlob, dwInBlobLength, &pOutBlob, &dwOutBlobLength); BAIL_ON_NT_STATUS(status); if (!SMBGSSContextNegotiateComplete(pContext->State.TreeConnect.hGssContext)) { pContext->Continue = RdrProcessSessionSetupResponse; status = RdrTransceiveSessionSetup( pContext, pSession, pOutBlob, dwOutBlobLength); BAIL_ON_NT_STATUS(status); } else { LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); if (pContext->Packet.haveSignature && (!memcmp(pPacket->pSMBHeader->extra.securitySignature, pContext->Packet.pSMBHeader->extra.securitySignature, sizeof(pContext->Packet.pSMBHeader->extra.securitySignature)))) { LWIO_LOG_WARNING("Server is exhibiting signing bug; ignoring signatures from server"); RdrSocketSetIgnoreServerSignatures(pSocket, TRUE); } status = SMBGSSContextGetSessionKey( pContext->State.TreeConnect.hGssContext, &pSession->pSessionKey, &pSession->dwSessionKeyLength); BAIL_ON_NT_STATUS(status); if (!pSocket->pSessionKey && pSession->pSessionKey && !(pContext->State.TreeConnect.pCreds->type == IO_CREDS_TYPE_PLAIN && pContext->State.TreeConnect.pCreds->payload.plain.pwszUsername[0] == '\0')) { status = LwIoAllocateMemory( pSession->dwSessionKeyLength, OUT_PPVOID(&pSocket->pSessionKey)); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSessionKey, pSession->pSessionKey, pSession->dwSessionKeyLength); pSocket->dwSessionKeyLength = pSession->dwSessionKeyLength; RdrSocketBeginSequence(pSocket); } status = RdrSocketAddSessionByUID(pSocket, pSession); BAIL_ON_NT_STATUS(status); pSession->state = RDR_SESSION_STATE_READY; RdrNotifyContextList( &pSession->StateWaiters, bSessionLocked, &pSession->mutex, status, pSession); LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RTL_FREE(&pOutBlob); if (status != STATUS_PENDING) { if (pContext->State.TreeConnect.hGssContext) { SMBGSSContextFree(pContext->State.TreeConnect.hGssContext); } RdrSessionInvalidate(pSession, status); RdrSessionRelease(pSession); RdrSessionSetupComplete(pContext, status, NULL); } return; error: goto cleanup; }
static NTSTATUS LwIoCreateDefaultKrb5Creds( PIO_CREDS* ppCreds ) { NTSTATUS Status = STATUS_SUCCESS; krb5_context pKrb5Context = NULL; krb5_error_code krb5Error = 0; krb5_ccache pKrb5Cache = NULL; krb5_principal pKrb5Principal = NULL; char* pszPrincipalName = NULL; const char* pszCredCachePath = NULL; PIO_CREDS pCreds = NULL; *ppCreds = NULL; krb5Error = krb5_init_context(&pKrb5Context); if (krb5Error) { Status = STATUS_INSUFFICIENT_RESOURCES; BAIL_ON_NT_STATUS(Status); } pszCredCachePath = krb5_cc_default_name(pKrb5Context); if (!pszCredCachePath) { /* If there is no default path, give up */ goto cleanup; } krb5Error = krb5_cc_resolve(pKrb5Context, pszCredCachePath, &pKrb5Cache); if (krb5Error) { /* If we can't access the cache, give up */ goto cleanup; } krb5Error = krb5_cc_get_principal(pKrb5Context, pKrb5Cache, &pKrb5Principal); if (krb5Error) { /* If there is no principal, give up */ goto cleanup; } krb5Error = krb5_unparse_name(pKrb5Context, pKrb5Principal, &pszPrincipalName); if (krb5Error) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } Status = LwIoAllocateMemory(sizeof(*pCreds), OUT_PPVOID(&pCreds)); BAIL_ON_NT_STATUS(Status); pCreds->type = IO_CREDS_TYPE_KRB5_CCACHE; Status = LwRtlWC16StringAllocateFromCString( &pCreds->payload.krb5Ccache.pwszPrincipal, pszPrincipalName ); BAIL_ON_NT_STATUS(Status); Status = LwRtlWC16StringAllocateFromCString( &pCreds->payload.krb5Ccache.pwszCachePath, pszCredCachePath ); BAIL_ON_NT_STATUS(Status); *ppCreds = pCreds; cleanup: if (pszPrincipalName) { krb5_free_unparsed_name(pKrb5Context, pszPrincipalName); } if (pKrb5Principal) { krb5_free_principal(pKrb5Context, pKrb5Principal); } if (pKrb5Cache) { krb5_cc_close(pKrb5Context, pKrb5Cache); } if (pKrb5Context) { krb5_free_context(pKrb5Context); } return Status; error: if (pCreds) { LwIoDeleteCreds(pCreds); } goto cleanup; }
DWORD SMBGSSContextBuild( PCWSTR pwszServerName, PIO_CREDS pCreds, PHANDLE phSMBGSSContext ) { DWORD dwError = 0; DWORD dwMajorStatus = 0; DWORD dwMinorStatus = 0; PSMB_GSS_SEC_CONTEXT pContext = NULL; PSTR pszTargetName = NULL; PSTR pszServerName = NULL; PSTR pszUsername = NULL; PSTR pszDomain = NULL; PSTR pszPassword = NULL; gss_buffer_desc usernameBuffer = {0}; gss_buffer_desc inputNameBuffer = {0}; gss_buffer_desc authDataBuffer = {0}; gss_name_t pUsername = NULL; gss_OID_set_desc desiredMechs; gss_OID_set actualMechs; OM_uint32 timeRec = 0; SEC_WINNT_AUTH_IDENTITY authData; static gss_OID_desc gssCredOptionPasswordOidDesc = { .length = GSS_CRED_OPT_PW_LEN, .elements = GSS_CRED_OPT_PW }; static gss_OID_desc gssNtlmOidDesc = { .length = GSS_MECH_NTLM_LEN, .elements = GSS_MECH_NTLM }; size_t sCopyServerChars = 0; dwError = LwRtlCStringAllocateFromWC16String(&pszServerName, pwszServerName); BAIL_ON_LWIO_ERROR(dwError); LWIO_LOG_DEBUG("Build GSS Context for server [%s]", LWIO_SAFE_LOG_STRING(pszServerName)); dwError = LwIoAllocateMemory( sizeof(SMB_GSS_SEC_CONTEXT), (PVOID*)&pContext); BAIL_ON_LWIO_ERROR(dwError); pContext->state = SMB_GSS_SEC_CONTEXT_STATE_INITIAL; if (pCreds) { switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_CCACHE: dwError = STATUS_ACCESS_DENIED; BAIL_ON_LWIO_ERROR(dwError); break; case IO_CREDS_TYPE_KRB5_TGT: sCopyServerChars = strlen(pszServerName); if (sCopyServerChars > 0 && pszServerName[sCopyServerChars - 1] == '.') { // Strip the trailing dot sCopyServerChars --; } if (sCopyServerChars > INT_MAX) { dwError = STATUS_INTEGER_OVERFLOW; BAIL_ON_LWIO_ERROR(dwError); } dwError = SMBAllocateStringPrintf( &pszTargetName, "cifs/%.*s@", (int)sCopyServerChars, pszServerName); BAIL_ON_LWIO_ERROR(dwError); inputNameBuffer.value = pszTargetName; inputNameBuffer.length = strlen(pszTargetName) + 1; dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &inputNameBuffer, (gss_OID) gss_nt_krb5_name, &pContext->target_name); smb_display_status("gss_import_name", dwMajorStatus, dwMinorStatus); BAIL_ON_SEC_ERROR(dwMajorStatus); dwError = LwRtlCStringAllocateFromWC16String( &pszUsername, pCreds->payload.krb5Tgt.pwszClientPrincipal); BAIL_ON_NT_STATUS(dwError); usernameBuffer.value = pszUsername; usernameBuffer.length = strlen(pszUsername) + 1; dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &usernameBuffer, GSS_C_NT_USER_NAME, &pUsername); BAIL_ON_SEC_ERROR(dwMajorStatus); desiredMechs.count = 1; desiredMechs.elements = (gss_OID) gss_mech_krb5; dwMajorStatus = gss_acquire_cred( (OM_uint32 *)&dwMinorStatus, pUsername, 0, &desiredMechs, GSS_C_INITIATE, &pContext->credHandle, &actualMechs, &timeRec); BAIL_ON_SEC_ERROR(dwMajorStatus); break; case IO_CREDS_TYPE_PLAIN: inputNameBuffer.value = (void*) "unset"; inputNameBuffer.length = strlen("unset"); dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &inputNameBuffer, (gss_OID) gss_nt_krb5_name, &pContext->target_name); smb_display_status("gss_import_name", dwMajorStatus, dwMinorStatus); BAIL_ON_SEC_ERROR(dwMajorStatus); if (pCreds->payload.plain.pwszUsername) { dwError = LwRtlCStringAllocateFromWC16String(&pszUsername, pCreds->payload.plain.pwszUsername); BAIL_ON_LWIO_ERROR(dwError); usernameBuffer.value = pszUsername; usernameBuffer.length = strlen(pszUsername); // If "" is passed in, that means to use anonymous // authentication. gss_import_name fails on "" though if (usernameBuffer.length) { dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &usernameBuffer, GSS_C_NT_USER_NAME, &pUsername); BAIL_ON_SEC_ERROR(dwMajorStatus); } } desiredMechs.count = 1; desiredMechs.elements = (gss_OID) &gssNtlmOidDesc; dwMajorStatus = gss_acquire_cred( (OM_uint32 *)&dwMinorStatus, pUsername, 0, &desiredMechs, GSS_C_INITIATE, &pContext->credHandle, &actualMechs, &timeRec); BAIL_ON_SEC_ERROR(dwMajorStatus); if (pCreds->payload.plain.pwszUsername && pCreds->payload.plain.pwszPassword && pCreds->payload.plain.pwszDomain) { dwError = LwRtlCStringAllocateFromWC16String(&pszDomain, pCreds->payload.plain.pwszDomain); BAIL_ON_LWIO_ERROR(dwError); dwError = LwRtlCStringAllocateFromWC16String(&pszPassword, pCreds->payload.plain.pwszPassword); BAIL_ON_LWIO_ERROR(dwError); authData.User = pszUsername; authData.UserLength = strlen(pszUsername); authData.Domain = pszDomain; authData.DomainLength = strlen(pszDomain); authData.Password = pszPassword; authData.PasswordLength = strlen(pszPassword); authData.Flags = 0; authDataBuffer.value = &authData; authDataBuffer.length = sizeof(authData); dwMajorStatus = gssspi_set_cred_option( (OM_uint32 *)&dwMinorStatus, pContext->credHandle, (gss_OID) &gssCredOptionPasswordOidDesc, &authDataBuffer); BAIL_ON_SEC_ERROR(dwMajorStatus); } break; } } dwError = LwIoAllocateMemory( sizeof(CtxtHandle), (PVOID*)&pContext->pGSSContext); BAIL_ON_LWIO_ERROR(dwError); *pContext->pGSSContext = GSS_C_NO_CONTEXT; *phSMBGSSContext = (HANDLE)pContext; cleanup: if (pUsername != NULL) { gss_release_name((OM_uint32 *)&dwMinorStatus, &pUsername); } LWIO_SAFE_FREE_STRING(pszTargetName); LWIO_SAFE_FREE_STRING(pszServerName); LWIO_SAFE_FREE_STRING(pszUsername); LWIO_SAFE_FREE_STRING(pszDomain); LWIO_SAFE_FREE_STRING(pszPassword); return dwError; sec_error: dwError = LWIO_ERROR_GSS; error: *phSMBGSSContext = NULL; if (pContext) { SMBGSSContextFree(pContext); } goto cleanup; }
DWORD SMBGSSContextNegotiate( HANDLE hSMBGSSContext, PBYTE pSecurityInputBlob, DWORD dwSecurityInputBlobLen, PBYTE* ppSecurityBlob, PDWORD pdwSecurityBlobLength ) { DWORD dwError = 0; DWORD dwMajorStatus = 0; DWORD dwMinorStatus = 0; PSMB_GSS_SEC_CONTEXT pContext = (PSMB_GSS_SEC_CONTEXT)hSMBGSSContext; gss_buffer_desc input_desc = {0}; gss_buffer_desc output_desc = {0}; DWORD ret_flags = 0; PBYTE pSecurityBlob = NULL; DWORD dwSecurityBlobLength = 0; static gss_OID_desc gss_spnego_mech_oid_desc = {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; if (pContext->state == SMB_GSS_SEC_CONTEXT_STATE_COMPLETE) { goto cleanup; } input_desc.value = pSecurityInputBlob; input_desc.length = dwSecurityInputBlobLen; dwMajorStatus = gss_init_sec_context( (OM_uint32 *)&dwMinorStatus, pContext->credHandle, pContext->pGSSContext, pContext->target_name, &gss_spnego_mech_oid_desc, GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG, 0, NULL, &input_desc, NULL, &output_desc, &ret_flags, NULL); smb_display_status("gss_init_sec_context", dwMajorStatus, dwMinorStatus); switch (dwMajorStatus) { case GSS_S_CONTINUE_NEEDED: pContext->state = SMB_GSS_SEC_CONTEXT_STATE_NEGOTIATE; break; case GSS_S_COMPLETE: pContext->state = SMB_GSS_SEC_CONTEXT_STATE_COMPLETE; break; case GSS_S_FAILURE: switch (dwMinorStatus) { case ((DWORD) KRB5KRB_AP_ERR_SKEW): dwError = LWIO_ERROR_CLOCK_SKEW; break; case ((DWORD) KRB5KDC_ERR_TGT_REVOKED): dwError = LW_STATUS_KDC_CERT_REVOKED; break; case ((DWORD) KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN): dwError = STATUS_ACCESS_DENIED; break; default: dwError = LWIO_ERROR_GSS; } BAIL_ON_LWIO_ERROR(dwError); break; default: dwError = LWIO_ERROR_GSS; BAIL_ON_LWIO_ERROR(dwError); break; } if (output_desc.length) { dwError = LwIoAllocateMemory( output_desc.length, (PVOID*)&pSecurityBlob); BAIL_ON_LWIO_ERROR(dwError); memcpy(pSecurityBlob, output_desc.value, output_desc.length); dwSecurityBlobLength = output_desc.length; } *ppSecurityBlob = pSecurityBlob; *pdwSecurityBlobLength = dwSecurityBlobLength; cleanup: gss_release_buffer(&dwMinorStatus, &output_desc); return dwError; error: *ppSecurityBlob = NULL; *pdwSecurityBlobLength = 0; LWIO_SAFE_FREE_MEMORY(pSecurityBlob); goto cleanup; }
static NTSTATUS LwIoCredentialCacheToTgt( PIO_CREDS pCacheToken, PIO_CREDS* ppCreds ) { NTSTATUS Status = STATUS_SUCCESS; krb5_context pContext = NULL; krb5_error_code krb5Error = 0; krb5_ccache pCache = NULL; PSTR pszClientPrincipalName = NULL; PSTR pszServerPrincipalName = NULL; PSTR pszDesiredPrincipal = NULL; PSTR pszCredCachePath = NULL; PIO_CREDS pCreds = NULL; BOOLEAN bFoundTgt = FALSE; BOOLEAN bStartSeq = FALSE; krb5_creds creds; krb5_cc_cursor cursor; Status = LwRtlCStringAllocateFromWC16String( &pszDesiredPrincipal, pCacheToken->payload.krb5Ccache.pwszPrincipal); BAIL_ON_NT_STATUS(Status); Status = LwRtlCStringAllocateFromWC16String( &pszCredCachePath, pCacheToken->payload.krb5Ccache.pwszCachePath); BAIL_ON_NT_STATUS(Status); /* Open credentials cache */ krb5Error = krb5_init_context(&pContext); if (krb5Error) { Status = STATUS_INSUFFICIENT_RESOURCES; BAIL_ON_NT_STATUS(Status); } krb5Error = krb5_cc_resolve(pContext, pszCredCachePath, &pCache); if (krb5Error) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } /* Look for a TGT */ krb5Error = krb5_cc_start_seq_get(pContext, pCache, &cursor); if (krb5Error) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } bStartSeq = TRUE; while ((krb5Error = krb5_cc_next_cred(pContext, pCache, &cursor, &creds)) == 0) { /* Look tickets with the intial flag set */ if (creds.ticket_flags & TKT_FLG_INITIAL) { /* Extract and compare client principal with desired principal */ krb5Error = krb5_unparse_name(pContext, creds.client, &pszClientPrincipalName); if (krb5Error) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } if (!strcmp(pszClientPrincipalName, pszDesiredPrincipal)) { bFoundTgt = TRUE; break; } krb5_free_unparsed_name(pContext, pszClientPrincipalName); pszClientPrincipalName = NULL; } krb5_free_cred_contents(pContext, &creds); } if (!bFoundTgt) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } /* Extract server principal name */ krb5Error = krb5_unparse_name(pContext, creds.server, &pszServerPrincipalName); if (krb5Error) { Status = STATUS_UNSUCCESSFUL; BAIL_ON_NT_STATUS(Status); } /* Construct token from krb5 credential data */ Status = LwIoAllocateMemory(sizeof(*pCreds), OUT_PPVOID(&pCreds)); BAIL_ON_NT_STATUS(Status); pCreds->type = IO_CREDS_TYPE_KRB5_TGT; /* Copy principal names */ Status = LwRtlWC16StringAllocateFromCString( &pCreds->payload.krb5Tgt.pwszClientPrincipal, pszClientPrincipalName); BAIL_ON_NT_STATUS(Status); Status = LwRtlWC16StringAllocateFromCString( &pCreds->payload.krb5Tgt.pwszServerPrincipal, pszServerPrincipalName); BAIL_ON_NT_STATUS(Status); /* Set time fields */ pCreds->payload.krb5Tgt.authTime = creds.times.authtime; pCreds->payload.krb5Tgt.startTime = creds.times.starttime; pCreds->payload.krb5Tgt.endTime = creds.times.endtime; pCreds->payload.krb5Tgt.renewTillTime = creds.times.renew_till; /* Copy encryption key */ pCreds->payload.krb5Tgt.keyType = creds.keyblock.enctype; pCreds->payload.krb5Tgt.ulKeySize = creds.keyblock.length; Status = LwIoAllocateMemory( creds.keyblock.length, OUT_PPVOID(&pCreds->payload.krb5Tgt.pKeyData)); BAIL_ON_NT_STATUS(Status); memcpy( pCreds->payload.krb5Tgt.pKeyData, creds.keyblock.contents, creds.keyblock.length); /* Copy tgt */ pCreds->payload.krb5Tgt.tgtFlags = creds.ticket_flags; pCreds->payload.krb5Tgt.ulTgtSize = creds.ticket.length; Status = LwIoAllocateMemory( creds.ticket.length, OUT_PPVOID(&pCreds->payload.krb5Tgt.pTgtData)); BAIL_ON_NT_STATUS(Status); memcpy( pCreds->payload.krb5Tgt.pTgtData, creds.ticket.data, creds.ticket.length); *ppCreds = pCreds; cleanup: LWIO_SAFE_FREE_MEMORY(pszDesiredPrincipal); LWIO_SAFE_FREE_MEMORY(pszCredCachePath); if (pszClientPrincipalName) { krb5_free_unparsed_name(pContext, pszClientPrincipalName); } if (pszServerPrincipalName) { krb5_free_unparsed_name(pContext, pszServerPrincipalName); } if (bFoundTgt) { krb5_free_cred_contents(pContext, &creds); } if (bStartSeq) { krb5_cc_end_seq_get(pContext, pCache, &cursor); } if (pCache) { krb5_cc_close(pContext, pCache); } if (pContext) { krb5_free_context(pContext); } return Status; error: *ppCreds = NULL; if (pCreds) { LwIoDeleteCreds(pCreds); } goto cleanup; }
NTSTATUS LwIoCopyCreds( PIO_CREDS pCreds, PIO_CREDS* ppCredsCopy ) { NTSTATUS Status = STATUS_SUCCESS; PIO_CREDS pCredsCopy = NULL; if (pCreds) { Status = LwIoAllocateMemory(sizeof(*pCredsCopy), OUT_PPVOID(&pCredsCopy)); BAIL_ON_NT_STATUS(Status); pCredsCopy->type = pCreds->type; switch (pCreds->type) { case IO_CREDS_TYPE_PLAIN: Status = RtlWC16StringDuplicate( &pCredsCopy->payload.plain.pwszUsername, pCreds->payload.plain.pwszUsername); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCredsCopy->payload.plain.pwszDomain, pCreds->payload.plain.pwszDomain); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCredsCopy->payload.plain.pwszPassword, pCreds->payload.plain.pwszPassword); BAIL_ON_NT_STATUS(Status); break; case IO_CREDS_TYPE_KRB5_CCACHE: Status = RtlWC16StringDuplicate( &pCredsCopy->payload.krb5Ccache.pwszPrincipal, pCreds->payload.krb5Ccache.pwszPrincipal); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCredsCopy->payload.krb5Ccache.pwszCachePath, pCreds->payload.krb5Ccache.pwszCachePath); BAIL_ON_NT_STATUS(Status); break; case IO_CREDS_TYPE_KRB5_TGT: Status = RtlWC16StringDuplicate( &pCredsCopy->payload.krb5Tgt.pwszClientPrincipal, pCreds->payload.krb5Tgt.pwszClientPrincipal); BAIL_ON_NT_STATUS(Status); Status = RtlWC16StringDuplicate( &pCredsCopy->payload.krb5Tgt.pwszServerPrincipal, pCreds->payload.krb5Tgt.pwszServerPrincipal); BAIL_ON_NT_STATUS(Status); pCredsCopy->payload.krb5Tgt.authTime = pCreds->payload.krb5Tgt.authTime; pCredsCopy->payload.krb5Tgt.startTime = pCreds->payload.krb5Tgt.startTime; pCredsCopy->payload.krb5Tgt.endTime = pCreds->payload.krb5Tgt.endTime; pCredsCopy->payload.krb5Tgt.renewTillTime = pCreds->payload.krb5Tgt.renewTillTime; pCredsCopy->payload.krb5Tgt.keyType = pCreds->payload.krb5Tgt.keyType; pCredsCopy->payload.krb5Tgt.ulKeySize = pCreds->payload.krb5Tgt.ulKeySize; Status = LwIoAllocateMemory( pCreds->payload.krb5Tgt.ulKeySize, OUT_PPVOID(&pCredsCopy->payload.krb5Tgt.pKeyData)); BAIL_ON_NT_STATUS(Status); memcpy( pCredsCopy->payload.krb5Tgt.pKeyData, pCreds->payload.krb5Tgt.pKeyData, pCreds->payload.krb5Tgt.ulKeySize); pCredsCopy->payload.krb5Tgt.tgtFlags = pCreds->payload.krb5Tgt.tgtFlags; pCredsCopy->payload.krb5Tgt.ulTgtSize = pCreds->payload.krb5Tgt.ulTgtSize; Status = LwIoAllocateMemory( pCreds->payload.krb5Tgt.ulTgtSize, OUT_PPVOID(&pCredsCopy->payload.krb5Tgt.pTgtData)); BAIL_ON_NT_STATUS(Status); memcpy( pCredsCopy->payload.krb5Tgt.pTgtData, pCreds->payload.krb5Tgt.pTgtData, pCreds->payload.krb5Tgt.ulTgtSize); break; } *ppCredsCopy = pCredsCopy; } else { *ppCredsCopy = NULL; } cleanup: return Status; error: if (pCredsCopy) { LwIoDeleteCreds(pCredsCopy); } goto cleanup; }
static NTSTATUS SMBPacketBufferAllocatePooled( IN PLWIO_PACKET_ALLOCATOR pPacketAllocator, IN size_t len, OUT uint8_t** ppBuffer, OUT size_t* pAllocatedLen ) { NTSTATUS ntStatus = 0; uint8_t* pBuffer = NULL; size_t allocatedLen = 0; BOOLEAN bInLock = FALSE; LWIO_LOCK_MUTEX(bInLock, &pPacketAllocator->mutex); /* If the len is greater than our current allocator len, adjust */ if (len > pPacketAllocator->freeBufferLen) { SMBStackFree(pPacketAllocator->pFreeBufferStack); pPacketAllocator->pFreeBufferStack = NULL; pPacketAllocator->freeBufferLen = len; } if (pPacketAllocator->pFreeBufferStack) { pBuffer = (uint8_t *) pPacketAllocator->pFreeBufferStack; allocatedLen = pPacketAllocator->freeBufferLen; SMBStackPopNoFree(&pPacketAllocator->pFreeBufferStack); pPacketAllocator->freeBufferCount--; LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); memset(pBuffer, 0, allocatedLen); } else { allocatedLen = pPacketAllocator->freeBufferLen; LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); ntStatus = LwIoAllocateMemory(allocatedLen, (PVOID *) &pBuffer); BAIL_ON_NT_STATUS(ntStatus); } *ppBuffer = pBuffer; *pAllocatedLen = allocatedLen; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pPacketAllocator->mutex); return ntStatus; error: *ppBuffer = NULL; *pAllocatedLen = 0; goto cleanup; }
NTSTATUS RdrTree2Create( PRDR_TREE2* ppTree ) { NTSTATUS status = 0; PRDR_TREE2 pTree = NULL; BOOLEAN bDestroyMutex = FALSE; pthread_mutexattr_t mutexAttr; pthread_mutexattr_t* pMutexAttr = NULL; status = LwIoAllocateMemory( sizeof(RDR_TREE2), (PVOID*)&pTree); BAIL_ON_NT_STATUS(status); LwListInit(&pTree->StateWaiters); status = pthread_mutexattr_init(&mutexAttr); BAIL_ON_NT_STATUS(status); pMutexAttr = &mutexAttr; status = pthread_mutexattr_settype(pMutexAttr, PTHREAD_MUTEX_RECURSIVE); BAIL_ON_NT_STATUS(status); pthread_mutex_init(&pTree->mutex, pMutexAttr); bDestroyMutex = TRUE; /* Pre-allocate resources to send a tree disconnect */ status = RdrCreateContext(NULL, &pTree->pDisconnectContext); BAIL_ON_NT_STATUS(status); status = RdrAllocateContextPacket(pTree->pDisconnectContext, RDR_SMB2_STUB_SIZE); BAIL_ON_NT_STATUS(status); pTree->refCount = 1; pTree->pSession = NULL; pTree->ulTid = 0; pTree->pwszPath = NULL; pTree->version = SMB_PROTOCOL_VERSION_2; *ppTree = pTree; cleanup: if (pMutexAttr) { pthread_mutexattr_destroy(pMutexAttr); } return status; error: if (bDestroyMutex) { pthread_mutex_destroy(&pTree->mutex); } if (pTree) { RdrTree2DestroyContents(pTree); } LWIO_SAFE_FREE_MEMORY(pTree); *ppTree = NULL; goto cleanup; }