Example #1
0
        private void ProcessPacket(SessionPacket packet, ConnectionState state)
        {
            if (packet is SessionMessagePacket)
            {
                SMB1Message message;
                try
                {
                    message = SMB1Message.GetSMB1Message(packet.Trailer);
                }
                catch (Exception ex)
                {
                    Log("Invalid SMB1 message: " + ex.Message);
                    state.ClientSocket.Close();
                    m_isConnected = false;
                    return;
                }

                // [MS-CIFS] 3.2.5.1 - If the MID value is the reserved value 0xFFFF, the message can be an OpLock break
                // sent by the server. Otherwise, if the PID and MID values of the received message are not found in the
                // Client.Connection.PIDMIDList, the message MUST be discarded.
                if ((message.Header.MID == 0xFFFF && message.Header.Command == CommandName.SMB_COM_LOCKING_ANDX) ||
                    (message.Header.PID == 0 && message.Header.MID == 0))
                {
                    lock (m_incomingQueueLock)
                    {
                        m_incomingQueue.Add(message);
                        m_incomingQueueEventHandle.Set();
                    }
                }
            }
            else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                m_sessionResponsePacket = packet;
                m_sessionResponseEventHandle.Set();
            }
            else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
            }
            else
            {
                Log("Inappropriate NetBIOS session packet");
                state.ClientSocket.Close();
            }
        }
Example #2
0
        private SMB1FileStore TreeConnect(string shareName, ServiceName serviceName)
        {
            if (!IsConnected || !m_isLoggedIn)
            {
                throw new InvalidOperationException("A login session must be successfully established before connecting to a share");
            }

            TreeConnectAndXRequest request = new TreeConnectAndXRequest
            {
                Path    = shareName,
                Service = serviceName
            };

            SendMessage(request);
            SMB1Message reply = WaitForMessage(CommandName.SMB_COM_TREE_CONNECT_ANDX);

            reply.IsSuccessElseThrow();
            return(new SMB1FileStore(this, reply.Header.TID));
        }
Example #3
0
        public void SetFileInformation(NtHandle handle, FileInformation information)
        {
            if (!m_client.InfoLevelPassthrough)
            {
                throw new NotSupportedException("Server does not support InfoLevelPassthrough");
            }

            if (information is FileRenameInformationType2 fileRenameInformationType2)
            {
                FileRenameInformationType1 informationType1 = new FileRenameInformationType1
                {
                    FileName        = fileRenameInformationType2.FileName,
                    ReplaceIfExists = fileRenameInformationType2.ReplaceIfExists,
                    RootDirectory   = (uint)fileRenameInformationType2.RootDirectory
                };
                information = informationType1;
            }

            int maxOutputLength = 4096;
            Transaction2SetFileInformationRequest subcommand = new Transaction2SetFileInformationRequest
            {
                FID = ((Smb1Handle)handle).FID,
            };

            subcommand.SetInformation(information);

            Transaction2Request request = new Transaction2Request
            {
                Setup           = subcommand.GetSetup(),
                TransParameters = subcommand.GetParameters(m_client.Unicode),
                TransData       = subcommand.GetData(m_client.Unicode)
            };

            request.TotalDataCount      = (ushort)request.TransData.Length;
            request.TotalParameterCount = (ushort)request.TransParameters.Length;
            request.MaxParameterCount   = Transaction2SetFileInformationResponse.ParametersLength;
            request.MaxDataCount        = (ushort)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);

            reply.IsSuccessElseThrow();
        }
Example #4
0
        public NTStatus Logoff()
        {
            if (!m_isConnected)
            {
                throw new InvalidOperationException("A login session must be successfully established before attempting logoff");
            }

            LogoffAndXRequest request = new LogoffAndXRequest();

            TrySendMessage(request);

            SMB1Message reply = WaitForMessage(CommandName.SMB_COM_LOGOFF_ANDX);

            if (reply != null)
            {
                m_isLoggedIn = (reply.Header.Status != NTStatus.STATUS_SUCCESS);
                return(reply.Header.Status);
            }
            return(NTStatus.STATUS_INVALID_SMB);
        }
Example #5
0
        public void ReadFile(out byte[]?data, NtHandle handle, long offset, int maxCount)
        {
            data = null;

            ReadAndXRequest request = new ReadAndXRequest
            {
                FID           = ((Smb1Handle)handle).FID,
                Offset        = (ulong)offset,
                MaxCountLarge = (uint)maxCount
            };

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_READ_ANDX);

            reply.IsSuccessElseThrow();
            if (reply.Commands[0] is ReadAndXResponse response)
            {
                data = response.Data;
            }
        }
Example #6
0
        public void WriteFile(out int numberOfBytesWritten, NtHandle handle, long offset, byte[] data)
        {
            numberOfBytesWritten = 0;

            WriteAndXRequest request = new WriteAndXRequest
            {
                FID    = ((Smb1Handle)handle).FID,
                Offset = (ulong)offset,
                Data   = data
            };

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_WRITE_ANDX);

            reply.IsSuccessElseThrow();
            if (reply.Commands[0] is WriteAndXResponse response)
            {
                numberOfBytesWritten = (int)response.Count;
            }
        }
