예제 #1
0
        internal static SMB2Command GetQueryInfoResponse(QueryInfoRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.InfoType == InfoType.File)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path))
                    {
                        state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }

                FileInformation fileInformation;
                NTStatus        queryStatus = share.FileStore.GetFileInformation(out fileInformation, openFile.Handle, request.FileInformationClass);
                if (queryStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}", share.Name, openFile.Path, request.FileInformationClass, queryStatus);
                    return(new ErrorResponse(request.CommandName, queryStatus));
                }

                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}", share.Name, openFile.Path, request.FileInformationClass);
                QueryInfoResponse response = new QueryInfoResponse();
                response.SetFileInformation(fileInformation);
                return(response);
            }
            else if (request.InfoType == InfoType.FileSystem)
            {
                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, @"\"))
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }

                    FileSystemInformation fileSystemInformation;
                    NTStatus queryStatus = share.FileStore.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass);
                    if (queryStatus != NTStatus.STATUS_SUCCESS)
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", share.Name, request.FileSystemInformationClass, queryStatus);
                        return(new ErrorResponse(request.CommandName, queryStatus));
                    }

                    state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0} succeeded. Information class: {1}", share.Name, request.FileSystemInformationClass);
                    QueryInfoResponse response = new QueryInfoResponse();
                    response.SetFileSystemInformation(fileSystemInformation);
                    return(response);
                }
            }
            return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
예제 #2
0
        internal static SMB2Command GetWriteResponse(WriteRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path))
                {
                    state.LogToServer(Severity.Verbose, "Write to '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                }
            }

            int      numberOfBytesWritten;
            NTStatus writeStatus = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, (long)request.Offset, request.Data);

            if (writeStatus != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(request.CommandName, writeStatus));
            }
            WriteResponse response = new WriteResponse();

            response.Count = (uint)numberOfBytesWritten;
            return(response);
        }
예제 #3
0
        internal static SMB2Command GetReadResponse(ReadRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path))
                {
                    state.LogToServer(Severity.Verbose, "Read from '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                }
            }

            byte[]   data;
            NTStatus readStatus = share.FileStore.ReadFile(out data, openFile.Handle, (long)request.Offset, (int)request.ReadLength);

            if (readStatus != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(request.CommandName, readStatus));
            }
            ReadResponse response = new ReadResponse();

            response.Data = data;
            return(response);
        }
예제 #4
0
        internal static SMB2Command GetCreateResponse(CreateRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);
            string      path    = request.Name;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess))
                {
                    state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, path, session.UserName);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                }
            }

            object     handle;
            FileStatus fileStatus;
            // GetFileInformation/FileNetworkOpenInformation requires FILE_READ_ATTRIBUTES
            AccessMask desiredAccess = request.DesiredAccess | (AccessMask)FileAccessMask.FILE_READ_ATTRIBUTES;
            NTStatus   createStatus  = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, request.FileAttributes, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext);

            if (createStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, createStatus);
                return(new ErrorResponse(request.CommandName, createStatus));
            }

            FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess);
            FileID?    fileID     = session.AddOpenFile(request.Header.TreeID, share.Name, path, handle, fileAccess);

            if (fileID == null)
            {
                share.FileStore.CloseFile(handle);
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES));
            }

            string fileAccessString  = fileAccess.ToString().Replace(", ", "|");
            string shareAccessString = request.ShareAccess.ToString().Replace(", ", "|");

            state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}', FileAccess: {2}, ShareAccess: {3}. (SessionID: {4}, TreeID: {5}, FileId: {6})", share.Name, path, fileAccessString, shareAccessString, request.Header.SessionID, request.Header.TreeID, fileID.Value.Volatile);
            if (share is NamedPipeShare)
            {
                return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
            }
            else
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
                CreateResponse             response = CreateResponseFromFileSystemEntry(fileInfo, fileID.Value, fileStatus);
                return(response);
            }
        }
예제 #5
0
        public ushort?AddConnectedTree(ISMBShare share)
        {
            ushort?treeID = m_connection.AllocateTreeID();

            if (treeID.HasValue)
            {
                m_connectedTrees.Add(treeID.Value, share);
            }
            return(treeID);
        }
예제 #6
0
        internal static SMB2Command GetCreateResponse(CreateRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);
            string      path    = request.Name;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess))
                {
                    state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, path, session.UserName);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                }
            }

            object     handle;
            FileStatus fileStatus;
            NTStatus   createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext);

            if (createStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: '{2}'.", share.Name, path, createStatus);
                return(new ErrorResponse(request.CommandName, createStatus));
            }

            state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}'.", share.Name, path);
            FileID?fileID = session.AddOpenFile(request.Header.TreeID, path, handle);

            if (fileID == null)
            {
                share.FileStore.CloseFile(handle);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES));
            }

            if (share is NamedPipeShare)
            {
                return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
            }
            else
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
                CreateResponse             response = CreateResponseFromFileSystemEntry(fileInfo, fileID.Value, fileStatus);
                if (request.RequestedOplockLevel == OplockLevel.Batch)
                {
                    response.OplockLevel = OplockLevel.Batch;
                }
                return(response);
            }
        }
