wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
@@ -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);
}
+500
View File
@@ -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);
}
+202
View File
@@ -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"