Example #7
0
        public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength)
        {
            if ((IoControlCode)ctlCode == IoControlCode.FSCTL_PIPE_TRANSCEIVE)
            {
                return(FsCtlPipeTranscieve(handle, input, out output, maxOutputLength));
            }

            output = null;
            NTTransactIOCTLRequest subcommand = new NTTransactIOCTLRequest();

            subcommand.FID          = (ushort)handle;
            subcommand.FunctionCode = ctlCode;
            subcommand.IsFsctl      = true;
            subcommand.Data         = input;

            NTTransactRequest request = new NTTransactRequest();

            request.Function            = subcommand.SubcommandName;
            request.Setup               = subcommand.GetSetup();
            request.TransParameters     = subcommand.GetParameters(m_client.Unicode);
            request.TransData           = subcommand.GetData();
            request.TotalDataCount      = (uint)request.TransData.Length;
            request.TotalParameterCount = (uint)request.TransParameters.Length;
            request.MaxParameterCount   = NTTransactIOCTLResponse.ParametersLength;
            request.MaxDataCount        = (uint)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_NT_TRANSACT);

            if (reply != null)
            {
                if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is NTTransactResponse)
                {
                    NTTransactResponse      response           = (NTTransactResponse)reply.Commands[0];
                    NTTransactIOCTLResponse subcommandResponse = new NTTransactIOCTLResponse(response.Setup, response.TransData);
                    output = subcommandResponse.Data;
                }
                return(reply.Header.Status);
            }
            return(NTStatus.STATUS_INVALID_SMB);
        }
Example #8
0
        public NTStatus SetFileInformation(object handle, FileInformation information)
        {
            if (m_client.InfoLevelPassthrough)
            {
                if (information is FileRenameInformationType2)
                {
                    FileRenameInformationType1 informationType1 = new FileRenameInformationType1();
                    informationType1.FileName        = ((FileRenameInformationType2)information).FileName;
                    informationType1.ReplaceIfExists = ((FileRenameInformationType2)information).ReplaceIfExists;
                    informationType1.RootDirectory   = (uint)((FileRenameInformationType2)information).RootDirectory;
                    information = informationType1;
                }

                int maxOutputLength = 4096;
                Transaction2SetFileInformationRequest subcommand = new Transaction2SetFileInformationRequest();
                subcommand.FID = (ushort)handle;
                subcommand.SetInformation(information);

                Transaction2Request request = new Transaction2Request();
                request.Setup               = subcommand.GetSetup();
                request.TransParameters     = subcommand.GetParameters(m_client.Unicode);
                request.TransData           = subcommand.GetData(m_client.Unicode);
                request.TotalDataCount      = (ushort)request.TransData.Length;
                request.TotalParameterCount = (ushort)request.TransParameters.Length;
                request.MaxParameterCount   = Transaction2SetFileInformationResponse.ParametersLength;
                request.MaxDataCount        = (ushort)maxOutputLength;

                TrySendMessage(request);
                SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);
                if (reply != null)
                {
                    return(reply.Header.Status);
                }
                return(NTStatus.STATUS_INVALID_SMB);
            }
            else
            {
                throw new NotSupportedException("Server does not support InfoLevelPassthrough");
            }
        }
Example #9
0
        public NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data)
        {
            numberOfBytesWritten = 0;
            WriteAndXRequest request = new WriteAndXRequest();

            request.FID    = (ushort)handle;
            request.Offset = (ulong)offset;
            request.Data   = data;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_WRITE_ANDX);

            if (reply != null)
            {
                if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is WriteAndXResponse)
                {
                    numberOfBytesWritten = (int)((WriteAndXResponse)reply.Commands[0]).Count;
                }
                return(reply.Header.Status);
            }
            return(NTStatus.STATUS_INVALID_SMB);
        }
Example #10
0
        public void GetFileSystemInformation(out FileSystemInformation?result,
                                             FileSystemInformationClass informationClass)
        {
            if (!m_client.InfoLevelPassthrough)
            {
                throw new NotSupportedException("Server does not support InfoLevelPassthrough");
            }

            result = null;
            int maxOutputLength = 4096;
            Transaction2QueryFSInformationRequest subcommand = new Transaction2QueryFSInformationRequest
            {
                FileSystemInformationClass = informationClass
            };

            Transaction2Request request = new Transaction2Request
            {
                Setup           = subcommand.GetSetup(),
                TransParameters = subcommand.GetParameters(m_client.Unicode),
                TransData       = subcommand.GetData(m_client.Unicode)
            };

            request.TotalDataCount      = (ushort)request.TransData.Length;
            request.TotalParameterCount = (ushort)request.TransParameters.Length;
            request.MaxParameterCount   = Transaction2QueryFSInformationResponse.ParametersLength;
            request.MaxDataCount        = (ushort)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);

            if (reply.Header.Status != NTStatus.STATUS_SUCCESS || !(reply.Commands[0] is Transaction2Response transaction2Response))
            {
                throw new NtStatusException(reply.Header.Status);
            }

            Transaction2QueryFSInformationResponse subcommandResponse = new Transaction2QueryFSInformationResponse(transaction2Response.TransData);

            result = subcommandResponse.GetFileSystemInformation(informationClass);
        }