예제 #7
0
 public uint?AddConnectedTree(ISMBShare share)
 {
     lock (m_connectedTrees)
     {
         uint?treeID = AllocateTreeID();
         if (treeID.HasValue)
         {
             m_connectedTrees.Add(treeID.Value, share);
         }
         return(treeID);
     }
 }
예제 #8
0
        internal static SMB2Command GetSetInfoResponse(SetInfoRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.InfoType == InfoType.File)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path))
                    {
                        state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }

                FileInformation information;
                try
                {
                    information = FileInformation.GetFileInformation(request.Buffer, 0, request.FileInformationClass);
                }
                catch (UnsupportedInformationLevelException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_INFO_CLASS", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS));
                }
                catch (NotImplementedException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_NOT_SUPPORTED", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
                }
                catch (Exception)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_PARAMETER", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }

                NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, information);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}", share.Name, openFile.Path, request.FileInformationClass, status);
                    return(new ErrorResponse(request.CommandName, status));
                }
                state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information class: {2}", share.Name, openFile.Path, request.FileInformationClass);
                return(new SetInfoResponse());
            }
            return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
예제 #9
0
        internal static SMB2Command GetIOCtlResponse(IOCtlRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS ||
                request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS_EX)
            {
                // [MS-SMB2] 3.3.5.15.2 Handling a DFS Referral Information Request
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FS_DRIVER_REQUIRED));
            }

            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
            object         handle;

            if (openFile == null)
            {
                if (request.CtlCode == (uint)IoControlCode.FSCTL_PIPE_WAIT ||
                    request.CtlCode == (uint)IoControlCode.FSCTL_VALIDATE_NEGOTIATE_INFO ||
                    request.CtlCode == (uint)IoControlCode.FSCTL_QUERY_NETWORK_INTERFACE_INFO)
                {
                    // [MS-SMB2] 3.3.5.1.5 - FSCTL_PIPE_WAIT / FSCTL_QUERY_NETWORK_INTERFACE_INFO /
                    // FSCTL_VALIDATE_NEGOTIATE_INFO requests have FileId set to 0xFFFFFFFFFFFFFFFF.
                    handle = null;
                }
                else
                {
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }
            }
            else
            {
                handle = openFile.Handle;
            }

            int maxOutputLength = (int)request.MaxOutputResponse;

            byte[]   output;
            NTStatus status = share.FileStore.DeviceIOControl(handle, request.CtlCode, request.Input, out output, maxOutputLength);

            if (status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(request.CommandName, status));
            }

            IOCtlResponse response = new IOCtlResponse();

            response.CtlCode = request.CtlCode;
            response.FileId  = request.FileId;
            response.Output  = output;
            return(response);
        }
예제 #10
0
        internal static SMB2Command GetCancelResponse(CancelRequest request, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.Header.IsAsync)
            {
                SMB2AsyncContext context = state.GetAsyncContext(request.Header.AsyncID);
                if (context != null)
                {
                    ISMBShare      share    = session.GetConnectedTree(context.TreeID);
                    OpenFileObject openFile = session.GetOpenFileObject(context.FileID);
                    NTStatus       status   = share.FileStore.Cancel(context.IORequest);
                    if (openFile != null)
                    {
                        state.LogToServer(Severity.Information, "Cancel: Requested cancel on '{0}{1}'. NTStatus: {2}, AsyncID: {3}.", share.Name, openFile.Path, status, context.AsyncID);
                    }
                    if (status == NTStatus.STATUS_SUCCESS ||
                        status == NTStatus.STATUS_CANCELLED ||
                        status == NTStatus.STATUS_NOT_SUPPORTED) // See ChangeNotifyHelper.cs
                    {
                        state.RemoveAsyncContext(context);
                        // [MS-SMB2] If the target request is successfully canceled, the target request MUST be failed by sending
                        // an ERROR response packet [..] with the status field of the SMB2 header set to STATUS_CANCELLED.
                        ErrorResponse response = new ErrorResponse(request.CommandName, NTStatus.STATUS_CANCELLED);
                        response.Header.IsAsync = true;
                        response.Header.AsyncID = context.AsyncID;
                        return(response);
                    }
                    // [MS-SMB2] If the target request is not successfully canceled [..] no response is sent.
                    // Note: Failing to respond might cause the client to disconnect the connection as per [MS-SMB2] 3.2.6.1 Request Expiration Timer Event
                    return(null);
                }
                else
                {
                    // [MS-SMB2] If a request is not found [..] no response is sent.
                    return(null);
                }
            }
            else
            {
                // [MS-SMB2] the SMB2 CANCEL Request MUST use an ASYNC header for canceling requests that have received an interim response.
                // [MS-SMB2] If the target request is not successfully canceled [..] no response is sent.
                return(null);
            }
        }
예제 #11
0
        internal static SMB2Command GetFlushResponse(FlushRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "Flush failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }
            NTStatus status = share.FileStore.FlushFileBuffers(openFile.Handle);

            if (status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Flush '{0}{1}' failed. NTStatus: {2}. (FileId: {3})", share.Name, openFile.Path, status, request.FileId.Volatile);
                return(new ErrorResponse(request.CommandName, status));
            }
            return(new FlushResponse());
        }
