3.3.5.13 Receiving an SMB2 WRITE Request

When the server receives a request with an SMB2 header with a Command value equal to SMB2 WRITE, message handling proceeds as follows:

The server MUST locate the session, as specified in section 3.3.5.2.9.

The server MUST locate the tree connection, as specified in section 3.3.5.2.11.

Next the server MUST locate the open being written to by performing a lookup in the Session.OpenTable, using FileId.Volatile of the request as the lookup key. If no open is found, or if Open.DurableFileId is not equal to FileId.Persistent, the server MUST fail the request with STATUS_FILE_CLOSED. Otherwise, the server MUST locate the Request in Connection.RequestList for which Request.MessageId matches the MessageId value in the SMB2 Header, and set Request.Open to the Open.

If Open.IsPersistent is FALSE and Open.IsReplayEligible is TRUE, the server MUST set Open.IsReplayEligible to FALSE.

If the range being written to is within the existing file size and Open.GrantedAccess does not include FILE_WRITE_DATA, or if the range being written to extends the file size and Open.GrantedAccess does not include FILE_APPEND_DATA, the server SHOULD<352> fail the request with STATUS_ACCESS_DENIED.

The server SHOULD<353> fail the request with STATUS_INVALID_PARAMETER if the Length field is greater than Connection.MaxWriteSize.

If Connection.Dialect belongs to the SMB 3.x dialect family and if any of the following conditions are TRUE, the server MUST fail the request with STATUS_INVALID_PARAMETER:

  • Connection.Dialect is "3.1.1" and one of the following conditions is TRUE:

    • IsRDMATransformSupported is TRUE and Channel is not equal to SMB2_CHANNEL_RDMA_TRANSFORM, SMB2_CHANNEL_RDMA_V1_INVALIDATE, SMB2_CHANNEL_RDMA_V1, or SMB2_CHANNEL_NONE.

    • Channel is not equal to SMB2_CHANNEL_RDMA_V1_INVALIDATE, SMB2_CHANNEL_RDMA_V1, or SMB2_CHANNEL_NONE.

  • Connection.Dialect is "3.0.2" and Channel is not equal to SMB2_CHANNEL_RDMA_V1_INVALIDATE or SMB2_CHANNEL_RDMA_V1 or SMB2_CHANNEL_NONE.

  • Connection.Dialect is "3.0" and Channel is not equal to SMB2_CHANNEL_RDMA_V1 or SMB2_CHANNEL_NONE.

  • Channel is equal to SMB2_CHANNEL_RDMA_V1, SMB2_CHANNEL_RDMA_V1_INVALIDATE, or SMB2_CHANNEL_RDMA_TRANSFORM and any of the following conditions is TRUE:

    • The underlying Connection is not RDMA.

    • Length or DataOffset are not equal to 0.

    • RemainingBytes, WriteChannelInfoOffset, or WriteChannelInfoLength are equal to 0.

If Channel is equal to SMB2_CHANNEL_NONE and DataOffset is greater than 0x100, the server MUST fail the request with STATUS_INVALID_PARAMETER.

If Channel is equal to SMB2_CHANNEL_NONE and the number of bytes received in Buffer is less than (DataOffset + Length), the server MUST fail the request with STATUS_INVALID_PARAMETER.

If Connection.SupportsMultiCredit is TRUE, the server MUST validate CreditCharge based on Length, as specified in section 3.3.5.2.5. If the validation fails, it MUST fail the write request with STATUS_INVALID_PARAMETER.

If the server implements the SMB 3.x dialect family, and if a write is being executed on a named pipe and the Flags field is set to SMB2_WRITEFLAG_WRITE_UNBUFFERED or SMB2_WRITEFLAG_WRITE_THROUGH, the server MUST fail the request with STATUS_INVALID_PARAMETER.

The server SHOULD<354> ignore undefined bits in the Flags field.

If the server implements the SMB 3.0.2 or SMB 3.1.1 dialect, Connection.Dialect is not "3.0.2" or "3.1.1", and the SMB2_WRITEFLAG_WRITE_UNBUFFERED bit is set in the Flags field, the server MUST ignore the bit.

