wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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);
|
||||
|
||||
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);
|
||||
|
||||
/* this request does not expect a reply, so tell the signing
|
||||
subsystem not to allocate an id for a reply */
|
||||
req->one_way_request = 1;
|
||||
|
||||
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)
|
||||
{
|
||||
transport->oplock.handler = handler;
|
||||
transport->oplock.private = private;
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/filesys.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 *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 = (uint16_t)getpid();
|
||||
session->vuid = UID_FIELD_INVALID;
|
||||
|
||||
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 (session->transport->negotiate.sign_info.doing_signing) {
|
||||
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, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, 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, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE);
|
||||
if (p < (req->in.data + req->in.data_size)) {
|
||||
p += smbcli_req_pull_string(req, 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, mem_ctx, p, len);
|
||||
p += parms->spnego.out.secblob.length;
|
||||
p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, 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)
|
||||
*****************************************************************************/
|
||||
NTSTATUS smb_raw_exit(struct smbcli_session *session)
|
||||
{
|
||||
struct smbcli_request *req = smb_raw_exit_send(session);
|
||||
return smbcli_request_simple_recv(req);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.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"
|
||||
|
||||
struct sock_connect_state {
|
||||
struct composite_context *ctx;
|
||||
const char *host_name;
|
||||
int num_ports;
|
||||
uint16_t *ports;
|
||||
struct smbcli_socket *result;
|
||||
};
|
||||
|
||||
/*
|
||||
connect a smbcli_socket context to an IP/port pair
|
||||
if port is 0 then choose 445 then 139
|
||||
*/
|
||||
|
||||
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,
|
||||
int port,
|
||||
const char *host_name,
|
||||
struct event_context *event_ctx)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct sock_connect_state *state;
|
||||
int reason = 0;
|
||||
char* reasons[] = {
|
||||
"could not allocate composite_context",
|
||||
"no event context/failed init",
|
||||
"could not allocate sock_connect_state",
|
||||
"no hostname/could not allocate copy",
|
||||
"ports setup error",
|
||||
"failed socket_connect_multi_send",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
result = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
reason++;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
|
||||
if (event_ctx != NULL) {
|
||||
result->event_ctx = talloc_reference(result, event_ctx);
|
||||
} else {
|
||||
result->event_ctx = event_context_init(result);
|
||||
}
|
||||
|
||||
if (result->event_ctx == NULL) goto failed;
|
||||
reason++;
|
||||
|
||||
state = talloc(result, struct sock_connect_state);
|
||||
if (state == NULL) goto failed;
|
||||
reason++;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->host_name = talloc_strdup(state, host_name);
|
||||
if (state->host_name == NULL) goto failed;
|
||||
reason++;
|
||||
|
||||
if (port == 0) {
|
||||
const char **ports = lp_smb_ports();
|
||||
int i;
|
||||
|
||||
for (i=0;ports[i];i++) /* noop */ ;
|
||||
if (i == 0) {
|
||||
DEBUG(3, ("no smb ports defined\n"));
|
||||
goto failed;
|
||||
}
|
||||
state->num_ports = i;
|
||||
state->ports = talloc_array(state, uint16_t, i);
|
||||
if (state->ports == NULL) goto failed;
|
||||
for (i=0;ports[i];i++) {
|
||||
state->ports[i] = atoi(ports[i]);
|
||||
}
|
||||
} else {
|
||||
state->ports = talloc_array(state, uint16_t, 1);
|
||||
if (state->ports == NULL) goto failed;
|
||||
state->num_ports = 1;
|
||||
state->ports[0] = port;
|
||||
}
|
||||
reason++;
|
||||
|
||||
ctx = socket_connect_multi_send(state, host_addr,
|
||||
state->num_ports, state->ports,
|
||||
state->ctx->event_ctx);
|
||||
if (ctx == NULL) goto failed;
|
||||
reason++;
|
||||
ctx->async.fn = smbcli_sock_connect_recv_conn;
|
||||
ctx->async.private_data = state;
|
||||
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
|
||||
DEBUG_FN_FAIL(reasons[reason]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
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_recv(ctx, state, &sock,
|
||||
&port);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->ctx->status =
|
||||
socket_set_option(sock, lp_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 =
|
||||
talloc_reference(state->result, state->ctx->event_ctx);
|
||||
if (composite_nomem(state->result->event.ctx, state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
finish a smbcli_sock_connect_send() operation
|
||||
*/
|
||||
NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_socket **result)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
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);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
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, int port,
|
||||
const char *host_name,
|
||||
struct event_context *event_ctx,
|
||||
struct smbcli_socket **result)
|
||||
{
|
||||
struct composite_context *c =
|
||||
smbcli_sock_connect_send(mem_ctx, host_addr, port, host_name,
|
||||
event_ctx);
|
||||
return smbcli_sock_connect_recv(c, mem_ctx, result);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
mark the socket as dead
|
||||
****************************************************************************/
|
||||
void smbcli_sock_dead(struct smbcli_socket *sock)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
talloc_free(sock->event.fde);
|
||||
sock->event.fde = NULL;
|
||||
talloc_free(sock->sock);
|
||||
sock->sock = NULL;
|
||||
|
||||
DEBUG_FN_EXIT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Set socket options on a open connection.
|
||||
****************************************************************************/
|
||||
void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
|
||||
{
|
||||
socket_set_option(sock->sock, options, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
resolve a hostname and connect
|
||||
****************************************************************************/
|
||||
struct smbcli_socket *smbcli_sock_connect_byname(const char *host, int port,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct event_context *event_ctx)
|
||||
{
|
||||
int name_type = NBT_NAME_SERVER;
|
||||
const char *address;
|
||||
NTSTATUS status;
|
||||
struct nbt_name nbt_name;
|
||||
char *name, *p;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
||||
struct smbcli_socket *result;
|
||||
|
||||
if (tmp_ctx == NULL) {
|
||||
DEBUG(0, ("talloc_new failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = talloc_strdup(tmp_ctx, host);
|
||||
if (name == NULL) {
|
||||
DEBUG(0, ("talloc_strdup failed\n"));
|
||||
talloc_free(tmp_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (event_ctx == NULL) {
|
||||
event_ctx = event_context_init(mem_ctx);
|
||||
}
|
||||
|
||||
if (event_ctx == NULL) {
|
||||
DEBUG(0, ("event_context_init failed\n"));
|
||||
talloc_free(tmp_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allow hostnames of the form NAME#xx and do a netbios lookup */
|
||||
if ((p = strchr(name, '#'))) {
|
||||
name_type = strtol(p+1, NULL, 16);
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
make_nbt_name(&nbt_name, host, name_type);
|
||||
|
||||
status = resolve_name(&nbt_name, tmp_ctx, &address, event_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(tmp_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = smbcli_sock_connect(mem_ctx, address, port, name, event_ctx,
|
||||
&result);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(9, ("smbcli_sock_connect failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
talloc_free(tmp_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/stream/packet.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
static int smbcli_request_deny_destructor(struct smbcli_request *req);
|
||||
|
||||
/*
|
||||
an event has happened on the socket
|
||||
*/
|
||||
static void smbcli_transport_event_handler(struct event_context *ev,
|
||||
struct fd_event *fde,
|
||||
uint16_t flags, void *private)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private,
|
||||
struct smbcli_transport);
|
||||
if (flags & EVENT_FD_READ) {
|
||||
packet_recv(transport->packet);
|
||||
return;
|
||||
}
|
||||
if (flags & EVENT_FD_WRITE) {
|
||||
packet_queue_run(transport->packet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
destroy a transport
|
||||
*/
|
||||
static int transport_destructor(struct smbcli_transport *transport)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle receive errors
|
||||
*/
|
||||
static void smbcli_transport_error(void *private, NTSTATUS status)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private, struct smbcli_transport);
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
smbcli_transport_dead(transport, status);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
}
|
||||
|
||||
static NTSTATUS smbcli_transport_finish_recv(void *private, DATA_BLOB blob);
|
||||
|
||||
/*
|
||||
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_transport *transport;
|
||||
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
transport = talloc_zero(parent_ctx, struct smbcli_transport);
|
||||
if (!transport) return NULL;
|
||||
|
||||
if (primary) {
|
||||
transport->socket = talloc_steal(transport, sock);
|
||||
} else {
|
||||
transport->socket = talloc_reference(transport, sock);
|
||||
}
|
||||
transport->negotiate.protocol = PROTOCOL_NT1;
|
||||
transport->options.use_spnego = lp_use_spnego() && lp_nt_status_support();
|
||||
transport->options.max_xmit = lp_max_xmit();
|
||||
transport->options.max_mux = lp_maxmux();
|
||||
transport->options.request_timeout = SMB_REQUEST_TIMEOUT;
|
||||
|
||||
transport->negotiate.max_xmit = transport->options.max_xmit;
|
||||
|
||||
/* setup the stream -> packet parser */
|
||||
transport->packet = packet_init(transport);
|
||||
if (transport->packet == NULL) {
|
||||
talloc_free(transport);
|
||||
DEBUG_FN_FAIL("packet_init_failed, return NULL");
|
||||
return NULL;
|
||||
}
|
||||
packet_set_private(transport->packet, transport);
|
||||
packet_set_socket(transport->packet, transport->socket->sock);
|
||||
packet_set_callback(transport->packet, smbcli_transport_finish_recv);
|
||||
packet_set_full_request(transport->packet, packet_full_request_nbt);
|
||||
packet_set_error_handler(transport->packet, smbcli_transport_error);
|
||||
packet_set_event_context(transport->packet, transport->socket->event.ctx);
|
||||
packet_set_nofree(transport->packet);
|
||||
|
||||
smbcli_init_signing(transport);
|
||||
|
||||
ZERO_STRUCT(transport->called);
|
||||
|
||||
/* take over event handling from the socket layer - it only
|
||||
handles events up until we are connected */
|
||||
talloc_free(transport->socket->event.fde);
|
||||
transport->socket->event.fde = event_add_fd(transport->socket->event.ctx,
|
||||
transport->socket->sock,
|
||||
socket_get_fd(transport->socket->sock),
|
||||
EVENT_FD_READ,
|
||||
smbcli_transport_event_handler,
|
||||
transport);
|
||||
|
||||
packet_set_fde(transport->packet, transport->socket->event.fde);
|
||||
packet_set_serialise(transport->packet);
|
||||
talloc_set_destructor(transport, transport_destructor);
|
||||
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
||||
/*
|
||||
mark the transport as dead
|
||||
*/
|
||||
void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
smbcli_sock_dead(transport->socket);
|
||||
|
||||
if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
|
||||
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Getting "using freed memory" in these callbacks when a connection
|
||||
* times out and the transport is being shutdown.
|
||||
*/
|
||||
#if 0
|
||||
void* transportRef = talloc_named_const(NULL,1,"TRANSPORT_REF");
|
||||
talloc_reference(transportRef, transport);
|
||||
|
||||
/* kill all pending receives */
|
||||
while (transport->pending_recv) {
|
||||
struct smbcli_request *req = transport->pending_recv;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
talloc_set_destructor(req, smbcli_request_deny_destructor);
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
talloc_set_destructor(req, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* all done with transport, free holder reference*/
|
||||
talloc_free(transportRef);
|
||||
#endif
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a session request
|
||||
*/
|
||||
struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
|
||||
struct nbt_name *calling,
|
||||
struct nbt_name *called)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
uint8_t *p;
|
||||
struct smbcli_request *req;
|
||||
DATA_BLOB calling_blob, called_blob;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(transport);
|
||||
NTSTATUS status;
|
||||
|
||||
status = nbt_name_dup(transport, called, &transport->called);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
status = nbt_name_to_blob(tmp_ctx, &calling_blob, calling);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
status = nbt_name_to_blob(tmp_ctx, &called_blob, called);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
/* allocate output buffer */
|
||||
req = smbcli_request_setup_nonsmb(transport,
|
||||
NBT_HDR_SIZE +
|
||||
calling_blob.length + called_blob.length);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
/* put in the destination name */
|
||||
p = req->out.buffer + 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(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE);
|
||||
SCVAL(req->out.buffer,0,0x81);
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return req;
|
||||
|
||||
failed:
|
||||
talloc_free(tmp_ctx);
|
||||
DEBUG_FN_FAIL("failed, return NULL");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
map a session request error to a NTSTATUS
|
||||
*/
|
||||
static NTSTATUS map_session_refused_error(uint8_t error)
|
||||
{
|
||||
switch (error) {
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
return NT_STATUS_REMOTE_NOT_LISTENING;
|
||||
case 0x82:
|
||||
return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
|
||||
case 0x83:
|
||||
return NT_STATUS_REMOTE_RESOURCES;
|
||||
}
|
||||
return NT_STATUS_UNEXPECTED_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
finish a smbcli_transport_connect()
|
||||
*/
|
||||
NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
if (!smbcli_request_receive(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
|
||||
}
|
||||
|
||||
switch (CVAL(req->in.buffer,0)) {
|
||||
case 0x82:
|
||||
status = NT_STATUS_OK;
|
||||
break;
|
||||
case 0x83:
|
||||
status = map_session_refused_error(CVAL(req->in.buffer,4));
|
||||
break;
|
||||
case 0x84:
|
||||
DEBUG(1,("Warning: session retarget not supported\n"));
|
||||
status = NT_STATUS_NOT_SUPPORTED;
|
||||
break;
|
||||
default:
|
||||
status = NT_STATUS_UNEXPECTED_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
smbcli_request_destroy(req);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a session request (if needed)
|
||||
*/
|
||||
BOOL smbcli_transport_connect(struct smbcli_transport *transport,
|
||||
struct nbt_name *calling,
|
||||
struct nbt_name *called)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
if (transport->socket->port == 445) {
|
||||
return True;
|
||||
}
|
||||
|
||||
req = smbcli_transport_connect_send(transport,
|
||||
calling, called);
|
||||
status = smbcli_transport_connect_recv(req);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return NT_STATUS_IS_OK(status);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
get next mid in sequence
|
||||
****************************************************************************/
|
||||
uint16_t smbcli_transport_next_mid(struct smbcli_transport *transport)
|
||||
{
|
||||
uint16_t mid;
|
||||
struct smbcli_request *req;
|
||||
|
||||
mid = transport->next_mid;
|
||||
|
||||
again:
|
||||
/* now check to see if this mid is being used by one of the
|
||||
pending requests. This is quite efficient because the list is
|
||||
usually very short */
|
||||
|
||||
/* the zero mid is reserved for requests that don't have a mid */
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
if (mid == 0) mid = 1;
|
||||
|
||||
for (req=transport->pending_recv; req; req=req->next) {
|
||||
if (req->mid == mid) {
|
||||
mid++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
transport->next_mid = mid+1;
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
static void idle_handler(struct event_context *ev,
|
||||
struct timed_event *te, struct timeval t, void *private)
|
||||
{
|
||||
struct smbcli_transport *transport = talloc_get_type(private,
|
||||
struct smbcli_transport);
|
||||
struct timeval next = timeval_add(&t, 0, transport->idle.period);
|
||||
transport->socket->event.te = event_add_timed(transport->socket->event.ctx,
|
||||
transport,
|
||||
next,
|
||||
idle_handler, transport);
|
||||
transport->idle.func(transport, transport->idle.private);
|
||||
}
|
||||
|
||||
/*
|
||||
setup the idle handler for a transport
|
||||
the period is in microseconds
|
||||
*/
|
||||
void smbcli_transport_idle_handler(struct smbcli_transport *transport,
|
||||
void (*idle_func)(struct smbcli_transport *, void *),
|
||||
uint64_t period,
|
||||
void *private)
|
||||
{
|
||||
transport->idle.func = idle_func;
|
||||
transport->idle.private = private;
|
||||
transport->idle.period = period;
|
||||
|
||||
if (transport->socket->event.te != NULL) {
|
||||
talloc_free(transport->socket->event.te);
|
||||
}
|
||||
|
||||
transport->socket->event.te = event_add_timed(transport->socket->event.ctx,
|
||||
transport,
|
||||
timeval_current_ofs(0, period),
|
||||
idle_handler, transport);
|
||||
}
|
||||
|
||||
/*
|
||||
we have a full request in our receive buffer - match it to a pending request
|
||||
and process
|
||||
*/
|
||||
static NTSTATUS smbcli_transport_finish_recv(void *private, DATA_BLOB blob)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
struct smbcli_transport *transport = talloc_get_type(private,
|
||||
struct smbcli_transport);
|
||||
uint8_t *buffer, *hdr, *vwv;
|
||||
int len;
|
||||
uint16_t wct=0, mid = 0, op = 0;
|
||||
struct smbcli_request *req = NULL;
|
||||
|
||||
buffer = blob.data;
|
||||
len = blob.length;
|
||||
|
||||
hdr = buffer+NBT_HDR_SIZE;
|
||||
vwv = hdr + HDR_VWV;
|
||||
|
||||
/* see if it could be an oplock break request */
|
||||
if (smbcli_handle_oplock_break(transport, len, hdr, vwv)) {
|
||||
talloc_free(buffer);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* at this point we need to check for a readbraw reply, as
|
||||
these can be any length */
|
||||
if (transport->readbraw_pending) {
|
||||
transport->readbraw_pending = 0;
|
||||
|
||||
/* it must match the first entry in the pending queue
|
||||
as the client is not allowed to have outstanding
|
||||
readbraw requests */
|
||||
req = transport->pending_recv;
|
||||
if (!req) goto error;
|
||||
|
||||
req->in.buffer = buffer;
|
||||
talloc_steal(req, buffer);
|
||||
req->in.size = len;
|
||||
req->in.allocated = req->in.size;
|
||||
goto async;
|
||||
}
|
||||
|
||||
if (len >= MIN_SMB_SIZE) {
|
||||
/* extract the mid for matching to pending requests */
|
||||
mid = SVAL(hdr, HDR_MID);
|
||||
wct = CVAL(hdr, HDR_WCT);
|
||||
op = CVAL(hdr, HDR_COM);
|
||||
}
|
||||
|
||||
/* match the incoming request against the list of pending requests */
|
||||
for (req=transport->pending_recv; req; req=req->next) {
|
||||
if (req->mid == mid) break;
|
||||
}
|
||||
|
||||
/* see if it's a ntcancel reply for the current MID */
|
||||
req = smbcli_handle_ntcancel_reply(req, len, hdr);
|
||||
|
||||
if (!req) {
|
||||
DEBUG(1,("Discarding unmatched reply with mid %d op %d\n", mid, op));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* fill in the 'in' portion of the matching request */
|
||||
req->in.buffer = buffer;
|
||||
talloc_steal(req, buffer);
|
||||
req->in.size = len;
|
||||
req->in.allocated = req->in.size;
|
||||
|
||||
/* handle NBT session replies */
|
||||
if (req->in.size >= 4 && req->in.buffer[0] != 0) {
|
||||
req->status = NT_STATUS_OK;
|
||||
goto async;
|
||||
}
|
||||
|
||||
/* handle non-SMB replies */
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
|
||||
DEBUG(2,("bad reply size for mid %d\n", mid));
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
req->in.hdr = hdr;
|
||||
req->in.vwv = vwv;
|
||||
req->in.wct = wct;
|
||||
if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
|
||||
req->in.data = req->in.vwv + VWV(wct) + 2;
|
||||
req->in.data_size = SVAL(req->in.vwv, VWV(wct));
|
||||
if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
|
||||
DEBUG(3,("bad data size for mid %d\n", mid));
|
||||
/* blergh - w2k3 gives a bogus data size values in some
|
||||
openX replies */
|
||||
req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
|
||||
}
|
||||
}
|
||||
req->in.ptr = req->in.data;
|
||||
req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
|
||||
|
||||
if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
|
||||
int class = CVAL(req->in.hdr,HDR_RCLS);
|
||||
int code = SVAL(req->in.hdr,HDR_ERR);
|
||||
if (class == 0 && code == 0) {
|
||||
transport->error.e.nt_status = NT_STATUS_OK;
|
||||
} else {
|
||||
transport->error.e.nt_status = NT_STATUS_DOS(class, code);
|
||||
}
|
||||
} else {
|
||||
transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
|
||||
}
|
||||
|
||||
req->status = transport->error.e.nt_status;
|
||||
if (NT_STATUS_IS_OK(req->status)) {
|
||||
transport->error.etype = ETYPE_NONE;
|
||||
} else {
|
||||
transport->error.etype = ETYPE_SMB;
|
||||
}
|
||||
|
||||
if (!smbcli_request_check_sign_mac(req)) {
|
||||
transport->error.etype = ETYPE_SOCKET;
|
||||
transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_ACCESS_DENIED;
|
||||
goto error;
|
||||
};
|
||||
|
||||
async:
|
||||
/* if this request has an async handler then call that to
|
||||
notify that the reply has been received. This might destroy
|
||||
the request so it must happen last */
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
DEBUG_FN_EXIT_MSG("async");
|
||||
|
||||
return NT_STATUS_OK;
|
||||
|
||||
error:
|
||||
if (req) {
|
||||
DLIST_REMOVE(transport->pending_recv, req);
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
} else {
|
||||
talloc_free(buffer);
|
||||
}
|
||||
DEBUG_FN_FAIL("failed, continue NT_STATUS_OK");
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
process some read/write requests that are pending
|
||||
return False if the socket is dead
|
||||
*/
|
||||
BOOL smbcli_transport_process(struct smbcli_transport *transport)
|
||||
{
|
||||
NTSTATUS status;
|
||||
size_t npending;
|
||||
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
packet_queue_run(transport->packet);
|
||||
if (transport->socket->sock == NULL) {
|
||||
return False;
|
||||
}
|
||||
|
||||
status = socket_pending(transport->socket->sock, &npending);
|
||||
if (NT_STATUS_IS_OK(status) && npending > 0) {
|
||||
packet_recv(transport->packet);
|
||||
}
|
||||
if (transport->socket->sock == NULL) {
|
||||
return False;
|
||||
}
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
handle timeouts of individual smb requests
|
||||
*/
|
||||
static void smbcli_timeout_handler(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
struct smbcli_request *req = talloc_get_type(private, struct smbcli_request);
|
||||
|
||||
if (req->state == SMBCLI_REQUEST_RECV) {
|
||||
DLIST_REMOVE(req->transport->pending_recv, req);
|
||||
}
|
||||
req->status = NT_STATUS_IO_TIMEOUT;
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
if (req->async.fn) {
|
||||
req->async.fn(req);
|
||||
}
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
destroy a request
|
||||
*/
|
||||
static int smbcli_request_destructor(struct smbcli_request *req)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
if (req->state == SMBCLI_REQUEST_RECV) {
|
||||
DLIST_REMOVE(req->transport->pending_recv, req);
|
||||
}
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbcli_request_deny_destructor(struct smbcli_request *req)
|
||||
{
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
put a request into the send queue
|
||||
*/
|
||||
void smbcli_transport_send(struct smbcli_request *req)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG_FN_ENTER;
|
||||
|
||||
/* check if the transport is dead */
|
||||
if (req->transport->socket->sock == NULL) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = NT_STATUS_NET_WRITE_FAULT;
|
||||
DEBUG_FN_FAIL("req->transport->socket->sock is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
blob = data_blob_const(req->out.buffer, req->out.size);
|
||||
status = packet_send(req->transport->packet, blob);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
req->state = SMBCLI_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
DEBUG_FN_FAIL("packet_send fail, !NTSTATUS_IS_OK");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->one_way_request) {
|
||||
req->state = SMBCLI_REQUEST_DONE;
|
||||
smbcli_request_destroy(req);
|
||||
DEBUG_FN_EXIT_MSG("one way request");
|
||||
return;
|
||||
}
|
||||
|
||||
req->state = SMBCLI_REQUEST_RECV;
|
||||
DLIST_ADD(req->transport->pending_recv, req);
|
||||
|
||||
/* add a timeout */
|
||||
if (req->transport->options.request_timeout) {
|
||||
event_add_timed(req->transport->socket->event.ctx, req,
|
||||
timeval_current_ofs(req->transport->options.request_timeout, 0),
|
||||
smbcli_timeout_handler, req);
|
||||
}
|
||||
|
||||
talloc_set_destructor(req, smbcli_request_destructor);
|
||||
DEBUG_FN_EXIT;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/smb_composite/smb_composite.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
|
||||
****************************************************************************/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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 >= 4) {
|
||||
parms->tconx.out.options = SVAL(req->in.vwv, VWV(3));
|
||||
}
|
||||
|
||||
/* output is actual service name */
|
||||
p = req->in.data;
|
||||
if (!p) break;
|
||||
|
||||
p += smbcli_req_pull_string(req, mem_ctx, &parms->tconx.out.dev_type,
|
||||
p, -1, STR_ASCII | STR_TERMINATE);
|
||||
p += smbcli_req_pull_string(req, 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)
|
||||
****************************************************************************/
|
||||
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.
|
||||
****************************************************************************/
|
||||
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 (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, int port,
|
||||
const char *service, const char *service_type,
|
||||
struct cli_credentials *credentials,
|
||||
struct event_context *ev)
|
||||
{
|
||||
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.port = port;
|
||||
io.in.called_name = strupper_talloc(tmp_ctx, dest_host);
|
||||
io.in.service = service;
|
||||
io.in.service_type = service_type;
|
||||
io.in.credentials = credentials;
|
||||
io.in.fallback_to_anonymous = False;
|
||||
io.in.workgroup = lp_workgroup();
|
||||
|
||||
status = smb_composite_connect(&io, parent_ctx, ev);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
*ret_tree = io.out.tree;
|
||||
}
|
||||
talloc_free(tmp_ctx);
|
||||
return status;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ioctl and fsctl definitions
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
/* ioctl codes */
|
||||
#define IOCTL_QUERY_JOB_INFO 0x530060
|
||||
|
||||
|
||||
/* filesystem control codes */
|
||||
#define FSCTL_METHOD_BUFFERED 0x00000000
|
||||
#define FSCTL_METHOD_IN_DIRECT 0x00000001
|
||||
#define FSCTL_METHOD_OUT_DIRECT 0x00000002
|
||||
#define FSCTL_METHOD_NEITHER 0x00000003
|
||||
|
||||
#define FSCTL_ACCESS_ANY 0x00000000
|
||||
#define FSCTL_ACCESS_READ 0x00004000
|
||||
#define FSCTL_ACCESS_WRITE 0x00008000
|
||||
|
||||
#define FSCTL_FILESYSTEM 0x00090000
|
||||
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0000 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_REQUEST_OPLOCK_LEVEL_2 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0004 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_REQUEST_BATCH_OPLOCK (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0008 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x000C | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_OPBATCH_ACK_CLOSE_PENDING (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0010 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_OPLOCK_BREAK_NOTIFY (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0014 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_FILESYS_GET_STATISTICS (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0060 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_GET_NTFS_VOLUME_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0064 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_FIND_FILES_BY_SID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x008C | FSCTL_METHOD_NEITHER)
|
||||
#define FSCTL_SET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0098 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x009C | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_DELETE_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A0 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_SET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A4 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_GET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A8 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_DELETE_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00AC | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_CREATE_OR_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C0 | FSCTL_METHOD_BUFFERED)
|
||||
#define FSCTL_SET_SPARSE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C4 | FSCTL_METHOD_BUFFERED)
|
||||
|
||||
#define FSCTL_NAMED_PIPE 0x00110000
|
||||
#define FSCTL_NAMED_PIPE_READ_WRITE (FSCTL_NAMED_PIPE | FSCTL_ACCESS_ANY | 0xC014 | FSCTL_METHOD_NEITHER)
|
||||
|
||||
#define FSCTL_NETWORK_FILESYSTEM 0x00140000
|
||||
#define FSCTL_GET_SHADOW_COPY_DATA (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ | 0x0064 | FSCTL_METHOD_BUFFERED)
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LIBCLI_RAW_H__
|
||||
#define __LIBCLI_RAW_H__
|
||||
|
||||
#include "libcli/raw/request.h"
|
||||
#include "librpc/gen_ndr/nbt.h"
|
||||
|
||||
struct smbcli_tree; /* forward declare */
|
||||
struct smbcli_request; /* forward declare */
|
||||
struct smbcli_session; /* forward declare */
|
||||
struct smbcli_transport; /* forward declare */
|
||||
|
||||
struct cli_credentials;
|
||||
|
||||
/* 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 */
|
||||
uint8_t key_len;
|
||||
DATA_BLOB server_guid; /* server_guid */
|
||||
DATA_BLOB secblob; /* cryptkey or negTokenInit blob */
|
||||
uint32_t sesskey;
|
||||
|
||||
struct smb_signing_context sign_info;
|
||||
|
||||
/* capabilities that the server reported */
|
||||
uint32_t capabilities;
|
||||
|
||||
int server_zone;
|
||||
time_t server_time;
|
||||
uint_t readbraw_supported:1;
|
||||
uint_t writebraw_supported:1;
|
||||
|
||||
char *server_domain;
|
||||
};
|
||||
|
||||
/* 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 event_context *ctx;
|
||||
struct fd_event *fde;
|
||||
struct timed_event *te;
|
||||
} event;
|
||||
};
|
||||
|
||||
/*
|
||||
this structure allows applications to control the behaviour of the
|
||||
client library
|
||||
*/
|
||||
struct smbcli_options {
|
||||
uint_t use_oplocks:1;
|
||||
uint_t use_level2_oplocks:1;
|
||||
uint_t use_spnego:1;
|
||||
uint32_t max_xmit;
|
||||
uint16_t max_mux;
|
||||
int request_timeout;
|
||||
};
|
||||
|
||||
/* this is the context for the client transport layer */
|
||||
struct smbcli_transport {
|
||||
/* socket level info */
|
||||
struct smbcli_socket *socket;
|
||||
|
||||
/* the next mid to be allocated - needed for signing and
|
||||
request matching */
|
||||
uint16_t next_mid;
|
||||
|
||||
/* negotiated protocol information */
|
||||
struct smbcli_negotiate negotiate;
|
||||
|
||||
/* options to control the behaviour of the client code */
|
||||
struct smbcli_options options;
|
||||
|
||||
/* is a readbraw pending? we need to handle that case
|
||||
specially on receiving packets */
|
||||
uint_t readbraw_pending:1;
|
||||
|
||||
/* 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;
|
||||
uint_t period;
|
||||
} 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;
|
||||
uint_t 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);
|
||||
/* private data passed to the oplock handler */
|
||||
void *private;
|
||||
} oplock;
|
||||
|
||||
/* a list of async requests that are pending for receive on this connection */
|
||||
struct smbcli_request *pending_recv;
|
||||
|
||||
/* remember the called name - some sub-protocols require us to
|
||||
know the server name */
|
||||
struct nbt_name called;
|
||||
|
||||
/* context of the stream -> packet parser */
|
||||
struct packet_context *packet;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
|
||||
DATA_BLOB user_session_key;
|
||||
|
||||
/* the spnego context if we use extented security */
|
||||
struct gensec_security *gensec;
|
||||
};
|
||||
|
||||
/*
|
||||
smbcli_tree context: internal state for a tree connection.
|
||||
*/
|
||||
struct smbcli_tree {
|
||||
/* session layer info */
|
||||
struct smbcli_session *session;
|
||||
|
||||
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 {
|
||||
/* allow a request to be part of a list of requests */
|
||||
struct smbcli_request *next, *prev;
|
||||
|
||||
/* 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 sequence number of this packet - used for signing */
|
||||
uint_t seq_num;
|
||||
|
||||
/* list of ntcancel request for this requests */
|
||||
struct smbcli_request *ntcancel;
|
||||
|
||||
/* set if this is a one-way request, meaning we are not
|
||||
expecting a reply from the server. */
|
||||
uint_t one_way_request:1;
|
||||
|
||||
/* set this when the request should only increment the signing
|
||||
counter by one */
|
||||
uint_t sign_single_increment:1;
|
||||
|
||||
/* the mid of this packet - used to match replies */
|
||||
uint16_t mid;
|
||||
|
||||
struct request_buffer in;
|
||||
struct request_buffer out;
|
||||
|
||||
/* information on what to do with a reply when it is received
|
||||
asyncronously. If this is not setup when a reply is received then
|
||||
the reply is discarded
|
||||
|
||||
The private pointer is private to the caller of the client
|
||||
library (the application), not private to the library
|
||||
*/
|
||||
struct {
|
||||
void (*fn)(struct smbcli_request *);
|
||||
void *private;
|
||||
} 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; \
|
||||
}
|
||||
|
||||
#include "libcli/raw/interfaces.h"
|
||||
#include "libcli/raw/raw_proto.h"
|
||||
|
||||
#endif /* __LIBCLI_RAW__H__ */
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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;
|
||||
|
||||
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;
|
||||
}
|
||||
status = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS,
|
||||
io->query_secdesc.out.sd);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
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;
|
||||
NTSTATUS status;
|
||||
|
||||
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();
|
||||
if (!ndr) return NULL;
|
||||
|
||||
status = ndr_push_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, io->set_secdesc.in.sd);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ndr_push_free(ndr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nt.in.data = ndr_push_blob(ndr);
|
||||
|
||||
req = smb_raw_nttrans_send(tree, &nt);
|
||||
|
||||
ndr_push_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);
|
||||
}
|
||||
@@ -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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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);
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "smb.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(uint_t num_eas, struct ea_struct *eas)
|
||||
{
|
||||
uint_t 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 uint_t ea_name_list_size(uint_t num_names, struct ea_name *eas)
|
||||
{
|
||||
uint_t 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(uint_t num_eas, struct ea_struct *eas)
|
||||
{
|
||||
uint_t total = 0;
|
||||
int i;
|
||||
for (i=0;i<num_eas;i++) {
|
||||
uint_t len = 8 + strlen(eas[i].name.s)+1 + eas[i].value.length;
|
||||
len = (len + 3) & ~3;
|
||||
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, uint_t 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++) {
|
||||
uint_t 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);
|
||||
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, uint_t num_eas, struct ea_struct *eas)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<num_eas;i++) {
|
||||
uint_t nlen = strlen(eas[i].name.s);
|
||||
uint32_t len = 8+nlen+1+eas[i].value.length;
|
||||
uint_t pad = ((len + 3) & ~3) - 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
|
||||
*/
|
||||
uint_t ea_pull_struct(const DATA_BLOB *blob,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct ea_struct *ea)
|
||||
{
|
||||
uint8_t nlen;
|
||||
uint16_t vlen;
|
||||
|
||||
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,
|
||||
uint_t *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) {
|
||||
uint_t 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,
|
||||
uint_t *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) {
|
||||
uint_t 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;
|
||||
}
|
||||
|
||||
ofs += next_ofs;
|
||||
|
||||
if (ofs+4 > blob->length) {
|
||||
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 uint_t 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,
|
||||
uint_t *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) {
|
||||
uint_t 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, uint_t 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++) {
|
||||
uint_t 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;
|
||||
}
|
||||
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "smb.h"
|
||||
#include "libcli/raw/libcliraw.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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Rename a file - sync interface
|
||||
****************************************************************************/
|
||||
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
|
||||
*/
|
||||
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
|
||||
****************************************************************************/
|
||||
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
|
||||
****************************************************************************/
|
||||
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;
|
||||
NTSTATUS status;
|
||||
|
||||
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) {
|
||||
status = ndr_push_struct_blob(&sd_blob, mem_ctx,
|
||||
parms->ntcreatex.in.sec_desc,
|
||||
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
memcpy(nt.in.data.data, sd_blob.data, sd_blob.length);
|
||||
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
|
||||
****************************************************************************/
|
||||
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);
|
||||
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_SMB2:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open a file - async recv
|
||||
****************************************************************************/
|
||||
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, 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, 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_SMB2:
|
||||
req->status = NT_STATUS_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
failed:
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Open a file - sync interface
|
||||
****************************************************************************/
|
||||
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
|
||||
****************************************************************************/
|
||||
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:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!req) return NULL;
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Close a file - sync interface
|
||||
****************************************************************************/
|
||||
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;
|
||||
uint_t lck_size = (parms->lockx.in.mode & LOCKING_ANDX_LARGE_FILES)? 20 : 10;
|
||||
uint_t 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:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Locking calls - sync interface
|
||||
****************************************************************************/
|
||||
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(SMBchkpth, 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
|
||||
****************************************************************************/
|
||||
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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
client trans2 operations
|
||||
Copyright (C) James Myers 2003
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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) {
|
||||
uint_t n = io->num_streams;
|
||||
uint32_t nlen, len;
|
||||
ssize_t size;
|
||||
void *vstr;
|
||||
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;
|
||||
}
|
||||
size = convert_string_talloc(io->streams, CH_UTF16, CH_UNIX,
|
||||
blob.data+ofs+24, nlen, &vstr);
|
||||
if (size == -1) {
|
||||
return NT_STATUS_ILLEGAL_CHARACTER;
|
||||
}
|
||||
io->streams[n].stream_name.s = vstr;
|
||||
io->streams[n].stream_name.private_length = nlen;
|
||||
io->num_streams++;
|
||||
len = IVAL(blob.data, ofs);
|
||||
if (len > blob.length - ofs) {
|
||||
return NT_STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
if (len == 0) break;
|
||||
ofs += len;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
parse the fsinfo 'passthru' level replies
|
||||
*/
|
||||
NTSTATUS smb_raw_fileinfo_passthru_parse(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
|
||||
enum smb_fileinfo_level level,
|
||||
union smb_fileinfo *parms)
|
||||
{
|
||||
switch (level) {
|
||||
case RAW_FILEINFO_BASIC_INFORMATION:
|
||||
/* some servers return 40 bytes and some 36. w2k3 return 40, so thats
|
||||
what we should do, but we need to accept 36 */
|
||||
if (blob->length != 36) {
|
||||
FINFO_CHECK_SIZE(40);
|
||||
}
|
||||
parms->basic_info.out.create_time = smbcli_pull_nttime(blob->data, 0);
|
||||
parms->basic_info.out.access_time = smbcli_pull_nttime(blob->data, 8);
|
||||
parms->basic_info.out.write_time = smbcli_pull_nttime(blob->data, 16);
|
||||
parms->basic_info.out.change_time = smbcli_pull_nttime(blob->data, 24);
|
||||
parms->basic_info.out.attrib = IVAL(blob->data, 32);
|
||||
return NT_STATUS_OK;
|
||||
|
||||
case RAW_FILEINFO_STANDARD_INFORMATION:
|
||||
FINFO_CHECK_SIZE(24);
|
||||
parms->standard_info.out.alloc_size = BVAL(blob->data, 0);
|
||||
parms->standard_info.out.size = BVAL(blob->data, 8);
|
||||
parms->standard_info.out.nlink = IVAL(blob->data, 16);
|
||||
parms->standard_info.out.delete_pending = CVAL(blob->data, 20);
|
||||
parms->standard_info.out.directory = CVAL(blob->data, 21);
|
||||
return NT_STATUS_OK;
|
||||
|
||||
case RAW_FILEINFO_EA_INFORMATION:
|
||||
FINFO_CHECK_SIZE(4);
|
||||
parms->ea_info.out.ea_size = IVAL(blob->data, 0);
|
||||
return NT_STATUS_OK;
|
||||
|
||||
case RAW_FILEINFO_NAME_INFORMATION:
|
||||
FINFO_CHECK_MIN_SIZE(4);
|
||||
smbcli_blob_pull_string(NULL, mem_ctx, blob,
|
||||
&parms->name_info.out.fname, 0, 4, STR_UNICODE);
|
||||
return NT_STATUS_OK;
|
||||
|
||||
case RAW_FILEINFO_ALL_INFORMATION:
|
||||
FINFO_CHECK_MIN_SIZE(72);
|
||||
parms->all_info.out.create_time = smbcli_pull_nttime(blob->data, 0);
|
||||
parms->all_info.out.access_time = smbcli_pull_nttime(blob->data, 8);
|
||||
parms->all_info.out.write_time = smbcli_pull_nttime(blob->data, 16);
|
||||
parms->all_info.out.change_time = smbcli_pull_nttime(blob->data, 24);
|
||||
parms->all_info.out.attrib = IVAL(blob->data, 32);
|
||||
parms->all_info.out.alloc_size = BVAL(blob->data, 40);
|
||||
parms->all_info.out.size = BVAL(blob->data, 48);
|
||||
parms->all_info.out.nlink = IVAL(blob->data, 56);
|
||||
parms->all_info.out.delete_pending = CVAL(blob->data, 60);
|
||||
parms->all_info.out.directory = CVAL(blob->data, 61);
|
||||
#if 1
|
||||
parms->all_info.out.ea_size = IVAL(blob->data, 64);
|
||||
smbcli_blob_pull_string(NULL, mem_ctx, blob,
|
||||
&parms->all_info.out.fname, 68, 72, STR_UNICODE);
|
||||
#else
|
||||
/* this is what the CIFS spec says - and its totally
|
||||
wrong, but its useful having it here so we can
|
||||
quickly adapt to broken servers when running
|
||||
tests */
|
||||
parms->all_info.out.ea_size = IVAL(blob->data, 72);
|
||||
/* access flags 4 bytes at 76
|
||||
current_position 8 bytes at 80
|
||||
mode 4 bytes at 88
|
||||
alignment 4 bytes at 92
|
||||
*/
|
||||
smbcli_blob_pull_string(NULL, mem_ctx, blob,
|
||||
&parms->all_info.out.fname, 96, 100, STR_UNICODE);
|
||||
#endif
|
||||
return NT_STATUS_OK;
|
||||
|
||||
case RAW_FILEINFO_ALT_NAME_INFORMATION:
|
||||
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_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 = BVAL(blob->data, 0x58);
|
||||
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: {
|
||||
NTSTATUS status;
|
||||
|
||||
parms->query_secdesc.out.sd = talloc(mem_ctx, struct security_descriptor);
|
||||
NT_STATUS_HAVE_NO_MEMORY(parms->query_secdesc.out.sd);
|
||||
|
||||
status = ndr_pull_struct_blob(blob, mem_ctx,
|
||||
parms->query_secdesc.out.sd,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
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:
|
||||
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:
|
||||
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_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_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);
|
||||
|
||||
}
|
||||
|
||||
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 (!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 (!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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
NTSTATUS smb_raw_pathinfo_recv(struct smbcli_request *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
union smb_fileinfo *parms)
|
||||
{
|
||||
/* recv is idential to fileinfo */
|
||||
return smb_raw_fileinfo_recv(req, mem_ctx, parms);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Query path info (sync interface)
|
||||
****************************************************************************/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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 (!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:
|
||||
QFS_CHECK_SIZE(64);
|
||||
status = ndr_pull_struct_blob(&blob, mem_ctx, &fsinfo->objectid_information.out.guid,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_GUID);
|
||||
for (i=0;i<6;i++) {
|
||||
fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
failed:
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Query FSInfo raw interface (sync interface)
|
||||
****************************************************************************/
|
||||
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);
|
||||
}
|
||||
@@ -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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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, 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 = (uint16_t *)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
|
||||
*/
|
||||
_PUBLIC_ 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);
|
||||
}
|
||||
@@ -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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "smb.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);
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "system/time.h"
|
||||
|
||||
static const struct {
|
||||
enum protocol_types prot;
|
||||
const char *name;
|
||||
} prots[] = {
|
||||
{PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
|
||||
{PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
|
||||
{PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
|
||||
{PROTOCOL_LANMAN1,"LANMAN1.0"},
|
||||
{PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
|
||||
{PROTOCOL_LANMAN2,"LM1.2X002"},
|
||||
{PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
|
||||
{PROTOCOL_LANMAN2,"LANMAN2.1"},
|
||||
{PROTOCOL_LANMAN2,"Samba"},
|
||||
{PROTOCOL_NT1,"NT LANMAN 1.0"},
|
||||
{PROTOCOL_NT1,"NT LM 0.12"},
|
||||
};
|
||||
|
||||
/*
|
||||
Send a negprot command.
|
||||
*/
|
||||
struct smbcli_request *smb_raw_negotiate_send(struct smbcli_transport *transport,
|
||||
int maxprotocol)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
int i;
|
||||
uint16_t flags2 = 0;
|
||||
|
||||
req = smbcli_request_setup_transport(transport, SMBnegprot, 0, 0);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags2 |= FLAGS2_32_BIT_ERROR_CODES;
|
||||
if (lp_unicode()) {
|
||||
flags2 |= FLAGS2_UNICODE_STRINGS;
|
||||
}
|
||||
flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
|
||||
flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
|
||||
flags2 |= FLAGS2_IS_LONG_NAME;
|
||||
|
||||
if (transport->options.use_spnego) {
|
||||
flags2 |= FLAGS2_EXTENDED_SECURITY;
|
||||
}
|
||||
|
||||
SSVAL(req->out.hdr,HDR_FLG2, flags2);
|
||||
|
||||
/* setup the protocol strings */
|
||||
for (i=0; i < ARRAY_SIZE(prots) && prots[i].prot <= maxprotocol; i++) {
|
||||
smbcli_req_append_bytes(req, (const uint8_t *)"\2", 1);
|
||||
smbcli_req_append_string(req, prots[i].name, STR_TERMINATE | STR_ASCII);
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/*
|
||||
Send a negprot command.
|
||||
*/
|
||||
NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req)
|
||||
{
|
||||
struct smbcli_transport *transport = req->transport;
|
||||
int protocol;
|
||||
|
||||
if (!smbcli_request_receive(req) ||
|
||||
smbcli_request_is_error(req)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
SMBCLI_CHECK_MIN_WCT(req, 1);
|
||||
|
||||
protocol = SVALS(req->in.vwv, VWV(0));
|
||||
|
||||
if (protocol >= ARRAY_SIZE(prots) || protocol < 0) {
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
transport->negotiate.protocol = prots[protocol].prot;
|
||||
|
||||
if (transport->negotiate.protocol >= PROTOCOL_NT1) {
|
||||
NTTIME ntt;
|
||||
|
||||
/* NT protocol */
|
||||
SMBCLI_CHECK_WCT(req, 17);
|
||||
transport->negotiate.sec_mode = CVAL(req->in.vwv,VWV(1));
|
||||
transport->negotiate.max_mux = SVAL(req->in.vwv,VWV(1)+1);
|
||||
transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1);
|
||||
transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(7)+1);
|
||||
transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
|
||||
|
||||
/* this time arrives in real GMT */
|
||||
ntt = smbcli_pull_nttime(req->in.vwv, VWV(11)+1);
|
||||
transport->negotiate.server_time = nt_time_to_unix(ntt);
|
||||
transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
|
||||
transport->negotiate.key_len = CVAL(req->in.vwv,VWV(16)+1);
|
||||
|
||||
if (transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
|
||||
if (req->in.data_size < 16) {
|
||||
goto failed;
|
||||
}
|
||||
transport->negotiate.server_guid = smbcli_req_pull_blob(req, transport, req->in.data, 16);
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(req, transport, req->in.data + 16, req->in.data_size - 16);
|
||||
} else {
|
||||
if (req->in.data_size < (transport->negotiate.key_len)) {
|
||||
goto failed;
|
||||
}
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(req, transport, req->in.data, transport->negotiate.key_len);
|
||||
smbcli_req_pull_string(req, transport, &transport->negotiate.server_domain,
|
||||
req->in.data+transport->negotiate.key_len,
|
||||
req->in.data_size-transport->negotiate.key_len, STR_UNICODE|STR_NOALIGN);
|
||||
/* here comes the server name */
|
||||
}
|
||||
|
||||
if (transport->negotiate.capabilities & CAP_RAW_MODE) {
|
||||
transport->negotiate.readbraw_supported = True;
|
||||
transport->negotiate.writebraw_supported = True;
|
||||
}
|
||||
} else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) {
|
||||
SMBCLI_CHECK_WCT(req, 13);
|
||||
transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1));
|
||||
transport->negotiate.max_xmit = SVAL(req->in.vwv,VWV(2));
|
||||
transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(6));
|
||||
transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(10)) * 60;
|
||||
|
||||
/* this time is converted to GMT by raw_pull_dos_date */
|
||||
transport->negotiate.server_time = raw_pull_dos_date(transport,
|
||||
req->in.vwv+VWV(8));
|
||||
if ((SVAL(req->in.vwv,VWV(5)) & 0x1)) {
|
||||
transport->negotiate.readbraw_supported = 1;
|
||||
}
|
||||
if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) {
|
||||
transport->negotiate.writebraw_supported = 1;
|
||||
}
|
||||
transport->negotiate.secblob = smbcli_req_pull_blob(req, transport,
|
||||
req->in.data, req->in.data_size);
|
||||
} else {
|
||||
/* the old core protocol */
|
||||
transport->negotiate.sec_mode = 0;
|
||||
transport->negotiate.server_time = time(NULL);
|
||||
transport->negotiate.max_xmit = transport->options.max_xmit;
|
||||
transport->negotiate.server_zone = get_time_zone(transport->negotiate.server_time);
|
||||
}
|
||||
|
||||
/* a way to force ascii SMB */
|
||||
if (!lp_unicode()) {
|
||||
transport->negotiate.capabilities &= ~CAP_UNICODE;
|
||||
}
|
||||
|
||||
if (!lp_nt_status_support()) {
|
||||
transport->negotiate.capabilities &= ~CAP_STATUS32;
|
||||
}
|
||||
|
||||
failed:
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Send a negprot command (sync interface)
|
||||
*/
|
||||
NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, int maxprotocol)
|
||||
{
|
||||
struct smbcli_request *req = smb_raw_negotiate_send(transport, maxprotocol);
|
||||
return smb_raw_negotiate_recv(req);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
|
||||
/****************************************************************************
|
||||
change notify (async send)
|
||||
****************************************************************************/
|
||||
struct smbcli_request *smb_raw_changenotify_send(struct smbcli_tree *tree, union smb_notify *parms)
|
||||
{
|
||||
struct smb_nttrans nt;
|
||||
uint16_t setup[4];
|
||||
|
||||
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)
|
||||
****************************************************************************/
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
handle ntcancel replies from the server,
|
||||
as the MID of the real reply and the ntcancel reply is the same
|
||||
we need to do find out to what request the reply belongs
|
||||
****************************************************************************/
|
||||
struct smbcli_request *smbcli_handle_ntcancel_reply(struct smbcli_request *req,
|
||||
size_t len, const uint8_t *hdr)
|
||||
{
|
||||
struct smbcli_request *ntcancel;
|
||||
|
||||
if (!req) return req;
|
||||
|
||||
if (!req->ntcancel) return req;
|
||||
|
||||
if (len >= MIN_SMB_SIZE + NBT_HDR_SIZE &&
|
||||
(CVAL(hdr, HDR_FLG) & FLAG_REPLY) &&
|
||||
CVAL(hdr,HDR_COM) == SMBntcancel) {
|
||||
ntcancel = req->ntcancel;
|
||||
DLIST_REMOVE(req->ntcancel, ntcancel);
|
||||
|
||||
/*
|
||||
* TODO: untill we understand how the
|
||||
* smb_signing works for this case we
|
||||
* return NULL, to just ignore the packet
|
||||
*/
|
||||
/*return ntcancel;*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
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)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = smbcli_request_setup_transport(oldreq->transport, SMBntcancel, 0, 0);
|
||||
|
||||
SSVAL(req->out.hdr, HDR_MID, SVAL(oldreq->out.hdr, HDR_MID));
|
||||
SSVAL(req->out.hdr, HDR_PID, SVAL(oldreq->out.hdr, HDR_PID));
|
||||
SSVAL(req->out.hdr, HDR_TID, SVAL(oldreq->out.hdr, HDR_TID));
|
||||
SSVAL(req->out.hdr, HDR_UID, SVAL(oldreq->out.hdr, HDR_UID));
|
||||
|
||||
/* this request does not expect a reply, so tell the signing
|
||||
subsystem not to allocate an id for a reply */
|
||||
req->sign_single_increment = 1;
|
||||
req->one_way_request = 1;
|
||||
|
||||
/*
|
||||
* smbcli_request_send() free's oneway requests
|
||||
* but we want to keep it under oldreq->ntcancel
|
||||
*/
|
||||
if (!talloc_reference(oldreq, req)) {
|
||||
talloc_free(req);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
smbcli_request_send(req);
|
||||
|
||||
DLIST_ADD_END(oldreq->ntcancel, req, struct smbcli_request *);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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)
|
||||
****************************************************************************/
|
||||
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;
|
||||
}
|
||||
|
||||
/* the transport layer needs to know that a readbraw is pending
|
||||
and handle receives a little differently */
|
||||
if (parms->generic.level == RAW_READ_READBRAW) {
|
||||
tree->session->transport->readbraw_pending = 1;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
low level read operation (async recv)
|
||||
****************************************************************************/
|
||||
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, 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, 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));
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) ||
|
||||
!smbcli_raw_pull_data(req, 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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms)
|
||||
{
|
||||
if (!smbcli_request_receive(req) ||
|
||||
smbcli_request_is_error(req)) {
|
||||
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)
|
||||
****************************************************************************/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,973 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/events/events.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
|
||||
|
||||
/* destroy a request structure and return final status */
|
||||
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->transport) {
|
||||
/* remove it from the list of pending requests (a null op if
|
||||
its not in the list) */
|
||||
DLIST_REMOVE(req->transport->pending_recv, req);
|
||||
}
|
||||
|
||||
if (req->state == SMBCLI_REQUEST_ERROR &&
|
||||
NT_STATUS_IS_OK(req->status)) {
|
||||
req->status = NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
status = req->status;
|
||||
talloc_free(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
low-level function to setup a request buffer for a non-SMB packet
|
||||
at the transport level
|
||||
*/
|
||||
struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, size_t size)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = talloc(transport, struct smbcli_request);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(req);
|
||||
|
||||
/* setup the request context */
|
||||
req->state = SMBCLI_REQUEST_INIT;
|
||||
req->transport = transport;
|
||||
req->session = NULL;
|
||||
req->tree = NULL;
|
||||
req->out.size = size;
|
||||
|
||||
/* over allocate by a small amount */
|
||||
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
|
||||
|
||||
req->out.buffer = talloc_size(req, req->out.allocated);
|
||||
if (!req->out.buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SIVAL(req->out.buffer, 0, 0);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup a SMB packet at transport level
|
||||
*/
|
||||
struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
|
||||
uint8_t command, uint_t wct, uint_t buflen)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
|
||||
|
||||
if (!req) 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);
|
||||
|
||||
if (command != SMBtranss && command != SMBtranss2) {
|
||||
/* assign a mid */
|
||||
req->mid = smbcli_transport_next_mid(transport);
|
||||
}
|
||||
|
||||
/* 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, req->mid);
|
||||
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, uint_t wct, size_t buflen)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
|
||||
|
||||
if (!req) return NULL;
|
||||
|
||||
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,
|
||||
uint_t wct, uint_t buflen)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
|
||||
req = smbcli_request_setup_session(tree->session, command, wct, buflen);
|
||||
if (req) {
|
||||
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, uint_t 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, uint_t 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,
|
||||
uint_t wct, size_t buflen)
|
||||
{
|
||||
uint_t new_size = 1 + (wct*2) + 2 + buflen;
|
||||
|
||||
SSVAL(req->out.vwv, VWV(0), command);
|
||||
SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
|
||||
|
||||
smbcli_req_grow_allocation(req, req->out.data_size + new_size);
|
||||
|
||||
req->out.vwv = req->out.buffer + req->out.size + 1;
|
||||
SCVAL(req->out.vwv, -1, wct);
|
||||
SSVAL(req->out.vwv, VWV(wct), buflen);
|
||||
|
||||
req->out.size += new_size;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
aadvance to the next chained reply in a request
|
||||
*/
|
||||
NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
|
||||
{
|
||||
uint8_t *buffer;
|
||||
|
||||
if (CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE) {
|
||||
return NT_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
buffer = req->in.hdr + SVAL(req->in.vwv, VWV(1));
|
||||
|
||||
if (buffer + 3 > req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
req->in.vwv = buffer + 1;
|
||||
req->in.wct = CVAL(buffer, 0);
|
||||
if (buffer + 3 + req->in.wct*2 > req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
req->in.data = req->in.vwv + 2 + req->in.wct * 2;
|
||||
req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
|
||||
|
||||
if (buffer + 3 + req->in.wct*2 + req->in.data_size >
|
||||
req->in.buffer + req->in.size) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a message
|
||||
*/
|
||||
BOOL smbcli_request_send(struct smbcli_request *req)
|
||||
{
|
||||
if (IVAL(req->out.buffer, 0) == 0) {
|
||||
_smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
|
||||
}
|
||||
|
||||
smbcli_request_calculate_sign_mac(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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
return req->state == SMBCLI_REQUEST_DONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
receive another reply to a request - this is used for requests that
|
||||
have multi-part replies (such as SMBtrans2)
|
||||
*/
|
||||
BOOL smbcli_request_receive_more(struct smbcli_request *req)
|
||||
{
|
||||
req->state = SMBCLI_REQUEST_RECV;
|
||||
DLIST_ADD(req->transport->pending_recv, req);
|
||||
|
||||
return smbcli_request_receive(req);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle oplock break requests from the server - return True if the request was
|
||||
an oplock break
|
||||
*/
|
||||
BOOL smbcli_handle_oplock_break(struct smbcli_transport *transport, uint_t len, const uint8_t *hdr, const uint8_t *vwv)
|
||||
{
|
||||
/* we must be very fussy about what we consider an oplock break to avoid
|
||||
matching readbraw replies */
|
||||
if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
|
||||
(CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
|
||||
CVAL(hdr,HDR_COM) != SMBlockingX ||
|
||||
SVAL(hdr, HDR_MID) != 0xFFFF ||
|
||||
SVAL(vwv,VWV(6)) != 0 ||
|
||||
SVAL(vwv,VWV(7)) != 0) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (transport->oplock.handler) {
|
||||
uint16_t tid = SVAL(hdr, HDR_TID);
|
||||
uint16_t fnum = SVAL(vwv,VWV(2));
|
||||
uint8_t level = CVAL(vwv,VWV(3)+1);
|
||||
transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
wait for a reply to be received for a packet that just returns an error
|
||||
code and nothing more
|
||||
*/
|
||||
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, uint_t 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, uint_t 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, uint_t 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 smbcli_request *req, TALLOC_CTX *mem_ctx,
|
||||
char **dest, const uint8_t *src, int byte_len, uint_t flags)
|
||||
{
|
||||
int src_len, src_len2, alignment=0;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
|
||||
src++;
|
||||
alignment=1;
|
||||
if (byte_len != -1) {
|
||||
byte_len--;
|
||||
}
|
||||
}
|
||||
|
||||
src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
|
||||
if (src_len < 0) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (byte_len != -1 && src_len > byte_len) {
|
||||
src_len = byte_len;
|
||||
}
|
||||
|
||||
src_len2 = utf16_len_n(src, src_len);
|
||||
|
||||
/* ucs2 strings must be at least 2 bytes long */
|
||||
if (src_len2 < 2) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest);
|
||||
if (ret == -1) {
|
||||
*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 smbcli_request *req, TALLOC_CTX *mem_ctx,
|
||||
char **dest, const uint8_t *src, int byte_len, uint_t flags)
|
||||
{
|
||||
int src_len, src_len2;
|
||||
ssize_t ret;
|
||||
|
||||
src_len = req->in.data_size - PTR_DIFF(src, req->in.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);
|
||||
|
||||
if (ret == -1) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
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 smbcli_request *req, TALLOC_CTX *mem_ctx,
|
||||
char **dest, const uint8_t *src, int byte_len, uint_t flags)
|
||||
{
|
||||
if (!(flags & STR_ASCII) &&
|
||||
(((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
|
||||
return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
|
||||
}
|
||||
|
||||
return smbcli_req_pull_ascii(req, 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 smbcli_request *req, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
|
||||
{
|
||||
int src_len;
|
||||
|
||||
src_len = req->in.data_size - PTR_DIFF(src, req->in.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 smbcli_request *req, const uint8_t *ptr, uint32_t count)
|
||||
{
|
||||
/* be careful with wraparound! */
|
||||
if (ptr < req->in.data ||
|
||||
ptr >= req->in.data + req->in.data_size ||
|
||||
count > req->in.data_size ||
|
||||
ptr + count > req->in.data + req->in.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 smbcli_request *req, const uint8_t *src, int len, uint8_t *dest)
|
||||
{
|
||||
if (len == 0) return True;
|
||||
|
||||
if (smbcli_req_data_oob(req, 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
|
||||
*/
|
||||
static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
|
||||
const DATA_BLOB *blob, const char **dest,
|
||||
const uint8_t *src, int byte_len, uint_t flags)
|
||||
{
|
||||
int src_len, src_len2, alignment=0;
|
||||
ssize_t ret;
|
||||
char *dest2;
|
||||
|
||||
if (src < blob->data ||
|
||||
src >= (blob->data + blob->length)) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
src_len = blob->length - PTR_DIFF(src, blob->data);
|
||||
|
||||
if (byte_len != -1 && src_len > byte_len) {
|
||||
src_len = byte_len;
|
||||
}
|
||||
|
||||
if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
|
||||
src++;
|
||||
alignment=1;
|
||||
src_len--;
|
||||
}
|
||||
|
||||
if (src_len < 2) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
src_len2 = utf16_len_n(src, src_len);
|
||||
|
||||
ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
|
||||
if (ret == -1) {
|
||||
*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, uint_t flags)
|
||||
{
|
||||
int src_len, src_len2;
|
||||
ssize_t 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);
|
||||
|
||||
if (ret == -1) {
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
*dest = dest2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
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,
|
||||
uint_t 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,
|
||||
uint_t 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, uint_t 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;
|
||||
}
|
||||
@@ -0,0 +1,796 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
client directory search routines
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
|
||||
{
|
||||
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, mem_ctx, &name, p+30, 13, STR_ASCII);
|
||||
search_data.search.name = name;
|
||||
if (!callback(private, &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,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
|
||||
{
|
||||
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, 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,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
|
||||
{
|
||||
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, 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,
|
||||
uint_t *next_ofs,
|
||||
uint_t str_flags)
|
||||
{
|
||||
uint_t 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);
|
||||
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)
|
||||
{
|
||||
uint_t 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_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: {
|
||||
uint_t 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,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
|
||||
{
|
||||
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;
|
||||
uint_t 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, &search_data)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == 0) break;
|
||||
|
||||
blob2.data += len;
|
||||
blob2.length -= len;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Implements trans2findfirst2 and old search
|
||||
*/
|
||||
NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
union smb_search_first *io, void *private,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
{
|
||||
DATA_BLOB p_blob, d_blob;
|
||||
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, 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, 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,
|
||||
BOOL (*callback)(void *private, union smb_search_data *file))
|
||||
{
|
||||
DATA_BLOB p_blob, d_blob;
|
||||
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, 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, 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);
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
RAW_SFILEINFO_* calls
|
||||
Copyright (C) James Myers 2003
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/libcliraw.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)
|
||||
{
|
||||
uint_t len;
|
||||
|
||||
#define NEED_BLOB(n) do { \
|
||||
*blob = data_blob_talloc(mem_ctx, NULL, n); \
|
||||
if (blob->data == NULL) 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_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: {
|
||||
NTSTATUS status;
|
||||
|
||||
status = ndr_push_struct_blob(blob, mem_ctx,
|
||||
parms->set_secdesc.in.sd,
|
||||
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
|
||||
if (!NT_STATUS_IS_OK(status)) return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Unhandled levels */
|
||||
case RAW_SFILEINFO_1023:
|
||||
case RAW_SFILEINFO_1025:
|
||||
case RAW_SFILEINFO_1029:
|
||||
case RAW_SFILEINFO_1032:
|
||||
case RAW_SFILEINFO_1039:
|
||||
case RAW_SFILEINFO_1040:
|
||||
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_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_1023:
|
||||
case RAW_SFILEINFO_1025:
|
||||
case RAW_SFILEINFO_1029:
|
||||
case RAW_SFILEINFO_1032:
|
||||
case RAW_SFILEINFO_1039:
|
||||
case RAW_SFILEINFO_1040:
|
||||
return smb_raw_setfileinfo_passthru(mem_ctx, parms->generic.level,
|
||||
parms, blob);
|
||||
|
||||
/* Unhandled levels */
|
||||
|
||||
case RAW_SFILEINFO_UNIX_LINK:
|
||||
case RAW_SFILEINFO_UNIX_HLINK:
|
||||
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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
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)
|
||||
****************************************************************************/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
|
||||
#define TORTURE_TRANS_DATA 0
|
||||
|
||||
/*
|
||||
check out of bounds for incoming data
|
||||
*/
|
||||
static BOOL raw_trans_oob(struct smbcli_request *req,
|
||||
uint_t offset, uint_t count)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
|
||||
if (count == 0) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ptr = req->in.hdr + offset;
|
||||
|
||||
/* be careful with wraparound! */
|
||||
if (ptr < req->in.data ||
|
||||
ptr >= req->in.data + req->in.data_size ||
|
||||
count > req->in.data_size ||
|
||||
ptr + count > req->in.data + req->in.data_size) {
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
receive a SMB trans or trans2 response allocating the necessary memory
|
||||
****************************************************************************/
|
||||
NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_trans2 *parms)
|
||||
{
|
||||
int total_data=0;
|
||||
int total_param=0;
|
||||
uint8_t *tdata;
|
||||
uint8_t *tparam;
|
||||
|
||||
parms->out.data.length = 0;
|
||||
parms->out.data.data = NULL;
|
||||
parms->out.params.length = 0;
|
||||
parms->out.params.data = NULL;
|
||||
|
||||
if (!smbcli_request_receive(req)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* An NT RPC pipe call can return ERRDOS, ERRmoredata
|
||||
* to a trans call. This is not an error and should not
|
||||
* be treated as such.
|
||||
*/
|
||||
if (NT_STATUS_IS_ERR(req->status)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
SMBCLI_CHECK_MIN_WCT(req, 10);
|
||||
|
||||
/* parse out the lengths */
|
||||
total_data = SVAL(req->in.vwv, VWV(1));
|
||||
total_param = SVAL(req->in.vwv, VWV(0));
|
||||
|
||||
/* allocate it */
|
||||
if (total_data != 0) {
|
||||
tdata = talloc_size(mem_ctx, total_data);
|
||||
if (!tdata) {
|
||||
DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data));
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
parms->out.data.data = tdata;
|
||||
}
|
||||
|
||||
if (total_param != 0) {
|
||||
tparam = talloc_size(mem_ctx, total_param);
|
||||
if (!tparam) {
|
||||
DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param));
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
parms->out.params.data = tparam;
|
||||
}
|
||||
|
||||
parms->out.setup_count = SVAL(req->in.vwv, VWV(9));
|
||||
SMBCLI_CHECK_WCT(req, 10 + parms->out.setup_count);
|
||||
|
||||
if (parms->out.setup_count > 0) {
|
||||
int i;
|
||||
parms->out.setup = talloc_array(mem_ctx, uint16_t, parms->out.setup_count);
|
||||
if (!parms->out.setup) {
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
for (i=0;i<parms->out.setup_count;i++) {
|
||||
parms->out.setup[i] = SVAL(req->in.vwv, VWV(10+i));
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint16_t param_count, param_ofs, param_disp;
|
||||
uint16_t data_count, data_ofs, data_disp;
|
||||
uint16_t total_data2, total_param2;
|
||||
|
||||
/* parse out the total lengths again - they can shrink! */
|
||||
total_data2 = SVAL(req->in.vwv, VWV(1));
|
||||
total_param2 = SVAL(req->in.vwv, VWV(0));
|
||||
|
||||
if (total_data2 > total_data ||
|
||||
total_param2 > total_param) {
|
||||
/* they must *only* shrink */
|
||||
DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
total_data = total_data2;
|
||||
total_param = total_param2;
|
||||
|
||||
/* parse params for this lump */
|
||||
param_count = SVAL(req->in.vwv, VWV(3));
|
||||
param_ofs = SVAL(req->in.vwv, VWV(4));
|
||||
param_disp = SVAL(req->in.vwv, VWV(5));
|
||||
|
||||
data_count = SVAL(req->in.vwv, VWV(6));
|
||||
data_ofs = SVAL(req->in.vwv, VWV(7));
|
||||
data_disp = SVAL(req->in.vwv, VWV(8));
|
||||
|
||||
if (data_count + data_disp > total_data ||
|
||||
param_count + param_disp > total_param) {
|
||||
DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
/* check the server isn't being nasty */
|
||||
if (raw_trans_oob(req, param_ofs, param_count) ||
|
||||
raw_trans_oob(req, data_ofs, data_count)) {
|
||||
DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
if (data_count) {
|
||||
memcpy(parms->out.data.data + data_disp,
|
||||
req->in.hdr + data_ofs,
|
||||
data_count);
|
||||
}
|
||||
|
||||
if (param_count) {
|
||||
memcpy(parms->out.params.data + param_disp,
|
||||
req->in.hdr + param_ofs,
|
||||
param_count);
|
||||
}
|
||||
|
||||
parms->out.data.length += data_count;
|
||||
parms->out.params.length += param_count;
|
||||
|
||||
if (total_data <= parms->out.data.length && total_param <= parms->out.params.length)
|
||||
break;
|
||||
|
||||
if (!smbcli_request_receive_more(req)) {
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
}
|
||||
|
||||
failed:
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
NTSTATUS smb_raw_trans_recv(struct smbcli_request *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_trans2 *parms)
|
||||
{
|
||||
return smb_raw_trans2_recv(req, mem_ctx, parms);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
trans/trans2 raw async interface - only BLOBs used in this interface.
|
||||
*/
|
||||
struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree,
|
||||
struct smb_trans2 *parms,
|
||||
uint8_t command)
|
||||
{
|
||||
int wct = 14 + parms->in.setup_count;
|
||||
struct smbcli_request *req, *req2;
|
||||
uint8_t *outdata,*outparam;
|
||||
int i;
|
||||
int padding;
|
||||
size_t namelen = 0;
|
||||
uint16_t data_disp, data_length, max_data;
|
||||
|
||||
if (parms->in.params.length > UINT16_MAX ||
|
||||
parms->in.data.length > UINT16_MAX) {
|
||||
DEBUG(3,("Attempt to send invalid trans2 request (params %u, data %u)\n",
|
||||
(unsigned)parms->in.params.length, (unsigned)parms->in.data.length));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (command == SMBtrans)
|
||||
padding = 1;
|
||||
else
|
||||
padding = 3;
|
||||
|
||||
req = smbcli_request_setup(tree, command, wct, padding);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Watch out, this changes the req->out.* pointers */
|
||||
if (command == SMBtrans && parms->in.trans_name) {
|
||||
namelen = smbcli_req_append_string(req, parms->in.trans_name,
|
||||
STR_TERMINATE);
|
||||
}
|
||||
|
||||
/* fill in SMB parameters */
|
||||
outparam = req->out.data + padding;
|
||||
outdata = outparam + parms->in.params.length;
|
||||
|
||||
/* make sure we don't leak data via the padding */
|
||||
memset(req->out.data, 0, padding);
|
||||
|
||||
data_length = parms->in.data.length;
|
||||
|
||||
max_data = smb_raw_max_trans_data(tree, parms->in.params.length);
|
||||
if (max_data < data_length) {
|
||||
data_length = max_data;
|
||||
}
|
||||
|
||||
#if TORTURE_TRANS_DATA
|
||||
if (data_length > 1) {
|
||||
data_length /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* primary request */
|
||||
SSVAL(req->out.vwv,VWV(0),parms->in.params.length);
|
||||
SSVAL(req->out.vwv,VWV(1),parms->in.data.length);
|
||||
SSVAL(req->out.vwv,VWV(2),parms->in.max_param);
|
||||
SSVAL(req->out.vwv,VWV(3),parms->in.max_data);
|
||||
SSVAL(req->out.vwv,VWV(4),parms->in.max_setup);
|
||||
SSVAL(req->out.vwv,VWV(5),parms->in.flags);
|
||||
SIVAL(req->out.vwv,VWV(6),parms->in.timeout);
|
||||
SSVAL(req->out.vwv,VWV(8),0); /* reserved */
|
||||
SSVAL(req->out.vwv,VWV(9),parms->in.params.length);
|
||||
SSVAL(req->out.vwv,VWV(10),PTR_DIFF(outparam,req->out.hdr)+namelen);
|
||||
SSVAL(req->out.vwv,VWV(11),data_length);
|
||||
SSVAL(req->out.vwv,VWV(12),PTR_DIFF(outdata,req->out.hdr)+namelen);
|
||||
SSVAL(req->out.vwv,VWV(13),parms->in.setup_count);
|
||||
for (i=0;i<parms->in.setup_count;i++) {
|
||||
SSVAL(req->out.vwv,VWV(14)+i*2,parms->in.setup[i]);
|
||||
}
|
||||
if (parms->in.params.data) {
|
||||
smbcli_req_append_blob(req, &parms->in.params);
|
||||
}
|
||||
if (parms->in.data.data) {
|
||||
DATA_BLOB data;
|
||||
data.data = parms->in.data.data;
|
||||
data.length = data_length;
|
||||
smbcli_req_append_blob(req, &data);
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data_disp = data_length;
|
||||
|
||||
|
||||
if (data_disp != parms->in.data.length) {
|
||||
/* TODO: this should be done asynchronously .... */
|
||||
if (!smbcli_request_receive(req) ||
|
||||
!NT_STATUS_IS_OK(req->status)) {
|
||||
return req;
|
||||
}
|
||||
|
||||
req->state = SMBCLI_REQUEST_RECV;
|
||||
DLIST_ADD(req->transport->pending_recv, req);
|
||||
}
|
||||
|
||||
|
||||
while (data_disp != parms->in.data.length) {
|
||||
data_length = parms->in.data.length - data_disp;
|
||||
|
||||
max_data = smb_raw_max_trans_data(tree, 0);
|
||||
if (max_data < data_length) {
|
||||
data_length = max_data;
|
||||
}
|
||||
|
||||
#if TORTURE_TRANS_DATA
|
||||
if (data_length > 1) {
|
||||
data_length /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
req2 = smbcli_request_setup(tree, command+1, 9, data_length);
|
||||
if (!req2) {
|
||||
return NULL;
|
||||
}
|
||||
req2->mid = req->mid;
|
||||
SSVAL(req2->out.hdr, HDR_MID, req2->mid);
|
||||
|
||||
outdata = req2->out.data;
|
||||
|
||||
SSVAL(req2->out.vwv,VWV(0), parms->in.params.length);
|
||||
SSVAL(req2->out.vwv,VWV(1), parms->in.data.length);
|
||||
SSVAL(req2->out.vwv,VWV(2), 0);
|
||||
SSVAL(req2->out.vwv,VWV(3), 0);
|
||||
SSVAL(req2->out.vwv,VWV(4), 0);
|
||||
SSVAL(req2->out.vwv,VWV(5), data_length);
|
||||
SSVAL(req2->out.vwv,VWV(6), PTR_DIFF(outdata,req2->out.hdr));
|
||||
SSVAL(req2->out.vwv,VWV(7), data_disp);
|
||||
SSVAL(req2->out.vwv,VWV(8), 0xFFFF);
|
||||
|
||||
if (data_length != 0) {
|
||||
memcpy(req2->out.data, parms->in.data.data + data_disp,
|
||||
data_length);
|
||||
}
|
||||
|
||||
data_disp += data_length;
|
||||
|
||||
req2->one_way_request = 1;
|
||||
|
||||
if (!smbcli_request_send(req2)) {
|
||||
smbcli_request_destroy(req2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->seq_num = req2->seq_num;
|
||||
}
|
||||
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
trans/trans2 raw async interface - only BLOBs used in this interface.
|
||||
note that this doesn't yet support multi-part requests
|
||||
*/
|
||||
struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree,
|
||||
struct smb_trans2 *parms)
|
||||
{
|
||||
return smb_raw_trans_send_backend(tree, parms, SMBtrans);
|
||||
}
|
||||
|
||||
struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree,
|
||||
struct smb_trans2 *parms)
|
||||
{
|
||||
return smb_raw_trans_send_backend(tree, parms, SMBtrans2);
|
||||
}
|
||||
|
||||
/*
|
||||
trans2 synchronous blob interface
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
trans synchronous blob interface
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
receive a SMB nttrans response allocating the necessary memory
|
||||
****************************************************************************/
|
||||
NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct smb_nttrans *parms)
|
||||
{
|
||||
uint32_t total_data, recvd_data=0;
|
||||
uint32_t total_param, recvd_param=0;
|
||||
|
||||
if (!smbcli_request_receive(req) ||
|
||||
smbcli_request_is_error(req)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
|
||||
DEBUG(0,("smb_raw_receive_nttrans: Expected %s response, got command 0x%02x\n",
|
||||
"SMBnttrans",
|
||||
CVAL(req->in.hdr,HDR_COM)));
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
SMBCLI_CHECK_MIN_WCT(req, 18);
|
||||
|
||||
/* parse out the lengths */
|
||||
total_param = IVAL(req->in.vwv, 3);
|
||||
total_data = IVAL(req->in.vwv, 7);
|
||||
|
||||
parms->out.data = data_blob_talloc(mem_ctx, NULL, total_data);
|
||||
parms->out.params = data_blob_talloc(mem_ctx, NULL, total_param);
|
||||
|
||||
if (parms->out.data.length != total_data ||
|
||||
parms->out.params.length != total_param) {
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
parms->out.setup_count = CVAL(req->in.vwv, 35);
|
||||
SMBCLI_CHECK_WCT(req, 18 + parms->out.setup_count);
|
||||
|
||||
if (parms->out.setup_count > 0) {
|
||||
int i;
|
||||
parms->out.setup = talloc_array(mem_ctx, uint16_t, parms->out.setup_count);
|
||||
if (!parms->out.setup) {
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
for (i=0;i<parms->out.setup_count;i++) {
|
||||
parms->out.setup[i] = SVAL(req->in.vwv, VWV(18+i));
|
||||
}
|
||||
}
|
||||
|
||||
while (recvd_data < total_data ||
|
||||
recvd_param < total_param) {
|
||||
uint32_t param_count, param_ofs, param_disp;
|
||||
uint32_t data_count, data_ofs, data_disp;
|
||||
uint32_t total_data2, total_param2;
|
||||
|
||||
/* parse out the total lengths again - they can shrink! */
|
||||
total_param2 = IVAL(req->in.vwv, 3);
|
||||
total_data2 = IVAL(req->in.vwv, 7);
|
||||
|
||||
if (total_data2 > total_data ||
|
||||
total_param2 > total_param) {
|
||||
/* they must *only* shrink */
|
||||
DEBUG(1,("smb_raw_receive_nttrans: data/params expanded!\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
total_data = total_data2;
|
||||
total_param = total_param2;
|
||||
parms->out.data.length = total_data;
|
||||
parms->out.params.length = total_param;
|
||||
|
||||
/* parse params for this lump */
|
||||
param_count = IVAL(req->in.vwv, 11);
|
||||
param_ofs = IVAL(req->in.vwv, 15);
|
||||
param_disp = IVAL(req->in.vwv, 19);
|
||||
|
||||
data_count = IVAL(req->in.vwv, 23);
|
||||
data_ofs = IVAL(req->in.vwv, 27);
|
||||
data_disp = IVAL(req->in.vwv, 31);
|
||||
|
||||
if (data_count + data_disp > total_data ||
|
||||
param_count + param_disp > total_param) {
|
||||
DEBUG(1,("smb_raw_receive_nttrans: Buffer overflow\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
/* check the server isn't being nasty */
|
||||
if (raw_trans_oob(req, param_ofs, param_count) ||
|
||||
raw_trans_oob(req, data_ofs, data_count)) {
|
||||
DEBUG(1,("smb_raw_receive_nttrans: out of bounds parameters!\n"));
|
||||
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
if (data_count) {
|
||||
memcpy(parms->out.data.data + data_disp,
|
||||
req->in.hdr + data_ofs,
|
||||
data_count);
|
||||
}
|
||||
|
||||
if (param_count) {
|
||||
memcpy(parms->out.params.data + param_disp,
|
||||
req->in.hdr + param_ofs,
|
||||
param_count);
|
||||
}
|
||||
|
||||
recvd_param += param_count;
|
||||
recvd_data += data_count;
|
||||
|
||||
if (recvd_data >= total_data &&
|
||||
recvd_param >= total_param) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!smbcli_request_receive(req) ||
|
||||
smbcli_request_is_error(req)) {
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
|
||||
DEBUG(0,("smb_raw_receive_nttrans: Expected nttranss, got command 0x%02x\n",
|
||||
CVAL(req->in.hdr, HDR_COM)));
|
||||
req->status = NT_STATUS_UNSUCCESSFUL;
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
}
|
||||
|
||||
failed:
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
nttrans raw - only BLOBs used in this interface.
|
||||
at the moment we only handle a single primary request
|
||||
****************************************************************************/
|
||||
struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
|
||||
struct smb_nttrans *parms)
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
uint8_t *outdata, *outparam;
|
||||
int i;
|
||||
int align = 0;
|
||||
|
||||
/* only align if there are parameters or data */
|
||||
if (parms->in.params.length || parms->in.data.length) {
|
||||
align = 3;
|
||||
}
|
||||
|
||||
req = smbcli_request_setup(tree, SMBnttrans,
|
||||
19 + parms->in.setup_count,
|
||||
align +
|
||||
parms->in.params.length +
|
||||
parms->in.data.length);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fill in SMB parameters */
|
||||
outparam = req->out.data + align;
|
||||
outdata = outparam + parms->in.params.length;
|
||||
|
||||
if (align != 0) {
|
||||
memset(req->out.data, 0, align);
|
||||
}
|
||||
|
||||
SCVAL(req->out.vwv, 0, parms->in.max_setup);
|
||||
SSVAL(req->out.vwv, 1, 0); /* reserved */
|
||||
SIVAL(req->out.vwv, 3, parms->in.params.length);
|
||||
SIVAL(req->out.vwv, 7, parms->in.data.length);
|
||||
SIVAL(req->out.vwv, 11, parms->in.max_param);
|
||||
SIVAL(req->out.vwv, 15, parms->in.max_data);
|
||||
SIVAL(req->out.vwv, 19, parms->in.params.length);
|
||||
SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
|
||||
SIVAL(req->out.vwv, 27, parms->in.data.length);
|
||||
SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
|
||||
SCVAL(req->out.vwv, 35, parms->in.setup_count);
|
||||
SSVAL(req->out.vwv, 36, parms->in.function);
|
||||
for (i=0;i<parms->in.setup_count;i++) {
|
||||
SSVAL(req->out.vwv,VWV(19+i),parms->in.setup[i]);
|
||||
}
|
||||
if (parms->in.params.length) {
|
||||
memcpy(outparam, parms->in.params.data, parms->in.params.length);
|
||||
}
|
||||
if (parms->in.data.length) {
|
||||
memcpy(outdata, parms->in.data.data, parms->in.data.length);
|
||||
}
|
||||
|
||||
if (!smbcli_request_send(req)) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 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);
|
||||
}
|
||||
|
||||
/*
|
||||
work out the maximum data size for a trans request while avoiding
|
||||
multi-part replies
|
||||
|
||||
TODO: we only need to avoid multi-part replies because the
|
||||
multi-part trans receive code is broken.
|
||||
*/
|
||||
size_t smb_raw_max_trans_data(struct smbcli_tree *tree, size_t param_size)
|
||||
{
|
||||
return tree->session->transport->negotiate.max_xmit - (70 + param_size);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "libcli/raw/signing.h"
|
||||
|
||||
/*
|
||||
Shared state structure between client and server, representing the basic packet.
|
||||
*/
|
||||
|
||||
struct 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;
|
||||
uint_t 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;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
enum smb_signing_engine_state {
|
||||
SMB_SIGNING_ENGINE_OFF,
|
||||
SMB_SIGNING_ENGINE_BSRSPYL,
|
||||
SMB_SIGNING_ENGINE_ON
|
||||
};
|
||||
|
||||
enum smb_signing_state {
|
||||
SMB_SIGNING_OFF, SMB_SIGNING_SUPPORTED,
|
||||
SMB_SIGNING_REQUIRED, SMB_SIGNING_AUTO};
|
||||
|
||||
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
|
||||
@@ -0,0 +1,593 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SMB_H
|
||||
#define _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
|
||||
|
||||
/* 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_SYNC_ALERT 0x0010
|
||||
#define NTCREATEX_OPTIONS_ASYNC_ALERT 0x0020
|
||||
#define NTCREATEX_OPTIONS_NON_DIRECTORY_FILE 0x0040
|
||||
#define NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE 0x0200
|
||||
#define NTCREATEX_OPTIONS_EIGHT_DOT_THREE_ONLY 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_UNKNOWN_400000 0x400000
|
||||
|
||||
/* create options these bits are for private use by backends, they are
|
||||
not valid on the wire */
|
||||
#define NTCREATEX_OPTIONS_PRIVATE_MASK 0xFF000000
|
||||
#define NTCREATEX_OPTIONS_PRIVATE_DENY_DOS 0x01000000
|
||||
#define NTCREATEX_OPTIONS_PRIVATE_DENY_FCB 0x02000000
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
#define SMB_MAGIC 0x424D53FF /* 0xFF 'S' 'M' 'B' */
|
||||
|
||||
/* the basic packet size, assuming no words or bytes. Does not include the NBT header */
|
||||
#define MIN_SMB_SIZE 35
|
||||
|
||||
/* when using NBT encapsulation every packet has a 4 byte header */
|
||||
#define NBT_HDR_SIZE 4
|
||||
|
||||
/* offsets into message header for common items - NOTE: These have
|
||||
changed from being offsets from the base of the NBT packet to the base of the SMB packet.
|
||||
this has reduced all these values by 4
|
||||
*/
|
||||
#define HDR_COM 4
|
||||
#define HDR_RCLS 5
|
||||
#define HDR_REH 6
|
||||
#define HDR_ERR 7
|
||||
#define HDR_FLG 9
|
||||
#define HDR_FLG2 10
|
||||
#define HDR_PIDHIGH 12
|
||||
#define HDR_SS_FIELD 14
|
||||
#define HDR_TID 24
|
||||
#define HDR_PID 26
|
||||
#define HDR_UID 28
|
||||
#define HDR_MID 30
|
||||
#define HDR_WCT 32
|
||||
#define HDR_VWV 33
|
||||
|
||||
|
||||
/* types of buffers in core SMB protocol */
|
||||
#define SMB_DATA_BLOCK 0x1
|
||||
#define SMB_ASCII4 0x4
|
||||
|
||||
|
||||
/* flag defines. CIFS spec 3.1.1 */
|
||||
#define FLAG_SUPPORT_LOCKREAD 0x01
|
||||
#define FLAG_CLIENT_BUF_AVAIL 0x02
|
||||
#define FLAG_RESERVED 0x04
|
||||
#define FLAG_CASELESS_PATHNAMES 0x08
|
||||
#define FLAG_CANONICAL_PATHNAMES 0x10
|
||||
#define FLAG_REQUEST_OPLOCK 0x20
|
||||
#define FLAG_REQUEST_BATCH_OPLOCK 0x40
|
||||
#define FLAG_REPLY 0x80
|
||||
|
||||
/* the complete */
|
||||
#define SMBmkdir 0x00 /* create directory */
|
||||
#define SMBrmdir 0x01 /* delete directory */
|
||||
#define SMBopen 0x02 /* open file */
|
||||
#define SMBcreate 0x03 /* create file */
|
||||
#define SMBclose 0x04 /* close file */
|
||||
#define SMBflush 0x05 /* flush file */
|
||||
#define SMBunlink 0x06 /* delete file */
|
||||
#define SMBmv 0x07 /* rename file */
|
||||
#define SMBgetatr 0x08 /* get file attributes */
|
||||
#define SMBsetatr 0x09 /* set file attributes */
|
||||
#define SMBread 0x0A /* read from file */
|
||||
#define SMBwrite 0x0B /* write to file */
|
||||
#define SMBlock 0x0C /* lock byte range */
|
||||
#define SMBunlock 0x0D /* unlock byte range */
|
||||
#define SMBctemp 0x0E /* create temporary file */
|
||||
#define SMBmknew 0x0F /* make new file */
|
||||
#define SMBchkpth 0x10 /* check directory path */
|
||||
#define SMBexit 0x11 /* process exit */
|
||||
#define SMBlseek 0x12 /* seek */
|
||||
#define SMBtcon 0x70 /* tree connect */
|
||||
#define SMBtconX 0x75 /* tree connect and X*/
|
||||
#define SMBtdis 0x71 /* tree disconnect */
|
||||
#define SMBnegprot 0x72 /* negotiate protocol */
|
||||
#define SMBdskattr 0x80 /* get disk attributes */
|
||||
#define SMBsearch 0x81 /* search directory */
|
||||
#define SMBsplopen 0xC0 /* open print spool file */
|
||||
#define SMBsplwr 0xC1 /* write to print spool file */
|
||||
#define SMBsplclose 0xC2 /* close print spool file */
|
||||
#define SMBsplretq 0xC3 /* return print queue */
|
||||
#define SMBsends 0xD0 /* send single block message */
|
||||
#define SMBsendb 0xD1 /* send broadcast message */
|
||||
#define SMBfwdname 0xD2 /* forward user name */
|
||||
#define SMBcancelf 0xD3 /* cancel forward */
|
||||
#define SMBgetmac 0xD4 /* get machine name */
|
||||
#define SMBsendstrt 0xD5 /* send start of multi-block message */
|
||||
#define SMBsendend 0xD6 /* send end of multi-block message */
|
||||
#define SMBsendtxt 0xD7 /* send text of multi-block message */
|
||||
|
||||
/* Core+ protocol */
|
||||
#define SMBlockread 0x13 /* Lock a range and read */
|
||||
#define SMBwriteunlock 0x14 /* write then range then unlock it */
|
||||
#define SMBreadbraw 0x1a /* read a block of data with no smb header */
|
||||
#define SMBwritebraw 0x1d /* write a block of data with no smb header */
|
||||
#define SMBwritec 0x20 /* secondary write request */
|
||||
#define SMBwriteclose 0x2c /* write a file then close it */
|
||||
|
||||
/* dos extended protocol */
|
||||
#define SMBreadBraw 0x1A /* read block raw */
|
||||
#define SMBreadBmpx 0x1B /* read block multiplexed */
|
||||
#define SMBreadBs 0x1C /* read block (secondary response) */
|
||||
#define SMBwriteBraw 0x1D /* write block raw */
|
||||
#define SMBwriteBmpx 0x1E /* write block multiplexed */
|
||||
#define SMBwriteBs 0x1F /* write block (secondary request) */
|
||||
#define SMBwriteC 0x20 /* write complete response */
|
||||
#define SMBsetattrE 0x22 /* set file attributes expanded */
|
||||
#define SMBgetattrE 0x23 /* get file attributes expanded */
|
||||
#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
|
||||
#define SMBtrans 0x25 /* transaction - name, bytes in/out */
|
||||
#define SMBtranss 0x26 /* transaction (secondary request/response) */
|
||||
#define SMBioctl 0x27 /* IOCTL */
|
||||
#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
|
||||
#define SMBcopy 0x29 /* copy */
|
||||
#define SMBmove 0x2A /* move */
|
||||
#define SMBecho 0x2B /* echo */
|
||||
#define SMBopenX 0x2D /* open and X */
|
||||
#define SMBreadX 0x2E /* read and X */
|
||||
#define SMBwriteX 0x2F /* write and X */
|
||||
#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
|
||||
#define SMBffirst 0x82 /* find first */
|
||||
#define SMBfunique 0x83 /* find unique */
|
||||
#define SMBfclose 0x84 /* find close */
|
||||
#define SMBkeepalive 0x85 /* keepalive */
|
||||
#define SMBinvalid 0xFE /* invalid command */
|
||||
|
||||
/* Extended 2.0 protocol */
|
||||
#define SMBtrans2 0x32 /* TRANS2 protocol set */
|
||||
#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
|
||||
#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
|
||||
#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
|
||||
#define SMBulogoffX 0x74 /* user logoff */
|
||||
|
||||
/* NT SMB extensions. */
|
||||
#define SMBnttrans 0xA0 /* NT transact */
|
||||
#define SMBnttranss 0xA1 /* NT transact secondary */
|
||||
#define SMBntcreateX 0xA2 /* NT create and X */
|
||||
#define SMBntcancel 0xA4 /* NT cancel */
|
||||
#define SMBntrename 0xA5 /* NT rename */
|
||||
|
||||
/* used to indicate end of chain */
|
||||
#define SMB_CHAIN_NONE 0xFF
|
||||
|
||||
/* These are the trans subcommands */
|
||||
#define TRANSACT_SETNAMEDPIPEHANDLESTATE 0x01
|
||||
#define TRANSACT_DCERPCCMD 0x26
|
||||
#define TRANSACT_WAITNAMEDPIPEHANDLESTATE 0x53
|
||||
|
||||
/* These are the NT transact sub commands. */
|
||||
#define NT_TRANSACT_CREATE 1
|
||||
#define NT_TRANSACT_IOCTL 2
|
||||
#define NT_TRANSACT_SET_SECURITY_DESC 3
|
||||
#define NT_TRANSACT_NOTIFY_CHANGE 4
|
||||
#define NT_TRANSACT_RENAME 5
|
||||
#define NT_TRANSACT_QUERY_SECURITY_DESC 6
|
||||
|
||||
/* this is used on a TConX. I'm not sure the name is very helpful though */
|
||||
#define SMB_SUPPORT_SEARCH_BITS 0x0001
|
||||
#define SMB_SHARE_IN_DFS 0x0002
|
||||
|
||||
/* 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
|
||||
|
||||
|
||||
/* Mapping of generic access rights for files to specific rights. */
|
||||
#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS| NT_ACCESS_SYNCHRONIZE_ACCESS|FILE_ALL_ACCESS)
|
||||
|
||||
#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|FILE_READ_DATA|FILE_READ_ATTRIBUTES|\
|
||||
FILE_READ_EA|NT_ACCESS_SYNCHRONIZE_ACCESS)
|
||||
|
||||
#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE_ACCESS|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|\
|
||||
FILE_WRITE_EA|FILE_APPEND_DATA|NT_ACCESS_SYNCHRONIZE_ACCESS)
|
||||
|
||||
#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|FILE_READ_ATTRIBUTES|\
|
||||
FILE_EXECUTE|NT_ACCESS_SYNCHRONIZE_ACCESS)
|
||||
|
||||
|
||||
/* FileAttributes (search attributes) field */
|
||||
#define FILE_ATTRIBUTE_READONLY 0x0001
|
||||
#define FILE_ATTRIBUTE_HIDDEN 0x0002
|
||||
#define FILE_ATTRIBUTE_SYSTEM 0x0004
|
||||
#define FILE_ATTRIBUTE_VOLUME 0x0008
|
||||
#define FILE_ATTRIBUTE_DIRECTORY 0x0010
|
||||
#define FILE_ATTRIBUTE_ARCHIVE 0x0020
|
||||
#define FILE_ATTRIBUTE_DEVICE 0x0040
|
||||
#define FILE_ATTRIBUTE_NORMAL 0x0080
|
||||
#define FILE_ATTRIBUTE_TEMPORARY 0x0100
|
||||
#define FILE_ATTRIBUTE_SPARSE 0x0200
|
||||
#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400
|
||||
#define FILE_ATTRIBUTE_COMPRESSED 0x0800
|
||||
#define FILE_ATTRIBUTE_OFFLINE 0x1000
|
||||
#define FILE_ATTRIBUTE_NONINDEXED 0x2000
|
||||
#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
|
||||
|
||||
/* Flags - combined with attributes. */
|
||||
#define FILE_FLAG_WRITE_THROUGH 0x80000000L
|
||||
#define FILE_FLAG_NO_BUFFERING 0x20000000L
|
||||
#define FILE_FLAG_RANDOM_ACCESS 0x10000000L
|
||||
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000L
|
||||
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000L
|
||||
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000L /* only if backup/restore privilege? */
|
||||
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000L
|
||||
|
||||
/* Responses when opening a file. */
|
||||
#define FILE_WAS_SUPERSEDED 0
|
||||
#define FILE_WAS_OPENED 1
|
||||
#define FILE_WAS_CREATED 2
|
||||
#define FILE_WAS_OVERWRITTEN 3
|
||||
|
||||
/* File type flags */
|
||||
#define FILE_TYPE_DISK 0
|
||||
#define FILE_TYPE_BYTE_MODE_PIPE 1
|
||||
#define FILE_TYPE_MESSAGE_MODE_PIPE 2
|
||||
#define FILE_TYPE_PRINTER 3
|
||||
#define FILE_TYPE_COMM_DEVICE 4
|
||||
#define FILE_TYPE_UNKNOWN 0xFFFF
|
||||
|
||||
/* 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
|
||||
|
||||
/* Filesystem Attributes. */
|
||||
#define FILE_CASE_SENSITIVE_SEARCH 0x01
|
||||
#define FILE_CASE_PRESERVED_NAMES 0x02
|
||||
#define FILE_UNICODE_ON_DISK 0x04
|
||||
/* According to cifs9f, this is 4, not 8 */
|
||||
/* Acconding to testing, this actually sets the security attribute! */
|
||||
#define FILE_PERSISTENT_ACLS 0x08
|
||||
/* These entries added from cifs9f --tsb */
|
||||
#define FILE_FILE_COMPRESSION 0x10
|
||||
#define FILE_VOLUME_QUOTAS 0x20
|
||||
/* I think this is wrong. JRA #define FILE_DEVICE_IS_MOUNTED 0x20 */
|
||||
#define FILE_VOLUME_SPARSE_FILE 0x40
|
||||
#define FILE_VOLUME_IS_COMPRESSED 0x8000
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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) (((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
|
||||
|
||||
/* Sercurity mode bits. */
|
||||
#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
|
||||
#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
|
||||
#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
|
||||
#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
|
||||
|
||||
/* NT Flags2 bits - cifs6.txt section 3.1.2 */
|
||||
#define FLAGS2_LONG_PATH_COMPONENTS 0x0001
|
||||
#define FLAGS2_EXTENDED_ATTRIBUTES 0x0002
|
||||
#define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
|
||||
#define FLAGS2_IS_LONG_NAME 0x0040
|
||||
#define FLAGS2_EXTENDED_SECURITY 0x0800
|
||||
#define FLAGS2_DFS_PATHNAMES 0x1000
|
||||
#define FLAGS2_READ_PERMIT_EXECUTE 0x2000
|
||||
#define FLAGS2_32_BIT_ERROR_CODES 0x4000
|
||||
#define FLAGS2_UNICODE_STRINGS 0x8000
|
||||
|
||||
|
||||
/* CIFS protocol capabilities */
|
||||
#define CAP_RAW_MODE 0x00000001
|
||||
#define CAP_MPX_MODE 0x00000002
|
||||
#define CAP_UNICODE 0x00000004
|
||||
#define CAP_LARGE_FILES 0x00000008
|
||||
#define CAP_NT_SMBS 0x00000010
|
||||
#define CAP_RPC_REMOTE_APIS 0x00000020
|
||||
#define CAP_STATUS32 0x00000040
|
||||
#define CAP_LEVEL_II_OPLOCKS 0x00000080
|
||||
#define CAP_LOCK_AND_READ 0x00000100
|
||||
#define CAP_NT_FIND 0x00000200
|
||||
#define CAP_DFS 0x00001000
|
||||
#define CAP_W2K_SMBS 0x00002000
|
||||
#define CAP_LARGE_READX 0x00004000
|
||||
#define CAP_LARGE_WRITEX 0x00008000
|
||||
#define CAP_UNIX 0x00800000 /* Capabilities for UNIX extensions. Created by HP. */
|
||||
#define CAP_EXTENDED_SECURITY 0x80000000
|
||||
|
||||
/*
|
||||
* Global value meaning that the smb_uid field should be
|
||||
* ingored (in share level security and protocol level == CORE)
|
||||
*/
|
||||
|
||||
#define UID_FIELD_INVALID 0
|
||||
|
||||
/* Lock types. */
|
||||
#define LOCKING_ANDX_SHARED_LOCK 0x01
|
||||
#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
|
||||
#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
|
||||
#define LOCKING_ANDX_CANCEL_LOCK 0x08
|
||||
#define LOCKING_ANDX_LARGE_FILES 0x10
|
||||
|
||||
/*
|
||||
* Bits we test with.
|
||||
*/
|
||||
|
||||
#define OPLOCK_NONE 0
|
||||
#define OPLOCK_EXCLUSIVE 1
|
||||
#define OPLOCK_BATCH 2
|
||||
#define OPLOCK_LEVEL_II 4
|
||||
|
||||
#define CORE_OPLOCK_GRANTED (1<<5)
|
||||
#define EXTENDED_OPLOCK_GRANTED (1<<15)
|
||||
|
||||
/*
|
||||
* Return values for oplock types.
|
||||
*/
|
||||
|
||||
#define NO_OPLOCK_RETURN 0
|
||||
#define EXCLUSIVE_OPLOCK_RETURN 1
|
||||
#define BATCH_OPLOCK_RETURN 2
|
||||
#define LEVEL_II_OPLOCK_RETURN 3
|
||||
|
||||
/* oplock levels sent in oplock break */
|
||||
#define OPLOCK_BREAK_TO_NONE 0
|
||||
#define OPLOCK_BREAK_TO_LEVEL_II 1
|
||||
|
||||
|
||||
#define CMD_REPLY 0x8000
|
||||
|
||||
/* The maximum length of a trust account password.
|
||||
Used when we randomly create it, 15 char passwords
|
||||
exceed NT4's max password length */
|
||||
|
||||
#define DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH 14
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
#define smb_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
|
||||
#define _smb_setlen(buf,len) do {(buf)[0] = 0; (buf)[1] = ((len)&0x10000)>>16; \
|
||||
(buf)[2] = ((len)&0xFF00)>>8; (buf)[3] = (len)&0xFF;} while (0)
|
||||
#define _smb2_setlen(buf,len) do {(buf)[0] = 0; (buf)[1] = ((len)&0xFF0000)>>16; \
|
||||
(buf)[2] = ((len)&0xFF00)>>8; (buf)[3] = (len)&0xFF;} while (0)
|
||||
|
||||
#include "libcli/raw/trans2.h"
|
||||
#include "libcli/raw/interfaces.h"
|
||||
|
||||
#endif /* _SMB_H */
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "smb.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "lib/crypto/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;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Common code before we set a new signing implementation
|
||||
************************************************************/
|
||||
static BOOL smbcli_set_smb_signing_common(struct smbcli_transport *transport)
|
||||
{
|
||||
if (!set_smb_signing_common(&transport->negotiate.sign_info)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!(transport->negotiate.sec_mode &
|
||||
(NEGOTIATE_SECURITY_SIGNATURES_REQUIRED|NEGOTIATE_SECURITY_SIGNATURES_ENABLED))) {
|
||||
DEBUG(5, ("SMB Signing is not negotiated by the peer\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* These calls are INCOMPATIBLE with SMB signing */
|
||||
transport->negotiate.readbraw_supported = False;
|
||||
transport->negotiate.writebraw_supported = False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void mark_packet_signed(struct 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 request_buffer *out, DATA_BLOB *mac_key, unsigned int seq_num)
|
||||
{
|
||||
uint8_t calc_md5_mac[16];
|
||||
struct MD5Context md5_ctx;
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
MD5Init(&md5_ctx);
|
||||
MD5Update(&md5_ctx, mac_key->data, mac_key->length);
|
||||
MD5Update(&md5_ctx,
|
||||
out->buffer + NBT_HDR_SIZE,
|
||||
out->size - NBT_HDR_SIZE);
|
||||
MD5Final(calc_md5_mac, &md5_ctx);
|
||||
|
||||
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);
|
||||
/* 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 request_buffer *in, DATA_BLOB *mac_key, uint_t seq_num)
|
||||
{
|
||||
BOOL good;
|
||||
uint8_t calc_md5_mac[16];
|
||||
uint8_t *server_sent_mac;
|
||||
uint8_t sequence_buf[8];
|
||||
struct MD5Context md5_ctx;
|
||||
const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
|
||||
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. */
|
||||
MD5Init(&md5_ctx);
|
||||
MD5Update(&md5_ctx, mac_key->data,
|
||||
mac_key->length);
|
||||
MD5Update(&md5_ctx, in->hdr, HDR_SS_FIELD);
|
||||
MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
|
||||
|
||||
MD5Update(&md5_ctx, in->hdr + offset_end_of_sig,
|
||||
in->size - NBT_HDR_SIZE - (offset_end_of_sig));
|
||||
MD5Final(calc_md5_mac, &md5_ctx);
|
||||
|
||||
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
|
||||
|
||||
if (i == 0) {
|
||||
if (!good) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (good) break;
|
||||
}
|
||||
|
||||
if (good && i != 0) {
|
||||
DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num));
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
static void smbcli_req_allocate_seq_num(struct smbcli_request *req)
|
||||
{
|
||||
req->seq_num = req->transport->negotiate.sign_info.next_seq_num;
|
||||
|
||||
/* some requests (eg. NTcancel) are one way, and the sequence number
|
||||
should be increased by 1 not 2 */
|
||||
if (req->sign_single_increment) {
|
||||
req->transport->negotiate.sign_info.next_seq_num += 1;
|
||||
} else {
|
||||
req->transport->negotiate.sign_info.next_seq_num += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
void smbcli_request_calculate_sign_mac(struct smbcli_request *req)
|
||||
{
|
||||
#if 0
|
||||
/* enable this when packet signing is preventing you working out why valgrind
|
||||
says that data is uninitialised */
|
||||
file_save("pkt.dat", req->out.buffer, req->out.size);
|
||||
#endif
|
||||
|
||||
switch (req->transport->negotiate.sign_info.signing_state) {
|
||||
case SMB_SIGNING_ENGINE_OFF:
|
||||
break;
|
||||
|
||||
case SMB_SIGNING_ENGINE_BSRSPYL:
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(&req->out);
|
||||
|
||||
/* I wonder what BSRSPYL stands for - but this is what MS
|
||||
actually sends! */
|
||||
memcpy((req->out.hdr + HDR_SS_FIELD), "BSRSPYL ", 8);
|
||||
break;
|
||||
|
||||
case SMB_SIGNING_ENGINE_ON:
|
||||
|
||||
smbcli_req_allocate_seq_num(req);
|
||||
sign_outgoing_message(&req->out,
|
||||
&req->transport->negotiate.sign_info.mac_key,
|
||||
req->seq_num);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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;
|
||||
sign_info->next_seq_num = 0;
|
||||
data_blob_free(&sign_info->mac_key);
|
||||
sign_info->signing_state = SMB_SIGNING_ENGINE_OFF;
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
SMB signing - TEMP implementation - setup the MAC key.
|
||||
|
||||
*/
|
||||
BOOL smbcli_temp_set_signing(struct smbcli_transport *transport)
|
||||
{
|
||||
if (!smbcli_set_smb_signing_common(transport)) {
|
||||
return False;
|
||||
}
|
||||
DEBUG(5, ("BSRSPYL SMB signing enabled\n"));
|
||||
smbcli_set_signing_off(&transport->negotiate.sign_info);
|
||||
|
||||
transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
|
||||
transport->negotiate.sign_info.signing_state = SMB_SIGNING_ENGINE_BSRSPYL;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
/**
|
||||
* Check a packet supplied by the server.
|
||||
* @return False if we had an established signing connection
|
||||
* which had a back checksum, True otherwise
|
||||
*/
|
||||
BOOL smbcli_request_check_sign_mac(struct smbcli_request *req)
|
||||
{
|
||||
BOOL good;
|
||||
|
||||
switch (req->transport->negotiate.sign_info.signing_state)
|
||||
{
|
||||
case SMB_SIGNING_ENGINE_OFF:
|
||||
return True;
|
||||
case SMB_SIGNING_ENGINE_BSRSPYL:
|
||||
case SMB_SIGNING_ENGINE_ON:
|
||||
{
|
||||
if (req->in.size < (HDR_SS_FIELD + 8)) {
|
||||
return False;
|
||||
} else {
|
||||
good = check_signed_incoming_message(&req->in,
|
||||
&req->transport->negotiate.sign_info.mac_key,
|
||||
req->seq_num+1);
|
||||
|
||||
return signing_good(&req->transport->negotiate.sign_info,
|
||||
req->seq_num+1, good);
|
||||
}
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************
|
||||
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);
|
||||
|
||||
/* Initialise the sequence number */
|
||||
sign_info->next_seq_num = 0;
|
||||
|
||||
sign_info->signing_state = SMB_SIGNING_ENGINE_ON;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
BOOL smbcli_transport_simple_set_signing(struct smbcli_transport *transport,
|
||||
const DATA_BLOB user_session_key,
|
||||
const DATA_BLOB response)
|
||||
{
|
||||
if (!smbcli_set_smb_signing_common(transport)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
return smbcli_simple_set_signing(transport,
|
||||
&transport->negotiate.sign_info,
|
||||
&user_session_key,
|
||||
&response);
|
||||
}
|
||||
|
||||
|
||||
BOOL smbcli_init_signing(struct smbcli_transport *transport)
|
||||
{
|
||||
transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
|
||||
if (!smbcli_set_signing_off(&transport->negotiate.sign_info)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
switch (lp_client_signing()) {
|
||||
case SMB_SIGNING_OFF:
|
||||
transport->negotiate.sign_info.allow_smb_signing = False;
|
||||
break;
|
||||
case SMB_SIGNING_SUPPORTED:
|
||||
case SMB_SIGNING_AUTO:
|
||||
transport->negotiate.sign_info.allow_smb_signing = True;
|
||||
break;
|
||||
case SMB_SIGNING_REQUIRED:
|
||||
transport->negotiate.sign_info.allow_smb_signing = True;
|
||||
transport->negotiate.sign_info.mandatory_signing = True;
|
||||
break;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB transaction2 handling
|
||||
Copyright (C) Jeremy Allison 1994-2002.
|
||||
Copyright (C) Andrew Tridgell 1995-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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _TRANS2_H_
|
||||
#define _TRANS2_H_
|
||||
|
||||
/* These are the TRANS2 sub commands */
|
||||
#define TRANSACT2_OPEN 0
|
||||
#define TRANSACT2_FINDFIRST 1
|
||||
#define TRANSACT2_FINDNEXT 2
|
||||
#define TRANSACT2_QFSINFO 3
|
||||
#define TRANSACT2_SETFSINFO 4
|
||||
#define TRANSACT2_QPATHINFO 5
|
||||
#define TRANSACT2_SETPATHINFO 6
|
||||
#define TRANSACT2_QFILEINFO 7
|
||||
#define TRANSACT2_SETFILEINFO 8
|
||||
#define TRANSACT2_FSCTL 9
|
||||
#define TRANSACT2_IOCTL 0xA
|
||||
#define TRANSACT2_FINDNOTIFYFIRST 0xB
|
||||
#define TRANSACT2_FINDNOTIFYNEXT 0xC
|
||||
#define TRANSACT2_MKDIR 0xD
|
||||
#define TRANSACT2_SESSION_SETUP 0xE
|
||||
#define TRANSACT2_GET_DFS_REFERRAL 0x10
|
||||
#define TRANSACT2_REPORT_DFS_INCONSISTANCY 0x11
|
||||
|
||||
|
||||
/* 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_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
|
||||
|
||||
|
||||
/* 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_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
|
||||
|
||||
|
||||
|
||||
/* 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_BASIC_INFORMATION 1004
|
||||
#define SMB_SFILEINFO_RENAME_INFORMATION 1010
|
||||
#define SMB_SFILEINFO_DISPOSITION_INFORMATION 1013
|
||||
#define SMB_SFILEINFO_POSITION_INFORMATION 1014
|
||||
#define SMB_SFILEINFO_MODE_INFORMATION 1016
|
||||
#define SMB_SFILEINFO_ALLOCATION_INFORMATION 1019
|
||||
#define SMB_SFILEINFO_END_OF_FILE_INFORMATION 1020
|
||||
|
||||
/* filemon shows FilePipeInformation */
|
||||
#define SMB_SFILEINFO_1023 1023
|
||||
|
||||
/* filemon shows FilePipeRemoteInformation */
|
||||
#define SMB_SFILEINFO_1025 1025
|
||||
|
||||
/* filemon shows CopyOnWriteInformation */
|
||||
#define SMB_SFILEINFO_1029 1029
|
||||
|
||||
/* filemon shows OleClassIdInformation */
|
||||
#define SMB_SFILEINFO_1032 1032
|
||||
|
||||
/* seems to be the file size - perhaps valid data size?
|
||||
filemon shows 'InheritContentIndexInfo'
|
||||
*/
|
||||
#define SMB_SFILEINFO_1039 1039
|
||||
|
||||
/* OLE_INFORMATION? */
|
||||
#define SMB_SFILEINFO_1040 1040
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
|
||||
/* UNIX CIFS Extensions - created by HP */
|
||||
/*
|
||||
* UNIX CIFS Extensions have the range 0x200 - 0x2FF reserved.
|
||||
* Supposedly Microsoft have agreed to this.
|
||||
*/
|
||||
|
||||
#define MIN_UNIX_INFO_LEVEL 0x200
|
||||
#define MAX_UNIX_INFO_LEVEL 0x2FF
|
||||
|
||||
#define INFO_LEVEL_IS_UNIX(level) (((level) >= MIN_UNIX_INFO_LEVEL) && ((level) <= MAX_UNIX_INFO_LEVEL))
|
||||
|
||||
#define SMB_QFILEINFO_UNIX_BASIC 0x200 /* UNIX File Info*/
|
||||
#define SMB_SFILEINFO_UNIX_BASIC 0x200
|
||||
|
||||
#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */
|
||||
/* means "don't change it" */
|
||||
#define SMB_UID_NO_CHANGE 0xFFFFFFFF
|
||||
#define SMB_GID_NO_CHANGE 0xFFFFFFFF
|
||||
|
||||
#define SMB_SIZE_NO_CHANGE_LO 0xFFFFFFFF
|
||||
#define SMB_SIZE_NO_CHANGE_HI 0xFFFFFFFF
|
||||
|
||||
#define SMB_TIME_NO_CHANGE_LO 0xFFFFFFFF
|
||||
#define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF
|
||||
|
||||
/*
|
||||
Offset Size Name
|
||||
0 LARGE_INTEGER EndOfFile File size
|
||||
8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks).
|
||||
16 LARGE_INTEGER CreationTime Creation time
|
||||
24 LARGE_INTEGER LastAccessTime Last access time
|
||||
32 LARGE_INTEGER LastModificationTime Last modification time
|
||||
40 LARGE_INTEGER Uid Numeric user id for the owner
|
||||
48 LARGE_INTEGER Gid Numeric group id of owner
|
||||
56 ULONG Type Enumeration specifying the pathname type:
|
||||
0 -- File
|
||||
1 -- Directory
|
||||
2 -- Symbolic link
|
||||
3 -- Character device
|
||||
4 -- Block device
|
||||
5 -- FIFO (named pipe)
|
||||
6 -- Unix domain socket
|
||||
|
||||
60 LARGE_INTEGER devmajor Major device number if type is device
|
||||
68 LARGE_INTEGER devminor Minor device number if type is device
|
||||
76 LARGE_INTEGER uniqueid This is a server-assigned unique id for the file. The client
|
||||
will typically map this onto an inode number. The scope of
|
||||
uniqueness is the share.
|
||||
84 LARGE_INTEGER permissions Standard UNIX file permissions - see below.
|
||||
92 LARGE_INTEGER nlinks The number of directory entries that map to this entry
|
||||
(number of hard links)
|
||||
|
||||
100 - end.
|
||||
*/
|
||||
|
||||
/* UNIX filetype mappings. */
|
||||
|
||||
#define UNIX_TYPE_FILE 0
|
||||
#define UNIX_TYPE_DIR 1
|
||||
#define UNIX_TYPE_SYMLINK 2
|
||||
#define UNIX_TYPE_CHARDEV 3
|
||||
#define UNIX_TYPE_BLKDEV 4
|
||||
#define UNIX_TYPE_FIFO 5
|
||||
#define UNIX_TYPE_SOCKET 6
|
||||
#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
/*
|
||||
* Oh this is fun. "Standard UNIX permissions" has no
|
||||
* meaning in POSIX. We need to define the mapping onto
|
||||
* and off the wire as this was not done in the original HP
|
||||
* spec. JRA.
|
||||
*/
|
||||
|
||||
#define UNIX_X_OTH 0000001
|
||||
#define UNIX_W_OTH 0000002
|
||||
#define UNIX_R_OTH 0000004
|
||||
#define UNIX_X_GRP 0000010
|
||||
#define UNIX_W_GRP 0000020
|
||||
#define UNIX_R_GRP 0000040
|
||||
#define UNIX_X_USR 0000100
|
||||
#define UNIX_W_USR 0000200
|
||||
#define UNIX_R_USR 0000400
|
||||
#define UNIX_STICKY 0001000
|
||||
#define UNIX_SET_GID 0002000
|
||||
#define UNIX_SET_UID 0004000
|
||||
|
||||
/* Masks for the above */
|
||||
#define UNIX_OTH_MASK 0000007
|
||||
#define UNIX_GRP_MASK 0000070
|
||||
#define UNIX_USR_MASK 0000700
|
||||
#define UNIX_PERM_MASK 0000777
|
||||
#define UNIX_EXTRA_MASK 0007000
|
||||
#define UNIX_ALL_MASK 0007777
|
||||
|
||||
#define SMB_QFILEINFO_UNIX_LINK 0x201
|
||||
#define SMB_SFILEINFO_UNIX_LINK 0x201
|
||||
#define SMB_SFILEINFO_UNIX_HLINK 0x203
|
||||
|
||||
#define SMB_FIND_FILE_UNIX 0x202
|
||||
|
||||
/*
|
||||
Info level for QVOLINFO - returns version of CIFS UNIX extensions, plus
|
||||
64-bits worth of capability fun :-).
|
||||
*/
|
||||
|
||||
#define SMB_QUERY_CIFS_UNIX_INFO 0x200
|
||||
|
||||
/* Returns the following.
|
||||
|
||||
UINT16 major version number
|
||||
UINT16 minor version number
|
||||
LARGE_INTEGER capability bitfield
|
||||
|
||||
*/
|
||||
|
||||
#define CIFS_UNIX_MAJOR_VERSION 1
|
||||
#define CIFS_UNIX_MINOR_VERSION 0
|
||||
|
||||
#define CIFS_UNIX_FCNTL_LOCKS_CAP 0x1
|
||||
#define CIFS_UNIX_POSIX_ACLS_CAP 0x2
|
||||
|
||||
/* ... more as we think of them :-). */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user