예제 #12
0
        internal static SMB2Command GetCloseResponse(CloseRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "Close failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }

            NTStatus closeStatus = share.FileStore.CloseFile(openFile.Handle);

            if (closeStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Information, "Close: Closing '{0}{1}' failed. NTStatus: {2}. (SessionID: {3}, TreeID: {4}, FileId: {5})", share.Name, openFile.Path, closeStatus, request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                return(new ErrorResponse(request.CommandName, closeStatus));
            }

            state.LogToServer(Severity.Information, "Close: Closed '{0}{1}'. (SessionID: {2}, TreeID: {3}, FileId: {4})", share.Name, openFile.Path, request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
            session.RemoveOpenFile(request.FileId);
            CloseResponse response = new CloseResponse();

            if (request.PostQueryAttributes)
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, openFile.Path, session.SecurityContext);
                if (fileInfo != null)
                {
                    response.CreationTime   = fileInfo.CreationTime;
                    response.LastAccessTime = fileInfo.LastAccessTime;
                    response.LastWriteTime  = fileInfo.LastWriteTime;
                    response.ChangeTime     = fileInfo.ChangeTime;
                    response.AllocationSize = fileInfo.AllocationSize;
                    response.EndofFile      = fileInfo.EndOfFile;
                    response.FileAttributes = fileInfo.FileAttributes;
                }
            }
            return(response);
        }
예제 #13
0
        internal static List <SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, uint maxParameterCount, uint maxDataCount, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
        {
            NTTransactSubcommand subcommand;

            try
            {
                subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag);
            }
            catch
            {
                // [MS-CIFS] If the Function code is not defined, the server MUST return STATUS_INVALID_SMB.
                header.Status = NTStatus.STATUS_INVALID_SMB;
                return(new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT));
            }
            state.LogToServer(Severity.Verbose, "Received complete SMB_COM_NT_TRANSACT subcommand: {0}", subcommand.SubcommandName);
            NTTransactSubcommand subcommandResponse = null;

            if (subcommand is NTTransactCreateRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is NTTransactIOCTLRequest)
            {
                subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactIOCTLRequest)subcommand, share, state);
            }
            else if (subcommand is NTTransactSetSecurityDescriptorRequest)
            {
                subcommandResponse = GetSubcommandResponse(header, (NTTransactSetSecurityDescriptorRequest)subcommand, share, state);
            }
            else if (subcommand is NTTransactNotifyChangeRequest)
            {
                NotifyChangeHelper.ProcessNTTransactNotifyChangeRequest(header, maxParameterCount, (NTTransactNotifyChangeRequest)subcommand, share, state);
                if (header.Status == NTStatus.STATUS_PENDING)
                {
                    return(new List <SMB1Command>());
                }
            }
            else if (subcommand is NTTransactQuerySecurityDescriptorRequest)
            {
                subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactQuerySecurityDescriptorRequest)subcommand, share, state);
            }
            else
            {
                // [MS-CIFS] If the Function code is defined but not implemented, the server MUST return STATUS_SMB_BAD_COMMAND.
                header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
            }

            if (subcommandResponse == null)
            {
                return(new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT));
            }

            byte[] responseSetup      = subcommandResponse.GetSetup();
            byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag);
            byte[] responseData       = subcommandResponse.GetData();
            return(GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize));
        }
예제 #14
0
        /// <summary>
        /// There are no secondary response messages.
        /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
        /// </summary>
        internal static List <SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactSecondaryRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            ProcessStateObject processState = state.GetProcessState(header.PID);

            if (processState == null)
            {
                throw new InvalidDataException();
            }
            ByteWriter.WriteBytes(processState.TransactionParameters, (int)request.ParameterDisplacement, request.TransParameters);
            ByteWriter.WriteBytes(processState.TransactionData, (int)request.DataDisplacement, request.TransData);
            processState.TransactionParametersReceived += request.TransParameters.Length;
            processState.TransactionDataReceived       += request.TransData.Length;

            if (processState.TransactionParametersReceived < processState.TransactionParameters.Length ||
                processState.TransactionDataReceived < processState.TransactionData.Length)
            {
                return(new List <SMB1Command>());
            }
            else
            {
                // We have a complete command
                state.RemoveProcessState(header.PID);
                return(GetCompleteNTTransactResponse(header, processState.MaxParameterCount, processState.MaxDataCount, (NTTransactSubcommandName)processState.SubcommandID, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state));
            }
        }
예제 #15
0
        private static NTTransactQuerySecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactQuerySecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID);
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            int maxOutputLength = (int)maxDataCount;
            SecurityDescriptor securityDescriptor;

            header.Status = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, subcommand.SecurityInfoFields);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), header.Status, subcommand.FID);
                return(null);
            }

            NTTransactQuerySecurityDescriptorResponse response = new NTTransactQuerySecurityDescriptorResponse();

            response.LengthNeeded = (uint)securityDescriptor.Length;
            if (response.LengthNeeded <= maxDataCount)
            {
                state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID);
                response.SecurityDescriptor = securityDescriptor;
            }
            else
            {
                state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID);
                header.Status = NTStatus.STATUS_BUFFER_TOO_SMALL;
            }
            return(response);
        }
