summaryrefslogtreecommitdiff
path: root/source4/libcli/smb_composite
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2008-05-23 15:24:40 +0200
committerJelmer Vernooij <jelmer@samba.org>2008-05-23 15:24:40 +0200
commit7fb26774021986a08d03db968a7826ee64ea7410 (patch)
tree272d8e4f7671b48c95c817724b41d9c27de1e282 /source4/libcli/smb_composite
parentfd01b27edd5a83306f4ce567e31d43641dd003b8 (diff)
parent1186579f94d81bc633b8f20e8ad8673313c8c39b (diff)
downloadsamba-7fb26774021986a08d03db968a7826ee64ea7410.tar.gz
samba-7fb26774021986a08d03db968a7826ee64ea7410.tar.bz2
samba-7fb26774021986a08d03db968a7826ee64ea7410.zip
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into registry
(This used to be commit e8d96b61db1cddc2d8dca45e6e9b53d5c31ee5d4)
Diffstat (limited to 'source4/libcli/smb_composite')
-rw-r--r--source4/libcli/smb_composite/connect.c89
-rw-r--r--source4/libcli/smb_composite/fetchfile.c2
-rw-r--r--source4/libcli/smb_composite/fsinfo.c2
-rw-r--r--source4/libcli/smb_composite/sesssetup.c2
-rw-r--r--source4/libcli/smb_composite/smb2.c371
-rw-r--r--source4/libcli/smb_composite/smb_composite.h5
6 files changed, 424 insertions, 47 deletions
diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c
index c44c62f868..e56339f96b 100644
--- a/source4/libcli/smb_composite/connect.c
+++ b/source4/libcli/smb_composite/connect.c
@@ -38,7 +38,9 @@ enum connect_stage {CONNECT_RESOLVE,
CONNECT_NEGPROT,
CONNECT_SESSION_SETUP,
CONNECT_SESSION_SETUP_ANON,
- CONNECT_TCON};
+ CONNECT_TCON,
+ CONNECT_DONE
+};
struct connect_state {
enum connect_stage stage;
@@ -57,25 +59,6 @@ static void request_handler(struct smbcli_request *);
static void composite_handler(struct composite_context *);
/*
- setup a negprot send
-*/
-static NTSTATUS connect_send_negprot(struct composite_context *c,
- struct smb_composite_connect *io)
-{
- struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
-
- state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol);
- NT_STATUS_HAVE_NO_MEMORY(state->req);
-
- state->req->async.fn = request_handler;
- state->req->async.private = c;
- state->stage = CONNECT_NEGPROT;
-
- return NT_STATUS_OK;
-}
-
-
-/*
a tree connect request has completed
*/
static NTSTATUS connect_tcon(struct composite_context *c,
@@ -97,8 +80,7 @@ static NTSTATUS connect_tcon(struct composite_context *c,
state->io_tcon->tconx.out.fs_type);
}
- /* all done! */
- c->state = COMPOSITE_STATE_DONE;
+ state->stage = CONNECT_DONE;
return NT_STATUS_OK;
}
@@ -121,9 +103,6 @@ static NTSTATUS connect_session_setup_anon(struct composite_context *c,
state->session->vuid = state->io_setup->out.vuid;
/* setup for a tconx */
- io->out.tree = smbcli_tree_init(state->session, state, true);
- NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
-
state->io_tcon = talloc(c, union smb_tcon);
NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
@@ -203,9 +182,12 @@ static NTSTATUS connect_session_setup(struct composite_context *c,
state->session->vuid = state->io_setup->out.vuid;
- /* setup for a tconx */
- io->out.tree = smbcli_tree_init(state->session, state, true);
- NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
+ /* If we don't have a remote share name then this indicates that
+ * we don't want to do a tree connect */
+ if (!io->in.service) {
+ state->stage = CONNECT_DONE;
+ return NT_STATUS_OK;
+ }
state->io_tcon = talloc(c, union smb_tcon);
NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
@@ -254,6 +236,18 @@ static NTSTATUS connect_negprot(struct composite_context *c,
/* next step is a session setup */
state->session = smbcli_session_init(state->transport, state, true);
NT_STATUS_HAVE_NO_MEMORY(state->session);
+
+ /* setup for a tconx (or at least have the structure ready to
+ * return, if we won't go that far) */
+ io->out.tree = smbcli_tree_init(state->session, state, true);
+ NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
+
+ /* If we don't have any credentials then this indicates that
+ * we don't want to do a session setup */
+ if (!io->in.credentials) {
+ state->stage = CONNECT_DONE;
+ return NT_STATUS_OK;
+ }
state->io_setup = talloc(c, struct smb_composite_sesssetup);
NT_STATUS_HAVE_NO_MEMORY(state->io_setup);
@@ -272,11 +266,30 @@ static NTSTATUS connect_negprot(struct composite_context *c,
state->creq->async.fn = composite_handler;
state->creq->async.private_data = c;
+
state->stage = CONNECT_SESSION_SETUP;
return NT_STATUS_OK;
}
+/*
+ setup a negprot send
+*/
+static NTSTATUS connect_send_negprot(struct composite_context *c,
+ struct smb_composite_connect *io)
+{
+ struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
+
+ state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol);
+ NT_STATUS_HAVE_NO_MEMORY(state->req);
+
+ state->req->async.fn = request_handler;
+ state->req->async.private = c;
+ state->stage = CONNECT_NEGPROT;
+
+ return NT_STATUS_OK;
+}
+
/*
a session request operation has completed
@@ -405,13 +418,11 @@ static void state_handler(struct composite_context *c)
break;
}
- if (!NT_STATUS_IS_OK(c->status)) {
- c->state = COMPOSITE_STATE_ERROR;
- }
-
- if (c->state >= COMPOSITE_STATE_DONE &&
- c->async.fn) {
- c->async.fn(c);
+ if (state->stage == CONNECT_DONE) {
+ /* all done! */
+ composite_done(c);
+ } else {
+ composite_is_ok(c);
}
}
@@ -451,17 +462,15 @@ struct composite_context *smb_composite_connect_send(struct smb_composite_connec
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) goto failed;
+ c->event_ctx = talloc_reference(c, event_ctx);
+ if (c->event_ctx == NULL) goto failed;
+
state = talloc_zero(c, struct connect_state);
if (state == NULL) goto failed;
- if (event_ctx == NULL) {
- event_ctx = event_context_init(mem_ctx);
- }
-
state->io = io;
c->state = COMPOSITE_STATE_IN_PROGRESS;
- c->event_ctx = talloc_reference(c, event_ctx);
c->private_data = state;
state->stage = CONNECT_RESOLVE;
diff --git a/source4/libcli/smb_composite/fetchfile.c b/source4/libcli/smb_composite/fetchfile.c
index d8d7481270..9cd02a51f4 100644
--- a/source4/libcli/smb_composite/fetchfile.c
+++ b/source4/libcli/smb_composite/fetchfile.c
@@ -62,7 +62,6 @@ static NTSTATUS fetchfile_connect(struct composite_context *c,
state->creq->async.fn = fetchfile_composite_handler;
state->stage = FETCHFILE_READ;
- c->event_ctx = talloc_reference(c, state->creq->event_ctx);
return NT_STATUS_OK;
}
@@ -158,7 +157,6 @@ struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetc
c->state = COMPOSITE_STATE_IN_PROGRESS;
state->stage = FETCHFILE_CONNECT;
- c->event_ctx = talloc_reference(c, state->creq->event_ctx);
c->private_data = state;
return c;
diff --git a/source4/libcli/smb_composite/fsinfo.c b/source4/libcli/smb_composite/fsinfo.c
index 2ec13df9b6..270d71f518 100644
--- a/source4/libcli/smb_composite/fsinfo.c
+++ b/source4/libcli/smb_composite/fsinfo.c
@@ -52,7 +52,6 @@ static NTSTATUS fsinfo_connect(struct composite_context *c,
state->req->async.fn = fsinfo_raw_handler;
state->stage = FSINFO_QUERY;
- c->event_ctx = talloc_reference(c, state->req->session->transport->socket->event.ctx);
return NT_STATUS_OK;
}
@@ -158,7 +157,6 @@ struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree,
c->state = COMPOSITE_STATE_IN_PROGRESS;
state->stage = FSINFO_CONNECT;
- c->event_ctx = talloc_reference(c, tree->session->transport->socket->event.ctx);
c->private_data = state;
state->creq = smb_composite_connect_send(state->connect, state,
diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c
index 1427fe525b..11ac37e257 100644
--- a/source4/libcli/smb_composite/sesssetup.c
+++ b/source4/libcli/smb_composite/sesssetup.c
@@ -224,7 +224,6 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
{
NTSTATUS nt_status;
struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
- const char *password = cli_credentials_get_password(io->in.credentials);
DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, lp_iconv_convenience(global_loadparm), session->transport->socket->hostname, lp_workgroup(global_loadparm));
DATA_BLOB session_key;
int flags = CLI_CRED_NTLM_AUTH;
@@ -266,6 +265,7 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
data_blob_free(&session_key);
} else if (session->options.plaintext_auth) {
+ const char *password = cli_credentials_get_password(io->in.credentials);
state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password));
state->setup.nt1.in.password2 = data_blob(NULL, 0);
} else {
diff --git a/source4/libcli/smb_composite/smb2.c b/source4/libcli/smb_composite/smb2.c
new file mode 100644
index 0000000000..6e005e03c0
--- /dev/null
+++ b/source4/libcli/smb_composite/smb2.c
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ a composite API for making SMB-like calls using SMB2. This is useful
+ as SMB2 often requires more than one requests where a single SMB
+ request would do. In converting code that uses SMB to use SMB2,
+ these routines make life a lot easier
+*/
+
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "param/param.h"
+#include "libcli/smb2/smb2_calls.h"
+
+/*
+ continue after a SMB2 close
+ */
+static void continue_close(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ NTSTATUS status;
+ struct smb2_close close_parm;
+
+ status = smb2_close_recv(req, &close_parm);
+ composite_error(ctx, status);
+}
+
+/*
+ continue after the create in a composite unlink
+ */
+static void continue_unlink(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct smb2_tree *tree = req->tree;
+ struct smb2_create create_parm;
+ struct smb2_close close_parm;
+ NTSTATUS status;
+
+ status = smb2_create_recv(req, ctx, &create_parm);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(ctx, status);
+ return;
+ }
+
+ ZERO_STRUCT(close_parm);
+ close_parm.in.file.handle = create_parm.out.file.handle;
+
+ req = smb2_close_send(tree, &close_parm);
+ composite_continue_smb2(ctx, req, continue_close, ctx);
+}
+
+/*
+ composite SMB2 unlink call
+*/
+struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree,
+ union smb_unlink *io)
+{
+ struct composite_context *ctx;
+ struct smb2_create create_parm;
+ struct smb2_request *req;
+
+ ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
+ if (ctx == NULL) return NULL;
+
+ /* check for wildcards - we could support these with a
+ search, but for now they aren't necessary */
+ if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
+ composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
+ return ctx;
+ }
+
+ ZERO_STRUCT(create_parm);
+ create_parm.in.desired_access = SEC_STD_DELETE;
+ create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_parm.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create_parm.in.create_options =
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ create_parm.in.fname = io->unlink.in.pattern;
+ if (create_parm.in.fname[0] == '\\') {
+ create_parm.in.fname++;
+ }
+
+ req = smb2_create_send(tree, &create_parm);
+
+ composite_continue_smb2(ctx, req, continue_unlink, ctx);
+ return ctx;
+}
+
+
+/*
+ composite unlink call - sync interface
+*/
+NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
+{
+ struct composite_context *c = smb2_composite_unlink_send(tree, io);
+ return composite_wait_free(c);
+}
+
+
+
+
+/*
+ continue after the create in a composite mkdir
+ */
+static void continue_mkdir(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct smb2_tree *tree = req->tree;
+ struct smb2_create create_parm;
+ struct smb2_close close_parm;
+ NTSTATUS status;
+
+ status = smb2_create_recv(req, ctx, &create_parm);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(ctx, status);
+ return;
+ }
+
+ ZERO_STRUCT(close_parm);
+ close_parm.in.file.handle = create_parm.out.file.handle;
+
+ req = smb2_close_send(tree, &close_parm);
+ composite_continue_smb2(ctx, req, continue_close, ctx);
+}
+
+/*
+ composite SMB2 mkdir call
+*/
+struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree,
+ union smb_mkdir *io)
+{
+ struct composite_context *ctx;
+ struct smb2_create create_parm;
+ struct smb2_request *req;
+
+ ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
+ if (ctx == NULL) return NULL;
+
+ ZERO_STRUCT(create_parm);
+
+ create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ create_parm.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create_parm.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create_parm.in.fname = io->mkdir.in.path;
+ if (create_parm.in.fname[0] == '\\') {
+ create_parm.in.fname++;
+ }
+
+ req = smb2_create_send(tree, &create_parm);
+
+ composite_continue_smb2(ctx, req, continue_mkdir, ctx);
+
+ return ctx;
+}
+
+
+/*
+ composite mkdir call - sync interface
+*/
+NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
+{
+ struct composite_context *c = smb2_composite_mkdir_send(tree, io);
+ return composite_wait_free(c);
+}
+
+
+
+/*
+ continue after the create in a composite rmdir
+ */
+static void continue_rmdir(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct smb2_tree *tree = req->tree;
+ struct smb2_create create_parm;
+ struct smb2_close close_parm;
+ NTSTATUS status;
+
+ status = smb2_create_recv(req, ctx, &create_parm);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(ctx, status);
+ return;
+ }
+
+ ZERO_STRUCT(close_parm);
+ close_parm.in.file.handle = create_parm.out.file.handle;
+
+ req = smb2_close_send(tree, &close_parm);
+ composite_continue_smb2(ctx, req, continue_close, ctx);
+}
+
+/*
+ composite SMB2 rmdir call
+*/
+struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree,
+ struct smb_rmdir *io)
+{
+ struct composite_context *ctx;
+ struct smb2_create create_parm;
+ struct smb2_request *req;
+
+ ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
+ if (ctx == NULL) return NULL;
+
+ ZERO_STRUCT(create_parm);
+ create_parm.in.desired_access = SEC_STD_DELETE;
+ create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_parm.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create_parm.in.create_options =
+ NTCREATEX_OPTIONS_DIRECTORY |
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ create_parm.in.fname = io->in.path;
+ if (create_parm.in.fname[0] == '\\') {
+ create_parm.in.fname++;
+ }
+
+ req = smb2_create_send(tree, &create_parm);
+
+ composite_continue_smb2(ctx, req, continue_rmdir, ctx);
+ return ctx;
+}
+
+
+/*
+ composite rmdir call - sync interface
+*/
+NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
+{
+ struct composite_context *c = smb2_composite_rmdir_send(tree, io);
+ return composite_wait_free(c);
+}
+
+
+/*
+ continue after the setfileinfo in a composite setpathinfo
+ */
+static void continue_setpathinfo_close(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct smb2_tree *tree = req->tree;
+ struct smb2_close close_parm;
+ NTSTATUS status;
+ union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data,
+ union smb_setfileinfo);
+
+ status = smb2_setinfo_recv(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(ctx, status);
+ return;
+ }
+
+ ZERO_STRUCT(close_parm);
+ close_parm.in.file.handle = io2->generic.in.file.handle;
+
+ req = smb2_close_send(tree, &close_parm);
+ composite_continue_smb2(ctx, req, continue_close, ctx);
+}
+
+
+/*
+ continue after the create in a composite setpathinfo
+ */
+static void continue_setpathinfo(struct smb2_request *req)
+{
+ struct composite_context *ctx = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct smb2_tree *tree = req->tree;
+ struct smb2_create create_parm;
+ NTSTATUS status;
+ union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data,
+ union smb_setfileinfo);
+
+ status = smb2_create_recv(req, ctx, &create_parm);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(ctx, status);
+ return;
+ }
+
+ io2->generic.in.file.handle = create_parm.out.file.handle;
+
+ req = smb2_setinfo_file_send(tree, io2);
+ composite_continue_smb2(ctx, req, continue_setpathinfo_close, ctx);
+}
+
+
+/*
+ composite SMB2 setpathinfo call
+*/
+struct composite_context *smb2_composite_setpathinfo_send(struct smb2_tree *tree,
+ union smb_setfileinfo *io)
+{
+ struct composite_context *ctx;
+ struct smb2_create create_parm;
+ struct smb2_request *req;
+ union smb_setfileinfo *io2;
+
+ ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
+ if (ctx == NULL) return NULL;
+
+ ZERO_STRUCT(create_parm);
+ create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_parm.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create_parm.in.create_options = 0;
+ create_parm.in.fname = io->generic.in.file.path;
+ if (create_parm.in.fname[0] == '\\') {
+ create_parm.in.fname++;
+ }
+
+ req = smb2_create_send(tree, &create_parm);
+
+ io2 = talloc(ctx, union smb_setfileinfo);
+ if (composite_nomem(io2, ctx)) {
+ return ctx;
+ }
+ *io2 = *io;
+
+ ctx->private_data = io2;
+
+ composite_continue_smb2(ctx, req, continue_setpathinfo, ctx);
+ return ctx;
+}
+
+
+/*
+ composite setpathinfo call
+ */
+NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io)
+{
+ struct composite_context *c = smb2_composite_setpathinfo_send(tree, io);
+ return composite_wait_free(c);
+}
diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h
index e7e131869c..7f4b9d73e4 100644
--- a/source4/libcli/smb_composite/smb_composite.h
+++ b/source4/libcli/smb_composite/smb_composite.h
@@ -29,6 +29,7 @@
#include "libcli/raw/signing.h"
#include "libcli/raw/libcliraw.h"
+#include "libcli/smb2/smb2.h"
/*
@@ -83,8 +84,8 @@ struct smb_composite_savefile {
- socket establishment
- session request
- negprot
- - session setup
- - tree connect
+ - session setup (if credentials are not NULL)
+ - tree connect (if service is not NULL)
*/
struct smb_composite_connect {
struct {