Example #11
0
        public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
        {
            data = null;
            ReadAndXRequest request = new ReadAndXRequest();

            request.FID           = (ushort)handle;
            request.Offset        = (ulong)offset;
            request.MaxCountLarge = (uint)maxCount;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_READ_ANDX);

            if (reply != null)
            {
                if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is ReadAndXResponse)
                {
                    data = ((ReadAndXResponse)reply.Commands[0]).Data;
                }
                return(reply.Header.Status);
            }
            return(NTStatus.STATUS_INVALID_SMB);
        }
Example #12
0
        public void DeviceIOControl(NtHandle handle, uint ctlCode, byte[] input, out byte[]?output, int maxOutputLength)
        {
            if ((IoControlCode)ctlCode == IoControlCode.FSCTL_PIPE_TRANSCEIVE)
            {
                FsCtlPipeTranscieve(handle, input, out output, maxOutputLength);
                return;
            }
            NTTransactIOCTLRequest subcommand = new NTTransactIOCTLRequest
            {
                FID          = ((Smb1Handle)handle).FID,
                FunctionCode = ctlCode,
                IsFsctl      = true,
                Data         = input
            };

            NTTransactRequest request = new NTTransactRequest
            {
                Function        = subcommand.SubcommandName,
                Setup           = subcommand.GetSetup(),
                TransParameters = subcommand.GetParameters(m_client.Unicode),
                TransData       = subcommand.GetData()
            };

            request.TotalDataCount      = (uint)request.TransData.Length;
            request.TotalParameterCount = (uint)request.TransParameters.Length;
            request.MaxParameterCount   = NTTransactIOCTLResponse.ParametersLength;
            request.MaxDataCount        = (uint)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_NT_TRANSACT);

            if (reply.Header.Status != NTStatus.STATUS_SUCCESS || !(reply.Commands[0] is NTTransactResponse ntTransactResponse))
            {
                throw new NtStatusException(reply.Header.Status);
            }
            NTTransactIOCTLResponse subcommandResponse = new NTTransactIOCTLResponse(ntTransactResponse.Setup, ntTransactResponse.TransData);

            output = subcommandResponse.Data;
        }
Example #13
0
        public void CreateFile(out NtHandle handle, out FileStatus fileStatus, string path,
                               AccessMask desiredAccess, FileAttributes fileAttributes, ShareAccess shareAccess,
                               CreateDisposition createDisposition, CreateOptions createOptions, SecurityContext?securityContext)
        {
            handle     = null;
            fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
            NTCreateAndXRequest request = new NTCreateAndXRequest
            {
                FileName           = path,
                DesiredAccess      = desiredAccess,
                ExtFileAttributes  = ToExtendedFileAttributes(fileAttributes),
                ShareAccess        = shareAccess,
                CreateDisposition  = createDisposition,
                CreateOptions      = createOptions,
                ImpersonationLevel = ImpersonationLevel.Impersonation
            };

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_NT_CREATE_ANDX);

            switch (reply.Commands[0])
            {
            case NTCreateAndXResponse response:
            {
                handle     = new Smb1Handle(response.FID);
                fileStatus = ToFileStatus(response.CreateDisposition);
                reply.IsSuccessElseThrow();
                break;
            }

            case ErrorResponse _:
                reply.IsSuccessElseThrow();
                break;

            default:
                throw new NtStatusException(NTStatus.STATUS_INVALID_SMB);
            }
        }
Example #14
0
        public NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass)
        {
            if (m_client.InfoLevelPassthrough)
            {
                result = null;
                int maxOutputLength = 4096;
                Transaction2QueryFSInformationRequest subcommand = new Transaction2QueryFSInformationRequest();
                subcommand.FileSystemInformationClass = informationClass;

                Transaction2Request request = new Transaction2Request();
                request.Setup               = subcommand.GetSetup();
                request.TransParameters     = subcommand.GetParameters(m_client.Unicode);
                request.TransData           = subcommand.GetData(m_client.Unicode);
                request.TotalDataCount      = (ushort)request.TransData.Length;
                request.TotalParameterCount = (ushort)request.TransParameters.Length;
                request.MaxParameterCount   = Transaction2QueryFSInformationResponse.ParametersLength;
                request.MaxDataCount        = (ushort)maxOutputLength;

                TrySendMessage(request);
                SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);
                if (reply != null)
                {
                    if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response)
                    {
                        Transaction2Response response = (Transaction2Response)reply.Commands[0];
                        Transaction2QueryFSInformationResponse subcommandResponse = new Transaction2QueryFSInformationResponse(response.TransParameters, response.TransData, reply.Header.UnicodeFlag);
                        result = subcommandResponse.GetFileSystemInformation(informationClass);
                    }
                    return(reply.Header.Status);
                }
                return(NTStatus.STATUS_INVALID_SMB);
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Example #15
0
        internal SMB1Message WaitForMessage(CommandName commandName)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            while (stopwatch.ElapsedMilliseconds < ResponseTimeoutInMilliseconds)
            {
                lock (m_incomingQueueLock)
                {
                    for (int index = 0; index < m_incomingQueue.Count; index++)
                    {
                        SMB1Message message = m_incomingQueue[index];

                        if (message.Commands[0].CommandName == commandName)
                        {
                            m_incomingQueue.RemoveAt(index);
                            return(message);
                        }
                    }
                }
                m_incomingQueueEventHandle.WaitOne(100);
            }
            return(null);
        }