If Connection.Dialect belongs to the SMB 3.x dialect family and the Channel field contains the value SMB2_CHANNEL_RDMA_V1, SMB2_CHANNEL_RDMA_V1_INVALIDATE, or SMB2_CHANNEL_RDMA_TRANSFORM, the server MUST do the following:

  • If Connection.Dialect is "3.1.1" and Channel is equal to SMB2_CHANNEL_RDMA_TRANSFORM, the server MUST return STATUS_INVALID_PARAMETER to the client in the following conditions:

    • Connection.RDMATransformIds is empty.

    • WriteChannelInfoLength is less than the size of SMB2_RDMA_TRANSFORM structure.

    • TransformCount is 0 in SMB2_RDMA_TRANSFORM structure.

    • Connection.RDMATransformIds does not contain SMB2_RDMA_TRANSFORM_ENCRYPTION, and SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION is present.

    • Connection.RDMATransformIds does not contain SMB2_RDMA_TRANSFORM_SIGNING, and SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_SIGNING is present.

    • SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION is present and Request.IsEncrypted is FALSE.

    • More than one SMB2_RDMA_CRYPTO_TRANSFORM structures with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION or SMB2_RDMA_TRANSFORM_TYPE_SIGNING are present.

    • More than one SMB2_RDMA_CRYPTO_TRANSFORM structures with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION are present.

    • Two SMB2_RDMA_CRYPTO_TRANSFORM structures with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION and SMB2_RDMA_TRANSFORM_TYPE_SIGNING are present.

    • SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_SIGNING is present and SMB2_FLAGS_SIGNED bit is not set in the Flags field of the SMB2 header.

    • An array of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures does not begin at the first 8-byte aligned offset after SMB2_RDMA_CRYPTO_TRANSFORM structure from the beginning of the Buffer field.

    • SMB2_RDMA_TRANSFORM structure is followed by a transform not specified in section 2.2.43.

  • The server MUST return STATUS_INVALID_PARAMETER to the client in the following conditions:

    • RemainingBytes field is greater than Connection.MaxWriteSize.

    • Length field of the first SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structure is zero.

    • Sum of the values of Length fields in all SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures is less than RemainingBytes.

  • If Channel is equal to SMB2_CHANNEL_RDMA_TRANSFORM, Connection.RDMATransformIds includes SMB2_RDMA_TRANSFORM_ENCRYPTION, and SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION is present, the data MUST first be obtained via the processing specified in [MS-SMBD] section 3.1.4.6, providing the Connection, a newly allocated buffer to receive the data, and the array of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures passed in the request at offset RdmaDescriptorOffset and of length RdmaDescriptorLength fields of SMB2_RDMA_TRANSFORM structure.

    • The server MUST fail the request with STATUS_AUTH_TAG_MISMATCH if one of the following is TRUE:

      • SignatureLength field is greater than 16.

      • Connection.CipherId is AES-128-CCM or AES-256-CCM and NonceLength field is not equal to 11.

      • Connection.CipherId is AES-128-GCM or AES-256-GCM and NonceLength field is not equal to 12.

    • The data obtained MUST be decrypted using the algorithm specified in Connection.CipherId and Session.DecryptionKey by passing encrypted data and Signature and Nonce, from the received SMB2_RDMA_CRYPTO_TRANSFORM structure. If the size of the decrypted data is not equal to RemainingBytes field in the request, the server MUST fail the request with STATUS_BAD_DATA.

    • If Channel is equal to SMB2_CHANNEL_RDMA_TRANSFORM, Connection.RDMATransformIds includes SMB2_RDMA_TRANSFORM_SIGNING, and SMB2_RDMA_CRYPTO_TRANSFORM with TransformType equal to SMB2_RDMA_TRANSFORM_TYPE_SIGNING is present, the data MUST first be obtained via the processing specified in [MS-SMBD] section 3.1.4.6, providing the Connection, a newly allocated buffer to receive the data, and the array of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures passed in the request at offset RdmaDescriptorOffset and of length RdmaDescriptorLength fields of SMB2_RDMA_TRANSFORM structure. The server MUST verify the received data as specified in section 3.1.5.1 except that the computed signature is compared with the value in Signature field of SMB2_RDMA_CRYPTO_TRANSFORM. If the signature verification fails, the server MUST fail the request with STATUS_INVALID_SIGNATURE.

  • Otherwise, the data MUST be first obtained via the processing specified in [MS-SMBD] section 3.1.4.6, providing the Connection, a newly allocated buffer to receive the data, and the array of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures passed in the request at offset WriteChannelInfoOffset and of length WriteChannelInfoLength fields.

