/// <summary> /// update the context of smb server /// </summary> /// <param name="connection">the connection of the client</param> /// <param name="packet">the packet to update the context</param> internal void UpdateRoleContext(SmbServerConnection connection, SmbPacket packet) { if (connection == null) { return; } // packet status SmbStatus packetStatus = (SmbStatus)packet.SmbHeader.Status; // filter error packet if (packetStatus != SmbStatus.STATUS_SUCCESS && packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED && packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW) { return; } // process the response packet. if (packet.PacketType == SmbPacketType.BatchedResponse || packet.PacketType == SmbPacketType.SingleResponse) { ResponsePacketUpdateRoleContext(connection, packet); return; } // process the request packet. if (packet.PacketType == SmbPacketType.BatchedRequest || packet.PacketType == SmbPacketType.SingleRequest) { RequestPacketUpdateRoleContext(connection, packet); return; } }
/// <summary> /// Remove connection from the context. if connection does not exists, do nothing. /// </summary> /// <param name="connection">the connection to remove</param> internal void RemoveConnection(SmbServerConnection connection) { lock (this.connectionList) { if (this.connectionList.Contains(connection)) { this.connectionList.Remove(connection); } } }
/// <summary> /// to decode stack packet from the received message bytes. /// the message bytes contains data without transport information /// </summary> /// <param name = "connection">the connection from which the message bytes are received. </param> /// <param name = "packetBytesWithoutTransport">the received message bytes to be decoded. </param> /// <param name = "consumedLength">the length of message bytes consumed by decoder. </param> /// <param name = "expectedLength">the length of message bytes the decoder expects to receive. </param> /// <returns>the stack packets decoded from the received message bytes. </returns> /// <exception cref="InvalidOperationException"> /// thrown when packet security signature is invalid. /// </exception> private SmbPacket[] DecodePacketFromBytesWithoutTransport( SmbServerConnection connection, byte[] packetBytesWithoutTransport, out int consumedLength, out int expectedLength) { expectedLength = 0; consumedLength = 0; SmbPacket[] packets = new SmbPacket[0]; int packetConsumedLength = 0; int packetExpectedLength = 0; // decode packets using cifs decorder. SmbPacket request = this.DecodeSmbRequestFromBytes( packetBytesWithoutTransport, out packetConsumedLength); // valid the signature if (request != null && request.SmbHeader.SecurityFeatures != 0 && connection.GssApi != null && connection.GssApi.SessionKey != null) { byte[] bytesToValid = ArrayUtility.SubArray(packetBytesWithoutTransport, 0); // the signature offset is 14. byte[] zeroSignature = new byte[sizeof(ulong)]; Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length); // the signature offset is 14. zeroSignature = BitConverter.GetBytes((ulong)connection.ServerNextReceiveSequenceNumber); Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length); byte[] signature = CifsMessageUtils.CreateSignature(bytesToValid, connection.GssApi.SessionKey); if (request.SmbHeader.SecurityFeatures != BitConverter.ToUInt64(signature, 0)) { throw new InvalidOperationException("packet security signature is invalid"); } } // Use the decoded packet to UpdateRoleContext if it is not null and ContextUpdate is enabled: if (request != null) { if (this.context.IsUpdateContext) { this.context.UpdateRoleContext(connection, request); } packets = new SmbPacket[] { request }; } // update the length after decode packet. consumedLength += packetConsumedLength; expectedLength += packetExpectedLength; return(packets); }
/// <summary> /// Add Connection to context /// </summary> /// <param name="connection">the connection</param> /// <exception cref="InvalidOperationException"> /// the connection already exists in the connection list, can not add duplicate connection /// </exception> internal void AddConnection(SmbServerConnection connection) { lock (this.connectionList) { if (this.connectionList.Contains(connection)) { throw new InvalidOperationException( "the connection already exists in the connection list, can not add duplicate connection"); } this.connectionList.Add(connection); } }
/// <summary> /// Create SMB_COM_OPEN_ANDX Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "fileId"> /// This field MUST be the SMB file identifier returned by the SMB server for the file or device that was /// opened or created /// </param> /// <param name="fileType">the type of file to open</param> /// <param name="byteCount"> /// This value should be set to zero.Windows-based servers may return a response where the ByteCount field is /// not initialized to 0. /// </param> /// <returns>The SmbOpenAndXResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbOpenAndxResponsePacket CreateSmbComOpenResponse( SmbServerConnection connection, ushort fileId, ResourceTypeValue fileType, ushort byteCount) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbOpenAndxResponsePacket packet = new SmbOpenAndxResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_OPEN_ANDX, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_OPEN_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.FID = fileId; smbParameters.FileAttrs = (SmbFileAttributes)0x00; smbParameters.LastWriteTime.Time = (uint)DateTime.Now.ToFileTime(); smbParameters.DataSize = 0x0; smbParameters.GrantedAccess = (AccessRightsValue)0x00; smbParameters.FileType = fileType; smbParameters.DeviceState = SMB_NMPIPE_STATUS.None; smbParameters.Action = OpenResultsValues.OpenResult3; smbParameters.ServerFid = 0x00; smbParameters.MaximalAccessRights = connection.MaximalShareAccessRights; smbParameters.GuestMaximalAccessRights = connection.GuestMaximalShareAccessRights; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_OPEN_ANDX_Response_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_OPEN_ANDX_Response_SMB_Data smbData = packet.SmbData; // update smbData.ByteCount smbData.ByteCount = byteCount; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create SMB_COM_NEGOTIATE response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "securityMode"> /// An 8-bit field, indicating the security modes supported or REQUIRED by the server /// </param> /// <param name = "maxBufferSize"> /// The maximum size, in bytes, of the largest SMB message the server can receive. This is the size of the /// SMB message that the client MAY send to the server. SMB message size includes the size of the SMB /// parameter, and data blocks. This size does not include any transport-layer framing or other data. The /// server MUST provide a MaxBufferSize of 1024 bytes (1Kbyte) or larger. If CAP_RAW_MODE is then the /// SMB_COM_WRITE_RAW command can bypass the MaxBufferSize limit. Otherwise, SMB messages sent to server /// MUST have a total size less than or equal to the MaxBufferSize value. This includes AndX chained /// </param> /// <param name="maxMpxCount"> /// The maximum number of outstanding SMB operations the server supports. This value includes existing /// OpLocks, the NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other command that are pending on the server. /// If the negotiated MaxMpxCount is one, then OpLock support MUST be disabled for this session. The /// MaxMpxCount MUST be greater than zero. This parameter has no specific relationship to the /// SMB_COM_READ_MPX and SMB_COM_WRITE_MPX commands. /// </param> /// <returns>a smb negotiate response packet </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> /// <exception cref="NotImplementedException">the security package is invalid</exception> public virtual SmbNegotiateResponsePacket CreateSmbComNegotiateResponse( SmbServerConnection connection, SecurityModes securityMode, uint maxBufferSize, ushort maxMpxCount) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbNegotiateResponsePacket packet = new SmbNegotiateResponsePacket(); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NEGOTIATE, connection.ProcessId, connection.MessageId, 0, 0, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Parameters smbParameters = packet.SmbParameters; ushort dialectIndex = 0x00; byte wordCount = 0x00; connection.GetPreferedDialectIndex(out dialectIndex, out wordCount); smbParameters.WordCount = wordCount; smbParameters.DialectIndex = dialectIndex; smbParameters.SecurityMode = securityMode; smbParameters.MaxBufferSize = maxBufferSize; smbParameters.MaxMpxCount = maxMpxCount; smbParameters.Capabilities = connection.ServerCapabilities; smbParameters.SystemTime.Time = (ulong)DateTime.Now.ToFileTime(); // update smb data SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Data smbData = packet.SmbData; if (connection.GssApi == null) { connection.GssApi = new SspiServerSecurityContext( SecurityPackageType.Negotiate, this.credential, "cifs/" + Environment.MachineName, ServerSecurityContextAttribute.Connection, SecurityTargetDataRepresentation.SecurityNetworkDrep); } // to generate the token. connection.GssApi.Accept(null); smbData.SecurityBlob = connection.GssApi.Token; // update smbData.ByteCount smbData.ByteCount = 0; smbData.ByteCount += (ushort)CifsMessageUtils.GetSize<Guid>(smbData.ServerGuid); if (smbData.SecurityBlob != null) { smbData.ByteCount += (ushort)smbData.SecurityBlob.Length; } // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create SMB_COM_LOGOFF_ANDX packet /// </summary> /// <param name="connection">the connection identified the client</param> /// <returns>a SMB_COM_LOGOFF_ANDX packet </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbLogoffAndxResponsePacket CreateSmbComLogoffResponse(SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbLogoffAndxResponsePacket packet = new SmbLogoffAndxResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_LOGOFF_ANDX, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_LOGOFF_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_LOGOFF_ANDX_Response_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_LOGOFF_ANDX_Response_SMB_Data smbData = packet.SmbData; // update smbData.ByteCount smbData.ByteCount = 0; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create NT_TRANSACT_SET_QUOTA Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <returns>The SmbNtTransSetQuotaResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNtTransSetQuotaResponsePacket CreateNtTransSetQuotaResponse(SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbNtTransSetQuotaResponsePacket packet = new SmbNtTransSetQuotaResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NT_TRANSACT, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; // reserved 3 bytes. smbParameters.Reserved1 = new byte[3]; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create NT_TRANSACT_CREATE Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "fileId"> /// The SMB file identifier returned by the SMB server for the file or device that was opened or created /// </param> /// <param name = "createAction">The action taken. This field MUST be interpreted as follows </param> /// <param name = "extFileAttributes">Extended attributes and flags for this file or directory </param> /// <param name = "fileType">The file type </param> /// <param name = "isDirectory"> /// A value that indicates whether this is a directory. MUST be nonzero when this is a directory /// </param> /// <returns>The SmbNtTransactCreateResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNtTransactCreateResponsePacket CreateNtTransCreateResponse( SmbServerConnection connection, ushort fileId, uint createAction, uint extFileAttributes, FileTypeValue fileType, bool isDirectory) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbNtTransactCreateResponsePacket packet = new SmbNtTransactCreateResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NT_TRANSACT, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; // reserved 3 bytes. smbParameters.Reserved1 = new byte[3]; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData; // update smbData.ByteCount smbData.ByteCount = 0; // update nt transaction parameters NT_TRANSACT_CREATE_Response_NT_Trans_Parameters ntTransPamameters = packet.NtTransParameters; ntTransPamameters.FID = fileId; ntTransPamameters.CreateAction = (NtTransactCreateActionValues)createAction; ntTransPamameters.ExtFileAttributes = (SMB_EXT_FILE_ATTR)extFileAttributes; ntTransPamameters.ResourceType = fileType; ntTransPamameters.Directory = (byte)(isDirectory ? 1 : 0); // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.NtTransParameters = ntTransPamameters; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Send bytes to specific connected client. /// </summary> /// <param name="bytes">the bytes to send to client</param> /// <param name="connection">the connection identified client</param> /// <exception cref="ArgumentNullException">the connection is null</exception> public virtual void SendBytes(byte[] bytes, SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } this.transport.SendBytes(connection.Identity, bytes); }
/// <summary> /// Create SMB_COM_TREE_CONNECT_ANDX Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "treeId"> /// This field identifies the subdirectory (or tree) (also referred to as a share in this document) on the /// server that the client is accessing /// </param> /// <param name = "service">The Service field indicates the type of resource the client is accessing </param> /// <param name = "nativeFileSystem"> /// The name of the file system on the local resource that is being connected to /// </param> /// <returns>The SmbTreeConnectAndXResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTreeConnectAndxResponsePacket CreateSmbComTreeConnectResponse( SmbServerConnection connection, ushort treeId, string service, string nativeFileSystem) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTreeConnectAndxResponsePacket packet = new SmbTreeConnectAndxResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TREE_CONNECT_ANDX, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, treeId, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.OptionalSupport = connection.OptionalSupport; smbParameters.MaximalShareAccessRights = connection.MaximalShareAccessRights; smbParameters.GuestMaximalShareAccessRights = connection.GuestMaximalShareAccessRights; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Data smbData = packet.SmbData; smbData.Service = CifsMessageUtils.ToSmbStringBytes(service, false); smbData.NativeFileSystem = CifsMessageUtils.ToSmbStringBytes(nativeFileSystem, connection.Capability.IsUnicode); // update smbData.ByteCount smbData.ByteCount = 0; if (smbData.Service != null) { smbData.ByteCount += (ushort)smbData.Service.Length; } if (smbData.NativeFileSystem != null) { smbData.ByteCount += (ushort)smbData.NativeFileSystem.Length; } // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create SMB_COM_SESSION_SETUP_ANDX Server response packet /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "uid"> /// the valid session id, must be response by server of the session setup request. /// </param> /// <param name = "action">A 16-bit field. The two lowest order bits have been defined </param> /// <returns>The SmbSessionSetupAndXResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbSessionSetupAndxResponsePacket CreateSmbComSessionSetupResponse( SmbServerConnection connection, ushort uid, ActionValues action ) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbSessionSetupAndxResponsePacket packet = new SmbSessionSetupAndxResponsePacket(); // create smb packet header SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_SESSION_SETUP_ANDX, connection.ProcessId, connection.MessageId, uid, 0, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.Action = action; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); #region Generate security blob according to client request. byte[] securityBlob = null; SmbSessionSetupAndxRequestPacket request = connection.GetRequestPacket(connection.MessageId) as SmbSessionSetupAndxRequestPacket; if (request != null) { connection.GssApi.Accept(request.SmbData.SecurityBlob); securityBlob = connection.GssApi.Token; if (connection.GssApi.NeedContinueProcessing) { unchecked { smbHeader.Status = (uint)SmbStatus.STATUS_MORE_PROCESSING_REQUIRED; } } } #endregion smbParameters.SecurityBlobLength = (ushort)securityBlob.Length; // update smb data SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Data smbData = packet.SmbData; smbData.SecurityBlob = securityBlob; if (connection.Capability.IsUnicode && (smbParameters.SecurityBlobLength % SmbCapability.TWO_BYTES_ALIGN) == 0) { smbData.Pad = new byte[1]; } else { smbData.Pad = new byte[0]; } smbData.NativeOS = CifsMessageUtils.ToSmbStringBytes( Environment.OSVersion.VersionString, connection.Capability.IsUnicode); smbData.NativeLanMan = CifsMessageUtils.ToSmbStringBytes( Environment.OSVersion.VersionString, connection.Capability.IsUnicode); smbData.PrimaryDomain = CifsMessageUtils.ToSmbStringBytes( Environment.UserDomainName, connection.Capability.IsUnicode); // update smbData.ByteCount smbData.ByteCount = 0; smbData.ByteCount += (ushort)smbData.SecurityBlob.Length; smbData.ByteCount += (ushort)smbData.Pad.Length; smbData.ByteCount += (ushort)smbData.NativeOS.Length; smbData.ByteCount += (ushort)smbData.NativeLanMan.Length; smbData.ByteCount += (ushort)smbData.PrimaryDomain.Length; // store the parameters and data to packet. packet.SmbHeader = smbHeader; packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create SMB_COM_SESSION_SETUP_ANDX Server response packet /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "uid"> /// the valid session id, must be response by server of the session setup request. /// </param> /// <param name = "action">A 16-bit field. The two lowest order bits have been defined </param> /// <returns>The SmbSessionSetupAndXResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbSessionSetupImplicitNtlmAndxResponsePacket CreateSmbComSessionSetupImplicitNtlmResponse( SmbServerConnection connection, ushort uid, ActionValues action ) { if (connection == null) { throw new ArgumentNullException("connection"); } Cifs.SmbSessionSetupAndxResponsePacket packet = new Cifs.SmbSessionSetupAndxResponsePacket(); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_SESSION_SETUP_ANDX, connection.ProcessId, connection.MessageId, uid, 0, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.Action = action; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Data smbData = packet.SmbData; if (connection.Capability.IsUnicode) { smbData.Pad = new byte[1]; } else { smbData.Pad = new byte[0]; } smbData.NativeOS = CifsMessageUtils.ToSmbStringBytes( Environment.OSVersion.VersionString, connection.Capability.IsUnicode); smbData.NativeLanMan = CifsMessageUtils.ToSmbStringBytes( Environment.OSVersion.VersionString, connection.Capability.IsUnicode); smbData.PrimaryDomain = CifsMessageUtils.ToSmbStringBytes( Environment.UserDomainName, connection.Capability.IsUnicode); // update smbData.ByteCount smbData.ByteCount = 0; smbData.ByteCount += (ushort)smbData.Pad.Length; smbData.ByteCount += (ushort)smbData.NativeOS.Length; smbData.ByteCount += (ushort)smbData.NativeLanMan.Length; smbData.ByteCount += (ushort)smbData.PrimaryDomain.Length; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return new SmbSessionSetupImplicitNtlmAndxResponsePacket(packet); }
/// <summary> /// update the context with request packet /// </summary> /// <param name="connection">the connection of endpoint</param> /// <param name="packet">the packet to update the context</param> private void RequestPacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet) { connection.AddRequestPacket(packet); // update the message id connection.MessageId = packet.SmbHeader.Mid; // update the process id connection.ProcessId = (uint)(packet.SmbHeader.PidHigh << 16); connection.ProcessId += packet.SmbHeader.PidLow; // update the message sign sequence number if (packet.SmbHeader.SecurityFeatures != 0 && connection.GssApi != null && connection.GssApi.SessionKey != null) { if (packet.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL) { connection.ServerNextReceiveSequenceNumber++; } else { ServerSendSequenceNumberKey key = new ServerSendSequenceNumberKey(); key.PidHigh = packet.SmbHeader.PidHigh; key.PidLow = packet.SmbHeader.PidLow; key.Mid = packet.SmbHeader.Mid; connection.ServerSendSequenceNumber[key] = connection.ServerNextReceiveSequenceNumber + 1; connection.ServerNextReceiveSequenceNumber += 2; } } // process each special command switch (packet.SmbHeader.Command) { case SmbCommand.SMB_COM_NEGOTIATE: SmbNegotiateRequestPacket request = packet as SmbNegotiateRequestPacket; byte[] dialects = request.SmbData.Dialects; List <string> negotiateDialects = new List <string>(); for (int i = 0; i < dialects.Length; i++) { if (dialects[i] == 0x02) { continue; } string dialect = ""; for (; i < dialects.Length && dialects[i] != 0x00; i++) { dialect += (char)dialects[i]; } negotiateDialects.Add(dialect); } connection.NegotiatedDialects = negotiateDialects.ToArray(); break; case SmbCommand.SMB_COM_TREE_CONNECT_ANDX: // down-case the packet Cifs.SmbTreeConnectAndxRequestPacket treeconnect = packet as Cifs.SmbTreeConnectAndxRequestPacket; // get the specified session. SmbServerSession treeconnectSession = connection.GetSession((ushort)treeconnect.SmbHeader.Uid); if (treeconnectSession == null) { return; } // Calculate the one-way hash byte[] sessionKey = FileServiceUtils.ProtectSessionKey(treeconnectSession.SessionKey); // update the session key state. treeconnectSession.SessionKeyState = SessionKeyStateValue.Available; // if server does not support SMB_EXTENDED_SIGNATURES, return. if (SmbClientTreeConnect.TreeConnectAndxExtendedSignatures != (treeconnect.SmbParameters.Flags & SmbClientTreeConnect.TreeConnectAndxExtendedSignatures)) { return; } treeconnectSession.SessionKey = sessionKey; break; default: return; } return; }
/// <summary> /// update the context with response packet /// </summary> /// <param name="connection">the connection of endpoint</param> /// <param name="packet">the packet to update the context</param> private void ResponsePacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet) { SmbHeader smbHeader = packet.SmbHeader; SmbPacket requestPacket = connection.GetRequestPacket(smbHeader.Mid); if (requestPacket == null) { return; } switch (smbHeader.Command) { case SmbCommand.SMB_COM_SESSION_SETUP_ANDX: if (smbHeader.Uid == 0) { break; } else { SmbServerSession session = new SmbServerSession(); session.Uid = smbHeader.Uid; session.AuthenticationState = SessionState.Complete; session.Connection = connection; session.SessionKey = connection.GssApi.SessionKey; connection.AddSession(session); } break; case SmbCommand.SMB_COM_LOGOFF_ANDX: if (requestPacket.SmbHeader.Uid == 0) { break; } else { connection.RemoveSession(connection.GetSession(requestPacket.SmbHeader.Uid)); } break; case SmbCommand.SMB_COM_TREE_CONNECT_ANDX: { SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket; SmbServerTreeConnect treeconnect = new SmbServerTreeConnect(); treeconnect.TreeId = smbHeader.Tid; treeconnect.Session = connection.GetSession(smbHeader.Uid); if (treeconnect.Session == null) { break; } if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) != 0) { treeconnect.Path = Encoding.Unicode.GetString(request.SmbData.Path); } else { treeconnect.Path = Encoding.ASCII.GetString(request.SmbData.Path); } treeconnect.Path = treeconnect.Path.TrimEnd('\0'); treeconnect.Session.AddTreeConnect(treeconnect); } break; case SmbCommand.SMB_COM_TREE_DISCONNECT: if (requestPacket.SmbHeader.Uid != 0) { SmbServerSession session = connection.GetSession(requestPacket.SmbHeader.Uid); if (session == null) { break; } session.RemoveTreeConnect(session.GetTreeConnect(requestPacket.SmbHeader.Tid)); } break; case SmbCommand.SMB_COM_NT_CREATE_ANDX: { SmbNtCreateAndxResponsePacket response = packet as SmbNtCreateAndxResponsePacket; SmbNtCreateAndxRequestPacket request = requestPacket as SmbNtCreateAndxRequestPacket; SmbServerOpen open = new SmbServerOpen(); open.SmbFid = response.SmbParameters.FID; open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName, SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE)); open.PathName = open.PathName.TrimEnd('\0'); open.Session = connection.GetSession(smbHeader.Uid); open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid); if (open.TreeConnect == null) { break; } open.TreeConnect.AddOpen(open); } break; case SmbCommand.SMB_COM_OPEN_ANDX: { SmbOpenAndxResponsePacket response = packet as SmbOpenAndxResponsePacket; SmbOpenAndxRequestPacket request = requestPacket as SmbOpenAndxRequestPacket; SmbServerOpen open = new SmbServerOpen(); open.SmbFid = response.SmbParameters.FID; open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName, SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE)); open.Session = connection.GetSession(smbHeader.Uid); open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid); if (open.TreeConnect == null) { break; } open.TreeConnect.AddOpen(open); } break; case SmbCommand.SMB_COM_CLOSE: { SmbCloseRequestPacket closeRequest = requestPacket as SmbCloseRequestPacket; SmbServerTreeConnect treeconnect = connection.GetTreeConnect(requestPacket.SmbHeader.Tid); if (treeconnect == null) { break; } treeconnect.RemoveOpen(treeconnect.GetOpen(closeRequest.SmbParameters.FID)); } break; default: break; } connection.RemoveRequestPacket(packet); }
/// <summary> /// update the context with request packet /// </summary> /// <param name="connection">the connection of endpoint</param> /// <param name="packet">the packet to update the context</param> private void RequestPacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet) { connection.AddRequestPacket(packet); // update the message id connection.MessageId = packet.SmbHeader.Mid; // update the process id connection.ProcessId = (uint)(packet.SmbHeader.PidHigh << 16); connection.ProcessId += packet.SmbHeader.PidLow; // update the message sign sequence number if (packet.SmbHeader.SecurityFeatures != 0 && connection.GssApi != null && connection.GssApi.SessionKey != null) { if (packet.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL) { connection.ServerNextReceiveSequenceNumber++; } else { ServerSendSequenceNumberKey key = new ServerSendSequenceNumberKey(); key.PidHigh = packet.SmbHeader.PidHigh; key.PidLow = packet.SmbHeader.PidLow; key.Mid = packet.SmbHeader.Mid; connection.ServerSendSequenceNumber[key] = connection.ServerNextReceiveSequenceNumber + 1; connection.ServerNextReceiveSequenceNumber += 2; } } // process each special command switch (packet.SmbHeader.Command) { case SmbCommand.SMB_COM_NEGOTIATE: SmbNegotiateRequestPacket request = packet as SmbNegotiateRequestPacket; byte[] dialects = request.SmbData.Dialects; List<string> negotiateDialects = new List<string>(); for (int i = 0; i < dialects.Length; i++) { if (dialects[i] == 0x02) { continue; } string dialect = ""; for (; i < dialects.Length && dialects[i] != 0x00; i++) { dialect += (char)dialects[i]; } negotiateDialects.Add(dialect); } connection.NegotiatedDialects = negotiateDialects.ToArray(); break; case SmbCommand.SMB_COM_TREE_CONNECT_ANDX: // down-case the packet Cifs.SmbTreeConnectAndxRequestPacket treeconnect = packet as Cifs.SmbTreeConnectAndxRequestPacket; // get the specified session. SmbServerSession treeconnectSession = connection.GetSession((ushort)treeconnect.SmbHeader.Uid); if (treeconnectSession == null) { return; } // Calculate the one-way hash byte[] sessionKey = FileServiceUtils.ProtectSessionKey(treeconnectSession.SessionKey); // update the session key state. treeconnectSession.SessionKeyState = SessionKeyStateValue.Available; // if server does not support SMB_EXTENDED_SIGNATURES, return. if (SmbClientTreeConnect.TreeConnectAndxExtendedSignatures != (treeconnect.SmbParameters.Flags & SmbClientTreeConnect.TreeConnectAndxExtendedSignatures)) { return; } treeconnectSession.SessionKey = sessionKey; break; default: return; } return; }
/// <summary> /// Create SMB_ERROR response, including only header portion /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "status">Status of the packet </param> /// <param name = "command">The operation code that this SMB is requesting or responding to </param> /// <returns>The CreateSmbErrorResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbErrorResponsePacket CreateSmbErrorResponse( SmbServerConnection connection, uint status, SmbCommand command) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbErrorResponsePacket packet = new SmbErrorResponsePacket(); // create smb packet header SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader( command, connection.ProcessId, connection.MessageId, 0x00, 0x00, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); smbHeader.Status = status; packet.SmbHeader = smbHeader; return packet; }
/// <summary> /// Expect a packet from a connected client /// </summary> /// <param name="timeout">waiting time</param> /// <param name="connection">the remote client who sent this packet</param> /// <returns>received smb the packet</returns> /// <exception cref="InvalidOperationException"> /// The transport is null for not started. Please invoke Start() first /// </exception> /// <exception cref="InvalidOperationException">Unknown object received from transport.</exception> public virtual SmbPacket ExpectPacket(TimeSpan timeout, out SmbServerConnection connection) { if (this.transport == null) { throw new InvalidOperationException( "The transport is null for not started. Please invoke Start() first."); } TransportEvent transportEvent = this.transport.ExpectTransportEvent(timeout); if (transportEvent.EventType == EventType.Connected) { connection = new SmbServerConnection(); connection.Identity = transportEvent.EndPoint; this.context.AddConnection(connection); return null; } else if (transportEvent.EventType == EventType.ReceivedPacket) { connection = this.context.GetConnection(transportEvent.EndPoint); return transportEvent.EventObject as SmbPacket; } else if (transportEvent.EventType == EventType.Disconnected) { connection = this.context.GetConnection(transportEvent.EndPoint); this.context.RemoveConnection(connection); return null; } else if (transportEvent.EventType == EventType.Exception) { throw transportEvent.EventObject as Exception; } else { throw new InvalidOperationException("Unknown object received from transport."); } }
/// <summary> /// Create TRANS2_FIND_NEXT2 Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "searchCount">search count </param> /// <param name = "isEndOfSearch">whether end of search </param> /// <param name = "eaErrorOffset">eaError Offset </param> /// <param name = "lastNameOffset">last name offset </param> /// <param name = "data">data specified by [CIFS] </param> /// <returns>The SmbTrans2FindNext2ResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTrans2FindNext2ResponsePacket CreateTrans2FindNext2Response( SmbServerConnection connection, ushort searchCount, bool isEndOfSearch, ushort eaErrorOffset, ushort lastNameOffset, object data) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTrans2FindNext2ResponsePacket packet = new SmbTrans2FindNext2ResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION2, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION2_FinalResponse_SMB_Data smbData = packet.SmbData; // update trans2 param TRANS2_FIND_NEXT2_Response_Trans2_Parameters trans2Parameters = packet.Trans2Parameters; trans2Parameters.SearchCount = searchCount; trans2Parameters.EndOfSearch = (ushort)(isEndOfSearch ? 1 : 0); trans2Parameters.EaErrorOffset = eaErrorOffset; trans2Parameters.LastNameOffset = lastNameOffset; // update trans2 data TRANS2_FIND_NEXT2_Response_Trans2_Data trans2Data = packet.Trans2Data; trans2Data.Data = data; // store the parameters and data to packet. packet.Trans2Parameters = trans2Parameters; packet.Trans2Data = trans2Data; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Send packet to a specific connected client /// </summary> /// <param name="connection">connection to remote client</param> /// <param name="packet">the smb packet</param> /// <exception cref="ArgumentNullException">smbPacket</exception> /// <exception cref="ArgumentNullException">endpoint</exception> /// <exception cref="InvalidOperationException"> /// The transport is null for not started. Please invoke Start() first /// </exception> public virtual void SendPacket(SmbPacket packet, SmbServerConnection connection) { if (packet == null) { throw new ArgumentNullException("packet"); } if (connection == null) { throw new ArgumentNullException("connection"); } if (this.transport == null) { throw new InvalidOperationException( "The transport is null for not started. Please invoke Start() first."); } SmbPacket smbPacket = packet as SmbPacket; if (smbPacket != null && this.context.IsUpdateContext) { this.context.UpdateRoleContext(connection, smbPacket); } switch(this.transportType) { case TransportType.TCP: // send packet through the direct tcp this.transport.SendPacket(connection.Identity, new SmbDirectTcpPacket(packet)); break; case TransportType.NetBIOS: // send packet through netbios over Tcp this.transport.SendPacket(connection.Identity, smbPacket); break; default: break; } }
/// <summary> /// Create FSCTL_SRV_ENUMERATE_SNAPSHOTS Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name="numberOfSnapShots">This value MUST be the number of snapshots for the volume. </param> /// <param name = "snapShotData"> /// A concatenated set of snapshot names. Each snapshot name MUST be formatted as a null-terminated array of /// 16-bit Unicode characters. The concatenated list MUST be terminated by two 16-bit Unicode NULL characters /// </param> /// <returns>The SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket CreateFsctlSrvEnumerateSnapshotsResponse( SmbServerConnection connection, uint numberOfSnapShots, params string[] snapShotData) { if (snapShotData == null) { snapShotData = new string[0]; } if (connection == null) { throw new ArgumentNullException("connection"); } SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket packet = new SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NT_TRANSACT, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; // reserved 3 bytes. smbParameters.Reserved1 = new byte[3]; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData; // update trans2 data NT_TRANSACT_ENUMERATE_SNAPSHOTS_Response_NT_Trans_Data ntTransData = packet.NtTransData; ntTransData.NumberOfSnapShots = numberOfSnapShots; ntTransData.NumberOfSnapShotsReturned = (uint)snapShotData.Length; // initiallize to zero ntTransData.SnapShotArraySize = 0x00; ntTransData.snapShotMultiSZ = new byte[ntTransData.SnapShotArraySize]; // update snapshots packet.SnapShots = new Collection<string>(snapShotData); // store the parameters and data to packet. packet.NtTransData = ntTransData; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create NT_TRANSACT_QUERY_QUOTA Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "quotaInfo">quota information </param> /// <returns>The SmbNtTransQueryQuotaResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNtTransQueryQuotaResponsePacket CreateNtTransQueryQuotaResponse( SmbServerConnection connection, params NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data[] quotaInfo) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbNtTransQueryQuotaResponsePacket packet = new SmbNtTransQueryQuotaResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NT_TRANSACT, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; // reserved 3 bytes. smbParameters.Reserved1 = new byte[3]; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData; // update query quota data Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data> ntTransDataList = new Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>(); if (quotaInfo != null) { ntTransDataList = new Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>(quotaInfo); } // update trans2 param NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Parameters ntTransParameters = packet.NtTransParameters; foreach (NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data data in ntTransDataList) { ntTransParameters.QuotaDataSize += (uint) CifsMessageUtils.GetSize<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>(data); } // store the parameters and data to packet. packet.NtTransParameters = ntTransParameters; packet.NtTransDataList = ntTransDataList; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create TRANS2_SET_PATH_INFORMATION Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <returns>The SmbTrans2SetPathInformationResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTrans2SetPathInformationResponsePacket CreateTrans2SetPathInformationResponse(SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTrans2SetPathInformationResponsePacket packet = new SmbTrans2SetPathInformationResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION2, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION2_FinalResponse_SMB_Data smbData = packet.SmbData; // update trans2 param TRANS2_SET_PATH_INFORMATION_Response_Trans2_Parameters trans2Parameters = packet.Trans2Parameters; // store the parameters and data to packet. packet.Trans2Parameters = trans2Parameters; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create SMB_COM_CLOSE packet /// </summary> /// <param name="connection">the connection identified the client</param> /// <returns>a SMB_COM_CLOSE packet </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbCloseResponsePacket CreateSmbComCloseResponse(SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbCloseResponsePacket packet = new SmbCloseResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_CLOSE, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_CLOSE_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.WordCount = 0; // update smb data SMB_COM_CLOSE_Response_SMB_Data smbData = packet.SmbData; // update smbData.ByteCount smbData.ByteCount = 0; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create Named Rap Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name="win32ErrorCode"> /// This MUST be a 16-bit unsigned integer. It contains a Win32 error code representing the result of the /// Remote Administration Protocol command. The following table lists error codes that have particular meaning /// to the Remote Administration Protocol, as indicated in this specification. /// </param> /// <param name="converter"> /// This field MUST contain a 16-bit signed integer, which a client MUST subtract from the string offset /// contained in the low 16 bits of a variable-length field in the Remote Administration Protocol response /// buffer. This is to derive the actual byte offset from the start of the response buffer for that field. /// </param> /// <param name="rapOutParams"> /// If present, this structure MUST contain the response information for the Remote Administration Protocol /// command in the corresponding Remote Administration Protocol request message. Certain RAPOpcodes require /// a RAPOutParams structure; for Remote Administration Protocol commands that require a RAPOutParams /// structure, see sections 2.5.5, 2.5.6, 2.5.7, 2.5.8, and 2.5.9. /// </param> /// <param name="rapOutData"> /// This is the response data for the Remote Administration Protocol operation. The content of the RAPOutData /// structure varies according to the Remote Administration Protocol command and the parameters of each Remote /// Administration Protocol command. See Remote Administration Protocol responses for each Remote /// Administration Protocol command in sections 2.5.5, 2.5.6, 2.5.7, 2.5.8, and 2.5.9. /// </param> /// <returns>a Named Rap write response </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTransRapResponsePacket CreateTransNamedRapResponse( SmbServerConnection connection, ushort win32ErrorCode, ushort converter, byte[] rapOutParams, byte[] rapOutData) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTransRapResponsePacket packet = new SmbTransRapResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData; // update trans parameters TRANSACTION_Rap_Response_Trans_Parameters transParameters = packet.TransParameters; transParameters.Win32ErrorCode = win32ErrorCode; transParameters.Converter = converter; transParameters.RAPOutParams = rapOutParams; // update trans data TRANSACTION_Rap_Response_Trans_Data transData = packet.TransData; transData.RAPOutData = rapOutData; // store the parameters and data to packet. packet.TransParameters = transParameters; packet.TransData = transData; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create SMB_COM_NEGOTIATE response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "securityMode"> /// An 8-bit field, indicating the security modes supported or REQUIRED by the server /// </param> /// <param name = "maxBufferSize"> /// The maximum size, in bytes, of the largest SMB message the servercan receive. This is the size of the SMB /// message that the clientMAY send to the server. SMB message size includes the size of the SMB header, and /// data blocks. This size does not include any transport-layer framing or other transport-layer data. server /// MUSTprovide a MaxBufferSize of 1024 bytes (1Kbyte) or larger.If CAP_RAW_MODE is negotiated, then /// SMB_COM_WRITE_RAW commandcan bypass the MaxBufferSize limit. Otherwise, SMB messages sent to the server /// have a total size less than or equal to the MaxBufferSize value.This includes AndX chained default /// MaxBufferSize on Windows NT server is 4356 bytes(4KB + 260Bytes) if the server has 512MB of or less. If /// the server has more than 512MB of memory, then the default MaxBufferSize is 16644 bytes (16KB 260Bytes). /// Windows NT servers always use a MaxBufferSize value that is a multiple of four (4). The can be configured /// through the following registry setting: /// </param> /// <param name="maxMpxCount"> /// The maximum number of outstanding SMB operations the server /// supports. This value includes existing OpLocks, /// the NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other command /// that are pending on the server. If the negotiated MaxMpxCount is one, /// then OpLock support MUST be disabled for this session. The MaxMpxCount /// MUST be greater than zero. This parameter has no specific /// relationship to the SMB_COM_READ_MPX and SMB_COM_WRITE_MPX commands. /// </param> /// <returns>a smb implicit ntlm negotiate response packet </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNegotiateImplicitNtlmResponsePacket CreateSmbComNegotiateImplicitNtlmResponse( SmbServerConnection connection, SecurityModes securityMode, uint maxBufferSize, ushort maxMpxCount) { if (connection == null) { throw new ArgumentNullException("connection"); } Cifs.SmbNegotiateResponsePacket packet = new Cifs.SmbNegotiateResponsePacket(); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NEGOTIATE, connection.ProcessId, connection.MessageId, 0, 0, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters Cifs.SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Parameters smbParameters = packet.SmbParameters; ushort dialectIndex = 0x00; byte wordCount = 0x00; connection.GetPreferedDialectIndex(out dialectIndex, out wordCount); smbParameters.WordCount = wordCount; smbParameters.DialectIndex = dialectIndex; smbParameters.SecurityMode = securityMode; smbParameters.MaxBufferSize = maxBufferSize; smbParameters.MaxMpxCount = maxMpxCount; smbParameters.Capabilities = (Cifs.Capabilities)connection.ServerCapabilities; smbParameters.SystemTime.Time = (ulong)connection.SystemTime; smbParameters.ChallengeLength = (byte)connection.NtlmEncryptionKey.Length; // update smb data Cifs.SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Data smbData = packet.SmbData; smbData.Challenge = connection.NtlmEncryptionKey; // update smbData.ByteCount smbData.ByteCount = 0; if (smbData.Challenge != null) { smbData.ByteCount += (ushort)smbData.Challenge.Length; } if (smbData.DomainName != null) { smbData.ByteCount += (ushort)smbData.DomainName.Length; } // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return new SmbNegotiateImplicitNtlmResponsePacket(packet); }
/// <summary> /// Create TRANS_PEEK_NMPIPE Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "readDataAvailable"> /// The first USHORT value (as specified in [MS-DTYP] section 2.2.57) in the Parameter buffer contains the /// total number of bytes available to be read from the pipe /// </param> /// <param name = "messageByteLength"> /// If the named pipe is a message mode pipe, this MUST be set to the number of bytes remaining in the message /// that was peeked (the number of bytes in the message minus the number of bytes read). If the entire message /// was read, this value is 0. If the named pipe is a byte mode pipe, this value MUST be set to 0 /// </param> /// <param name = "namedPipeState">The status of the named pipe </param> /// <param name = "peekedData">The data buffer contains the data read from the named pipe </param> /// <returns>The SmbTransPeekNmpipeResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTransPeekNmpipeResponsePacket CreateTransPeekNmpipeResponse( SmbServerConnection connection, ushort readDataAvailable, ushort messageByteLength, NamedPipePeekState namedPipeState, byte[] peekedData) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTransPeekNmpipeResponsePacket packet = new SmbTransPeekNmpipeResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData; // update trans param TRANS_PEEK_NMPIPE_Response_Trans_Parameters transParameters = packet.TransParameters; transParameters.ReadDataAvailable = readDataAvailable; transParameters.MessageBytesLength = messageByteLength; transParameters.NamedPipeState = (ushort)namedPipeState; // update trans data TRANS_PEEK_NMPIPE_Response_Trans_Data transData = packet.TransData; transData.ReadData = peekedData; // store the parameters and data to packet. packet.TransParameters = transParameters; packet.TransData = transData; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create SMB_COM_NT_CREATE_ANDX Server Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "fileId"> /// The SMB file identifier returned by the SMB server for the file or device that was opened or created /// </param> /// <param name = "createAction">The action taken. This field MUST be interpreted as follows </param> /// <param name = "extFileAttributes">Extended attributes and flags for this file or directory </param> /// <param name = "fileType">The file type </param> /// <param name = "isDirectory"> /// A value that indicates whether this is a directory. MUST be nonzero when this is a directory /// </param> /// <returns>The SmbNtCreateAndXResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbNtCreateAndxResponsePacket CreateSmbComNtCreateResponse( SmbServerConnection connection, ushort fileId, uint createAction, uint extFileAttributes, FileTypeValue fileType, bool isDirectory) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbNtCreateAndxResponsePacket packet = new SmbNtCreateAndxResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_NT_CREATE_ANDX, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND; smbParameters.OplockLevel = OplockLevelValue.None; smbParameters.FID = fileId; smbParameters.CreationAction = createAction; smbParameters.CreateTime.Time = (ulong)DateTime.Now.ToFileTime(); smbParameters.LastAccessTime.Time = (ulong)DateTime.Now.ToFileTime(); smbParameters.LastWriteTime.Time = (ulong)DateTime.Now.ToFileTime(); smbParameters.LastChangeTime.Time = (ulong)DateTime.Now.ToFileTime(); smbParameters.ExtFileAttributes = extFileAttributes; smbParameters.AllocationSize = 0x00; smbParameters.EndOfFile = 0x00; smbParameters.ResourceType = fileType; smbParameters.NMPipeStatus_or_FileStatusFlags = SMB_NMPIPE_STATUS.None; smbParameters.Directory = (byte)(isDirectory == true ? 1 : 0); smbParameters.VolumeGUID = Guid.Empty.ToByteArray(); smbParameters.FileId = new byte[sizeof(long)]; smbParameters.MaximalAccessRights = new byte[sizeof(int)]; smbParameters.GuestMaximalAccessRights = new byte[sizeof(int)]; int size = CifsMessageUtils.GetSize<Cifs.SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters>( new Cifs.SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters()); size += smbParameters.VolumeGUID.Length; size += smbParameters.FileId.Length; size += smbParameters.MaximalAccessRights.Length; size += smbParameters.GuestMaximalAccessRights.Length; smbParameters.WordCount = (byte)(size / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_NT_CREATE_ANDX_Response_SMB_Data smbData = packet.SmbData; // update smbData.ByteCount smbData.ByteCount = 0; // store the parameters and data to packet. packet.SmbParameters = smbParameters; packet.SmbData = smbData; return packet; }
/// <summary> /// Create TRANS_QUERY_NMPIPE_INFO Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "outputBufferSize"> /// The first word of the data buffer that MUST contain the actual size of the buffer for outgoing (server) /// I/O /// </param> /// <param name = "inputBufferSize"> /// This value MUST be the actual size of the buffer for incoming (client) I/O /// </param> /// <param name = "maximumInstances"> /// This value MUST be the maximum allowed number of named pipe instances. /// </param> /// <param name = "currectInstances">This value MUST be the current number of named pipe instances </param> /// <param name = "pipeName"> /// This value MUST be a null-terminated string containing the name of the named pipe /// </param> /// <returns>The SmbTransQueryNmpipeInfoResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTransQueryNmpipeInfoResponsePacket CreateTransQueryNmpipeInfoResponse( SmbServerConnection connection, ushort outputBufferSize, ushort inputBufferSize, byte maximumInstances, byte currectInstances, string pipeName) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTransQueryNmpipeInfoResponsePacket packet = new SmbTransQueryNmpipeInfoResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData; // update trans data TRANS_QUERY_NMPIPE_INFO_Response_Trans_Data transData = packet.TransData; transData.OutputBufferSize = outputBufferSize; transData.InputBufferSize = inputBufferSize; transData.MaximumInstances = maximumInstances; transData.CurrentInstances = currectInstances; transData.PipeName = CifsMessageUtils.ToSmbStringBytes(pipeName, connection.Capability.IsUnicode); transData.PipeNameLength = (byte)transData.PipeName.Length; // store the parameters and data to packet. packet.TransData = transData; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Add Connection to context /// </summary> /// <param name="connection">the connection</param> /// <exception cref="InvalidOperationException"> /// the connection already exists in the connection list, can not add duplicate connection /// </exception> internal void AddConnection(SmbServerConnection connection) { lock (this.connectionList) { if(this.connectionList.Contains(connection)) { throw new InvalidOperationException( "the connection already exists in the connection list, can not add duplicate connection"); } this.connectionList.Add(connection); } }
/// <summary> /// Create TRANS_RAW_READ_NMPIPE Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name = "dataBuffer"> /// The Data buffer that MUST contain the bytes read from the named pipe in raw mode /// </param> /// <returns>The SmbTransRawReadNmpipeResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTransRawReadNmpipeResponsePacket CreateTransRawReadNmpipeResponse( SmbServerConnection connection, byte[] dataBuffer) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTransRawReadNmpipeResponsePacket packet = new SmbTransRawReadNmpipeResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.SetupCount = 0; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData; int alignBytesCount = (SmbCapability.NUM_BYTES_OF_BYTE // WordCount + smbParameters.WordCount * SmbCapability.NUM_BYTES_OF_WORD // Words + SmbCapability.NUM_BYTES_OF_WORD) // ByteCount % SmbCapability.FOUR_BYTES_ALIGN; if (alignBytesCount != 0) { smbData.Pad2 = new byte[SmbCapability.FOUR_BYTES_ALIGN - alignBytesCount]; } // update trans data TRANS_RAW_READ_NMPIPE_Response_Trans_Data transData = packet.TransData; transData.BytesRead = dataBuffer; // store the parameters and data to packet. packet.TransData = transData; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// Create TRANS_WRITE_NMPIPE Response /// </summary> /// <param name="connection">the connection identified the client</param> /// <param name="bytesWritten">This value MUST be set to the number of bytes written to the pipe.</param> /// <returns>The SmbTransWriteNmpipeResponsePacket </returns> /// <exception cref="ArgumentNullException">connection must not be null</exception> public virtual SmbTransWriteNmpipeResponsePacket CreateTransWriteNmpipeResponse( SmbServerConnection connection, ushort bytesWritten) { if (connection == null) { throw new ArgumentNullException("connection"); } SmbTransWriteNmpipeResponsePacket packet = new SmbTransWriteNmpipeResponsePacket(); // get the request packet SmbPacket request = connection.GetRequestPacket(connection.MessageId); // create smb packet header packet.SmbHeader = CifsMessageUtils.CreateSmbHeader( SmbCommand.SMB_COM_TRANSACTION, connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid, (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2); // update smb parameters SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters; smbParameters.Setup = new ushort[0]; smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>( smbParameters) / SmbCapability.NUM_BYTES_OF_WORD); // update smb data SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData; // update trans param TRANS_WRITE_NMPIPE_Response_Trans_Parameters transParameters = packet.TransParameters; transParameters.BytesWritten = bytesWritten; // store the parameters and data to packet. packet.TransParameters = transParameters; packet.SmbParameters = smbParameters; packet.SmbData = smbData; packet.UpdateCountAndOffset(); return packet; }
/// <summary> /// disconnect the connection /// </summary> /// <param name="connection">the connection to disconnect</param> /// <exception cref="ArgumentNullException">the connection is null</exception> /// <exception cref="NotImplementedException">dis connect the connection have not been implemented</exception> public virtual void Disconnect(SmbServerConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } this.transport.Disconnect(connection.Identity); this.context.RemoveConnection(connection); // dispose gss api connection.DisposeGssApi(); }