예제 #16
0
 /// <summary>
 /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
 /// </summary>
 internal static List <SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactRequest request, ISMBShare share, SMB1ConnectionState state)
 {
     if (request.TransParameters.Length < request.TotalParameterCount ||
         request.TransData.Length < request.TotalDataCount)
     {
         // A secondary transaction request is pending
         ProcessStateObject processState = state.CreateProcessState(header.PID);
         processState.SubcommandID          = (ushort)request.Function;
         processState.MaxParameterCount     = request.MaxParameterCount;
         processState.MaxDataCount          = request.MaxDataCount;
         processState.TransactionSetup      = request.Setup;
         processState.TransactionParameters = new byte[request.TotalParameterCount];
         processState.TransactionData       = new byte[request.TotalDataCount];
         ByteWriter.WriteBytes(processState.TransactionParameters, 0, request.TransParameters);
         ByteWriter.WriteBytes(processState.TransactionData, 0, request.TransData);
         processState.TransactionParametersReceived += request.TransParameters.Length;
         processState.TransactionDataReceived       += request.TransData.Length;
         return(new NTTransactInterimResponse());
     }
     else
     {
         // We have a complete command
         return(GetCompleteNTTransactResponse(header, request.MaxParameterCount, request.MaxDataCount, request.Function, request.Setup, request.TransParameters, request.TransData, share, state));
     }
 }
예제 #17
0
        private static NTTransactSetSecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, NTTransactSetSecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "SetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID);
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            header.Status = share.FileStore.SetSecurityInformation(openFile.Handle, subcommand.SecurityInformation, subcommand.SecurityDescriptor);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), header.Status, subcommand.FID);
                return(null);
            }

            state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), subcommand.FID);
            NTTransactSetSecurityDescriptorResponse response = new NTTransactSetSecurityDescriptorResponse();

            return(response);
        }
예제 #18
0
        private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);
            string      ctlCode = Enum.IsDefined(typeof(IoControlCode), subcommand.FunctionCode) ? ((IoControlCode)subcommand.FunctionCode).ToString() : ("0x" + subcommand.FunctionCode.ToString("X8"));

            if (!subcommand.IsFsctl)
            {
                // [MS-SMB] If the IsFsctl field is set to zero, the server SHOULD fail the request with STATUS_NOT_SUPPORTED
                state.LogToServer(Severity.Verbose, "IOCTL: Non-FSCTL requests are not supported. CTL Code: {0}", ctlCode);
                header.Status = NTStatus.STATUS_NOT_SUPPORTED;
                return(null);
            }

            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. Invalid FID. (UID: {1}, TID: {2}, FID: {3})", ctlCode, header.UID, header.TID, subcommand.FID);
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            int maxOutputLength = (int)maxDataCount;

            byte[] output;
            header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength);
            if (header.Status != NTStatus.STATUS_SUCCESS && header.Status != NTStatus.STATUS_BUFFER_OVERFLOW)
            {
                state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. NTStatus: {1}. (FID: {2})", ctlCode, header.Status, subcommand.FID);
                return(null);
            }

            state.LogToServer(Severity.Verbose, "IOCTL succeeded. CTL Code: {0}. (FID: {1})", ctlCode, subcommand.FID);
            NTTransactIOCTLResponse response = new NTTransactIOCTLResponse();

            response.Data = output;
            return(response);
        }
예제 #19
0
        /// <summary>
        /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
        /// The server MUST respond to the transaction request as a whole.
        /// </summary>
        internal static List <SMB1Command> GetTransactionResponse(SMB1Header header, TransactionRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            ProcessStateObject processState = state.ObtainProcessState(header.PID);

            processState.MaxDataCount = request.MaxDataCount;

            if (request.TransParameters.Length < request.TotalParameterCount ||
                request.TransData.Length < request.TotalDataCount)
            {
                // A secondary transaction request is pending
                processState.Name                  = request.Name;
                processState.TransactionSetup      = request.Setup;
                processState.TransactionParameters = new byte[request.TotalParameterCount];
                processState.TransactionData       = new byte[request.TotalDataCount];
                ByteWriter.WriteBytes(processState.TransactionParameters, 0, request.TransParameters);
                ByteWriter.WriteBytes(processState.TransactionData, 0, request.TransData);
                processState.TransactionParametersReceived += request.TransParameters.Length;
                processState.TransactionDataReceived       += request.TransData.Length;
                if (request is Transaction2Request)
                {
                    return(new Transaction2InterimResponse());
                }
                else
                {
                    return(new TransactionInterimResponse());
                }
            }
            else
            {
                // We have a complete command
                if (request is Transaction2Request)
                {
                    return(GetCompleteTransaction2Response(header, request.Setup, request.TransParameters, request.TransData, share, state));
                }
                else
                {
                    return(GetCompleteTransactionResponse(header, request.Name, request.Setup, request.TransParameters, request.TransData, share, state));
                }
            }
        }
        internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            int maxOutputLength = UInt16.MaxValue;

            byte[] output;
            header.Status = share.FileStore.DeviceIOControl(openFile.Handle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, subcommand.WriteData, out output, maxOutputLength);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(null);
            }
            TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse();

            response.ReadData = output;
            return(response);
        }
