TODO s4:libcli/smb2: don't schedule idle handlers on a dead connection
[metze/samba/wip.git] / source4 / libcli / smb2 / transport.c
index 01f363b0a09c0c301f0129f376f011a4dda3baea..b501b52ce51843e894c96f39cd8d1d61f4e7fd3d 100644 (file)
@@ -27,9 +27,9 @@
 #include "libcli/smb2/smb2_calls.h"
 #include "lib/socket/socket.h"
 #include "lib/events/events.h"
-#include "lib/stream/packet.h"
 #include "../lib/util/dlinklist.h"
 #include "../libcli/smb/smbXcli_base.h"
+#include "librpc/ndr/libndr.h"
 
 /*
   destroy a transport
@@ -55,6 +55,14 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
        transport->ev = sock->event.ctx;
        transport->options = *options;
 
+       if (transport->options.max_protocol == PROTOCOL_DEFAULT) {
+               transport->options.max_protocol = PROTOCOL_LATEST;
+       }
+
+       if (transport->options.max_protocol < PROTOCOL_SMB2_02) {
+               transport->options.max_protocol = PROTOCOL_LATEST;
+       }
+
        TALLOC_FREE(sock->event.fde);
        TALLOC_FREE(sock->event.te);
 
@@ -63,7 +71,8 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
                                              sock->hostname,
                                              options->signing,
                                              0, /* smb1_capabilities */
-                                             NULL); /* client_guid */
+                                             &options->client_guid,
+                                             options->smb2_capabilities);
        if (transport->conn == NULL) {
                talloc_free(transport);
                return NULL;
@@ -107,8 +116,7 @@ void smb2_transport_send(struct smb2_request *req)
        uint16_t cmd = SVAL(req->out.hdr, SMB2_HDR_OPCODE);
        uint32_t additional_flags = IVAL(req->out.hdr, SMB2_HDR_FLAGS);
        uint32_t clear_flags = 0;
-       uint32_t pid = IVAL(req->out.hdr, SMB2_HDR_PID);
-       uint32_t tid = IVAL(req->out.hdr, SMB2_HDR_TID);
+       struct smbXcli_tcon *tcon = NULL;
        struct smbXcli_session *session = NULL;
        bool need_pending_break = false;
        size_t hdr_ofs;
@@ -139,13 +147,13 @@ void smb2_transport_send(struct smb2_request *req)
                                            0, /* additional_flags */
                                            0, /*clear_flags */
                                            0, /* timeout_msec */
-                                           0, /* pid */
-                                           0, /* tid */
+                                           NULL, /* tcon */
                                            NULL, /* session */
                                            NULL, /* body */
                                            0, /* body_fixed */
                                            NULL, /* dyn */
-                                           0); /* dyn_len */
+                                           0, /* dyn_len */
+                                           0); /* max_dyn_len */
                if (subreq != NULL) {
                        smbXcli_req_set_pending(subreq);
                        tevent_req_set_callback(subreq,
@@ -159,6 +167,10 @@ void smb2_transport_send(struct smb2_request *req)
                session = req->session->smbXcli;
        }
 
+       if (req->tree) {
+               tcon = req->tree->smbXcli;
+       }
+
        if (transport->compound.related) {
                additional_flags |= SMB2_HDR_FLAG_CHAINED;
        }
@@ -177,11 +189,11 @@ void smb2_transport_send(struct smb2_request *req)
                                         additional_flags,
                                         clear_flags,
                                         timeout_msec,
-                                        pid,
-                                        tid,
+                                        tcon,
                                         session,
                                         body.data, body.length,
-                                        dyn.data, dyn.length);
+                                        dyn.data, dyn.length,
+                                        0); /* max_dyn_len */
        if (req->subreq == NULL) {
                req->state = SMB2_REQUEST_ERROR;
                req->status = NT_STATUS_NO_MEMORY;
@@ -225,8 +237,11 @@ void smb2_transport_send(struct smb2_request *req)
        status = smb2cli_req_compound_submit(reqs, num_reqs);
 
        TALLOC_FREE(transport->compound.reqs);
+       transport->compound.related = false;
 
        if (!NT_STATUS_IS_OK(status)) {
+               req->status = status;
+               req->state = SMB2_REQUEST_ERROR;
                smbXcli_conn_disconnect(transport->conn, status);
        }
 }
