diff options
Diffstat (limited to 'source4/libcli/raw')
30 files changed, 12745 insertions, 0 deletions
diff --git a/source4/libcli/raw/README b/source4/libcli/raw/README new file mode 100644 index 0000000..cb3e507 --- /dev/null +++ b/source4/libcli/raw/README @@ -0,0 +1,5 @@ +Design notes for client library restructure: + +1 - no references to cli_state should exist in libcli/raw. +2 - all interfaces to functions in this directory should use cli_session or cli_tree as + the primary context structure
\ No newline at end of file diff --git a/source4/libcli/raw/clierror.c b/source4/libcli/raw/clierror.c new file mode 100644 index 0000000..a417486 --- /dev/null +++ b/source4/libcli/raw/clierror.c @@ -0,0 +1,73 @@ +/* + Unix SMB/CIFS implementation. + client error handling routines + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) James Myers 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + + +/*************************************************************************** + Return an error message from the last response +****************************************************************************/ +_PUBLIC_ const char *smbcli_errstr(struct smbcli_tree *tree) +{ + switch (tree->session->transport->error.etype) { + case ETYPE_SMB: + return nt_errstr(tree->session->transport->error.e.nt_status); + + case ETYPE_SOCKET: + return "socket_error"; + + case ETYPE_NBT: + return "nbt_error"; + + case ETYPE_NONE: + return "no_error"; + } + return NULL; +} + + +/* Return the 32-bit NT status code from the last packet */ +_PUBLIC_ NTSTATUS smbcli_nt_error(struct smbcli_tree *tree) +{ + switch (tree->session->transport->error.etype) { + case ETYPE_SMB: + return tree->session->transport->error.e.nt_status; + + case ETYPE_SOCKET: + return NT_STATUS_UNSUCCESSFUL; + + case ETYPE_NBT: + return NT_STATUS_UNSUCCESSFUL; + + case ETYPE_NONE: + return NT_STATUS_OK; + } + + return NT_STATUS_UNSUCCESSFUL; +} + + +/* Return true if the last packet was an error */ +bool smbcli_is_error(struct smbcli_tree *tree) +{ + return NT_STATUS_IS_ERR(smbcli_nt_error(tree)); +} diff --git a/source4/libcli/raw/clioplock.c b/source4/libcli/raw/clioplock.c new file mode 100644 index 0000000..6c04843 --- /dev/null +++ b/source4/libcli/raw/clioplock.c @@ -0,0 +1,66 @@ +/* + Unix SMB/CIFS implementation. + SMB client oplock functions + Copyright (C) Andrew Tridgell 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/**************************************************************************** +send an ack for an oplock break request +****************************************************************************/ +_PUBLIC_ bool smbcli_oplock_ack(struct smbcli_tree *tree, uint16_t fnum, uint16_t ack_level) +{ + bool ret; + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBlockingX, 8, 0); + if (req == NULL) { + return false; + } + + SSVAL(req->out.vwv,VWV(0),0xFF); + SSVAL(req->out.vwv,VWV(1),0); + SSVAL(req->out.vwv,VWV(2),fnum); + SCVAL(req->out.vwv,VWV(3),LOCKING_ANDX_OPLOCK_RELEASE); + SCVAL(req->out.vwv,VWV(3)+1,ack_level); + SIVAL(req->out.vwv,VWV(4),0); + SSVAL(req->out.vwv,VWV(6),0); + SSVAL(req->out.vwv,VWV(7),0); + + /* + * The low level code knows it is a + * one way request by looking at SMBlockingX, + * wct == 8 and LOCKING_ANDX_OPLOCK_RELEASE + */ + ret = smbcli_request_send(req); + + return ret; +} + + +/**************************************************************************** +set the oplock handler for a connection +****************************************************************************/ +_PUBLIC_ void smbcli_oplock_handler(struct smbcli_transport *transport, + bool (*handler)(struct smbcli_transport *, uint16_t, uint16_t, uint8_t, void *), + void *private_data) +{ + transport->oplock.handler = handler; + transport->oplock.private_data = private_data; +} diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c new file mode 100644 index 0000000..5c3d7f9 --- /dev/null +++ b/source4/libcli/raw/clisession.c @@ -0,0 +1,310 @@ +/* + Unix SMB/CIFS implementation. + SMB client session context management functions + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "system/filesys.h" +#include "../libcli/smb/smbXcli_base.h" + +#define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \ + req = smbcli_request_setup_session(session, cmd, wct, buflen); \ + if (!req) return NULL; \ +} while (0) + + +/**************************************************************************** + Initialize the session context +****************************************************************************/ +struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport, + TALLOC_CTX *parent_ctx, bool primary, + struct smbcli_session_options options) +{ + struct smbcli_session *session; + uint16_t flags2; + uint32_t capabilities; + + session = talloc_zero(parent_ctx, struct smbcli_session); + if (!session) { + return NULL; + } + + if (primary) { + session->transport = talloc_steal(session, transport); + } else { + session->transport = talloc_reference(session, transport); + } + session->pid = (uint32_t)getpid(); + session->vuid = UID_FIELD_INVALID; + session->options = options; + + /* + * for now session->vuid is still used by the callers, but we call: + * smb1cli_session_set_id(session->smbXcli, session->vuid); + * before using session->smbXcli, in future we should remove + * session->vuid. + */ + session->smbXcli = smbXcli_session_create(session, transport->conn); + if (session->smbXcli == NULL) { + talloc_free(session); + return NULL; + } + + capabilities = transport->negotiate.capabilities; + + flags2 = FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_EXTENDED_ATTRIBUTES; + + if (capabilities & CAP_UNICODE) { + flags2 |= FLAGS2_UNICODE_STRINGS; + } + if (capabilities & CAP_STATUS32) { + flags2 |= FLAGS2_32_BIT_ERROR_CODES; + } + if (capabilities & CAP_EXTENDED_SECURITY) { + flags2 |= FLAGS2_EXTENDED_SECURITY; + } + if (smb1cli_conn_signing_is_active(session->transport->conn)) { + flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; + } + + session->flags2 = flags2; + + return session; +} + +/**************************************************************************** + Perform a session setup (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_sesssetup_send(struct smbcli_session *session, + union smb_sesssetup *parms) +{ + struct smbcli_request *req = NULL; + + switch (parms->old.level) { + case RAW_SESSSETUP_OLD: + SETUP_REQUEST_SESSION(SMBsesssetupX, 10, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv,VWV(2),parms->old.in.bufsize); + SSVAL(req->out.vwv,VWV(3),parms->old.in.mpx_max); + SSVAL(req->out.vwv,VWV(4),parms->old.in.vc_num); + SIVAL(req->out.vwv,VWV(5),parms->old.in.sesskey); + SSVAL(req->out.vwv,VWV(7),parms->old.in.password.length); + SIVAL(req->out.vwv,VWV(8), 0); /* reserved */ + smbcli_req_append_blob(req, &parms->old.in.password); + smbcli_req_append_string(req, parms->old.in.user, STR_TERMINATE); + smbcli_req_append_string(req, parms->old.in.domain, STR_TERMINATE|STR_UPPER); + smbcli_req_append_string(req, parms->old.in.os, STR_TERMINATE); + smbcli_req_append_string(req, parms->old.in.lanman, STR_TERMINATE); + break; + + case RAW_SESSSETUP_NT1: + SETUP_REQUEST_SESSION(SMBsesssetupX, 13, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->nt1.in.bufsize); + SSVAL(req->out.vwv, VWV(3), parms->nt1.in.mpx_max); + SSVAL(req->out.vwv, VWV(4), parms->nt1.in.vc_num); + SIVAL(req->out.vwv, VWV(5), parms->nt1.in.sesskey); + SSVAL(req->out.vwv, VWV(7), parms->nt1.in.password1.length); + SSVAL(req->out.vwv, VWV(8), parms->nt1.in.password2.length); + SIVAL(req->out.vwv, VWV(9), 0); /* reserved */ + SIVAL(req->out.vwv, VWV(11), parms->nt1.in.capabilities); + smbcli_req_append_blob(req, &parms->nt1.in.password1); + smbcli_req_append_blob(req, &parms->nt1.in.password2); + smbcli_req_append_string(req, parms->nt1.in.user, STR_TERMINATE); + smbcli_req_append_string(req, parms->nt1.in.domain, STR_TERMINATE|STR_UPPER); + smbcli_req_append_string(req, parms->nt1.in.os, STR_TERMINATE); + smbcli_req_append_string(req, parms->nt1.in.lanman, STR_TERMINATE); + break; + + case RAW_SESSSETUP_SPNEGO: + SETUP_REQUEST_SESSION(SMBsesssetupX, 12, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->spnego.in.bufsize); + SSVAL(req->out.vwv, VWV(3), parms->spnego.in.mpx_max); + SSVAL(req->out.vwv, VWV(4), parms->spnego.in.vc_num); + SIVAL(req->out.vwv, VWV(5), parms->spnego.in.sesskey); + SSVAL(req->out.vwv, VWV(7), parms->spnego.in.secblob.length); + SIVAL(req->out.vwv, VWV(8), 0); /* reserved */ + SIVAL(req->out.vwv, VWV(10), parms->spnego.in.capabilities); + smbcli_req_append_blob(req, &parms->spnego.in.secblob); + smbcli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE); + smbcli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE); + smbcli_req_append_string(req, parms->spnego.in.workgroup, STR_TERMINATE); + break; + + case RAW_SESSSETUP_SMB2: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + + +/**************************************************************************** + Perform a session setup (async recv) +****************************************************************************/ +NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_sesssetup *parms) +{ + uint16_t len; + uint8_t *p; + + if (!smbcli_request_receive(req)) { + return smbcli_request_destroy(req); + } + + if (!NT_STATUS_IS_OK(req->status) && + !NT_STATUS_EQUAL(req->status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { + return smbcli_request_destroy(req); + } + + switch (parms->old.level) { + case RAW_SESSSETUP_OLD: + SMBCLI_CHECK_WCT(req, 3); + ZERO_STRUCT(parms->old.out); + parms->old.out.vuid = SVAL(req->in.hdr, HDR_UID); + parms->old.out.action = SVAL(req->in.vwv, VWV(2)); + p = req->in.data; + if (p) { + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE); + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE); + } + break; + + case RAW_SESSSETUP_NT1: + SMBCLI_CHECK_WCT(req, 3); + ZERO_STRUCT(parms->nt1.out); + parms->nt1.out.vuid = SVAL(req->in.hdr, HDR_UID); + parms->nt1.out.action = SVAL(req->in.vwv, VWV(2)); + p = req->in.data; + if (p) { + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE); + if (p < (req->in.data + req->in.data_size)) { + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE); + } + } + break; + + case RAW_SESSSETUP_SPNEGO: + SMBCLI_CHECK_WCT(req, 4); + ZERO_STRUCT(parms->spnego.out); + parms->spnego.out.vuid = SVAL(req->in.hdr, HDR_UID); + parms->spnego.out.action = SVAL(req->in.vwv, VWV(2)); + len = SVAL(req->in.vwv, VWV(3)); + p = req->in.data; + if (!p) { + break; + } + + parms->spnego.out.secblob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, p, len); + p += parms->spnego.out.secblob.length; + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); + break; + + case RAW_SESSSETUP_SMB2: + req->status = NT_STATUS_INTERNAL_ERROR; + break; + } + +failed: + return smbcli_request_destroy(req); +} + + +/* + Perform a session setup (sync interface) +*/ +NTSTATUS smb_raw_sesssetup(struct smbcli_session *session, + TALLOC_CTX *mem_ctx, union smb_sesssetup *parms) +{ + struct smbcli_request *req = smb_raw_sesssetup_send(session, parms); + return smb_raw_sesssetup_recv(req, mem_ctx, parms); +} + + +/**************************************************************************** + Send a ulogoff (async send) +*****************************************************************************/ +struct smbcli_request *smb_raw_ulogoff_send(struct smbcli_session *session) +{ + struct smbcli_request *req; + + SETUP_REQUEST_SESSION(SMBulogoffX, 2, 0); + + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Send a ulogoff (sync interface) +*****************************************************************************/ +NTSTATUS smb_raw_ulogoff(struct smbcli_session *session) +{ + struct smbcli_request *req = smb_raw_ulogoff_send(session); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + Send a exit (async send) +*****************************************************************************/ +struct smbcli_request *smb_raw_exit_send(struct smbcli_session *session) +{ + struct smbcli_request *req; + + SETUP_REQUEST_SESSION(SMBexit, 0, 0); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Send a exit (sync interface) +*****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_exit(struct smbcli_session *session) +{ + struct smbcli_request *req = smb_raw_exit_send(session); + return smbcli_request_simple_recv(req); +} diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c new file mode 100644 index 0000000..1959a93 --- /dev/null +++ b/source4/libcli/raw/clisocket.c @@ -0,0 +1,459 @@ +/* + Unix SMB/CIFS implementation. + + SMB client socket context management functions + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/network.h" +#include "../lib/async_req/async_sock.h" +#include "../lib/util/tevent_ntstatus.h" +#include "lib/events/events.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" +#include "lib/socket/socket.h" +#include "libcli/resolve/resolve.h" +#include "param/param.h" +#include "libcli/raw/raw_proto.h" +#include "../libcli/smb/read_smb.h" + +struct smbcli_transport_connect_state { + struct tevent_context *ev; + struct socket_context *sock; + struct tevent_req *io_req; + uint8_t *request; + struct iovec iov; + uint8_t *response; +}; + +static void smbcli_transport_connect_cleanup(struct tevent_req *req, + enum tevent_req_state req_state); +static void smbcli_transport_connect_writev_done(struct tevent_req *subreq); +static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq); + +static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct socket_context *sock, + uint16_t port, + uint32_t timeout_msec, + struct nbt_name *calling, + struct nbt_name *called) +{ + struct tevent_req *req; + struct smbcli_transport_connect_state *state; + struct tevent_req *subreq; + DATA_BLOB calling_blob, called_blob; + uint8_t *p; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct smbcli_transport_connect_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->sock = sock; + + if (port != 139) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + tevent_req_set_cleanup_fn(req, smbcli_transport_connect_cleanup); + + status = nbt_name_to_blob(state, &calling_blob, calling); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + status = nbt_name_to_blob(state, &called_blob, called); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + state->request = talloc_array(state, uint8_t, + NBT_HDR_SIZE + + called_blob.length + + calling_blob.length); + if (tevent_req_nomem(state->request, req)) { + return tevent_req_post(req, ev); + } + + /* put in the destination name */ + p = state->request + NBT_HDR_SIZE; + memcpy(p, called_blob.data, called_blob.length); + p += called_blob.length; + + memcpy(p, calling_blob.data, calling_blob.length); + p += calling_blob.length; + + _smb_setlen_nbt(state->request, + PTR_DIFF(p, state->request) - NBT_HDR_SIZE); + SCVAL(state->request, 0, NBSSrequest); + + state->iov.iov_len = talloc_array_length(state->request); + state->iov.iov_base = (void *)state->request; + + subreq = writev_send(state, ev, NULL, + sock->fd, + true, /* err_on_readability */ + &state->iov, 1); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, + smbcli_transport_connect_writev_done, + req); + state->io_req = subreq; + + if (timeout_msec > 0) { + struct timeval endtime; + + endtime = timeval_current_ofs_msec(timeout_msec); + if (!tevent_req_set_endtime(req, ev, endtime)) { + return tevent_req_post(req, ev); + } + } + + return req; +} + +static void smbcli_transport_connect_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) +{ + struct smbcli_transport_connect_state *state = + tevent_req_data(req, + struct smbcli_transport_connect_state); + + TALLOC_FREE(state->io_req); + + if (state->sock == NULL) { + return; + } + + if (state->sock->fd == -1) { + return; + } + + if (req_state == TEVENT_REQ_DONE) { + /* + * we keep the socket open for the caller to use + */ + state->sock = NULL; + return; + } + + close(state->sock->fd); + state->sock->fd = -1; + state->sock = NULL; +} + +static void smbcli_transport_connect_writev_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smbcli_transport_connect_state *state = + tevent_req_data(req, + struct smbcli_transport_connect_state); + ssize_t ret; + int err; + + state->io_req = NULL; + + ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + NTSTATUS status = map_nt_error_from_unix_common(err); + tevent_req_nterror(req, status); + return; + } + + subreq = read_smb_send(state, state->ev, + state->sock->fd); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, + smbcli_transport_connect_read_smb_done, + req); + state->io_req = subreq; +} + +static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smbcli_transport_connect_state *state = + tevent_req_data(req, + struct smbcli_transport_connect_state); + ssize_t ret; + int err; + NTSTATUS status; + uint8_t error; + + state->io_req = NULL; + + ret = read_smb_recv(subreq, state, + &state->response, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + status = map_nt_error_from_unix_common(err); + tevent_req_nterror(req, status); + return; + } + + if (ret < 4) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + switch (CVAL(state->response, 0)) { + case NBSSpositive: + tevent_req_done(req); + return; + + case NBSSnegative: + if (ret < 5) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + error = CVAL(state->response, 4); + switch (error) { + case 0x80: + case 0x81: + status = NT_STATUS_REMOTE_NOT_LISTENING; + break; + case 0x82: + status = NT_STATUS_RESOURCE_NAME_NOT_FOUND; + break; + case 0x83: + status = NT_STATUS_REMOTE_RESOURCES; + break; + default: + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + break; + } + break; + + case NBSSretarget: + DEBUG(1,("Warning: session retarget not supported\n")); + status = NT_STATUS_NOT_SUPPORTED; + break; + + default: + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + break; + } + + tevent_req_nterror(req, status); +} + +static NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct sock_connect_state { + struct composite_context *ctx; + const char *host_name; + int num_ports; + uint16_t *ports; + const char *socket_options; + struct smbcli_socket *result; + struct socket_connect_multi_ex multi_ex; + struct nbt_name calling; + struct nbt_name called; +}; + +/* + connect a smbcli_socket context to an IP/port pair + if port is 0 then choose 445 then 139 +*/ + +static struct tevent_req *smbcli_sock_establish_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct socket_context *sock, + struct socket_address *addr, + void *private_data) +{ + struct sock_connect_state *state = + talloc_get_type_abort(private_data, + struct sock_connect_state); + uint32_t timeout_msec = 15 * 1000; + + return smbcli_transport_connect_send(state, + ev, + sock, + addr->port, + timeout_msec, + &state->calling, + &state->called); +} + +static NTSTATUS smbcli_sock_establish_recv(struct tevent_req *req) +{ + return smbcli_transport_connect_recv(req); +} + +static void smbcli_sock_connect_recv_conn(struct composite_context *ctx); + +struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx, + const char *host_addr, + const char **ports, + const char *host_name, + struct resolve_context *resolve_ctx, + struct tevent_context *event_ctx, + const char *socket_options, + struct nbt_name *calling, + struct nbt_name *called) +{ + struct composite_context *result, *ctx; + struct sock_connect_state *state; + NTSTATUS status; + int i; + + result = talloc_zero(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + + result->event_ctx = event_ctx; + if (result->event_ctx == NULL) goto failed; + + state = talloc(result, struct sock_connect_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->host_name = talloc_strdup(state, host_name); + if (state->host_name == NULL) goto failed; + + state->num_ports = str_list_length(ports); + state->ports = talloc_array(state, uint16_t, state->num_ports); + if (state->ports == NULL) goto failed; + for (i=0;ports[i];i++) { + state->ports[i] = atoi(ports[i]); + } + state->socket_options = talloc_reference(state, socket_options); + + if (!host_addr) { + host_addr = host_name; + } + + state->multi_ex.private_data = state; + state->multi_ex.establish_send = smbcli_sock_establish_send; + state->multi_ex.establish_recv = smbcli_sock_establish_recv; + + status = nbt_name_dup(state, calling, &state->calling); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + status = nbt_name_dup(state, called, &state->called); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + ctx = socket_connect_multi_ex_send(state, host_addr, + state->num_ports, state->ports, + resolve_ctx, + state->ctx->event_ctx, + &state->multi_ex); + if (ctx == NULL) goto failed; + ctx->async.fn = smbcli_sock_connect_recv_conn; + ctx->async.private_data = state; + return result; + +failed: + talloc_free(result); + return NULL; +} + +static void smbcli_sock_connect_recv_conn(struct composite_context *ctx) +{ + struct sock_connect_state *state = + talloc_get_type(ctx->async.private_data, + struct sock_connect_state); + struct socket_context *sock; + uint16_t port; + + state->ctx->status = socket_connect_multi_ex_recv(ctx, state, &sock, + &port); + if (!composite_is_ok(state->ctx)) return; + + state->ctx->status = + socket_set_option(sock, state->socket_options, NULL); + if (!composite_is_ok(state->ctx)) return; + + + state->result = talloc_zero(state, struct smbcli_socket); + if (composite_nomem(state->result, state->ctx)) return; + + state->result->sock = talloc_steal(state->result, sock); + state->result->port = port; + state->result->hostname = talloc_steal(sock, state->host_name); + + state->result->event.ctx = state->ctx->event_ctx; + if (composite_nomem(state->result->event.ctx, state->ctx)) return; + + composite_done(state->ctx); +} + +/* + finish a smbcli_sock_connect_send() operation +*/ +NTSTATUS smbcli_sock_connect_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + struct smbcli_socket **result) +{ + NTSTATUS status = composite_wait(c); + if (NT_STATUS_IS_OK(status)) { + struct sock_connect_state *state = + talloc_get_type(c->private_data, + struct sock_connect_state); + *result = talloc_steal(mem_ctx, state->result); + } + talloc_free(c); + return status; +} + +/* + connect a smbcli_socket context to an IP/port pair + if port is 0 then choose the ports listed in smb.conf (normally 445 then 139) + + sync version of the function +*/ +NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx, + const char *host_addr, const char **ports, + const char *host_name, + struct resolve_context *resolve_ctx, + struct tevent_context *event_ctx, + const char *socket_options, + struct nbt_name *calling, + struct nbt_name *called, + struct smbcli_socket **result) +{ + struct composite_context *c = + smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name, + resolve_ctx, + event_ctx, socket_options, + calling, called); + return smbcli_sock_connect_recv(c, mem_ctx, result); +} diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c new file mode 100644 index 0000000..573e98a --- /dev/null +++ b/source4/libcli/raw/clitransport.c @@ -0,0 +1,673 @@ +/* + Unix SMB/CIFS implementation. + SMB client transport context management functions + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/network.h" +#include "../lib/async_req/async_sock.h" +#include "../lib/util/tevent_ntstatus.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "lib/socket/socket.h" +#include "lib/events/events.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "../libcli/nbt/libnbt.h" +#include "../libcli/smb/smbXcli_base.h" +#include "../libcli/smb/read_smb.h" + +/* + destroy a transport + */ +static int transport_destructor(struct smbcli_transport *transport) +{ + smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT); + return 0; +} + +/* + create a transport structure based on an established socket +*/ +struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock, + TALLOC_CTX *parent_ctx, + bool primary, + struct smbcli_options *options) +{ + struct smbcli_transport *transport; + uint32_t smb1_capabilities; + + transport = talloc_zero(parent_ctx, struct smbcli_transport); + if (!transport) return NULL; + + transport->ev = sock->event.ctx; + transport->options = *options; + + if (transport->options.max_protocol == PROTOCOL_DEFAULT) { + transport->options.max_protocol = PROTOCOL_NT1; + } + + if (transport->options.max_protocol > PROTOCOL_NT1) { + transport->options.max_protocol = PROTOCOL_NT1; + } + + TALLOC_FREE(sock->event.fde); + TALLOC_FREE(sock->event.te); + + smb1_capabilities = 0; + smb1_capabilities |= CAP_LARGE_FILES; + smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; + smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; + smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS; + smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; + smb1_capabilities |= CAP_LWIO; + + if (options->ntstatus_support) { + smb1_capabilities |= CAP_STATUS32; + } + + if (options->unicode) { + smb1_capabilities |= CAP_UNICODE; + } + + if (options->use_spnego) { + smb1_capabilities |= CAP_EXTENDED_SECURITY; + } + + if (options->use_level2_oplocks) { + smb1_capabilities |= CAP_LEVEL_II_OPLOCKS; + } + + transport->conn = smbXcli_conn_create(transport, + sock->sock->fd, + sock->hostname, + options->signing, + smb1_capabilities, + NULL, /* client_guid */ + 0, /* smb2_capabilities */ + NULL); /* smb3_ciphers */ + if (transport->conn == NULL) { + TALLOC_FREE(sock); + TALLOC_FREE(transport); + return NULL; + } + sock->sock->fd = -1; + TALLOC_FREE(sock); + + talloc_set_destructor(transport, transport_destructor); + + return transport; +} + +/* + create a transport structure based on an established socket +*/ +NTSTATUS smbcli_transport_raw_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbXcli_conn **_conn, + const struct smbcli_options *options, + struct smbcli_transport **_transport) +{ + struct smbcli_transport *transport = NULL; + NTSTATUS status; + + if (*_conn == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + transport = talloc_zero(mem_ctx, struct smbcli_transport); + if (transport == NULL) { + return NT_STATUS_NO_MEMORY; + } + + transport->ev = ev; + transport->options = *options; + + /* + * First only set the pointer without move. + */ + transport->conn = *_conn; + status = smb_raw_negotiate_fill_transport(transport); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(transport); + return status; + } + + talloc_set_destructor(transport, transport_destructor); + + /* + * Now move it away from the caller... + */ + transport->conn = talloc_move(transport, _conn); + *_transport = transport; + return NT_STATUS_OK; +} + +/* + mark the transport as dead +*/ +void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status) +{ + if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { + status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + } + if (NT_STATUS_IS_OK(status)) { + status = NT_STATUS_LOCAL_DISCONNECT; + } + + smbXcli_conn_disconnect(transport->conn, status); +} + +static void idle_handler(struct tevent_context *ev, + struct tevent_timer *te, struct timeval t, void *private_data) +{ + struct smbcli_transport *transport = talloc_get_type(private_data, + struct smbcli_transport); + struct timeval next; + + transport->idle.func(transport, transport->idle.private_data); + + if (transport->idle.func == NULL) { + return; + } + + if (!smbXcli_conn_is_connected(transport->conn)) { + return; + } + + next = timeval_current_ofs_usec(transport->idle.period); + + transport->idle.te = tevent_add_timer(transport->ev, + transport, + next, + idle_handler, + transport); +} + +/* + setup the idle handler for a transport + the period is in microseconds +*/ +_PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, + void (*idle_func)(struct smbcli_transport *, void *), + uint64_t period, + void *private_data) +{ + TALLOC_FREE(transport->idle.te); + ZERO_STRUCT(transport->idle); + + if (idle_func == NULL) { + return; + } + + if (!smbXcli_conn_is_connected(transport->conn)) { + return; + } + + transport->idle.func = idle_func; + transport->idle.private_data = private_data; + transport->idle.period = period; + + transport->idle.te = tevent_add_timer(transport->ev, + transport, + timeval_current_ofs_usec(period), + idle_handler, + transport); +} + +/* + process some read/write requests that are pending + return false if the socket is dead +*/ +_PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport) +{ + struct tevent_req *subreq = NULL; + int ret; + + if (!smbXcli_conn_is_connected(transport->conn)) { + return false; + } + + if (!smbXcli_conn_has_async_calls(transport->conn)) { + return true; + } + + /* + * do not block for more than 500 micro seconds + */ + subreq = tevent_wakeup_send(transport, + transport->ev, + timeval_current_ofs_usec(500)); + if (subreq == NULL) { + return false; + } + + ret = tevent_loop_once(transport->ev); + if (ret != 0) { + return false; + } + + TALLOC_FREE(subreq); + + if (!smbXcli_conn_is_connected(transport->conn)) { + return false; + } + + return true; +} + +static void smbcli_transport_break_handler(struct tevent_req *subreq); +static void smbcli_request_done(struct tevent_req *subreq); + +struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req) +{ + struct smbcli_transport *transport = req->transport; + uint8_t smb_command; + uint8_t additional_flags; + uint8_t clear_flags; + uint16_t additional_flags2; + uint16_t clear_flags2; + uint32_t pid; + struct smbXcli_tcon *tcon = NULL; + struct smbXcli_session *session = NULL; + uint32_t timeout_msec = transport->options.request_timeout * 1000; + struct iovec *bytes_iov = NULL; + struct tevent_req *subreq = NULL; + + smb_command = SVAL(req->out.hdr, HDR_COM); + additional_flags = CVAL(req->out.hdr, HDR_FLG); + additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); + pid = SVAL(req->out.hdr, HDR_PID); + pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; + + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; + + if (req->session) { + session = req->session->smbXcli; + } + + if (req->tree) { + tcon = req->tree->smbXcli; + } + + bytes_iov = talloc(req, struct iovec); + if (bytes_iov == NULL) { + return NULL; + } + bytes_iov->iov_base = (void *)req->out.data; + bytes_iov->iov_len = req->out.data_size; + + subreq = smb1cli_req_create(req, + transport->ev, + transport->conn, + smb_command, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, + tcon, + session, + req->out.wct, + (uint16_t *)req->out.vwv, + 1, bytes_iov); + if (subreq == NULL) { + return NULL; + } + + ZERO_STRUCT(req->out); + + return subreq; +} + +/* + put a request into the send queue +*/ +void smbcli_transport_send(struct smbcli_request *req) +{ + struct smbcli_transport *transport = req->transport; + NTSTATUS status; + bool need_pending_break = false; + struct tevent_req *subreq = NULL; + size_t i; + size_t num_subreqs = 0; + + if (transport->oplock.handler) { + need_pending_break = true; + } + + if (transport->break_subreq) { + need_pending_break = false; + } + + if (need_pending_break) { + subreq = smb1cli_req_create(transport, + transport->ev, + transport->conn, + 0, /* smb_command */ + 0, /* additional_flags */ + 0, /* clear_flags */ + 0, /* additional_flags2 */ + 0, /* clear_flags2 */ + 0, /* timeout_msec */ + 0, /* pid */ + NULL, /* tcon */ + NULL, /* session */ + 0, /* wct */ + NULL, /* vwv */ + 0, /* iov_count */ + NULL); /* bytes_iov */ + if (subreq != NULL) { + smb1cli_req_set_mid(subreq, 0xFFFF); + smbXcli_req_set_pending(subreq); + tevent_req_set_callback(subreq, + smbcli_transport_break_handler, + transport); + transport->break_subreq = subreq; + subreq = NULL; + } + } + + subreq = smbcli_transport_setup_subreq(req); + if (subreq == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_NO_MEMORY; + return; + } + + for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) { + if (req->subreqs[i] == NULL) { + req->subreqs[i] = subreq; + subreq = NULL; + } + if (req->subreqs[i] == NULL) { + break; + } + + if (!tevent_req_is_in_progress(req->subreqs[i])) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_INTERNAL_ERROR; + return; + } + } + num_subreqs = i; + + req->state = SMBCLI_REQUEST_RECV; + tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req); + + status = smb1cli_req_chain_submit(req->subreqs, num_subreqs); + if (!NT_STATUS_IS_OK(status)) { + req->status = status; + req->state = SMBCLI_REQUEST_ERROR; + smbXcli_conn_disconnect(transport->conn, status); + } +} + +static void smbcli_request_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + ssize_t len; + size_t i; + uint8_t *hdr = NULL; + uint8_t wct = 0; + uint16_t *vwv = NULL; + uint32_t num_bytes = 0; + uint8_t *bytes = NULL; + struct iovec *recv_iov = NULL; + uint8_t *inbuf = NULL; + + req->status = smb1cli_req_recv(req->subreqs[0], req, + &recv_iov, + &hdr, + &wct, + &vwv, + NULL, /* pvwv_offset */ + &num_bytes, + &bytes, + NULL, /* pbytes_offset */ + &inbuf, + NULL, 0); /* expected */ + TALLOC_FREE(req->subreqs[0]); + if (!NT_STATUS_IS_OK(req->status)) { + if (recv_iov == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SOCKET; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + } + + /* + * For SMBreadBraw hdr is NULL + */ + len = recv_iov[0].iov_len; + for (i=1; hdr != NULL && i < 3; i++) { + uint8_t *p = recv_iov[i-1].iov_base; + uint8_t *c1 = recv_iov[i].iov_base; + uint8_t *c2 = p + recv_iov[i-1].iov_len; + + len += recv_iov[i].iov_len; + + c2 += i; + len += i; + + if (recv_iov[i].iov_len == 0) { + continue; + } + + if (c1 != c2) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_INTERNAL_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + } + + /* fill in the 'in' portion of the matching request */ + req->in.buffer = inbuf; + req->in.size = NBT_HDR_SIZE + len; + req->in.allocated = req->in.size; + + req->in.hdr = hdr; + req->in.vwv = (uint8_t *)vwv; + req->in.wct = wct; + req->in.data = bytes; + req->in.data_size = num_bytes; + req->in.ptr = req->in.data; + if (hdr != NULL) { + req->flags2 = SVAL(req->in.hdr, HDR_FLG2); + } + + smb_setup_bufinfo(req); + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } +} + +static void smbcli_transport_break_handler(struct tevent_req *subreq) +{ + struct smbcli_transport *transport = + tevent_req_callback_data(subreq, + struct smbcli_transport); + NTSTATUS status; + struct iovec *recv_iov = NULL; + uint8_t *hdr = NULL; + uint16_t *vwv = NULL; + const struct smb1cli_req_expected_response expected[] = { + { + .status = NT_STATUS_OK, + .wct = 8, + } + }; + uint16_t tid; + uint16_t fnum; + uint8_t level; + + transport->break_subreq = NULL; + + status = smb1cli_req_recv(subreq, transport, + &recv_iov, + &hdr, + NULL, /* pwct */ + &vwv, + NULL, /* pvwv_offset */ + NULL, /* pnum_bytes */ + NULL, /* pbytes */ + NULL, /* pbytes_offset */ + NULL, /* pinbuf */ + expected, + ARRAY_SIZE(expected)); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(recv_iov); + smbcli_transport_dead(transport, status); + return; + } + + /* + * Setup the subreq to handle the + * next incoming SMB2 Break. + */ + subreq = smb1cli_req_create(transport, + transport->ev, + transport->conn, + 0, /* smb_command */ + 0, /* additional_flags */ + 0, /* clear_flags */ + 0, /* additional_flags2 */ + 0, /* clear_flags2 */ + 0, /* timeout_msec */ + 0, /* pid */ + NULL, /* tcon */ + NULL, /* session */ + 0, /* wct */ + NULL, /* vwv */ + 0, /* iov_count */ + NULL); /* bytes_iov */ + if (subreq != NULL) { + smb1cli_req_set_mid(subreq, 0xFFFF); + smbXcli_req_set_pending(subreq); + tevent_req_set_callback(subreq, + smbcli_transport_break_handler, + transport); + transport->break_subreq = subreq; + } + + tid = SVAL(hdr, HDR_TID); + fnum = SVAL(vwv+2, 0); + level = CVAL(vwv+3, 1); + + TALLOC_FREE(recv_iov); + + if (transport->oplock.handler) { + transport->oplock.handler(transport, tid, fnum, level, + transport->oplock.private_data); + } else { + DEBUG(5,("Got SMB oplock break with no handler\n")); + } + +} + + +/**************************************************************************** + Send an SMBecho (async send) +*****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport, + struct smb_echo *p) +{ + struct smbcli_request *req; + + req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size); + if (!req) return NULL; + + SSVAL(req->out.vwv, VWV(0), p->in.repeat_count); + + memcpy(req->out.data, p->in.data, p->in.size); + + ZERO_STRUCT(p->out); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + raw echo interface (async recv) +****************************************************************************/ +NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, + struct smb_echo *p) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + SMBCLI_CHECK_WCT(req, 1); + p->out.count++; + p->out.sequence_number = SVAL(req->in.vwv, VWV(0)); + p->out.size = req->in.data_size; + talloc_free(p->out.data); + p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size); + NT_STATUS_HAVE_NO_MEMORY(p->out.data); + + if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + + if (p->out.count == p->in.repeat_count) { + return smbcli_request_destroy(req); + } + + return NT_STATUS_OK; + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + Send a echo (sync interface) +*****************************************************************************/ +NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p) +{ + struct smbcli_request *req = smb_raw_echo_send(transport, p); + return smbcli_request_simple_recv(req); +} diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c new file mode 100644 index 0000000..e6b7c8a --- /dev/null +++ b/source4/libcli/raw/clitree.c @@ -0,0 +1,228 @@ +/* + Unix SMB/CIFS implementation. + + SMB client tree context management functions + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "libcli/smb_composite/smb_composite.h" +#include "../libcli/smb/smbXcli_base.h" + +#define SETUP_REQUEST_TREE(cmd, wct, buflen) do { \ + req = smbcli_request_setup(tree, cmd, wct, buflen); \ + if (!req) return NULL; \ +} while (0) + +/**************************************************************************** + Initialize the tree context +****************************************************************************/ +_PUBLIC_ struct smbcli_tree *smbcli_tree_init(struct smbcli_session *session, + TALLOC_CTX *parent_ctx, bool primary) +{ + struct smbcli_tree *tree; + + tree = talloc_zero(parent_ctx, struct smbcli_tree); + if (!tree) { + return NULL; + } + + if (primary) { + tree->session = talloc_steal(tree, session); + } else { + tree->session = talloc_reference(tree, session); + } + + tree->smbXcli = smbXcli_tcon_create(tree); + if (tree->smbXcli == NULL) { + talloc_free(tree); + return NULL; + } + + return tree; +} + +/**************************************************************************** + Send a tconX (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_tcon_send(struct smbcli_tree *tree, + union smb_tcon *parms) +{ + struct smbcli_request *req = NULL; + + switch (parms->tcon.level) { + case RAW_TCON_TCON: + SETUP_REQUEST_TREE(SMBtcon, 0, 0); + smbcli_req_append_ascii4(req, parms->tcon.in.service, STR_ASCII); + smbcli_req_append_ascii4(req, parms->tcon.in.password,STR_ASCII); + smbcli_req_append_ascii4(req, parms->tcon.in.dev, STR_ASCII); + break; + + case RAW_TCON_TCONX: + SETUP_REQUEST_TREE(SMBtconX, 4, 0); + SSVAL(req->out.vwv, VWV(0), 0xFF); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->tconx.in.flags); + SSVAL(req->out.vwv, VWV(3), parms->tconx.in.password.length); + smbcli_req_append_blob(req, &parms->tconx.in.password); + smbcli_req_append_string(req, parms->tconx.in.path, STR_TERMINATE | STR_UPPER); + smbcli_req_append_string(req, parms->tconx.in.device, STR_TERMINATE | STR_ASCII); + break; + + case RAW_TCON_SMB2: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Send a tconX (async recv) +****************************************************************************/ +NTSTATUS smb_raw_tcon_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, + union smb_tcon *parms) +{ + uint8_t *p; + + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + switch (parms->tcon.level) { + case RAW_TCON_TCON: + SMBCLI_CHECK_WCT(req, 2); + parms->tcon.out.max_xmit = SVAL(req->in.vwv, VWV(0)); + parms->tcon.out.tid = SVAL(req->in.vwv, VWV(1)); + break; + + case RAW_TCON_TCONX: + ZERO_STRUCT(parms->tconx.out); + parms->tconx.out.tid = SVAL(req->in.hdr, HDR_TID); + if (req->in.wct >= 3) { + parms->tconx.out.options = SVAL(req->in.vwv, VWV(2)); + } + if (req->in.wct >= 7) { + parms->tconx.out.max_access = IVAL(req->in.vwv, VWV(3)); + parms->tconx.out.guest_max_access = IVAL(req->in.vwv, VWV(5)); + } + + /* output is actual service name */ + p = req->in.data; + if (!p) break; + + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->tconx.out.dev_type, + p, -1, STR_ASCII | STR_TERMINATE); + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->tconx.out.fs_type, + p, -1, STR_TERMINATE); + break; + + case RAW_TCON_SMB2: + req->status = NT_STATUS_INTERNAL_ERROR; + break; + } + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + Send a tconX (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_tcon(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, + union smb_tcon *parms) +{ + struct smbcli_request *req = smb_raw_tcon_send(tree, parms); + return smb_raw_tcon_recv(req, mem_ctx, parms); +} + + +/**************************************************************************** + Send a tree disconnect. +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_tree_disconnect(struct smbcli_tree *tree) +{ + struct smbcli_request *req; + + if (!tree) return NT_STATUS_OK; + req = smbcli_request_setup(tree, SMBtdis, 0, 0); + if (req == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (smbcli_request_send(req)) { + (void) smbcli_request_receive(req); + } + return smbcli_request_destroy(req); +} + + +/* + a convenient function to establish a smbcli_tree from scratch +*/ +NTSTATUS smbcli_tree_full_connection(TALLOC_CTX *parent_ctx, + struct smbcli_tree **ret_tree, + const char *dest_host, const char **dest_ports, + const char *service, const char *service_type, + const char *socket_options, + struct cli_credentials *credentials, + struct resolve_context *resolve_ctx, + struct tevent_context *ev, + struct smbcli_options *options, + struct smbcli_session_options *session_options, + struct gensec_settings *gensec_settings) +{ + struct smb_composite_connect io; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(parent_ctx); + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + io.in.dest_host = dest_host; + io.in.dest_ports = dest_ports; + io.in.socket_options = socket_options; + io.in.called_name = strupper_talloc(tmp_ctx, dest_host); + io.in.service = service; + io.in.service_type = service_type; + io.in.existing_conn = NULL; + io.in.credentials = credentials; + io.in.gensec_settings = gensec_settings; + io.in.fallback_to_anonymous = false; + + /* This workgroup gets sent out by the SPNEGO session setup. + * I don't know of any servers that look at it, so we + * hardcode it to "". */ + io.in.workgroup = ""; + io.in.options = *options; + io.in.session_options = *session_options; + + status = smb_composite_connect(&io, parent_ctx, resolve_ctx, ev); + if (NT_STATUS_IS_OK(status)) { + *ret_tree = io.out.tree; + } + talloc_free(tmp_ctx); + return status; +} diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h new file mode 100644 index 0000000..5b398ee --- /dev/null +++ b/source4/libcli/raw/interfaces.h @@ -0,0 +1,2867 @@ +/* + Unix SMB/CIFS implementation. + SMB request interface structures + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + Copyright (C) James Peach 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LIBCLI_RAW_INTERFACES_H__ +#define __LIBCLI_RAW_INTERFACES_H__ + +#include "source4/libcli/raw/smb.h" +#include "../libcli/smb/smb_common.h" +#include "librpc/gen_ndr/misc.h" /* for struct GUID */ +#include "librpc/gen_ndr/smb2_lease_struct.h" + +/* this structure is just a wrapper for a string, the only reason we + bother with this is that it allows us to check the length provided + on the wire in testsuite test code to ensure that we are + terminating names in the same way that win2003 is. The *ONLY* time + you should ever look at the 'private_length' field in this + structure is inside compliance test code, in all other cases just + use the null terminated char* as the definitive definition of the + string + + also note that this structure is only used in packets where there + is an explicit length provided on the wire (hence the name). That + length is placed in 'private_length'. For packets where the length + is always determined by NULL or packet termination a normal char* + is used in the structure definition. + */ +struct smb_wire_string { + uint32_t private_length; + const char *s; +}; + +/* + * SMB2 uses a 16Byte handle, + * (we can maybe use struct GUID later) + */ +struct smb2_handle { + uint64_t data[2]; +}; + +struct smb2_lease_break { + struct smb2_lease current_lease; + uint16_t new_epoch; /* only for v2 leases */ + uint32_t break_flags; + uint32_t new_lease_state; + uint32_t break_reason; /* should be 0 */ + uint32_t access_mask_hint; /* should be 0 */ + uint32_t share_mask_hint; /* should be 0 */ +}; + +struct ntvfs_handle; + +/* + * a generic container for file handles or file pathes + * for qfileinfo/setfileinfo and qpathinfo/setpathinfo +*/ +union smb_handle_or_path { + /* + * this is used for + * the qpathinfo and setpathinfo + * calls + */ + const char *path; + /* + * this is used as file handle in SMB + */ + uint16_t fnum; + + /* + * this is used as file handle in SMB2 + */ + struct smb2_handle handle; + + /* + * this is used as generic file handle for the NTVFS layer + */ + struct ntvfs_handle *ntvfs; +}; + +/* + a generic container for file handles +*/ +union smb_handle { + /* + * this is used as file handle in SMB + */ + uint16_t fnum; + + /* + * this is used as file handle in SMB2 + */ + struct smb2_handle handle; + + /* + * this is used as generic file handle for the NTVFS layer + */ + struct ntvfs_handle *ntvfs; +}; + +/* + this header defines the structures and unions used between the SMB + parser and the backends. +*/ + +/* struct used for SMBlseek call */ +union smb_seek { + struct { + struct { + union smb_handle file; + uint16_t mode; + int32_t offset; /* signed */ + } in; + struct { + int32_t offset; + } out; + } lseek, generic; +}; + +/* struct used in unlink() call */ +union smb_unlink { + struct { + struct { + const char *pattern; + uint16_t attrib; + } in; + } unlink; +}; + + +/* struct used in chkpath() call */ +union smb_chkpath { + struct { + struct { + const char *path; + } in; + } chkpath; +}; + +enum smb_mkdir_level {RAW_MKDIR_GENERIC, RAW_MKDIR_MKDIR, RAW_MKDIR_T2MKDIR}; + +/* union used in mkdir() call */ +union smb_mkdir { + /* generic level */ + struct { + enum smb_mkdir_level level; + } generic; + + struct { + enum smb_mkdir_level level; + struct { + const char *path; + } in; + } mkdir; + + struct { + enum smb_mkdir_level level; + struct { + const char *path; + unsigned int num_eas; + struct ea_struct *eas; + } in; + } t2mkdir; +}; + +/* struct used in rmdir() call */ +struct smb_rmdir { + struct { + const char *path; + } in; +}; + +/* struct used in rename() call */ +enum smb_rename_level {RAW_RENAME_RENAME, RAW_RENAME_NTRENAME, RAW_RENAME_NTTRANS}; + +union smb_rename { + struct { + enum smb_rename_level level; + } generic; + + /* SMBrename interface */ + struct { + enum smb_rename_level level; + + struct { + const char *pattern1; + const char *pattern2; + uint16_t attrib; + } in; + } rename; + + + /* SMBntrename interface */ + struct { + enum smb_rename_level level; + + struct { + uint16_t attrib; + uint16_t flags; /* see RENAME_FLAG_* */ + uint32_t cluster_size; + const char *old_name; + const char *new_name; + } in; + } ntrename; + + /* NT TRANS rename interface */ + struct { + enum smb_rename_level level; + + struct { + union smb_handle file; + uint16_t flags;/* see RENAME_REPLACE_IF_EXISTS */ + const char *new_name; + } in; + } nttrans; +}; + +enum smb_tcon_level { + RAW_TCON_TCON, + RAW_TCON_TCONX, + RAW_TCON_SMB2 +}; + +/* union used in tree connect call */ +union smb_tcon { + /* generic interface */ + struct { + enum smb_tcon_level level; + } generic; + + /* SMBtcon interface */ + struct { + enum smb_tcon_level level; + + struct { + const char *service; + const char *password; + const char *dev; + } in; + struct { + uint16_t max_xmit; + uint16_t tid; + } out; + } tcon; + + /* SMBtconX interface */ + struct { + enum smb_tcon_level level; + + struct { + uint16_t flags; + DATA_BLOB password; + const char *path; + const char *device; + } in; + struct { + uint16_t options; + uint32_t max_access; + uint32_t guest_max_access; + char *dev_type; + char *fs_type; + uint16_t tid; + } out; + } tconx; + + /* SMB2 TreeConnect */ + struct smb2_tree_connect { + enum smb_tcon_level level; + + struct { + /* static body buffer 8 (0x08) bytes */ + uint16_t reserved; + /* uint16_t path_ofs */ + /* uint16_t path_size */ + /* dynamic body */ + const char *path; /* as non-terminated UTF-16 on the wire */ + } in; + struct { + /* static body buffer 16 (0x10) bytes */ + /* uint16_t buffer_code; 0x10 */ + uint8_t share_type; + uint8_t reserved; + uint32_t flags; + uint32_t capabilities; + uint32_t access_mask; + + /* extracted from the SMB2 header */ + uint32_t tid; + } out; + } smb2; +}; + + +enum smb_sesssetup_level { + RAW_SESSSETUP_OLD, + RAW_SESSSETUP_NT1, + RAW_SESSSETUP_SPNEGO, + RAW_SESSSETUP_SMB2 +}; + +/* union used in session_setup call */ +union smb_sesssetup { + /* the pre-NT1 interface */ + struct { + enum smb_sesssetup_level level; + + struct { + uint16_t bufsize; + uint16_t mpx_max; + uint16_t vc_num; + uint32_t sesskey; + DATA_BLOB password; + const char *user; + const char *domain; + const char *os; + const char *lanman; + } in; + struct { + uint16_t action; + uint16_t vuid; + char *os; + char *lanman; + char *domain; + } out; + } old; + + /* the NT1 interface */ + struct { + enum smb_sesssetup_level level; + + struct { + uint16_t bufsize; + uint16_t mpx_max; + uint16_t vc_num; + uint32_t sesskey; + uint32_t capabilities; + DATA_BLOB password1; + DATA_BLOB password2; + const char *user; + const char *domain; + const char *os; + const char *lanman; + } in; + struct { + uint16_t action; + uint16_t vuid; + char *os; + char *lanman; + char *domain; + } out; + } nt1; + + + /* the SPNEGO interface */ + struct { + enum smb_sesssetup_level level; + + struct { + uint16_t bufsize; + uint16_t mpx_max; + uint16_t vc_num; + uint32_t sesskey; + uint32_t capabilities; + DATA_BLOB secblob; + const char *os; + const char *lanman; + const char *workgroup; + } in; + struct { + uint16_t action; + DATA_BLOB secblob; + char *os; + char *lanman; + char *workgroup; + uint16_t vuid; + } out; + } spnego; + + /* SMB2 SessionSetup */ + struct smb2_session_setup { + enum smb_sesssetup_level level; + + struct { + /* static body 24 (0x18) bytes */ + uint8_t vc_number; + uint8_t security_mode; + uint32_t capabilities; + uint32_t channel; + /* uint16_t secblob_ofs */ + /* uint16_t secblob_size */ + uint64_t previous_sessionid; + /* dynamic body */ + DATA_BLOB secblob; + } in; + struct { + /* body buffer 8 (0x08) bytes */ + uint16_t session_flags; + /* uint16_t secblob_ofs */ + /* uint16_t secblob_size */ + /* dynamic body */ + DATA_BLOB secblob; + + /* extracted from the SMB2 header */ + uint64_t uid; + } out; + } smb2; +}; + +/* Note that the specified enum values are identical to the actual info-levels used + * on the wire. + */ +enum smb_fileinfo_level { + RAW_FILEINFO_GENERIC = 0xF000, + RAW_FILEINFO_GETATTR, /* SMBgetatr */ + RAW_FILEINFO_GETATTRE, /* SMBgetattrE */ + RAW_FILEINFO_SEC_DESC, /* NT_TRANSACT_QUERY_SECURITY_DESC */ + RAW_FILEINFO_STANDARD = SMB_QFILEINFO_STANDARD, + RAW_FILEINFO_EA_SIZE = SMB_QFILEINFO_EA_SIZE, + RAW_FILEINFO_EA_LIST = SMB_QFILEINFO_EA_LIST, + RAW_FILEINFO_ALL_EAS = SMB_QFILEINFO_ALL_EAS, + RAW_FILEINFO_IS_NAME_VALID = SMB_QFILEINFO_IS_NAME_VALID, + RAW_FILEINFO_BASIC_INFO = SMB_QFILEINFO_BASIC_INFO, + RAW_FILEINFO_STANDARD_INFO = SMB_QFILEINFO_STANDARD_INFO, + RAW_FILEINFO_EA_INFO = SMB_QFILEINFO_EA_INFO, + RAW_FILEINFO_NAME_INFO = SMB_QFILEINFO_NAME_INFO, + RAW_FILEINFO_ALL_INFO = SMB_QFILEINFO_ALL_INFO, + RAW_FILEINFO_ALT_NAME_INFO = SMB_QFILEINFO_ALT_NAME_INFO, + RAW_FILEINFO_STREAM_INFO = SMB_QFILEINFO_STREAM_INFO, + RAW_FILEINFO_COMPRESSION_INFO = SMB_QFILEINFO_COMPRESSION_INFO, + RAW_FILEINFO_UNIX_BASIC = SMB_QFILEINFO_UNIX_BASIC, + RAW_FILEINFO_UNIX_INFO2 = SMB_QFILEINFO_UNIX_INFO2, + RAW_FILEINFO_UNIX_LINK = SMB_QFILEINFO_UNIX_LINK, + RAW_FILEINFO_BASIC_INFORMATION = SMB_QFILEINFO_BASIC_INFORMATION, + RAW_FILEINFO_STANDARD_INFORMATION = SMB_QFILEINFO_STANDARD_INFORMATION, + RAW_FILEINFO_INTERNAL_INFORMATION = SMB_QFILEINFO_INTERNAL_INFORMATION, + RAW_FILEINFO_EA_INFORMATION = SMB_QFILEINFO_EA_INFORMATION, + RAW_FILEINFO_ACCESS_INFORMATION = SMB_QFILEINFO_ACCESS_INFORMATION, + RAW_FILEINFO_NAME_INFORMATION = SMB_QFILEINFO_NAME_INFORMATION, + RAW_FILEINFO_POSITION_INFORMATION = SMB_QFILEINFO_POSITION_INFORMATION, + RAW_FILEINFO_MODE_INFORMATION = SMB_QFILEINFO_MODE_INFORMATION, + RAW_FILEINFO_ALIGNMENT_INFORMATION = SMB_QFILEINFO_ALIGNMENT_INFORMATION, + RAW_FILEINFO_ALL_INFORMATION = SMB_QFILEINFO_ALL_INFORMATION, + RAW_FILEINFO_ALT_NAME_INFORMATION = SMB_QFILEINFO_ALT_NAME_INFORMATION, + RAW_FILEINFO_STREAM_INFORMATION = SMB_QFILEINFO_STREAM_INFORMATION, + RAW_FILEINFO_COMPRESSION_INFORMATION = SMB_QFILEINFO_COMPRESSION_INFORMATION, + RAW_FILEINFO_NETWORK_OPEN_INFORMATION = SMB_QFILEINFO_NETWORK_OPEN_INFORMATION, + RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION = SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION, + RAW_FILEINFO_NORMALIZED_NAME_INFORMATION= SMB_QFILEINFO_NORMALIZED_NAME_INFORMATION, + /* SMB2 specific levels */ + RAW_FILEINFO_SMB2_ALL_EAS = 0x0f01, + RAW_FILEINFO_SMB2_ALL_INFORMATION = 0x1201, + RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION = 0x1501 +}; + +/* union used in qfileinfo() and qpathinfo() backend calls */ +union smb_fileinfo { + /* generic interface: + * matches RAW_FILEINFO_GENERIC */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t attrib; + uint32_t ea_size; + unsigned int num_eas; + struct ea_struct { + uint8_t flags; + struct smb_wire_string name; + DATA_BLOB value; + } *eas; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t alloc_size; + uint64_t size; + uint32_t nlink; + struct smb_wire_string fname; + struct smb_wire_string alt_fname; + uint8_t delete_pending; + uint8_t directory; + uint64_t compressed_size; + uint16_t format; + uint8_t unit_shift; + uint8_t chunk_shift; + uint8_t cluster_shift; + uint64_t file_id; + uint32_t access_flags; /* seen 0x001f01ff from w2k3 */ + uint64_t position; + uint32_t mode; + uint32_t alignment_requirement; + uint32_t reparse_tag; + unsigned int num_streams; + struct stream_struct { + uint64_t size; + uint64_t alloc_size; + struct smb_wire_string stream_name; + } *streams; + } out; + } generic; + + + /* SMBgetatr interface: + * matches RAW_FILEINFO_GETATTR */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint16_t attrib; + uint32_t size; + time_t write_time; + } out; + } getattr; + + /* SMBgetattrE and RAW_FILEINFO_STANDARD interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + } out; + } getattre, standard; + + /* trans2 RAW_FILEINFO_EA_SIZE interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + uint32_t ea_size; + } out; + } ea_size; + + /* trans2 RAW_FILEINFO_EA_LIST interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + unsigned int num_names; + struct ea_name { + struct smb_wire_string name; + } *ea_names; + } in; + + struct smb_ea_list { + unsigned int num_eas; + struct ea_struct *eas; + } out; + } ea_list; + + /* trans2 RAW_FILEINFO_ALL_EAS and RAW_FILEINFO_FULL_EA_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + /* SMB2 only - SMB2_CONTINUE_FLAG_* */ + uint8_t continue_flags; + } in; + struct smb_ea_list out; + } all_eas; + + /* trans2 qpathinfo RAW_FILEINFO_IS_NAME_VALID interface + only valid for a QPATHNAME call - no returned data */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + } is_name_valid; + + /* RAW_FILEINFO_BASIC_INFO and RAW_FILEINFO_BASIC_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + } out; + } basic_info; + + + /* RAW_FILEINFO_STANDARD_INFO and RAW_FILEINFO_STANDARD_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t alloc_size; + uint64_t size; + uint32_t nlink; + bool delete_pending; + bool directory; + } out; + } standard_info; + + /* RAW_FILEINFO_EA_INFO and RAW_FILEINFO_EA_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t ea_size; + } out; + } ea_info; + + /* RAW_FILEINFO_NAME_INFO and RAW_FILEINFO_NAME_INFORMATION interfaces */ + /* RAW_FILEINFO_ALT_NAME_INFO and RAW_FILEINFO_ALT_NAME_INFORMATION interfaces */ + /* RAW_FILEINFO_NORMALIZED_NAME_INFORMATION interface */ + /* RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + struct smb_wire_string fname; + } out; + } name_info, alt_name_info, normalized_name_info; + + /* RAW_FILEINFO_ALL_INFO and RAW_FILEINFO_ALL_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint64_t alloc_size; + uint64_t size; + uint32_t nlink; + uint8_t delete_pending; + uint8_t directory; + uint32_t ea_size; + struct smb_wire_string fname; + } out; + } all_info; + + /* RAW_FILEINFO_SMB2_ALL_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint32_t unknown1; + uint64_t alloc_size; + uint64_t size; + uint32_t nlink; + uint8_t delete_pending; + uint8_t directory; + /* uint16_t _pad; */ + uint64_t file_id; + uint32_t ea_size; + uint32_t access_mask; + uint64_t position; + uint32_t mode; + uint32_t alignment_requirement; + struct smb_wire_string fname; + } out; + } all_info2; + + /* RAW_FILEINFO_STREAM_INFO and RAW_FILEINFO_STREAM_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct stream_information { + unsigned int num_streams; + struct stream_struct *streams; + } out; + } stream_info; + + /* RAW_FILEINFO_COMPRESSION_INFO and RAW_FILEINFO_COMPRESSION_INFORMATION interfaces */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t compressed_size; + uint16_t format; + uint8_t unit_shift; + uint8_t chunk_shift; + uint8_t cluster_shift; + } out; + } compression_info; + + /* RAW_FILEINFO_UNIX_BASIC interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t end_of_file; + uint64_t num_bytes; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + } out; + } unix_basic_info; + + /* RAW_FILEINFO_UNIX_INFO2 interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t end_of_file; + uint64_t num_bytes; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + NTTIME create_time; + uint32_t file_flags; + uint32_t flags_mask; + } out; + } unix_info2; + + /* RAW_FILEINFO_UNIX_LINK interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + struct smb_wire_string link_dest; + } out; + } unix_link_info; + + /* RAW_FILEINFO_INTERNAL_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t file_id; + } out; + } internal_information; + + /* RAW_FILEINFO_ACCESS_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t access_flags; + } out; + } access_information; + + /* RAW_FILEINFO_POSITION_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint64_t position; + } out; + } position_information; + + /* RAW_FILEINFO_MODE_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t mode; + } out; + } mode_information; + + /* RAW_FILEINFO_ALIGNMENT_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t alignment_requirement; + } out; + } alignment_information; + + /* RAW_FILEINFO_NETWORK_OPEN_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t alloc_size; + uint64_t size; + uint32_t attrib; + } out; + } network_open_information; + + + /* RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + struct { + uint32_t attrib; + uint32_t reparse_tag; + } out; + } attribute_tag_information; + + /* RAW_FILEINFO_SEC_DESC */ + struct { + enum smb_fileinfo_level level; + struct { + union smb_handle_or_path file; + uint32_t secinfo_flags; + } in; + struct { + struct security_descriptor *sd; + } out; + } query_secdesc; +}; + + +enum smb_setfileinfo_level { + RAW_SFILEINFO_GENERIC = 0xF000, + RAW_SFILEINFO_SETATTR, /* SMBsetatr */ + RAW_SFILEINFO_SETATTRE, /* SMBsetattrE */ + RAW_SFILEINFO_SEC_DESC, /* NT_TRANSACT_SET_SECURITY_DESC */ + RAW_SFILEINFO_STANDARD = SMB_SFILEINFO_STANDARD, + RAW_SFILEINFO_EA_SET = SMB_SFILEINFO_EA_SET, + RAW_SFILEINFO_BASIC_INFO = SMB_SFILEINFO_BASIC_INFO, + RAW_SFILEINFO_DISPOSITION_INFO = SMB_SFILEINFO_DISPOSITION_INFO, + RAW_SFILEINFO_ALLOCATION_INFO = SMB_SFILEINFO_ALLOCATION_INFO, + RAW_SFILEINFO_END_OF_FILE_INFO = SMB_SFILEINFO_END_OF_FILE_INFO, + RAW_SFILEINFO_UNIX_BASIC = SMB_SFILEINFO_UNIX_BASIC, + RAW_SFILEINFO_UNIX_INFO2 = SMB_SFILEINFO_UNIX_INFO2, + RAW_SFILEINFO_UNIX_LINK = SMB_SET_FILE_UNIX_LINK, + RAW_SFILEINFO_UNIX_HLINK = SMB_SET_FILE_UNIX_HLINK, + RAW_SFILEINFO_BASIC_INFORMATION = SMB_SFILEINFO_BASIC_INFORMATION, + RAW_SFILEINFO_RENAME_INFORMATION = SMB_SFILEINFO_RENAME_INFORMATION, + RAW_SFILEINFO_LINK_INFORMATION = SMB_SFILEINFO_LINK_INFORMATION, + RAW_SFILEINFO_DISPOSITION_INFORMATION = SMB_SFILEINFO_DISPOSITION_INFORMATION, + RAW_SFILEINFO_POSITION_INFORMATION = SMB_SFILEINFO_POSITION_INFORMATION, + RAW_SFILEINFO_FULL_EA_INFORMATION = SMB_SFILEINFO_FULL_EA_INFORMATION, + RAW_SFILEINFO_MODE_INFORMATION = SMB_SFILEINFO_MODE_INFORMATION, + RAW_SFILEINFO_ALLOCATION_INFORMATION = SMB_SFILEINFO_ALLOCATION_INFORMATION, + RAW_SFILEINFO_END_OF_FILE_INFORMATION = SMB_SFILEINFO_END_OF_FILE_INFORMATION, + RAW_SFILEINFO_PIPE_INFORMATION = SMB_SFILEINFO_PIPE_INFORMATION, + RAW_SFILEINFO_VALID_DATA_INFORMATION = SMB_SFILEINFO_VALID_DATA_INFORMATION, + RAW_SFILEINFO_SHORT_NAME_INFORMATION = SMB_SFILEINFO_SHORT_NAME_INFORMATION, + RAW_SFILEINFO_1025 = SMB_SFILEINFO_1025, + RAW_SFILEINFO_1027 = SMB_SFILEINFO_1027, + RAW_SFILEINFO_1029 = SMB_SFILEINFO_1029, + RAW_SFILEINFO_1030 = SMB_SFILEINFO_1030, + RAW_SFILEINFO_1031 = SMB_SFILEINFO_1031, + RAW_SFILEINFO_1032 = SMB_SFILEINFO_1032, + RAW_SFILEINFO_1036 = SMB_SFILEINFO_1036, + RAW_SFILEINFO_1041 = SMB_SFILEINFO_1041, + RAW_SFILEINFO_1042 = SMB_SFILEINFO_1042, + RAW_SFILEINFO_1043 = SMB_SFILEINFO_1043, + RAW_SFILEINFO_1044 = SMB_SFILEINFO_1044, + + /* cope with breakage in SMB2 */ + RAW_SFILEINFO_RENAME_INFORMATION_SMB2 = SMB_SFILEINFO_RENAME_INFORMATION|0x80000000, +}; + +/* union used in setfileinfo() and setpathinfo() calls */ +union smb_setfileinfo { + /* generic interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + } in; + } generic; + + /* RAW_SFILEINFO_SETATTR (SMBsetatr) interface - only via setpathinfo() */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint16_t attrib; + time_t write_time; + } in; + } setattr; + + /* RAW_SFILEINFO_SETATTRE (SMBsetattrE) interface - only via setfileinfo() + also RAW_SFILEINFO_STANDARD */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + time_t create_time; + time_t access_time; + time_t write_time; + /* notice that size, alloc_size and attrib are not settable, + unlike the corresponding qfileinfo level */ + } in; + } setattre, standard; + + /* RAW_SFILEINFO_EA_SET interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + unsigned int num_eas; + struct ea_struct *eas; + } in; + } ea_set; + + /* RAW_SFILEINFO_BASIC_INFO and + RAW_SFILEINFO_BASIC_INFORMATION interfaces */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint32_t reserved; + } in; + } basic_info; + + /* RAW_SFILEINFO_DISPOSITION_INFO and + RAW_SFILEINFO_DISPOSITION_INFORMATION interfaces */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + bool delete_on_close; + } in; + } disposition_info; + + /* RAW_SFILEINFO_ALLOCATION_INFO and + RAW_SFILEINFO_ALLOCATION_INFORMATION interfaces */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + /* w2k3 rounds this up to nearest 4096 */ + uint64_t alloc_size; + } in; + } allocation_info; + + /* RAW_SFILEINFO_END_OF_FILE_INFO and + RAW_SFILEINFO_END_OF_FILE_INFORMATION interfaces */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint64_t size; + } in; + } end_of_file_info; + + /* RAW_SFILEINFO_RENAME_INFORMATION interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint8_t overwrite; + uint64_t root_fid; + const char *new_name; + } in; + } rename_information; + + /* RAW_SFILEINFO_LINK_INFORMATION interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint8_t overwrite; + uint64_t root_fid; + const char *new_name; + } in; + } link_information; + + /* RAW_SFILEINFO_POSITION_INFORMATION interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint64_t position; + } in; + } position_information; + + /* RAW_SFILEINFO_MODE_INFORMATION interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + /* valid values seem to be 0, 2, 4 and 6 */ + uint32_t mode; + } in; + } mode_information; + + /* RAW_SFILEINFO_UNIX_BASIC interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint32_t mode; /* yuck - this field remains to fix compile of libcli/clifile.c */ + uint64_t end_of_file; + uint64_t num_bytes; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + } in; + } unix_basic; + + /* RAW_SFILEINFO_UNIX_INFO2 interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint64_t end_of_file; + uint64_t num_bytes; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + NTTIME create_time; + uint32_t file_flags; + uint32_t flags_mask; + } in; + } unix_info2; + + /* RAW_SFILEINFO_UNIX_LINK, RAW_SFILEINFO_UNIX_HLINK interface */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + const char *link_dest; + } in; + } unix_link, unix_hlink; + + /* RAW_SFILEINFO_SEC_DESC */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + uint32_t secinfo_flags; + struct security_descriptor *sd; + } in; + } set_secdesc; + + /* RAW_SFILEINFO_FULL_EA_INFORMATION */ + struct { + enum smb_setfileinfo_level level; + struct { + union smb_handle_or_path file; + struct smb_ea_list eas; + } in; + } full_ea_information; +}; + + +enum smb_fsinfo_level { + RAW_QFS_GENERIC = 0xF000, + RAW_QFS_DSKATTR, /* SMBdskattr */ + RAW_QFS_ALLOCATION = SMB_QFS_ALLOCATION, + RAW_QFS_VOLUME = SMB_QFS_VOLUME, + RAW_QFS_VOLUME_INFO = SMB_QFS_VOLUME_INFO, + RAW_QFS_SIZE_INFO = SMB_QFS_SIZE_INFO, + RAW_QFS_DEVICE_INFO = SMB_QFS_DEVICE_INFO, + RAW_QFS_ATTRIBUTE_INFO = SMB_QFS_ATTRIBUTE_INFO, + RAW_QFS_UNIX_INFO = SMB_QFS_UNIX_INFO, + RAW_QFS_VOLUME_INFORMATION = SMB_QFS_VOLUME_INFORMATION, + RAW_QFS_SIZE_INFORMATION = SMB_QFS_SIZE_INFORMATION, + RAW_QFS_DEVICE_INFORMATION = SMB_QFS_DEVICE_INFORMATION, + RAW_QFS_ATTRIBUTE_INFORMATION = SMB_QFS_ATTRIBUTE_INFORMATION, + RAW_QFS_QUOTA_INFORMATION = SMB_QFS_QUOTA_INFORMATION, + RAW_QFS_FULL_SIZE_INFORMATION = SMB_QFS_FULL_SIZE_INFORMATION, + RAW_QFS_OBJECTID_INFORMATION = SMB_QFS_OBJECTID_INFORMATION, + RAW_QFS_SECTOR_SIZE_INFORMATION = SMB_QFS_SECTOR_SIZE_INFORMATION, +}; + + +/* union for fsinfo() backend call. Note that there are no in + structures, as this call only contains out parameters */ +union smb_fsinfo { + /* generic interface */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint32_t block_size; + uint64_t blocks_total; + uint64_t blocks_free; + uint32_t fs_id; + NTTIME create_time; + uint32_t serial_number; + uint32_t fs_attr; + uint32_t max_file_component_length; + uint32_t device_type; + uint32_t device_characteristics; + uint64_t quota_soft; + uint64_t quota_hard; + uint64_t quota_flags; + struct GUID guid; + char *volume_name; + char *fs_type; + } out; + } generic; + + /* SMBdskattr interface */ + struct { + enum smb_fsinfo_level level; + + struct { + uint16_t units_total; + uint16_t blocks_per_unit; + uint16_t block_size; + uint16_t units_free; + } out; + } dskattr; + + /* trans2 RAW_QFS_ALLOCATION interface */ + struct { + enum smb_fsinfo_level level; + + struct { + uint32_t fs_id; + uint32_t sectors_per_unit; + uint32_t total_alloc_units; + uint32_t avail_alloc_units; + uint16_t bytes_per_sector; + } out; + } allocation; + + /* TRANS2 RAW_QFS_VOLUME interface */ + struct { + enum smb_fsinfo_level level; + + struct { + uint32_t serial_number; + struct smb_wire_string volume_name; + } out; + } volume; + + /* TRANS2 RAW_QFS_VOLUME_INFO and RAW_QFS_VOLUME_INFORMATION interfaces */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + NTTIME create_time; + uint32_t serial_number; + struct smb_wire_string volume_name; + } out; + } volume_info; + + /* trans2 RAW_QFS_SIZE_INFO and RAW_QFS_SIZE_INFORMATION interfaces */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint64_t total_alloc_units; + uint64_t avail_alloc_units; /* maps to call_avail_alloc_units */ + uint32_t sectors_per_unit; + uint32_t bytes_per_sector; + } out; + } size_info; + + /* TRANS2 RAW_QFS_DEVICE_INFO and RAW_QFS_DEVICE_INFORMATION interfaces */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint32_t device_type; + uint32_t characteristics; + } out; + } device_info; + + + /* TRANS2 RAW_QFS_ATTRIBUTE_INFO and RAW_QFS_ATTRIBUTE_INFORMATION interfaces */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint32_t fs_attr; + uint32_t max_file_component_length; + struct smb_wire_string fs_type; + } out; + } attribute_info; + + + /* TRANS2 RAW_QFS_UNIX_INFO interface */ + struct { + enum smb_fsinfo_level level; + + struct { + uint16_t major_version; + uint16_t minor_version; + uint64_t capability; + } out; + } unix_info; + + /* trans2 RAW_QFS_QUOTA_INFORMATION interface */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint64_t unknown[3]; + uint64_t quota_soft; + uint64_t quota_hard; + uint64_t quota_flags; + } out; + } quota_information; + + /* trans2 RAW_QFS_FULL_SIZE_INFORMATION interface */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint64_t total_alloc_units; + uint64_t call_avail_alloc_units; + uint64_t actual_avail_alloc_units; + uint32_t sectors_per_unit; + uint32_t bytes_per_sector; + } out; + } full_size_information; + + /* trans2 RAW_QFS_OBJECTID_INFORMATION interface */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + struct GUID guid; + uint64_t unknown[6]; + } out; + } objectid_information; + + /* trans2 RAW_QFS_SECTOR_SIZE_INFORMATION interface */ + struct { + enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ + + struct { + uint32_t logical_bytes_per_sector; + uint32_t phys_bytes_per_sector_atomic; + uint32_t phys_bytes_per_sector_perf; + uint32_t fs_effective_phys_bytes_per_sector_atomic; + uint32_t flags; + uint32_t byte_off_sector_align; + uint32_t byte_off_partition_align; + } out; + } sector_size_info; +}; + + +enum smb_setfsinfo_level { + RAW_SETFS_UNIX_INFO = SMB_SET_CIFS_UNIX_INFO}; + +union smb_setfsinfo { + /* generic interface */ + struct { + enum smb_setfsinfo_level level; + } generic; + + /* TRANS2 RAW_QFS_UNIX_INFO interface */ + struct { + enum smb_setfsinfo_level level; + + struct { + uint16_t major_version; + uint16_t minor_version; + uint64_t capability; + } in; + } unix_info; +}; + +enum smb_open_level { + RAW_OPEN_OPEN, + RAW_OPEN_OPENX, + RAW_OPEN_MKNEW, + RAW_OPEN_CREATE, + RAW_OPEN_CTEMP, + RAW_OPEN_SPLOPEN, + RAW_OPEN_NTCREATEX, + RAW_OPEN_T2OPEN, + RAW_OPEN_NTTRANS_CREATE, + RAW_OPEN_OPENX_READX, + RAW_OPEN_NTCREATEX_READX, + RAW_OPEN_SMB2 +}; + +/* the generic interface is defined to be equal to the NTCREATEX interface */ +#define RAW_OPEN_GENERIC RAW_OPEN_NTCREATEX + +/* union for open() backend call */ +union smb_open { +/* + * because the *.out.file structs are not aligned to the same offset for each level + * we provide a hepler macro that should be used to find the current smb_handle structure + */ +#define SMB_OPEN_OUT_FILE(op, file) do { \ + switch (op->generic.level) { \ + case RAW_OPEN_OPEN: \ + file = &op->openold.out.file; \ + break; \ + case RAW_OPEN_OPENX: \ + file = &op->openx.out.file; \ + break; \ + case RAW_OPEN_MKNEW: \ + file = &op->mknew.out.file; \ + break; \ + case RAW_OPEN_CREATE: \ + file = &op->create.out.file; \ + break; \ + case RAW_OPEN_CTEMP: \ + file = &op->ctemp.out.file; \ + break; \ + case RAW_OPEN_SPLOPEN: \ + file = &op->splopen.out.file; \ + break; \ + case RAW_OPEN_NTCREATEX: \ + file = &op->ntcreatex.out.file; \ + break; \ + case RAW_OPEN_T2OPEN: \ + file = &op->t2open.out.file; \ + break; \ + case RAW_OPEN_NTTRANS_CREATE: \ + file = &op->nttrans.out.file; \ + break; \ + case RAW_OPEN_OPENX_READX: \ + file = &op->openxreadx.out.file; \ + break; \ + case RAW_OPEN_NTCREATEX_READX: \ + file = &op->ntcreatexreadx.out.file; \ + break; \ + case RAW_OPEN_SMB2: \ + file = &op->smb2.out.file; \ + break; \ + default: \ + /* this must be a programmer error */ \ + file = NULL; \ + break; \ + } \ +} while (0) + /* SMBNTCreateX, nttrans and generic interface */ + struct { + enum smb_open_level level; + struct { + uint32_t flags; + union smb_handle root_fid; + uint32_t access_mask; + uint64_t alloc_size; + uint32_t file_attr; + uint32_t share_access; + uint32_t open_disposition; + uint32_t create_options; + uint32_t impersonation; + uint8_t security_flags; + /* NOTE: fname can also be a pointer to a + uint64_t file_id if create_options has the + NTCREATEX_OPTIONS_OPEN_BY_FILE_ID flag set */ + const char *fname; + + /* these last 2 elements are only used in the + NTTRANS varient of the call */ + struct security_descriptor *sec_desc; + struct smb_ea_list *ea_list; + + /* some optional parameters from the SMB2 varient */ + bool query_maximal_access; + bool query_on_disk_id; + + /* private flags for internal use only */ + uint8_t private_flags; + } in; + struct { + union smb_handle file; + uint8_t oplock_level; + uint32_t create_action; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint64_t alloc_size; + uint64_t size; + uint16_t file_type; + uint16_t ipc_state; + uint8_t is_directory; + + /* optional return values matching SMB2 tagged + values in the call */ + uint32_t maximal_access; + uint8_t on_disk_id[32]; + } out; + } ntcreatex, nttrans, generic; + + /* TRANS2_OPEN interface */ + struct { + enum smb_open_level level; + struct { + uint16_t flags; + uint16_t open_mode; + uint16_t search_attrs; + uint16_t file_attrs; + time_t write_time; + uint16_t open_func; + uint32_t size; + uint32_t timeout; + const char *fname; + unsigned int num_eas; + struct ea_struct *eas; + } in; + struct { + union smb_handle file; + uint16_t attrib; + time_t write_time; + uint32_t size; + uint16_t access; + uint16_t ftype; + uint16_t devstate; + uint16_t action; + uint32_t file_id; + } out; + } t2open; + + /* SMBopen interface */ + struct { + enum smb_open_level level; + struct { + uint16_t open_mode; + uint16_t search_attrs; + const char *fname; + } in; + struct { + union smb_handle file; + uint16_t attrib; + time_t write_time; + uint32_t size; + uint16_t rmode; + } out; + } openold; + + /* SMBopenX interface */ + struct { + enum smb_open_level level; + struct { + uint16_t flags; + uint16_t open_mode; + uint16_t search_attrs; /* not honoured by win2003 */ + uint16_t file_attrs; + time_t write_time; /* not honoured by win2003 */ + uint16_t open_func; + uint32_t size; /* note that this sets the + initial file size, not + just allocation size */ + uint32_t timeout; /* not honoured by win2003 */ + const char *fname; + } in; + struct { + union smb_handle file; + uint16_t attrib; + time_t write_time; + uint32_t size; + uint16_t access; + uint16_t ftype; + uint16_t devstate; + uint16_t action; + uint32_t unique_fid; + uint32_t access_mask; + uint32_t unknown; + } out; + } openx; + + /* SMBmknew interface */ + struct { + enum smb_open_level level; + struct { + uint16_t attrib; + time_t write_time; + const char *fname; + } in; + struct { + union smb_handle file; + } out; + } mknew, create; + + /* SMBctemp interface */ + struct { + enum smb_open_level level; + struct { + uint16_t attrib; + time_t write_time; + const char *directory; + } in; + struct { + union smb_handle file; + /* temp name, relative to directory */ + char *name; + } out; + } ctemp; + + /* SMBsplopen interface */ + struct { + enum smb_open_level level; + struct { + uint16_t setup_length; + uint16_t mode; + const char *ident; + } in; + struct { + union smb_handle file; + } out; + } splopen; + + + /* chained OpenX/ReadX interface */ + struct { + enum smb_open_level level; + struct { + uint16_t flags; + uint16_t open_mode; + uint16_t search_attrs; /* not honoured by win2003 */ + uint16_t file_attrs; + time_t write_time; /* not honoured by win2003 */ + uint16_t open_func; + uint32_t size; /* note that this sets the + initial file size, not + just allocation size */ + uint32_t timeout; /* not honoured by win2003 */ + const char *fname; + + /* readx part */ + uint64_t offset; + uint16_t mincnt; + uint32_t maxcnt; + uint16_t remaining; + } in; + struct { + union smb_handle file; + uint16_t attrib; + time_t write_time; + uint32_t size; + uint16_t access; + uint16_t ftype; + uint16_t devstate; + uint16_t action; + uint32_t unique_fid; + uint32_t access_mask; + uint32_t unknown; + + /* readx part */ + uint8_t *data; + uint16_t remaining; + uint16_t compaction_mode; + uint16_t nread; + } out; + } openxreadx; + + /* chained NTCreateX/ReadX interface */ + struct { + enum smb_open_level level; + struct { + uint32_t flags; + union smb_handle root_fid; + uint32_t access_mask; + uint64_t alloc_size; + uint32_t file_attr; + uint32_t share_access; + uint32_t open_disposition; + uint32_t create_options; + uint32_t impersonation; + uint8_t security_flags; + /* NOTE: fname can also be a pointer to a + uint64_t file_id if create_options has the + NTCREATEX_OPTIONS_OPEN_BY_FILE_ID flag set */ + const char *fname; + + /* readx part */ + uint64_t offset; + uint16_t mincnt; + uint32_t maxcnt; + uint16_t remaining; + } in; + struct { + union smb_handle file; + uint8_t oplock_level; + uint32_t create_action; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint64_t alloc_size; + uint64_t size; + uint16_t file_type; + uint16_t ipc_state; + uint8_t is_directory; + + /* readx part */ + uint8_t *data; + uint16_t remaining; + uint16_t compaction_mode; + uint16_t nread; + } out; + } ntcreatexreadx; + +#define SMB2_CREATE_FLAG_REQUEST_OPLOCK 0x0100 +#define SMB2_CREATE_FLAG_REQUEST_EXCLUSIVE_OPLOCK 0x0800 +#define SMB2_CREATE_FLAG_GRANT_OPLOCK 0x0001 +#define SMB2_CREATE_FLAG_GRANT_EXCLUSIVE_OPLOCK 0x0080 + + /* SMB2 Create */ + struct smb2_create { + enum smb_open_level level; + struct { + /* static body buffer 56 (0x38) bytes */ + uint8_t security_flags; /* SMB2_SECURITY_* */ + uint8_t oplock_level; /* SMB2_OPLOCK_LEVEL_* */ + uint32_t impersonation_level; /* SMB2_IMPERSONATION_* */ + uint64_t create_flags; + uint64_t reserved; + uint32_t desired_access; + uint32_t file_attributes; + uint32_t share_access; /* NTCREATEX_SHARE_ACCESS_* */ + uint32_t create_disposition; /* NTCREATEX_DISP_* */ + uint32_t create_options; /* NTCREATEX_OPTIONS_* */ + + /* uint16_t fname_ofs */ + /* uint16_t fname_size */ + /* uint32_t blob_ofs; */ + /* uint32_t blob_size; */ + + /* dynamic body */ + const char *fname; + + /* now some optional parameters - encoded as tagged blobs */ + struct smb_ea_list eas; + uint64_t alloc_size; + struct security_descriptor *sec_desc; + bool durable_open; + struct smb2_handle *durable_handle; + + /* data for durable handle v2 */ + bool durable_open_v2; + struct GUID create_guid; + bool persistent_open; + uint32_t timeout; + struct smb2_handle *durable_handle_v2; + + bool query_maximal_access; + NTTIME timewarp; + bool query_on_disk_id; + struct smb2_lease *lease_request; + struct smb2_lease *lease_request_v2; + + struct GUID *app_instance_id; + + /* and any additional blobs the caller wants */ + struct smb2_create_blobs blobs; + } in; + struct { + union smb_handle file; + + /* static body buffer 88 (0x58) bytes */ + /* uint16_t buffer_code; 0x59 = 0x58 + 1 */ + uint8_t oplock_level; + uint8_t reserved; + uint32_t create_action; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t alloc_size; + uint64_t size; + uint32_t file_attr; + uint32_t reserved2; + /* struct smb2_handle handle;*/ + /* uint32_t blob_ofs; */ + /* uint32_t blob_size; */ + + /* optional return values matching tagged values in the call */ + uint32_t maximal_access_status; + uint32_t maximal_access; + uint8_t on_disk_id[32]; + struct smb2_lease lease_response; + struct smb2_lease lease_response_v2; + bool durable_open; + + /* durable handle v2 */ + bool durable_open_v2; + bool persistent_open; + uint32_t timeout; + + /* tagged blobs in the reply */ + struct smb2_create_blobs blobs; + } out; + } smb2; +}; + + + +enum smb_read_level { + RAW_READ_READBRAW, + RAW_READ_LOCKREAD, + RAW_READ_READ, + RAW_READ_READX, + RAW_READ_SMB2 +}; + +#define RAW_READ_GENERIC RAW_READ_READX + +/* union for read() backend call + + note that .infoX.out.data will be allocated before the backend is + called. It will be big enough to hold the maximum size asked for +*/ +union smb_read { + /* SMBreadX (and generic) interface */ + struct { + enum smb_read_level level; + struct { + union smb_handle file; + uint64_t offset; + uint32_t mincnt; /* enforced on SMB2, 16 bit on SMB */ + uint32_t maxcnt; + uint16_t remaining; + bool read_for_execute; + } in; + struct { + uint8_t *data; + uint16_t remaining; + uint16_t compaction_mode; + uint32_t nread; + uint16_t flags2; + uint16_t data_offset; + } out; + } readx, generic; + + /* SMBreadbraw interface */ + struct { + enum smb_read_level level; + struct { + union smb_handle file; + uint64_t offset; + uint16_t maxcnt; + uint16_t mincnt; + uint32_t timeout; + } in; + struct { + uint8_t *data; + uint32_t nread; + } out; + } readbraw; + + + /* SMBlockandread interface */ + struct { + enum smb_read_level level; + struct { + union smb_handle file; + uint16_t count; + uint32_t offset; + uint16_t remaining; + } in; + struct { + uint8_t *data; + uint16_t nread; + } out; + } lockread; + + /* SMBread interface */ + struct { + enum smb_read_level level; + struct { + union smb_handle file; + uint16_t count; + uint32_t offset; + uint16_t remaining; + } in; + struct { + uint8_t *data; + uint16_t nread; + } out; + } read; + + /* SMB2 Read */ + struct smb2_read { + enum smb_read_level level; + struct { + union smb_handle file; + + /* static body buffer 48 (0x30) bytes */ + /* uint16_t buffer_code; 0x31 = 0x30 + 1 */ + uint8_t _pad; + uint8_t reserved; + uint32_t length; + uint64_t offset; + /* struct smb2_handle handle; */ + uint32_t min_count; + uint32_t channel; + uint32_t remaining; + /* the docs give no indication of what + these channel variables are for */ + uint16_t channel_offset; + uint16_t channel_length; + } in; + struct { + /* static body buffer 16 (0x10) bytes */ + /* uint16_t buffer_code; 0x11 = 0x10 + 1 */ + /* uint8_t data_ofs; */ + /* uint8_t reserved; */ + /* uint32_t data_size; */ + uint32_t remaining; + uint32_t reserved; + + /* dynamic body */ + DATA_BLOB data; + } out; + } smb2; +}; + + +enum smb_write_level { + RAW_WRITE_WRITEUNLOCK, + RAW_WRITE_WRITE, + RAW_WRITE_WRITEX, + RAW_WRITE_WRITECLOSE, + RAW_WRITE_SPLWRITE, + RAW_WRITE_SMB2 +}; + +#define RAW_WRITE_GENERIC RAW_WRITE_WRITEX + +/* union for write() backend call +*/ +union smb_write { + /* SMBwriteX interface */ + struct { + enum smb_write_level level; + struct { + union smb_handle file; + uint64_t offset; + uint16_t wmode; + uint16_t remaining; + uint32_t count; + const uint8_t *data; + } in; + struct { + uint32_t nwritten; + uint16_t remaining; + } out; + } writex, generic; + + /* SMBwriteunlock interface */ + struct { + enum smb_write_level level; + struct { + union smb_handle file; + uint16_t count; + uint32_t offset; + uint16_t remaining; + const uint8_t *data; + } in; + struct { + uint32_t nwritten; + } out; + } writeunlock; + + /* SMBwrite interface */ + struct { + enum smb_write_level level; + struct { + union smb_handle file; + uint16_t count; + uint32_t offset; + uint16_t remaining; + const uint8_t *data; + } in; + struct { + uint16_t nwritten; + } out; + } write; + + /* SMBwriteclose interface */ + struct { + enum smb_write_level level; + struct { + union smb_handle file; + uint16_t count; + uint32_t offset; + time_t mtime; + const uint8_t *data; + } in; + struct { + uint16_t nwritten; + } out; + } writeclose; + + /* SMBsplwrite interface */ + struct { + enum smb_write_level level; + struct { + union smb_handle file; + uint16_t count; + const uint8_t *data; + } in; + } splwrite; + + /* SMB2 Write */ + struct smb2_write { + enum smb_write_level level; + struct { + union smb_handle file; + + /* static body buffer 48 (0x30) bytes */ + /* uint16_t buffer_code; 0x31 = 0x30 + 1 */ + /* uint16_t data_ofs; */ + /* uint32_t data_size; */ + uint64_t offset; + /* struct smb2_handle handle; */ + uint64_t unknown1; /* 0xFFFFFFFFFFFFFFFF */ + uint64_t unknown2; /* 0xFFFFFFFFFFFFFFFF */ + + /* dynamic body */ + DATA_BLOB data; + } in; + struct { + /* static body buffer 17 (0x11) bytes */ + /* uint16_t buffer_code; 0x11 = 0x10 + 1*/ + uint16_t _pad; + uint32_t nwritten; + uint64_t unknown1; /* 0x0000000000000000 */ + } out; + } smb2; +}; + + +enum smb_lock_level { + RAW_LOCK_LOCK, + RAW_LOCK_UNLOCK, + RAW_LOCK_LOCKX, + RAW_LOCK_SMB2, + RAW_LOCK_SMB2_BREAK +}; + +#define RAW_LOCK_GENERIC RAW_LOCK_LOCKX + +/* union for lock() backend call +*/ +union smb_lock { + /* SMBlockingX and generic interface */ + struct { + enum smb_lock_level level; + struct { + union smb_handle file; + uint16_t mode; + uint32_t timeout; + uint16_t ulock_cnt; + uint16_t lock_cnt; + struct smb_lock_entry { + uint32_t pid; /* 16 bits in SMB1 */ + uint64_t offset; + uint64_t count; + } *locks; /* unlocks are first in the arrray */ + } in; + } generic, lockx; + + /* SMBlock and SMBunlock interface */ + struct { + enum smb_lock_level level; + struct { + union smb_handle file; + uint32_t count; + uint32_t offset; + } in; + } lock, unlock; + + /* SMB2 Lock */ + struct smb2_lock { + enum smb_lock_level level; + struct { + union smb_handle file; + + /* static body buffer 48 (0x30) bytes */ + /* uint16_t buffer_code; 0x30 */ + uint16_t lock_count; + uint32_t lock_sequence; + /* struct smb2_handle handle; */ + struct smb2_lock_element *locks; + } in; + struct { + /* static body buffer 4 (0x04) bytes */ + /* uint16_t buffer_code; 0x04 */ + uint16_t reserved; + } out; + } smb2; + + /* SMB2 Break */ + struct smb2_break { + enum smb_lock_level level; + struct { + union smb_handle file; + + /* static body buffer 24 (0x18) bytes */ + uint8_t oplock_level; + uint8_t reserved; + uint32_t reserved2; + /* struct smb2_handle handle; */ + } in, out; + } smb2_break; + + /* SMB2 Lease Break Ack (same opcode as smb2_break) */ + struct smb2_lease_break_ack { + struct { + uint32_t reserved; + struct smb2_lease lease; + } in, out; + } smb2_lease_break_ack; +}; + + +enum smb_close_level { + RAW_CLOSE_CLOSE, + RAW_CLOSE_SPLCLOSE, + RAW_CLOSE_SMB2, + RAW_CLOSE_GENERIC, +}; + +/* + union for close() backend call +*/ +union smb_close { + /* generic interface */ + struct { + enum smb_close_level level; + struct { + union smb_handle file; + time_t write_time; + uint16_t flags; /* SMB2_CLOSE_FLAGS_* */ + } in; + struct { + uint16_t flags; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t alloc_size; + uint64_t size; + uint32_t file_attr; + } out; + } generic; + + /* SMBclose interface */ + struct { + enum smb_close_level level; + struct { + union smb_handle file; + time_t write_time; + } in; + } close; + + /* SMBsplclose interface - empty! */ + struct { + enum smb_close_level level; + struct { + union smb_handle file; + } in; + } splclose; + + /* SMB2 Close */ + struct smb2_close { + enum smb_close_level level; + struct { + union smb_handle file; + + /* static body buffer 24 (0x18) bytes */ + /* uint16_t buffer_code; 0x18 */ + uint16_t flags; /* SMB2_CLOSE_FLAGS_* */ + uint32_t _pad; + } in; + struct { + /* static body buffer 60 (0x3C) bytes */ + /* uint16_t buffer_code; 0x3C */ + uint16_t flags; + uint32_t _pad; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t alloc_size; + uint64_t size; + uint32_t file_attr; + } out; + } smb2; +}; + + +enum smb_lpq_level {RAW_LPQ_GENERIC, RAW_LPQ_RETQ}; + +/* + union for lpq() backend +*/ +union smb_lpq { + /* generic interface */ + struct { + enum smb_lpq_level level; + + } generic; + + + /* SMBsplretq interface */ + struct { + enum smb_lpq_level level; + + struct { + uint16_t maxcount; + uint16_t startidx; + } in; + struct { + uint16_t count; + uint16_t restart_idx; + struct { + time_t time; + uint8_t status; + uint16_t job; + uint32_t size; + char *user; + } *queue; + } out; + } retq; +}; + +enum smb_ioctl_level { + RAW_IOCTL_IOCTL, + RAW_IOCTL_NTIOCTL, + RAW_IOCTL_SMB2, + RAW_IOCTL_SMB2_NO_HANDLE +}; + +/* + union for ioctl() backend +*/ +union smb_ioctl { + /* generic interface */ + struct { + enum smb_ioctl_level level; + struct { + union smb_handle file; + } in; + } generic; + + /* struct for SMBioctl */ + struct { + enum smb_ioctl_level level; + struct { + union smb_handle file; + uint32_t request; + } in; + struct { + DATA_BLOB blob; + } out; + } ioctl; + + + /* struct for NT ioctl call */ + struct { + enum smb_ioctl_level level; + struct { + union smb_handle file; + uint32_t function; + bool fsctl; + uint8_t filter; + uint32_t max_data; + DATA_BLOB blob; + } in; + struct { + DATA_BLOB blob; + } out; + } ntioctl; + + /* SMB2 Ioctl */ + struct smb2_ioctl { + enum smb_ioctl_level level; + struct { + union smb_handle file; + + /* static body buffer 56 (0x38) bytes */ + /* uint16_t buffer_code; 0x39 = 0x38 + 1 */ + uint16_t reserved; + uint32_t function; + /*struct smb2_handle handle;*/ + /* uint32_t out_ofs; */ + /* uint32_t out_size; */ + uint32_t max_input_response; + /* uint32_t in_ofs; */ + /* uint32_t in_size; */ + uint32_t max_output_response; + uint32_t flags; + uint32_t reserved2; + + /* dynamic body */ + DATA_BLOB out; + DATA_BLOB in; + } in; + struct { + union smb_handle file; + + /* static body buffer 48 (0x30) bytes */ + /* uint16_t buffer_code; 0x31 = 0x30 + 1 */ + uint16_t reserved; + uint32_t function; + /* struct smb2_handle handle; */ + /* uint32_t in_ofs; */ + /* uint32_t in_size; */ + /* uint32_t out_ofs; */ + /* uint32_t out_size; */ + uint32_t flags; + uint32_t reserved2; + + /* dynamic body */ + DATA_BLOB in; + DATA_BLOB out; + } out; + } smb2; +}; + +enum smb_flush_level { + RAW_FLUSH_FLUSH, + RAW_FLUSH_ALL, + RAW_FLUSH_SMB2 +}; + +union smb_flush { + /* struct for SMBflush */ + struct { + enum smb_flush_level level; + struct { + union smb_handle file; + } in; + } flush, generic; + + /* SMBflush with 0xFFFF wildcard fnum */ + struct { + enum smb_flush_level level; + } flush_all; + + /* SMB2 Flush */ + struct smb2_flush { + enum smb_flush_level level; + struct { + union smb_handle file; + uint16_t reserved1; + uint32_t reserved2; + } in; + struct { + uint16_t reserved; + } out; + } smb2; +}; + +/* struct for SMBcopy */ +struct smb_copy { + struct { + uint16_t tid2; + uint16_t ofun; + uint16_t flags; + const char *path1; + const char *path2; + } in; + struct { + uint16_t count; + } out; +}; + + +/* struct for transact/transact2 call */ +struct smb_trans2 { + struct { + uint16_t max_param; + uint16_t max_data; + uint8_t max_setup; + uint16_t flags; + uint32_t timeout; + uint8_t setup_count; + uint16_t *setup; + const char *trans_name; /* SMBtrans only */ + DATA_BLOB params; + DATA_BLOB data; + } in; + + struct { + uint8_t setup_count; + uint16_t *setup; + DATA_BLOB params; + DATA_BLOB data; + } out; +}; + +/* struct for nttransact2 call */ +struct smb_nttrans { + struct { + uint8_t max_setup; + uint32_t max_param; + uint32_t max_data; + uint8_t setup_count; + uint16_t function; + uint8_t *setup; + DATA_BLOB params; + DATA_BLOB data; + } in; + + struct { + uint8_t setup_count; /* in units of 16 bit words */ + uint8_t *setup; + DATA_BLOB params; + DATA_BLOB data; + } out; +}; + +enum smb_notify_level { + RAW_NOTIFY_NTTRANS, + RAW_NOTIFY_SMB2 +}; + +union smb_notify { + /* struct for nttrans change notify call */ + struct { + enum smb_notify_level level; + + struct { + union smb_handle file; + uint32_t buffer_size; + uint32_t completion_filter; + bool recursive; + } in; + + struct { + uint32_t num_changes; + struct notify_changes { + uint32_t action; + struct smb_wire_string name; + } *changes; + } out; + } nttrans; + + struct smb2_notify { + enum smb_notify_level level; + + struct { + union smb_handle file; + /* static body buffer 32 (0x20) bytes */ + /* uint16_t buffer_code; 0x32 */ + uint16_t recursive; + uint32_t buffer_size; + /*struct smb2_handle file;*/ + uint32_t completion_filter; + uint32_t unknown; + } in; + + struct { + /* static body buffer 8 (0x08) bytes */ + /* uint16_t buffer_code; 0x09 = 0x08 + 1 */ + /* uint16_t blob_ofs; */ + /* uint16_t blob_size; */ + + /* dynamic body */ + /*DATA_BLOB blob;*/ + + /* DATA_BLOB content */ + uint32_t num_changes; + struct notify_changes *changes; + } out; + } smb2; +}; + +enum smb_search_level { + RAW_SEARCH_SEARCH, /* SMBsearch */ + RAW_SEARCH_FFIRST, /* SMBffirst */ + RAW_SEARCH_FUNIQUE, /* SMBfunique */ + RAW_SEARCH_TRANS2, /* SMBtrans2 */ + RAW_SEARCH_SMB2 /* SMB2 Find */ +}; + +enum smb_search_data_level { + RAW_SEARCH_DATA_GENERIC = 0x10000, /* only used in the smbcli_ code */ + RAW_SEARCH_DATA_SEARCH, + RAW_SEARCH_DATA_STANDARD = SMB_FIND_STANDARD, + RAW_SEARCH_DATA_EA_SIZE = SMB_FIND_EA_SIZE, + RAW_SEARCH_DATA_EA_LIST = SMB_FIND_EA_LIST, + RAW_SEARCH_DATA_DIRECTORY_INFO = SMB_FIND_DIRECTORY_INFO, + RAW_SEARCH_DATA_FULL_DIRECTORY_INFO = SMB_FIND_FULL_DIRECTORY_INFO, + RAW_SEARCH_DATA_NAME_INFO = SMB_FIND_NAME_INFO, + RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO = SMB_FIND_BOTH_DIRECTORY_INFO, + RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO = SMB_FIND_ID_FULL_DIRECTORY_INFO, + RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO = SMB_FIND_ID_BOTH_DIRECTORY_INFO, + RAW_SEARCH_DATA_UNIX_INFO = SMB_FIND_UNIX_INFO, + RAW_SEARCH_DATA_UNIX_INFO2 = SMB_FIND_UNIX_INFO2 +}; + +/* union for file search */ +union smb_search_first { + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + } generic; + + /* search (old) findfirst interface. + Also used for ffirst and funique. */ + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + + struct { + uint16_t max_count; + uint16_t search_attrib; + const char *pattern; + } in; + struct { + int16_t count; + } out; + } search_first; + + /* trans2 findfirst interface */ + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + + struct { + uint16_t search_attrib; + uint16_t max_count; + uint16_t flags; + uint32_t storage_type; + const char *pattern; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + unsigned int num_names; + struct ea_name *ea_names; + } in; + struct { + uint16_t handle; + uint16_t count; + uint16_t end_of_search; + } out; + } t2ffirst; + + /* SMB2 Find */ + struct smb2_find { + enum smb_search_level level; + enum smb_search_data_level data_level; + struct { + union smb_handle file; + + /* static body buffer 32 (0x20) bytes */ + /* uint16_t buffer_code; 0x21 = 0x20 + 1 */ + uint8_t level; + uint8_t continue_flags; /* SMB2_CONTINUE_FLAG_* */ + uint32_t file_index; + /* struct smb2_handle handle; */ + /* uint16_t pattern_ofs; */ + /* uint16_t pattern_size; */ + uint32_t max_response_size; + + /* dynamic body */ + const char *pattern; + } in; + struct { + /* static body buffer 8 (0x08) bytes */ + /* uint16_t buffer_code; 0x08 */ + /* uint16_t blob_ofs; */ + /* uint32_t blob_size; */ + + /* dynamic body */ + DATA_BLOB blob; + } out; + } smb2; +}; + +/* union for file search continue */ +union smb_search_next { + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + } generic; + + /* search (old) findnext interface. Also used + for ffirst when continuing */ + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + + struct { + uint16_t max_count; + uint16_t search_attrib; + struct smb_search_id { + uint8_t reserved; + char name[11]; + uint8_t handle; + uint32_t server_cookie; + uint32_t client_cookie; + } id; + } in; + struct { + uint16_t count; + } out; + } search_next; + + /* trans2 findnext interface */ + struct { + enum smb_search_level level; + enum smb_search_data_level data_level; + + struct { + uint16_t handle; + uint16_t max_count; + uint32_t resume_key; + uint16_t flags; + const char *last_name; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + unsigned int num_names; + struct ea_name *ea_names; + } in; + struct { + uint16_t count; + uint16_t end_of_search; + } out; + } t2fnext; + + /* SMB2 Find */ + struct smb2_find smb2; +}; + +/* union for search reply file data */ +union smb_search_data { + /* + * search (old) findfirst + * RAW_SEARCH_DATA_SEARCH + */ + struct { + uint16_t attrib; + time_t write_time; + uint32_t size; + struct smb_search_id id; + const char *name; + } search; + + /* trans2 findfirst RAW_SEARCH_DATA_STANDARD level */ + struct { + uint32_t resume_key; + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + struct smb_wire_string name; + } standard; + + /* trans2 findfirst RAW_SEARCH_DATA_EA_SIZE level */ + struct { + uint32_t resume_key; + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + uint32_t ea_size; + struct smb_wire_string name; + } ea_size; + + /* trans2 findfirst RAW_SEARCH_DATA_EA_LIST level */ + struct { + uint32_t resume_key; + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + struct smb_ea_list eas; + struct smb_wire_string name; + } ea_list; + + /* RAW_SEARCH_DATA_DIRECTORY_INFO interface */ + struct { + uint32_t file_index; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t size; + uint64_t alloc_size; + uint32_t attrib; + struct smb_wire_string name; + } directory_info; + + /* RAW_SEARCH_DATA_FULL_DIRECTORY_INFO interface */ + struct { + uint32_t file_index; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t size; + uint64_t alloc_size; + uint32_t attrib; + uint32_t ea_size; + struct smb_wire_string name; + } full_directory_info; + + /* RAW_SEARCH_DATA_NAME_INFO interface */ + struct { + uint32_t file_index; + struct smb_wire_string name; + } name_info; + + /* RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO interface */ + struct { + uint32_t file_index; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t size; + uint64_t alloc_size; + uint32_t attrib; + uint32_t ea_size; + struct smb_wire_string short_name; + struct smb_wire_string name; + } both_directory_info; + + /* RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO interface */ + struct { + uint32_t file_index; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t size; + uint64_t alloc_size; + uint32_t attrib; + uint32_t ea_size; + uint64_t file_id; + struct smb_wire_string name; + } id_full_directory_info; + + /* RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO interface */ + struct { + uint32_t file_index; + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint64_t size; + uint64_t alloc_size; + uint32_t attrib; + uint32_t ea_size; + uint64_t file_id; + uint8_t short_name_buf[24]; + struct smb_wire_string short_name; + struct smb_wire_string name; + } id_both_directory_info; + + /* RAW_SEARCH_DATA_UNIX_INFO interface */ + struct { + uint32_t file_index; + uint64_t size; + uint64_t alloc_size; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + const char *name; + } unix_info; + + /* RAW_SEARCH_DATA_UNIX_INFO2 interface */ + struct { + uint32_t file_index; + uint64_t end_of_file; + uint64_t num_bytes; + NTTIME status_change_time; + NTTIME access_time; + NTTIME change_time; + uint64_t uid; + uint64_t gid; + uint32_t file_type; + uint64_t dev_major; + uint64_t dev_minor; + uint64_t unique_id; + uint64_t permissions; + uint64_t nlink; + NTTIME create_time; + uint32_t file_flags; + uint32_t flags_mask; + struct smb_wire_string name; + } unix_info2; +}; + +/* Callback function passed to the raw search interface. */ +typedef bool (*smbcli_search_callback)(void *private_data, const union smb_search_data *file); + +enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_FCLOSE, RAW_FINDCLOSE_FINDCLOSE}; + +/* union for file search close */ +union smb_search_close { + struct { + enum smb_search_close_level level; + } generic; + + /* SMBfclose (old search) interface */ + struct { + enum smb_search_close_level level; + + struct { + /* max_count and search_attrib are not used, but are present */ + uint16_t max_count; + uint16_t search_attrib; + struct smb_search_id id; + } in; + } fclose; + + /* SMBfindclose interface */ + struct { + enum smb_search_close_level level; + + struct { + uint16_t handle; + } in; + } findclose; +}; + + +/* + struct for SMBecho call +*/ +struct smb_echo { + struct { + uint16_t repeat_count; + uint16_t size; + uint8_t *data; + } in; + struct { + uint16_t count; + uint16_t sequence_number; + uint16_t size; + uint8_t *data; + } out; +}; + +/* + struct for shadow copy volumes + */ +struct smb_shadow_copy { + struct { + union smb_handle file; + uint32_t max_data; + } in; + struct { + uint32_t num_volumes; + uint32_t num_names; + const char **names; + } out; +}; + +#endif /* __LIBCLI_RAW_INTERFACES_H__ */ diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h new file mode 100644 index 0000000..a4c4cf3 --- /dev/null +++ b/source4/libcli/raw/libcliraw.h @@ -0,0 +1,343 @@ +/* + Unix SMB/CIFS implementation. + SMB parameters and setup + + Copyright (C) Andrew Tridgell 2002-2004 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LIBCLI_RAW_H__ +#define __LIBCLI_RAW_H__ + +#include "../libcli/smb/smb_common.h" +#include "libcli/raw/request.h" +#include "librpc/gen_ndr/nbt.h" +#include "libcli/raw/interfaces.h" +#include "libcli/smb/smb2_negotiate_context.h" + +struct smbcli_tree; /* forward declare */ +struct smbcli_request; /* forward declare */ +struct smbcli_session; /* forward declare */ +struct smbcli_transport; /* forward declare */ + +struct resolve_context; +struct cli_credentials; +struct gensec_settings; + +/* default timeout for all smb requests */ +#define SMB_REQUEST_TIMEOUT 60 + +/* context that will be and has been negotiated between the client and server */ +struct smbcli_negotiate { + /* + * negotiated maximum transmit size - this is given to us by the server + */ + uint32_t max_xmit; + + /* maximum number of requests that can be multiplexed */ + uint16_t max_mux; + + /* the negotiatiated protocol */ + enum protocol_types protocol; + + uint8_t sec_mode; /* security mode returned by negprot */ + DATA_BLOB secblob; /* cryptkey or negTokenInit blob */ + uint32_t sesskey; + + /* capabilities that the server reported */ + uint32_t capabilities; + + int server_zone; + time_t server_time; + + unsigned int readbraw_supported:1; + unsigned int writebraw_supported:1; + unsigned int lockread_supported:1; +}; + +/* this is the context for a SMB socket associated with the socket itself */ +struct smbcli_socket { + struct socket_context *sock; + + /* what port we ended up connected to */ + int port; + + /* the hostname we connected to */ + const char *hostname; + + /* the event handle for waiting for socket IO */ + struct { + struct tevent_context *ctx; + struct tevent_fd *fde; + struct tevent_timer *te; + } event; +}; + +/* + this structure allows applications to control the behaviour of the + client library +*/ +struct smbcli_options { + unsigned int use_oplocks:1; + unsigned int use_level2_oplocks:1; + unsigned int use_spnego:1; + unsigned int unicode:1; + unsigned int ntstatus_support:1; + int min_protocol; + int max_protocol; + uint32_t max_xmit; + uint16_t max_mux; + int request_timeout; + enum smb_signing_setting signing; + uint32_t smb2_capabilities; + struct GUID client_guid; + uint64_t max_credits; + unsigned int only_negprot; + struct smb311_capabilities smb3_capabilities; +}; + +/* this is the context for the client transport layer */ +struct smbcli_transport { + struct tevent_context *ev; /* TODO: remove this !!! */ + struct smbXcli_conn *conn; + + /* negotiated protocol information */ + struct smbcli_negotiate negotiate; + + /* options to control the behaviour of the client code */ + struct smbcli_options options; + + /* an idle function - if this is defined then it will be + called once every period microseconds while we are waiting + for a packet */ + struct { + void (*func)(struct smbcli_transport *, void *); + void *private_data; + unsigned int period; + struct tevent_timer *te; + } idle; + + /* the error fields from the last message */ + struct { + enum {ETYPE_NONE, ETYPE_SMB, ETYPE_SOCKET, ETYPE_NBT} etype; + union { + NTSTATUS nt_status; + enum {SOCKET_READ_TIMEOUT, + SOCKET_READ_EOF, + SOCKET_READ_ERROR, + SOCKET_WRITE_ERROR, + SOCKET_READ_BAD_SIG} socket_error; + unsigned int nbt_error; + } e; + } error; + + struct { + /* a oplock break request handler */ + bool (*handler)(struct smbcli_transport *transport, + uint16_t tid, uint16_t fnum, uint8_t level, void *private_data); + /* private data passed to the oplock handler */ + void *private_data; + } oplock; + struct tevent_req *break_subreq; +}; + +/* this is the context for the user */ + +/* this is the context for the session layer */ +struct smbcli_session { + /* transport layer info */ + struct smbcli_transport *transport; + + /* after a session setup the server provides us with + a vuid identifying the security context */ + struct smbXcli_session *smbXcli; + uint16_t vuid; + + /* default pid for this session */ + uint32_t pid; + + /* the flags2 for each packet - this allows + the user to control these for torture testing */ + uint16_t flags2; + + /* the spnego context if we use extented security */ + struct gensec_security *gensec; + + struct smbcli_session_options { + unsigned int lanman_auth:1; + unsigned int ntlmv2_auth:1; + unsigned int plaintext_auth:1; + } options; + + const char *os; + const char *lanman; +}; + +/* + smbcli_tree context: internal state for a tree connection. + */ +struct smbcli_tree { + /* session layer info */ + struct smbcli_session *session; + + struct smbXcli_tcon *smbXcli; + uint16_t tid; /* tree id, aka cnum */ + char *device; + char *fs_type; +}; + + +/* + a client request moves between the following 4 states. +*/ +enum smbcli_request_state {SMBCLI_REQUEST_INIT, /* we are creating the request */ + SMBCLI_REQUEST_RECV, /* we are waiting for a matching reply */ + SMBCLI_REQUEST_DONE, /* the request is finished */ + SMBCLI_REQUEST_ERROR}; /* a packet or transport level error has occurred */ + +/* the context for a single SMB request. This is passed to any request-context + * functions (similar to context.h, the server version). + * This will allow requests to be multi-threaded. */ +struct smbcli_request { + /* smbXcli_req */ + struct tevent_req *subreqs[2]; + + /* each request is in one of 4 possible states */ + enum smbcli_request_state state; + + /* a request always has a transport context, nearly always has + a session context and usually has a tree context */ + struct smbcli_transport *transport; + struct smbcli_session *session; + struct smbcli_tree *tree; + + /* the flags2 from the SMB request, in raw form (host byte + order). Used to parse strings */ + uint16_t flags2; + + /* the NT status for this request. Set by packet receive code + or code detecting error. */ + NTSTATUS status; + + /* the caller wants to do the signing check */ + bool sign_caller_checks; + + /* give the caller a chance to prevent the talloc_free() in the _recv() function */ + bool do_not_free; + + struct smb_request_buffer in; + struct smb_request_buffer out; + + struct smb_trans2 trans2; + struct smb_nttrans nttrans; + + /* information on what to do with a reply when it is received + asyncronously. If this is not setup when a reply is received then + the reply is discarded + + The private pointer is private to the caller of the client + library (the application), not private to the library + */ + struct { + void (*fn)(struct smbcli_request *); + void *private_data; + } async; +}; + +/* useful way of catching wct errors with file and line number */ +#define SMBCLI_CHECK_MIN_WCT(req, wcount) if ((req)->in.wct < (wcount)) { \ + DEBUG(1,("Unexpected WCT %d at %s(%d) - expected min %d\n", (req)->in.wct, __FILE__, __LINE__, wcount)); \ + req->status = NT_STATUS_INVALID_PARAMETER; \ + goto failed; \ +} + +#define SMBCLI_CHECK_WCT(req, wcount) if ((req)->in.wct != (wcount)) { \ + DEBUG(1,("Unexpected WCT %d at %s(%d) - expected %d\n", (req)->in.wct, __FILE__, __LINE__, wcount)); \ + req->status = NT_STATUS_INVALID_PARAMETER; \ + goto failed; \ +} + +NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms); +struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_read *parms); +NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms); +struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, struct smb_trans2 *parms); +NTSTATUS smbcli_request_destroy(struct smbcli_request *req); +struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_write *parms); +NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms); +struct smbcli_request *smb_raw_close_send(struct smbcli_tree *tree, union smb_close *parms); +NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms); +struct smbcli_request *smb_raw_open_send(struct smbcli_tree *tree, union smb_open *parms); + +bool smbcli_transport_process(struct smbcli_transport *transport); +const char *smbcli_errstr(struct smbcli_tree *tree); +NTSTATUS smb_raw_fsinfo(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_fsinfo *fsinfo); +NTSTATUS smb_raw_setfsinfo(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_setfsinfo *set_fsinfo); +NTSTATUS smb_raw_pathinfo(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_fileinfo *parms); +NTSTATUS smb_raw_shadow_data(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, struct smb_shadow_copy *info); +NTSTATUS smb_raw_fileinfo(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_fileinfo *parms); +struct smbcli_tree *smbcli_tree_init(struct smbcli_session *session, TALLOC_CTX *parent_ctx, bool primary); +NTSTATUS smb_raw_tcon(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_tcon *parms); +void smbcli_oplock_handler(struct smbcli_transport *transport, + bool (*handler)(struct smbcli_transport *, uint16_t, uint16_t, uint8_t, void *), + void *private_data); +void smbcli_transport_idle_handler(struct smbcli_transport *transport, + void (*idle_func)(struct smbcli_transport *, void *), + uint64_t period, + void *private_data); +NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req); +bool smbcli_oplock_ack(struct smbcli_tree *tree, uint16_t fnum, uint16_t ack_level); +NTSTATUS smb_raw_open(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_open *parms); +NTSTATUS smb_raw_close(struct smbcli_tree *tree, union smb_close *parms); +NTSTATUS smb_raw_unlink(struct smbcli_tree *tree, union smb_unlink *parms); +NTSTATUS smb_raw_chkpath(struct smbcli_tree *tree, union smb_chkpath *parms); +NTSTATUS smb_raw_mkdir(struct smbcli_tree *tree, union smb_mkdir *parms); +NTSTATUS smb_raw_rmdir(struct smbcli_tree *tree, struct smb_rmdir *parms); +NTSTATUS smb_raw_rename(struct smbcli_tree *tree, union smb_rename *parms); +NTSTATUS smb_raw_seek(struct smbcli_tree *tree, union smb_seek *parms); +NTSTATUS smb_raw_read(struct smbcli_tree *tree, union smb_read *parms); +NTSTATUS smb_raw_write(struct smbcli_tree *tree, union smb_write *parms); +NTSTATUS smb_raw_lock(struct smbcli_tree *tree, union smb_lock *parms); +NTSTATUS smb_raw_setpathinfo(struct smbcli_tree *tree, union smb_setfileinfo *parms); +NTSTATUS smb_raw_setfileinfo(struct smbcli_tree *tree, union smb_setfileinfo *parms); + +struct smbcli_request *smb_raw_changenotify_send(struct smbcli_tree *tree, union smb_notify *parms); +NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_notify *parms); + +NTSTATUS smb_tree_disconnect(struct smbcli_tree *tree); +NTSTATUS smbcli_nt_error(struct smbcli_tree *tree); +NTSTATUS smb_raw_exit(struct smbcli_session *session); +NTSTATUS smb_raw_pathinfo_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms); +struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree, + union smb_fileinfo *parms); +struct smbcli_request *smb_raw_setpathinfo_send(struct smbcli_tree *tree, + union smb_setfileinfo *parms); +struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport, + struct smb_echo *p); +NTSTATUS smb_raw_search_first(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_first *io, void *private_data, + smbcli_search_callback callback); +NTSTATUS smb_raw_flush(struct smbcli_tree *tree, union smb_flush *parms); + +NTSTATUS smb_raw_trans(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms); + +#endif /* __LIBCLI_RAW__H__ */ diff --git a/source4/libcli/raw/rawacl.c b/source4/libcli/raw/rawacl.c new file mode 100644 index 0000000..c2de2cc --- /dev/null +++ b/source4/libcli/raw/rawacl.c @@ -0,0 +1,163 @@ +/* + Unix SMB/CIFS implementation. + ACL get/set operations + + Copyright (C) Andrew Tridgell 2003-2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_security.h" + +/**************************************************************************** +fetch file ACL (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_query_secdesc_send(struct smbcli_tree *tree, + union smb_fileinfo *io) +{ + struct smb_nttrans nt; + uint8_t params[8]; + + nt.in.max_setup = 0; + nt.in.max_param = 4; + nt.in.max_data = 0xFFFF; + nt.in.setup_count = 0; + nt.in.function = NT_TRANSACT_QUERY_SECURITY_DESC; + nt.in.setup = NULL; + + SSVAL(params, 0, io->query_secdesc.in.file.fnum); + SSVAL(params, 2, 0); /* padding */ + SIVAL(params, 4, io->query_secdesc.in.secinfo_flags); + + nt.in.params.data = params; + nt.in.params.length = 8; + + nt.in.data = data_blob(NULL, 0); + + return smb_raw_nttrans_send(tree, &nt); +} + + +/**************************************************************************** +fetch file ACL (async recv) +****************************************************************************/ +NTSTATUS smb_raw_query_secdesc_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *io) +{ + NTSTATUS status; + struct smb_nttrans nt; + struct ndr_pull *ndr; + enum ndr_err_code ndr_err; + + status = smb_raw_nttrans_recv(req, mem_ctx, &nt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* check that the basics are valid */ + if (nt.out.params.length != 4 || + IVAL(nt.out.params.data, 0) > nt.out.data.length) { + return NT_STATUS_INVALID_PARAMETER; + } + + nt.out.data.length = IVAL(nt.out.params.data, 0); + + ndr = ndr_pull_init_blob(&nt.out.data, mem_ctx); + if (!ndr) { + return NT_STATUS_INVALID_PARAMETER; + } + + io->query_secdesc.out.sd = talloc(mem_ctx, struct security_descriptor); + if (!io->query_secdesc.out.sd) { + return NT_STATUS_NO_MEMORY; + } + ndr_err = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, + io->query_secdesc.out.sd); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; +} + + +/**************************************************************************** +fetch file ACL (sync interface) +****************************************************************************/ +NTSTATUS smb_raw_query_secdesc(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *io) +{ + struct smbcli_request *req = smb_raw_query_secdesc_send(tree, io); + return smb_raw_query_secdesc_recv(req, mem_ctx, io); +} + + + +/**************************************************************************** +set file ACL (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_set_secdesc_send(struct smbcli_tree *tree, + union smb_setfileinfo *io) +{ + struct smb_nttrans nt; + uint8_t params[8]; + struct ndr_push *ndr; + struct smbcli_request *req; + enum ndr_err_code ndr_err; + + nt.in.max_setup = 0; + nt.in.max_param = 0; + nt.in.max_data = 0; + nt.in.setup_count = 0; + nt.in.function = NT_TRANSACT_SET_SECURITY_DESC; + nt.in.setup = NULL; + + SSVAL(params, 0, io->set_secdesc.in.file.fnum); + SSVAL(params, 2, 0); /* padding */ + SIVAL(params, 4, io->set_secdesc.in.secinfo_flags); + + nt.in.params.data = params; + nt.in.params.length = 8; + + ndr = ndr_push_init_ctx(NULL); + if (!ndr) return NULL; + + ndr_err = ndr_push_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, io->set_secdesc.in.sd); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(ndr); + return NULL; + } + + nt.in.data = ndr_push_blob(ndr); + + req = smb_raw_nttrans_send(tree, &nt); + + talloc_free(ndr); + return req; +} + +/**************************************************************************** +set file ACL (sync interface) +****************************************************************************/ +NTSTATUS smb_raw_set_secdesc(struct smbcli_tree *tree, + union smb_setfileinfo *io) +{ + struct smbcli_request *req = smb_raw_set_secdesc_send(tree, io); + return smbcli_request_simple_recv(req); +} diff --git a/source4/libcli/raw/rawdate.c b/source4/libcli/raw/rawdate.c new file mode 100644 index 0000000..5264653 --- /dev/null +++ b/source4/libcli/raw/rawdate.c @@ -0,0 +1,82 @@ +/* + Unix SMB/CIFS implementation. + + raw date handling functions + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/******************************************************************* +put a dos date into a buffer (time/date format) +This takes GMT time and puts local time for zone_offset in the buffer +********************************************************************/ +void raw_push_dos_date(struct smbcli_transport *transport, + uint8_t *buf, int offset, time_t unixdate) +{ + push_dos_date(buf, offset, unixdate, transport->negotiate.server_zone); +} + +/******************************************************************* +put a dos date into a buffer (date/time format) +This takes GMT time and puts local time in the buffer +********************************************************************/ +void raw_push_dos_date2(struct smbcli_transport *transport, + uint8_t *buf, int offset, time_t unixdate) +{ + push_dos_date2(buf, offset, unixdate, transport->negotiate.server_zone); +} + +/******************************************************************* +put a dos 32 bit "unix like" date into a buffer. This routine takes +GMT and converts it to LOCAL time in zone_offset before putting it +********************************************************************/ +void raw_push_dos_date3(struct smbcli_transport *transport, + uint8_t *buf, int offset, time_t unixdate) +{ + push_dos_date3(buf, offset, unixdate, transport->negotiate.server_zone); +} + +/******************************************************************* +convert a dos date +********************************************************************/ +time_t raw_pull_dos_date(struct smbcli_transport *transport, + const uint8_t *date_ptr) +{ + return pull_dos_date(date_ptr, transport->negotiate.server_zone); +} + +/******************************************************************* +like raw_pull_dos_date() but the words are reversed +********************************************************************/ +time_t raw_pull_dos_date2(struct smbcli_transport *transport, + const uint8_t *date_ptr) +{ + return pull_dos_date2(date_ptr, transport->negotiate.server_zone); +} + +/******************************************************************* + create a unix GMT date from a dos date in 32 bit "unix like" format + these arrive in server zone, with corresponding DST + ******************************************************************/ +time_t raw_pull_dos_date3(struct smbcli_transport *transport, + const uint8_t *date_ptr) +{ + return pull_dos_date3(date_ptr, transport->negotiate.server_zone); +} diff --git a/source4/libcli/raw/raweas.c b/source4/libcli/raw/raweas.c new file mode 100644 index 0000000..2f551b0 --- /dev/null +++ b/source4/libcli/raw/raweas.c @@ -0,0 +1,371 @@ +/* + Unix SMB/CIFS implementation. + parsing of EA (extended attribute) lists + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/* + work out how many bytes on the wire a ea list will consume. + This assumes the names are strict ascii, which should be a + reasonable assumption +*/ +size_t ea_list_size(unsigned int num_eas, struct ea_struct *eas) +{ + unsigned int total = 4; + int i; + for (i=0;i<num_eas;i++) { + total += 4 + strlen(eas[i].name.s)+1 + eas[i].value.length; + } + return total; +} + +/* + work out how many bytes on the wire a ea name list will consume. +*/ +static unsigned int ea_name_list_size(unsigned int num_names, struct ea_name *eas) +{ + unsigned int total = 4; + int i; + for (i=0;i<num_names;i++) { + total += 1 + strlen(eas[i].name.s) + 1; + } + return total; +} + +/* + work out how many bytes on the wire a chained ea list will consume. + This assumes the names are strict ascii, which should be a + reasonable assumption +*/ +size_t ea_list_size_chained(unsigned int num_eas, struct ea_struct *eas, unsigned alignment) +{ + unsigned int total = 0; + int i; + for (i=0;i<num_eas;i++) { + unsigned int len = 8 + strlen(eas[i].name.s)+1 + eas[i].value.length; + len = (len + (alignment-1)) & ~(alignment-1); + total += len; + } + return total; +} + +/* + put a ea_list into a pre-allocated buffer - buffer must be at least + of size ea_list_size() +*/ +void ea_put_list(uint8_t *data, unsigned int num_eas, struct ea_struct *eas) +{ + int i; + uint32_t ea_size; + + ea_size = ea_list_size(num_eas, eas); + + SIVAL(data, 0, ea_size); + data += 4; + + for (i=0;i<num_eas;i++) { + unsigned int nlen = strlen(eas[i].name.s); + SCVAL(data, 0, eas[i].flags); + SCVAL(data, 1, nlen); + SSVAL(data, 2, eas[i].value.length); + memcpy(data+4, eas[i].name.s, nlen+1); + if (eas[i].value.length > 0) { + memcpy(data + 4 + nlen + 1, + eas[i].value.data, + eas[i].value.length); + } + data += 4+nlen+1+eas[i].value.length; + } +} + + +/* + put a chained ea_list into a pre-allocated buffer - buffer must be + at least of size ea_list_size() +*/ +void ea_put_list_chained(uint8_t *data, unsigned int num_eas, struct ea_struct *eas, + unsigned alignment) +{ + int i; + + for (i=0;i<num_eas;i++) { + unsigned int nlen = strlen(eas[i].name.s); + uint32_t len = 8+nlen+1+eas[i].value.length; + unsigned int pad = ((len + (alignment-1)) & ~(alignment-1)) - len; + if (i == num_eas-1) { + SIVAL(data, 0, 0); + } else { + SIVAL(data, 0, len+pad); + } + SCVAL(data, 4, eas[i].flags); + SCVAL(data, 5, nlen); + SSVAL(data, 6, eas[i].value.length); + memcpy(data+8, eas[i].name.s, nlen+1); + memcpy(data+8+nlen+1, eas[i].value.data, eas[i].value.length); + memset(data+len, 0, pad); + data += len + pad; + } +} + + +/* + pull a ea_struct from a buffer. Return the number of bytes consumed +*/ +unsigned int ea_pull_struct(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + struct ea_struct *ea) +{ + uint8_t nlen; + uint16_t vlen; + + ZERO_STRUCTP(ea); + + if (blob->length < 6) { + return 0; + } + + ea->flags = CVAL(blob->data, 0); + nlen = CVAL(blob->data, 1); + vlen = SVAL(blob->data, 2); + + if (nlen+1+vlen > blob->length-4) { + return 0; + } + + ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+4), nlen); + ea->name.private_length = nlen; + ea->value = data_blob_talloc(mem_ctx, NULL, vlen+1); + if (!ea->value.data) return 0; + if (vlen) { + memcpy(ea->value.data, blob->data+4+nlen+1, vlen); + } + ea->value.data[vlen] = 0; + ea->value.length--; + + return 4 + nlen+1 + vlen; +} + + +/* + pull a ea_list from a buffer +*/ +NTSTATUS ea_pull_list(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + unsigned int *num_eas, struct ea_struct **eas) +{ + int n; + uint32_t ea_size, ofs; + + if (blob->length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + ea_size = IVAL(blob->data, 0); + if (ea_size > blob->length) { + return NT_STATUS_INVALID_PARAMETER; + } + + ofs = 4; + n = 0; + *num_eas = 0; + *eas = NULL; + + while (ofs < ea_size) { + unsigned int len; + DATA_BLOB blob2; + + blob2.data = blob->data + ofs; + blob2.length = ea_size - ofs; + + *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1); + if (! *eas) return NT_STATUS_NO_MEMORY; + + len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]); + if (len == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + ofs += len; + n++; + } + + *num_eas = n; + + return NT_STATUS_OK; +} + + +/* + pull a chained ea_list from a buffer +*/ +NTSTATUS ea_pull_list_chained(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + unsigned int *num_eas, struct ea_struct **eas) +{ + int n; + uint32_t ofs; + + if (blob->length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + ofs = 0; + n = 0; + *num_eas = 0; + *eas = NULL; + + while (ofs < blob->length) { + unsigned int len; + DATA_BLOB blob2; + uint32_t next_ofs = IVAL(blob->data, ofs); + + blob2.data = blob->data + ofs + 4; + blob2.length = blob->length - (ofs + 4); + + *eas = talloc_realloc(mem_ctx, *eas, struct ea_struct, n+1); + if (! *eas) return NT_STATUS_NO_MEMORY; + + len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]); + if (len == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (ofs + next_ofs < ofs) { + return NT_STATUS_INVALID_PARAMETER; + } + + ofs += next_ofs; + if (ofs+4 > blob->length || ofs+4 < ofs) { + return NT_STATUS_INVALID_PARAMETER; + } + n++; + if (next_ofs == 0) break; + } + + *num_eas = n; + + return NT_STATUS_OK; +} + + +/* + pull a ea_name from a buffer. Return the number of bytes consumed +*/ +static unsigned int ea_pull_name(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + struct ea_name *ea) +{ + uint8_t nlen; + + if (blob->length < 2) { + return 0; + } + + nlen = CVAL(blob->data, 0); + + if (nlen+2 > blob->length) { + return 0; + } + + ea->name.s = talloc_strndup(mem_ctx, (const char *)(blob->data+1), nlen); + ea->name.private_length = nlen; + + return nlen+2; +} + + +/* + pull a ea_name list from a buffer +*/ +NTSTATUS ea_pull_name_list(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + unsigned int *num_names, struct ea_name **ea_names) +{ + int n; + uint32_t ea_size, ofs; + + if (blob->length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + ea_size = IVAL(blob->data, 0); + if (ea_size > blob->length) { + return NT_STATUS_INVALID_PARAMETER; + } + + ofs = 4; + n = 0; + *num_names = 0; + *ea_names = NULL; + + while (ofs < ea_size) { + unsigned int len; + DATA_BLOB blob2; + + blob2.data = blob->data + ofs; + blob2.length = ea_size - ofs; + + *ea_names = talloc_realloc(mem_ctx, *ea_names, struct ea_name, n+1); + if (! *ea_names) return NT_STATUS_NO_MEMORY; + + len = ea_pull_name(&blob2, mem_ctx, &(*ea_names)[n]); + if (len == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + ofs += len; + n++; + } + + *num_names = n; + + return NT_STATUS_OK; +} + + +/* + put a ea_name list into a data blob +*/ +bool ea_push_name_list(TALLOC_CTX *mem_ctx, + DATA_BLOB *data, unsigned int num_names, struct ea_name *eas) +{ + int i; + uint32_t ea_size; + uint32_t off; + + ea_size = ea_name_list_size(num_names, eas); + + *data = data_blob_talloc(mem_ctx, NULL, ea_size); + if (data->data == NULL) { + return false; + } + + SIVAL(data->data, 0, ea_size); + off = 4; + + for (i=0;i<num_names;i++) { + unsigned int nlen = strlen(eas[i].name.s); + SCVAL(data->data, off, nlen); + memcpy(data->data+off+1, eas[i].name.s, nlen+1); + off += 1+nlen+1; + } + + return true; +} diff --git a/source4/libcli/raw/rawfile.c b/source4/libcli/raw/rawfile.c new file mode 100644 index 0000000..39e9a8d --- /dev/null +++ b/source4/libcli/raw/rawfile.c @@ -0,0 +1,1052 @@ +/* + Unix SMB/CIFS implementation. + client file operations + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) Jeremy Allison 2001-2002 + Copyright (C) James Myers 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_security.h" + +#define SETUP_REQUEST(cmd, wct, buflen) do { \ + req = smbcli_request_setup(tree, cmd, wct, buflen); \ + if (!req) return NULL; \ +} while (0) + +/**************************************************************************** + Rename a file - async interface +****************************************************************************/ +struct smbcli_request *smb_raw_rename_send(struct smbcli_tree *tree, + union smb_rename *parms) +{ + struct smbcli_request *req = NULL; + struct smb_nttrans nt; + TALLOC_CTX *mem_ctx; + + switch (parms->generic.level) { + case RAW_RENAME_RENAME: + SETUP_REQUEST(SMBmv, 1, 0); + SSVAL(req->out.vwv, VWV(0), parms->rename.in.attrib); + smbcli_req_append_ascii4(req, parms->rename.in.pattern1, STR_TERMINATE); + smbcli_req_append_ascii4(req, parms->rename.in.pattern2, STR_TERMINATE); + break; + + case RAW_RENAME_NTRENAME: + SETUP_REQUEST(SMBntrename, 4, 0); + SSVAL(req->out.vwv, VWV(0), parms->ntrename.in.attrib); + SSVAL(req->out.vwv, VWV(1), parms->ntrename.in.flags); + SIVAL(req->out.vwv, VWV(2), parms->ntrename.in.cluster_size); + smbcli_req_append_ascii4(req, parms->ntrename.in.old_name, STR_TERMINATE); + smbcli_req_append_ascii4(req, parms->ntrename.in.new_name, STR_TERMINATE); + break; + + case RAW_RENAME_NTTRANS: + + mem_ctx = talloc_new(tree); + + nt.in.max_setup = 0; + nt.in.max_param = 0; + nt.in.max_data = 0; + nt.in.setup_count = 0; + nt.in.setup = NULL; + nt.in.function = NT_TRANSACT_RENAME; + nt.in.params = data_blob_talloc(mem_ctx, NULL, 4); + nt.in.data = data_blob(NULL, 0); + + SSVAL(nt.in.params.data, VWV(0), parms->nttrans.in.file.fnum); + SSVAL(nt.in.params.data, VWV(1), parms->nttrans.in.flags); + + smbcli_blob_append_string(tree->session, mem_ctx, + &nt.in.params, parms->nttrans.in.new_name, + STR_TERMINATE); + + req = smb_raw_nttrans_send(tree, &nt); + talloc_free(mem_ctx); + return req; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Rename a file - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_rename(struct smbcli_tree *tree, + union smb_rename *parms) +{ + struct smbcli_request *req = smb_raw_rename_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + Delete a file - async interface +****************************************************************************/ +struct smbcli_request *smb_raw_unlink_send(struct smbcli_tree *tree, + union smb_unlink *parms) +{ + struct smbcli_request *req; + + SETUP_REQUEST(SMBunlink, 1, 0); + + SSVAL(req->out.vwv, VWV(0), parms->unlink.in.attrib); + smbcli_req_append_ascii4(req, parms->unlink.in.pattern, STR_TERMINATE); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + return req; +} + +/* + delete a file - sync interface +*/ +_PUBLIC_ NTSTATUS smb_raw_unlink(struct smbcli_tree *tree, + union smb_unlink *parms) +{ + struct smbcli_request *req = smb_raw_unlink_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + create a directory using TRANSACT2_MKDIR - async interface +****************************************************************************/ +static struct smbcli_request *smb_raw_t2mkdir_send(struct smbcli_tree *tree, + union smb_mkdir *parms) +{ + struct smb_trans2 t2; + uint16_t setup = TRANSACT2_MKDIR; + TALLOC_CTX *mem_ctx; + struct smbcli_request *req; + uint16_t data_total; + + mem_ctx = talloc_init("t2mkdir"); + + data_total = ea_list_size(parms->t2mkdir.in.num_eas, parms->t2mkdir.in.eas); + + t2.in.max_param = 2; + t2.in.max_data = 0; + t2.in.max_setup = 0; + t2.in.flags = 0; + t2.in.timeout = 0; + t2.in.setup_count = 1; + t2.in.setup = &setup; + t2.in.params = data_blob_talloc(mem_ctx, NULL, 4); + t2.in.data = data_blob_talloc(mem_ctx, NULL, data_total); + + SIVAL(t2.in.params.data, VWV(0), 0); /* reserved */ + + smbcli_blob_append_string(tree->session, mem_ctx, + &t2.in.params, parms->t2mkdir.in.path, STR_TERMINATE); + + ea_put_list(t2.in.data.data, parms->t2mkdir.in.num_eas, parms->t2mkdir.in.eas); + + req = smb_raw_trans2_send(tree, &t2); + + talloc_free(mem_ctx); + + return req; +} + +/**************************************************************************** + Create a directory - async interface +****************************************************************************/ +struct smbcli_request *smb_raw_mkdir_send(struct smbcli_tree *tree, + union smb_mkdir *parms) +{ + struct smbcli_request *req; + + if (parms->generic.level == RAW_MKDIR_T2MKDIR) { + return smb_raw_t2mkdir_send(tree, parms); + } + + if (parms->generic.level != RAW_MKDIR_MKDIR) { + return NULL; + } + + SETUP_REQUEST(SMBmkdir, 0, 0); + + smbcli_req_append_ascii4(req, parms->mkdir.in.path, STR_TERMINATE); + + if (!smbcli_request_send(req)) { + return NULL; + } + + return req; +} + +/**************************************************************************** + Create a directory - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_mkdir(struct smbcli_tree *tree, + union smb_mkdir *parms) +{ + struct smbcli_request *req = smb_raw_mkdir_send(tree, parms); + return smbcli_request_simple_recv(req); +} + +/**************************************************************************** + Remove a directory - async interface +****************************************************************************/ +struct smbcli_request *smb_raw_rmdir_send(struct smbcli_tree *tree, + struct smb_rmdir *parms) +{ + struct smbcli_request *req; + + SETUP_REQUEST(SMBrmdir, 0, 0); + + smbcli_req_append_ascii4(req, parms->in.path, STR_TERMINATE); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Remove a directory - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_rmdir(struct smbcli_tree *tree, + struct smb_rmdir *parms) +{ + struct smbcli_request *req = smb_raw_rmdir_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/* + Open a file using TRANSACT2_OPEN - async recv +*/ +static NTSTATUS smb_raw_nttrans_create_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_open *parms) +{ + NTSTATUS status; + struct smb_nttrans nt; + uint8_t *params; + + status = smb_raw_nttrans_recv(req, mem_ctx, &nt); + if (!NT_STATUS_IS_OK(status)) return status; + + if (nt.out.params.length < 69) { + return NT_STATUS_INVALID_PARAMETER; + } + + params = nt.out.params.data; + + parms->ntcreatex.out.oplock_level = CVAL(params, 0); + parms->ntcreatex.out.file.fnum = SVAL(params, 2); + parms->ntcreatex.out.create_action = IVAL(params, 4); + parms->ntcreatex.out.create_time = smbcli_pull_nttime(params, 12); + parms->ntcreatex.out.access_time = smbcli_pull_nttime(params, 20); + parms->ntcreatex.out.write_time = smbcli_pull_nttime(params, 28); + parms->ntcreatex.out.change_time = smbcli_pull_nttime(params, 36); + parms->ntcreatex.out.attrib = IVAL(params, 44); + parms->ntcreatex.out.alloc_size = BVAL(params, 48); + parms->ntcreatex.out.size = BVAL(params, 56); + parms->ntcreatex.out.file_type = SVAL(params, 64); + parms->ntcreatex.out.ipc_state = SVAL(params, 66); + parms->ntcreatex.out.is_directory = CVAL(params, 68); + + return NT_STATUS_OK; +} + + +/* + Open a file using NTTRANS CREATE - async send +*/ +static struct smbcli_request *smb_raw_nttrans_create_send(struct smbcli_tree *tree, + union smb_open *parms) +{ + struct smb_nttrans nt; + uint8_t *params; + TALLOC_CTX *mem_ctx = talloc_new(tree); + uint16_t fname_len; + DATA_BLOB sd_blob, ea_blob; + struct smbcli_request *req; + + nt.in.max_setup = 0; + nt.in.max_param = 101; + nt.in.max_data = 0; + nt.in.setup_count = 0; + nt.in.function = NT_TRANSACT_CREATE; + nt.in.setup = NULL; + + sd_blob = data_blob(NULL, 0); + ea_blob = data_blob(NULL, 0); + + if (parms->ntcreatex.in.sec_desc) { + enum ndr_err_code ndr_err; + ndr_err = ndr_push_struct_blob(&sd_blob, mem_ctx, + parms->ntcreatex.in.sec_desc, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(mem_ctx); + return NULL; + } + } + + if (parms->ntcreatex.in.ea_list) { + uint32_t ea_size = ea_list_size_chained(parms->ntcreatex.in.ea_list->num_eas, + parms->ntcreatex.in.ea_list->eas, 4); + ea_blob = data_blob_talloc(mem_ctx, NULL, ea_size); + if (ea_blob.data == NULL) { + return NULL; + } + ea_put_list_chained(ea_blob.data, + parms->ntcreatex.in.ea_list->num_eas, + parms->ntcreatex.in.ea_list->eas, 4); + } + + nt.in.params = data_blob_talloc(mem_ctx, NULL, 53); + if (nt.in.params.data == NULL) { + talloc_free(mem_ctx); + return NULL; + } + + /* build the parameter section */ + params = nt.in.params.data; + + SIVAL(params, 0, parms->ntcreatex.in.flags); + SIVAL(params, 4, parms->ntcreatex.in.root_fid.fnum); + SIVAL(params, 8, parms->ntcreatex.in.access_mask); + SBVAL(params, 12, parms->ntcreatex.in.alloc_size); + SIVAL(params, 20, parms->ntcreatex.in.file_attr); + SIVAL(params, 24, parms->ntcreatex.in.share_access); + SIVAL(params, 28, parms->ntcreatex.in.open_disposition); + SIVAL(params, 32, parms->ntcreatex.in.create_options); + SIVAL(params, 36, sd_blob.length); + SIVAL(params, 40, ea_blob.length); + SIVAL(params, 48, parms->ntcreatex.in.impersonation); + SCVAL(params, 52, parms->ntcreatex.in.security_flags); + + /* the empty string first forces the correct alignment */ + smbcli_blob_append_string(tree->session, mem_ctx, &nt.in.params,"", 0); + fname_len = smbcli_blob_append_string(tree->session, mem_ctx, &nt.in.params, + parms->ntcreatex.in.fname, STR_TERMINATE); + + SIVAL(nt.in.params.data, 44, fname_len); + + /* build the data section */ + nt.in.data = data_blob_talloc(mem_ctx, NULL, sd_blob.length + ea_blob.length); + if (sd_blob.length > 0) { + memcpy(nt.in.data.data, sd_blob.data, sd_blob.length); + } + if (ea_blob.length > 0) { + memcpy(nt.in.data.data + sd_blob.length, + ea_blob.data, + ea_blob.length); + } + + /* send the request on its way */ + req = smb_raw_nttrans_send(tree, &nt); + + talloc_free(mem_ctx); + + return req; +} + + +/**************************************************************************** + Open a file using TRANSACT2_OPEN - async send +****************************************************************************/ +static struct smbcli_request *smb_raw_t2open_send(struct smbcli_tree *tree, + union smb_open *parms) +{ + struct smb_trans2 t2; + uint16_t setup = TRANSACT2_OPEN; + TALLOC_CTX *mem_ctx = talloc_init("smb_raw_t2open"); + struct smbcli_request *req; + uint16_t list_size; + + list_size = ea_list_size(parms->t2open.in.num_eas, parms->t2open.in.eas); + + t2.in.max_param = 30; + t2.in.max_data = 0; + t2.in.max_setup = 0; + t2.in.flags = 0; + t2.in.timeout = 0; + t2.in.setup_count = 1; + t2.in.setup = &setup; + t2.in.params = data_blob_talloc(mem_ctx, NULL, 28); + t2.in.data = data_blob_talloc(mem_ctx, NULL, list_size); + + SSVAL(t2.in.params.data, VWV(0), parms->t2open.in.flags); + SSVAL(t2.in.params.data, VWV(1), parms->t2open.in.open_mode); + SSVAL(t2.in.params.data, VWV(2), parms->t2open.in.search_attrs); + SSVAL(t2.in.params.data, VWV(3), parms->t2open.in.file_attrs); + raw_push_dos_date(tree->session->transport, + t2.in.params.data, VWV(4), parms->t2open.in.write_time); + SSVAL(t2.in.params.data, VWV(6), parms->t2open.in.open_func); + SIVAL(t2.in.params.data, VWV(7), parms->t2open.in.size); + SIVAL(t2.in.params.data, VWV(9), parms->t2open.in.timeout); + SIVAL(t2.in.params.data, VWV(11), 0); + SSVAL(t2.in.params.data, VWV(13), 0); + + smbcli_blob_append_string(tree->session, mem_ctx, + &t2.in.params, parms->t2open.in.fname, + STR_TERMINATE); + + ea_put_list(t2.in.data.data, parms->t2open.in.num_eas, parms->t2open.in.eas); + + req = smb_raw_trans2_send(tree, &t2); + + talloc_free(mem_ctx); + + return req; +} + + +/**************************************************************************** + Open a file using TRANSACT2_OPEN - async recv +****************************************************************************/ +static NTSTATUS smb_raw_t2open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms) +{ + struct smbcli_transport *transport = req->transport; + struct smb_trans2 t2; + NTSTATUS status; + + status = smb_raw_trans2_recv(req, mem_ctx, &t2); + if (!NT_STATUS_IS_OK(status)) return status; + + if (t2.out.params.length < 30) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + parms->t2open.out.file.fnum = SVAL(t2.out.params.data, VWV(0)); + parms->t2open.out.attrib = SVAL(t2.out.params.data, VWV(1)); + parms->t2open.out.write_time = raw_pull_dos_date3(transport, t2.out.params.data + VWV(2)); + parms->t2open.out.size = IVAL(t2.out.params.data, VWV(4)); + parms->t2open.out.access = SVAL(t2.out.params.data, VWV(6)); + parms->t2open.out.ftype = SVAL(t2.out.params.data, VWV(7)); + parms->t2open.out.devstate = SVAL(t2.out.params.data, VWV(8)); + parms->t2open.out.action = SVAL(t2.out.params.data, VWV(9)); + parms->t2open.out.file_id = SVAL(t2.out.params.data, VWV(10)); + + return NT_STATUS_OK; +} + +/**************************************************************************** + Open a file - async send +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_open_send(struct smbcli_tree *tree, union smb_open *parms) +{ + int len; + struct smbcli_request *req = NULL; + bool bigoffset = false; + + switch (parms->generic.level) { + case RAW_OPEN_T2OPEN: + return smb_raw_t2open_send(tree, parms); + + case RAW_OPEN_OPEN: + SETUP_REQUEST(SMBopen, 2, 0); + SSVAL(req->out.vwv, VWV(0), parms->openold.in.open_mode); + SSVAL(req->out.vwv, VWV(1), parms->openold.in.search_attrs); + smbcli_req_append_ascii4(req, parms->openold.in.fname, STR_TERMINATE); + break; + + case RAW_OPEN_OPENX: + SETUP_REQUEST(SMBopenX, 15, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->openx.in.flags); + SSVAL(req->out.vwv, VWV(3), parms->openx.in.open_mode); + SSVAL(req->out.vwv, VWV(4), parms->openx.in.search_attrs); + SSVAL(req->out.vwv, VWV(5), parms->openx.in.file_attrs); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(6), parms->openx.in.write_time); + SSVAL(req->out.vwv, VWV(8), parms->openx.in.open_func); + SIVAL(req->out.vwv, VWV(9), parms->openx.in.size); + SIVAL(req->out.vwv, VWV(11),parms->openx.in.timeout); + SIVAL(req->out.vwv, VWV(13),0); /* reserved */ + smbcli_req_append_string(req, parms->openx.in.fname, STR_TERMINATE); + break; + + case RAW_OPEN_MKNEW: + SETUP_REQUEST(SMBmknew, 3, 0); + SSVAL(req->out.vwv, VWV(0), parms->mknew.in.attrib); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(1), parms->mknew.in.write_time); + smbcli_req_append_ascii4(req, parms->mknew.in.fname, STR_TERMINATE); + break; + + case RAW_OPEN_CREATE: + SETUP_REQUEST(SMBcreate, 3, 0); + SSVAL(req->out.vwv, VWV(0), parms->create.in.attrib); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(1), parms->create.in.write_time); + smbcli_req_append_ascii4(req, parms->create.in.fname, STR_TERMINATE); + break; + + case RAW_OPEN_CTEMP: + SETUP_REQUEST(SMBctemp, 3, 0); + SSVAL(req->out.vwv, VWV(0), parms->ctemp.in.attrib); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(1), parms->ctemp.in.write_time); + smbcli_req_append_ascii4(req, parms->ctemp.in.directory, STR_TERMINATE); + break; + + case RAW_OPEN_SPLOPEN: + SETUP_REQUEST(SMBsplopen, 2, 0); + SSVAL(req->out.vwv, VWV(0), parms->splopen.in.setup_length); + SSVAL(req->out.vwv, VWV(1), parms->splopen.in.mode); + break; + + case RAW_OPEN_NTCREATEX: + SETUP_REQUEST(SMBntcreateX, 24, 0); + SSVAL(req->out.vwv, VWV(0),SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1),0); + SCVAL(req->out.vwv, VWV(2),0); /* padding */ + SIVAL(req->out.vwv, 7, parms->ntcreatex.in.flags); + SIVAL(req->out.vwv, 11, parms->ntcreatex.in.root_fid.fnum); + SIVAL(req->out.vwv, 15, parms->ntcreatex.in.access_mask); + SBVAL(req->out.vwv, 19, parms->ntcreatex.in.alloc_size); + SIVAL(req->out.vwv, 27, parms->ntcreatex.in.file_attr); + SIVAL(req->out.vwv, 31, parms->ntcreatex.in.share_access); + SIVAL(req->out.vwv, 35, parms->ntcreatex.in.open_disposition); + SIVAL(req->out.vwv, 39, parms->ntcreatex.in.create_options); + SIVAL(req->out.vwv, 43, parms->ntcreatex.in.impersonation); + SCVAL(req->out.vwv, 47, parms->ntcreatex.in.security_flags); + + smbcli_req_append_string_len(req, parms->ntcreatex.in.fname, STR_TERMINATE, &len); + SSVAL(req->out.vwv, 5, len); + break; + + case RAW_OPEN_NTTRANS_CREATE: + return smb_raw_nttrans_create_send(tree, parms); + + + case RAW_OPEN_OPENX_READX: + SETUP_REQUEST(SMBopenX, 15, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->openxreadx.in.flags); + SSVAL(req->out.vwv, VWV(3), parms->openxreadx.in.open_mode); + SSVAL(req->out.vwv, VWV(4), parms->openxreadx.in.search_attrs); + SSVAL(req->out.vwv, VWV(5), parms->openxreadx.in.file_attrs); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(6), parms->openxreadx.in.write_time); + SSVAL(req->out.vwv, VWV(8), parms->openxreadx.in.open_func); + SIVAL(req->out.vwv, VWV(9), parms->openxreadx.in.size); + SIVAL(req->out.vwv, VWV(11),parms->openxreadx.in.timeout); + SIVAL(req->out.vwv, VWV(13),0); + smbcli_req_append_string(req, parms->openxreadx.in.fname, STR_TERMINATE); + + if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) { + bigoffset = true; + } + + smbcli_chained_request_setup(req, SMBreadX, bigoffset ? 12 : 10, 0); + + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), 0); + SIVAL(req->out.vwv, VWV(3), parms->openxreadx.in.offset); + SSVAL(req->out.vwv, VWV(5), parms->openxreadx.in.maxcnt & 0xFFFF); + SSVAL(req->out.vwv, VWV(6), parms->openxreadx.in.mincnt); + SIVAL(req->out.vwv, VWV(7), parms->openxreadx.in.maxcnt >> 16); + SSVAL(req->out.vwv, VWV(9), parms->openxreadx.in.remaining); + if (bigoffset) { + SIVAL(req->out.vwv, VWV(10),parms->openxreadx.in.offset>>32); + } + break; + + case RAW_OPEN_NTCREATEX_READX: + SETUP_REQUEST(SMBntcreateX, 24, 0); + SSVAL(req->out.vwv, VWV(0),SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1),0); + SCVAL(req->out.vwv, VWV(2),0); /* padding */ + SIVAL(req->out.vwv, 7, parms->ntcreatexreadx.in.flags); + SIVAL(req->out.vwv, 11, parms->ntcreatexreadx.in.root_fid.fnum); + SIVAL(req->out.vwv, 15, parms->ntcreatexreadx.in.access_mask); + SBVAL(req->out.vwv, 19, parms->ntcreatexreadx.in.alloc_size); + SIVAL(req->out.vwv, 27, parms->ntcreatexreadx.in.file_attr); + SIVAL(req->out.vwv, 31, parms->ntcreatexreadx.in.share_access); + SIVAL(req->out.vwv, 35, parms->ntcreatexreadx.in.open_disposition); + SIVAL(req->out.vwv, 39, parms->ntcreatexreadx.in.create_options); + SIVAL(req->out.vwv, 43, parms->ntcreatexreadx.in.impersonation); + SCVAL(req->out.vwv, 47, parms->ntcreatexreadx.in.security_flags); + + smbcli_req_append_string_len(req, parms->ntcreatexreadx.in.fname, STR_TERMINATE, &len); + SSVAL(req->out.vwv, 5, len); + + if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) { + bigoffset = true; + } + + smbcli_chained_request_setup(req, SMBreadX, bigoffset ? 12 : 10, 0); + + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), 0); + SIVAL(req->out.vwv, VWV(3), parms->ntcreatexreadx.in.offset); + SSVAL(req->out.vwv, VWV(5), parms->ntcreatexreadx.in.maxcnt & 0xFFFF); + SSVAL(req->out.vwv, VWV(6), parms->ntcreatexreadx.in.mincnt); + SIVAL(req->out.vwv, VWV(7), parms->ntcreatexreadx.in.maxcnt >> 16); + SSVAL(req->out.vwv, VWV(9), parms->ntcreatexreadx.in.remaining); + if (bigoffset) { + SIVAL(req->out.vwv, VWV(10),parms->ntcreatexreadx.in.offset>>32); + } + break; + + case RAW_OPEN_SMB2: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Open a file - async recv +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms) +{ + NTSTATUS status; + + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + switch (parms->openold.level) { + case RAW_OPEN_T2OPEN: + return smb_raw_t2open_recv(req, mem_ctx, parms); + + case RAW_OPEN_OPEN: + SMBCLI_CHECK_WCT(req, 7); + parms->openold.out.file.fnum = SVAL(req->in.vwv, VWV(0)); + parms->openold.out.attrib = SVAL(req->in.vwv, VWV(1)); + parms->openold.out.write_time = raw_pull_dos_date3(req->transport, + req->in.vwv + VWV(2)); + parms->openold.out.size = IVAL(req->in.vwv, VWV(4)); + parms->openold.out.rmode = SVAL(req->in.vwv, VWV(6)); + break; + + case RAW_OPEN_OPENX: + SMBCLI_CHECK_MIN_WCT(req, 15); + parms->openx.out.file.fnum = SVAL(req->in.vwv, VWV(2)); + parms->openx.out.attrib = SVAL(req->in.vwv, VWV(3)); + parms->openx.out.write_time = raw_pull_dos_date3(req->transport, + req->in.vwv + VWV(4)); + parms->openx.out.size = IVAL(req->in.vwv, VWV(6)); + parms->openx.out.access = SVAL(req->in.vwv, VWV(8)); + parms->openx.out.ftype = SVAL(req->in.vwv, VWV(9)); + parms->openx.out.devstate = SVAL(req->in.vwv, VWV(10)); + parms->openx.out.action = SVAL(req->in.vwv, VWV(11)); + parms->openx.out.unique_fid = IVAL(req->in.vwv, VWV(12)); + if (req->in.wct >= 19) { + parms->openx.out.access_mask = IVAL(req->in.vwv, VWV(15)); + parms->openx.out.unknown = IVAL(req->in.vwv, VWV(17)); + } else { + parms->openx.out.access_mask = 0; + parms->openx.out.unknown = 0; + } + break; + + case RAW_OPEN_MKNEW: + SMBCLI_CHECK_WCT(req, 1); + parms->mknew.out.file.fnum = SVAL(req->in.vwv, VWV(0)); + break; + + case RAW_OPEN_CREATE: + SMBCLI_CHECK_WCT(req, 1); + parms->create.out.file.fnum = SVAL(req->in.vwv, VWV(0)); + break; + + case RAW_OPEN_CTEMP: + SMBCLI_CHECK_WCT(req, 1); + parms->ctemp.out.file.fnum = SVAL(req->in.vwv, VWV(0)); + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->ctemp.out.name, req->in.data, -1, STR_TERMINATE | STR_ASCII); + break; + + case RAW_OPEN_SPLOPEN: + SMBCLI_CHECK_WCT(req, 1); + parms->splopen.out.file.fnum = SVAL(req->in.vwv, VWV(0)); + break; + + case RAW_OPEN_NTCREATEX: + SMBCLI_CHECK_MIN_WCT(req, 34); + parms->ntcreatex.out.oplock_level = CVAL(req->in.vwv, 4); + parms->ntcreatex.out.file.fnum = SVAL(req->in.vwv, 5); + parms->ntcreatex.out.create_action = IVAL(req->in.vwv, 7); + parms->ntcreatex.out.create_time = smbcli_pull_nttime(req->in.vwv, 11); + parms->ntcreatex.out.access_time = smbcli_pull_nttime(req->in.vwv, 19); + parms->ntcreatex.out.write_time = smbcli_pull_nttime(req->in.vwv, 27); + parms->ntcreatex.out.change_time = smbcli_pull_nttime(req->in.vwv, 35); + parms->ntcreatex.out.attrib = IVAL(req->in.vwv, 43); + parms->ntcreatex.out.alloc_size = BVAL(req->in.vwv, 47); + parms->ntcreatex.out.size = BVAL(req->in.vwv, 55); + parms->ntcreatex.out.file_type = SVAL(req->in.vwv, 63); + parms->ntcreatex.out.ipc_state = SVAL(req->in.vwv, 65); + parms->ntcreatex.out.is_directory = CVAL(req->in.vwv, 67); + break; + + case RAW_OPEN_NTTRANS_CREATE: + return smb_raw_nttrans_create_recv(req, mem_ctx, parms); + + case RAW_OPEN_OPENX_READX: + SMBCLI_CHECK_MIN_WCT(req, 15); + parms->openxreadx.out.file.fnum = SVAL(req->in.vwv, VWV(2)); + parms->openxreadx.out.attrib = SVAL(req->in.vwv, VWV(3)); + parms->openxreadx.out.write_time = raw_pull_dos_date3(req->transport, + req->in.vwv + VWV(4)); + parms->openxreadx.out.size = IVAL(req->in.vwv, VWV(6)); + parms->openxreadx.out.access = SVAL(req->in.vwv, VWV(8)); + parms->openxreadx.out.ftype = SVAL(req->in.vwv, VWV(9)); + parms->openxreadx.out.devstate = SVAL(req->in.vwv, VWV(10)); + parms->openxreadx.out.action = SVAL(req->in.vwv, VWV(11)); + parms->openxreadx.out.unique_fid = IVAL(req->in.vwv, VWV(12)); + if (req->in.wct >= 19) { + parms->openxreadx.out.access_mask = IVAL(req->in.vwv, VWV(15)); + parms->openxreadx.out.unknown = IVAL(req->in.vwv, VWV(17)); + } else { + parms->openxreadx.out.access_mask = 0; + parms->openxreadx.out.unknown = 0; + } + + status = smbcli_chained_advance(req); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + SMBCLI_CHECK_WCT(req, 12); + parms->openxreadx.out.remaining = SVAL(req->in.vwv, VWV(2)); + parms->openxreadx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); + parms->openxreadx.out.nread = SVAL(req->in.vwv, VWV(5)); + if (parms->openxreadx.out.nread > + MAX(parms->openxreadx.in.mincnt, parms->openxreadx.in.maxcnt) || + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), + parms->openxreadx.out.nread, + parms->openxreadx.out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + break; + + case RAW_OPEN_NTCREATEX_READX: + SMBCLI_CHECK_MIN_WCT(req, 34); + parms->ntcreatexreadx.out.oplock_level = CVAL(req->in.vwv, 4); + parms->ntcreatexreadx.out.file.fnum = SVAL(req->in.vwv, 5); + parms->ntcreatexreadx.out.create_action = IVAL(req->in.vwv, 7); + parms->ntcreatexreadx.out.create_time = smbcli_pull_nttime(req->in.vwv, 11); + parms->ntcreatexreadx.out.access_time = smbcli_pull_nttime(req->in.vwv, 19); + parms->ntcreatexreadx.out.write_time = smbcli_pull_nttime(req->in.vwv, 27); + parms->ntcreatexreadx.out.change_time = smbcli_pull_nttime(req->in.vwv, 35); + parms->ntcreatexreadx.out.attrib = IVAL(req->in.vwv, 43); + parms->ntcreatexreadx.out.alloc_size = BVAL(req->in.vwv, 47); + parms->ntcreatexreadx.out.size = BVAL(req->in.vwv, 55); + parms->ntcreatexreadx.out.file_type = SVAL(req->in.vwv, 63); + parms->ntcreatexreadx.out.ipc_state = SVAL(req->in.vwv, 65); + parms->ntcreatexreadx.out.is_directory = CVAL(req->in.vwv, 67); + + status = smbcli_chained_advance(req); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + SMBCLI_CHECK_WCT(req, 12); + parms->ntcreatexreadx.out.remaining = SVAL(req->in.vwv, VWV(2)); + parms->ntcreatexreadx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); + parms->ntcreatexreadx.out.nread = SVAL(req->in.vwv, VWV(5)); + if (parms->ntcreatexreadx.out.nread > + MAX(parms->ntcreatexreadx.in.mincnt, parms->ntcreatexreadx.in.maxcnt) || + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), + parms->ntcreatexreadx.out.nread, + parms->ntcreatexreadx.out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + break; + + case RAW_OPEN_SMB2: + req->status = NT_STATUS_INTERNAL_ERROR; + break; + } + +failed: + return smbcli_request_destroy(req); +} + + +/**************************************************************************** + Open a file - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_open(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, union smb_open *parms) +{ + struct smbcli_request *req = smb_raw_open_send(tree, parms); + return smb_raw_open_recv(req, mem_ctx, parms); +} + + +/**************************************************************************** + Close a file - async send +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_close_send(struct smbcli_tree *tree, union smb_close *parms) +{ + struct smbcli_request *req = NULL; + + switch (parms->generic.level) { + case RAW_CLOSE_CLOSE: + SETUP_REQUEST(SMBclose, 3, 0); + SSVAL(req->out.vwv, VWV(0), parms->close.in.file.fnum); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(1), parms->close.in.write_time); + break; + + case RAW_CLOSE_SPLCLOSE: + SETUP_REQUEST(SMBsplclose, 3, 0); + SSVAL(req->out.vwv, VWV(0), parms->splclose.in.file.fnum); + SIVAL(req->out.vwv, VWV(1), 0); /* reserved */ + break; + + case RAW_CLOSE_SMB2: + case RAW_CLOSE_GENERIC: + return NULL; + } + + if (!req) return NULL; + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + + +/**************************************************************************** + Close a file - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_close(struct smbcli_tree *tree, union smb_close *parms) +{ + struct smbcli_request *req = smb_raw_close_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + Locking calls - async interface +****************************************************************************/ +struct smbcli_request *smb_raw_lock_send(struct smbcli_tree *tree, union smb_lock *parms) +{ + struct smbcli_request *req = NULL; + + switch (parms->generic.level) { + case RAW_LOCK_LOCK: + SETUP_REQUEST(SMBlock, 5, 0); + SSVAL(req->out.vwv, VWV(0), parms->lock.in.file.fnum); + SIVAL(req->out.vwv, VWV(1), parms->lock.in.count); + SIVAL(req->out.vwv, VWV(3), parms->lock.in.offset); + break; + + case RAW_LOCK_UNLOCK: + SETUP_REQUEST(SMBunlock, 5, 0); + SSVAL(req->out.vwv, VWV(0), parms->unlock.in.file.fnum); + SIVAL(req->out.vwv, VWV(1), parms->unlock.in.count); + SIVAL(req->out.vwv, VWV(3), parms->unlock.in.offset); + break; + + case RAW_LOCK_LOCKX: { + struct smb_lock_entry *lockp; + unsigned int lck_size = (parms->lockx.in.mode & LOCKING_ANDX_LARGE_FILES)? 20 : 10; + unsigned int lock_count = parms->lockx.in.ulock_cnt + parms->lockx.in.lock_cnt; + int i; + + SETUP_REQUEST(SMBlockingX, 8, lck_size * lock_count); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->lockx.in.file.fnum); + SSVAL(req->out.vwv, VWV(3), parms->lockx.in.mode); + SIVAL(req->out.vwv, VWV(4), parms->lockx.in.timeout); + SSVAL(req->out.vwv, VWV(6), parms->lockx.in.ulock_cnt); + SSVAL(req->out.vwv, VWV(7), parms->lockx.in.lock_cnt); + + /* copy in all the locks */ + lockp = &parms->lockx.in.locks[0]; + for (i = 0; i < lock_count; i++) { + uint8_t *p = req->out.data + lck_size * i; + SSVAL(p, 0, lockp[i].pid); + if (parms->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) { + SSVAL(p, 2, 0); /* reserved */ + SIVAL(p, 4, lockp[i].offset>>32); + SIVAL(p, 8, lockp[i].offset); + SIVAL(p, 12, lockp[i].count>>32); + SIVAL(p, 16, lockp[i].count); + } else { + SIVAL(p, 2, lockp[i].offset); + SIVAL(p, 6, lockp[i].count); + } + } + break; + } + case RAW_LOCK_SMB2: + case RAW_LOCK_SMB2_BREAK: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Locking calls - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_lock(struct smbcli_tree *tree, union smb_lock *parms) +{ + struct smbcli_request *req = smb_raw_lock_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + Check for existence of a dir - async send +****************************************************************************/ +struct smbcli_request *smb_raw_chkpath_send(struct smbcli_tree *tree, union smb_chkpath *parms) +{ + struct smbcli_request *req; + + SETUP_REQUEST(SMBcheckpath, 0, 0); + + smbcli_req_append_ascii4(req, parms->chkpath.in.path, STR_TERMINATE); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Check for existence of a dir - sync interface +****************************************************************************/ +NTSTATUS smb_raw_chkpath(struct smbcli_tree *tree, union smb_chkpath *parms) +{ + struct smbcli_request *req = smb_raw_chkpath_send(tree, parms); + return smbcli_request_simple_recv(req); +} + +/**************************************************************************** + flush a file - async send + a flush with RAW_FLUSH_ALL will flush all files +****************************************************************************/ +struct smbcli_request *smb_raw_flush_send(struct smbcli_tree *tree, union smb_flush *parms) +{ + struct smbcli_request *req; + uint16_t fnum=0; + + switch (parms->generic.level) { + case RAW_FLUSH_FLUSH: + fnum = parms->flush.in.file.fnum; + break; + case RAW_FLUSH_ALL: + fnum = 0xFFFF; + break; + case RAW_FLUSH_SMB2: + return NULL; + } + + SETUP_REQUEST(SMBflush, 1, 0); + SSVAL(req->out.vwv, VWV(0), fnum); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + + +/**************************************************************************** + flush a file - sync interface +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_flush(struct smbcli_tree *tree, union smb_flush *parms) +{ + struct smbcli_request *req = smb_raw_flush_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + seek a file - async send +****************************************************************************/ +struct smbcli_request *smb_raw_seek_send(struct smbcli_tree *tree, + union smb_seek *parms) +{ + struct smbcli_request *req; + + SETUP_REQUEST(SMBlseek, 4, 0); + + SSVAL(req->out.vwv, VWV(0), parms->lseek.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->lseek.in.mode); + SIVALS(req->out.vwv, VWV(2), parms->lseek.in.offset); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + return req; +} + +/**************************************************************************** + seek a file - async receive +****************************************************************************/ +NTSTATUS smb_raw_seek_recv(struct smbcli_request *req, + union smb_seek *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + return smbcli_request_destroy(req); + } + + SMBCLI_CHECK_WCT(req, 2); + parms->lseek.out.offset = IVAL(req->in.vwv, VWV(0)); + +failed: + return smbcli_request_destroy(req); +} + +/* + seek a file - sync interface +*/ +_PUBLIC_ NTSTATUS smb_raw_seek(struct smbcli_tree *tree, + union smb_seek *parms) +{ + struct smbcli_request *req = smb_raw_seek_send(tree, parms); + return smb_raw_seek_recv(req, parms); +} diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c new file mode 100644 index 0000000..b18bc87 --- /dev/null +++ b/source4/libcli/raw/rawfileinfo.c @@ -0,0 +1,810 @@ +/* + Unix SMB/CIFS implementation. + client trans2 operations + Copyright (C) James Myers 2003 + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James Peach 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_security.h" + +/* local macros to make the code more readable */ +#define FINFO_CHECK_MIN_SIZE(size) if (blob->length < (size)) { \ + DEBUG(1,("Unexpected FILEINFO reply size %d for level %u - expected min of %d\n", \ + (int)blob->length, parms->generic.level, (size))); \ + return NT_STATUS_INFO_LENGTH_MISMATCH; \ +} +#define FINFO_CHECK_SIZE(size) if (blob->length != (size)) { \ + DEBUG(1,("Unexpected FILEINFO reply size %d for level %u - expected %d\n", \ + (int)blob->length, parms->generic.level, (size))); \ + return NT_STATUS_INFO_LENGTH_MISMATCH; \ +} + +/* + parse a stream information structure +*/ +NTSTATUS smbcli_parse_stream_info(DATA_BLOB blob, TALLOC_CTX *mem_ctx, + struct stream_information *io) +{ + uint32_t ofs = 0; + io->num_streams = 0; + io->streams = NULL; + + while (blob.length - ofs >= 24) { + unsigned int n = io->num_streams; + uint32_t nlen, len; + bool ret; + void *vstr; + size_t converted_size = 0; + + io->streams = + talloc_realloc(mem_ctx, io->streams, struct stream_struct, n+1); + if (!io->streams) { + return NT_STATUS_NO_MEMORY; + } + nlen = IVAL(blob.data, ofs + 0x04); + io->streams[n].size = BVAL(blob.data, ofs + 0x08); + io->streams[n].alloc_size = BVAL(blob.data, ofs + 0x10); + if (nlen > blob.length - (ofs + 24)) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + ret = convert_string_talloc(io->streams, + CH_UTF16, CH_UNIX, + blob.data+ofs+24, nlen, &vstr, &converted_size); + if (!ret) { + return NT_STATUS_ILLEGAL_CHARACTER; + } + io->streams[n].stream_name.s = (const char *)vstr; + io->streams[n].stream_name.private_length = nlen; + io->num_streams++; + len = IVAL(blob.data, ofs); + if (len > blob.length - ofs) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + if (len == 0) break; + ofs += len; + } + + return NT_STATUS_OK; +} + +/* + parse the fsinfo 'passthru' level replies +*/ +NTSTATUS smb_raw_fileinfo_passthru_parse(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + enum smb_fileinfo_level level, + union smb_fileinfo *parms) +{ + switch (level) { + case RAW_FILEINFO_BASIC_INFORMATION: + /* some servers return 40 bytes and some 36. w2k3 return 40, so thats + what we should do, but we need to accept 36 */ + if (blob->length != 36) { + FINFO_CHECK_SIZE(40); + } + parms->basic_info.out.create_time = smbcli_pull_nttime(blob->data, 0); + parms->basic_info.out.access_time = smbcli_pull_nttime(blob->data, 8); + parms->basic_info.out.write_time = smbcli_pull_nttime(blob->data, 16); + parms->basic_info.out.change_time = smbcli_pull_nttime(blob->data, 24); + parms->basic_info.out.attrib = IVAL(blob->data, 32); + return NT_STATUS_OK; + + case RAW_FILEINFO_STANDARD_INFORMATION: + FINFO_CHECK_SIZE(24); + parms->standard_info.out.alloc_size = BVAL(blob->data, 0); + parms->standard_info.out.size = BVAL(blob->data, 8); + parms->standard_info.out.nlink = IVAL(blob->data, 16); + parms->standard_info.out.delete_pending = CVAL(blob->data, 20); + parms->standard_info.out.directory = CVAL(blob->data, 21); + return NT_STATUS_OK; + + case RAW_FILEINFO_EA_INFORMATION: + FINFO_CHECK_SIZE(4); + parms->ea_info.out.ea_size = IVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_NAME_INFORMATION: + FINFO_CHECK_MIN_SIZE(4); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->name_info.out.fname, 0, 4, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_ALL_INFORMATION: + FINFO_CHECK_MIN_SIZE(72); + parms->all_info.out.create_time = smbcli_pull_nttime(blob->data, 0); + parms->all_info.out.access_time = smbcli_pull_nttime(blob->data, 8); + parms->all_info.out.write_time = smbcli_pull_nttime(blob->data, 16); + parms->all_info.out.change_time = smbcli_pull_nttime(blob->data, 24); + parms->all_info.out.attrib = IVAL(blob->data, 32); + parms->all_info.out.alloc_size = BVAL(blob->data, 40); + parms->all_info.out.size = BVAL(blob->data, 48); + parms->all_info.out.nlink = IVAL(blob->data, 56); + parms->all_info.out.delete_pending = CVAL(blob->data, 60); + parms->all_info.out.directory = CVAL(blob->data, 61); +#if 1 + parms->all_info.out.ea_size = IVAL(blob->data, 64); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->all_info.out.fname, 68, 72, STR_UNICODE); +#else + /* this is what the CIFS spec says - and its totally + wrong, but its useful having it here so we can + quickly adapt to broken servers when running + tests */ + parms->all_info.out.ea_size = IVAL(blob->data, 72); + /* access flags 4 bytes at 76 + current_position 8 bytes at 80 + mode 4 bytes at 88 + alignment 4 bytes at 92 + */ + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->all_info.out.fname, 96, 100, STR_UNICODE); +#endif + return NT_STATUS_OK; + + case RAW_FILEINFO_ALT_NAME_INFORMATION: + case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION: + FINFO_CHECK_MIN_SIZE(4); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->alt_name_info.out.fname, 0, 4, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_STREAM_INFORMATION: + return smbcli_parse_stream_info(*blob, mem_ctx, &parms->stream_info.out); + + case RAW_FILEINFO_INTERNAL_INFORMATION: + FINFO_CHECK_SIZE(8); + parms->internal_information.out.file_id = BVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_ACCESS_INFORMATION: + FINFO_CHECK_SIZE(4); + parms->access_information.out.access_flags = IVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_POSITION_INFORMATION: + FINFO_CHECK_SIZE(8); + parms->position_information.out.position = BVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_MODE_INFORMATION: + FINFO_CHECK_SIZE(4); + parms->mode_information.out.mode = IVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_ALIGNMENT_INFORMATION: + FINFO_CHECK_SIZE(4); + parms->alignment_information.out.alignment_requirement + = IVAL(blob->data, 0); + return NT_STATUS_OK; + + case RAW_FILEINFO_COMPRESSION_INFORMATION: + FINFO_CHECK_SIZE(16); + parms->compression_info.out.compressed_size = BVAL(blob->data, 0); + parms->compression_info.out.format = SVAL(blob->data, 8); + parms->compression_info.out.unit_shift = CVAL(blob->data, 10); + parms->compression_info.out.chunk_shift = CVAL(blob->data, 11); + parms->compression_info.out.cluster_shift = CVAL(blob->data, 12); + /* 3 bytes of padding */ + return NT_STATUS_OK; + + case RAW_FILEINFO_NETWORK_OPEN_INFORMATION: + FINFO_CHECK_SIZE(56); + parms->network_open_information.out.create_time = smbcli_pull_nttime(blob->data, 0); + parms->network_open_information.out.access_time = smbcli_pull_nttime(blob->data, 8); + parms->network_open_information.out.write_time = smbcli_pull_nttime(blob->data, 16); + parms->network_open_information.out.change_time = smbcli_pull_nttime(blob->data, 24); + parms->network_open_information.out.alloc_size = BVAL(blob->data, 32); + parms->network_open_information.out.size = BVAL(blob->data, 40); + parms->network_open_information.out.attrib = IVAL(blob->data, 48); + return NT_STATUS_OK; + + case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION: + FINFO_CHECK_SIZE(8); + parms->attribute_tag_information.out.attrib = IVAL(blob->data, 0); + parms->attribute_tag_information.out.reparse_tag = IVAL(blob->data, 4); + return NT_STATUS_OK; + + case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION: + FINFO_CHECK_MIN_SIZE(4); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->normalized_name_info.out.fname, + 0, 4, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_SMB2_ALL_EAS: + FINFO_CHECK_MIN_SIZE(4); + return ea_pull_list_chained(blob, mem_ctx, + &parms->all_eas.out.num_eas, + &parms->all_eas.out.eas); + + case RAW_FILEINFO_SMB2_ALL_INFORMATION: + FINFO_CHECK_MIN_SIZE(0x64); + parms->all_info2.out.create_time = smbcli_pull_nttime(blob->data, 0x00); + parms->all_info2.out.access_time = smbcli_pull_nttime(blob->data, 0x08); + parms->all_info2.out.write_time = smbcli_pull_nttime(blob->data, 0x10); + parms->all_info2.out.change_time = smbcli_pull_nttime(blob->data, 0x18); + parms->all_info2.out.attrib = IVAL(blob->data, 0x20); + parms->all_info2.out.unknown1 = IVAL(blob->data, 0x24); + parms->all_info2.out.alloc_size = BVAL(blob->data, 0x28); + parms->all_info2.out.size = BVAL(blob->data, 0x30); + parms->all_info2.out.nlink = IVAL(blob->data, 0x38); + parms->all_info2.out.delete_pending = CVAL(blob->data, 0x3C); + parms->all_info2.out.directory = CVAL(blob->data, 0x3D); + /* 0x3E-0x3F padding */ + parms->all_info2.out.file_id = BVAL(blob->data, 0x40); + parms->all_info2.out.ea_size = IVAL(blob->data, 0x48); + parms->all_info2.out.access_mask = IVAL(blob->data, 0x4C); + parms->all_info2.out.position = BVAL(blob->data, 0x50); + parms->all_info2.out.mode = IVAL(blob->data, 0x58); + parms->all_info2.out.alignment_requirement = IVAL(blob->data, 0x5C); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->all_info2.out.fname, 0x60, 0x64, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_SEC_DESC: { + enum ndr_err_code ndr_err; + + parms->query_secdesc.out.sd = talloc(mem_ctx, struct security_descriptor); + NT_STATUS_HAVE_NO_MEMORY(parms->query_secdesc.out.sd); + + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, + parms->query_secdesc.out.sd, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; + } + + default: + break; + } + + return NT_STATUS_INVALID_LEVEL; +} + + +/**************************************************************************** + Handle qfileinfo/qpathinfo trans2 backend. +****************************************************************************/ +static NTSTATUS smb_raw_info_backend(struct smbcli_session *session, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms, + DATA_BLOB *blob) +{ + switch (parms->generic.level) { + case RAW_FILEINFO_GENERIC: + case RAW_FILEINFO_GETATTR: + case RAW_FILEINFO_GETATTRE: + case RAW_FILEINFO_SEC_DESC: + /* not handled here */ + return NT_STATUS_INVALID_LEVEL; + + case RAW_FILEINFO_STANDARD: + if (session == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + FINFO_CHECK_SIZE(22); + parms->standard.out.create_time = raw_pull_dos_date2(session->transport, + blob->data + 0); + parms->standard.out.access_time = raw_pull_dos_date2(session->transport, + blob->data + 4); + parms->standard.out.write_time = raw_pull_dos_date2(session->transport, + blob->data + 8); + parms->standard.out.size = IVAL(blob->data, 12); + parms->standard.out.alloc_size = IVAL(blob->data, 16); + parms->standard.out.attrib = SVAL(blob->data, 20); + return NT_STATUS_OK; + + case RAW_FILEINFO_EA_SIZE: + if (session == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + FINFO_CHECK_SIZE(26); + parms->ea_size.out.create_time = raw_pull_dos_date2(session->transport, + blob->data + 0); + parms->ea_size.out.access_time = raw_pull_dos_date2(session->transport, + blob->data + 4); + parms->ea_size.out.write_time = raw_pull_dos_date2(session->transport, + blob->data + 8); + parms->ea_size.out.size = IVAL(blob->data, 12); + parms->ea_size.out.alloc_size = IVAL(blob->data, 16); + parms->ea_size.out.attrib = SVAL(blob->data, 20); + parms->ea_size.out.ea_size = IVAL(blob->data, 22); + return NT_STATUS_OK; + + case RAW_FILEINFO_EA_LIST: + FINFO_CHECK_MIN_SIZE(4); + return ea_pull_list(blob, mem_ctx, + &parms->ea_list.out.num_eas, + &parms->ea_list.out.eas); + + case RAW_FILEINFO_ALL_EAS: + FINFO_CHECK_MIN_SIZE(4); + return ea_pull_list(blob, mem_ctx, + &parms->all_eas.out.num_eas, + &parms->all_eas.out.eas); + + case RAW_FILEINFO_IS_NAME_VALID: + /* no data! */ + FINFO_CHECK_SIZE(0); + return NT_STATUS_OK; + + case RAW_FILEINFO_BASIC_INFO: + case RAW_FILEINFO_BASIC_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_BASIC_INFORMATION, parms); + + case RAW_FILEINFO_STANDARD_INFO: + case RAW_FILEINFO_STANDARD_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_STANDARD_INFORMATION, parms); + + case RAW_FILEINFO_EA_INFO: + case RAW_FILEINFO_EA_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_EA_INFORMATION, parms); + + case RAW_FILEINFO_NAME_INFO: + case RAW_FILEINFO_NAME_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_NAME_INFORMATION, parms); + + case RAW_FILEINFO_ALL_INFO: + case RAW_FILEINFO_ALL_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_ALL_INFORMATION, parms); + + case RAW_FILEINFO_ALT_NAME_INFO: + case RAW_FILEINFO_ALT_NAME_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_ALT_NAME_INFORMATION, parms); + + case RAW_FILEINFO_STREAM_INFO: + case RAW_FILEINFO_STREAM_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_STREAM_INFORMATION, parms); + + case RAW_FILEINFO_INTERNAL_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_INTERNAL_INFORMATION, parms); + + case RAW_FILEINFO_ACCESS_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_ACCESS_INFORMATION, parms); + + case RAW_FILEINFO_POSITION_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_POSITION_INFORMATION, parms); + + case RAW_FILEINFO_MODE_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_MODE_INFORMATION, parms); + + case RAW_FILEINFO_ALIGNMENT_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_ALIGNMENT_INFORMATION, parms); + + case RAW_FILEINFO_COMPRESSION_INFO: + case RAW_FILEINFO_COMPRESSION_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_COMPRESSION_INFORMATION, parms); + + case RAW_FILEINFO_UNIX_BASIC: + FINFO_CHECK_SIZE(100); + parms->unix_basic_info.out.end_of_file = BVAL(blob->data, 0); + parms->unix_basic_info.out.num_bytes = BVAL(blob->data, 8); + parms->unix_basic_info.out.status_change_time = smbcli_pull_nttime(blob->data, 16); + parms->unix_basic_info.out.access_time = smbcli_pull_nttime(blob->data, 24); + parms->unix_basic_info.out.change_time = smbcli_pull_nttime(blob->data, 32); + parms->unix_basic_info.out.uid = BVAL(blob->data, 40); + parms->unix_basic_info.out.gid = BVAL(blob->data, 48); + parms->unix_basic_info.out.file_type = IVAL(blob->data, 52); + parms->unix_basic_info.out.dev_major = BVAL(blob->data, 60); + parms->unix_basic_info.out.dev_minor = BVAL(blob->data, 68); + parms->unix_basic_info.out.unique_id = BVAL(blob->data, 76); + parms->unix_basic_info.out.permissions = BVAL(blob->data, 84); + parms->unix_basic_info.out.nlink = BVAL(blob->data, 92); + return NT_STATUS_OK; + + case RAW_FILEINFO_UNIX_INFO2: + FINFO_CHECK_SIZE(116); + parms->unix_info2.out.end_of_file = BVAL(blob->data, 0); + parms->unix_info2.out.num_bytes = BVAL(blob->data, 8); + parms->unix_info2.out.status_change_time = smbcli_pull_nttime(blob->data, 16); + parms->unix_info2.out.access_time = smbcli_pull_nttime(blob->data, 24); + parms->unix_info2.out.change_time = smbcli_pull_nttime(blob->data, 32); + parms->unix_info2.out.uid = BVAL(blob->data, 40); + parms->unix_info2.out.gid = BVAL(blob->data, 48); + parms->unix_info2.out.file_type = IVAL(blob->data, 52); + parms->unix_info2.out.dev_major = BVAL(blob->data, 60); + parms->unix_info2.out.dev_minor = BVAL(blob->data, 68); + parms->unix_info2.out.unique_id = BVAL(blob->data, 76); + parms->unix_info2.out.permissions = BVAL(blob->data, 84); + parms->unix_info2.out.nlink = BVAL(blob->data, 92); + parms->unix_info2.out.create_time = smbcli_pull_nttime(blob->data, 100); + parms->unix_info2.out.file_flags = IVAL(blob->data, 108); + parms->unix_info2.out.flags_mask = IVAL(blob->data, 112); + return NT_STATUS_OK; + + case RAW_FILEINFO_UNIX_LINK: + smbcli_blob_pull_string(session, mem_ctx, blob, + &parms->unix_link_info.out.link_dest, 0, 4, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_NETWORK_OPEN_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_NETWORK_OPEN_INFORMATION, parms); + + case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, parms); + + case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_NORMALIZED_NAME_INFORMATION, parms); + + case RAW_FILEINFO_SMB2_ALL_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_SMB2_ALL_INFORMATION, parms); + + case RAW_FILEINFO_SMB2_ALL_EAS: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_SMB2_ALL_EAS, parms); + + case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION, parms); + + } + + return NT_STATUS_INVALID_LEVEL; +} + + +/**************************************************************************** + Very raw query file info - returns param/data blobs - (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_fileinfo_blob_send(struct smbcli_tree *tree, + uint16_t fnum, + uint16_t info_level, + DATA_BLOB data) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_QFILEINFO; + struct smbcli_request *req; + TALLOC_CTX *mem_ctx = talloc_init("raw_fileinfo"); + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.data = data; + tp.in.max_param = 2; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 4); + if (!tp.in.params.data) { + talloc_free(mem_ctx); + return NULL; + } + + SSVAL(tp.in.params.data, 0, fnum); + SSVAL(tp.in.params.data, 2, info_level); + + req = smb_raw_trans2_send(tree, &tp); + + talloc_free(mem_ctx); + + return req; +} + + +/**************************************************************************** + Very raw query file info - returns param/data blobs - (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_fileinfo_blob_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + struct smb_trans2 tp; + NTSTATUS status = smb_raw_trans2_recv(req, mem_ctx, &tp); + if (NT_STATUS_IS_OK(status)) { + *blob = tp.out.data; + } + return status; +} + +/**************************************************************************** + Very raw query path info - returns param/data blobs (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_pathinfo_blob_send(struct smbcli_tree *tree, + const char *fname, + uint16_t info_level, + DATA_BLOB data) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_QPATHINFO; + struct smbcli_request *req; + TALLOC_CTX *mem_ctx = talloc_init("raw_pathinfo"); + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.data = data; + tp.in.max_param = 2; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 6); + if (!tp.in.params.data) { + talloc_free(mem_ctx); + return NULL; + } + + SSVAL(tp.in.params.data, 0, info_level); + SIVAL(tp.in.params.data, 2, 0); + smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params, + fname, STR_TERMINATE); + + req = smb_raw_trans2_send(tree, &tp); + + talloc_free(mem_ctx); + + return req; +} + +/**************************************************************************** + send a SMBgetatr (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_getattr_send(struct smbcli_tree *tree, + union smb_fileinfo *parms) +{ + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBgetatr, 0, 0); + if (!req) return NULL; + + smbcli_req_append_ascii4(req, parms->getattr.in.file.path, STR_TERMINATE); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + send a SMBgetatr (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_getattr_recv(struct smbcli_request *req, + union smb_fileinfo *parms) +{ + if (req == NULL) { + goto failed; + } + + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + return smbcli_request_destroy(req); + } + + SMBCLI_CHECK_WCT(req, 10); + parms->getattr.out.attrib = SVAL(req->in.vwv, VWV(0)); + parms->getattr.out.write_time = raw_pull_dos_date3(req->transport, + req->in.vwv + VWV(1)); + parms->getattr.out.size = IVAL(req->in.vwv, VWV(3)); + +failed: + return smbcli_request_destroy(req); +} + + +/**************************************************************************** + Handle SMBgetattrE (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_getattrE_send(struct smbcli_tree *tree, + union smb_fileinfo *parms) +{ + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBgetattrE, 1, 0); + if (!req) return NULL; + + SSVAL(req->out.vwv, VWV(0), parms->getattre.in.file.fnum); + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Handle SMBgetattrE (async send) +****************************************************************************/ +static NTSTATUS smb_raw_getattrE_recv(struct smbcli_request *req, + union smb_fileinfo *parms) +{ + if (req == NULL) { + goto failed; + } + + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + return smbcli_request_destroy(req); + } + + SMBCLI_CHECK_WCT(req, 11); + parms->getattre.out.create_time = raw_pull_dos_date2(req->transport, + req->in.vwv + VWV(0)); + parms->getattre.out.access_time = raw_pull_dos_date2(req->transport, + req->in.vwv + VWV(2)); + parms->getattre.out.write_time = raw_pull_dos_date2(req->transport, + req->in.vwv + VWV(4)); + parms->getattre.out.size = IVAL(req->in.vwv, VWV(6)); + parms->getattre.out.alloc_size = IVAL(req->in.vwv, VWV(8)); + parms->getattre.out.attrib = SVAL(req->in.vwv, VWV(10)); + +failed: + return smbcli_request_destroy(req); +} + + +/**************************************************************************** + Query file info (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_fileinfo_send(struct smbcli_tree *tree, + union smb_fileinfo *parms) +{ + DATA_BLOB data; + struct smbcli_request *req; + + /* pass off the non-trans2 level to specialised functions */ + if (parms->generic.level == RAW_FILEINFO_GETATTRE) { + return smb_raw_getattrE_send(tree, parms); + } + if (parms->generic.level == RAW_FILEINFO_SEC_DESC) { + return smb_raw_query_secdesc_send(tree, parms); + } + if (parms->generic.level >= RAW_FILEINFO_GENERIC) { + return NULL; + } + + data = data_blob(NULL, 0); + + if (parms->generic.level == RAW_FILEINFO_EA_LIST) { + if (!ea_push_name_list(tree, + &data, + parms->ea_list.in.num_names, + parms->ea_list.in.ea_names)) { + return NULL; + } + } + + req = smb_raw_fileinfo_blob_send(tree, + parms->generic.in.file.fnum, + parms->generic.level, data); + + data_blob_free(&data); + + return req; +} + +/**************************************************************************** + Query file info (async recv) +****************************************************************************/ +NTSTATUS smb_raw_fileinfo_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms) +{ + DATA_BLOB blob; + NTSTATUS status; + struct smbcli_session *session = req?req->session:NULL; + + if (parms->generic.level == RAW_FILEINFO_GETATTRE) { + return smb_raw_getattrE_recv(req, parms); + } + if (parms->generic.level == RAW_FILEINFO_SEC_DESC) { + return smb_raw_query_secdesc_recv(req, mem_ctx, parms); + } + if (parms->generic.level == RAW_FILEINFO_GETATTR) { + return smb_raw_getattr_recv(req, parms); + } + + status = smb_raw_fileinfo_blob_recv(req, mem_ctx, &blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return smb_raw_info_backend(session, mem_ctx, parms, &blob); +} + +/**************************************************************************** + Query file info (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_fileinfo(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms) +{ + struct smbcli_request *req = smb_raw_fileinfo_send(tree, parms); + return smb_raw_fileinfo_recv(req, mem_ctx, parms); +} + +/**************************************************************************** + Query path info (async send) +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree, + union smb_fileinfo *parms) +{ + DATA_BLOB data; + struct smbcli_request *req; + + if (parms->generic.level == RAW_FILEINFO_GETATTR) { + return smb_raw_getattr_send(tree, parms); + } + if (parms->generic.level >= RAW_FILEINFO_GENERIC) { + return NULL; + } + + data = data_blob(NULL, 0); + + if (parms->generic.level == RAW_FILEINFO_EA_LIST) { + if (!ea_push_name_list(tree, + &data, + parms->ea_list.in.num_names, + parms->ea_list.in.ea_names)) { + return NULL; + } + } + + req = smb_raw_pathinfo_blob_send(tree, parms->generic.in.file.path, + parms->generic.level, data); + data_blob_free(&data); + + return req; +} + +/**************************************************************************** + Query path info (async recv) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_pathinfo_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms) +{ + /* recv is idential to fileinfo */ + return smb_raw_fileinfo_recv(req, mem_ctx, parms); +} + +/**************************************************************************** + Query path info (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_pathinfo(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_fileinfo *parms) +{ + struct smbcli_request *req = smb_raw_pathinfo_send(tree, parms); + return smb_raw_pathinfo_recv(req, mem_ctx, parms); +} diff --git a/source4/libcli/raw/rawfsinfo.c b/source4/libcli/raw/rawfsinfo.c new file mode 100644 index 0000000..bf149ee --- /dev/null +++ b/source4/libcli/raw/rawfsinfo.c @@ -0,0 +1,431 @@ +/* + Unix SMB/CIFS implementation. + + RAW_QFS_* operations + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_misc.h" + +/**************************************************************************** + Query FS Info - SMBdskattr call (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_dskattr_send(struct smbcli_tree *tree, + union smb_fsinfo *fsinfo) +{ + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBdskattr, 0, 0); + if (req == NULL) { + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Query FS Info - SMBdskattr call (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_dskattr_recv(struct smbcli_request *req, + union smb_fsinfo *fsinfo) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + SMBCLI_CHECK_WCT(req, 5); + fsinfo->dskattr.out.units_total = SVAL(req->in.vwv, VWV(0)); + fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1)); + fsinfo->dskattr.out.block_size = SVAL(req->in.vwv, VWV(2)); + fsinfo->dskattr.out.units_free = SVAL(req->in.vwv, VWV(3)); + +failed: + return smbcli_request_destroy(req); +} + + +/**************************************************************************** + RAW_QFS_ trans2 interface via blobs (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_qfsinfo_send(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + uint16_t info_level) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_QFSINFO; + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 0; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + tp.in.data = data_blob(NULL, 0); + tp.in.timeout = 0; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 2); + if (!tp.in.params.data) { + return NULL; + } + SSVAL(tp.in.params.data, 0, info_level); + + return smb_raw_trans2_send(tree, &tp); +} + +/**************************************************************************** + RAW_QFS_ trans2 interface via blobs (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_qfsinfo_blob_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + struct smb_trans2 tp; + NTSTATUS status; + + status = smb_raw_trans2_recv(req, mem_ctx, &tp); + + if (NT_STATUS_IS_OK(status)) { + (*blob) = tp.out.data; + } + + return status; +} + + +/* local macros to make the code more readable */ +#define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \ + DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \ + (int)blob.length, fsinfo->generic.level, (size))); \ + status = NT_STATUS_INFO_LENGTH_MISMATCH; \ + goto failed; \ +} +#define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \ + DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \ + (int)blob.length, fsinfo->generic.level, (size))); \ + status = NT_STATUS_INFO_LENGTH_MISMATCH; \ + goto failed; \ +} + + +/**************************************************************************** + Query FSInfo raw interface (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_fsinfo_send(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_fsinfo *fsinfo) +{ + uint16_t info_level; + + /* handle the only non-trans2 call separately */ + if (fsinfo->generic.level == RAW_QFS_DSKATTR) { + return smb_raw_dskattr_send(tree, fsinfo); + } + if (fsinfo->generic.level >= RAW_QFS_GENERIC) { + return NULL; + } + + /* the headers map the trans2 levels direct to info levels */ + info_level = (uint16_t)fsinfo->generic.level; + + return smb_raw_qfsinfo_send(tree, mem_ctx, info_level); +} + +/* + parse the fsinfo 'passthru' level replies +*/ +NTSTATUS smb_raw_fsinfo_passthru_parse(DATA_BLOB blob, TALLOC_CTX *mem_ctx, + enum smb_fsinfo_level level, + union smb_fsinfo *fsinfo) +{ + NTSTATUS status = NT_STATUS_OK; + int i; + + /* parse the results */ + switch (level) { + case RAW_QFS_VOLUME_INFORMATION: + QFS_CHECK_MIN_SIZE(18); + fsinfo->volume_info.out.create_time = smbcli_pull_nttime(blob.data, 0); + fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8); + smbcli_blob_pull_string(NULL, mem_ctx, &blob, + &fsinfo->volume_info.out.volume_name, + 12, 18, STR_UNICODE); + break; + + case RAW_QFS_SIZE_INFORMATION: + QFS_CHECK_SIZE(24); + fsinfo->size_info.out.total_alloc_units = BVAL(blob.data, 0); + fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data, 8); + fsinfo->size_info.out.sectors_per_unit = IVAL(blob.data, 16); + fsinfo->size_info.out.bytes_per_sector = IVAL(blob.data, 20); + break; + + case RAW_QFS_DEVICE_INFORMATION: + QFS_CHECK_SIZE(8); + fsinfo->device_info.out.device_type = IVAL(blob.data, 0); + fsinfo->device_info.out.characteristics = IVAL(blob.data, 4); + break; + + case RAW_QFS_ATTRIBUTE_INFORMATION: + QFS_CHECK_MIN_SIZE(12); + fsinfo->attribute_info.out.fs_attr = IVAL(blob.data, 0); + fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4); + smbcli_blob_pull_string(NULL, mem_ctx, &blob, + &fsinfo->attribute_info.out.fs_type, + 8, 12, STR_UNICODE); + break; + + case RAW_QFS_QUOTA_INFORMATION: + QFS_CHECK_SIZE(48); + fsinfo->quota_information.out.unknown[0] = BVAL(blob.data, 0); + fsinfo->quota_information.out.unknown[1] = BVAL(blob.data, 8); + fsinfo->quota_information.out.unknown[2] = BVAL(blob.data, 16); + fsinfo->quota_information.out.quota_soft = BVAL(blob.data, 24); + fsinfo->quota_information.out.quota_hard = BVAL(blob.data, 32); + fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40); + break; + + case RAW_QFS_FULL_SIZE_INFORMATION: + QFS_CHECK_SIZE(32); + fsinfo->full_size_information.out.total_alloc_units = BVAL(blob.data, 0); + fsinfo->full_size_information.out.call_avail_alloc_units = BVAL(blob.data, 8); + fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16); + fsinfo->full_size_information.out.sectors_per_unit = IVAL(blob.data, 24); + fsinfo->full_size_information.out.bytes_per_sector = IVAL(blob.data, 28); + break; + + case RAW_QFS_OBJECTID_INFORMATION: { + DATA_BLOB b2 = data_blob_const(blob.data, MIN(16, blob.length)); + QFS_CHECK_SIZE(64); + status = GUID_from_ndr_blob(&b2, &fsinfo->objectid_information.out.guid); + NT_STATUS_NOT_OK_RETURN(status); + for (i=0;i<6;i++) { + fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8); + } + break; + + case RAW_QFS_SECTOR_SIZE_INFORMATION: + QFS_CHECK_SIZE(28); + fsinfo->sector_size_info.out.logical_bytes_per_sector + = IVAL(blob.data, 0); + fsinfo->sector_size_info.out.phys_bytes_per_sector_atomic + = IVAL(blob.data, 4); + fsinfo->sector_size_info.out.phys_bytes_per_sector_perf + = IVAL(blob.data, 8); + fsinfo->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic + = IVAL(blob.data, 12); + fsinfo->sector_size_info.out.flags = IVAL(blob.data, 16); + fsinfo->sector_size_info.out.byte_off_sector_align + = IVAL(blob.data, 20); + fsinfo->sector_size_info.out.byte_off_partition_align + = IVAL(blob.data, 24); + break; + } + + default: + status = NT_STATUS_INVALID_INFO_CLASS; + } + +failed: + return status; +} + + +/**************************************************************************** + Query FSInfo raw interface (async recv) +****************************************************************************/ +NTSTATUS smb_raw_fsinfo_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_fsinfo *fsinfo) +{ + DATA_BLOB blob; + NTSTATUS status; + struct smbcli_session *session = req?req->session:NULL; + + if (fsinfo->generic.level == RAW_QFS_DSKATTR) { + return smb_raw_dskattr_recv(req, fsinfo); + } + + status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* parse the results */ + switch (fsinfo->generic.level) { + case RAW_QFS_GENERIC: + case RAW_QFS_DSKATTR: + /* handled above */ + break; + + case RAW_QFS_ALLOCATION: + QFS_CHECK_SIZE(18); + fsinfo->allocation.out.fs_id = IVAL(blob.data, 0); + fsinfo->allocation.out.sectors_per_unit = IVAL(blob.data, 4); + fsinfo->allocation.out.total_alloc_units = IVAL(blob.data, 8); + fsinfo->allocation.out.avail_alloc_units = IVAL(blob.data, 12); + fsinfo->allocation.out.bytes_per_sector = SVAL(blob.data, 16); + break; + + case RAW_QFS_VOLUME: + QFS_CHECK_MIN_SIZE(5); + fsinfo->volume.out.serial_number = IVAL(blob.data, 0); + smbcli_blob_pull_string(session, mem_ctx, &blob, + &fsinfo->volume.out.volume_name, + 4, 5, STR_LEN8BIT | STR_NOALIGN); + break; + + case RAW_QFS_VOLUME_INFO: + case RAW_QFS_VOLUME_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_VOLUME_INFORMATION, fsinfo); + + case RAW_QFS_SIZE_INFO: + case RAW_QFS_SIZE_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_SIZE_INFORMATION, fsinfo); + + case RAW_QFS_DEVICE_INFO: + case RAW_QFS_DEVICE_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_DEVICE_INFORMATION, fsinfo); + + case RAW_QFS_ATTRIBUTE_INFO: + case RAW_QFS_ATTRIBUTE_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_ATTRIBUTE_INFORMATION, fsinfo); + + case RAW_QFS_UNIX_INFO: + QFS_CHECK_SIZE(12); + fsinfo->unix_info.out.major_version = SVAL(blob.data, 0); + fsinfo->unix_info.out.minor_version = SVAL(blob.data, 2); + fsinfo->unix_info.out.capability = SVAL(blob.data, 4); + break; + + case RAW_QFS_QUOTA_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_QUOTA_INFORMATION, fsinfo); + + case RAW_QFS_FULL_SIZE_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_FULL_SIZE_INFORMATION, fsinfo); + + case RAW_QFS_OBJECTID_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_OBJECTID_INFORMATION, fsinfo); + + case RAW_QFS_SECTOR_SIZE_INFORMATION: + return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, + RAW_QFS_SECTOR_SIZE_INFORMATION, fsinfo); + } + +failed: + return status; +} + +/**************************************************************************** + Query FSInfo raw interface (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_fsinfo(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_fsinfo *fsinfo) +{ + struct smbcli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo); + return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo); +} + +/**************************************************************************** + Set FSInfo raw interface (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_setfsinfo_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_setfsinfo *set_fsinfo) +{ + DATA_BLOB blob = data_blob_null; + NTSTATUS status; + + if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob); + data_blob_free(&blob); + return status; +} + +/**************************************************************************** + Set FSInfo raw interface (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_setfsinfo_send(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_setfsinfo *set_fsinfo) +{ + struct smb_trans2 tp; + uint16_t info_level; + uint16_t setup = TRANSACT2_SETFSINFO; + + if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) { + return NULL; + } + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 0; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + tp.in.timeout = 0; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 4); + if (!tp.in.params.data) { + return NULL; + } + info_level = (uint16_t)set_fsinfo->generic.level; + SSVAL(tp.in.params.data, 0, 0); + SSVAL(tp.in.params.data, 2, info_level); + + tp.in.data = data_blob_talloc(mem_ctx, NULL, 12); + if (!tp.in.data.data) { + return NULL; + } + + SSVAL(tp.in.data.data, 0, set_fsinfo->unix_info.in.major_version); + SSVAL(tp.in.data.data, 2, set_fsinfo->unix_info.in.minor_version); + SBVAL(tp.in.data.data, 4, set_fsinfo->unix_info.in.capability); + + return smb_raw_trans2_send(tree, &tp); +} + +/**************************************************************************** + Set FSInfo raw interface (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_setfsinfo(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_setfsinfo *set_fsinfo) +{ + struct smbcli_request *req = smb_raw_setfsinfo_send(tree, mem_ctx, set_fsinfo); + return smb_raw_setfsinfo_recv(req, mem_ctx, set_fsinfo); +} diff --git a/source4/libcli/raw/rawioctl.c b/source4/libcli/raw/rawioctl.c new file mode 100644 index 0000000..77c7b03 --- /dev/null +++ b/source4/libcli/raw/rawioctl.c @@ -0,0 +1,173 @@ +/* + Unix SMB/CIFS implementation. + client file operations + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +#define SETUP_REQUEST(cmd, wct, buflen) do { \ + req = smbcli_request_setup(tree, cmd, wct, buflen); \ + if (!req) return NULL; \ +} while (0) + +/* + send a raw smb ioctl - async send +*/ +static struct smbcli_request *smb_raw_smbioctl_send(struct smbcli_tree *tree, + union smb_ioctl *parms) +{ + struct smbcli_request *req; + + SETUP_REQUEST(SMBioctl, 3, 0); + + SSVAL(req->out.vwv, VWV(0), parms->ioctl.in.file.fnum); + SIVAL(req->out.vwv, VWV(1), parms->ioctl.in.request); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/* + send a raw smb ioctl - async recv +*/ +static NTSTATUS smb_raw_smbioctl_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_ioctl *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + return smbcli_request_destroy(req); + } + + parms->ioctl.out.blob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, req->in.data, -1); + return smbcli_request_destroy(req); +} + + + +/**************************************************************************** +NT ioctl (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_ntioctl_send(struct smbcli_tree *tree, + union smb_ioctl *parms) +{ + struct smb_nttrans nt; + uint8_t setup[8]; + + nt.in.max_setup = 4; + nt.in.max_param = 0; + nt.in.max_data = parms->ntioctl.in.max_data; + nt.in.setup_count = 4; + nt.in.setup = setup; + SIVAL(setup, 0, parms->ntioctl.in.function); + SSVAL(setup, 4, parms->ntioctl.in.file.fnum); + SCVAL(setup, 6, parms->ntioctl.in.fsctl); + SCVAL(setup, 7, parms->ntioctl.in.filter); + nt.in.function = NT_TRANSACT_IOCTL; + nt.in.params = data_blob(NULL, 0); + nt.in.data = parms->ntioctl.in.blob; + + return smb_raw_nttrans_send(tree, &nt); +} + +/**************************************************************************** +NT ioctl (async recv) +****************************************************************************/ +static NTSTATUS smb_raw_ntioctl_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + union smb_ioctl *parms) +{ + NTSTATUS status; + struct smb_nttrans nt; + TALLOC_CTX *tmp_mem; + + tmp_mem = talloc_new(mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(tmp_mem); + + status = smb_raw_nttrans_recv(req, tmp_mem, &nt); + if (!NT_STATUS_IS_OK(status)) goto fail; + + parms->ntioctl.out.blob = nt.out.data; + talloc_steal(mem_ctx, parms->ntioctl.out.blob.data); + +fail: + talloc_free(tmp_mem); + return status; +} + + +/* + send a raw ioctl - async send +*/ +struct smbcli_request *smb_raw_ioctl_send(struct smbcli_tree *tree, union smb_ioctl *parms) +{ + struct smbcli_request *req = NULL; + + switch (parms->generic.level) { + case RAW_IOCTL_IOCTL: + req = smb_raw_smbioctl_send(tree, parms); + break; + + case RAW_IOCTL_NTIOCTL: + req = smb_raw_ntioctl_send(tree, parms); + break; + + case RAW_IOCTL_SMB2: + case RAW_IOCTL_SMB2_NO_HANDLE: + return NULL; + } + + return req; +} + +/* + recv a raw ioctl - async recv +*/ +NTSTATUS smb_raw_ioctl_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, union smb_ioctl *parms) +{ + switch (parms->generic.level) { + case RAW_IOCTL_IOCTL: + return smb_raw_smbioctl_recv(req, mem_ctx, parms); + + case RAW_IOCTL_NTIOCTL: + return smb_raw_ntioctl_recv(req, mem_ctx, parms); + + case RAW_IOCTL_SMB2: + case RAW_IOCTL_SMB2_NO_HANDLE: + break; + } + return NT_STATUS_INVALID_LEVEL; +} + +/* + send a raw ioctl - sync interface +*/ +NTSTATUS smb_raw_ioctl(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, union smb_ioctl *parms) +{ + struct smbcli_request *req; + req = smb_raw_ioctl_send(tree, parms); + return smb_raw_ioctl_recv(req, mem_ctx, parms); +} diff --git a/source4/libcli/raw/rawlpq.c b/source4/libcli/raw/rawlpq.c new file mode 100644 index 0000000..5c44772 --- /dev/null +++ b/source4/libcli/raw/rawlpq.c @@ -0,0 +1,48 @@ +/* + Unix SMB/CIFS implementation. + client lpq operations + Copyright (C) Tim Potter 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/**************************************************************************** + lpq - async send +****************************************************************************/ +struct smbcli_request *smb_raw_lpq_send(struct smbcli_tree *tree, + union smb_lpq *parms) +{ + return NULL; +} + +/**************************************************************************** + lpq - async receive +****************************************************************************/ +NTSTATUS smb_raw_lpq_recv(struct smbcli_request *req, union smb_lpq *parms) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* + lpq - sync interface +*/ +NTSTATUS smb_raw_lpq(struct smbcli_tree *tree, union smb_lpq *parms) +{ + struct smbcli_request *req = smb_raw_lpq_send(tree, parms); + return smb_raw_lpq_recv(req, parms); +} diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c new file mode 100644 index 0000000..6d1b736 --- /dev/null +++ b/source4/libcli/raw/rawnegotiate.c @@ -0,0 +1,183 @@ +/* + Unix SMB/CIFS implementation. + + SMB client negotiate context management functions + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include <tevent.h> +#include "system/time.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "../libcli/smb/smbXcli_base.h" +#include "../lib/util/tevent_ntstatus.h" + +NTSTATUS smb_raw_negotiate_fill_transport(struct smbcli_transport *transport) +{ + struct smbcli_negotiate *n = &transport->negotiate; + struct smbXcli_conn *c = transport->conn; + NTTIME ntt; + + n->protocol = smbXcli_conn_protocol(c); + if (n->protocol > PROTOCOL_NT1) { + return NT_STATUS_REVISION_MISMATCH; + } + + n->sec_mode = smb1cli_conn_server_security_mode(c); + n->max_mux = smbXcli_conn_max_requests(c); + n->max_xmit = smb1cli_conn_max_xmit(c); + n->sesskey = smb1cli_conn_server_session_key(c); + n->capabilities = smb1cli_conn_capabilities(c);; + + /* this time arrives in real GMT */ + ntt = smbXcli_conn_server_system_time(c); + n->server_time = nt_time_to_unix(ntt); + n->server_zone = smb1cli_conn_server_time_zone(c); + + if (n->capabilities & CAP_EXTENDED_SECURITY) { + const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c); + if (b) { + n->secblob = *b; + } + } else { + const uint8_t *p = smb1cli_conn_server_challenge(c); + if (p) { + n->secblob = data_blob_const(p, 8); + } + } + + n->readbraw_supported = smb1cli_conn_server_readbraw(c); + n->readbraw_supported = smb1cli_conn_server_writebraw(c); + n->lockread_supported = smb1cli_conn_server_lockread(c); + + return NT_STATUS_OK; +} + +struct smb_raw_negotiate_state { + struct smbcli_transport *transport; +}; + +static void smb_raw_negotiate_done(struct tevent_req *subreq); + +struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbcli_transport *transport, + int minprotocol, + int maxprotocol) +{ + struct tevent_req *req; + struct smb_raw_negotiate_state *state; + struct tevent_req *subreq; + uint32_t timeout_msec = transport->options.request_timeout * 1000; + + req = tevent_req_create(mem_ctx, &state, + struct smb_raw_negotiate_state);; + if (req == NULL) { + return NULL; + } + state->transport = transport; + + if (maxprotocol > PROTOCOL_NT1) { + maxprotocol = PROTOCOL_NT1; + } + + if (minprotocol > maxprotocol) { + minprotocol = maxprotocol; + } + + subreq = smbXcli_negprot_send(state, ev, + transport->conn, + timeout_msec, + minprotocol, + maxprotocol, + transport->options.max_credits, + NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, smb_raw_negotiate_done, req); + + return req; +} + +static void smb_raw_negotiate_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smb_raw_negotiate_state *state = + tevent_req_data(req, + struct smb_raw_negotiate_state); + NTSTATUS status; + + status = smbXcli_negprot_recv(subreq, NULL, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + status = smb_raw_negotiate_fill_transport(state->transport); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + +/* + Send a negprot command. +*/ +NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + + +/* + Send a negprot command (sync interface) +*/ +NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode, + int minprotocol, int maxprotocol) +{ + NTSTATUS status; + struct tevent_req *subreq = NULL; + bool ok; + + subreq = smb_raw_negotiate_send(transport, + transport->ev, + transport, + minprotocol, + maxprotocol); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ok = tevent_req_poll(subreq, transport->ev); + if (!ok) { + status = map_nt_error_from_unix_common(errno); + goto failed; + } + + status = smb_raw_negotiate_recv(subreq); + +failed: + TALLOC_FREE(subreq); + return status; +} diff --git a/source4/libcli/raw/rawnotify.c b/source4/libcli/raw/rawnotify.c new file mode 100644 index 0000000..dcb979b --- /dev/null +++ b/source4/libcli/raw/rawnotify.c @@ -0,0 +1,122 @@ +/* + Unix SMB/CIFS implementation. + client change notify operations + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include <tevent.h> +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/**************************************************************************** +change notify (async send) +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_changenotify_send(struct smbcli_tree *tree, union smb_notify *parms) +{ + struct smb_nttrans nt; + uint8_t setup[8]; + + if (parms->nttrans.level != RAW_NOTIFY_NTTRANS) { + return NULL; + } + + nt.in.max_setup = 0; + nt.in.max_param = parms->nttrans.in.buffer_size; + nt.in.max_data = 0; + nt.in.setup_count = 4; + nt.in.setup = setup; + SIVAL(setup, 0, parms->nttrans.in.completion_filter); + SSVAL(setup, 4, parms->nttrans.in.file.fnum); + SSVAL(setup, 6, parms->nttrans.in.recursive); + nt.in.function = NT_TRANSACT_NOTIFY_CHANGE; + nt.in.params = data_blob(NULL, 0); + nt.in.data = data_blob(NULL, 0); + + return smb_raw_nttrans_send(tree, &nt); +} + +/**************************************************************************** +change notify (async recv) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, union smb_notify *parms) +{ + struct smb_nttrans nt; + NTSTATUS status; + uint32_t ofs, i; + struct smbcli_session *session = req?req->session:NULL; + + if (parms->nttrans.level != RAW_NOTIFY_NTTRANS) { + return NT_STATUS_INVALID_LEVEL; + } + + status = smb_raw_nttrans_recv(req, mem_ctx, &nt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + parms->nttrans.out.changes = NULL; + parms->nttrans.out.num_changes = 0; + + /* count them */ + for (ofs=0; nt.out.params.length - ofs > 12; ) { + uint32_t next = IVAL(nt.out.params.data, ofs); + if (next % 4 != 0) + return NT_STATUS_INVALID_NETWORK_RESPONSE; + parms->nttrans.out.num_changes++; + if (next == 0 || + ofs + next >= nt.out.params.length) break; + ofs += next; + } + + /* allocate array */ + parms->nttrans.out.changes = talloc_array(mem_ctx, struct notify_changes, parms->nttrans.out.num_changes); + if (!parms->nttrans.out.changes) { + return NT_STATUS_NO_MEMORY; + } + + for (i=ofs=0; i<parms->nttrans.out.num_changes; i++) { + parms->nttrans.out.changes[i].action = IVAL(nt.out.params.data, ofs+4); + smbcli_blob_pull_string(session, mem_ctx, &nt.out.params, + &parms->nttrans.out.changes[i].name, + ofs+8, ofs+12, STR_UNICODE); + ofs += IVAL(nt.out.params.data, ofs); + } + + return NT_STATUS_OK; +} + +/**************************************************************************** + Send a NT Cancel request - used to hurry along a pending request. Usually + used to cancel a pending change notify request + note that this request does not expect a response! +****************************************************************************/ +NTSTATUS smb_raw_ntcancel(struct smbcli_request *oldreq) +{ + bool ok; + + if (oldreq->subreqs[0] == NULL) { + return NT_STATUS_OK; + } + + ok = tevent_req_cancel(oldreq->subreqs[0]); + if (!ok) { + return NT_STATUS_INTERNAL_ERROR; + } + + return NT_STATUS_OK; +} diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c new file mode 100644 index 0000000..fb44ba4 --- /dev/null +++ b/source4/libcli/raw/rawreadwrite.c @@ -0,0 +1,345 @@ +/* + Unix SMB/CIFS implementation. + client file read/write routines + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) James Myers 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +#define SETUP_REQUEST(cmd, wct, buflen) do { \ + req = smbcli_request_setup(tree, cmd, wct, buflen); \ + if (!req) return NULL; \ +} while (0) + +/**************************************************************************** + low level read operation (async send) +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_read *parms) +{ + bool bigoffset = false; + struct smbcli_request *req = NULL; + + switch (parms->generic.level) { + case RAW_READ_READBRAW: + if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) { + bigoffset = true; + } + SETUP_REQUEST(SMBreadbraw, bigoffset? 10:8, 0); + SSVAL(req->out.vwv, VWV(0), parms->readbraw.in.file.fnum); + SIVAL(req->out.vwv, VWV(1), parms->readbraw.in.offset); + SSVAL(req->out.vwv, VWV(3), parms->readbraw.in.maxcnt); + SSVAL(req->out.vwv, VWV(4), parms->readbraw.in.mincnt); + SIVAL(req->out.vwv, VWV(5), parms->readbraw.in.timeout); + SSVAL(req->out.vwv, VWV(7), 0); /* reserved */ + if (bigoffset) { + SIVAL(req->out.vwv, VWV(8),parms->readbraw.in.offset>>32); + } + break; + + case RAW_READ_LOCKREAD: + SETUP_REQUEST(SMBlockread, 5, 0); + SSVAL(req->out.vwv, VWV(0), parms->lockread.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->lockread.in.count); + SIVAL(req->out.vwv, VWV(2), parms->lockread.in.offset); + SSVAL(req->out.vwv, VWV(4), parms->lockread.in.remaining); + break; + + case RAW_READ_READ: + SETUP_REQUEST(SMBread, 5, 0); + SSVAL(req->out.vwv, VWV(0), parms->read.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->read.in.count); + SIVAL(req->out.vwv, VWV(2), parms->read.in.offset); + SSVAL(req->out.vwv, VWV(4), parms->read.in.remaining); + break; + + case RAW_READ_READX: + if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) { + bigoffset = true; + } + SETUP_REQUEST(SMBreadX, bigoffset ? 12 : 10, 0); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->readx.in.file.fnum); + SIVAL(req->out.vwv, VWV(3), parms->readx.in.offset); + SSVAL(req->out.vwv, VWV(5), parms->readx.in.maxcnt & 0xFFFF); + SSVAL(req->out.vwv, VWV(6), parms->readx.in.mincnt); + SIVAL(req->out.vwv, VWV(7), parms->readx.in.maxcnt >> 16); + SSVAL(req->out.vwv, VWV(9), parms->readx.in.remaining); + /* + * TODO: give an error when the offset is 64 bit + * and the server doesn't support it + */ + if (bigoffset) { + SIVAL(req->out.vwv, VWV(10),parms->readx.in.offset>>32); + } + if (parms->readx.in.read_for_execute) { + uint16_t flags2 = SVAL(req->out.hdr, HDR_FLG2); + flags2 |= FLAGS2_READ_PERMIT_EXECUTE; + SSVAL(req->out.hdr, HDR_FLG2, flags2); + } + break; + + case RAW_READ_SMB2: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + low level read operation (async recv) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + switch (parms->generic.level) { + case RAW_READ_READBRAW: + parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE; + if (parms->readbraw.out.nread > + MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + goto failed; + } + memcpy(parms->readbraw.out.data, req->in.buffer + NBT_HDR_SIZE, parms->readbraw.out.nread); + break; + + case RAW_READ_LOCKREAD: + SMBCLI_CHECK_WCT(req, 5); + parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0)); + if (parms->lockread.out.nread > parms->lockread.in.count || + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, + parms->lockread.out.nread, parms->lockread.out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + break; + + case RAW_READ_READ: + /* there are 4 reserved words in the reply */ + SMBCLI_CHECK_WCT(req, 5); + parms->read.out.nread = SVAL(req->in.vwv, VWV(0)); + if (parms->read.out.nread > parms->read.in.count || + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, + parms->read.out.nread, parms->read.out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + break; + + case RAW_READ_READX: + /* there are 5 reserved words in the reply */ + SMBCLI_CHECK_WCT(req, 12); + parms->readx.out.remaining = SVAL(req->in.vwv, VWV(2)); + parms->readx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); + parms->readx.out.nread = SVAL(req->in.vwv, VWV(5)); + parms->readx.out.flags2 = req->flags2; + parms->readx.out.data_offset = SVAL(req->in.vwv, VWV(6)); + + /* handle oversize replies for non-chained readx replies with + CAP_LARGE_READX. The snia spec has must to answer for. */ + if ((req->tree->session->transport->negotiate.capabilities & CAP_LARGE_READX) + && CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE && + req->in.size >= 0x10000) { + parms->readx.out.nread += (SVAL(req->in.vwv, VWV(7)) << 16); + if (req->in.hdr + SVAL(req->in.vwv, VWV(6)) + + parms->readx.out.nread <= + req->in.buffer + req->in.size) { + req->in.data_size += (SVAL(req->in.vwv, VWV(7)) << 16); + + /* update the bufinfo with the new size */ + smb_setup_bufinfo(req); + } + } + + if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) || + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), + parms->readx.out.nread, + parms->readx.out.data)) { + req->status = NT_STATUS_BUFFER_TOO_SMALL; + } + break; + + case RAW_READ_SMB2: + req->status = NT_STATUS_INTERNAL_ERROR; + break; + } + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + low level read operation (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_read(struct smbcli_tree *tree, union smb_read *parms) +{ + struct smbcli_request *req = smb_raw_read_send(tree, parms); + return smb_raw_read_recv(req, parms); +} + + +/**************************************************************************** + raw write interface (async send) +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_write *parms) +{ + bool bigoffset = false; + struct smbcli_request *req = NULL; + + switch (parms->generic.level) { + case RAW_WRITE_WRITEUNLOCK: + SETUP_REQUEST(SMBwriteunlock, 5, 3 + parms->writeunlock.in.count); + SSVAL(req->out.vwv, VWV(0), parms->writeunlock.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->writeunlock.in.count); + SIVAL(req->out.vwv, VWV(2), parms->writeunlock.in.offset); + SSVAL(req->out.vwv, VWV(4), parms->writeunlock.in.remaining); + SCVAL(req->out.data, 0, SMB_DATA_BLOCK); + SSVAL(req->out.data, 1, parms->writeunlock.in.count); + if (parms->writeunlock.in.count > 0) { + memcpy(req->out.data+3, parms->writeunlock.in.data, + parms->writeunlock.in.count); + } + break; + + case RAW_WRITE_WRITE: + SETUP_REQUEST(SMBwrite, 5, 3 + parms->write.in.count); + SSVAL(req->out.vwv, VWV(0), parms->write.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->write.in.count); + SIVAL(req->out.vwv, VWV(2), parms->write.in.offset); + SSVAL(req->out.vwv, VWV(4), parms->write.in.remaining); + SCVAL(req->out.data, 0, SMB_DATA_BLOCK); + SSVAL(req->out.data, 1, parms->write.in.count); + if (parms->write.in.count > 0) { + memcpy(req->out.data+3, parms->write.in.data, parms->write.in.count); + } + break; + + case RAW_WRITE_WRITECLOSE: + SETUP_REQUEST(SMBwriteclose, 6, 1 + parms->writeclose.in.count); + SSVAL(req->out.vwv, VWV(0), parms->writeclose.in.file.fnum); + SSVAL(req->out.vwv, VWV(1), parms->writeclose.in.count); + SIVAL(req->out.vwv, VWV(2), parms->writeclose.in.offset); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(4), parms->writeclose.in.mtime); + SCVAL(req->out.data, 0, 0); + if (parms->writeclose.in.count > 0) { + memcpy(req->out.data+1, parms->writeclose.in.data, + parms->writeclose.in.count); + } + break; + + case RAW_WRITE_WRITEX: + if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) { + bigoffset = true; + } + SETUP_REQUEST(SMBwriteX, bigoffset ? 14 : 12, parms->writex.in.count); + SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); + SSVAL(req->out.vwv, VWV(1), 0); + SSVAL(req->out.vwv, VWV(2), parms->writex.in.file.fnum); + SIVAL(req->out.vwv, VWV(3), parms->writex.in.offset); + SIVAL(req->out.vwv, VWV(5), 0); /* reserved */ + SSVAL(req->out.vwv, VWV(7), parms->writex.in.wmode); + SSVAL(req->out.vwv, VWV(8), parms->writex.in.remaining); + SSVAL(req->out.vwv, VWV(9), parms->writex.in.count>>16); + SSVAL(req->out.vwv, VWV(10), parms->writex.in.count); + SSVAL(req->out.vwv, VWV(11), PTR_DIFF(req->out.data, req->out.hdr)); + if (bigoffset) { + SIVAL(req->out.vwv,VWV(12),parms->writex.in.offset>>32); + } + if (parms->writex.in.count > 0) { + memcpy(req->out.data, parms->writex.in.data, parms->writex.in.count); + } + break; + + case RAW_WRITE_SPLWRITE: + SETUP_REQUEST(SMBsplwr, 1, parms->splwrite.in.count); + SSVAL(req->out.vwv, VWV(0), parms->splwrite.in.file.fnum); + if (parms->splwrite.in.count > 0) { + memcpy(req->out.data, parms->splwrite.in.data, parms->splwrite.in.count); + } + break; + + case RAW_WRITE_SMB2: + return NULL; + } + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + + +/**************************************************************************** + raw write interface (async recv) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms) +{ + if (!smbcli_request_receive(req) || + !NT_STATUS_IS_OK(req->status)) { + goto failed; + } + + switch (parms->generic.level) { + case RAW_WRITE_WRITEUNLOCK: + SMBCLI_CHECK_WCT(req, 1); + parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0)); + break; + case RAW_WRITE_WRITE: + SMBCLI_CHECK_WCT(req, 1); + parms->write.out.nwritten = SVAL(req->in.vwv, VWV(0)); + break; + case RAW_WRITE_WRITECLOSE: + SMBCLI_CHECK_WCT(req, 1); + parms->writeclose.out.nwritten = SVAL(req->in.vwv, VWV(0)); + break; + case RAW_WRITE_WRITEX: + SMBCLI_CHECK_WCT(req, 6); + parms->writex.out.nwritten = SVAL(req->in.vwv, VWV(2)); + parms->writex.out.nwritten += (CVAL(req->in.vwv, VWV(4)) << 16); + parms->writex.out.remaining = SVAL(req->in.vwv, VWV(3)); + break; + case RAW_WRITE_SPLWRITE: + break; + case RAW_WRITE_SMB2: + req->status = NT_STATUS_INTERNAL_ERROR; + break; + } + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + raw write interface (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_write(struct smbcli_tree *tree, union smb_write *parms) +{ + struct smbcli_request *req = smb_raw_write_send(tree, parms); + return smb_raw_write_recv(req, parms); +} diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c new file mode 100644 index 0000000..3a6cf5d --- /dev/null +++ b/source4/libcli/raw/rawrequest.c @@ -0,0 +1,1055 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "lib/events/events.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "../libcli/smb/smbXcli_base.h" + +/* we over allocate the data buffer to prevent too many realloc calls */ +#define REQ_OVER_ALLOCATION 0 + +/* assume that a character will not consume more than 3 bytes per char */ +#define MAX_BYTES_PER_CHAR 3 + +/* setup the bufinfo used for strings and range checking */ +void smb_setup_bufinfo(struct smbcli_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.flags = 0; + if (req->flags2 & FLAGS2_UNICODE_STRINGS) { + req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE; + } + req->in.bufinfo.align_base = req->in.buffer; + req->in.bufinfo.data = req->in.data; + req->in.bufinfo.data_size = req->in.data_size; +} + + +/* destroy a request structure and return final status */ +_PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req) +{ + NTSTATUS status; + + /* this is the error code we give the application for when a + _send() call fails completely */ + if (!req) return NT_STATUS_UNSUCCESSFUL; + + if (req->state == SMBCLI_REQUEST_ERROR && + NT_STATUS_IS_OK(req->status)) { + req->status = NT_STATUS_INTERNAL_ERROR; + } + + status = req->status; + + if (!req->do_not_free) { + talloc_free(req); + } + + return status; +} + + +/* + setup a SMB packet at transport level +*/ +struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport, + uint8_t command, unsigned int wct, unsigned int buflen) +{ + struct smbcli_request *req; + size_t size; + + size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen; + + req = talloc_zero(transport, struct smbcli_request); + if (!req) { + return NULL; + } + + /* setup the request context */ + req->state = SMBCLI_REQUEST_INIT; + req->transport = transport; + req->out.size = size; + + /* over allocate by a small amount */ + req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; + + req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated); + if (!req->out.buffer) { + return NULL; + } + + req->out.hdr = req->out.buffer + NBT_HDR_SIZE; + req->out.vwv = req->out.hdr + HDR_VWV; + req->out.wct = wct; + req->out.data = req->out.vwv + VWV(wct) + 2; + req->out.data_size = buflen; + req->out.ptr = req->out.data; + + SCVAL(req->out.hdr, HDR_WCT, wct); + SSVAL(req->out.vwv, VWV(wct), buflen); + + memcpy(req->out.hdr, "\377SMB", 4); + SCVAL(req->out.hdr,HDR_COM,command); + + SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES); + SSVAL(req->out.hdr,HDR_FLG2, 0); + + /* copy the pid, uid and mid to the request */ + SSVAL(req->out.hdr, HDR_PID, 0); + SSVAL(req->out.hdr, HDR_UID, 0); + SSVAL(req->out.hdr, HDR_MID, 0); + SSVAL(req->out.hdr, HDR_TID,0); + SSVAL(req->out.hdr, HDR_PIDHIGH,0); + SIVAL(req->out.hdr, HDR_RCLS, 0); + memset(req->out.hdr+HDR_SS_FIELD, 0, 10); + + return req; +} + +/* + setup a reply in req->out with the given word count and initial data + buffer size. the caller will then fill in the command words and + data before calling smbcli_request_send() to send the reply on its + way. This interface is used before a session is setup. +*/ +struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session, + uint8_t command, unsigned int wct, size_t buflen) +{ + struct smbcli_request *req; + + req = smbcli_request_setup_transport(session->transport, command, wct, buflen); + + if (!req) return NULL; + + smb1cli_session_set_id(session->smbXcli, session->vuid); + + req->session = session; + + SSVAL(req->out.hdr, HDR_FLG2, session->flags2); + SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF); + SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16); + SSVAL(req->out.hdr, HDR_UID, session->vuid); + + return req; +} + +/* + setup a request for tree based commands +*/ +struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree, + uint8_t command, + unsigned int wct, unsigned int buflen) +{ + struct smbcli_request *req; + + req = smbcli_request_setup_session(tree->session, command, wct, buflen); + if (req) { + smb1cli_tcon_set_id(tree->smbXcli, tree->tid); + + req->tree = tree; + SSVAL(req->out.hdr,HDR_TID,tree->tid); + } + return req; +} + + +/* + grow the allocation of the data buffer portion of a reply + packet. Note that as this can reallocate the packet buffer this + invalidates any local pointers into the packet. + + To cope with this req->out.ptr is supplied. This will be updated to + point at the same offset into the packet as before this call +*/ +static void smbcli_req_grow_allocation(struct smbcli_request *req, unsigned int new_size) +{ + int delta; + uint8_t *buf2; + + delta = new_size - req->out.data_size; + if (delta + req->out.size <= req->out.allocated) { + /* it fits in the preallocation */ + return; + } + + /* we need to realloc */ + req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION; + buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated); + if (buf2 == NULL) { + smb_panic("out of memory in req_grow_allocation"); + } + + if (buf2 == req->out.buffer) { + /* the malloc library gave us the same pointer */ + return; + } + + /* update the pointers into the packet */ + req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer); + req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer); + req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer); + req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer); + + req->out.buffer = buf2; +} + + +/* + grow the data buffer portion of a reply packet. Note that as this + can reallocate the packet buffer this invalidates any local pointers + into the packet. + + To cope with this req->out.ptr is supplied. This will be updated to + point at the same offset into the packet as before this call +*/ +static void smbcli_req_grow_data(struct smbcli_request *req, unsigned int new_size) +{ + int delta; + + smbcli_req_grow_allocation(req, new_size); + + delta = new_size - req->out.data_size; + + req->out.size += delta; + req->out.data_size += delta; + + /* set the BCC to the new data size */ + SSVAL(req->out.vwv, VWV(req->out.wct), new_size); +} + + +/* + setup a chained reply in req->out with the given word count and + initial data buffer size. +*/ +NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req, + uint8_t command, + unsigned int wct, size_t buflen) +{ + size_t wct_ofs; + size_t size; + + /* + * here we only support one chained command + * If someone needs longer chains, the low + * level code should be used directly. + */ + if (req->subreqs[0] != NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + if (req->subreqs[1] != NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + + req->subreqs[0] = smbcli_transport_setup_subreq(req); + if (req->subreqs[0] == NULL) { + return NT_STATUS_NO_MEMORY; + } + + wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1); + + size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen; + + req->out.size = size; + + /* over allocate by a small amount */ + req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; + + req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated); + if (!req->out.buffer) { + return NT_STATUS_NO_MEMORY; + } + + req->out.hdr = req->out.buffer + NBT_HDR_SIZE; + req->out.vwv = req->out.hdr + wct_ofs; + req->out.wct = wct; + req->out.data = req->out.vwv + VWV(wct) + 2; + req->out.data_size = buflen; + req->out.ptr = req->out.data; + + SCVAL(req->out.hdr, HDR_WCT, wct); + SSVAL(req->out.vwv, VWV(wct), buflen); + + memcpy(req->out.hdr, "\377SMB", 4); + SCVAL(req->out.hdr,HDR_COM,command); + + SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES); + SSVAL(req->out.hdr,HDR_FLG2, 0); + + /* copy the pid, uid and mid to the request */ + SSVAL(req->out.hdr, HDR_PID, 0); + SSVAL(req->out.hdr, HDR_UID, 0); + SSVAL(req->out.hdr, HDR_MID, 0); + SSVAL(req->out.hdr, HDR_TID,0); + SSVAL(req->out.hdr, HDR_PIDHIGH,0); + SIVAL(req->out.hdr, HDR_RCLS, 0); + memset(req->out.hdr+HDR_SS_FIELD, 0, 10); + + if (req->session != NULL) { + SSVAL(req->out.hdr, HDR_FLG2, req->session->flags2); + SSVAL(req->out.hdr, HDR_PID, req->session->pid & 0xFFFF); + SSVAL(req->out.hdr, HDR_PIDHIGH, req->session->pid >> 16); + SSVAL(req->out.hdr, HDR_UID, req->session->vuid); + } + + if (req->tree != NULL) { + SSVAL(req->out.hdr, HDR_TID, req->tree->tid); + } + + return NT_STATUS_OK; +} + +/* + advance to the next chained reply in a request +*/ +NTSTATUS smbcli_chained_advance(struct smbcli_request *req) +{ + struct smbcli_transport *transport = req->transport; + uint8_t *hdr = NULL; + uint8_t wct = 0; + uint16_t *vwv = NULL; + uint32_t num_bytes = 0; + uint8_t *bytes = NULL; + struct iovec *recv_iov = NULL; + uint8_t *inbuf = NULL; + + if (req->subreqs[0] != NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + if (req->subreqs[1] == NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + + req->status = smb1cli_req_recv(req->subreqs[1], req, + &recv_iov, + &hdr, + &wct, + &vwv, + NULL, /* pvwv_offset */ + &num_bytes, + &bytes, + NULL, /* pbytes_offset */ + &inbuf, + NULL, 0); /* expected */ + TALLOC_FREE(req->subreqs[1]); + if (!NT_STATUS_IS_OK(req->status)) { + if (recv_iov == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + return req->status; + } + } + + /* fill in the 'in' portion of the matching request */ + req->in.buffer = inbuf; + req->in.size = NBT_HDR_SIZE + PTR_DIFF(bytes, hdr) + num_bytes; + req->in.allocated = req->in.size; + + req->in.hdr = hdr; + req->in.vwv = (uint8_t *)vwv; + req->in.wct = wct; + req->in.data = bytes; + req->in.data_size = num_bytes; + req->in.ptr = req->in.data; + req->flags2 = SVAL(req->in.hdr, HDR_FLG2); + + smb_setup_bufinfo(req); + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + + return NT_STATUS_OK; +} + + +/* + send a message +*/ +bool smbcli_request_send(struct smbcli_request *req) +{ + smbcli_transport_send(req); + return true; +} + + +/* + receive a response to a packet +*/ +bool smbcli_request_receive(struct smbcli_request *req) +{ + /* req can be NULL when a send has failed. This eliminates lots of NULL + checks in each module */ + if (!req) return false; + + /* keep receiving packets until this one is replied to */ + while (req->state <= SMBCLI_REQUEST_RECV) { + if (tevent_loop_once(req->transport->ev) != 0) { + return false; + } + } + + return req->state == SMBCLI_REQUEST_DONE; +} + +/* + wait for a reply to be received for a packet that just returns an error + code and nothing more +*/ +_PUBLIC_ NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req) +{ + (void) smbcli_request_receive(req); + return smbcli_request_destroy(req); +} + + +/* Return true if the last packet was in error */ +bool smbcli_request_is_error(struct smbcli_request *req) +{ + return NT_STATUS_IS_ERR(req->status); +} + +/* + append a string into the data portion of the request packet + + return the number of bytes added to the packet +*/ +size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, unsigned int flags) +{ + size_t len; + + /* determine string type to use */ + if (!(flags & (STR_ASCII|STR_UNICODE))) { + flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII; + } + + len = (strlen(str)+2) * MAX_BYTES_PER_CHAR; + + smbcli_req_grow_allocation(req, len + req->out.data_size); + + len = push_string(req->out.data + req->out.data_size, str, len, flags); + + smbcli_req_grow_data(req, len + req->out.data_size); + + return len; +} + + +/* + this is like smbcli_req_append_string but it also return the + non-terminated string byte length, which can be less than the number + of bytes consumed in the packet for 2 reasons: + + 1) the string in the packet may be null terminated + 2) the string in the packet may need a 1 byte UCS2 alignment + + this is used in places where the non-terminated string byte length is + placed in the packet as a separate field +*/ +size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len) +{ + int diff = 0; + size_t ret; + + /* determine string type to use */ + if (!(flags & (STR_ASCII|STR_UNICODE))) { + flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII; + } + + /* see if an alignment byte will be used */ + if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) { + diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags); + } + + /* do the hard work */ + ret = smbcli_req_append_string(req, str, flags); + + /* see if we need to subtract the termination */ + if (flags & STR_TERMINATE) { + diff += (flags & STR_UNICODE) ? 2 : 1; + } + + if (ret >= diff) { + (*len) = ret - diff; + } else { + (*len) = ret; + } + + return ret; +} + + +/* + push a string into the data portion of the request packet, growing it if necessary + this gets quite tricky - please be very careful to cover all cases when modifying this + + if dest is NULL, then put the string at the end of the data portion of the packet + + if dest_len is -1 then no limit applies +*/ +size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, unsigned int flags) +{ + size_t size; + smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1); + size = smbcli_req_append_string(req, str, flags); + return size + 1; +} + + +/* + push a blob into the data portion of the request packet, growing it if necessary + this gets quite tricky - please be very careful to cover all cases when modifying this + + if dest is NULL, then put the blob at the end of the data portion of the packet +*/ +size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob) +{ + if (blob->length > 0) { + smbcli_req_grow_allocation(req, + req->out.data_size + blob->length); + memcpy(req->out.data + req->out.data_size, + blob->data, + blob->length); + smbcli_req_grow_data(req, req->out.data_size + blob->length); + } + return blob->length; +} + +/* + append raw bytes into the data portion of the request packet + return the number of bytes added +*/ +size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len) +{ + if (byte_len > 0) { + smbcli_req_grow_allocation(req, byte_len + req->out.data_size); + memcpy(req->out.data + req->out.data_size, bytes, byte_len); + smbcli_req_grow_data(req, byte_len + req->out.data_size); + } + return byte_len; +} + +/* + append variable block (type 5 buffer) into the data portion of the request packet + return the number of bytes added +*/ +size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len) +{ + smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size); + SCVAL(req->out.data + req->out.data_size, 0, 5); + SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */ + if (byte_len > 0) { + memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len); + } + smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size); + return byte_len + 3; +} + + +/* + pull a UCS2 string from a request packet, returning a talloced unix string + + the string length is limited by the 3 things: + - the data size in the request (end of packet) + - the passed 'byte_len' if it is not -1 + - the end of string (null termination) + + Note that 'byte_len' is the number of bytes in the packet + + on failure zero is returned and *dest is set to NULL, otherwise the number + of bytes consumed in the packet is returned +*/ +static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, + char **dest, const uint8_t *src, int byte_len, unsigned int flags) +{ + int src_len, src_len2, alignment=0; + bool ret; + size_t ret_size; + + if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) { + src++; + alignment=1; + if (byte_len != -1) { + byte_len--; + } + } + + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); + if (src_len < 0) { + *dest = NULL; + return 0; + } + if (byte_len != -1 && src_len > byte_len) { + src_len = byte_len; + } + + src_len2 = utf16_len_n(src, src_len); + + /* ucs2 strings must be at least 2 bytes long */ + if (src_len2 < 2) { + *dest = NULL; + return 0; + } + + ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size); + if (!ret) { + *dest = NULL; + return 0; + } + + return src_len2 + alignment; +} + +/* + pull a ascii string from a request packet, returning a talloced string + + the string length is limited by the 3 things: + - the data size in the request (end of packet) + - the passed 'byte_len' if it is not -1 + - the end of string (null termination) + + Note that 'byte_len' is the number of bytes in the packet + + on failure zero is returned and *dest is set to NULL, otherwise the number + of bytes consumed in the packet is returned +*/ +size_t smbcli_req_pull_ascii(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, + char **dest, const uint8_t *src, int byte_len, unsigned int flags) +{ + int src_len, src_len2; + bool ret; + size_t ret_size; + + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); + if (src_len < 0) { + *dest = NULL; + return 0; + } + if (byte_len != -1 && src_len > byte_len) { + src_len = byte_len; + } + src_len2 = strnlen((const char *)src, src_len); + if (src_len2 < src_len - 1) { + /* include the termination if we didn't reach the end of the packet */ + src_len2++; + } + + ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest, &ret_size); + + if (!ret) { + *dest = NULL; + return 0; + } + + return ret_size; +} + +/** + pull a string from a request packet, returning a talloced string + + the string length is limited by the 3 things: + - the data size in the request (end of packet) + - the passed 'byte_len' if it is not -1 + - the end of string (null termination) + + Note that 'byte_len' is the number of bytes in the packet + + on failure zero is returned and *dest is set to NULL, otherwise the number + of bytes consumed in the packet is returned +*/ +size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, + char **dest, const uint8_t *src, int byte_len, unsigned int flags) +{ + if (!(flags & STR_ASCII) && + (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) { + return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags); + } + + return smbcli_req_pull_ascii(bufinfo, mem_ctx, dest, src, byte_len, flags); +} + + +/** + pull a DATA_BLOB from a reply packet, returning a talloced blob + make sure we don't go past end of packet + + if byte_len is -1 then limit the blob only by packet size +*/ +DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len) +{ + int src_len; + + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); + + if (src_len < 0) { + return data_blob(NULL, 0); + } + + if (byte_len != -1 && src_len > byte_len) { + src_len = byte_len; + } + + return data_blob_talloc(mem_ctx, src, src_len); +} + +/* check that a lump of data in a request is within the bounds of the data section of + the packet */ +static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count) +{ + /* be careful with wraparound! */ + if ((uintptr_t)ptr < (uintptr_t)bufinfo->data || + (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size || + count > bufinfo->data_size || + (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) { + return true; + } + return false; +} + +/* + pull a lump of data from a request packet + + return false if any part is outside the data portion of the packet +*/ +bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest) +{ + if (len == 0) return true; + + if (smbcli_req_data_oob(bufinfo, src, len)) { + return false; + } + + memcpy(dest, src, len); + return true; +} + + +/* + put a NTTIME into a packet +*/ +void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t) +{ + SBVAL(base, offset, t); +} + +/* + pull a NTTIME from a packet +*/ +NTTIME smbcli_pull_nttime(void *base, uint16_t offset) +{ + NTTIME ret = BVAL(base, offset); + return ret; +} + +/** + pull a UCS2 string from a blob, returning a talloced unix string + + the string length is limited by the 3 things: + - the data size in the blob + - the passed 'byte_len' if it is not -1 + - the end of string (null termination) + + Note that 'byte_len' is the number of bytes in the packet + + on failure zero is returned and *dest is set to NULL, otherwise the number + of bytes consumed in the blob is returned +*/ +size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx, + const DATA_BLOB *blob, const char **dest, + const uint8_t *src, int byte_len, unsigned int flags) +{ + int src_len, src_len2, alignment=0; + size_t ret_size; + bool ret; + char *dest2; + + if (src < blob->data || + src >= (blob->data + blob->length)) { + *dest = NULL; + return 0; + } + + src_len = blob->length - PTR_DIFF(src, blob->data); + + if (byte_len != -1 && src_len > byte_len) { + src_len = byte_len; + } + + if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) { + src++; + alignment=1; + src_len--; + } + + if (src_len < 2) { + *dest = NULL; + return 0; + } + + src_len2 = utf16_len_n(src, src_len); + + ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size); + if (!ret) { + *dest = NULL; + return 0; + } + *dest = dest2; + + return src_len2 + alignment; +} + +/** + pull a ascii string from a blob, returning a talloced string + + the string length is limited by the 3 things: + - the data size in the blob + - the passed 'byte_len' if it is not -1 + - the end of string (null termination) + + Note that 'byte_len' is the number of bytes in the blob + + on failure zero is returned and *dest is set to NULL, otherwise the number + of bytes consumed in the blob is returned +*/ +static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, const char **dest, + const uint8_t *src, int byte_len, unsigned int flags) +{ + int src_len, src_len2; + size_t ret_size; + bool ret; + char *dest2; + + src_len = blob->length - PTR_DIFF(src, blob->data); + if (src_len < 0) { + *dest = NULL; + return 0; + } + if (byte_len != -1 && src_len > byte_len) { + src_len = byte_len; + } + src_len2 = strnlen((const char *)src, src_len); + + if (src_len2 < src_len - 1) { + /* include the termination if we didn't reach the end of the packet */ + src_len2++; + } + + ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size); + + if (!ret) { + *dest = NULL; + return 0; + } + *dest = dest2; + + return ret_size; +} + +/** + pull a string from a blob, returning a talloced struct smb_wire_string + + the string length is limited by the 3 things: + - the data size in the blob + - length field on the wire + - the end of string (null termination) + + if STR_LEN8BIT is set in the flags then assume the length field is + 8 bits, instead of 32 + + on failure zero is returned and dest->s is set to NULL, otherwise the number + of bytes consumed in the blob is returned +*/ +size_t smbcli_blob_pull_string(struct smbcli_session *session, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + struct smb_wire_string *dest, + uint16_t len_offset, uint16_t str_offset, + unsigned int flags) +{ + int extra; + dest->s = NULL; + + if (!(flags & STR_ASCII)) { + /* this is here to cope with SMB2 calls using the SMB + parsers. SMB2 will pass smbcli_session==NULL, which forces + unicode on (as used by SMB2) */ + if (session == NULL) { + flags |= STR_UNICODE; + } else if (session->transport->negotiate.capabilities & CAP_UNICODE) { + flags |= STR_UNICODE; + } + } + + if (flags & STR_LEN8BIT) { + if (len_offset > blob->length-1) { + return 0; + } + dest->private_length = CVAL(blob->data, len_offset); + } else { + if (len_offset > blob->length-4) { + return 0; + } + dest->private_length = IVAL(blob->data, len_offset); + } + extra = 0; + dest->s = NULL; + if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) { + int align = 0; + if ((str_offset&1) && !(flags & STR_NOALIGN)) { + align = 1; + } + if (flags & STR_LEN_NOTERM) { + extra = 2; + } + return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s, + blob->data+str_offset+align, + dest->private_length, flags); + } + + if (flags & STR_LEN_NOTERM) { + extra = 1; + } + + return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s, + blob->data+str_offset, dest->private_length, flags); +} + +/** + pull a string from a blob, returning a talloced char * + + Currently only used by the UNIX search info level. + + the string length is limited by 2 things: + - the data size in the blob + - the end of string (null termination) + + on failure zero is returned and dest->s is set to NULL, otherwise the number + of bytes consumed in the blob is returned +*/ +size_t smbcli_blob_pull_unix_string(struct smbcli_session *session, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, + const char **dest, + uint16_t str_offset, + unsigned int flags) +{ + int extra = 0; + *dest = NULL; + + if (!(flags & STR_ASCII) && + ((flags & STR_UNICODE) || + (session->transport->negotiate.capabilities & CAP_UNICODE))) { + int align = 0; + if ((str_offset&1) && !(flags & STR_NOALIGN)) { + align = 1; + } + if (flags & STR_LEN_NOTERM) { + extra = 2; + } + return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest, + blob->data+str_offset+align, + -1, flags); + } + + if (flags & STR_LEN_NOTERM) { + extra = 1; + } + + return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest, + blob->data+str_offset, -1, flags); +} + + +/* + append a string into a blob +*/ +size_t smbcli_blob_append_string(struct smbcli_session *session, + TALLOC_CTX *mem_ctx, DATA_BLOB *blob, + const char *str, unsigned int flags) +{ + size_t max_len; + int len; + + if (!str) return 0; + + /* determine string type to use */ + if (!(flags & (STR_ASCII|STR_UNICODE))) { + flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII; + } + + max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR; + + blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length + max_len); + if (!blob->data) { + return 0; + } + + len = push_string(blob->data + blob->length, str, max_len, flags); + + blob->length += len; + + return len; +} + +/* + pull a GUID structure from the wire. The buffer must be at least 16 + bytes long + */ +NTSTATUS smbcli_pull_guid(void *base, uint16_t offset, + struct GUID *guid) +{ + DATA_BLOB blob; + + ZERO_STRUCTP(guid); + + blob.data = offset + (uint8_t *)base; + blob.length = 16; + + return GUID_from_ndr_blob(&blob, guid); +} + +/* + push a guid onto the wire. The buffer must hold 16 bytes + */ +NTSTATUS smbcli_push_guid(void *base, uint16_t offset, const struct GUID *guid) +{ + NTSTATUS status; + struct GUID_ndr_buf buf = { .buf = {0}, }; + + status = GUID_to_ndr_buf(guid, &buf); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + memcpy(offset + (uint8_t *)base, buf.buf, sizeof(buf.buf)); + return NT_STATUS_OK; +} diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c new file mode 100644 index 0000000..665dfd3 --- /dev/null +++ b/source4/libcli/raw/rawsearch.c @@ -0,0 +1,842 @@ +/* + Unix SMB/CIFS implementation. + client directory search routines + Copyright (C) James Myers 2003 <myersjj@samba.org> + Copyright (C) James Peach 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" + +/**************************************************************************** + Old style search backend - process output. +****************************************************************************/ +static void smb_raw_search_backend(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + uint16_t count, + void *private_data, + smbcli_search_callback callback) + +{ + union smb_search_data search_data; + int i; + uint8_t *p; + + if (req->in.data_size < 3 + count*43) { + req->status = NT_STATUS_INVALID_PARAMETER; + return; + } + + p = req->in.data + 3; + + for (i=0; i < count; i++) { + char *name; + + search_data.search.id.reserved = CVAL(p, 0); + memcpy(search_data.search.id.name, p+1, 11); + search_data.search.id.handle = CVAL(p, 12); + search_data.search.id.server_cookie = IVAL(p, 13); + search_data.search.id.client_cookie = IVAL(p, 17); + search_data.search.attrib = CVAL(p, 21); + search_data.search.write_time = raw_pull_dos_date(req->transport, + p + 22); + search_data.search.size = IVAL(p, 26); + smbcli_req_pull_ascii(&req->in.bufinfo, mem_ctx, &name, p+30, 13, STR_ASCII); + search_data.search.name = name; + if (!callback(private_data, &search_data)) { + break; + } + p += 43; + } +} + +/**************************************************************************** + Old style search first. +****************************************************************************/ +static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_first *io, void *private_data, + smbcli_search_callback callback) + +{ + struct smbcli_request *req; + uint8_t op = SMBsearch; + + if (io->generic.level == RAW_SEARCH_FFIRST) { + op = SMBffirst; + } else if (io->generic.level == RAW_SEARCH_FUNIQUE) { + op = SMBfunique; + } + + req = smbcli_request_setup(tree, op, 2, 0); + if (!req) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(req->out.vwv, VWV(0), io->search_first.in.max_count); + SSVAL(req->out.vwv, VWV(1), io->search_first.in.search_attrib); + smbcli_req_append_ascii4(req, io->search_first.in.pattern, STR_TERMINATE); + smbcli_req_append_var_block(req, NULL, 0); + + if (!smbcli_request_send(req) || + !smbcli_request_receive(req)) { + return smbcli_request_destroy(req); + } + + if (NT_STATUS_IS_OK(req->status)) { + io->search_first.out.count = SVAL(req->in.vwv, VWV(0)); + smb_raw_search_backend(req, mem_ctx, io->search_first.out.count, private_data, callback); + } + + return smbcli_request_destroy(req); +} + +/**************************************************************************** + Old style search next. +****************************************************************************/ +static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_next *io, void *private_data, + smbcli_search_callback callback) + +{ + struct smbcli_request *req; + uint8_t var_block[21]; + uint8_t op = SMBsearch; + + if (io->generic.level == RAW_SEARCH_FFIRST) { + op = SMBffirst; + } + + req = smbcli_request_setup(tree, op, 2, 0); + if (!req) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count); + SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib); + smbcli_req_append_ascii4(req, "", STR_TERMINATE); + + SCVAL(var_block, 0, io->search_next.in.id.reserved); + memcpy(&var_block[1], io->search_next.in.id.name, 11); + SCVAL(var_block, 12, io->search_next.in.id.handle); + SIVAL(var_block, 13, io->search_next.in.id.server_cookie); + SIVAL(var_block, 17, io->search_next.in.id.client_cookie); + + smbcli_req_append_var_block(req, var_block, 21); + + if (!smbcli_request_send(req) || + !smbcli_request_receive(req)) { + return smbcli_request_destroy(req); + } + + if (NT_STATUS_IS_OK(req->status)) { + io->search_next.out.count = SVAL(req->in.vwv, VWV(0)); + smb_raw_search_backend(req, mem_ctx, io->search_next.out.count, private_data, callback); + } + + return smbcli_request_destroy(req); +} + + +/**************************************************************************** + Old style search next. +****************************************************************************/ +static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree, + union smb_search_close *io) +{ + struct smbcli_request *req; + uint8_t var_block[21]; + + req = smbcli_request_setup(tree, SMBfclose, 2, 0); + if (!req) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count); + SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib); + smbcli_req_append_ascii4(req, "", STR_TERMINATE); + + SCVAL(var_block, 0, io->fclose.in.id.reserved); + memcpy(&var_block[1], io->fclose.in.id.name, 11); + SCVAL(var_block, 12, io->fclose.in.id.handle); + SIVAL(var_block, 13, io->fclose.in.id.server_cookie); + SIVAL(var_block, 17, io->fclose.in.id.client_cookie); + + smbcli_req_append_var_block(req, var_block, 21); + + if (!smbcli_request_send(req) || + !smbcli_request_receive(req)) { + return smbcli_request_destroy(req); + } + + return smbcli_request_destroy(req); +} + + + +/**************************************************************************** + Very raw search first - returns param/data blobs. +****************************************************************************/ +static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, /* used to allocate output blobs */ + union smb_search_first *io, + DATA_BLOB *out_param_blob, + DATA_BLOB *out_data_blob) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_FINDFIRST; + NTSTATUS status; + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.data = data_blob(NULL, 0); + tp.in.max_param = 10; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + + if (io->t2ffirst.level != RAW_SEARCH_TRANS2) { + return NT_STATUS_INVALID_LEVEL; + } + + if (io->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) { + return NT_STATUS_INVALID_LEVEL; + } + + if (io->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2ffirst.in.num_names, + io->t2ffirst.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); + if (!tp.in.params.data) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(tp.in.params.data, 0, io->t2ffirst.in.search_attrib); + SSVAL(tp.in.params.data, 2, io->t2ffirst.in.max_count); + SSVAL(tp.in.params.data, 4, io->t2ffirst.in.flags); + SSVAL(tp.in.params.data, 6, io->t2ffirst.data_level); + SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type); + + smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params, + io->t2ffirst.in.pattern, STR_TERMINATE); + + status = smb_raw_trans2(tree, mem_ctx, &tp); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + out_param_blob->length = tp.out.params.length; + out_param_blob->data = tp.out.params.data; + out_data_blob->length = tp.out.data.length; + out_data_blob->data = tp.out.data.data; + + return NT_STATUS_OK; +} + + +/**************************************************************************** + Very raw search first - returns param/data blobs. + Used in CIFS-on-CIFS NTVFS. +****************************************************************************/ +static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_next *io, + DATA_BLOB *out_param_blob, + DATA_BLOB *out_data_blob) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_FINDNEXT; + NTSTATUS status; + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.data = data_blob(NULL, 0); + tp.in.max_param = 10; + tp.in.max_data = 0xFFFF; + tp.in.setup = &setup; + + if (io->t2fnext.level != RAW_SEARCH_TRANS2) { + return NT_STATUS_INVALID_LEVEL; + } + + if (io->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) { + return NT_STATUS_INVALID_LEVEL; + } + + if (io->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2fnext.in.num_names, + io->t2fnext.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); + if (!tp.in.params.data) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(tp.in.params.data, 0, io->t2fnext.in.handle); + SSVAL(tp.in.params.data, 2, io->t2fnext.in.max_count); + SSVAL(tp.in.params.data, 4, io->t2fnext.data_level); + SIVAL(tp.in.params.data, 6, io->t2fnext.in.resume_key); + SSVAL(tp.in.params.data, 10, io->t2fnext.in.flags); + + smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params, + io->t2fnext.in.last_name, + STR_TERMINATE); + + status = smb_raw_trans2(tree, mem_ctx, &tp); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + out_param_blob->length = tp.out.params.length; + out_param_blob->data = tp.out.params.data; + out_data_blob->length = tp.out.data.length; + out_data_blob->data = tp.out.data.data; + + return NT_STATUS_OK; +} + + +/* + parse the wire search formats that are in common between SMB and + SMB2 +*/ +NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx, + enum smb_search_data_level level, + const DATA_BLOB *blob, + union smb_search_data *data, + unsigned int *next_ofs, + unsigned int str_flags) +{ + unsigned int len, blen; + + if (blob->length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + *next_ofs = IVAL(blob->data, 0); + if (*next_ofs != 0) { + blen = *next_ofs; + } else { + blen = blob->length; + } + + switch (level) { + case RAW_SEARCH_DATA_DIRECTORY_INFO: + if (blen < 65) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->directory_info.file_index = IVAL(blob->data, 4); + data->directory_info.create_time = smbcli_pull_nttime(blob->data, 8); + data->directory_info.access_time = smbcli_pull_nttime(blob->data, 16); + data->directory_info.write_time = smbcli_pull_nttime(blob->data, 24); + data->directory_info.change_time = smbcli_pull_nttime(blob->data, 32); + data->directory_info.size = BVAL(blob->data, 40); + data->directory_info.alloc_size = BVAL(blob->data, 48); + data->directory_info.attrib = IVAL(blob->data, 56); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->directory_info.name, + 60, 64, str_flags); + if (*next_ofs != 0 && *next_ofs < 64+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: + if (blen < 69) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->full_directory_info.file_index = IVAL(blob->data, 4); + data->full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); + data->full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); + data->full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); + data->full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); + data->full_directory_info.size = BVAL(blob->data, 40); + data->full_directory_info.alloc_size = BVAL(blob->data, 48); + data->full_directory_info.attrib = IVAL(blob->data, 56); + data->full_directory_info.ea_size = IVAL(blob->data, 64); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->full_directory_info.name, + 60, 68, str_flags); + if (*next_ofs != 0 && *next_ofs < 68+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + case RAW_SEARCH_DATA_NAME_INFO: + if (blen < 13) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->name_info.file_index = IVAL(blob->data, 4); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->name_info.name, + 8, 12, str_flags); + if (*next_ofs != 0 && *next_ofs < 12+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + + case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: + if (blen < 95) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->both_directory_info.file_index = IVAL(blob->data, 4); + data->both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); + data->both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); + data->both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); + data->both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); + data->both_directory_info.size = BVAL(blob->data, 40); + data->both_directory_info.alloc_size = BVAL(blob->data, 48); + data->both_directory_info.attrib = IVAL(blob->data, 56); + data->both_directory_info.ea_size = IVAL(blob->data, 64); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->both_directory_info.short_name, + 68, 70, STR_LEN8BIT | STR_UNICODE); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->both_directory_info.name, + 60, 94, str_flags); + if (*next_ofs != 0 && *next_ofs < 94+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + + case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: + if (blen < 81) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->id_full_directory_info.file_index = IVAL(blob->data, 4); + data->id_full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); + data->id_full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); + data->id_full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); + data->id_full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); + data->id_full_directory_info.size = BVAL(blob->data, 40); + data->id_full_directory_info.alloc_size = BVAL(blob->data, 48); + data->id_full_directory_info.attrib = IVAL(blob->data, 56); + data->id_full_directory_info.ea_size = IVAL(blob->data, 64); + data->id_full_directory_info.file_id = BVAL(blob->data, 72); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->id_full_directory_info.name, + 60, 80, str_flags); + if (*next_ofs != 0 && *next_ofs < 80+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: + if (blen < 105) return NT_STATUS_INFO_LENGTH_MISMATCH; + data->id_both_directory_info.file_index = IVAL(blob->data, 4); + data->id_both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); + data->id_both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); + data->id_both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); + data->id_both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); + data->id_both_directory_info.size = BVAL(blob->data, 40); + data->id_both_directory_info.alloc_size = BVAL(blob->data, 48); + data->id_both_directory_info.attrib = SVAL(blob->data, 56); + data->id_both_directory_info.ea_size = IVAL(blob->data, 64); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->id_both_directory_info.short_name, + 68, 70, STR_LEN8BIT | STR_UNICODE); + memcpy(data->id_both_directory_info.short_name_buf, blob->data + 70, 24); + data->id_both_directory_info.file_id = BVAL(blob->data, 96); + len = smbcli_blob_pull_string(NULL, mem_ctx, blob, + &data->id_both_directory_info.name, + 60, 104, str_flags); + if (*next_ofs != 0 && *next_ofs < 104+len) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + return NT_STATUS_OK; + + default: + break; + } + + /* invalid level */ + return NT_STATUS_INVALID_INFO_CLASS; +} + + +/* + parse a trans2 search response. + Return the number of bytes consumed + return 0 for success with end of list + return -1 for a parse error +*/ +static int parse_trans2_search(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + enum smb_search_data_level level, + uint16_t flags, + DATA_BLOB *blob, + union smb_search_data *data) +{ + unsigned int len, ofs; + uint32_t ea_size; + DATA_BLOB eablob; + NTSTATUS status; + + switch (level) { + case RAW_SEARCH_DATA_GENERIC: + case RAW_SEARCH_DATA_SEARCH: + /* handled elsewhere */ + return -1; + + case RAW_SEARCH_DATA_STANDARD: + if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + if (blob->length < 4) return -1; + data->standard.resume_key = IVAL(blob->data, 0); + blob->data += 4; + blob->length -= 4; + } + if (blob->length < 24) return -1; + data->standard.create_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 0); + data->standard.access_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 4); + data->standard.write_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 8); + data->standard.size = IVAL(blob->data, 12); + data->standard.alloc_size = IVAL(blob->data, 16); + data->standard.attrib = SVAL(blob->data, 20); + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->standard.name, + 22, 23, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM); + return len + 23; + + case RAW_SEARCH_DATA_EA_SIZE: + if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + if (blob->length < 4) return -1; + data->ea_size.resume_key = IVAL(blob->data, 0); + blob->data += 4; + blob->length -= 4; + } + if (blob->length < 28) return -1; + data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 0); + data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 4); + data->ea_size.write_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 8); + data->ea_size.size = IVAL(blob->data, 12); + data->ea_size.alloc_size = IVAL(blob->data, 16); + data->ea_size.attrib = SVAL(blob->data, 20); + data->ea_size.ea_size = IVAL(blob->data, 22); + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->ea_size.name, + 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); + return len + 27 + 1; + + case RAW_SEARCH_DATA_EA_LIST: + if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + if (blob->length < 4) return -1; + data->ea_list.resume_key = IVAL(blob->data, 0); + blob->data += 4; + blob->length -= 4; + } + if (blob->length < 28) return -1; + data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 0); + data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 4); + data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 8); + data->ea_list.size = IVAL(blob->data, 12); + data->ea_list.alloc_size = IVAL(blob->data, 16); + data->ea_list.attrib = SVAL(blob->data, 20); + ea_size = IVAL(blob->data, 22); + if (ea_size > 0xFFFF) { + return -1; + } + eablob.data = blob->data + 22; + eablob.length = ea_size; + if (eablob.length > blob->length - 24) { + return -1; + } + status = ea_pull_list(&eablob, mem_ctx, + &data->ea_list.eas.num_eas, + &data->ea_list.eas.eas); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->ea_list.name, + 22+ea_size, 23+ea_size, + STR_LEN8BIT | STR_NOALIGN); + return len + ea_size + 23 + 1; + + case RAW_SEARCH_DATA_UNIX_INFO: + if (blob->length < 109) return -1; + ofs = IVAL(blob->data, 0); + data->unix_info.file_index = IVAL(blob->data, 4); + data->unix_info.size = BVAL(blob->data, 8); + data->unix_info.alloc_size = BVAL(blob->data, 16); + data->unix_info.status_change_time = smbcli_pull_nttime(blob->data, 24); + data->unix_info.access_time = smbcli_pull_nttime(blob->data, 32); + data->unix_info.change_time = smbcli_pull_nttime(blob->data, 40); + data->unix_info.uid = IVAL(blob->data, 48); + data->unix_info.gid = IVAL(blob->data, 56); + data->unix_info.file_type = IVAL(blob->data, 64); + data->unix_info.dev_major = BVAL(blob->data, 68); + data->unix_info.dev_minor = BVAL(blob->data, 76); + data->unix_info.unique_id = BVAL(blob->data, 84); + data->unix_info.permissions = IVAL(blob->data, 92); + data->unix_info.nlink = IVAL(blob->data, 100); + /* There is no length field for this name but we know it's null terminated. */ + len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob, + &data->unix_info.name, 108, 0); + if (ofs != 0 && ofs < 108+len) { + return -1; + } + return ofs; + + case RAW_SEARCH_DATA_UNIX_INFO2: + /* 8 - size of ofs + file_index + * 116 - size of unix_info2 + * 4 - size of name length + * 2 - "." is the shortest name + */ + if (blob->length < (116 + 8 + 4 + 2)) { + return -1; + } + + ofs = IVAL(blob->data, 0); + data->unix_info2.file_index = IVAL(blob->data, 4); + data->unix_info2.end_of_file = BVAL(blob->data, 8); + data->unix_info2.num_bytes = BVAL(blob->data, 16); + data->unix_info2.status_change_time = smbcli_pull_nttime(blob->data, 24); + data->unix_info2.access_time = smbcli_pull_nttime(blob->data, 32); + data->unix_info2.change_time = smbcli_pull_nttime(blob->data, 40); + data->unix_info2.uid = IVAL(blob->data, 48); + data->unix_info2.gid = IVAL(blob->data, 56); + data->unix_info2.file_type = IVAL(blob->data, 64); + data->unix_info2.dev_major = BVAL(blob->data, 68); + data->unix_info2.dev_minor = BVAL(blob->data, 76); + data->unix_info2.unique_id = BVAL(blob->data, 84); + data->unix_info2.permissions = IVAL(blob->data, 92); + data->unix_info2.nlink = IVAL(blob->data, 100); + data->unix_info2.create_time = smbcli_pull_nttime(blob->data, 108); + data->unix_info2.file_flags = IVAL(blob->data, 116); + data->unix_info2.flags_mask = IVAL(blob->data, 120); + + /* There is a 4 byte length field for this name. The length + * does not include the NULL terminator. + */ + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->unix_info2.name, + 8 + 116, /* offset to length */ + 8 + 116 + 4, /* offset to string */ + 0); + + if (ofs != 0 && ofs < (8 + 116 + 4 + len)) { + return -1; + } + + return ofs; + + case RAW_SEARCH_DATA_DIRECTORY_INFO: + case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: + case RAW_SEARCH_DATA_NAME_INFO: + case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: + case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: + case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: { + unsigned int str_flags = STR_UNICODE; + if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) { + str_flags = STR_ASCII; + } + + status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + return ofs; + } + } + + /* invalid level */ + return -1; +} + +/**************************************************************************** + Trans2 search backend - process output. +****************************************************************************/ +static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + enum smb_search_data_level level, + uint16_t flags, + int16_t count, + DATA_BLOB *blob, + void *private_data, + smbcli_search_callback callback) + +{ + int i; + DATA_BLOB blob2; + + blob2.data = blob->data; + blob2.length = blob->length; + + for (i=0; i < count; i++) { + union smb_search_data search_data; + unsigned int len; + + len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data); + if (len == -1) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* the callback function can tell us that no more will + fit - in that case we stop, but it isn't an error */ + if (!callback(private_data, &search_data)) { + break; + } + + if (len == 0) break; + + blob2.data += len; + blob2.length -= len; + } + + return NT_STATUS_OK; +} + + +/* Implements trans2findfirst2 and old search + */ +_PUBLIC_ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_first *io, void *private_data, + smbcli_search_callback callback) +{ + DATA_BLOB p_blob = data_blob_null, d_blob = data_blob_null; + NTSTATUS status; + + switch (io->generic.level) { + case RAW_SEARCH_SEARCH: + case RAW_SEARCH_FFIRST: + case RAW_SEARCH_FUNIQUE: + return smb_raw_search_first_old(tree, mem_ctx, io, private_data, callback); + + case RAW_SEARCH_TRANS2: + break; + + case RAW_SEARCH_SMB2: + return NT_STATUS_INVALID_LEVEL; + } + + status = smb_raw_search_first_blob(tree, mem_ctx, + io, &p_blob, &d_blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (p_blob.length < 10) { + DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n", + (int)p_blob.length)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* process output data */ + io->t2ffirst.out.handle = SVAL(p_blob.data, 0); + io->t2ffirst.out.count = SVAL(p_blob.data, 2); + io->t2ffirst.out.end_of_search = SVAL(p_blob.data, 4); + + status = smb_raw_t2search_backend(tree, mem_ctx, + io->generic.data_level, + io->t2ffirst.in.flags, io->t2ffirst.out.count, + &d_blob, private_data, callback); + + return status; +} + +/* Implements trans2findnext2 and old smbsearch + */ +NTSTATUS smb_raw_search_next(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_search_next *io, void *private_data, + smbcli_search_callback callback) +{ + DATA_BLOB p_blob = data_blob_null, d_blob = data_blob_null; + NTSTATUS status; + + switch (io->generic.level) { + case RAW_SEARCH_SEARCH: + case RAW_SEARCH_FFIRST: + return smb_raw_search_next_old(tree, mem_ctx, io, private_data, callback); + + case RAW_SEARCH_FUNIQUE: + return NT_STATUS_INVALID_LEVEL; + + case RAW_SEARCH_TRANS2: + break; + + case RAW_SEARCH_SMB2: + return NT_STATUS_INVALID_LEVEL; + } + + status = smb_raw_search_next_blob(tree, mem_ctx, + io, &p_blob, &d_blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (p_blob.length != 8) { + DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n", + (int)p_blob.length)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* process output data */ + io->t2fnext.out.count = SVAL(p_blob.data, 0); + io->t2fnext.out.end_of_search = SVAL(p_blob.data, 2); + + status = smb_raw_t2search_backend(tree, mem_ctx, + io->generic.data_level, + io->t2fnext.in.flags, io->t2fnext.out.count, + &d_blob, private_data, callback); + + return status; +} + +/* + Implements trans2findclose2 + */ +NTSTATUS smb_raw_search_close(struct smbcli_tree *tree, + union smb_search_close *io) +{ + struct smbcli_request *req; + + if (io->generic.level == RAW_FINDCLOSE_FCLOSE) { + return smb_raw_search_close_old(tree, io); + } + + req = smbcli_request_setup(tree, SMBfindclose, 1, 0); + if (!req) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle); + + if (smbcli_request_send(req)) { + (void) smbcli_request_receive(req); + } + + return smbcli_request_destroy(req); +} diff --git a/source4/libcli/raw/rawsetfileinfo.c b/source4/libcli/raw/rawsetfileinfo.c new file mode 100644 index 0000000..fec99d3 --- /dev/null +++ b/source4/libcli/raw/rawsetfileinfo.c @@ -0,0 +1,492 @@ +/* + Unix SMB/CIFS implementation. + RAW_SFILEINFO_* calls + Copyright (C) James Myers 2003 + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James Peach 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_security.h" + + +/* + Handle setfileinfo/setpathinfo passthu constructions +*/ +bool smb_raw_setfileinfo_passthru(TALLOC_CTX *mem_ctx, + enum smb_setfileinfo_level level, + union smb_setfileinfo *parms, + DATA_BLOB *blob) +{ + unsigned int len; + +#define NEED_BLOB(n) do { \ + *blob = data_blob_talloc(mem_ctx, NULL, n); \ + if (blob->data == NULL && n != 0) return false; \ + } while (0) + + switch (level) { + case RAW_SFILEINFO_BASIC_INFORMATION: + NEED_BLOB(40); + smbcli_push_nttime(blob->data, 0, parms->basic_info.in.create_time); + smbcli_push_nttime(blob->data, 8, parms->basic_info.in.access_time); + smbcli_push_nttime(blob->data, 16, parms->basic_info.in.write_time); + smbcli_push_nttime(blob->data, 24, parms->basic_info.in.change_time); + SIVAL(blob->data, 32, parms->basic_info.in.attrib); + SIVAL(blob->data, 36, 0); /* padding */ + return true; + + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + NEED_BLOB(4); + SIVAL(blob->data, 0, parms->disposition_info.in.delete_on_close); + return true; + + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->allocation_info.in.alloc_size); + return true; + + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->end_of_file_info.in.size); + return true; + + case RAW_SFILEINFO_RENAME_INFORMATION: + NEED_BLOB(12); + SIVAL(blob->data, 0, parms->rename_information.in.overwrite); + SIVAL(blob->data, 4, parms->rename_information.in.root_fid); + len = smbcli_blob_append_string(NULL, mem_ctx, blob, + parms->rename_information.in.new_name, + STR_UNICODE|STR_TERMINATE); + SIVAL(blob->data, 8, len - 2); + return true; + + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + NEED_BLOB(20); + SIVAL(blob->data, 0, parms->rename_information.in.overwrite); + SIVAL(blob->data, 4, 0); + SBVAL(blob->data, 8, parms->rename_information.in.root_fid); + len = smbcli_blob_append_string(NULL, mem_ctx, blob, + parms->rename_information.in.new_name, + STR_UNICODE|STR_TERMINATE); + SIVAL(blob->data, 16, len - 2); + return true; + + case RAW_SFILEINFO_POSITION_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->position_information.in.position); + return true; + + case RAW_SFILEINFO_MODE_INFORMATION: + NEED_BLOB(4); + SIVAL(blob->data, 0, parms->mode_information.in.mode); + return true; + + case RAW_FILEINFO_SEC_DESC: { + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, parms->set_secdesc.in.sd, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; + } + + return true; + } + + case RAW_SFILEINFO_FULL_EA_INFORMATION: + printf("num_eas=%d\n", parms->full_ea_information.in.eas.num_eas); + NEED_BLOB(ea_list_size_chained( + parms->full_ea_information.in.eas.num_eas, + parms->full_ea_information.in.eas.eas, 4)); + ea_put_list_chained(blob->data, + parms->full_ea_information.in.eas.num_eas, + parms->full_ea_information.in.eas.eas, 4); + return true; + + /* Unhandled levels */ + case RAW_SFILEINFO_PIPE_INFORMATION: + case RAW_SFILEINFO_VALID_DATA_INFORMATION: + case RAW_SFILEINFO_SHORT_NAME_INFORMATION: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1027: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1030: + case RAW_SFILEINFO_1031: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1036: + case RAW_SFILEINFO_1041: + case RAW_SFILEINFO_1042: + case RAW_SFILEINFO_1043: + case RAW_SFILEINFO_1044: + break; + + default: + DEBUG(0,("Unhandled setfileinfo passthru level %d\n", level)); + return false; + } + + return false; +} + +/* + Handle setfileinfo/setpathinfo trans2 backend. +*/ +static bool smb_raw_setinfo_backend(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_setfileinfo *parms, + DATA_BLOB *blob) +{ + switch (parms->generic.level) { + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SETATTR: + case RAW_SFILEINFO_SETATTRE: + case RAW_SFILEINFO_SEC_DESC: + /* not handled here */ + return false; + + case RAW_SFILEINFO_STANDARD: + NEED_BLOB(12); + raw_push_dos_date2(tree->session->transport, + blob->data, 0, parms->standard.in.create_time); + raw_push_dos_date2(tree->session->transport, + blob->data, 4, parms->standard.in.access_time); + raw_push_dos_date2(tree->session->transport, + blob->data, 8, parms->standard.in.write_time); + return true; + + case RAW_SFILEINFO_EA_SET: + NEED_BLOB(ea_list_size(parms->ea_set.in.num_eas, parms->ea_set.in.eas)); + ea_put_list(blob->data, parms->ea_set.in.num_eas, parms->ea_set.in.eas); + return true; + + case RAW_SFILEINFO_BASIC_INFO: + case RAW_SFILEINFO_BASIC_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_BASIC_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_UNIX_BASIC: + NEED_BLOB(100); + SBVAL(blob->data, 0, parms->unix_basic.in.end_of_file); + SBVAL(blob->data, 8, parms->unix_basic.in.num_bytes); + smbcli_push_nttime(blob->data, 16, parms->unix_basic.in.status_change_time); + smbcli_push_nttime(blob->data, 24, parms->unix_basic.in.access_time); + smbcli_push_nttime(blob->data, 32, parms->unix_basic.in.change_time); + SBVAL(blob->data, 40, parms->unix_basic.in.uid); + SBVAL(blob->data, 48, parms->unix_basic.in.gid); + SIVAL(blob->data, 56, parms->unix_basic.in.file_type); + SBVAL(blob->data, 60, parms->unix_basic.in.dev_major); + SBVAL(blob->data, 68, parms->unix_basic.in.dev_minor); + SBVAL(blob->data, 76, parms->unix_basic.in.unique_id); + SBVAL(blob->data, 84, parms->unix_basic.in.permissions); + SBVAL(blob->data, 92, parms->unix_basic.in.nlink); + return true; + + case RAW_SFILEINFO_UNIX_INFO2: + NEED_BLOB(116); + SBVAL(blob->data, 0, parms->unix_info2.in.end_of_file); + SBVAL(blob->data, 8, parms->unix_info2.in.num_bytes); + smbcli_push_nttime(blob->data, 16, parms->unix_info2.in.status_change_time); + smbcli_push_nttime(blob->data, 24, parms->unix_info2.in.access_time); + smbcli_push_nttime(blob->data, 32, parms->unix_info2.in.change_time); + SBVAL(blob->data, 40,parms->unix_info2.in.uid); + SBVAL(blob->data, 48,parms->unix_info2.in.gid); + SIVAL(blob->data, 56,parms->unix_info2.in.file_type); + SBVAL(blob->data, 60,parms->unix_info2.in.dev_major); + SBVAL(blob->data, 68,parms->unix_info2.in.dev_minor); + SBVAL(blob->data, 76,parms->unix_info2.in.unique_id); + SBVAL(blob->data, 84,parms->unix_info2.in.permissions); + SBVAL(blob->data, 92,parms->unix_info2.in.nlink); + smbcli_push_nttime(blob->data, 100, parms->unix_info2.in.create_time); + SIVAL(blob->data, 108, parms->unix_info2.in.file_flags); + SIVAL(blob->data, 112, parms->unix_info2.in.flags_mask); + return true; + + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_DISPOSITION_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_ALLOCATION_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_END_OF_FILE_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_RENAME_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_RENAME_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_POSITION_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_POSITION_INFORMATION, + parms, blob); + + case RAW_SFILEINFO_MODE_INFORMATION: + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_MODE_INFORMATION, + parms, blob); + + /* Unhandled passthru levels */ + case RAW_SFILEINFO_PIPE_INFORMATION: + case RAW_SFILEINFO_VALID_DATA_INFORMATION: + case RAW_SFILEINFO_SHORT_NAME_INFORMATION: + case RAW_SFILEINFO_FULL_EA_INFORMATION: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1027: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1030: + case RAW_SFILEINFO_1031: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1036: + case RAW_SFILEINFO_1041: + case RAW_SFILEINFO_1042: + case RAW_SFILEINFO_1043: + case RAW_SFILEINFO_1044: + return smb_raw_setfileinfo_passthru(mem_ctx, parms->generic.level, + parms, blob); + + /* Unhandled levels */ + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + case RAW_SFILEINFO_LINK_INFORMATION: + break; + } + + return false; +} + +/**************************************************************************** + Very raw set file info - takes data blob (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_setfileinfo_blob_send(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + uint16_t fnum, + uint16_t info_level, + DATA_BLOB *blob) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_SETFILEINFO; + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 2; + tp.in.max_data = 0; + tp.in.setup = &setup; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 6); + if (!tp.in.params.data) { + return NULL; + } + SSVAL(tp.in.params.data, 0, fnum); + SSVAL(tp.in.params.data, 2, info_level); + SSVAL(tp.in.params.data, 4, 0); /* reserved */ + + tp.in.data = *blob; + + return smb_raw_trans2_send(tree, &tp); +} + +/**************************************************************************** + Very raw set path info - takes data blob +****************************************************************************/ +static struct smbcli_request *smb_raw_setpathinfo_blob_send(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + const char *fname, + uint16_t info_level, + DATA_BLOB *blob) +{ + struct smb_trans2 tp; + uint16_t setup = TRANSACT2_SETPATHINFO; + + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 2; + tp.in.max_data = 0; + tp.in.setup = &setup; + + tp.in.params = data_blob_talloc(mem_ctx, NULL, 6); + if (!tp.in.params.data) { + return NULL; + } + SSVAL(tp.in.params.data, 0, info_level); + SIVAL(tp.in.params.data, 2, 0); + smbcli_blob_append_string(tree->session, mem_ctx, + &tp.in.params, + fname, STR_TERMINATE); + + tp.in.data = *blob; + + return smb_raw_trans2_send(tree, &tp); +} + +/**************************************************************************** + Handle setattr (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_setattr_send(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBsetatr, 8, 0); + if (!req) return NULL; + + SSVAL(req->out.vwv, VWV(0), parms->setattr.in.attrib); + raw_push_dos_date3(tree->session->transport, + req->out.vwv, VWV(1), parms->setattr.in.write_time); + memset(req->out.vwv + VWV(3), 0, 10); /* reserved */ + smbcli_req_append_ascii4(req, parms->setattr.in.file.path, STR_TERMINATE); + smbcli_req_append_ascii4(req, "", STR_TERMINATE); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Handle setattrE. (async send) +****************************************************************************/ +static struct smbcli_request *smb_raw_setattrE_send(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + struct smbcli_request *req; + + req = smbcli_request_setup(tree, SMBsetattrE, 7, 0); + if (!req) return NULL; + + SSVAL(req->out.vwv, VWV(0), parms->setattre.in.file.fnum); + raw_push_dos_date2(tree->session->transport, + req->out.vwv, VWV(1), parms->setattre.in.create_time); + raw_push_dos_date2(tree->session->transport, + req->out.vwv, VWV(3), parms->setattre.in.access_time); + raw_push_dos_date2(tree->session->transport, + req->out.vwv, VWV(5), parms->setattre.in.write_time); + + if (!smbcli_request_send(req)) { + smbcli_request_destroy(req); + return NULL; + } + + return req; +} + +/**************************************************************************** + Set file info (async send) +****************************************************************************/ +struct smbcli_request *smb_raw_setfileinfo_send(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + DATA_BLOB blob; + TALLOC_CTX *mem_ctx; + struct smbcli_request *req; + + if (parms->generic.level == RAW_SFILEINFO_SETATTRE) { + return smb_raw_setattrE_send(tree, parms); + } + if (parms->generic.level == RAW_SFILEINFO_SEC_DESC) { + return smb_raw_set_secdesc_send(tree, parms); + } + if (parms->generic.level >= RAW_SFILEINFO_GENERIC) { + return NULL; + } + + mem_ctx = talloc_init("setpathinfo"); + if (!mem_ctx) return NULL; + + if (!smb_raw_setinfo_backend(tree, mem_ctx, parms, &blob)) { + talloc_free(mem_ctx); + return NULL; + } + + /* send request and process the output */ + req = smb_raw_setfileinfo_blob_send(tree, + mem_ctx, + parms->generic.in.file.fnum, + parms->generic.level, + &blob); + + talloc_free(mem_ctx); + return req; +} + +/**************************************************************************** + Set file info (async send) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_setfileinfo(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + struct smbcli_request *req = smb_raw_setfileinfo_send(tree, parms); + return smbcli_request_simple_recv(req); +} + + +/**************************************************************************** + Set path info (async send) +****************************************************************************/ +_PUBLIC_ struct smbcli_request *smb_raw_setpathinfo_send(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + DATA_BLOB blob; + TALLOC_CTX *mem_ctx; + struct smbcli_request *req; + + if (parms->generic.level == RAW_SFILEINFO_SETATTR) { + return smb_raw_setattr_send(tree, parms); + } + if (parms->generic.level >= RAW_SFILEINFO_GENERIC) { + return NULL; + } + + mem_ctx = talloc_init("setpathinfo"); + if (!mem_ctx) return NULL; + + if (!smb_raw_setinfo_backend(tree, mem_ctx, parms, &blob)) { + talloc_free(mem_ctx); + return NULL; + } + + /* send request and process the output */ + req = smb_raw_setpathinfo_blob_send(tree, + mem_ctx, + parms->generic.in.file.path, + parms->generic.level, + &blob); + + talloc_free(mem_ctx); + return req; +} + +/**************************************************************************** + Set path info (sync interface) +****************************************************************************/ +_PUBLIC_ NTSTATUS smb_raw_setpathinfo(struct smbcli_tree *tree, + union smb_setfileinfo *parms) +{ + struct smbcli_request *req = smb_raw_setpathinfo_send(tree, parms); + return smbcli_request_simple_recv(req); +} diff --git a/source4/libcli/raw/rawshadow.c b/source4/libcli/raw/rawshadow.c new file mode 100644 index 0000000..7e48f26 --- /dev/null +++ b/source4/libcli/raw/rawshadow.c @@ -0,0 +1,82 @@ +/* + Unix SMB/CIFS implementation. + + shadow copy file operations + + Copyright (C) Andrew Tridgell 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "../libcli/smb/smb_constants.h" + +/* + get shadow volume data +*/ +_PUBLIC_ NTSTATUS smb_raw_shadow_data(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, struct smb_shadow_copy *info) +{ + union smb_ioctl nt; + NTSTATUS status; + DATA_BLOB blob; + uint32_t dlength; + int i; + uint32_t ofs; + + nt.ntioctl.level = RAW_IOCTL_NTIOCTL; + nt.ntioctl.in.function = FSCTL_GET_SHADOW_COPY_DATA; + nt.ntioctl.in.file.fnum = info->in.file.fnum; + nt.ntioctl.in.fsctl = true; + nt.ntioctl.in.filter = 0; + nt.ntioctl.in.max_data = info->in.max_data; + nt.ntioctl.in.blob = data_blob(NULL, 0); + + status = smb_raw_ioctl(tree, mem_ctx, &nt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + blob = nt.ntioctl.out.blob; + + if (blob.length < 12) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + info->out.num_volumes = IVAL(blob.data, 0); + info->out.num_names = IVAL(blob.data, 4); + dlength = IVAL(blob.data, 8); + if (dlength > blob.length - 12) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + info->out.names = talloc_array(mem_ctx, const char *, info->out.num_names); + NT_STATUS_HAVE_NO_MEMORY(info->out.names); + + ofs = 12; + for (i=0;i<info->out.num_names;i++) { + size_t len; + len = smbcli_blob_pull_ucs2(info->out.names, + &blob, &info->out.names[i], + blob.data+ofs, -1, STR_TERMINATE); + if (len == 0) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + ofs += len; + } + + return status; +} diff --git a/source4/libcli/raw/rawtrans.c b/source4/libcli/raw/rawtrans.c new file mode 100644 index 0000000..1a1c836 --- /dev/null +++ b/source4/libcli/raw/rawtrans.c @@ -0,0 +1,446 @@ +/* + Unix SMB/CIFS implementation. + raw trans/trans2/nttrans operations + + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include <tevent.h> +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "../libcli/smb/smbXcli_base.h" + +static void smb_raw_trans_backend_done(struct tevent_req *subreq); + +static struct smbcli_request *smb_raw_trans_backend_send(struct smbcli_tree *tree, + struct smb_trans2 *parms, + uint8_t command) +{ + struct smbcli_request *req; + uint8_t additional_flags; + uint8_t clear_flags; + uint16_t additional_flags2; + uint16_t clear_flags2; + uint32_t pid; + struct smbXcli_tcon *tcon = NULL; + struct smbXcli_session *session = NULL; + const char *pipe_name = NULL; + uint8_t s; + uint32_t timeout_msec; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, command, parms->in.setup_count, tmp); + if (req == NULL) { + return NULL; + } + + additional_flags = CVAL(req->out.hdr, HDR_FLG); + additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); + pid = SVAL(req->out.hdr, HDR_PID); + pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; + + if (req->session) { + session = req->session->smbXcli; + } + + if (req->tree) { + tcon = req->tree->smbXcli; + } + + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; + + timeout_msec = req->transport->options.request_timeout * 1000; + + for (s=0; s < parms->in.setup_count; s++) { + SSVAL(req->out.vwv, VWV(s), parms->in.setup[s]); + } + + if (parms->in.params.length > 0) { + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + } + if (parms->in.data.length > 0) { + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); + } + + if (command == SMBtrans && parms->in.trans_name) { + pipe_name = parms->in.trans_name; + } + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + command, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, + tcon, + session, + pipe_name, + 0xFFFF, /* fid */ + 0, /* function */ + parms->in.flags, + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { + talloc_free(req); + return NULL; + } + tevent_req_set_callback(req->subreqs[0], + smb_raw_trans_backend_done, + req); + + return req; +} + +static void smb_raw_trans_backend_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t s; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + req->trans2.out.setup_count = num_setup; + req->trans2.out.setup = talloc_array(req, uint16_t, num_setup); + if (req->trans2.out.setup == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_NO_MEMORY; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + for (s = 0; s < num_setup; s++) { + req->trans2.out.setup[s] = SVAL(setup, VWV(s)); + } + + req->trans2.out.params.data = param; + req->trans2.out.params.length = num_param; + + req->trans2.out.data.data = data; + req->trans2.out.data.length = num_data; + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } +} + +static NTSTATUS smb_raw_trans_backend_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + parms->out = req->trans2.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); + +failed: + return smbcli_request_destroy(req); +} + +_PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_send(tree, parms, SMBtrans); +} + +_PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_recv(req, mem_ctx, parms); +} + +_PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + struct smbcli_request *req; + req = smb_raw_trans_send(tree, parms); + if (!req) return NT_STATUS_UNSUCCESSFUL; + return smb_raw_trans_recv(req, mem_ctx, parms); +} + +struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_send(tree, parms, SMBtrans2); +} + +NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_recv(req, mem_ctx, parms); +} + +NTSTATUS smb_raw_trans2(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + struct smbcli_request *req; + req = smb_raw_trans2_send(tree, parms); + if (!req) return NT_STATUS_UNSUCCESSFUL; + return smb_raw_trans2_recv(req, mem_ctx, parms); +} + +static void smb_raw_nttrans_done(struct tevent_req *subreq); + +struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree, + struct smb_nttrans *parms) +{ + struct smbcli_request *req; + uint8_t additional_flags; + uint8_t clear_flags; + uint16_t additional_flags2; + uint16_t clear_flags2; + uint32_t pid; + struct smbXcli_tcon *tcon = NULL; + struct smbXcli_session *session = NULL; + uint32_t timeout_msec; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, SMBnttrans, parms->in.setup_count, tmp); + if (req == NULL) { + return NULL; + } + + additional_flags = CVAL(req->out.hdr, HDR_FLG); + additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); + pid = SVAL(req->out.hdr, HDR_PID); + pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; + + if (req->session) { + session = req->session->smbXcli; + } + + if (req->tree) { + tcon = req->tree->smbXcli; + } + + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; + + timeout_msec = req->transport->options.request_timeout * 1000; + + if (parms->in.setup_count > 0) { + memcpy( + req->out.vwv, parms->in.setup, parms->in.setup_count * 2); + } + + if (parms->in.params.length > 0) { + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + } + if (parms->in.data.length > 0) { + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); + } + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + SMBnttrans, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, + tcon, + session, + NULL, /* pipe_name */ + 0xFFFF, /* fid */ + parms->in.function, + 0, /* flags */ + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { + talloc_free(req); + return NULL; + } + tevent_req_set_callback(req->subreqs[0], + smb_raw_nttrans_done, + req); + + return req; +} + +static void smb_raw_nttrans_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + req->nttrans.out.setup_count = num_setup; + req->nttrans.out.setup = (uint8_t *)setup; + + req->nttrans.out.params.data = param; + req->nttrans.out.params.length = num_param; + + req->nttrans.out.data.data = data; + req->nttrans.out.data.length = num_data; + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } +} + +NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_nttrans *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + parms->out = req->nttrans.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + receive a SMB nttrans response allocating the necessary memory + ****************************************************************************/ +NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_nttrans *parms) +{ + struct smbcli_request *req; + + req = smb_raw_nttrans_send(tree, parms); + if (!req) { + return NT_STATUS_UNSUCCESSFUL; + } + + return smb_raw_nttrans_recv(req, mem_ctx, parms); +} diff --git a/source4/libcli/raw/request.h b/source4/libcli/raw/request.h new file mode 100644 index 0000000..dd38b31 --- /dev/null +++ b/source4/libcli/raw/request.h @@ -0,0 +1,78 @@ +#ifndef _REQUEST_H +#define _REQUEST_H +/* + Unix SMB/CIFS implementation. + SMB parameters and setup + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "libcli/raw/signing.h" + +#define BUFINFO_FLAG_UNICODE 0x0001 +#define BUFINFO_FLAG_SMB2 0x0002 + +/* + buffer limit structure used by both SMB and SMB2 + */ +struct request_bufinfo { + TALLOC_CTX *mem_ctx; + uint32_t flags; + const uint8_t *align_base; + const uint8_t *data; + size_t data_size; +}; + +/* + Shared state structure between client and server, representing the basic packet. +*/ + +struct smb_request_buffer { + /* the raw SMB buffer, including the 4 byte length header */ + uint8_t *buffer; + + /* the size of the raw buffer, including 4 byte header */ + size_t size; + + /* how much has been allocated - on reply the buffer is over-allocated to + prevent too many realloc() calls + */ + size_t allocated; + + /* the start of the SMB header - this is always buffer+4 */ + uint8_t *hdr; + + /* the command words and command word count. vwv points + into the raw buffer */ + uint8_t *vwv; + unsigned int wct; + + /* the data buffer and size. data points into the raw buffer */ + uint8_t *data; + size_t data_size; + + /* ptr is used as a moving pointer into the data area + * of the packet. The reason its here and not a local + * variable in each function is that when a realloc of + * a send packet is done we need to move this + * pointer */ + uint8_t *ptr; + + /* this is used to range check and align strings and buffers */ + struct request_bufinfo bufinfo; +}; + +#endif diff --git a/source4/libcli/raw/signing.h b/source4/libcli/raw/signing.h new file mode 100644 index 0000000..933db4d --- /dev/null +++ b/source4/libcli/raw/signing.h @@ -0,0 +1,39 @@ +#ifndef _SIGNING_H +#define _SIGNING_H +/* + Unix SMB/CIFS implementation. + SMB Signing + + Andrew Bartlett <abartlet@samba.org> 2003-2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +enum smb_signing_engine_state { + SMB_SIGNING_ENGINE_OFF, + SMB_SIGNING_ENGINE_BSRSPYL, + SMB_SIGNING_ENGINE_ON +}; + +struct smb_signing_context { + enum smb_signing_engine_state signing_state; + DATA_BLOB mac_key; + uint32_t next_seq_num; + bool allow_smb_signing; + bool doing_signing; + bool mandatory_signing; + bool seen_valid; /* Have I ever seen a validly signed packet? */ +}; + +#endif diff --git a/source4/libcli/raw/smb.h b/source4/libcli/raw/smb.h new file mode 100644 index 0000000..780260e --- /dev/null +++ b/source4/libcli/raw/smb.h @@ -0,0 +1,322 @@ +/* + Unix SMB/CIFS implementation. + SMB parameters and setup, plus a whole lot more. + + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) John H Terpstra 1996-2002 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Copyright (C) Paul Ashton 1998-2000 + Copyright (C) Simo Sorce 2001-2002 + Copyright (C) Martin Pool 2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _RAW_SMB_H +#define _RAW_SMB_H + +/* deny modes */ +#define DENY_DOS 0 +#define DENY_ALL 1 +#define DENY_WRITE 2 +#define DENY_READ 3 +#define DENY_NONE 4 +#define DENY_FCB 7 + +/* open modes */ +#define DOS_OPEN_RDONLY 0 +#define DOS_OPEN_WRONLY 1 +#define DOS_OPEN_RDWR 2 +#define DOS_OPEN_FCB 0xF + + +/**********************************/ +/* SMBopen field definitions */ +#define OPEN_FLAGS_DENY_MASK 0x70 +#define OPEN_FLAGS_DENY_DOS 0x00 +#define OPEN_FLAGS_DENY_ALL 0x10 +#define OPEN_FLAGS_DENY_WRITE 0x20 +#define OPEN_FLAGS_DENY_READ 0x30 +#define OPEN_FLAGS_DENY_NONE 0x40 + +#define OPEN_FLAGS_MODE_MASK 0x0F +#define OPEN_FLAGS_OPEN_READ 0 +#define OPEN_FLAGS_OPEN_WRITE 1 +#define OPEN_FLAGS_OPEN_RDWR 2 +#define OPEN_FLAGS_FCB 0xFF + + +/**********************************/ +/* SMBopenX field definitions */ + +/* OpenX Flags field. */ +#define OPENX_FLAGS_ADDITIONAL_INFO 0x01 +#define OPENX_FLAGS_REQUEST_OPLOCK 0x02 +#define OPENX_FLAGS_REQUEST_BATCH_OPLOCK 0x04 +#define OPENX_FLAGS_EA_LEN 0x08 +#define OPENX_FLAGS_EXTENDED_RETURN 0x10 + +/* desired access (open_mode), split info 4 4-bit nibbles */ +#define OPENX_MODE_ACCESS_MASK 0x000F +#define OPENX_MODE_ACCESS_READ 0x0000 +#define OPENX_MODE_ACCESS_WRITE 0x0001 +#define OPENX_MODE_ACCESS_RDWR 0x0002 +#define OPENX_MODE_ACCESS_EXEC 0x0003 +#define OPENX_MODE_ACCESS_FCB 0x000F + +#define OPENX_MODE_DENY_SHIFT 4 +#define OPENX_MODE_DENY_MASK (0xF << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_DOS (DENY_DOS << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_ALL (DENY_ALL << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_WRITE (DENY_WRITE << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_READ (DENY_READ << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_NONE (DENY_NONE << OPENX_MODE_DENY_SHIFT) +#define OPENX_MODE_DENY_FCB (0xF << OPENX_MODE_DENY_SHIFT) + +#define OPENX_MODE_LOCALITY_MASK 0x0F00 /* what does this do? */ + +#define OPENX_MODE_NO_CACHE 0x1000 +#define OPENX_MODE_WRITE_THRU 0x4000 + +/* open function values */ +#define OPENX_OPEN_FUNC_MASK 0x3 +#define OPENX_OPEN_FUNC_FAIL 0x0 +#define OPENX_OPEN_FUNC_OPEN 0x1 +#define OPENX_OPEN_FUNC_TRUNC 0x2 + +/* The above can be OR'ed with... */ +#define OPENX_OPEN_FUNC_CREATE 0x10 + +/* openx action in reply */ +#define OPENX_ACTION_EXISTED 1 +#define OPENX_ACTION_CREATED 2 +#define OPENX_ACTION_TRUNCATED 3 + + +/**********************************/ +/* SMBntcreateX field definitions */ + +/* ntcreatex flags field. */ +#define NTCREATEX_FLAGS_REQUEST_OPLOCK 0x02 +#define NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK 0x04 +#define NTCREATEX_FLAGS_OPEN_DIRECTORY 0x08 /* TODO: opens parent? we need + a test suite for this */ +#define NTCREATEX_FLAGS_EXTENDED 0x10 + +/* the ntcreatex access_mask field + this is split into 4 pieces + AAAABBBBCCCCCCCCDDDDDDDDDDDDDDDD + A -> GENERIC_RIGHT_* + B -> SEC_RIGHT_* + C -> STD_RIGHT_* + D -> SA_RIGHT_* + + which set of SA_RIGHT_* bits is applicable depends on the type + of object. +*/ + + + +/* ntcreatex share_access field */ +#define NTCREATEX_SHARE_ACCESS_NONE 0 +#define NTCREATEX_SHARE_ACCESS_READ 1 +#define NTCREATEX_SHARE_ACCESS_WRITE 2 +#define NTCREATEX_SHARE_ACCESS_DELETE 4 +#define NTCREATEX_SHARE_ACCESS_MASK 7 + +/* ntcreatex open_disposition field */ +#define NTCREATEX_DISP_SUPERSEDE 0 /* supersede existing file (if it exists) */ +#define NTCREATEX_DISP_OPEN 1 /* if file exists open it, else fail */ +#define NTCREATEX_DISP_CREATE 2 /* if file exists fail, else create it */ +#define NTCREATEX_DISP_OPEN_IF 3 /* if file exists open it, else create it */ +#define NTCREATEX_DISP_OVERWRITE 4 /* if exists overwrite, else fail */ +#define NTCREATEX_DISP_OVERWRITE_IF 5 /* if exists overwrite, else create */ + +/* ntcreatex create_options field */ +#define NTCREATEX_OPTIONS_DIRECTORY 0x0001 +#define NTCREATEX_OPTIONS_WRITE_THROUGH 0x0002 +#define NTCREATEX_OPTIONS_SEQUENTIAL_ONLY 0x0004 +#define NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING 0x0008 +#define NTCREATEX_OPTIONS_SYNC_ALERT 0x0010 +#define NTCREATEX_OPTIONS_ASYNC_ALERT 0x0020 +#define NTCREATEX_OPTIONS_NON_DIRECTORY_FILE 0x0040 +#define NTCREATEX_OPTIONS_TREE_CONNECTION 0x0080 +#define NTCREATEX_OPTIONS_COMPLETE_IF_OPLOCKED 0x0100 +#define NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE 0x0200 +#define NTCREATEX_OPTIONS_OPEN_FOR_RECOVERY 0x0400 +#define NTCREATEX_OPTIONS_RANDOM_ACCESS 0x0800 +#define NTCREATEX_OPTIONS_DELETE_ON_CLOSE 0x1000 +#define NTCREATEX_OPTIONS_OPEN_BY_FILE_ID 0x2000 +#define NTCREATEX_OPTIONS_BACKUP_INTENT 0x4000 +#define NTCREATEX_OPTIONS_NO_COMPRESSION 0x8000 +/* Must be ignored by the server, per MS-SMB 2.2.8 */ +#define NTCREATEX_OPTIONS_OPFILTER 0x00100000 +#define NTCREATEX_OPTIONS_REPARSE_POINT 0x00200000 +/* Don't pull this file off tape in a HSM system */ +#define NTCREATEX_OPTIONS_NO_RECALL 0x00400000 +/* Must be ignored by the server, per MS-SMB 2.2.8 */ +#define NTCREATEX_OPTIONS_FREE_SPACE_QUERY 0x00800000 + +#define NTCREATEX_OPTIONS_MUST_IGNORE_MASK (NTCREATEX_OPTIONS_TREE_CONNECTION | \ + NTCREATEX_OPTIONS_OPEN_FOR_RECOVERY | \ + NTCREATEX_OPTIONS_FREE_SPACE_QUERY | \ + 0x000F0000) + +#define NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK (NTCREATEX_OPTIONS_OPEN_BY_FILE_ID) + +#define NTCREATEX_OPTIONS_INVALID_PARAM_MASK (NTCREATEX_OPTIONS_OPFILTER | \ + NTCREATEX_OPTIONS_SYNC_ALERT | \ + NTCREATEX_OPTIONS_ASYNC_ALERT | \ + 0xFF000000) + +/* + * private_flags field in ntcreatex + * This values have different meaning for some ntvfs backends. + */ +#define NTCREATEX_FLAG_DENY_DOS 0x0001 +#define NTCREATEX_FLAG_DENY_FCB 0x0002 + + +/* ntcreatex impersonation field */ +#define NTCREATEX_IMPERSONATION_ANONYMOUS 0 +#define NTCREATEX_IMPERSONATION_IDENTIFICATION 1 +#define NTCREATEX_IMPERSONATION_IMPERSONATION 2 +#define NTCREATEX_IMPERSONATION_DELEGATION 3 + +/* ntcreatex security flags bit field */ +#define NTCREATEX_SECURITY_DYNAMIC 1 +#define NTCREATEX_SECURITY_ALL 2 + +/* ntcreatex create_action in reply */ +#define NTCREATEX_ACTION_EXISTED 1 +#define NTCREATEX_ACTION_CREATED 2 +#define NTCREATEX_ACTION_TRUNCATED 3 +/* the value 5 can also be returned when you try to create a directory with + incorrect parameters - what does it mean? maybe created temporary file? */ +#define NTCREATEX_ACTION_UNKNOWN 5 + +/* Named pipe write mode flags. Used in writeX calls. */ +#define PIPE_RAW_MODE 0x4 +#define PIPE_START_MESSAGE 0x8 + +/* the desired access to use when opening a pipe */ +#define DESIRED_ACCESS_PIPE 0x2019f + +/* Flag for NT transact rename call. */ +#define RENAME_REPLACE_IF_EXISTS 1 + +/* flags for SMBntrename call */ +#define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102 /* ???? */ +#define RENAME_FLAG_HARD_LINK 0x103 +#define RENAME_FLAG_RENAME 0x104 +#define RENAME_FLAG_COPY 0x105 + +/* ChangeNotify flags. */ +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_EA 0x00000080 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 + +#define FILE_NOTIFY_CHANGE_NAME \ + (FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME) + +#define FILE_NOTIFY_CHANGE_ALL \ + (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | \ + FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | \ + FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | \ + FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA | \ + FILE_NOTIFY_CHANGE_SECURITY | FILE_NOTIFY_CHANGE_STREAM_NAME | \ + FILE_NOTIFY_CHANGE_STREAM_SIZE | FILE_NOTIFY_CHANGE_STREAM_WRITE) + +/* change notify action results */ +#define NOTIFY_ACTION_ADDED 1 +#define NOTIFY_ACTION_REMOVED 2 +#define NOTIFY_ACTION_MODIFIED 3 +#define NOTIFY_ACTION_OLD_NAME 4 +#define NOTIFY_ACTION_NEW_NAME 5 +#define NOTIFY_ACTION_ADDED_STREAM 6 +#define NOTIFY_ACTION_REMOVED_STREAM 7 +#define NOTIFY_ACTION_MODIFIED_STREAM 8 + +/* seek modes for smb_seek */ +#define SEEK_MODE_START 0 +#define SEEK_MODE_CURRENT 1 +#define SEEK_MODE_END 2 + +/* where to find the base of the SMB packet proper */ +/* REWRITE TODO: smb_base needs to be removed */ +#define smb_base(buf) (((const char *)(buf))+4) + +/* we don't allow server strings to be longer than 48 characters as + otherwise NT will not honour the announce packets */ +#define MAX_SERVER_STRING_LENGTH 48 + +/* This was set by JHT in liaison with Jeremy Allison early 1997 + * History: + * Version 4.0 - never made public + * Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9 + * - Reappeared in 1.9.16p11 with fixed smbd services + * Version 4.20 - To indicate that nmbd and browsing now works better + * Version 4.50 - Set at release of samba-2.2.0 by JHT + * + * Note: In the presence of NT4.X do not set above 4.9 + * Setting this above 4.9 can have undesired side-effects. + * This may change again in Samba-3.0 after further testing. JHT + */ + +#define DEFAULT_MAJOR_VERSION 0x04 +#define DEFAULT_MINOR_VERSION 0x09 + +/* Browser Election Values */ +#define BROWSER_ELECTION_VERSION 0x010f +#define BROWSER_CONSTANT 0xaa55 + +/* + * Global value meaning that the smb_uid field should be + * ingored (in share level security and protocol level == CORE) + */ + +#define UID_FIELD_INVALID 0 + +/* + filesystem attribute bits +*/ +#define FS_ATTR_CASE_SENSITIVE_SEARCH 0x00000001 +#define FS_ATTR_CASE_PRESERVED_NAMES 0x00000002 +#define FS_ATTR_UNICODE_ON_DISK 0x00000004 +#define FS_ATTR_PERSISTANT_ACLS 0x00000008 +#define FS_ATTR_COMPRESSION 0x00000010 +#define FS_ATTR_QUOTAS 0x00000020 +#define FS_ATTR_SPARSE_FILES 0x00000040 +#define FS_ATTR_REPARSE_POINTS 0x00000080 +#define FS_ATTR_REMOTE_STORAGE 0x00000100 +#define FS_ATTR_LFN_SUPPORT 0x00004000 +#define FS_ATTR_IS_COMPRESSED 0x00008000 +#define FS_ATTR_OBJECT_IDS 0x00010000 +#define FS_ATTR_ENCRYPTION 0x00020000 +#define FS_ATTR_NAMED_STREAMS 0x00040000 + +#include "source4/libcli/raw/trans2.h" +#include "libcli/raw/interfaces.h" +#include "libcli/smb/smb_common.h" + +#endif /* _RAW_SMB_H */ diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c new file mode 100644 index 0000000..6747fc3 --- /dev/null +++ b/source4/libcli/raw/smb_signing.c @@ -0,0 +1,276 @@ +/* + Unix SMB/CIFS implementation. + SMB Signing Code + Copyright (C) Jeremy Allison 2002. + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 + Copyright (C) James J Myers <myersjj@samba.org> 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "../lib/crypto/crypto.h" + +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> + +/*********************************************************** + SMB signing - Common code before we set a new signing implementation +************************************************************/ +bool set_smb_signing_common(struct smb_signing_context *sign_info) +{ + if (sign_info->doing_signing) { + DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n")); + return false; + } + + if (!sign_info->allow_smb_signing) { + DEBUG(5, ("SMB Signing has been locally disabled\n")); + return false; + } + + return true; +} + +void mark_packet_signed(struct smb_request_buffer *out) +{ + uint16_t flags2; + flags2 = SVAL(out->hdr, HDR_FLG2); + flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; + SSVAL(out->hdr, HDR_FLG2, flags2); +} + +bool signing_good(struct smb_signing_context *sign_info, + unsigned int seq, bool good) +{ + if (good) { + if (!sign_info->doing_signing) { + DEBUG(5, ("Seen valid packet, so turning signing on\n")); + sign_info->doing_signing = true; + } + if (!sign_info->seen_valid) { + DEBUG(5, ("Seen valid packet, so marking signing as 'seen valid'\n")); + sign_info->seen_valid = true; + } + } else { + if (!sign_info->seen_valid) { + /* If we have never seen a good packet, just turn it off */ + DEBUG(5, ("signing_good: signing negotiated but not required and peer\n" + "isn't sending correct signatures. Turning off.\n")); + smbcli_set_signing_off(sign_info); + return true; + } else { + /* bad packet after signing started - fail and disconnect. */ + DEBUG(0, ("signing_good: BAD SIG: seq %u\n", seq)); + return false; + } + } + return true; +} + +void sign_outgoing_message(struct smb_request_buffer *out, DATA_BLOB *mac_key, unsigned int seq_num) +{ + uint8_t calc_md5_mac[16]; + gnutls_hash_hd_t hash_hnd = NULL; + int rc; + + /* + * Firstly put the sequence number into the first 4 bytes. + * and zero out the next 4 bytes. + */ + SIVAL(out->hdr, HDR_SS_FIELD, seq_num); + SIVAL(out->hdr, HDR_SS_FIELD + 4, 0); + + /* mark the packet as signed - BEFORE we sign it...*/ + mark_packet_signed(out); + + /* Calculate the 16 byte MAC and place first 8 bytes into the field. */ + rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5); + if (rc < 0) { + return; + } + + rc = gnutls_hash(hash_hnd, mac_key->data, mac_key->length); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + return; + } + rc = gnutls_hash(hash_hnd, + out->buffer + NBT_HDR_SIZE, + out->size - NBT_HDR_SIZE); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + return; + } + gnutls_hash_deinit(hash_hnd, calc_md5_mac); + + memcpy(&out->hdr[HDR_SS_FIELD], calc_md5_mac, 8); + + DEBUG(5, ("sign_outgoing_message: SENT SIG (seq: %d): sent SMB signature of\n", + seq_num)); + dump_data(5, calc_md5_mac, 8); + ZERO_ARRAY(calc_md5_mac); +/* req->out.hdr[HDR_SS_FIELD+2]=0; + Uncomment this to test if the remote server actually verifies signitures...*/ +} + +bool check_signed_incoming_message(struct smb_request_buffer *in, DATA_BLOB *mac_key, unsigned int seq_num) +{ + bool ok = false; + uint8_t calc_md5_mac[16]; + uint8_t *server_sent_mac; + uint8_t sequence_buf[8]; + gnutls_hash_hd_t hash_hnd; + const size_t offset_end_of_sig = (HDR_SS_FIELD + 8); + int rc; + int i; + const int sign_range = 0; + + /* room enough for the signature? */ + if (in->size < NBT_HDR_SIZE + HDR_SS_FIELD + 8) { + return false; + } + + if (!mac_key->length) { + /* NO key yet */ + return false; + } + + /* its quite bogus to be guessing sequence numbers, but very useful + when debugging signing implementations */ + for (i = 0-sign_range; i <= 0+sign_range; i++) { + /* + * Firstly put the sequence number into the first 4 bytes. + * and zero out the next 4 bytes. + */ + SIVAL(sequence_buf, 0, seq_num + i); + SIVAL(sequence_buf, 4, 0); + + /* get a copy of the server-sent mac */ + server_sent_mac = &in->hdr[HDR_SS_FIELD]; + + /* Calculate the 16 byte MAC and place first 8 bytes into the field. */ + rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5); + if (rc < 0) { + ok = false; + goto out; + } + + rc = gnutls_hash(hash_hnd, mac_key->data, mac_key->length); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + ok = false; + goto out; + } + rc = gnutls_hash(hash_hnd, in->hdr, HDR_SS_FIELD); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + ok = false; + goto out; + } + rc = gnutls_hash(hash_hnd, sequence_buf, sizeof(sequence_buf)); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + ok = false; + goto out; + } + rc = gnutls_hash(hash_hnd, + in->hdr + offset_end_of_sig, + in->size - NBT_HDR_SIZE - (offset_end_of_sig)); + if (rc < 0) { + gnutls_hash_deinit(hash_hnd, NULL); + ok = false; + goto out; + } + + gnutls_hash_deinit(hash_hnd, calc_md5_mac); + + ok = mem_equal_const_time(server_sent_mac, calc_md5_mac, 8); + + if (i == 0) { + if (!ok) { + DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", seq_num + i)); + dump_data(5, calc_md5_mac, 8); + + DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num + i)); + dump_data(5, server_sent_mac, 8); + } else { + DEBUG(15, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num + i)); + dump_data(5, server_sent_mac, 8); + } + } + ZERO_ARRAY(calc_md5_mac); + + if (ok) break; + } + + if (ok && i != 0) { + DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num)); + } + +out: + return ok; +} + +/** + SMB signing - NULL implementation + + @note Used as an initialisation only - it will not correctly + shut down a real signing mechanism +*/ +bool smbcli_set_signing_off(struct smb_signing_context *sign_info) +{ + DEBUG(5, ("Shutdown SMB signing\n")); + sign_info->doing_signing = false; + data_blob_free(&sign_info->mac_key); + sign_info->signing_state = SMB_SIGNING_ENGINE_OFF; + return true; +} + +/*********************************************************** + SMB signing - Simple implementation - setup the MAC key. +************************************************************/ +bool smbcli_simple_set_signing(TALLOC_CTX *mem_ctx, + struct smb_signing_context *sign_info, + const DATA_BLOB *user_session_key, + const DATA_BLOB *response) +{ + if (sign_info->mandatory_signing) { + DEBUG(5, ("Mandatory SMB signing enabled!\n")); + } + + DEBUG(5, ("SMB signing enabled!\n")); + + if (response && response->length) { + sign_info->mac_key = data_blob_talloc(mem_ctx, NULL, response->length + user_session_key->length); + } else { + sign_info->mac_key = data_blob_talloc(mem_ctx, NULL, user_session_key->length); + } + + memcpy(&sign_info->mac_key.data[0], user_session_key->data, user_session_key->length); + + if (response && response->length) { + memcpy(&sign_info->mac_key.data[user_session_key->length],response->data, response->length); + } + + dump_data_pw("Started Signing with key:\n", sign_info->mac_key.data, sign_info->mac_key.length); + + sign_info->signing_state = SMB_SIGNING_ENGINE_ON; + sign_info->next_seq_num = 2; + + return true; +} + diff --git a/source4/libcli/raw/trans2.h b/source4/libcli/raw/trans2.h new file mode 100644 index 0000000..f93b1f1 --- /dev/null +++ b/source4/libcli/raw/trans2.h @@ -0,0 +1,309 @@ +/* + Unix SMB/CIFS implementation. + SMB transaction2 handling + Copyright (C) Jeremy Allison 1994-2002. + Copyright (C) Andrew Tridgell 1995-2003. + Copyright (C) James Peach 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _TRANS2_H_ +#define _TRANS2_H_ + + +/* trans2 Query FS info levels */ +/* +w2k3 TRANS2ALIASES: +Checking for QFSINFO aliases + Found level 1 (0x001) of size 18 (0x12) + Found level 2 (0x002) of size 12 (0x0c) + Found level 258 (0x102) of size 26 (0x1a) + Found level 259 (0x103) of size 24 (0x18) + Found level 260 (0x104) of size 8 (0x08) + Found level 261 (0x105) of size 20 (0x14) + Found level 1001 (0x3e9) of size 26 (0x1a) + Found level 1003 (0x3eb) of size 24 (0x18) + Found level 1004 (0x3ec) of size 8 (0x08) + Found level 1005 (0x3ed) of size 20 (0x14) + Found level 1006 (0x3ee) of size 48 (0x30) + Found level 1007 (0x3ef) of size 32 (0x20) + Found level 1008 (0x3f0) of size 64 (0x40) +Found 13 levels with success status + Level 261 (0x105) and level 1005 (0x3ed) are possible aliases + Level 260 (0x104) and level 1004 (0x3ec) are possible aliases + Level 259 (0x103) and level 1003 (0x3eb) are possible aliases + Level 258 (0x102) and level 1001 (0x3e9) are possible aliases +Found 4 aliased levels +*/ +#define SMB_QFS_ALLOCATION 1 +#define SMB_QFS_VOLUME 2 +#define SMB_QFS_VOLUME_INFO 0x102 +#define SMB_QFS_SIZE_INFO 0x103 +#define SMB_QFS_DEVICE_INFO 0x104 +#define SMB_QFS_ATTRIBUTE_INFO 0x105 +#define SMB_QFS_UNIX_INFO 0x200 +#define SMB_QFS_POSIX_INFO 0x201 +#define SMB_QFS_POSIX_WHOAMI 0x202 +#define SMB_QFS_VOLUME_INFORMATION 1001 +#define SMB_QFS_SIZE_INFORMATION 1003 +#define SMB_QFS_DEVICE_INFORMATION 1004 +#define SMB_QFS_ATTRIBUTE_INFORMATION 1005 +#define SMB_QFS_QUOTA_INFORMATION 1006 +#define SMB_QFS_FULL_SIZE_INFORMATION 1007 +#define SMB_QFS_OBJECTID_INFORMATION 1008 +#define SMB_QFS_SECTOR_SIZE_INFORMATION 1011 + + +/* trans2 qfileinfo/qpathinfo */ +/* w2k3 TRANS2ALIASES: +Checking for QPATHINFO aliases +setting up complex file \qpathinfo_aliases.txt + Found level 1 (0x001) of size 22 (0x16) + Found level 2 (0x002) of size 26 (0x1a) + Found level 4 (0x004) of size 41 (0x29) + Found level 6 (0x006) of size 0 (0x00) + Found level 257 (0x101) of size 40 (0x28) + Found level 258 (0x102) of size 24 (0x18) + Found level 259 (0x103) of size 4 (0x04) + Found level 260 (0x104) of size 48 (0x30) + Found level 263 (0x107) of size 126 (0x7e) + Found level 264 (0x108) of size 28 (0x1c) + Found level 265 (0x109) of size 38 (0x26) + Found level 267 (0x10b) of size 16 (0x10) + Found level 1004 (0x3ec) of size 40 (0x28) + Found level 1005 (0x3ed) of size 24 (0x18) + Found level 1006 (0x3ee) of size 8 (0x08) + Found level 1007 (0x3ef) of size 4 (0x04) + Found level 1008 (0x3f0) of size 4 (0x04) + Found level 1009 (0x3f1) of size 48 (0x30) + Found level 1014 (0x3f6) of size 8 (0x08) + Found level 1016 (0x3f8) of size 4 (0x04) + Found level 1017 (0x3f9) of size 4 (0x04) + Found level 1018 (0x3fa) of size 126 (0x7e) + Found level 1021 (0x3fd) of size 28 (0x1c) + Found level 1022 (0x3fe) of size 38 (0x26) + Found level 1028 (0x404) of size 16 (0x10) + Found level 1034 (0x40a) of size 56 (0x38) + Found level 1035 (0x40b) of size 8 (0x08) +Found 27 levels with success status + Level 267 (0x10b) and level 1028 (0x404) are possible aliases + Level 265 (0x109) and level 1022 (0x3fe) are possible aliases + Level 264 (0x108) and level 1021 (0x3fd) are possible aliases + Level 263 (0x107) and level 1018 (0x3fa) are possible aliases + Level 260 (0x104) and level 1009 (0x3f1) are possible aliases + Level 259 (0x103) and level 1007 (0x3ef) are possible aliases + Level 258 (0x102) and level 1005 (0x3ed) are possible aliases + Level 257 (0x101) and level 1004 (0x3ec) are possible aliases +Found 8 aliased levels +*/ +#define SMB_QFILEINFO_STANDARD 1 +#define SMB_QFILEINFO_EA_SIZE 2 +#define SMB_QFILEINFO_EA_LIST 3 +#define SMB_QFILEINFO_ALL_EAS 4 +#define SMB_QFILEINFO_IS_NAME_VALID 6 /* only for QPATHINFO */ +#define SMB_QFILEINFO_BASIC_INFO 0x101 +#define SMB_QFILEINFO_STANDARD_INFO 0x102 +#define SMB_QFILEINFO_EA_INFO 0x103 +#define SMB_QFILEINFO_NAME_INFO 0x104 +#define SMB_QFILEINFO_ALL_INFO 0x107 +#define SMB_QFILEINFO_ALT_NAME_INFO 0x108 +#define SMB_QFILEINFO_STREAM_INFO 0x109 +#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b +#define SMB_QFILEINFO_UNIX_BASIC 0x200 +#define SMB_QFILEINFO_UNIX_LINK 0x201 +#define SMB_QFILEINFO_UNIX_INFO2 0x20b +#define SMB_QFILEINFO_BASIC_INFORMATION 1004 +#define SMB_QFILEINFO_STANDARD_INFORMATION 1005 +#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006 +#define SMB_QFILEINFO_EA_INFORMATION 1007 +#define SMB_QFILEINFO_ACCESS_INFORMATION 1008 +#define SMB_QFILEINFO_NAME_INFORMATION 1009 +#define SMB_QFILEINFO_POSITION_INFORMATION 1014 +#define SMB_QFILEINFO_MODE_INFORMATION 1016 +#define SMB_QFILEINFO_ALIGNMENT_INFORMATION 1017 +#define SMB_QFILEINFO_ALL_INFORMATION 1018 +#define SMB_QFILEINFO_ALT_NAME_INFORMATION 1021 +#define SMB_QFILEINFO_STREAM_INFORMATION 1022 +#define SMB_QFILEINFO_COMPRESSION_INFORMATION 1028 +#define SMB_QFILEINFO_NETWORK_OPEN_INFORMATION 1034 +#define SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION 1035 +#define SMB_QFILEINFO_NORMALIZED_NAME_INFORMATION 1048 + + + +/* trans2 setfileinfo/setpathinfo levels */ +/* +w2k3 TRANS2ALIASES +Checking for SETFILEINFO aliases +setting up complex file \setfileinfo_aliases.txt + Found level 1 (0x001) of size 2 (0x02) + Found level 2 (0x002) of size 2 (0x02) + Found level 257 (0x101) of size 40 (0x28) + Found level 258 (0x102) of size 2 (0x02) + Found level 259 (0x103) of size 8 (0x08) + Found level 260 (0x104) of size 8 (0x08) + Found level 1004 (0x3ec) of size 40 (0x28) + Found level 1010 (0x3f2) of size 2 (0x02) + Found level 1013 (0x3f5) of size 2 (0x02) + Found level 1014 (0x3f6) of size 8 (0x08) + Found level 1016 (0x3f8) of size 4 (0x04) + Found level 1019 (0x3fb) of size 8 (0x08) + Found level 1020 (0x3fc) of size 8 (0x08) + Found level 1023 (0x3ff) of size 8 (0x08) + Found level 1025 (0x401) of size 16 (0x10) + Found level 1029 (0x405) of size 72 (0x48) + Found level 1032 (0x408) of size 56 (0x38) + Found level 1039 (0x40f) of size 8 (0x08) + Found level 1040 (0x410) of size 8 (0x08) +Found 19 valid levels + +Checking for SETPATHINFO aliases + Found level 1004 (0x3ec) of size 40 (0x28) + Found level 1010 (0x3f2) of size 2 (0x02) + Found level 1013 (0x3f5) of size 2 (0x02) + Found level 1014 (0x3f6) of size 8 (0x08) + Found level 1016 (0x3f8) of size 4 (0x04) + Found level 1019 (0x3fb) of size 8 (0x08) + Found level 1020 (0x3fc) of size 8 (0x08) + Found level 1023 (0x3ff) of size 8 (0x08) + Found level 1025 (0x401) of size 16 (0x10) + Found level 1029 (0x405) of size 72 (0x48) + Found level 1032 (0x408) of size 56 (0x38) + Found level 1039 (0x40f) of size 8 (0x08) + Found level 1040 (0x410) of size 8 (0x08) +Found 13 valid levels +*/ +#define SMB_SFILEINFO_STANDARD 1 +#define SMB_SFILEINFO_EA_SET 2 +#define SMB_SFILEINFO_BASIC_INFO 0x101 +#define SMB_SFILEINFO_DISPOSITION_INFO 0x102 +#define SMB_SFILEINFO_ALLOCATION_INFO 0x103 +#define SMB_SFILEINFO_END_OF_FILE_INFO 0x104 +#define SMB_SFILEINFO_UNIX_BASIC 0x200 +#define SMB_SFILEINFO_UNIX_LINK 0x201 +#define SMB_SPATHINFO_UNIX_HLINK 0x203 +#define SMB_SPATHINFO_POSIX_ACL 0x204 +#define SMB_SPATHINFO_XATTR 0x205 +#define SMB_SFILEINFO_ATTR_FLAGS 0x206 +#define SMB_SFILEINFO_UNIX_INFO2 0x20b +#define SMB_SFILEINFO_BASIC_INFORMATION 1004 +#define SMB_SFILEINFO_RENAME_INFORMATION 1010 +#define SMB_SFILEINFO_LINK_INFORMATION 1011 +#define SMB_SFILEINFO_DISPOSITION_INFORMATION 1013 +#define SMB_SFILEINFO_POSITION_INFORMATION 1014 +#define SMB_SFILEINFO_FULL_EA_INFORMATION 1015 +#define SMB_SFILEINFO_MODE_INFORMATION 1016 +#define SMB_SFILEINFO_ALLOCATION_INFORMATION 1019 +#define SMB_SFILEINFO_END_OF_FILE_INFORMATION 1020 +#define SMB_SFILEINFO_PIPE_INFORMATION 1023 +#define SMB_SFILEINFO_VALID_DATA_INFORMATION 1039 +#define SMB_SFILEINFO_SHORT_NAME_INFORMATION 1040 + +/* filemon shows FilePipeRemoteInformation */ +#define SMB_SFILEINFO_1025 1025 + +/* vista scan responds */ +#define SMB_SFILEINFO_1027 1027 + +/* filemon shows CopyOnWriteInformation */ +#define SMB_SFILEINFO_1029 1029 + +/* filemon shows OleClassIdInformation */ +#define SMB_SFILEINFO_1032 1032 + +/* vista scan responds to these */ +#define SMB_SFILEINFO_1030 1030 +#define SMB_SFILEINFO_1031 1031 +#define SMB_SFILEINFO_1036 1036 +#define SMB_SFILEINFO_1041 1041 +#define SMB_SFILEINFO_1042 1042 +#define SMB_SFILEINFO_1043 1043 +#define SMB_SFILEINFO_1044 1044 + +/* trans2 findfirst levels */ +/* +w2k3 TRANS2ALIASES: +Checking for FINDFIRST aliases + Found level 1 (0x001) of size 68 (0x44) + Found level 2 (0x002) of size 70 (0x46) + Found level 257 (0x101) of size 108 (0x6c) + Found level 258 (0x102) of size 116 (0x74) + Found level 259 (0x103) of size 60 (0x3c) + Found level 260 (0x104) of size 140 (0x8c) + Found level 261 (0x105) of size 124 (0x7c) + Found level 262 (0x106) of size 148 (0x94) +Found 8 levels with success status +Found 0 aliased levels +*/ +#define SMB_FIND_STANDARD 1 +#define SMB_FIND_EA_SIZE 2 +#define SMB_FIND_EA_LIST 3 +#define SMB_FIND_DIRECTORY_INFO 0x101 +#define SMB_FIND_FULL_DIRECTORY_INFO 0x102 +#define SMB_FIND_NAME_INFO 0x103 +#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104 +#define SMB_FIND_ID_FULL_DIRECTORY_INFO 0x105 +#define SMB_FIND_ID_BOTH_DIRECTORY_INFO 0x106 +#define SMB_FIND_UNIX_INFO 0x202 +#define SMB_FIND_UNIX_INFO2 0x20b + +/* flags on trans2 findfirst/findnext that control search */ +#define FLAG_TRANS2_FIND_CLOSE 0x1 +#define FLAG_TRANS2_FIND_CLOSE_IF_END 0x2 +#define FLAG_TRANS2_FIND_REQUIRE_RESUME 0x4 +#define FLAG_TRANS2_FIND_CONTINUE 0x8 +#define FLAG_TRANS2_FIND_BACKUP_INTENT 0x10 + +/* + * DeviceType and Characteristics returned in a + * SMB_QFS_DEVICE_INFO call. + */ +#define QFS_DEVICETYPE_CD_ROM 0x2 +#define QFS_DEVICETYPE_CD_ROM_FILE_SYSTEM 0x3 +#define QFS_DEVICETYPE_DISK 0x7 +#define QFS_DEVICETYPE_DISK_FILE_SYSTEM 0x8 +#define QFS_DEVICETYPE_FILE_SYSTEM 0x9 + +/* Characteristics. */ +#define QFS_TYPE_REMOVABLE_MEDIA 0x1 +#define QFS_TYPE_READ_ONLY_DEVICE 0x2 +#define QFS_TYPE_FLOPPY 0x4 +#define QFS_TYPE_WORM 0x8 +#define QFS_TYPE_REMOTE 0x10 +#define QFS_TYPE_MOUNTED 0x20 +#define QFS_TYPE_VIRTUAL 0x40 + +/* SMB_QFS_SECTOR_SIZE_INFORMATION values */ +#define QFS_SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 +#define QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 +#define QFS_SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004 +#define QFS_SSINFO_FLAGS_TRIM_ENABLED 0x00000008 + +#define QFS_SSINFO_OFFSET_UNKNOWN 0xffffffff + +/* + * Thursby MAC extensions.... + */ + +/* + * MAC CIFS Extensions have the range 0x300 - 0x2FF reserved. + * Supposedly Microsoft have agreed to this. + */ + +#define MIN_MAC_INFO_LEVEL 0x300 +#define MAX_MAC_INFO_LEVEL 0x3FF +#define SMB_QFS_MAC_FS_INFO 0x301 + +#endif |