예제 #21
0
        internal static SMB2Command GetQueryInfoResponse(QueryInfoRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.InfoType == InfoType.File)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path))
                    {
                        state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }

                FileInformation fileInformation;
                NTStatus        queryStatus = share.FileStore.GetFileInformation(out fileInformation, openFile.Handle, request.FileInformationClass);
                if (queryStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.FileInformationClass, queryStatus, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, queryStatus));
                }

                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FileId: {3})", share.Name, openFile.Path, request.FileInformationClass, request.FileId.Volatile);
                QueryInfoResponse response = new QueryInfoResponse();
                response.SetFileInformation(fileInformation);
                return(response);
            }
            else if (request.InfoType == InfoType.FileSystem)
            {
                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, @"\"))
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }

                    FileSystemInformation fileSystemInformation;
                    NTStatus queryStatus = share.FileStore.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass);
                    if (queryStatus != NTStatus.STATUS_SUCCESS)
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", share.Name, request.FileSystemInformationClass, queryStatus);
                        return(new ErrorResponse(request.CommandName, queryStatus));
                    }

                    state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information class: {1}", share.Name, request.FileSystemInformationClass);
                    QueryInfoResponse response = new QueryInfoResponse();
                    response.SetFileSystemInformation(fileSystemInformation);
                    return(response);
                }
            }
            else if (request.InfoType == InfoType.Security)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path))
                    {
                        state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }

                SecurityDescriptor securityDescriptor;
                NTStatus           queryStatus = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, request.SecurityInformation);
                if (queryStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), queryStatus, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, queryStatus));
                }

                if (securityDescriptor.Length > request.OutputBufferLength)
                {
                    state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile);
                    byte[] errorData = LittleEndianConverter.GetBytes((uint)securityDescriptor.Length);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_BUFFER_TOO_SMALL, errorData));
                }

                state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile);
                QueryInfoResponse response = new QueryInfoResponse();
                response.SetSecurityInformation(securityDescriptor);
                return(response);
            }
            return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
예제 #22
0
        internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session    = state.GetSession(header.UID);
            bool        isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0;
            string      path       = request.FileName;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess))
                {
                    state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            object         handle;
            FileStatus     fileStatus;
            FileAttributes fileAttributes = ToFileAttributes(request.ExtFileAttributes);
            // GetFileInformation/FileNetworkOpenInformation requires FILE_READ_ATTRIBUTES
            AccessMask desiredAccess = request.DesiredAccess | (AccessMask)FileAccessMask.FILE_READ_ATTRIBUTES;
            NTStatus   createStatus  = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, fileAttributes, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext);

            if (createStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, createStatus);
                header.Status = createStatus;
                return(new ErrorResponse(request.CommandName));
            }

            FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess);
            ushort?    fileID     = session.AddOpenFile(header.TID, share.Name, path, handle, fileAccess);

            if (!fileID.HasValue)
            {
                share.FileStore.CloseFile(handle);
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path);
                header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
                return(new ErrorResponse(request.CommandName));
            }

            string fileAccessString  = fileAccess.ToString().Replace(", ", "|");
            string shareAccessString = request.ShareAccess.ToString().Replace(", ", "|");

            state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}', FileAccess: {2}, ShareAccess: {3}. (UID: {4}, TID: {5}, FID: {6})", share.Name, path, fileAccessString, shareAccessString, header.UID, header.TID, fileID.Value);
            if (share is NamedPipeShare)
            {
                if (isExtended)
                {
                    return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
                }
                else
                {
                    return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
                }
            }
            else // FileSystemShare
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
                if (isExtended)
                {
                    NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus);
                    return(response);
                }
                else
                {
                    NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus);
                    return(response);
                }
            }
        }
예제 #23
0
        internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session      = state.GetSession(header.UID);
            bool        isExtended   = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0;
            string      path         = request.FileName;
            FileAccess  createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess))
                {
                    state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            object     handle;
            FileStatus fileStatus;
            NTStatus   createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext);

            if (createStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: '{2}'.", share.Name, path, createStatus);
                header.Status = createStatus;
                return(new ErrorResponse(request.CommandName));
            }

            state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}'.", share.Name, path);
            ushort?fileID = session.AddOpenFile(header.TID, path, handle);

            if (!fileID.HasValue)
            {
                share.FileStore.CloseFile(handle);
                header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
                return(new ErrorResponse(request.CommandName));
            }

            if (share is NamedPipeShare)
            {
                if (isExtended)
                {
                    return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
                }
                else
                {
                    return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED));
                }
            }
            else // FileSystemShare
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
                if (isExtended)
                {
                    NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus);
                    if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
                    {
                        response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
                    }
                    return(response);
                }
                else
                {
                    NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus);
                    if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
                    {
                        response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
                    }
                    return(response);
                }
            }
        }