If Connection.Dialect is "3.0.2" or "3.1.1", SMB2_WRITEFLAG_WRITE_THROUGH is set in the Flags field of the request, SMB2_WRITEFLAG_WRITE_UNBUFFERED is not set in the Flags field of the request, and Open.CreateOptions doesn't include the FILE_NO_INTERMEDIATE_BUFFERING bit, the server MUST fail the request with STATUS_INVALID_PARAMETER.

If Connection.Dialect is "2.1" or "3.0", SMB2_WRITEFLAG_WRITE_THROUGH is set in the Flags field of the request, and Open.CreateOptions doesn't include the FILE_NO_INTERMEDIATE_BUFFERING bit, the server MUST fail the request with STATUS_INVALID_PARAMETER.

The server MUST issue a write to the underlying object store represented by Open.LocalOpen for the length, in bytes, given by Length, at the offset, in bytes, from the beginning of the file, provided in Offset. If Connection.Dialect is not "2.0.2", and SMB2_WRITEFLAG_WRITE_THROUGH is set in the Flags field of the SMB2 WRITE Request, the server SHOULD<355> indicate to the underlying object store that the write is to be written to underlying storage before completion is returned. If the server implements the SMB 3.0.2 or SMB 3.1.1 dialect, and if the SMB2_WRITEFLAG_WRITE_UNBUFFERED bit is set in the Flags field of the request, the server SHOULD indicate to the underlying object store that the write data is not to be buffered.

If the write is being executed on a named pipe, and the pipe is in blocking mode (the default), the operation could block for a long time, so the server MAY<356> choose to handle it asynchronously, as specified in section 3.3.4.2. To query a pipe's blocking mode, use the FilePipeInformation file information class, as specified in [MS-FSCC] section 2.4.32. To change a pipe's blocking mode, use an SMB2 SET_INFO Request with the FilePipeInformation file information class, as specified in [MS-FSCC] section 2.4.32.

If the write fails, the server MUST fail the request with the error code received from the write.

If the write succeeds, the server MUST construct a write response following the syntax specified in section 2.2.22 with the following values:

  • Count MUST be set to the number of bytes written.

  • Remaining MUST be set to zero.

  • WriteChannelInfoOffset MUST be set to zero.

  • WriteChannelInfoLength MUST be set to zero.

The response MUST then be sent to the client.

The Token in the first element of the array of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures passed in the request MUST additionally be supplied, as specified in [MS-SMBD] section 3.1.4.2, if any of the following conditions is TRUE:

  • Channel field in the request is equal to SMB2_CHANNEL_RDMA_TRANSFORM, and the Channel field in SMB2_RDMA_TRANSFORM structure is equal to SMB2_CHANNEL_RDMA_V1_INVALIDATE.

  • Channel field in the request is equal to SMB2_CHANNEL_RDMA_V1_INVALIDATE.

The status code returned by this operation MUST be one of those defined in [MS-ERREF]. Common status codes returned by this operation include:

  • STATUS_SUCCESS

  • STATUS_INSUFFICIENT_RESOURCES

  • STATUS_ACCESS_DENIED

  • STATUS_FILE_CLOSED

  • STATUS_NETWORK_NAME_DELETED

  • STATUS_USER_SESSION_DELETED

  • STATUS_NETWORK_SESSION_EXPIRED

  • STATUS_INVALID_PARAMETER

  • STATUS_PIPE_BROKEN

  • STATUS_DISK_FULL

  • STATUS_CANCELLED

  • STATUS_FILE_LOCK_CONFLICT