Example #16
0
        public void GetFileInformation(out QueryInformation result, NtHandle handle, QueryInformationLevel informationLevel)
        {
            int maxOutputLength = 4096;
            Transaction2QueryFileInformationRequest subcommand = new Transaction2QueryFileInformationRequest
            {
                FID = ((Smb1Handle)handle).FID,
                QueryInformationLevel = informationLevel
            };

            Transaction2Request request = new Transaction2Request
            {
                Setup           = subcommand.GetSetup(),
                TransParameters = subcommand.GetParameters(m_client.Unicode),
                TransData       = subcommand.GetData(m_client.Unicode)
            };

            request.TotalDataCount      = (ushort)request.TransData.Length;
            request.TotalParameterCount = (ushort)request.TransParameters.Length;
            request.MaxParameterCount   = Transaction2QueryFileInformationResponse.ParametersLength;
            request.MaxDataCount        = (ushort)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);

            reply.IsSuccessElseThrow();
            if (!(reply.Commands[0] is Transaction2Response))
            {
                throw new NtStatusException(reply.Header.Status);
            }

            Transaction2Response response = (Transaction2Response)reply.Commands[0];
            Transaction2QueryFileInformationResponse subcommandResponse = new Transaction2QueryFileInformationResponse(response.TransParameters, response.TransData);

            result = subcommandResponse.GetQueryInformation(informationLevel);
            reply.IsSuccessElseThrow();
        }
Example #17
0
        public void Logoff()
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("A session must be successfully established before attempting logoff");
            }

            if (!m_isLoggedIn)
            {
                throw new InvalidOperationException("A login session must be successfully established before attempting logoff");
            }

            LogoffAndXRequest request = new LogoffAndXRequest();

            SendMessage(request);

            SMB1Message reply = WaitForMessage(CommandName.SMB_COM_LOGOFF_ANDX);

            if (reply.Header.Status == NTStatus.STATUS_SUCCESS)
            {
                m_isLoggedIn = false;
            }
            reply.IsSuccessElseThrow();
        }
Example #18
0
        internal static SMB1Message GetUnsolicitedEchoReply()
        {
            // [MS-CIFS] 3.2.5.1 - If the PID and MID values of the received message are not found in the
            // Client.Connection.PIDMIDList, the message MUST be discarded.
            SMB1Header header = new SMB1Header();

            header.Command = CommandName.SMB_COM_ECHO;
            header.Status  = NTStatus.STATUS_SUCCESS;
            header.Flags   = HeaderFlags.CaseInsensitive | HeaderFlags.CanonicalizedPaths | HeaderFlags.Reply;
            // [MS-CIFS] SMB_FLAGS2_LONG_NAMES SHOULD be set to 1 when the negotiated dialect is NT LANMAN.
            // [MS-CIFS] SMB_FLAGS2_UNICODE SHOULD be set to 1 when the negotiated dialect is NT LANMAN.
            header.Flags2 = HeaderFlags2.LongNamesAllowed | HeaderFlags2.NTStatusCode | HeaderFlags2.Unicode;
            header.UID    = 0xFFFF;
            header.TID    = 0xFFFF;
            header.PID    = 0xFFFFFFFF;
            header.MID    = 0xFFFF;

            EchoResponse response = new EchoResponse();
            SMB1Message  reply    = new SMB1Message();

            reply.Header = header;
            reply.Commands.Add(response);
            return(reply);
        }
Example #19
0
        private void ProcessPacket(SessionPacket packet, ConnectionState state)
        {
            if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
            }
            else if (packet is PositiveSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
            }
            else if (packet is NegativeSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                m_clientSocket.Close();
                m_isConnected = false;
            }
            else if (packet is SessionMessagePacket)
            {
                SMB1Message message;
                try
                {
                    message = SMB1Message.GetSMB1Message(packet.Trailer);
                }
                catch (Exception ex)
                {
                    Log("Invalid SMB1 message: " + ex.Message);
                    m_clientSocket.Close();
                    m_isConnected = false;
                    return;
                }

                lock (m_incomingQueueLock)
                {
                    m_incomingQueue.Add(message);
                    m_incomingQueueEventHandle.Set();
                }
            }
        }