예제 #24
0
        /// <summary>
        /// There are no secondary response messages.
        /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
        /// The server MUST respond to the transaction request as a whole.
        /// </summary>
        internal static List <SMB1Command> GetTransactionResponse(SMB1Header header, TransactionSecondaryRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            ProcessStateObject processState = state.GetProcessState(header.PID);

            if (processState == null)
            {
                throw new InvalidRequestException();
            }
            ByteWriter.WriteBytes(processState.TransactionParameters, request.ParameterDisplacement, request.TransParameters);
            ByteWriter.WriteBytes(processState.TransactionData, request.DataDisplacement, request.TransData);
            processState.TransactionParametersReceived += request.TransParameters.Length;
            processState.TransactionDataReceived       += request.TransData.Length;

            if (processState.TransactionParametersReceived < processState.TransactionParameters.Length ||
                processState.TransactionDataReceived < processState.TransactionData.Length)
            {
                return(new List <SMB1Command>());
            }
            else
            {
                // We have a complete command
                if (request is Transaction2SecondaryRequest)
                {
                    return(GetCompleteTransaction2Response(header, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state));
                }
                else
                {
                    return(GetCompleteTransactionResponse(header, processState.Name, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state));
                }
            }
        }
예제 #25
0
        private SMB2Command ProcessSMB2Command(SMB2Command command, SMB2ConnectionState state)
        {
            if (command is SessionSetupRequest)
            {
                return(SessionSetupHelper.GetSessionSetupResponse((SessionSetupRequest)command, m_securityProvider, state));
            }
            else if (command is EchoRequest)
            {
                return(new EchoResponse());
            }
            else
            {
                SMB2Session session = state.GetSession(command.Header.SessionID);
                if (session == null)
                {
                    return(new ErrorResponse(command.CommandName, NTStatus.STATUS_USER_SESSION_DELETED));
                }

                if (command is TreeConnectRequest)
                {
                    return(TreeConnectHelper.GetTreeConnectResponse((TreeConnectRequest)command, state, m_services, m_shares));
                }
                else if (command is LogoffRequest)
                {
                    state.LogToServer(Severity.Information, "Logoff: User '{0}' logged off. (SessionID: {1})", session.UserName, command.Header.SessionID);
                    m_securityProvider.DeleteSecurityContext(ref session.SecurityContext.AuthenticationContext);
                    state.RemoveSession(command.Header.SessionID);
                    return(new LogoffResponse());
                }
                else if (command.Header.IsAsync)
                {
                    // TreeID will not be present in an ASYNC header
                    if (command is CancelRequest)
                    {
                        return(CancelHelper.GetCancelResponse((CancelRequest)command, state));
                    }
                }
                else
                {
                    ISMBShare share = session.GetConnectedTree(command.Header.TreeID);
                    if (share == null)
                    {
                        state.LogToServer(Severity.Verbose, "{0} failed. Invalid TreeID (SessionID: {1}, TreeID: {2}).", command.CommandName, command.Header.SessionID, command.Header.TreeID);
                        return(new ErrorResponse(command.CommandName, NTStatus.STATUS_NETWORK_NAME_DELETED));
                    }

                    if (command is TreeDisconnectRequest)
                    {
                        return(TreeConnectHelper.GetTreeDisconnectResponse((TreeDisconnectRequest)command, share, state));
                    }
                    else if (command is CreateRequest)
                    {
                        return(CreateHelper.GetCreateResponse((CreateRequest)command, share, state));
                    }
                    else if (command is QueryInfoRequest)
                    {
                        return(QueryInfoHelper.GetQueryInfoResponse((QueryInfoRequest)command, share, state));
                    }
                    else if (command is SetInfoRequest)
                    {
                        return(SetInfoHelper.GetSetInfoResponse((SetInfoRequest)command, share, state));
                    }
                    else if (command is QueryDirectoryRequest)
                    {
                        return(QueryDirectoryHelper.GetQueryDirectoryResponse((QueryDirectoryRequest)command, share, state));
                    }
                    else if (command is ReadRequest)
                    {
                        return(ReadWriteResponseHelper.GetReadResponse((ReadRequest)command, share, state));
                    }
                    else if (command is WriteRequest)
                    {
                        return(ReadWriteResponseHelper.GetWriteResponse((WriteRequest)command, share, state));
                    }
                    else if (command is LockRequest)
                    {
                        return(LockHelper.GetLockResponse((LockRequest)command, share, state));
                    }
                    else if (command is FlushRequest)
                    {
                        return(ReadWriteResponseHelper.GetFlushResponse((FlushRequest)command, share, state));
                    }
                    else if (command is CloseRequest)
                    {
                        return(CloseHelper.GetCloseResponse((CloseRequest)command, share, state));
                    }
                    else if (command is IOCtlRequest)
                    {
                        return(IOCtlHelper.GetIOCtlResponse((IOCtlRequest)command, share, state));
                    }
                    else if (command is CancelRequest)
                    {
                        return(CancelHelper.GetCancelResponse((CancelRequest)command, state));
                    }
                    else if (command is ChangeNotifyRequest)
                    {
                        return(ChangeNotifyHelper.GetChangeNotifyInterimResponse((ChangeNotifyRequest)command, share, state));
                    }
                }
            }

            return(new ErrorResponse(command.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
예제 #26
0
        internal static SMB1Command GetCloseResponse(SMB1Header header, CloseRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "Close failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID);
                header.Status = NTStatus.STATUS_SMB_BAD_FID;
                return(new ErrorResponse(request.CommandName));
            }

            header.Status = share.FileStore.CloseFile(openFile.Handle);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Information, "Close: Closing '{0}{1}' failed. NTStatus: {2}. (UID: {3}, TID: {4}, FID: {5})", share.Name, openFile.Path, header.Status, header.UID, header.TID, request.FID);
                return(new ErrorResponse(request.CommandName));
            }

            state.LogToServer(Severity.Information, "Close: Closed '{0}{1}'. (UID: {2}, TID: {3}, FID: {4})", share.Name, openFile.Path, header.UID, header.TID, request.FID);
            session.RemoveOpenFile(request.FID);
            return(new CloseResponse());
        }
