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 RdrNegotiateComplete( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pParam; PRDR_SESSION pSession = NULL; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; PIO_CREDS pCreds = pContext->State.TreeConnect.pCreds; BAIL_ON_NT_STATUS(status); /* Several op contexts could be queued with this function * as the continue routine before we transition to SMB2 mode, * so we need to hand off to the correct function in this case. * Subsequent attempts should go straight to connect2.c */ if (pSocket->version == SMB_PROTOCOL_VERSION_2) { /* Short circuit to SMB2 session setup logic in connect2.c */ return RdrNegotiateComplete2(pContext, status, pParam); } if (pContext->State.TreeConnect.bStopOnDfs && pSocket->capabilities & CAP_DFS) { /* Abort tree connect because we need to do DFS referral processing first */ status = STATUS_DFS_EXIT_PATH_FOUND; BAIL_ON_NT_STATUS(status); } status = RdrSessionFindOrCreate( &pSocket, pContext->State.TreeConnect.pCreds, pContext->State.TreeConnect.Uid, &pSession); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSession = pSession; LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); switch (pSession->state) { case RDR_SESSION_STATE_NOT_READY: pSession->state = RDR_SESSION_STATE_INITIALIZING; switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_TGT: status = SMBCredTokenToKrb5CredCache( pCreds, &pContext->State.TreeConnect.pszCachePath); BAIL_ON_NT_STATUS(status); break; case IO_CREDS_TYPE_PLAIN: break; default: status = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(status); } LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrProcessSessionSetupResponse(pContext, STATUS_SUCCESS, NULL); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_INITIALIZING: pContext->Continue = RdrSessionSetupComplete; LwListInsertTail(&pSession->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_READY: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_ERROR: status = pSession->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSessionInvalidate(pSession, status); } RdrSessionRelease(pSession); } if (status != STATUS_PENDING && pSocket) { if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSocketInvalidate(pSocket, status); } RdrSocketRelease(pSocket); } goto cleanup; }