@@ -304,7 +319,6 @@ static void smb2_transport_break_handler(struct tevent_req *subreq)
                tevent_req_callback_data(subreq,
                struct smb2_transport);
        NTSTATUS status;
-       uint8_t *hdr;
        uint8_t *body;
        uint16_t len = 0;
        bool lease;
@@ -331,13 +345,13 @@ static void smb2_transport_break_handler(struct tevent_req *subreq)
                                    0, /* additional_flags */
                                    0, /*clear_flags */
                                    0, /* timeout_msec */
-                                   0, /* pid */
-                                   0, /* tid */
+                                   NULL, /* tcon */
                                    NULL, /* session */
                                    NULL, /* body */
                                    0, /* body_fixed */
                                    NULL, /* dyn */
-                                   0); /* dyn_len */
+                                   0, /* dyn_len */
+                                   0); /* max_dyn_len */
        if (subreq != NULL) {
                smbXcli_req_set_pending(subreq);
                tevent_req_set_callback(subreq,
@@ -346,7 +360,6 @@ static void smb2_transport_break_handler(struct tevent_req *subreq)
                transport->break_subreq = subreq;
        }
 
-       hdr = recv_iov[0].iov_base;
        body = recv_iov[1].iov_base;
 
        len = recv_iov[1].iov_len;
@@ -385,6 +398,7 @@ static void smb2_transport_break_handler(struct tevent_req *subreq)
                struct smb2_lease_break lb;
 
                ZERO_STRUCT(lb);
+               lb.new_epoch =                  SVAL(body, 0x2);
                lb.break_flags =                SVAL(body, 0x4);
                memcpy(&lb.current_lease.lease_key, body+0x8,
                    sizeof(struct smb2_lease_key));
@@ -438,12 +452,24 @@ static void idle_handler(struct tevent_context *ev,
 {
        struct smb2_transport *transport = talloc_get_type(private_data,
                                                           struct smb2_transport);
-       struct timeval next = timeval_add(&t, 0, transport->idle.period);
-       tevent_add_timer(transport->ev,
-                        transport,
-                        next,
-                        idle_handler, transport);
+       struct timeval next;
+
        transport->idle.func(transport, transport->idle.private_data);
+
+       if (transport->idle.func == NULL) {
+               return;
+       }
+
+       if (!smbXcli_conn_is_connected(transport->conn)) {
+               return;
+       }
+
+       next = timeval_current_ofs_usec(transport->idle.period);
+       transport->idle.te = tevent_add_timer(transport->ev,
+                                             transport,
+                                             next,
+                                             idle_handler,
+                                             transport);
 }
 
 /*
@@ -455,12 +481,24 @@ void smb2_transport_idle_handler(struct smb2_transport *transport,
                                 uint64_t period,
                                 void *private_data)
 {
+       TALLOC_FREE(transport->idle.te);
+       ZERO_STRUCT(transport->idle);
+
+       if (idle_func == NULL) {
+               return;
+       }
+
+       if (!smbXcli_conn_is_connected(transport->conn)) {
+               return;
+       }
+
        transport->idle.func = idle_func;
        transport->idle.private_data = private_data;
        transport->idle.period = period;
 
-       tevent_add_timer(transport->ev,
-                        transport,
-                        timeval_current_ofs(0, period),
-                        idle_handler, transport);
+       transport->idle.te = tevent_add_timer(transport->ev,
+                                             transport,
+                                             timeval_current_ofs_usec(period),
+                                             idle_handler,
+                                             transport);
 }