static const struct tstream_context_ops tstream_smbXcli_np_ops;
-/*
- * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
- * This is fits into the max_xmit negotiated at the SMB layer.
- *
- * On the sending side they may use SMBtranss if the request does not
- * fit into a single SMBtrans call.
- *
- * Windows uses 1024 as max data size of a SMBtrans request and then
- * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
- * via a SMBreadX.
- *
- * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
- * request to get the whole fragment at once (like samba 3.5.x and below did.
- *
- * It is important that we use do SMBwriteX with the size of a full fragment,
- * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
- * from NT4 servers. (See bug #8195)
- */
-#define TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE 4280
-
#define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
SEC_STD_READ_CONTROL | \
SEC_FILE_READ_DATA | \
struct tstream_smbXcli_np_ref;
struct tstream_smbXcli_np {
- struct tstream_smbXcli_np_ref *ref;
struct smbXcli_conn *conn;
+ struct tstream_smbXcli_np_ref *conn_ref;
struct smbXcli_session *session;
+ struct tstream_smbXcli_np_ref *session_ref;
struct smbXcli_tcon *tcon;
+ struct tstream_smbXcli_np_ref *tcon_ref;
uint16_t pid;
unsigned int timeout;
{
NTSTATUS status;
- if (cli_nps->ref != NULL) {
- cli_nps->ref->cli_nps = NULL;
- TALLOC_FREE(cli_nps->ref);
+ if (cli_nps->conn_ref != NULL) {
+ cli_nps->conn_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->conn_ref);
+ }
+
+ if (cli_nps->session_ref != NULL) {
+ cli_nps->session_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->session_ref);
+ }
+
+ if (cli_nps->tcon_ref != NULL) {
+ cli_nps->tcon_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->tcon_ref);
}
if (!smbXcli_conn_is_connected(cli_nps->conn)) {
* Once we've fixed all callers to call
* tstream_disconnect_send()/_recv(), this will
* never be called.
+ *
+ * We use a maximun timeout of 1 second == 1000 msec.
*/
+ cli_nps->timeout = MIN(cli_nps->timeout, 1000);
+
if (cli_nps->is_smb1) {
status = smb1cli_close(cli_nps->conn,
cli_nps->timeout,
return 0;
}
+ if (ref->cli_nps->conn == NULL) {
+ return 0;
+ }
+
ref->cli_nps->conn = NULL;
ref->cli_nps->session = NULL;
ref->cli_nps->tcon = NULL;
- ref->cli_nps->ref = NULL;
+
+ TALLOC_FREE(ref->cli_nps->conn_ref);
+ TALLOC_FREE(ref->cli_nps->session_ref);
+ TALLOC_FREE(ref->cli_nps->tcon_ref);
return 0;
};
+static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
struct tstream_smbXcli_np_open_state {
struct smbXcli_conn *conn;
struct smbXcli_session *session;
status = smb2cli_create_recv(subreq,
&state->fid_persistent,
&state->fid_volatile,
- NULL);
+ NULL, NULL, NULL);
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
}
ZERO_STRUCTP(cli_nps);
- cli_nps->ref = talloc_zero(state->conn, struct tstream_smbXcli_np_ref);
- if (cli_nps->ref == NULL) {
+ cli_nps->conn_ref = talloc_zero(state->conn,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->conn_ref == NULL) {
TALLOC_FREE(cli_nps);
tevent_req_received(req);
return NT_STATUS_NO_MEMORY;
}
- cli_nps->ref->cli_nps = cli_nps;
+ cli_nps->conn_ref->cli_nps = cli_nps;
+
+ cli_nps->session_ref = talloc_zero(state->session,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->session_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->session_ref->cli_nps = cli_nps;
+
+ cli_nps->tcon_ref = talloc_zero(state->tcon,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->tcon_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->tcon_ref->cli_nps = cli_nps;
+
cli_nps->conn = state->conn;
cli_nps->session = state->session;
cli_nps->tcon = state->tcon;
cli_nps->fid_volatile = state->fid_volatile;
talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
- talloc_set_destructor(cli_nps->ref, tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->conn_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->session_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->tcon_ref,
+ tstream_smbXcli_np_ref_destructor);
cli_nps->trans.active = false;
cli_nps->trans.read_req = NULL;
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
return;
}
return;
}
- if (cli_nps->is_smb1) {
- subreq = smb1cli_close_send(state, state->ev,
- cli_nps->conn,
- cli_nps->timeout,
- cli_nps->pid,
- cli_nps->tcon,
- cli_nps->session,
- cli_nps->fnum, UINT32_MAX);
- } else {
- subreq = smb2cli_close_send(state, state->ev,
- cli_nps->conn,
- cli_nps->timeout,
- cli_nps->session,
- cli_nps->tcon,
- 0, /* flags */
- cli_nps->fid_persistent,
- cli_nps->fid_volatile);
- }
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
if (subreq == NULL) {
/* return the original error */
_tevent_req_error(req, state->error.val, state->error.location);
tevent_req_callback_data(subreq, struct tevent_req);
struct tstream_smbXcli_np_writev_state *state =
tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
- struct tstream_smbXcli_np *cli_nps =
- tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ int error;
- if (cli_nps->is_smb1) {
- smb1cli_close_recv(subreq);
- } else {
- smb2cli_close_recv(subreq);
- }
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
TALLOC_FREE(subreq);
- cli_nps->conn = NULL;
- cli_nps->tcon = NULL;
- cli_nps->session = NULL;
-
/* return the original error */
_tevent_req_error(req, state->error.val, state->error.location);
}
received = out_output_buffer.length;
}
TALLOC_FREE(subreq);
- if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /*
+ * STATUS_BUFFER_OVERFLOW means that there's
+ * more data to read when the named pipe is used
+ * in message mode (which is the case here).
+ *
+ * But we hide this from the caller.
+ */
status = NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(status)) {
- tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
return;
}
cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
if (cli_nps->read.buf == NULL) {
TALLOC_FREE(subreq);
- tevent_req_nomem(cli_nps->read.buf, req);
+ tevent_req_oom(req);
return;
}
memcpy(cli_nps->read.buf, rcvbuf, received);
* We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
* child of that.
*/
- if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
/*
- * NT_STATUS_BUFFER_TOO_SMALL means that there's
+ * STATUS_BUFFER_OVERFLOW means that there's
* more data to read when the named pipe is used
* in message mode (which is the case here).
*
}
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(subreq);
- tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
return;
}
cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
if (cli_nps->read.buf == NULL) {
TALLOC_FREE(subreq);
- tevent_req_nomem(cli_nps->read.buf, req);
+ tevent_req_oom(req);
return;
}
memcpy(cli_nps->read.buf, rcvbuf, received);
return;
}
- if (cli_nps->is_smb1) {
- subreq = smb1cli_close_send(state, state->ev,
- cli_nps->conn,
- cli_nps->timeout,
- cli_nps->pid,
- cli_nps->tcon,
- cli_nps->session,
- cli_nps->fnum, UINT32_MAX);
- } else {
- subreq = smb2cli_close_send(state, state->ev,
- cli_nps->conn,
- cli_nps->timeout,
- cli_nps->session,
- cli_nps->tcon,
- 0, /* flags */
- cli_nps->fid_persistent,
- cli_nps->fid_volatile);
- }
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
if (subreq == NULL) {
/* return the original error */
tstream_smbXcli_np_readv_error(req);
{
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
- struct tstream_smbXcli_np_readv_state *state =
- tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
- struct tstream_smbXcli_np *cli_nps =
- tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ int error;
- if (cli_nps->is_smb1) {
- smb1cli_close_recv(subreq);
- } else {
- smb2cli_close_recv(subreq);
- }
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
TALLOC_FREE(subreq);
- cli_nps->conn = NULL;
- cli_nps->session = NULL;
- cli_nps->tcon = NULL;
-
tstream_smbXcli_np_readv_error(req);
}
struct tstream_smbXcli_np_disconnect_state {
struct tstream_context *stream;
+ struct tevent_req *subreq;
};
static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
+ state->subreq = subreq;
+
+ tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
+
+ /*
+ * Make sure we don't send any requests anymore.
+ */
+ cli_nps->conn = NULL;
return req;
}
tstream_context_data(state->stream, struct tstream_smbXcli_np);
NTSTATUS status;
+ state->subreq = NULL;
+
if (cli_nps->is_smb1) {
status = smb1cli_close_recv(subreq);
} else {
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- tevent_req_error(req, EIO);
+ tevent_req_error(req, EPIPE);
return;
}
tevent_req_done(req);
}
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct tstream_smbXcli_np_disconnect_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
+ struct tstream_smbXcli_np *cli_nps = NULL;
+
+ if (state->subreq == NULL) {
+ return;
+ }
+
+ cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
+
+ if (cli_nps->tcon == NULL) {
+ return;
+ }
+
+ /*
+ * We're no longer interested in the result
+ * any more, but need to make sure that the close
+ * request arrives at the server if the smb connection,
+ * session and tcon are still alive.
+ *
+ * We move the low level request to the tcon,
+ * which means that it stays as long as the tcon
+ * is available.
+ */
+ talloc_steal(cli_nps->tcon, state->subreq);
+ tevent_req_set_callback(state->subreq,
+ tstream_smbXcli_np_disconnect_free,
+ NULL);
+ state->subreq = NULL;
+
+ cli_nps->conn = NULL;
+ cli_nps->session = NULL;
+ cli_nps->tcon = NULL;
+}
+
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
+{
+ TALLOC_FREE(subreq);
+}
+
static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
int *perrno)
{