summaryrefslogtreecommitdiffstats
path: root/source4/libcli/raw
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/raw')
-rw-r--r--source4/libcli/raw/README5
-rw-r--r--source4/libcli/raw/clierror.c73
-rw-r--r--source4/libcli/raw/clioplock.c66
-rw-r--r--source4/libcli/raw/clisession.c310
-rw-r--r--source4/libcli/raw/clisocket.c459
-rw-r--r--source4/libcli/raw/clitransport.c673
-rw-r--r--source4/libcli/raw/clitree.c228
-rw-r--r--source4/libcli/raw/interfaces.h2867
-rw-r--r--source4/libcli/raw/libcliraw.h343
-rw-r--r--source4/libcli/raw/rawacl.c163
-rw-r--r--source4/libcli/raw/rawdate.c82
-rw-r--r--source4/libcli/raw/raweas.c371
-rw-r--r--source4/libcli/raw/rawfile.c1052
-rw-r--r--source4/libcli/raw/rawfileinfo.c810
-rw-r--r--source4/libcli/raw/rawfsinfo.c431
-rw-r--r--source4/libcli/raw/rawioctl.c173
-rw-r--r--source4/libcli/raw/rawlpq.c48
-rw-r--r--source4/libcli/raw/rawnegotiate.c183
-rw-r--r--source4/libcli/raw/rawnotify.c122
-rw-r--r--source4/libcli/raw/rawreadwrite.c345
-rw-r--r--source4/libcli/raw/rawrequest.c1055
-rw-r--r--source4/libcli/raw/rawsearch.c842
-rw-r--r--source4/libcli/raw/rawsetfileinfo.c506
-rw-r--r--source4/libcli/raw/rawshadow.c82
-rw-r--r--source4/libcli/raw/rawtrans.c446
-rw-r--r--source4/libcli/raw/request.h78
-rw-r--r--source4/libcli/raw/signing.h39
-rw-r--r--source4/libcli/raw/smb.h322
-rw-r--r--source4/libcli/raw/smb_signing.c275
-rw-r--r--source4/libcli/raw/trans2.h309
30 files changed, 12758 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..66376f0
--- /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..d1ac910
--- /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..69b7e8b
--- /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..0c53014
--- /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..04761d6
--- /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..cf32ad2
--- /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..6abc06d
--- /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 paths
+ * 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 helper 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 variant of the call */
+ struct security_descriptor *sec_desc;
+ struct smb_ea_list *ea_list;
+
+ /* some optional parameters from the SMB2 variant */
+ 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 array */
+ } 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..3584cdc
--- /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 extended 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
+ asynchronously. 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..a6ff776
--- /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..b9af57f
--- /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..ee3a999
--- /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..112b3e1
--- /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..c8b0ec7
--- /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 that's
+ 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 identical 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..9e5ad82
--- /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..7971478
--- /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..2da647a
--- /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..22f681e
--- /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..a78a023
--- /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..384db55
--- /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..1c72bc2
--- /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_null_terminated_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_null_terminated_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..21e8868
--- /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..7044905
--- /dev/null
+++ b/source4/libcli/raw/rawsetfileinfo.c
@@ -0,0 +1,506 @@
+/*
+ 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;
+
+ case RAW_SFILEINFO_LINK_INFORMATION:
+ NEED_BLOB(20);
+ memset(blob->data, 0, blob->length);
+
+ PUSH_LE_U8(blob->data, 0, parms->link_information.in.overwrite);
+ PUSH_LE_U64(blob->data, 8, parms->link_information.in.root_fid);
+
+ len = smbcli_blob_append_string(
+ NULL, mem_ctx, blob,
+ parms->link_information.in.new_name,
+ STR_UNICODE | STR_TERMINATE);
+ PUSH_LE_U32(blob->data, 16, len - 2);
+ 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..0ce92c5
--- /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..de3e054
--- /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,
+ &param,
+ 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,
+ &param,
+ 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..88cd066
--- /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
+ * ignored (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..c921db2
--- /dev/null
+++ b/source4/libcli/raw/smb_signing.c
@@ -0,0 +1,275 @@
+/*
+ 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..34f4617
--- /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