create a transport structure based on an established socket
*/
struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
- TALLOC_CTX *parent_ctx)
+ TALLOC_CTX *parent_ctx,
+ struct smbcli_options *options)
{
struct smb2_transport *transport;
if (!transport) return NULL;
transport->socket = talloc_steal(transport, sock);
+ transport->options = *options;
/* setup the stream -> packet parser */
transport->packet = packet_init(transport);
talloc_set_destructor(transport, transport_destructor);
- transport->options.timeout = 30;
-
return transport;
}
}
}
-static bool smb2_handle_oplock_break(struct smb2_transport *transport,
- const DATA_BLOB *blob)
+static NTSTATUS smb2_handle_oplock_break(struct smb2_transport *transport,
+ const DATA_BLOB *blob)
{
uint8_t *hdr;
uint16_t opcode;
- uint64_t seqnum;
hdr = blob->data+NBT_HDR_SIZE;
if (blob->length < (SMB2_MIN_SIZE+0x18)) {
DEBUG(1,("Discarding smb2 oplock reply of size %u\n",
- blob->length));
- return false;
+ (unsigned)blob->length));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
opcode = SVAL(hdr, SMB2_HDR_OPCODE);
- seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
- if ((opcode != SMB2_OP_BREAK) ||
- (seqnum != UINT64_MAX)) {
- return false;
+ if (opcode != SMB2_OP_BREAK) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (transport->oplock.handler) {
transport->oplock.handler(transport, &h, level,
transport->oplock.private_data);
+ } else {
+ DEBUG(5,("Got SMB2 oplock break with no handler\n"));
}
- return true;
+ return NT_STATUS_OK;
}
/*
uint16_t buffer_code;
uint32_t dynamic_size;
uint32_t i;
+ NTSTATUS status;
buffer = blob.data;
len = blob.length;
goto error;
}
- if (smb2_handle_oplock_break(transport, &blob)) {
- talloc_free(buffer);
- return NT_STATUS_OK;
- }
-
flags = IVAL(hdr, SMB2_HDR_FLAGS);
seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
+ /* see MS-SMB2 3.2.5.19 */
+ if (seqnum == UINT64_MAX) {
+ return smb2_handle_oplock_break(transport, &blob);
+ }
+
/* match the incoming request against the list of pending requests */
for (req=transport->pending_recv; req; req=req->next) {
if (req->seqnum == seqnum) break;
req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
+ if (transport->signing.signing_started &&
+ transport->signing.doing_signing) {
+ status = smb2_check_signature(&req->in,
+ transport->signing.session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* the spec says to ignore packets with a bad signature */
+ talloc_free(buffer);
+ return status;
+ }
+ }
+
+
if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
if (flags & 0x00000002) {
req->cancel.can_cancel = true;
return;
}
+ /* possibly sign the message */
+ if (req->transport->signing.doing_signing &&
+ req->transport->signing.signing_started) {
+ status = smb2_sign_message(&req->out, req->transport->signing.session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ req->state = SMB2_REQUEST_ERROR;
+ req->status = status;
+ return;
+ }
+ }
+
blob = data_blob_const(req->out.buffer, req->out.size);
status = packet_send(req->transport->packet, blob);
if (!NT_STATUS_IS_OK(status)) {
DLIST_ADD(req->transport->pending_recv, req);
/* add a timeout */
- if (req->transport->options.timeout) {
+ if (req->transport->options.request_timeout) {
event_add_timed(req->transport->socket->event.ctx, req,
- timeval_current_ofs(req->transport->options.timeout, 0),
+ timeval_current_ofs(req->transport->options.request_timeout, 0),
smb2_timeout_handler, req);
}