/*++ Copyright (c) 1989 Microsoft Corporation Module Name: smbce.h Abstract: This module defines all functions, along with implementations for inline functions related to accessing the SMB connection engine Revision History: Balan Sethu Raman [SethuR] 6-March-1995 --*/ #ifndef _SMBCE_H_ #define _SMBCE_H_ #define SECURITY_KERNEL #define SECURITY_NTLM #include "security.h" #include "secint.h" #include "md5.h" // // Flag to enable/disable double buffering on exchanges with security signatures. // #define SMBCE_NO_DOUBLE_BUFFERING 0x80000000 // // The SMB protocol has a number of dialects. These reflect the extensions made // to the core protocol over a period of time to cater to increasingly sophisticated // file systems. The connection engine must be capable of dealing with different // dialects implemented by server. The underlying Transport mechanism is used to // uniquely identify the file server and the SMB protocol furnishes the remaining // identification information to uniquely map an SMB onto a particular file opened by // a particular client. The three important pieces of information are the SMB_TREE_ID, // SMB_FILE_ID and SMB_USER_ID. These identify the particular connection made by a // client machine, the particular file opened on that connection, and the user on // behalf of whom the file has been opened. Note that there could be multiple // connections from a client machine to a server machine. Therefore the unique id. is // really connection based rather than machine based. The SMB connection engine // data structures are built around these concepts. // // The known SMB dialects are as follows. // typedef enum _SMB_DIALECT_ { PCNET1_DIALECT, //XENIXCORE_DIALECT, //MSNET103_DIALECT, LANMAN10_DIALECT, WFW10_DIALECT, LANMAN12_DIALECT, LANMAN21_DIALECT, NTLANMAN_DIALECT } SMB_DIALECT, *PSMB_DIALECT; #define NET_ROOT_FILESYSTEM_UNKOWN ((UCHAR)0) #define NET_ROOT_FILESYSTEM_FAT ((UCHAR)1) #define NET_ROOT_FILESYSTEM_NTFS ((UCHAR)2) typedef UCHAR NET_ROOT_FILESYSTEM, *PNET_ROOT_FILESYSTEM; // // The SMBCE_NET_ROOT encapsulates the information pertaining to a share on a server. // //we restrict to the first 7 characters (HPFS386) #define SMB_MAXIMUM_SUPPORTED_VOLUME_LABEL 7 #define MaximumNumberOfVNetRootContextsForScavenging 10 typedef struct _SMBCE_NET_ROOT_ { BOOLEAN DfsAware; NET_ROOT_TYPE NetRootType; NET_ROOT_FILESYSTEM NetRootFileSystem; SMB_USER_ID UserId; ULONG MaximumReadBufferSize; ULONG MaximumWriteBufferSize; LIST_ENTRY ClusterSizeSerializationQueue; ULONG FileSystemAttributes; LONG MaximumComponentNameLength; USHORT CompressionFormatAndEngine; UCHAR CompressionUnitShift; UCHAR ChunkShift; UCHAR ClusterShift; ULONG ChunkSize; //CSC Stuff CSC_ROOT_INFO sCscRootInfo; ULONG CachedNumberOfSrvOpens; BOOLEAN CscEnabled; //this, if we are to automatically build shadows BOOLEAN CscShadowable; //this, if we are allowed to build shadows USHORT CscFlags; // CSC flags as returned by the server BOOLEAN UpdateCscShareRights; // indication to update share rights on the CSC database BOOLEAN Disconnected; LIST_ENTRY DirNotifyList; // head of a list of notify Irps. PNOTIFY_SYNC pNotifySync; // used to synchronize the dir notify list. LIST_ENTRY NotifyeeFobxList; // list of fobx's given to the fsrtl structure FAST_MUTEX NotifyeeFobxListMutex; union { struct { USHORT FileSystemNameLength; WCHAR FileSystemName[SMB_MAXIMUM_SUPPORTED_VOLUME_LABEL]; }; struct { USHORT Pad2; UCHAR FileSystemNameALength; UCHAR FileSystemNameA[SMB_MAXIMUM_SUPPORTED_VOLUME_LABEL]; UCHAR Pad; //this field is used for a null in a dbgprint; don't move it }; }; //ULONG ClusterSize; } SMBCE_NET_ROOT, *PSMBCE_NET_ROOT; // // There are two levels of security in the SMB protocol. User level security and Share level // security. Corresponding to each user in the user level security mode there is a session. // // Typically the password, user name and domain name strings associated with the session entry // revert to the default values, i.e., they are zero. In the event that they are not zero the // SessionString represents a concatenated version of the password,user name and domain name in // that order. This representation in a concatenated way yields us a savings of atleast 3 // USHORT's over other representations. // typedef enum _SECURITY_MODE_ { SECURITY_MODE_SHARE_LEVEL = 0, SECURITY_MODE_USER_LEVEL = 1 } SECURITY_MODE, *PSECURITY_MODE; #define SMBCE_SHARE_LEVEL_SERVER_USERID 0xffffffff typedef enum _SESSION_TYPE_ { UNINITIALIZED_SESSION, LANMAN_SESSION, EXTENDED_NT_SESSION } SESSION_TYPE, *PSESSION_TYPE; typedef enum _SMB_SESSION_KEY_STATE { SmbSessionKeyUnavailible = 0, SmbSessionKeyAuthenticating, SmbSessionKeyAvailible } SMB_SESSION_KEY_STATE; #define SMBCE_SESSION_FLAGS_LANMAN_SESSION_KEY_USED (0x002) #define SMBCE_SESSION_FLAGS_NULL_CREDENTIALS (0x004) #define SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION (0x008) #define SMBCE_SESSION_FLAGS_GUEST_SESSION (0x010) #define SMBCE_SESSION_FLAGS_LOGGED_OFF (0x020) #define SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION (0x040) #define SMBCE_SESSION_FLAGS_SECSIG_ENABLED (0x080) #define SMBCE_SESSION_FLAGS_SESSION_KEY_HASHED (0x100) typedef struct _SMBCE_SESSION_ { SESSION_TYPE Type; SMB_USER_ID UserId; // Flags associated with the session. ULONG Flags; LUID LogonId; PUNICODE_STRING pUserName; PUNICODE_STRING pPassword; PUNICODE_STRING pUserDomainName; SMB_SESSION_KEY_STATE SessionKeyState; UCHAR UserSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH]; UCHAR UserNewSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH]; UCHAR LanmanSessionKey[MSV1_0_LANMAN_SESSION_KEY_LENGTH]; // The credential and context handles. CtxtHandle SecurityContextHandle; CredHandle CredentialHandle; ULONG SessionId; ULONG SessionKeyLength; ULONG NumberOfActiveVNetRoot; ULONG TargetInfoLength; PUSHORT TargetInfoMarshalled; } SMBCE_SESSION, *PSMBCE_SESSION; extern VOID UninitializeSecurityContextsForSession(PSMBCE_SESSION pSession); extern VOID DeleteSecurityContextForSession(PSMBCE_SESSION pSession); // // SMBCE_*_SERVER -- This data structure encapsulates all the information related to a server. // Since there are multiple dialects of the SMB protocol, the capabilities as well as the // actions that need to be taken at the client machine are very different. // // Owing to the number of dialects of the SMB protocol we have two design possibilities. // Either we define an all encompassing data structure and have a code path that // uses the dialect and the capabilities of the connection to determine the action // required, or we use a subclassing mechanism associated with a dispatch vector. // The advantage of the second mechanism is that it can be developed incrementally and // it is very easily extensible. The disadvantage of this mechanism is that it can // lead to a very large footprint, if sufficient care is not exercised during // factorization and we could have lots and lots of procedure calls which has an // adverse effect on the code generated. // // We will adopt the second approach ( Thereby implicitly defining the metrics by // which the code should be evaluated !! ). // // The types of SMBCE_SERVER's can be classified in the following hierarchy // // SMBCE_SERVER // // SMBCE_USER_LEVEL_SERVER // // SMBCE_NT_SERVER // // SMBCE_SHARE_LEVEL_SERVER // // The dispatch vector which defines the set of methods supported by all the connections // (virtual functions in C++ terminology) are as follows // #define RAW_READ_CAPABILITY 0x0001 #define RAW_WRITE_CAPABILITY 0x0002 #define LWIO_CAPABILITY 0x0004 #define COMPRESSED_DATA_CAPABILITY 0x0008 #define ECHO_PROBE_IDLE 0x1 #define ECHO_PROBE_AWAITING_RESPONSE 0x2 #define CRYPT_TEXT_LEN MSV1_0_CHALLENGE_LENGTH typedef struct _NTLANMAN_SERVER_ { ULONG NtCapabilities; GUID ServerGuid; ULONG SecurityBlobLength; PVOID pSecurityBlob; } NTLANMAN_SERVER, *PNTLANMAN_SERVER; typedef struct _SMBCE_SERVER_ { // the server version count ULONG Version; // the dispatch vector struct _SMBCE_SERVER_DISPATCH_VECTOR_ *pDispatch; // the SMB dialect SMB_DIALECT Dialect; // More Server Capabilities ULONG DialectFlags; // the session key ULONG SessionKey; // the server Ip address ULONG IpAddress; // Security mode supported on the server SECURITY_MODE SecurityMode; // Time zone bias for conversion. LARGE_INTEGER TimeZoneBias; // Echo Expiry Time LARGE_INTEGER EchoExpiryTime; LONG SmbsReceivedSinceLastStrobe; //CSC stuff LONG CscState; LONG EchoProbeState; LONG NumberOfEchoProbesSent; // Maximum negotiated buffer size. ULONG MaximumBufferSize; // maximum buffer size for read/write operations ULONG MaximumDiskFileReadBufferSize; ULONG MaximumNonDiskFileReadBufferSize; ULONG MaximumDiskFileWriteBufferSize; ULONG MaximumNonDiskFileWriteBufferSize; // This is used to detect the number of server opens. If it is larger than 0, // we shouldn't tear down the current transport in case the user provides the transport. LONG NumberOfSrvOpens; LONG NumberOfVNetRootContextsForScavenging; LONG MidCounter; // Maximum number of multiplexed requests USHORT MaximumRequests; // Maximum number of VC's USHORT MaximumVCs; // Server Capabilities USHORT Capabilities; // encrypt passwords BOOLEAN EncryptPasswords; BOOLEAN SecuritySignaturesEnabled; BOOLEAN SecuritySignaturesRequired; // distinguishes a loopback connections BOOLEAN IsLoopBack; // TRUE if the same server is being referred to by multiple names BOOLEAN AliasedServers; BOOLEAN IsRemoteBootServer; // There are certain servers that return DF_NT_SMBS in the negotiate // but do not support change notifies. This allows us to suppress // change notify requests to those servers. BOOLEAN ChangeNotifyNotSupported; // avoid multiple event logs posted for security context failures BOOLEAN EventLogPosted; // The sessions on this server should use the extended timeout interval BOOLEAN ExtendedSessTimeout; USHORT EncryptionKeyLength; UCHAR EncryptionKey[CRYPT_TEXT_LEN]; // Dialect specific information union { NTLANMAN_SERVER NtServer; }; MD5_CTX SmbSecuritySignatureIntermediateContext; ULONG SmbSecuritySignatureIndex; BOOLEAN IsFakeDfsServerForOfflineUse; BOOLEAN IsPinnedOffline; } SMBCE_SERVER, *PSMBCE_SERVER; typedef NTSTATUS (*PBUILD_SESSION_SETUP_SMB)( IN OUT struct _SMB_EXCHANGE *pExchange, IN OUT PGENERIC_ANDX pSmb, IN OUT PULONG pBufferSize ); typedef NTSTATUS (*PBUILD_TREE_CONNECT_SMB)( IN OUT struct _SMB_EXCHANGE *pExchange, IN OUT PGENERIC_ANDX pSmb, IN OUT PULONG pBufferSize ); typedef struct _SMBCE_SERVER_DISPATCH_VECTOR_ { PBUILD_SESSION_SETUP_SMB BuildSessionSetup; PBUILD_TREE_CONNECT_SMB BuildTreeConnect; } SMBCE_SERVER_DISPATCH_VECTOR, *PSMBCE_SERVER_DISPATCH_VECTOR; #define SMBCE_SERVER_DIALECT_DISPATCH(pServer,Routine,Arguments) \ (*((pServer)->pDispatch->Routine))##Arguments // The SMBCE engine process all requests in an asychronous fashion. Therefore for synchronous // requests an additional mechanism is required for synchronization. The following data structure // provides an easy way for implementing this synchronization. // // NOTE: For asynchronous resumption contexts the resumption routine can be invoked // at DPC level. #define SMBCE_RESUMPTION_CONTEXT_FLAG_ASYNCHRONOUS (0x1) typedef struct SMBCE_RESUMPTION_CONTEXT { ULONG Flags; NTSTATUS Status; // the status PVOID pContext; // a void pointer for clients to add additional context information union { PRX_WORKERTHREAD_ROUTINE pRoutine; // asynchronous contexts KEVENT Event; // the event for synchronization }; BOOLEAN SecuritySignatureReturned; } SMBCE_RESUMPTION_CONTEXT, *PSMBCE_RESUMPTION_CONTEXT; #define SmbCeIsResumptionContextAsynchronous(pResumptionContext) \ ((pResumptionContext)->Flags & SMBCE_RESUMPTION_CONTEXT_FLAG_ASYNCHRONOUS) INLINE VOID SmbCeInitializeResumptionContext( PSMBCE_RESUMPTION_CONTEXT pResumptionContext) { KeInitializeEvent(&(pResumptionContext)->Event,NotificationEvent,FALSE); pResumptionContext->Status = STATUS_SUCCESS; pResumptionContext->Flags = 0; pResumptionContext->pContext = NULL; } INLINE VOID SmbCeInitializeAsynchronousResumptionContext( PSMBCE_RESUMPTION_CONTEXT pResumptionContext, PRX_WORKERTHREAD_ROUTINE pResumptionRoutine, PVOID pResumptionRoutineParam) { pResumptionContext->Status = STATUS_SUCCESS; pResumptionContext->Flags = SMBCE_RESUMPTION_CONTEXT_FLAG_ASYNCHRONOUS; pResumptionContext->pContext = pResumptionRoutineParam; pResumptionContext->pRoutine = pResumptionRoutine; } INLINE VOID SmbCeSuspend( PSMBCE_RESUMPTION_CONTEXT pResumptionContext) { ASSERT(!(pResumptionContext->Flags & SMBCE_RESUMPTION_CONTEXT_FLAG_ASYNCHRONOUS)); KeWaitForSingleObject( &pResumptionContext->Event, Executive, KernelMode, FALSE, NULL); } INLINE VOID SmbCeResume( PSMBCE_RESUMPTION_CONTEXT pResumptionContext) { if (!(pResumptionContext->Flags & SMBCE_RESUMPTION_CONTEXT_FLAG_ASYNCHRONOUS)) { KeSetEvent(&(pResumptionContext)->Event,0,FALSE); } else { if (RxShouldPostCompletion()) { RxDispatchToWorkerThread( MRxSmbDeviceObject, CriticalWorkQueue, pResumptionContext->pRoutine, pResumptionContext->pContext); } else { (pResumptionContext->pRoutine)(pResumptionContext->pContext); } } } // // The SMBCE_REQUEST struct encapsulates the continuation context associated. Typically // the act of sending a SMB along an exchange results in a SMBCE_REQUEST structure being // created with sufficient context information to resume the exchange upon reciept of // response from the serve. The SMBCE_REQUEST conatins ebough information to identify // the SMB for which the response is being obtained followed by enough context information // to resume the exchange. // typedef enum _SMBCE_OPERATION_ { SMBCE_TRANCEIVE, SMBCE_RECEIVE, SMBCE_SEND, SMBCE_ASYNCHRONOUS_SEND, SMBCE_ACQUIRE_MID } SMBCE_OPERATION, *PSMBCE_OPERATION; typedef enum _SMBCE_REQUEST_TYPE_ { ORDINARY_REQUEST, COPY_DATA_REQUEST, RECONNECT_REQUEST, ACQUIRE_MID_REQUEST, HOLD_REQUEST } SMBCE_REQUEST_TYPE, *PSMBCE_REQUEST_TYPE; typedef struct _SMBCE_GENERIC_REQUEST_ { SMBCE_REQUEST_TYPE Type; // the exchange instance that originated this SMB struct _SMB_EXCHANGE * pExchange; } SMBCE_GENERIC_REQUEST, *PSMBCE_GENERIC_REQUEST; // // The release routine prototype definition. // typedef NTSTATUS (*PSMBCE_RELEASE_ROUTINE) ( struct _SMB_EXCHANGE * pExchange, PRX_CONTEXT pRxContext ); // // Request to hold an exchange in suspension until someone releases it. // typedef struct _SMBCE_HOLD_REQUEST_ { SMBCE_GENERIC_REQUEST; PSMBCE_RELEASE_ROUTINE ReleaseRoutine; } SMBCE_HOLD_REQUEST, *PSMBCE_HOLD_REQUEST; typedef struct _SMBCE_REQUEST_ { SMBCE_GENERIC_REQUEST; // the type of request SMBCE_OPERATION Operation; // the virtual circuit along which this request was sent. PRXCE_VC pVc; // MPX Id of outgoing request. SMB_MPX_ID Mid; // the pedigree of the request SMB_TREE_ID TreeId; // The Tree Id. SMB_FILE_ID FileId; // The file id. SMB_USER_ID UserId; // User Id. for cancel. SMB_PROCESS_ID ProcessId; // Process Id. for cancel. PMDL pSendBuffer; ULONG BytesSent; } SMBCE_REQUEST, *PSMBCE_REQUEST; typedef struct _SMBCE_COPY_DATA_REQUEST_ { SMBCE_GENERIC_REQUEST; // the virtual circuit along which this request was sent. PRXCE_VC pVc; // the buffer into whihc data is being copied. PVOID pBuffer; // the actual number of bytes copied ULONG BytesCopied; } SMBCE_COPY_DATA_REQUEST, *PSMBCE_COPY_DATA_REQUEST; typedef struct _SMBCE_RECONNECT_REQUEST_ { SMBCE_GENERIC_REQUEST; } SMBCE_RECONNECT_REQUEST, *PSMBCE_RECONNECT_REQUEST; typedef struct _SMBCE_MID_REQUEST_ { SMBCE_GENERIC_REQUEST; PSMBCE_RESUMPTION_CONTEXT pResumptionContext; } SMBCE_MID_REQUEST, *PSMBCE_MID_REQUEST; // // extern function declarations // extern NTSTATUS BuildSessionSetupSmb( struct _SMB_EXCHANGE *pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize); extern NTSTATUS CoreBuildTreeConnectSmb( struct _SMB_EXCHANGE *pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize); extern NTSTATUS LmBuildTreeConnectSmb( struct _SMB_EXCHANGE *pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize); extern NTSTATUS NtBuildTreeConnectSmb( struct _SMB_EXCHANGE *pExchange, PGENERIC_ANDX pAndXSmb, PULONG pAndXSmbBufferSize); extern NTSTATUS BuildNegotiateSmb( PVOID *pSmbBufferPointer, PULONG pSmbBufferLength, BOOLEAN RemoteBootSession); extern NTSTATUS ParseNegotiateResponse( IN OUT struct _SMB_ADMIN_EXCHANGE_ *pExchange, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT PULONG pBytesTaken, IN PSMB_HEADER pSmbHeader, OUT PMDL *pDataBufferPointer, OUT PULONG pDataSize); extern NTSTATUS SmbCeHoldExchangeForSessionRecovery( struct _SMB_EXCHANGE *pExchange, PSMBCE_RELEASE_ROUTINE pRoutine ); extern struct _MINIRDR_DISPATCH MRxSmbDispatch; #endif // _SMBCE_H_