Example #20
0
        private static void OnNotifyChangeCompleted(NTStatus status, byte[] buffer, object context)
        {
            SMB1AsyncContext asyncContext = (SMB1AsyncContext)context;

            // Wait until the 'Monitoring started' will be written to the log
            lock (asyncContext)
            {
                SMB1ConnectionState connection = asyncContext.Connection;
                connection.RemoveAsyncContext(asyncContext);
                SMB1Session session = connection.GetSession(asyncContext.UID);
                if (session != null)
                {
                    OpenFileObject openFile = session.GetOpenFileObject(asyncContext.FileID);
                    if (openFile != null)
                    {
                        connection.LogToServer(Severity.Verbose, "NotifyChange: Monitoring of '{0}{1}' completed. NTStatus: {2}. PID: {3}. MID: {4}.", openFile.ShareName, openFile.Path, status, asyncContext.PID, asyncContext.MID);
                    }
                    SMB1Header header = new SMB1Header();
                    header.Command = CommandName.SMB_COM_NT_TRANSACT;
                    header.Status  = status;
                    header.Flags   = HeaderFlags.CaseInsensitive | HeaderFlags.CanonicalizedPaths | HeaderFlags.Reply;
                    // [MS-CIFS] SMB_FLAGS2_LONG_NAMES SHOULD be set to 1 when the negotiated dialect is NT LANMAN.
                    // [MS-CIFS] SMB_FLAGS2_UNICODE SHOULD be set to 1 when the negotiated dialect is NT LANMAN.
                    // [MS-CIFS] The Windows NT Server implementation of NT_TRANSACT_NOTIFY_CHANGE always returns the names of changed files in Unicode format.
                    header.Flags2 = HeaderFlags2.LongNamesAllowed | HeaderFlags2.NTStatusCode | HeaderFlags2.Unicode;
                    header.UID    = asyncContext.UID;
                    header.TID    = asyncContext.TID;
                    header.PID    = asyncContext.PID;
                    header.MID    = asyncContext.MID;

                    if (status == NTStatus.STATUS_SUCCESS)
                    {
                        NTTransactNotifyChangeResponse notifyChangeResponse = new NTTransactNotifyChangeResponse();
                        notifyChangeResponse.FileNotifyInformationBytes = buffer;
                        byte[]             responseSetup      = notifyChangeResponse.GetSetup();
                        byte[]             responseParameters = notifyChangeResponse.GetParameters(false);
                        byte[]             responseData       = notifyChangeResponse.GetData();
                        List <SMB1Command> responseList       = NTTransactHelper.GetNTTransactResponse(responseSetup, responseParameters, responseData, asyncContext.Connection.MaxBufferSize);
                        if (responseList.Count == 1)
                        {
                            SMB1Message reply = new SMB1Message();
                            reply.Header = header;
                            reply.Commands.Add(responseList[0]);
                            SMBServer.EnqueueMessage(asyncContext.Connection, reply);
                        }
                        else
                        {
                            // [MS-CIFS] In the event that the number of changes exceeds [..] the maximum size of the NT_Trans_Parameter block in
                            // the response [..] the NT Trans subsystem MUST return an error response with a Status value of STATUS_NOTIFY_ENUM_DIR.
                            header.Status = NTStatus.STATUS_NOTIFY_ENUM_DIR;
                            ErrorResponse response = new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT);
                            SMB1Message   reply    = new SMB1Message();
                            reply.Header = header;
                            reply.Commands.Add(response);
                            SMBServer.EnqueueMessage(asyncContext.Connection, reply);
                        }
                    }
                    else
                    {
                        // Windows Server 2008 SP1 Will use ErrorResponse to return any status other than STATUS_SUCCESS (including STATUS_CANCELLED and STATUS_DELETE_PENDING).
                        //
                        // [MS-CIFS] In the event that the number of changes exceeds the size of the change notify buffer [..]
                        // the NT Trans subsystem MUST return an error response with a Status value of STATUS_NOTIFY_ENUM_DIR.
                        ErrorResponse response = new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT);
                        SMB1Message   reply    = new SMB1Message();
                        reply.Header = header;
                        reply.Commands.Add(response);
                        SMBServer.EnqueueMessage(asyncContext.Connection, reply);
                    }
                }
            }
        }