예제 #27
0
        internal static SMB2Command GetLockResponse(LockRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "Lock failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }

            if (request.Locks.Count == 0)
            {
                // [MS-SMB2] The lock count MUST be greater than or equal to 1
                state.LogToServer(Severity.Verbose, "Lock: Invalid number of locks, must be greater than 0.");
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
            }

            // [MS-SMB2] If the flags of the initial SMB2_LOCK_ELEMENT in the Locks array of the request has
            // SMB2_LOCKFLAG_UNLOCK set, the server MUST process the lock array as a series of unlocks.
            // Otherwise, it MUST process the lock array as a series of lock requests.
            bool unlock = request.Locks[0].Unlock;

            foreach (LockElement lockElement in request.Locks)
            {
                if (unlock)
                {
                    if (lockElement.SharedLock || lockElement.ExclusiveLock)
                    {
                        state.LogToServer(Severity.Verbose, "Lock: Invalid parameter: Lock in a series of unlocks.");
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                    }
                }
                else
                {
                    if (lockElement.Unlock)
                    {
                        state.LogToServer(Severity.Verbose, "Lock: Invalid parameter: Unlock in a series of locks.");
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                    }

                    if (lockElement.SharedLock && lockElement.ExclusiveLock)
                    {
                        state.LogToServer(Severity.Verbose, "Lock: Invalid parameter: SMB2_LOCKFLAG_SHARED_LOCK and SMB2_LOCKFLAG_EXCLUSIVE_LOCK are mutually exclusive.");
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                    }

                    if (request.Locks.Count > 1 && !lockElement.FailImmediately)
                    {
                        state.LogToServer(Severity.Verbose, "Lock: Invalid parameter: SMB2_LOCKFLAG_FAIL_IMMEDIATELY not set in a series of locks.");
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                    }
                }
            }

            for (int lockIndex = 0; lockIndex < request.Locks.Count; lockIndex++)
            {
                LockElement lockElement = request.Locks[lockIndex];
                if (unlock)
                {
                    NTStatus status = share.FileStore.UnlockFile(openFile.Handle, (long)lockElement.Offset, (long)lockElement.Length);
                    if (status != NTStatus.STATUS_SUCCESS)
                    {
                        // [MS-SMB2] If the unlock operation fails, the server MUST fail the operation with the error code received from the object store and stop processing further entries in the Locks array.
                        state.LogToServer(Severity.Information, "Lock: Unlocking '{0}{1}' failed. Offset: {2}, Length: {3}. NTStatus: {4}.", share.Name, openFile.Path, lockElement.Offset, lockElement.Length, status);
                        return(new ErrorResponse(request.CommandName, status));
                    }
                    state.LogToServer(Severity.Information, "Lock: Unlocking '{0}{1}' succeeded. Offset: {2}, Length: {3}.", share.Name, openFile.Path, lockElement.Offset, lockElement.Length);
                }
                else
                {
                    NTStatus status = share.FileStore.LockFile(openFile.Handle, (long)lockElement.Offset, (long)lockElement.Length, lockElement.ExclusiveLock);
                    if (status != NTStatus.STATUS_SUCCESS)
                    {
                        // [MS-SMB2] If the lock operation fails, the server MUST unlock any ranges locked as part of processing the previous entries in the Locks array of this request.
                        state.LogToServer(Severity.Information, "Lock: Locking '{0}{1}' failed. Offset: {2}, Length: {3}. NTStatus: {4}.", share.Name, openFile.Path, lockElement.Offset, lockElement.Length, status);
                        for (int index = 0; index < lockIndex; index++)
                        {
                            share.FileStore.UnlockFile(openFile.Handle, (long)request.Locks[index].Offset, (long)request.Locks[index].Length);
                        }
                        return(new ErrorResponse(request.CommandName, status));
                    }
                    state.LogToServer(Severity.Information, "Lock: Locking '{0}{1}' succeeded. Offset: {2}, Length: {3}.", share.Name, openFile.Path, lockElement.Offset, lockElement.Length);
                }
            }

            return(new LockResponse());
        }
