wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
|
||||
/* the stages of this call */
|
||||
enum appendacl_stage {APPENDACL_OPENPATH, APPENDACL_GET,
|
||||
APPENDACL_SET, APPENDACL_GETAGAIN, APPENDACL_CLOSEPATH};
|
||||
|
||||
static void appendacl_handler(struct smbcli_request *req);
|
||||
|
||||
struct appendacl_state {
|
||||
enum appendacl_stage stage;
|
||||
struct smb_composite_appendacl *io;
|
||||
|
||||
union smb_open *io_open;
|
||||
union smb_setfileinfo *io_setfileinfo;
|
||||
union smb_fileinfo *io_fileinfo;
|
||||
|
||||
struct smbcli_request *req;
|
||||
};
|
||||
|
||||
|
||||
static NTSTATUS appendacl_open(struct composite_context *c,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_open_recv(state->req, c, state->io_open);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* setup structures for getting fileinfo */
|
||||
state->io_fileinfo = talloc(c, union smb_fileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_fileinfo);
|
||||
|
||||
state->io_fileinfo->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
|
||||
state->io_fileinfo->query_secdesc.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
|
||||
state->io_fileinfo->query_secdesc.in.secinfo_flags = SECINFO_DACL;
|
||||
|
||||
state->req = smb_raw_fileinfo_send(tree, state->io_fileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* set the handler */
|
||||
state->req->async.fn = appendacl_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = APPENDACL_GET;
|
||||
|
||||
talloc_free (state->io_open);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS appendacl_get(struct composite_context *c,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
int i;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_fileinfo_recv(state->req, state->io_fileinfo, state->io_fileinfo);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* setup structures for setting fileinfo */
|
||||
state->io_setfileinfo = talloc(c, union smb_setfileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_setfileinfo);
|
||||
|
||||
state->io_setfileinfo->set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
|
||||
state->io_setfileinfo->set_secdesc.in.file.fnum = state->io_fileinfo->query_secdesc.in.file.fnum;
|
||||
|
||||
state->io_setfileinfo->set_secdesc.in.secinfo_flags = SECINFO_DACL;
|
||||
state->io_setfileinfo->set_secdesc.in.sd = state->io_fileinfo->query_secdesc.out.sd;
|
||||
talloc_steal(state->io_setfileinfo, state->io_setfileinfo->set_secdesc.in.sd);
|
||||
|
||||
/* append all aces from io->in.sd->dacl to new security descriptor */
|
||||
if (io->in.sd->dacl != NULL) {
|
||||
for (i = 0; i < io->in.sd->dacl->num_aces; i++) {
|
||||
security_descriptor_dacl_add(state->io_setfileinfo->set_secdesc.in.sd,
|
||||
&(io->in.sd->dacl->aces[i]));
|
||||
}
|
||||
}
|
||||
|
||||
status = smb_raw_setfileinfo(tree, state->io_setfileinfo);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->req = smb_raw_setfileinfo_send(tree, state->io_setfileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call handler when done setting new security descriptor on file */
|
||||
state->req->async.fn = appendacl_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = APPENDACL_SET;
|
||||
|
||||
talloc_free (state->io_fileinfo);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS appendacl_set(struct composite_context *c,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smbcli_request_simple_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* setup structures for getting fileinfo */
|
||||
state->io_fileinfo = talloc(c, union smb_fileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_fileinfo);
|
||||
|
||||
|
||||
state->io_fileinfo->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
|
||||
state->io_fileinfo->query_secdesc.in.file.fnum = state->io_setfileinfo->set_secdesc.in.file.fnum;
|
||||
state->io_fileinfo->query_secdesc.in.secinfo_flags = SECINFO_DACL;
|
||||
|
||||
state->req = smb_raw_fileinfo_send(tree, state->io_fileinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* set the handler */
|
||||
state->req->async.fn = appendacl_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = APPENDACL_GETAGAIN;
|
||||
|
||||
talloc_free (state->io_setfileinfo);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS appendacl_getagain(struct composite_context *c,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
union smb_close *io_close;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_fileinfo_recv(state->req, c, state->io_fileinfo);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
io->out.sd = state->io_fileinfo->query_secdesc.out.sd;
|
||||
|
||||
/* setup structures for close */
|
||||
io_close = talloc(c, union smb_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(io_close);
|
||||
|
||||
io_close->close.level = RAW_CLOSE_CLOSE;
|
||||
io_close->close.in.file.fnum = state->io_fileinfo->query_secdesc.in.file.fnum;
|
||||
io_close->close.in.write_time = 0;
|
||||
|
||||
state->req = smb_raw_close_send(tree, io_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler */
|
||||
state->req->async.fn = appendacl_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = APPENDACL_CLOSEPATH;
|
||||
|
||||
talloc_free (state->io_fileinfo);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static NTSTATUS appendacl_close(struct composite_context *c,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smbcli_request_simple_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
handler for completion of a sub-request in appendacl
|
||||
*/
|
||||
static void appendacl_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = req->async.private;
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
|
||||
/* when this handler is called, the stage indicates what
|
||||
call has just finished */
|
||||
switch (state->stage) {
|
||||
case APPENDACL_OPENPATH:
|
||||
c->status = appendacl_open(c, state->io);
|
||||
break;
|
||||
|
||||
case APPENDACL_GET:
|
||||
c->status = appendacl_get(c, state->io);
|
||||
break;
|
||||
|
||||
case APPENDACL_SET:
|
||||
c->status = appendacl_set(c, state->io);
|
||||
break;
|
||||
|
||||
case APPENDACL_GETAGAIN:
|
||||
c->status = appendacl_getagain(c, state->io);
|
||||
break;
|
||||
|
||||
case APPENDACL_CLOSEPATH:
|
||||
c->status = appendacl_close(c, state->io);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We should get here if c->state >= SMBCLI_REQUEST_DONE */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite appendacl call - does an open followed by a number setfileinfo,
|
||||
after that new acls are read with fileinfo, followed by a close
|
||||
*/
|
||||
struct composite_context *smb_composite_appendacl_send(struct smbcli_tree *tree,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct appendacl_state *state;
|
||||
|
||||
c = talloc_zero(tree, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
state = talloc(c, struct appendacl_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->io = io;
|
||||
|
||||
c->private_data = state;
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
c->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
/* setup structures for opening file */
|
||||
state->io_open = talloc_zero(c, union smb_open);
|
||||
if (state->io_open == NULL) goto failed;
|
||||
|
||||
state->io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
|
||||
state->io_open->ntcreatex.in.root_fid = 0;
|
||||
state->io_open->ntcreatex.in.flags = 0;
|
||||
state->io_open->ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
state->io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
state->io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
state->io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
state->io_open->ntcreatex.in.security_flags = 0;
|
||||
state->io_open->ntcreatex.in.fname = io->in.fname;
|
||||
|
||||
/* send the open on its way */
|
||||
state->req = smb_raw_open_send(tree, state->io_open);
|
||||
if (state->req == NULL) goto failed;
|
||||
|
||||
/* setup the callback handler */
|
||||
state->req->async.fn = appendacl_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = APPENDACL_OPENPATH;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite appendacl call - recv side
|
||||
*/
|
||||
NTSTATUS smb_composite_appendacl_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
|
||||
state->io->out.sd = security_descriptor_copy (mem_ctx, state->io->out.sd);
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite appendacl call - sync interface
|
||||
*/
|
||||
NTSTATUS smb_composite_appendacl(struct smbcli_tree *tree,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_composite_appendacl *io)
|
||||
{
|
||||
struct composite_context *c = smb_composite_appendacl_send(tree, io);
|
||||
return smb_composite_appendacl_recv(c, mem_ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for making a full SMB connection
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/* the stages of this call */
|
||||
enum connect_stage {CONNECT_RESOLVE,
|
||||
CONNECT_SOCKET,
|
||||
CONNECT_SESSION_REQUEST,
|
||||
CONNECT_NEGPROT,
|
||||
CONNECT_SESSION_SETUP,
|
||||
CONNECT_SESSION_SETUP_ANON,
|
||||
CONNECT_TCON};
|
||||
|
||||
struct connect_state {
|
||||
enum connect_stage stage;
|
||||
struct smbcli_socket *sock;
|
||||
struct smbcli_transport *transport;
|
||||
struct smbcli_session *session;
|
||||
struct smb_composite_connect *io;
|
||||
union smb_tcon *io_tcon;
|
||||
struct smb_composite_sesssetup *io_setup;
|
||||
struct smbcli_request *req;
|
||||
struct composite_context *creq;
|
||||
};
|
||||
|
||||
|
||||
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, lp_cli_maxprotocol());
|
||||
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,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_tcon_recv(state->req, c, state->io_tcon);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
io->out.tree->tid = state->io_tcon->tconx.out.tid;
|
||||
if (state->io_tcon->tconx.out.dev_type) {
|
||||
io->out.tree->device = talloc_strdup(io->out.tree,
|
||||
state->io_tcon->tconx.out.dev_type);
|
||||
}
|
||||
if (state->io_tcon->tconx.out.fs_type) {
|
||||
io->out.tree->fs_type = talloc_strdup(io->out.tree,
|
||||
state->io_tcon->tconx.out.fs_type);
|
||||
}
|
||||
|
||||
/* all done! */
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a session setup request with anonymous fallback has completed
|
||||
*/
|
||||
static NTSTATUS connect_session_setup_anon(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_composite_sesssetup_recv(state->creq);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
io->out.anonymous_fallback_done = True;
|
||||
|
||||
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);
|
||||
|
||||
/* connect to a share using a tree connect */
|
||||
state->io_tcon->generic.level = RAW_TCON_TCONX;
|
||||
state->io_tcon->tconx.in.flags = 0;
|
||||
state->io_tcon->tconx.in.password = data_blob(NULL, 0);
|
||||
|
||||
state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon,
|
||||
"\\\\%s\\%s",
|
||||
io->in.called_name,
|
||||
io->in.service);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
|
||||
if (!io->in.service_type) {
|
||||
state->io_tcon->tconx.in.device = "?????";
|
||||
} else {
|
||||
state->io_tcon->tconx.in.device = io->in.service_type;
|
||||
}
|
||||
|
||||
state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
if (state->req->state == SMBCLI_REQUEST_ERROR) {
|
||||
return state->req->status;
|
||||
}
|
||||
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = CONNECT_TCON;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
a session setup request has completed
|
||||
*/
|
||||
static NTSTATUS connect_session_setup(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_composite_sesssetup_recv(state->creq);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status) &&
|
||||
!cli_credentials_is_anonymous(state->io->in.credentials) &&
|
||||
io->in.fallback_to_anonymous) {
|
||||
|
||||
state->io_setup->in.credentials = cli_credentials_init(state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_setup->in.credentials);
|
||||
cli_credentials_set_conf(state->io_setup->in.credentials);
|
||||
cli_credentials_set_anonymous(state->io_setup->in.credentials);
|
||||
|
||||
/* If the preceding attempt was with extended security, we
|
||||
* have been given a uid in the NTLMSSP_CHALLENGE reply. This
|
||||
* would lead to an invalid uid in the anonymous fallback */
|
||||
state->session->vuid = 0;
|
||||
data_blob_free(&state->session->user_session_key);
|
||||
talloc_free(state->session->gensec);
|
||||
state->session->gensec = NULL;
|
||||
|
||||
state->creq = smb_composite_sesssetup_send(state->session,
|
||||
state->io_setup);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->creq);
|
||||
if (state->creq->state == COMPOSITE_STATE_ERROR) {
|
||||
return state->creq->status;
|
||||
}
|
||||
state->creq->async.fn = composite_handler;
|
||||
state->creq->async.private_data = c;
|
||||
state->stage = CONNECT_SESSION_SETUP_ANON;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
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);
|
||||
|
||||
/* connect to a share using a tree connect */
|
||||
state->io_tcon->generic.level = RAW_TCON_TCONX;
|
||||
state->io_tcon->tconx.in.flags = 0;
|
||||
state->io_tcon->tconx.in.password = data_blob(NULL, 0);
|
||||
|
||||
state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon,
|
||||
"\\\\%s\\%s",
|
||||
io->in.called_name,
|
||||
io->in.service);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
|
||||
if (!io->in.service_type) {
|
||||
state->io_tcon->tconx.in.device = "?????";
|
||||
} else {
|
||||
state->io_tcon->tconx.in.device = io->in.service_type;
|
||||
}
|
||||
|
||||
state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
if (state->req->state == SMBCLI_REQUEST_ERROR) {
|
||||
return state->req->status;
|
||||
}
|
||||
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = CONNECT_TCON;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
a negprot request has completed
|
||||
*/
|
||||
static NTSTATUS connect_negprot(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_negotiate_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* next step is a session setup */
|
||||
state->session = smbcli_session_init(state->transport, state, True);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->session);
|
||||
|
||||
state->io_setup = talloc(c, struct smb_composite_sesssetup);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_setup);
|
||||
|
||||
/* prepare a session setup to establish a security context */
|
||||
state->io_setup->in.sesskey = state->transport->negotiate.sesskey;
|
||||
state->io_setup->in.capabilities = state->transport->negotiate.capabilities;
|
||||
state->io_setup->in.credentials = io->in.credentials;
|
||||
state->io_setup->in.workgroup = io->in.workgroup;
|
||||
|
||||
state->creq = smb_composite_sesssetup_send(state->session, state->io_setup);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->creq);
|
||||
if (state->creq->state == COMPOSITE_STATE_ERROR) {
|
||||
return state->creq->status;
|
||||
}
|
||||
|
||||
state->creq->async.fn = composite_handler;
|
||||
state->creq->async.private_data = c;
|
||||
state->stage = CONNECT_SESSION_SETUP;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a session request operation has completed
|
||||
*/
|
||||
static NTSTATUS connect_session_request(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smbcli_transport_connect_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* next step is a negprot */
|
||||
return connect_send_negprot(c, io);
|
||||
}
|
||||
|
||||
/*
|
||||
a socket connection operation has completed
|
||||
*/
|
||||
static NTSTATUS connect_socket(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
struct nbt_name calling, called;
|
||||
|
||||
status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* the socket is up - we can initialise the smbcli transport layer */
|
||||
state->transport = smbcli_transport_init(state->sock, state, True);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->transport);
|
||||
|
||||
if (is_ipaddress(state->sock->hostname) &&
|
||||
(state->io->in.called_name != NULL)) {
|
||||
/* If connecting to an IP address, we might want the real name
|
||||
* of the host for later kerberos. The called name is a better
|
||||
* approximation */
|
||||
state->sock->hostname =
|
||||
talloc_strdup(state->sock, io->in.called_name);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->sock->hostname);
|
||||
}
|
||||
|
||||
make_nbt_name_client(&calling, cli_credentials_get_workstation(io->in.credentials));
|
||||
|
||||
nbt_choose_called_name(state, &called, io->in.called_name, NBT_NAME_SERVER);
|
||||
|
||||
/* we have a connected socket - next step is a session
|
||||
request, if needed. Port 445 doesn't need it, so it goes
|
||||
straight to the negprot */
|
||||
if (state->sock->port == 445) {
|
||||
status = nbt_name_dup(state->transport, &called,
|
||||
&state->transport->called);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
return connect_send_negprot(c, io);
|
||||
}
|
||||
|
||||
state->req = smbcli_transport_connect_send(state->transport, &calling, &called);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = CONNECT_SESSION_REQUEST;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
called when name resolution is finished
|
||||
*/
|
||||
static NTSTATUS connect_resolve(struct composite_context *c,
|
||||
struct smb_composite_connect *io)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
NTSTATUS status;
|
||||
const char *address;
|
||||
|
||||
status = resolve_name_recv(state->creq, state, &address);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->creq = smbcli_sock_connect_send(state, address, io->in.port,
|
||||
io->in.dest_host, c->event_ctx);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->creq);
|
||||
|
||||
state->stage = CONNECT_SOCKET;
|
||||
state->creq->async.private_data = c;
|
||||
state->creq->async.fn = composite_handler;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle and dispatch state transitions
|
||||
*/
|
||||
static void state_handler(struct composite_context *c)
|
||||
{
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
|
||||
switch (state->stage) {
|
||||
case CONNECT_RESOLVE:
|
||||
c->status = connect_resolve(c, state->io);
|
||||
break;
|
||||
case CONNECT_SOCKET:
|
||||
c->status = connect_socket(c, state->io);
|
||||
break;
|
||||
case CONNECT_SESSION_REQUEST:
|
||||
c->status = connect_session_request(c, state->io);
|
||||
break;
|
||||
case CONNECT_NEGPROT:
|
||||
c->status = connect_negprot(c, state->io);
|
||||
break;
|
||||
case CONNECT_SESSION_SETUP:
|
||||
c->status = connect_session_setup(c, state->io);
|
||||
break;
|
||||
case CONNECT_SESSION_SETUP_ANON:
|
||||
c->status = connect_session_setup_anon(c, state->io);
|
||||
break;
|
||||
case CONNECT_TCON:
|
||||
c->status = connect_tcon(c, state->io);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handler for completion of a smbcli_request sub-request
|
||||
*/
|
||||
static void request_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
state_handler(c);
|
||||
}
|
||||
|
||||
/*
|
||||
handler for completion of a smbcli_composite sub-request
|
||||
*/
|
||||
static void composite_handler(struct composite_context *creq)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(creq->async.private_data,
|
||||
struct composite_context);
|
||||
state_handler(c);
|
||||
}
|
||||
|
||||
/*
|
||||
a function to establish a smbcli_tree from scratch
|
||||
*/
|
||||
struct composite_context *smb_composite_connect_send(struct smb_composite_connect *io,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct event_context *event_ctx)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct connect_state *state;
|
||||
struct nbt_name name;
|
||||
|
||||
c = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (c == 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;
|
||||
make_nbt_name_server(&name, io->in.dest_host);
|
||||
state->creq = resolve_name_send(&name, c->event_ctx, lp_name_resolve_order());
|
||||
|
||||
if (state->creq == NULL) goto failed;
|
||||
state->creq->async.private_data = c;
|
||||
state->creq->async.fn = composite_handler;
|
||||
|
||||
return c;
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
recv half of async composite connect code
|
||||
*/
|
||||
NTSTATUS smb_composite_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
|
||||
talloc_steal(mem_ctx, state->io->out.tree);
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
sync version of smb_composite_connect
|
||||
*/
|
||||
NTSTATUS smb_composite_connect(struct smb_composite_connect *io, TALLOC_CTX *mem_ctx,
|
||||
struct event_context *ev)
|
||||
{
|
||||
struct composite_context *c = smb_composite_connect_send(io, mem_ctx, ev);
|
||||
return smb_composite_connect_recv(c, mem_ctx);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for loading a whole file into memory
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
|
||||
enum fetchfile_stage {FETCHFILE_CONNECT,
|
||||
FETCHFILE_READ};
|
||||
|
||||
struct fetchfile_state {
|
||||
enum fetchfile_stage stage;
|
||||
struct smb_composite_fetchfile *io;
|
||||
struct composite_context *creq;
|
||||
struct smb_composite_connect *connect;
|
||||
struct smb_composite_loadfile *loadfile;
|
||||
};
|
||||
|
||||
static void fetchfile_composite_handler(struct composite_context *req);
|
||||
|
||||
static NTSTATUS fetchfile_connect(struct composite_context *c,
|
||||
struct smb_composite_fetchfile *io)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct fetchfile_state *state;
|
||||
state = talloc_get_type(c->private_data, struct fetchfile_state);
|
||||
|
||||
status = smb_composite_connect_recv(state->creq, c);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->loadfile = talloc(state, struct smb_composite_loadfile);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->loadfile);
|
||||
|
||||
state->loadfile->in.fname = io->in.filename;
|
||||
|
||||
state->creq = smb_composite_loadfile_send(state->connect->out.tree,
|
||||
state->loadfile);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->creq);
|
||||
|
||||
state->creq->async.private_data = 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;
|
||||
}
|
||||
|
||||
static NTSTATUS fetchfile_read(struct composite_context *c,
|
||||
struct smb_composite_fetchfile *io)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct fetchfile_state *state;
|
||||
state = talloc_get_type(c->private_data, struct fetchfile_state);
|
||||
|
||||
status = smb_composite_loadfile_recv(state->creq, NULL);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
io->out.data = state->loadfile->out.data;
|
||||
io->out.size = state->loadfile->out.size;
|
||||
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
if (c->async.fn)
|
||||
c->async.fn(c);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void fetchfile_state_handler(struct composite_context *c)
|
||||
{
|
||||
struct fetchfile_state *state;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
state = talloc_get_type(c->private_data, struct fetchfile_state);
|
||||
|
||||
/* when this handler is called, the stage indicates what
|
||||
call has just finished */
|
||||
switch (state->stage) {
|
||||
case FETCHFILE_CONNECT:
|
||||
status = fetchfile_connect(c, state->io);
|
||||
break;
|
||||
case FETCHFILE_READ:
|
||||
status = fetchfile_read(c, state->io);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
c->status = status;
|
||||
c->state = COMPOSITE_STATE_ERROR;
|
||||
if (c->async.fn) {
|
||||
c->async.fn(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fetchfile_composite_handler(struct composite_context *creq)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(creq->async.private_data,
|
||||
struct composite_context);
|
||||
fetchfile_state_handler(c);
|
||||
}
|
||||
|
||||
struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetchfile *io,
|
||||
struct event_context *event_ctx)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct fetchfile_state *state;
|
||||
|
||||
c = talloc_zero(NULL, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
state = talloc(c, struct fetchfile_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->connect = talloc(state, struct smb_composite_connect);
|
||||
if (state->connect == NULL) goto failed;
|
||||
|
||||
state->io = io;
|
||||
|
||||
state->connect->in.dest_host = io->in.dest_host;
|
||||
state->connect->in.port = io->in.port;
|
||||
state->connect->in.called_name = io->in.called_name;
|
||||
state->connect->in.service = io->in.service;
|
||||
state->connect->in.service_type = io->in.service_type;
|
||||
state->connect->in.credentials = io->in.credentials;
|
||||
state->connect->in.fallback_to_anonymous = False;
|
||||
state->connect->in.workgroup = io->in.workgroup;
|
||||
|
||||
state->creq = smb_composite_connect_send(state->connect, state, event_ctx);
|
||||
if (state->creq == NULL) goto failed;
|
||||
|
||||
state->creq->async.private_data = c;
|
||||
state->creq->async.fn = fetchfile_composite_handler;
|
||||
|
||||
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;
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NTSTATUS smb_composite_fetchfile_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct fetchfile_state *state = talloc_get_type(c->private_data, struct fetchfile_state);
|
||||
talloc_steal(mem_ctx, state->io->out.data);
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS smb_composite_fetchfile(struct smb_composite_fetchfile *io,
|
||||
TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
struct composite_context *c = smb_composite_fetchfile_send(io, NULL);
|
||||
return smb_composite_fetchfile_recv(c, mem_ctx);
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
a composite API for quering file system information
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
|
||||
/* the stages of this call */
|
||||
enum fsinfo_stage {FSINFO_CONNECT, FSINFO_QUERY};
|
||||
|
||||
|
||||
static void fsinfo_raw_handler(struct smbcli_request *req);
|
||||
static void fsinfo_composite_handler(struct composite_context *c);
|
||||
static void fsinfo_state_handler(struct composite_context *c);
|
||||
|
||||
struct fsinfo_state {
|
||||
enum fsinfo_stage stage;
|
||||
struct composite_context *creq;
|
||||
struct smb_composite_fsinfo *io;
|
||||
struct smb_composite_connect *connect;
|
||||
union smb_fsinfo *fsinfo;
|
||||
struct smbcli_tree *tree;
|
||||
struct smbcli_request *req;
|
||||
};
|
||||
|
||||
static NTSTATUS fsinfo_connect(struct composite_context *c,
|
||||
struct smb_composite_fsinfo *io)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct fsinfo_state *state;
|
||||
state = talloc_get_type(c->private_data, struct fsinfo_state);
|
||||
|
||||
status = smb_composite_connect_recv(state->creq, c);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->fsinfo = talloc(state, union smb_fsinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->fsinfo);
|
||||
|
||||
state->fsinfo->generic.level = io->in.level;
|
||||
|
||||
state->req = smb_raw_fsinfo_send(state->connect->out.tree,
|
||||
state,
|
||||
state->fsinfo);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
state->req->async.private = 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;
|
||||
}
|
||||
|
||||
static NTSTATUS fsinfo_query(struct composite_context *c,
|
||||
struct smb_composite_fsinfo *io)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct fsinfo_state *state;
|
||||
state = talloc_get_type(c->private_data, struct fsinfo_state);
|
||||
|
||||
status = smb_raw_fsinfo_recv(state->req, state, state->fsinfo);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->io->out.fsinfo = state->fsinfo;
|
||||
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
|
||||
if (c->async.fn)
|
||||
c->async.fn(c);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
handler for completion of a sub-request in fsinfo
|
||||
*/
|
||||
static void fsinfo_state_handler(struct composite_context *creq)
|
||||
{
|
||||
struct fsinfo_state *state = talloc_get_type(creq->private_data, struct fsinfo_state);
|
||||
|
||||
/* when this handler is called, the stage indicates what
|
||||
call has just finished */
|
||||
switch (state->stage) {
|
||||
case FSINFO_CONNECT:
|
||||
creq->status = fsinfo_connect(creq, state->io);
|
||||
break;
|
||||
|
||||
case FSINFO_QUERY:
|
||||
creq->status = fsinfo_query(creq, state->io);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(creq->status)) {
|
||||
creq->state = COMPOSITE_STATE_ERROR;
|
||||
}
|
||||
|
||||
if (creq->state >= COMPOSITE_STATE_DONE && creq->async.fn) {
|
||||
creq->async.fn(creq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
As raw and composite handlers take different requests, we need to handlers
|
||||
to adapt both for the same state machine in fsinfo_state_handler()
|
||||
*/
|
||||
static void fsinfo_raw_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
fsinfo_state_handler(c);
|
||||
}
|
||||
|
||||
static void fsinfo_composite_handler(struct composite_context *creq)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(creq->async.private_data,
|
||||
struct composite_context);
|
||||
fsinfo_state_handler(c);
|
||||
}
|
||||
|
||||
/*
|
||||
composite fsinfo call - connects to a tree and queries a file system information
|
||||
*/
|
||||
struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree,
|
||||
struct smb_composite_fsinfo *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct fsinfo_state *state;
|
||||
|
||||
c = talloc_zero(tree, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
state = talloc(c, struct fsinfo_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->io = io;
|
||||
|
||||
state->connect = talloc(state, struct smb_composite_connect);
|
||||
|
||||
if (state->connect == NULL) goto failed;
|
||||
|
||||
state->connect->in.dest_host = io->in.dest_host;
|
||||
state->connect->in.port = io->in.port;
|
||||
state->connect->in.called_name = io->in.called_name;
|
||||
state->connect->in.service = io->in.service;
|
||||
state->connect->in.service_type = io->in.service_type;
|
||||
state->connect->in.credentials = io->in.credentials;
|
||||
state->connect->in.fallback_to_anonymous = False;
|
||||
state->connect->in.workgroup = io->in.workgroup;
|
||||
|
||||
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,
|
||||
c->event_ctx);
|
||||
|
||||
if (state->creq == NULL) goto failed;
|
||||
|
||||
state->creq->async.private_data = c;
|
||||
state->creq->async.fn = fsinfo_composite_handler;
|
||||
|
||||
return c;
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
composite fsinfo call - recv side
|
||||
*/
|
||||
NTSTATUS smb_composite_fsinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct fsinfo_state *state = talloc_get_type(c->private_data, struct fsinfo_state);
|
||||
talloc_steal(mem_ctx, state->io->out.fsinfo);
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite fsinfo call - sync interface
|
||||
*/
|
||||
NTSTATUS smb_composite_fsinfo(struct smbcli_tree *tree,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_composite_fsinfo *io)
|
||||
{
|
||||
struct composite_context *c = smb_composite_fsinfo_send(tree, io);
|
||||
return smb_composite_fsinfo_recv(c, mem_ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for loading a whole file into memory
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
|
||||
/* the stages of this call */
|
||||
enum loadfile_stage {LOADFILE_OPEN, LOADFILE_READ, LOADFILE_CLOSE};
|
||||
|
||||
|
||||
static void loadfile_handler(struct smbcli_request *req);
|
||||
|
||||
struct loadfile_state {
|
||||
enum loadfile_stage stage;
|
||||
struct smb_composite_loadfile *io;
|
||||
struct smbcli_request *req;
|
||||
union smb_open *io_open;
|
||||
union smb_read *io_read;
|
||||
};
|
||||
|
||||
/*
|
||||
setup for the close
|
||||
*/
|
||||
static NTSTATUS setup_close(struct composite_context *c,
|
||||
struct smbcli_tree *tree, uint16_t fnum)
|
||||
{
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
union smb_close *io_close;
|
||||
|
||||
/* nothing to read, setup the close */
|
||||
io_close = talloc(c, union smb_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(io_close);
|
||||
|
||||
io_close->close.level = RAW_CLOSE_CLOSE;
|
||||
io_close->close.in.file.fnum = fnum;
|
||||
io_close->close.in.write_time = 0;
|
||||
|
||||
state->req = smb_raw_close_send(tree, io_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the close is done */
|
||||
state->req->async.fn = loadfile_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = LOADFILE_CLOSE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
called when the open is done - pull the results and setup for the
|
||||
first readx, or close if the file is zero size
|
||||
*/
|
||||
static NTSTATUS loadfile_open(struct composite_context *c,
|
||||
struct smb_composite_loadfile *io)
|
||||
{
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_open_recv(state->req, c, state->io_open);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* don't allow stupidly large loads */
|
||||
if (state->io_open->ntcreatex.out.size > 100*1000*1000) {
|
||||
return NT_STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* allocate space for the file data */
|
||||
io->out.size = state->io_open->ntcreatex.out.size;
|
||||
io->out.data = talloc_array(c, uint8_t, io->out.size);
|
||||
NT_STATUS_HAVE_NO_MEMORY(io->out.data);
|
||||
|
||||
if (io->out.size == 0) {
|
||||
return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum);
|
||||
}
|
||||
|
||||
/* setup for the read */
|
||||
state->io_read = talloc(c, union smb_read);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->io_read);
|
||||
|
||||
state->io_read->readx.level = RAW_READ_READX;
|
||||
state->io_read->readx.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
|
||||
state->io_read->readx.in.offset = 0;
|
||||
state->io_read->readx.in.mincnt = MIN(32768, io->out.size);
|
||||
state->io_read->readx.in.maxcnt = state->io_read->readx.in.mincnt;
|
||||
state->io_read->readx.in.remaining = 0;
|
||||
state->io_read->readx.in.read_for_execute = False;
|
||||
state->io_read->readx.out.data = io->out.data;
|
||||
|
||||
state->req = smb_raw_read_send(tree, state->io_read);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the first read is done */
|
||||
state->req->async.fn = loadfile_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = LOADFILE_READ;
|
||||
|
||||
talloc_free(state->io_open);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
called when a read is done - pull the results and setup for the
|
||||
next read, or close if the file is all done
|
||||
*/
|
||||
static NTSTATUS loadfile_read(struct composite_context *c,
|
||||
struct smb_composite_loadfile *io)
|
||||
{
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_read_recv(state->req, state->io_read);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* we might be done */
|
||||
if (state->io_read->readx.in.offset +
|
||||
state->io_read->readx.out.nread == io->out.size) {
|
||||
return setup_close(c, tree, state->io_read->readx.in.file.fnum);
|
||||
}
|
||||
|
||||
/* setup for the next read */
|
||||
state->io_read->readx.in.offset += state->io_read->readx.out.nread;
|
||||
state->io_read->readx.in.mincnt = MIN(32768, io->out.size - state->io_read->readx.in.offset);
|
||||
state->io_read->readx.out.data = io->out.data + state->io_read->readx.in.offset;
|
||||
|
||||
state->req = smb_raw_read_send(tree, state->io_read);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the read is done */
|
||||
state->req->async.fn = loadfile_handler;
|
||||
state->req->async.private = c;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
called when the close is done, check the status and cleanup
|
||||
*/
|
||||
static NTSTATUS loadfile_close(struct composite_context *c,
|
||||
struct smb_composite_loadfile *io)
|
||||
{
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smbcli_request_simple_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handler for completion of a sub-request in loadfile
|
||||
*/
|
||||
static void loadfile_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = req->async.private;
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
|
||||
/* when this handler is called, the stage indicates what
|
||||
call has just finished */
|
||||
switch (state->stage) {
|
||||
case LOADFILE_OPEN:
|
||||
c->status = loadfile_open(c, state->io);
|
||||
break;
|
||||
|
||||
case LOADFILE_READ:
|
||||
c->status = loadfile_read(c, state->io);
|
||||
break;
|
||||
|
||||
case LOADFILE_CLOSE:
|
||||
c->status = loadfile_close(c, state->io);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
composite loadfile call - does an openx followed by a number of readx calls,
|
||||
followed by a close
|
||||
*/
|
||||
struct composite_context *smb_composite_loadfile_send(struct smbcli_tree *tree,
|
||||
struct smb_composite_loadfile *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct loadfile_state *state;
|
||||
|
||||
c = talloc_zero(tree, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
state = talloc(c, struct loadfile_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->io = io;
|
||||
|
||||
c->private_data = state;
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
c->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
/* setup for the open */
|
||||
state->io_open = talloc_zero(c, union smb_open);
|
||||
if (state->io_open == NULL) goto failed;
|
||||
|
||||
state->io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
|
||||
state->io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
|
||||
state->io_open->ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
|
||||
state->io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
state->io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
state->io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
state->io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
state->io_open->ntcreatex.in.fname = io->in.fname;
|
||||
|
||||
/* send the open on its way */
|
||||
state->req = smb_raw_open_send(tree, state->io_open);
|
||||
if (state->req == NULL) goto failed;
|
||||
|
||||
/* setup the callback handler */
|
||||
state->req->async.fn = loadfile_handler;
|
||||
state->req->async.private = c;
|
||||
state->stage = LOADFILE_OPEN;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite loadfile call - recv side
|
||||
*/
|
||||
NTSTATUS smb_composite_loadfile_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
|
||||
talloc_steal(mem_ctx, state->io->out.data);
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite loadfile call - sync interface
|
||||
*/
|
||||
NTSTATUS smb_composite_loadfile(struct smbcli_tree *tree,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_composite_loadfile *io)
|
||||
{
|
||||
struct composite_context *c = smb_composite_loadfile_send(tree, io);
|
||||
return smb_composite_loadfile_recv(c, mem_ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for saving a whole file from memory
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
|
||||
/* the stages of this call */
|
||||
enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE};
|
||||
|
||||
static void savefile_handler(struct smbcli_request *req);
|
||||
|
||||
struct savefile_state {
|
||||
enum savefile_stage stage;
|
||||
off_t total_written;
|
||||
struct smb_composite_savefile *io;
|
||||
union smb_open *io_open;
|
||||
union smb_write *io_write;
|
||||
struct smbcli_request *req;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
setup for the close
|
||||
*/
|
||||
static NTSTATUS setup_close(struct composite_context *c,
|
||||
struct smbcli_tree *tree, uint16_t fnum)
|
||||
{
|
||||
struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
|
||||
union smb_close *io_close;
|
||||
|
||||
/* nothing to write, setup the close */
|
||||
io_close = talloc(c, union smb_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(io_close);
|
||||
|
||||
io_close->close.level = RAW_CLOSE_CLOSE;
|
||||
io_close->close.in.file.fnum = fnum;
|
||||
io_close->close.in.write_time = 0;
|
||||
|
||||
state->req = smb_raw_close_send(tree, io_close);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the close is done */
|
||||
state->stage = SAVEFILE_CLOSE;
|
||||
state->req->async.fn = savefile_handler;
|
||||
state->req->async.private = c;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
called when the open is done - pull the results and setup for the
|
||||
first writex, or close if the file is zero size
|
||||
*/
|
||||
static NTSTATUS savefile_open(struct composite_context *c,
|
||||
struct smb_composite_savefile *io)
|
||||
{
|
||||
struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
|
||||
union smb_write *io_write;
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
|
||||
|
||||
status = smb_raw_open_recv(state->req, c, state->io_open);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
if (io->in.size == 0) {
|
||||
return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum);
|
||||
}
|
||||
|
||||
/* setup for the first write */
|
||||
io_write = talloc(c, union smb_write);
|
||||
NT_STATUS_HAVE_NO_MEMORY(io_write);
|
||||
|
||||
io_write->writex.level = RAW_WRITE_WRITEX;
|
||||
io_write->writex.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
|
||||
io_write->writex.in.offset = 0;
|
||||
io_write->writex.in.wmode = 0;
|
||||
io_write->writex.in.remaining = 0;
|
||||
io_write->writex.in.count = MIN(max_xmit - 100, io->in.size);
|
||||
io_write->writex.in.data = io->in.data;
|
||||
state->io_write = io_write;
|
||||
|
||||
state->req = smb_raw_write_send(tree, io_write);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the first write is done */
|
||||
state->stage = SAVEFILE_WRITE;
|
||||
state->req->async.fn = savefile_handler;
|
||||
state->req->async.private = c;
|
||||
talloc_free(state->io_open);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
called when a write is done - pull the results and setup for the
|
||||
next write, or close if the file is all done
|
||||
*/
|
||||
static NTSTATUS savefile_write(struct composite_context *c,
|
||||
struct smb_composite_savefile *io)
|
||||
{
|
||||
struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
|
||||
struct smbcli_tree *tree = state->req->tree;
|
||||
NTSTATUS status;
|
||||
uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
|
||||
|
||||
status = smb_raw_write_recv(state->req, state->io_write);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
state->total_written += state->io_write->writex.out.nwritten;
|
||||
|
||||
/* we might be done */
|
||||
if (state->io_write->writex.out.nwritten != state->io_write->writex.in.count ||
|
||||
state->total_written == io->in.size) {
|
||||
return setup_close(c, tree, state->io_write->writex.in.file.fnum);
|
||||
}
|
||||
|
||||
/* setup for the next write */
|
||||
state->io_write->writex.in.offset = state->total_written;
|
||||
state->io_write->writex.in.count = MIN(max_xmit - 100,
|
||||
io->in.size - state->total_written);
|
||||
state->io_write->writex.in.data = io->in.data + state->total_written;
|
||||
|
||||
state->req = smb_raw_write_send(tree, state->io_write);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state->req);
|
||||
|
||||
/* call the handler again when the write is done */
|
||||
state->req->async.fn = savefile_handler;
|
||||
state->req->async.private = c;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
called when the close is done, check the status and cleanup
|
||||
*/
|
||||
static NTSTATUS savefile_close(struct composite_context *c,
|
||||
struct smb_composite_savefile *io)
|
||||
{
|
||||
struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = smbcli_request_simple_recv(state->req);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
if (state->total_written != io->in.size) {
|
||||
return NT_STATUS_DISK_FULL;
|
||||
}
|
||||
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handler for completion of a sub-request in savefile
|
||||
*/
|
||||
static void savefile_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = req->async.private;
|
||||
struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
|
||||
|
||||
/* when this handler is called, the stage indicates what
|
||||
call has just finished */
|
||||
switch (state->stage) {
|
||||
case SAVEFILE_OPEN:
|
||||
c->status = savefile_open(c, state->io);
|
||||
break;
|
||||
|
||||
case SAVEFILE_WRITE:
|
||||
c->status = savefile_write(c, state->io);
|
||||
break;
|
||||
|
||||
case SAVEFILE_CLOSE:
|
||||
c->status = savefile_close(c, state->io);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
composite savefile call - does an openx followed by a number of writex calls,
|
||||
followed by a close
|
||||
*/
|
||||
struct composite_context *smb_composite_savefile_send(struct smbcli_tree *tree,
|
||||
struct smb_composite_savefile *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct savefile_state *state;
|
||||
union smb_open *io_open;
|
||||
|
||||
c = talloc_zero(tree, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
c->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
state = talloc(c, struct savefile_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->stage = SAVEFILE_OPEN;
|
||||
state->total_written = 0;
|
||||
state->io = io;
|
||||
|
||||
/* setup for the open */
|
||||
io_open = talloc_zero(c, union smb_open);
|
||||
if (io_open == NULL) goto failed;
|
||||
|
||||
io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
|
||||
io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
|
||||
io_open->ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
|
||||
io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
io_open->ntcreatex.in.fname = io->in.fname;
|
||||
state->io_open = io_open;
|
||||
|
||||
/* send the open on its way */
|
||||
state->req = smb_raw_open_send(tree, io_open);
|
||||
if (state->req == NULL) goto failed;
|
||||
|
||||
/* setup the callback handler */
|
||||
state->req->async.fn = savefile_handler;
|
||||
state->req->async.private = c;
|
||||
c->private_data = state;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite savefile call - recv side
|
||||
*/
|
||||
NTSTATUS smb_composite_savefile_recv(struct composite_context *c)
|
||||
{
|
||||
NTSTATUS status;
|
||||
status = composite_wait(c);
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite savefile call - sync interface
|
||||
*/
|
||||
NTSTATUS smb_composite_savefile(struct smbcli_tree *tree,
|
||||
struct smb_composite_savefile *io)
|
||||
{
|
||||
struct composite_context *c = smb_composite_savefile_send(tree, io);
|
||||
return smb_composite_savefile_recv(c);
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for making handling a generic async session setup
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
#include "libcli/auth/libcli_auth.h"
|
||||
#include "auth/auth.h"
|
||||
#include "auth/gensec/gensec.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "version.h"
|
||||
|
||||
struct sesssetup_state {
|
||||
union smb_sesssetup setup;
|
||||
NTSTATUS gensec_status;
|
||||
struct smb_composite_sesssetup *io;
|
||||
struct smbcli_request *req;
|
||||
};
|
||||
|
||||
static NTSTATUS session_setup_old(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req);
|
||||
static NTSTATUS session_setup_nt1(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req);
|
||||
static NTSTATUS session_setup_spnego(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req);
|
||||
|
||||
/*
|
||||
store the user session key for a transport
|
||||
*/
|
||||
static void set_user_session_key(struct smbcli_session *session,
|
||||
const DATA_BLOB *session_key)
|
||||
{
|
||||
session->user_session_key = data_blob_talloc(session,
|
||||
session_key->data,
|
||||
session_key->length);
|
||||
}
|
||||
|
||||
/*
|
||||
handler for completion of a smbcli_request sub-request
|
||||
*/
|
||||
static void request_handler(struct smbcli_request *req)
|
||||
{
|
||||
struct composite_context *c = req->async.private;
|
||||
struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
|
||||
struct smbcli_session *session = req->session;
|
||||
DATA_BLOB session_key = data_blob(NULL, 0);
|
||||
DATA_BLOB null_data_blob = data_blob(NULL, 0);
|
||||
NTSTATUS session_key_err, nt_status;
|
||||
|
||||
c->status = smb_raw_sesssetup_recv(req, state, &state->setup);
|
||||
|
||||
switch (state->setup.old.level) {
|
||||
case RAW_SESSSETUP_OLD:
|
||||
state->io->out.vuid = state->setup.old.out.vuid;
|
||||
/* This doesn't work, as this only happens on old
|
||||
* protocols, where this comparison won't match. */
|
||||
if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
|
||||
/* we neet to reset the vuid for a new try */
|
||||
session->vuid = 0;
|
||||
if (cli_credentials_wrong_password(state->io->in.credentials)) {
|
||||
nt_status = session_setup_old(c, session,
|
||||
state->io,
|
||||
&state->req);
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
c->status = nt_status;
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RAW_SESSSETUP_NT1:
|
||||
state->io->out.vuid = state->setup.nt1.out.vuid;
|
||||
if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
|
||||
/* we neet to reset the vuid for a new try */
|
||||
session->vuid = 0;
|
||||
if (cli_credentials_wrong_password(state->io->in.credentials)) {
|
||||
nt_status = session_setup_nt1(c, session,
|
||||
state->io,
|
||||
&state->req);
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
c->status = nt_status;
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RAW_SESSSETUP_SPNEGO:
|
||||
state->io->out.vuid = state->setup.spnego.out.vuid;
|
||||
if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
|
||||
/* we neet to reset the vuid for a new try */
|
||||
session->vuid = 0;
|
||||
if (cli_credentials_wrong_password(state->io->in.credentials)) {
|
||||
nt_status = session_setup_spnego(c, session,
|
||||
state->io,
|
||||
&state->req);
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
c->status = nt_status;
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
!NT_STATUS_IS_OK(c->status)) {
|
||||
break;
|
||||
}
|
||||
if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
|
||||
|
||||
/* The status value here, from the earlier pass at GENSEC is
|
||||
* vital to the security of the system. Even if the other end
|
||||
* accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then
|
||||
* you must keep feeding it blobs, or else the remote
|
||||
* host/attacker might avoid mutal authentication
|
||||
* requirements */
|
||||
|
||||
state->gensec_status = gensec_update(session->gensec, state,
|
||||
state->setup.spnego.out.secblob,
|
||||
&state->setup.spnego.in.secblob);
|
||||
c->status = state->gensec_status;
|
||||
if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
!NT_STATUS_IS_OK(c->status)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
state->setup.spnego.in.secblob = data_blob(NULL, 0);
|
||||
}
|
||||
|
||||
/* we need to do another round of session setup. We keep going until both sides
|
||||
are happy */
|
||||
session_key_err = gensec_session_key(session->gensec, &session_key);
|
||||
if (NT_STATUS_IS_OK(session_key_err)) {
|
||||
set_user_session_key(session, &session_key);
|
||||
smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
|
||||
}
|
||||
|
||||
if (state->setup.spnego.in.secblob.length) {
|
||||
/*
|
||||
* set the session->vuid value only for calling
|
||||
* smb_raw_sesssetup_send()
|
||||
*/
|
||||
uint16_t vuid = session->vuid;
|
||||
session->vuid = state->io->out.vuid;
|
||||
state->req = smb_raw_sesssetup_send(session, &state->setup);
|
||||
session->vuid = vuid;
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case RAW_SESSSETUP_SMB2:
|
||||
c->status = NT_STATUS_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* enforce the local signing required flag */
|
||||
if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) {
|
||||
if (!session->transport->negotiate.sign_info.doing_signing
|
||||
&& session->transport->negotiate.sign_info.mandatory_signing) {
|
||||
DEBUG(0, ("SMB signing required, but server does not support it\n"));
|
||||
c->status = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(c->status)) {
|
||||
c->state = COMPOSITE_STATE_DONE;
|
||||
} else {
|
||||
c->state = COMPOSITE_STATE_ERROR;
|
||||
}
|
||||
if (c->async.fn) {
|
||||
c->async.fn(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a nt1 style session setup
|
||||
*/
|
||||
static NTSTATUS session_setup_nt1(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req)
|
||||
{
|
||||
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, session->transport->socket->hostname, lp_workgroup());
|
||||
DATA_BLOB session_key;
|
||||
int flags = CLI_CRED_NTLM_AUTH;
|
||||
if (lp_client_lanman_auth()) {
|
||||
flags |= CLI_CRED_LANMAN_AUTH;
|
||||
}
|
||||
|
||||
if (lp_client_ntlmv2_auth()) {
|
||||
flags |= CLI_CRED_NTLMv2_AUTH;
|
||||
}
|
||||
|
||||
state->setup.nt1.level = RAW_SESSSETUP_NT1;
|
||||
state->setup.nt1.in.bufsize = session->transport->options.max_xmit;
|
||||
state->setup.nt1.in.mpx_max = session->transport->options.max_mux;
|
||||
state->setup.nt1.in.vc_num = 1;
|
||||
state->setup.nt1.in.sesskey = io->in.sesskey;
|
||||
state->setup.nt1.in.capabilities = io->in.capabilities;
|
||||
state->setup.nt1.in.os = "Unix";
|
||||
state->setup.nt1.in.lanman = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
|
||||
|
||||
cli_credentials_get_ntlm_username_domain(io->in.credentials, state,
|
||||
&state->setup.nt1.in.user,
|
||||
&state->setup.nt1.in.domain);
|
||||
|
||||
|
||||
if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
|
||||
nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state,
|
||||
&flags,
|
||||
session->transport->negotiate.secblob,
|
||||
names_blob,
|
||||
&state->setup.nt1.in.password1,
|
||||
&state->setup.nt1.in.password2,
|
||||
NULL, &session_key);
|
||||
NT_STATUS_NOT_OK_RETURN(nt_status);
|
||||
|
||||
smbcli_transport_simple_set_signing(session->transport, session_key,
|
||||
state->setup.nt1.in.password2);
|
||||
set_user_session_key(session, &session_key);
|
||||
|
||||
data_blob_free(&session_key);
|
||||
} else if (lp_client_plaintext_auth()) {
|
||||
state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password));
|
||||
state->setup.nt1.in.password2 = data_blob(NULL, 0);
|
||||
} else {
|
||||
/* could match windows client and return 'cannot logon from this workstation', but it just confuses everybody */
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*req = smb_raw_sesssetup_send(session, &state->setup);
|
||||
if (!*req) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
return (*req)->status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
old style session setup (pre NT1 protocol level)
|
||||
*/
|
||||
static NTSTATUS session_setup_old(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req)
|
||||
{
|
||||
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, session->transport->socket->hostname, lp_workgroup());
|
||||
DATA_BLOB session_key;
|
||||
int flags = 0;
|
||||
if (lp_client_lanman_auth()) {
|
||||
flags |= CLI_CRED_LANMAN_AUTH;
|
||||
}
|
||||
|
||||
if (lp_client_ntlmv2_auth()) {
|
||||
flags |= CLI_CRED_NTLMv2_AUTH;
|
||||
}
|
||||
|
||||
state->setup.old.level = RAW_SESSSETUP_OLD;
|
||||
state->setup.old.in.bufsize = session->transport->options.max_xmit;
|
||||
state->setup.old.in.mpx_max = session->transport->options.max_mux;
|
||||
state->setup.old.in.vc_num = 1;
|
||||
state->setup.old.in.sesskey = io->in.sesskey;
|
||||
state->setup.old.in.os = "Unix";
|
||||
state->setup.old.in.lanman = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
|
||||
cli_credentials_get_ntlm_username_domain(io->in.credentials, state,
|
||||
&state->setup.old.in.user,
|
||||
&state->setup.old.in.domain);
|
||||
|
||||
if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
|
||||
nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state,
|
||||
&flags,
|
||||
session->transport->negotiate.secblob,
|
||||
names_blob,
|
||||
&state->setup.old.in.password,
|
||||
NULL,
|
||||
NULL, &session_key);
|
||||
NT_STATUS_NOT_OK_RETURN(nt_status);
|
||||
set_user_session_key(session, &session_key);
|
||||
|
||||
data_blob_free(&session_key);
|
||||
} else if (lp_client_plaintext_auth()) {
|
||||
state->setup.old.in.password = data_blob_talloc(state, password, strlen(password));
|
||||
} else {
|
||||
/* could match windows client and return 'cannot logon from this workstation', but it just confuses everybody */
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*req = smb_raw_sesssetup_send(session, &state->setup);
|
||||
if (!*req) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
return (*req)->status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Modern, all singing, all dancing extended security (and possibly SPNEGO) request
|
||||
*/
|
||||
static NTSTATUS session_setup_spnego(struct composite_context *c,
|
||||
struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io,
|
||||
struct smbcli_request **req)
|
||||
{
|
||||
struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
|
||||
NTSTATUS status, session_key_err;
|
||||
DATA_BLOB session_key = data_blob(NULL, 0);
|
||||
DATA_BLOB null_data_blob = data_blob(NULL, 0);
|
||||
const char *chosen_oid = NULL;
|
||||
|
||||
state->setup.spnego.level = RAW_SESSSETUP_SPNEGO;
|
||||
state->setup.spnego.in.bufsize = session->transport->options.max_xmit;
|
||||
state->setup.spnego.in.mpx_max = session->transport->options.max_mux;
|
||||
state->setup.spnego.in.vc_num = 1;
|
||||
state->setup.spnego.in.sesskey = io->in.sesskey;
|
||||
state->setup.spnego.in.capabilities = io->in.capabilities;
|
||||
state->setup.spnego.in.os = "Unix";
|
||||
state->setup.spnego.in.lanman = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
|
||||
state->setup.spnego.in.workgroup = io->in.workgroup;
|
||||
|
||||
smbcli_temp_set_signing(session->transport);
|
||||
|
||||
status = gensec_client_start(session, &session->gensec, c->event_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
|
||||
|
||||
status = gensec_set_credentials(session->gensec, io->in.credentials);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC client credentails: %s\n",
|
||||
nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
|
||||
nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = gensec_set_target_service(session->gensec, "cifs");
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC target service: %s\n",
|
||||
nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (session->transport->negotiate.secblob.length) {
|
||||
chosen_oid = GENSEC_OID_SPNEGO;
|
||||
status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
|
||||
gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
|
||||
chosen_oid = GENSEC_OID_NTLMSSP;
|
||||
status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
|
||||
gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* without a sec blob, means raw NTLMSSP */
|
||||
chosen_oid = GENSEC_OID_NTLMSSP;
|
||||
status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
|
||||
gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen_oid == GENSEC_OID_SPNEGO) {
|
||||
status = gensec_update(session->gensec, state,
|
||||
session->transport->negotiate.secblob,
|
||||
&state->setup.spnego.in.secblob);
|
||||
} else {
|
||||
status = gensec_update(session->gensec, state,
|
||||
data_blob(NULL, 0),
|
||||
&state->setup.spnego.in.secblob);
|
||||
|
||||
}
|
||||
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed initial gensec_update with mechanism %s: %s\n",
|
||||
gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
state->gensec_status = status;
|
||||
|
||||
session_key_err = gensec_session_key(session->gensec, &session_key);
|
||||
if (NT_STATUS_IS_OK(session_key_err)) {
|
||||
smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
|
||||
}
|
||||
|
||||
*req = smb_raw_sesssetup_send(session, &state->setup);
|
||||
if (!*req) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
return (*req)->status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
composite session setup function that hides the details of all the
|
||||
different session setup varients, including the multi-pass nature of
|
||||
the spnego varient
|
||||
*/
|
||||
struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *session,
|
||||
struct smb_composite_sesssetup *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct sesssetup_state *state;
|
||||
NTSTATUS status;
|
||||
|
||||
c = talloc_zero(session, struct composite_context);
|
||||
if (c == NULL) return NULL;
|
||||
|
||||
state = talloc(c, struct sesssetup_state);
|
||||
if (state == NULL) {
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->io = io;
|
||||
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
c->private_data = state;
|
||||
c->event_ctx = session->transport->socket->event.ctx;
|
||||
|
||||
/* no session setup at all in earliest protocol varients */
|
||||
if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
|
||||
ZERO_STRUCT(io->out);
|
||||
composite_done(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* see what session setup interface we will use */
|
||||
if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
|
||||
status = session_setup_old(c, session, io, &state->req);
|
||||
} else if (!session->transport->options.use_spnego ||
|
||||
!(io->in.capabilities & CAP_EXTENDED_SECURITY)) {
|
||||
status = session_setup_nt1(c, session, io, &state->req);
|
||||
} else {
|
||||
status = session_setup_spnego(c, session, io, &state->req);
|
||||
}
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
|
||||
NT_STATUS_IS_OK(status)) {
|
||||
state->req->async.fn = request_handler;
|
||||
state->req->async.private = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
c->state = COMPOSITE_STATE_ERROR;
|
||||
c->status = status;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
receive a composite session setup reply
|
||||
*/
|
||||
NTSTATUS smb_composite_sesssetup_recv(struct composite_context *c)
|
||||
{
|
||||
NTSTATUS status;
|
||||
status = composite_wait(c);
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
sync version of smb_composite_sesssetup
|
||||
*/
|
||||
NTSTATUS smb_composite_sesssetup(struct smbcli_session *session, struct smb_composite_sesssetup *io)
|
||||
{
|
||||
struct composite_context *c = smb_composite_sesssetup_send(session, io);
|
||||
return smb_composite_sesssetup_recv(c);
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SMB composite request interfaces
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
this defines the structures associated with "composite"
|
||||
requests. Composite requests are libcli requests that are internally
|
||||
implemented as multiple libcli/raw/ calls, but can be treated as a
|
||||
single call via these composite calls. The composite calls are
|
||||
particularly designed to be used in async applications
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
a composite open/read(s)/close request that loads a whole file
|
||||
into memory. Used as a demo of the composite system.
|
||||
*/
|
||||
struct smb_composite_loadfile {
|
||||
struct {
|
||||
const char *fname;
|
||||
} in;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t size;
|
||||
} out;
|
||||
};
|
||||
|
||||
struct smb_composite_fetchfile {
|
||||
struct {
|
||||
const char *dest_host;
|
||||
int port;
|
||||
const char *called_name;
|
||||
const char *service;
|
||||
const char *service_type;
|
||||
struct cli_credentials *credentials;
|
||||
const char *workgroup;
|
||||
const char *filename;
|
||||
} in;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t size;
|
||||
} out;
|
||||
};
|
||||
|
||||
/*
|
||||
a composite open/write(s)/close request that saves a whole file from
|
||||
memory. Used as a demo of the composite system.
|
||||
*/
|
||||
struct smb_composite_savefile {
|
||||
struct {
|
||||
const char *fname;
|
||||
uint8_t *data;
|
||||
uint32_t size;
|
||||
} in;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
a composite request for a full connection to a remote server. Includes
|
||||
|
||||
- socket establishment
|
||||
- session request
|
||||
- negprot
|
||||
- session setup
|
||||
- tree connect
|
||||
*/
|
||||
struct smb_composite_connect {
|
||||
struct {
|
||||
const char *dest_host;
|
||||
int port;
|
||||
const char *called_name;
|
||||
const char *service;
|
||||
const char *service_type;
|
||||
struct cli_credentials *credentials;
|
||||
BOOL fallback_to_anonymous;
|
||||
const char *workgroup;
|
||||
} in;
|
||||
struct {
|
||||
struct smbcli_tree *tree;
|
||||
BOOL anonymous_fallback_done;
|
||||
} out;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
generic session setup interface that takes care of which
|
||||
session setup varient to use
|
||||
*/
|
||||
struct smb_composite_sesssetup {
|
||||
struct {
|
||||
uint32_t sesskey;
|
||||
uint32_t capabilities;
|
||||
struct cli_credentials *credentials;
|
||||
const char *workgroup;
|
||||
} in;
|
||||
struct {
|
||||
uint16_t vuid;
|
||||
} out;
|
||||
};
|
||||
|
||||
/*
|
||||
query file system info
|
||||
*/
|
||||
struct smb_composite_fsinfo {
|
||||
struct {
|
||||
const char *dest_host;
|
||||
int port;
|
||||
const char *called_name;
|
||||
const char *service;
|
||||
const char *service_type;
|
||||
struct cli_credentials *credentials;
|
||||
const char *workgroup;
|
||||
enum smb_fsinfo_level level;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
union smb_fsinfo *fsinfo;
|
||||
} out;
|
||||
};
|
||||
|
||||
/*
|
||||
composite call for appending new acl to the file's security descriptor and get
|
||||
new full acl
|
||||
*/
|
||||
|
||||
struct smb_composite_appendacl {
|
||||
struct {
|
||||
const char *fname;
|
||||
|
||||
const struct security_descriptor *sd;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
struct security_descriptor *sd;
|
||||
} out;
|
||||
};
|
||||
|
||||
/*
|
||||
a composite API to fire connect() calls to multiple targets, picking the
|
||||
first one.
|
||||
*/
|
||||
|
||||
struct smb_composite_connectmulti {
|
||||
struct {
|
||||
int num_dests;
|
||||
const char **hostnames;
|
||||
const char **addresses;
|
||||
int *ports; /* Either NULL for lp_smb_ports() per
|
||||
* destination or a list of explicit ports */
|
||||
} in;
|
||||
struct {
|
||||
struct smbcli_socket *socket;
|
||||
} out;
|
||||
};
|
||||
|
||||
struct smbcli_session;
|
||||
|
||||
#include "libcli/smb_composite/proto.h"
|
||||
Reference in New Issue
Block a user