Example #21
0
        public void QueryDirectory(out List <FindInformation>?result, string fileName, FindInformationLevel informationLevel)
        {
            result = null;
            int maxOutputLength = 4096;
            Transaction2FindFirst2Request subCommand = new Transaction2FindFirst2Request
            {
                SearchAttributes = SMBFileAttributes.Hidden | SMBFileAttributes.System | SMBFileAttributes.Directory,
                SearchCount      = ushort.MaxValue,
                Flags            = FindFlags.SMB_FIND_CLOSE_AT_EOS,
                InformationLevel = informationLevel,
                FileName         = fileName
            };

            Transaction2Request request = new Transaction2Request
            {
                Setup           = subCommand.GetSetup(),
                TransParameters = subCommand.GetParameters(m_client.Unicode),
                TransData       = subCommand.GetData(m_client.Unicode)
            };

            request.TotalDataCount      = (ushort)request.TransData.Length;
            request.TotalParameterCount = (ushort)request.TransParameters.Length;
            request.MaxParameterCount   = Transaction2FindFirst2Response.ParametersLength;
            request.MaxDataCount        = (ushort)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);

            reply.IsSuccessElseThrow();
            if (!(reply.Commands[0] is Transaction2Response))
            {
                throw new NtStatusException(reply.Header.Status);
            }

            result = new List <FindInformation>();
            Transaction2Response           response            = (Transaction2Response)reply.Commands[0];
            Transaction2FindFirst2Response subcommandResponse  = new Transaction2FindFirst2Response(response.TransParameters, response.TransData);
            FindInformationList            findInformationList = subcommandResponse.GetFindInformationList(subCommand.InformationLevel, reply.Header.UnicodeFlag);

            result.AddRange(findInformationList);
            bool endOfSearch = subcommandResponse.EndOfSearch;

            while (!endOfSearch)
            {
                Transaction2FindNext2Request nextSubCommand = new Transaction2FindNext2Request
                {
                    SID              = subcommandResponse.SID,
                    SearchCount      = ushort.MaxValue,
                    Flags            = FindFlags.SMB_FIND_CLOSE_AT_EOS | FindFlags.SMB_FIND_CONTINUE_FROM_LAST,
                    InformationLevel = informationLevel,
                    FileName         = fileName
                };

                request = new Transaction2Request
                {
                    Setup           = nextSubCommand.GetSetup(),
                    TransParameters = nextSubCommand.GetParameters(m_client.Unicode),
                    TransData       = nextSubCommand.GetData(m_client.Unicode)
                };
                request.TotalDataCount      = (ushort)request.TransData.Length;
                request.TotalParameterCount = (ushort)request.TransParameters.Length;
                request.MaxParameterCount   = Transaction2FindNext2Response.ParametersLength;
                request.MaxDataCount        = (ushort)maxOutputLength;

                TrySendMessage(request);
                reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);
                if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response transaction2Response)
                {
                    Transaction2FindNext2Response nextSubCommandResponse = new Transaction2FindNext2Response(transaction2Response.TransParameters, transaction2Response.TransData);
                    findInformationList = nextSubCommandResponse.GetFindInformationList(subCommand.InformationLevel, reply.Header.UnicodeFlag);
                    result.AddRange(findInformationList);
                    endOfSearch = nextSubCommandResponse.EndOfSearch;
                }
                else
                {
                    endOfSearch = true;
                }
            }
            reply.IsSuccessElseThrow();
        }
Example #22
0
        public NTStatus Login(string domainName, string userName, string password, AuthenticationMethod authenticationMethod)
        {
            if (!m_isConnected)
            {
                throw new InvalidOperationException("A connection must be successfully established before attempting login");
            }

            Capabilities clientCapabilities = Capabilities.NTSMB | Capabilities.RpcRemoteApi | Capabilities.NTStatusCode | Capabilities.NTFind;

            if (m_unicode)
            {
                clientCapabilities |= Capabilities.Unicode;
            }
            if (m_largeFiles)
            {
                clientCapabilities |= Capabilities.LargeFiles;
            }
            if (m_largeRead)
            {
                clientCapabilities |= Capabilities.LargeRead;
            }

            if (m_serverChallenge != null)
            {
                SessionSetupAndXRequest request = new SessionSetupAndXRequest();
                request.MaxBufferSize = ClientMaxBufferSize;
                request.MaxMpxCount   = m_maxMpxCount;
                request.Capabilities  = clientCapabilities;
                request.AccountName   = userName;
                request.PrimaryDomain = domainName;
                byte[] clientChallenge = new byte[8];
                new Random().NextBytes(clientChallenge);
                if (authenticationMethod == AuthenticationMethod.NTLMv1)
                {
                    request.OEMPassword     = NTLMCryptography.ComputeLMv1Response(m_serverChallenge, password);
                    request.UnicodePassword = NTLMCryptography.ComputeNTLMv1Response(m_serverChallenge, password);
                }
                else if (authenticationMethod == AuthenticationMethod.NTLMv1ExtendedSessionSecurity)
                {
                    // [MS-CIFS] CIFS does not support Extended Session Security because there is no mechanism in CIFS to negotiate Extended Session Security
                    throw new ArgumentException("SMB Extended Security must be negotiated in order for NTLMv1 Extended Session Security to be used");
                }
                else // NTLMv2
                {
                    // Note: NTLMv2 over non-extended security session setup is not supported under Windows Vista and later which will return STATUS_INVALID_PARAMETER.
                    // https://msdn.microsoft.com/en-us/library/ee441701.aspx
                    // https://msdn.microsoft.com/en-us/library/cc236700.aspx
                    request.OEMPassword = NTLMCryptography.ComputeLMv2Response(m_serverChallenge, clientChallenge, password, userName, domainName);
                    NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(DateTime.UtcNow, clientChallenge, AVPairUtils.GetAVPairSequence(domainName, Environment.MachineName));
                    byte[] temp     = clientChallengeStructure.GetBytesPadded();
                    byte[] proofStr = NTLMCryptography.ComputeNTLMv2Proof(m_serverChallenge, temp, password, userName, domainName);
                    request.UnicodePassword = ByteUtils.Concatenate(proofStr, temp);
                }

                TrySendMessage(request);

                SMB1Message reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
                if (reply != null)
                {
                    m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
                    return(reply.Header.Status);
                }
                return(NTStatus.STATUS_INVALID_SMB);
            }
            else // m_securityBlob != null
            {
                byte[] negotiateMessage = NTLMAuthenticationHelper.GetNegotiateMessage(m_securityBlob, domainName, authenticationMethod);
                if (negotiateMessage == null)
                {
                    return(NTStatus.SEC_E_INVALID_TOKEN);
                }

                SessionSetupAndXRequestExtended request = new SessionSetupAndXRequestExtended();
                request.MaxBufferSize = ClientMaxBufferSize;
                request.MaxMpxCount   = m_maxMpxCount;
                request.Capabilities  = clientCapabilities;
                request.SecurityBlob  = negotiateMessage;
                TrySendMessage(request);

                SMB1Message reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
                if (reply != null)
                {
                    if (reply.Header.Status == NTStatus.STATUS_MORE_PROCESSING_REQUIRED && reply.Commands[0] is SessionSetupAndXResponseExtended)
                    {
                        SessionSetupAndXResponseExtended response = (SessionSetupAndXResponseExtended)reply.Commands[0];
                        byte[] authenticateMessage = NTLMAuthenticationHelper.GetAuthenticateMessage(response.SecurityBlob, domainName, userName, password, authenticationMethod, out m_sessionKey);
                        if (authenticateMessage == null)
                        {
                            return(NTStatus.SEC_E_INVALID_TOKEN);
                        }

                        m_userID = reply.Header.UID;
                        request  = new SessionSetupAndXRequestExtended();
                        request.MaxBufferSize = ClientMaxBufferSize;
                        request.MaxMpxCount   = m_maxMpxCount;
                        request.Capabilities  = clientCapabilities;
                        request.SecurityBlob  = authenticateMessage;
                        TrySendMessage(request);

                        reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
                        if (reply != null)
                        {
                            m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
                            return(reply.Header.Status);
                        }
                    }
                    else
                    {
                        return(reply.Header.Status);
                    }
                }
                return(NTStatus.STATUS_INVALID_SMB);
            }
        }
