/*++ BUILD Version: 0009 // Increment this if a change has global effects Copyright (c) 1987-1993 Microsoft Corporation Module Name: 3connect.c Abstract: This module implements the tree connect SMB related routines. It also implements the three flavours of this routine ( user level and share level non NT server tree connect SMB construction and the tree connect SMB construction for SMB servers) --*/ #include "precomp.h" #pragma hdrstop #include "ntlsapi.h" // // The order of these names should match the order in which the enumerated type // NET_ROOT_TYPE is defined. This facilitates easy access of share type names // PCHAR s_NetRootTypeName[] = { SHARE_TYPE_NAME_DISK, SHARE_TYPE_NAME_PIPE, SHARE_TYPE_NAME_COMM, SHARE_TYPE_NAME_PRINT, SHARE_TYPE_NAME_WILD }; extern NTSTATUS BuildTreeConnectSecurityInformation( PSMB_EXCHANGE pExchange, PBYTE pBuffer, PBYTE pPasswordLength, PULONG pSmbBufferSize); NTSTATUS BuildCanonicalNetRootInformation( PUNICODE_STRING pServerName, PUNICODE_STRING pNetRootName, NET_ROOT_TYPE NetRootType, BOOLEAN fUnicode, BOOLEAN fPostPendServiceString, PBYTE *pBufferPointer, PULONG pBufferSize) /*++ Routine Description: This routine builds the desired net root information for a tree connect SMB Arguments: pServerName - the server name pNetRootName - the net root name NetRootType - the net root type ( print,pipe,disk etc.,) fUnicode - TRUE if it is to be built in UNICODE pBufferPointer - the SMB buffer pBufferSize - the size on input. modified to the remaining size on output Return Value: RXSTATUS - The return status for the operation Notes: This routine relies upon the names being in certain formats to ensure that a valid UNC name can be formulated. 1) The RDBSS netroot names start with a \ and also include the server name as part of the net root name. This is mandated by the prefix table search requirements in RDBSS. --*/ { NTSTATUS Status; if (fUnicode) { // Align the buffer and adjust the size accordingly. PBYTE pBuffer = *pBufferPointer; RxDbgTrace( 0, (DEBUG_TRACE_CREATE), ("BuildCanonicalNetRootInformation -- tcstring as unicode %wZ\n", pNetRootName)); pBuffer = ALIGN_SMB_WSTR(pBuffer); *pBufferSize -= (pBuffer - *pBufferPointer); *pBufferPointer = pBuffer; *((PWCHAR)*pBufferPointer) = L'\\'; *pBufferPointer = *pBufferPointer + sizeof(WCHAR); *pBufferSize -= sizeof(WCHAR); Status = SmbPutUnicodeStringAndUpcase(pBufferPointer,pNetRootName,pBufferSize); } else { RxDbgTrace( 0, (DEBUG_TRACE_CREATE), ("BuildCanonicalNetRootInformation -- tcstring as ascii\n")); *((PCHAR)*pBufferPointer) = '\\'; *pBufferPointer += sizeof(CHAR); *pBufferSize -= sizeof(CHAR); Status = SmbPutUnicodeStringAsOemStringAndUpcase(pBufferPointer,pNetRootName,pBufferSize); } if (NT_SUCCESS(Status) && fPostPendServiceString) { // Put the desired service name in ASCII ( always ) ULONG Length = strlen(s_NetRootTypeName[NetRootType]) + 1; if (*pBufferSize >= Length) { RtlCopyMemory(*pBufferPointer,s_NetRootTypeName[NetRootType],Length); *pBufferSize -= Length; } else { Status = STATUS_BUFFER_OVERFLOW; } } return Status; } NTSTATUS CoreBuildTreeConnectSmb( PSMB_EXCHANGE pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize) /*++ Routine Description: This routine builds the tree connect SMB for a pre NT server Arguments: pExchange - the exchange instance pAndXSmb - the tree connect to be filled in...it's not really a andX pAndXSmbBufferSize - the SMB buffer size on input modified to remaining size on output. Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; USHORT PasswordLength; PMRX_NET_ROOT NetRoot; UNICODE_STRING ServerName; UNICODE_STRING NetRootName; PSMBCE_SERVER pServer; PREQ_TREE_CONNECT pTreeConnect = (PREQ_TREE_CONNECT)pAndXSmb; ULONG OriginalBufferSize = *pAndXSmbBufferSize; BOOLEAN AppendServiceString; PBYTE pBuffer; PCHAR ServiceName; // = s_NetRootTypeName[NET_ROOT_WILD]; ULONG Length; // = strlen(ServiceName) + 1; NetRoot = pExchange->SmbCeContext.pVNetRoot->pNetRoot; RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("CoreBuildTreeConnectSmb buffer,remptr %08lx %08lx, nrt=%08lx\n",pAndXSmb,pAndXSmbBufferSize,NetRoot->Type)); pServer = &pExchange->SmbCeContext.pServerEntry->Server; SmbCeGetServerName(NetRoot->pSrvCall,&ServerName); SmbCeGetNetRootName(NetRoot,&NetRootName); ServiceName = s_NetRootTypeName[NetRoot->Type]; Length = strlen(ServiceName) + 1; pTreeConnect->WordCount = 0; AppendServiceString = FALSE; pBuffer = (PBYTE)pTreeConnect + FIELD_OFFSET(REQ_TREE_CONNECT,Buffer); *pBuffer = 0x04; pBuffer++; *pAndXSmbBufferSize -= (FIELD_OFFSET(REQ_TREE_CONNECT,Buffer)+1); // put in the netname Status = BuildCanonicalNetRootInformation( &ServerName, &NetRootName, pExchange->SmbCeContext.pVNetRoot->pNetRoot->Type, (BOOLEAN)(pServer->Dialect >= NTLANMAN_DIALECT), AppendServiceString, &pBuffer, pAndXSmbBufferSize); if (!NT_SUCCESS(Status)) return Status; // put in the password pBuffer = (PBYTE)pTreeConnect + OriginalBufferSize - *pAndXSmbBufferSize; *pBuffer = 0x04; pBuffer++; *pAndXSmbBufferSize -= 1; if (pServer->SecurityMode == SECURITY_MODE_SHARE_LEVEL) { // The password information needs to be sent as part of the tree connect // SMB for share level servers. Status = BuildTreeConnectSecurityInformation( pExchange, pBuffer, (PBYTE)&PasswordLength, pAndXSmbBufferSize); } // string in the service string based on the netroot type pBuffer = (PBYTE)pTreeConnect + OriginalBufferSize - *pAndXSmbBufferSize; *pBuffer = 0x04; pBuffer++; *pAndXSmbBufferSize -= 1; if (*pAndXSmbBufferSize >= Length) { RtlCopyMemory(pBuffer,ServiceName,Length); *pAndXSmbBufferSize -= Length; } else { Status = STATUS_BUFFER_OVERFLOW; } SmbPutUshort(&pTreeConnect->ByteCount, (USHORT)(OriginalBufferSize - *pAndXSmbBufferSize - FIELD_OFFSET(REQ_TREE_CONNECT,Buffer) ) ); RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("CoreBuildTreeConnectSmb end buffer,rem %08lx %08lx\n",pBuffer,*pAndXSmbBufferSize)); return Status; } NTSTATUS LmBuildTreeConnectSmb( PSMB_EXCHANGE pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize) /*++ Routine Description: This routine builds the tree connect SMB for a pre NT server Arguments: pExchange - the exchange instance pAndXSmb - the tree connect to be filled in...it's not really a andX pAndXSmbBufferSize - the SMB buffer size on input modified to remaining size on output. Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; USHORT PasswordLength; PMRX_NET_ROOT NetRoot; UNICODE_STRING ServerName; UNICODE_STRING NetRootName; PSMBCE_SERVER pServer; PREQ_TREE_CONNECT_ANDX pTreeConnectAndX = (PREQ_TREE_CONNECT_ANDX)pAndXSmb; ULONG OriginalBufferSize = *pAndXSmbBufferSize; BOOLEAN AppendServiceString; PBYTE pBuffer; PCHAR ServiceName; ULONG Length; NetRoot = pExchange->SmbCeContext.pVNetRoot->pNetRoot; RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("LmBuildTreeConnectSmb buffer,remptr %08lx %08lx, nrt=%08lx\n",pAndXSmb,pAndXSmbBufferSize,NetRoot->Type)); pServer = &pExchange->SmbCeContext.pServerEntry->Server; SmbCeGetServerName(NetRoot->pSrvCall,&ServerName); SmbCeGetNetRootName(NetRoot,&NetRootName); ServiceName = s_NetRootTypeName[NetRoot->Type]; Length = strlen(ServiceName) + 1; AppendServiceString = TRUE; pTreeConnectAndX->WordCount = 4; SmbPutUshort(&pTreeConnectAndX->AndXReserved,0); SmbPutUshort(&pTreeConnectAndX->Flags,0); pBuffer = (PBYTE)pTreeConnectAndX + FIELD_OFFSET(REQ_TREE_CONNECT_ANDX,Buffer); *pAndXSmbBufferSize -= (FIELD_OFFSET(REQ_TREE_CONNECT_ANDX,Buffer)+1); if (pServer->SecurityMode == SECURITY_MODE_SHARE_LEVEL) { // The password information needs to be sent as part of the tree connect // SMB for share level servers. Status = BuildTreeConnectSecurityInformation( pExchange, pBuffer, (PBYTE)&PasswordLength, pAndXSmbBufferSize); if (Status == STATUS_SUCCESS) { pBuffer += PasswordLength; SmbPutUshort(&pTreeConnectAndX->PasswordLength,PasswordLength); } } else { pBuffer = (PBYTE)pTreeConnectAndX + FIELD_OFFSET(REQ_TREE_CONNECT_ANDX,Buffer); *pAndXSmbBufferSize -= FIELD_OFFSET(REQ_TREE_CONNECT_ANDX,Buffer); // No password is required for user level security servers as part of tree // connect SmbPutUshort(&pTreeConnectAndX->PasswordLength,0x1); *((PCHAR)pBuffer) = '\0'; pBuffer += sizeof(CHAR); *pAndXSmbBufferSize -= sizeof(CHAR); Status = STATUS_SUCCESS; } if (Status == STATUS_SUCCESS) { Status = BuildCanonicalNetRootInformation( &ServerName, &NetRootName, pExchange->SmbCeContext.pVNetRoot->pNetRoot->Type, (BOOLEAN)(pServer->Dialect >= NTLANMAN_DIALECT), AppendServiceString, &pBuffer, pAndXSmbBufferSize); if (Status == STATUS_SUCCESS) { SmbPutUshort(&pTreeConnectAndX->ByteCount, (USHORT)(OriginalBufferSize - *pAndXSmbBufferSize - FIELD_OFFSET(REQ_TREE_CONNECT_ANDX,Buffer) ) ); } RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("LmBuildTreeConnectSmb end buffer,rem %08lx %08lx\n",pBuffer,*pAndXSmbBufferSize)); } return Status; }