예제 #28
0
        internal static List <SMB1Command> GetCompleteTransactionResponse(SMB1Header header, string name, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
        {
            if (String.Equals(name, @"\pipe\lanman", StringComparison.InvariantCultureIgnoreCase))
            {
                // [MS-RAP] Remote Administration Protocol request
                state.LogToServer(Severity.Debug, "Remote Administration Protocol requests are not implemented");
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION));
            }

            TransactionSubcommand subcommand;

            try
            {
                subcommand = TransactionSubcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag);
            }
            catch
            {
                header.Status = NTStatus.STATUS_INVALID_SMB;
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION));
            }
            TransactionSubcommand subcommandResponse = null;

            if (subcommand is TransactionSetNamedPipeStateRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionRawReadNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionQueryNamedPipeStateRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionQueryNamedPipeInfoRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionPeekNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionTransactNamedPipeRequest)
            {
                subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, (TransactionTransactNamedPipeRequest)subcommand, share, state);
            }
            else if (subcommand is TransactionRawWriteNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionReadNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionWriteNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionWaitNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is TransactionCallNamedPipeRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else
            {
                header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
            }

            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION));
            }

            byte[] responseSetup      = subcommandResponse.GetSetup();
            byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag);
            byte[] responseData       = subcommandResponse.GetData();
            return(GetTransactionResponse(false, responseSetup, responseParameters, responseData, state.MaxBufferSize));
        }
예제 #29
0
        internal static SMB1Command GetOpenAndXResponse(SMB1Header header, OpenAndXRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session    = state.GetSession(header.UID);
            bool        isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
            string      path       = request.FileName;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            AccessMask        desiredAccess;
            ShareAccess       shareAccess;
            CreateDisposition createDisposition;

            try
            {
                desiredAccess     = ToAccessMask(request.AccessMode.AccessMode);
                shareAccess       = ToShareAccess(request.AccessMode.SharingMode);
                createDisposition = ToCreateDisposition(request.OpenMode);
            }
            catch (ArgumentException)
            {
                // Invalid input according to MS-CIFS
                header.Status = NTStatus.STATUS_OS2_INVALID_ACCESS;
                return(new ErrorResponse(request.CommandName));
            }
            CreateOptions createOptions = ToCreateOptions(request.AccessMode);

            FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(desiredAccess, createDisposition);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess))
                {
                    state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            object     handle;
            FileStatus fileStatus;

            header.Status = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, 0, shareAccess, createDisposition, createOptions, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, header.Status);
                return(new ErrorResponse(request.CommandName));
            }

            FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode);
            ushort?    fileID     = session.AddOpenFile(header.TID, share.Name, path, handle, fileAccess);

            if (!fileID.HasValue)
            {
                share.FileStore.CloseFile(handle);
                state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path);
                header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
                return(new ErrorResponse(request.CommandName));
            }

            state.LogToServer(Severity.Verbose, "OpenAndX: Opened '{0}{1}'. (UID: {2}, TID: {3}, FID: {4})", share.Name, path, header.UID, header.TID, fileID.Value);
            OpenResult openResult = ToOpenResult(fileStatus);

            if (share is NamedPipeShare)
            {
                if (isExtended)
                {
                    return(CreateResponseExtendedForNamedPipe(fileID.Value, openResult));
                }
                else
                {
                    return(CreateResponseForNamedPipe(fileID.Value, openResult));
                }
            }
            else // FileSystemShare
            {
                FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
                if (isExtended)
                {
                    return(CreateResponseExtendedFromFileInfo(fileInfo, fileID.Value, openResult));
                }
                else
                {
                    return(CreateResponseFromFileInfo(fileInfo, fileID.Value, openResult));
                }
            }
        }
예제 #30
0
        internal static List <SMB1Command> GetCompleteTransaction2Response(SMB1Header header, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
        {
            Transaction2Subcommand subcommand;

            try
            {
                subcommand = Transaction2Subcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag);
            }
            catch
            {
                header.Status = NTStatus.STATUS_INVALID_SMB;
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2));
            }
            Transaction2Subcommand subcommandResponse = null;

            if (subcommand is Transaction2FindFirst2Request)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindFirst2Request)subcommand, share, state);
            }
            else if (subcommand is Transaction2FindNext2Request)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindNext2Request)subcommand, share, state);
            }
            else if (subcommand is Transaction2QueryFSInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFSInformationRequest)subcommand, share, state);
            }
            else if (subcommand is Transaction2QueryPathInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryPathInformationRequest)subcommand, share, state);
            }
            else if (subcommand is Transaction2SetPathInformationRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is Transaction2QueryFileInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFileInformationRequest)subcommand, share, state);
            }
            else if (subcommand is Transaction2SetFileInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2SetFileInformationRequest)subcommand, share, state);
            }
            else if (subcommand is Transaction2CreateDirectoryRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is Transaction2GetDfsReferralRequest)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_DEVICE;
            }
            else
            {
                header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
            }

            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2));
            }

            byte[] responseSetup      = subcommandResponse.GetSetup();
            byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag);
            byte[] responseData       = subcommandResponse.GetData(header.UnicodeFlag);
            return(GetTransactionResponse(true, responseSetup, responseParameters, responseData, state.MaxBufferSize));
        }