Example #23
0
        private void ProcessPacket(SessionPacket packet, ref ConnectionState state)
        {
            if (packet is SessionMessagePacket)
            {
                // Note: To be compatible with SMB2 specifications, we must accept SMB_COM_NEGOTIATE.
                // We will disconnect the connection if m_enableSMB1 == false and the client does not support SMB2.
                bool acceptSMB1 = (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.NTLM012);
                bool acceptSMB2 = (m_enableSMB2 && (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.SMB202 || state.Dialect == SMBDialect.SMB210 || state.Dialect == SMBDialect.SMB300));

                if (SMB1Header.IsValidSMB1Header(packet.Trailer))
                {
                    if (!acceptSMB1)
                    {
                        state.LogToServer(Severity.Verbose, "Rejected SMB1 message");
                        state.ClientSocket.Close();
                        return;
                    }

                    SMB1Message message = null;
                    try
                    {
                        message = SMB1Message.GetSMB1Message(packet.Trailer);
                    }
                    catch (Exception ex)
                    {
                        state.LogToServer(Severity.Warning, "Invalid SMB1 message: " + ex.Message);
                        state.ClientSocket.Close();
                        return;
                    }
                    state.LogToServer(Severity.Verbose, "SMB1 message received: {0} requests, First request: {1}, Packet length: {2}", message.Commands.Count, message.Commands[0].CommandName.ToString(), packet.Length);
                    if (state.Dialect == SMBDialect.NotSet && m_enableSMB2)
                    {
                        // Check if the client supports SMB 2
                        List <string> smb2Dialects = SMB2.NegotiateHelper.FindSMB2Dialects(message);
                        if (smb2Dialects.Count > 0)
                        {
                            SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, m_securityProvider, state, m_transport, m_serverGuid, m_serverStartTime);
                            if (state.Dialect != SMBDialect.NotSet)
                            {
                                state = new SMB2ConnectionState(state);
                                m_connectionManager.AddConnection(state);
                            }
                            EnqueueResponse(state, response);
                            return;
                        }
                    }

                    if (m_enableSMB1)
                    {
                        ProcessSMB1Message(message, ref state);
                    }
                    else
                    {
                        // [MS-SMB2] 3.3.5.3.2 If the string is not present in the dialect list and the server does not implement SMB,
                        // the server MUST disconnect the connection [..] without sending a response.
                        state.LogToServer(Severity.Verbose, "Rejected SMB1 message");
                        state.ClientSocket.Close();
                    }
                }
                else if (SMB2Header.IsValidSMB2Header(packet.Trailer))
                {
                    if (!acceptSMB2)
                    {
                        state.LogToServer(Severity.Verbose, "Rejected SMB2 message");
                        state.ClientSocket.Close();
                        return;
                    }

                    List <SMB2Command> requestChain;
                    try
                    {
                        requestChain = SMB2Command.ReadRequestChain(packet.Trailer, 0);
                    }
                    catch (Exception ex)
                    {
                        state.LogToServer(Severity.Warning, "Invalid SMB2 request chain: " + ex.Message);
                        state.ClientSocket.Close();
                        return;
                    }
                    state.LogToServer(Severity.Verbose, "SMB2 request chain received: {0} requests, First request: {1}, Packet length: {2}", requestChain.Count, requestChain[0].CommandName.ToString(), packet.Length);
                    ProcessSMB2RequestChain(requestChain, ref state);
                }
                else
                {
                    state.LogToServer(Severity.Warning, "Invalid SMB message");
                    state.ClientSocket.Close();
                }
            }
            else if (packet is SessionRequestPacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                PositiveSessionResponsePacket response = new PositiveSessionResponsePacket();
                state.SendQueue.Enqueue(response);
            }
            else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
            }
            else
            {
                state.LogToServer(Severity.Warning, "Inappropriate NetBIOS session packet");
                state.ClientSocket.Close();
                return;
            }
        }
Example #24
0
        public NTStatus QueryDirectory(out List <FindInformation> result, string fileName, FindInformationLevel informationLevel)
        {
            result = null;
            int maxOutputLength = 4096;
            Transaction2FindFirst2Request subcommand = new Transaction2FindFirst2Request();

            subcommand.SearchAttributes = SMBFileAttributes.Hidden | SMBFileAttributes.System | SMBFileAttributes.Directory;
            subcommand.SearchCount      = UInt16.MaxValue;
            subcommand.Flags            = FindFlags.SMB_FIND_CLOSE_AT_EOS;
            subcommand.InformationLevel = informationLevel;
            subcommand.FileName         = fileName;

            Transaction2Request request = new Transaction2Request();

            request.Setup               = subcommand.GetSetup();
            request.TransParameters     = subcommand.GetParameters(m_client.Unicode);
            request.TransData           = subcommand.GetData(m_client.Unicode);
            request.TotalDataCount      = (ushort)request.TransData.Length;
            request.TotalParameterCount = (ushort)request.TransParameters.Length;
            request.MaxParameterCount   = Transaction2FindFirst2Response.ParametersLength;
            request.MaxDataCount        = (ushort)maxOutputLength;

            TrySendMessage(request);
            SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);

            if (reply != null)
            {
                if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response)
                {
                    result = new List <FindInformation>();
                    Transaction2Response           response            = (Transaction2Response)reply.Commands[0];
                    Transaction2FindFirst2Response subcommandResponse  = new Transaction2FindFirst2Response(response.TransParameters, response.TransData, reply.Header.UnicodeFlag);
                    FindInformationList            findInformationList = subcommandResponse.GetFindInformationList(subcommand.InformationLevel, reply.Header.UnicodeFlag);
                    result.AddRange(findInformationList);
                    bool endOfSearch = subcommandResponse.EndOfSearch;
                    while (!endOfSearch)
                    {
                        Transaction2FindNext2Request nextSubcommand = new Transaction2FindNext2Request();
                        nextSubcommand.SID              = subcommandResponse.SID;
                        nextSubcommand.SearchCount      = UInt16.MaxValue;
                        nextSubcommand.Flags            = FindFlags.SMB_FIND_CLOSE_AT_EOS | FindFlags.SMB_FIND_CONTINUE_FROM_LAST;
                        nextSubcommand.InformationLevel = informationLevel;
                        nextSubcommand.FileName         = fileName;

                        request                     = new Transaction2Request();
                        request.Setup               = nextSubcommand.GetSetup();
                        request.TransParameters     = nextSubcommand.GetParameters(m_client.Unicode);
                        request.TransData           = nextSubcommand.GetData(m_client.Unicode);
                        request.TotalDataCount      = (ushort)request.TransData.Length;
                        request.TotalParameterCount = (ushort)request.TransParameters.Length;
                        request.MaxParameterCount   = Transaction2FindNext2Response.ParametersLength;
                        request.MaxDataCount        = (ushort)maxOutputLength;

                        TrySendMessage(request);
                        reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2);
                        if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response)
                        {
                            response = (Transaction2Response)reply.Commands[0];
                            Transaction2FindNext2Response nextSubcommandResponse = new Transaction2FindNext2Response(response.TransParameters, response.TransData, reply.Header.UnicodeFlag);
                            findInformationList = nextSubcommandResponse.GetFindInformationList(subcommand.InformationLevel, reply.Header.UnicodeFlag);
                            result.AddRange(findInformationList);
                            endOfSearch = nextSubcommandResponse.EndOfSearch;
                        }
                        else
                        {
                            endOfSearch = true;
                        }
                    }
                }
                return(reply.Header.Status);
            }
            return(NTStatus.STATUS_INVALID_SMB);
        }