/*
Unix SMB/CIFS implementation.
transaction2 handling
Copyright (C) Andrew Tridgell 2003
Copyright Matthieu Patou <mat@matws.net> 2010-2011
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file handles the parsing of transact2 requests
*/
#include "includes.h"
#include "samba/service_stream.h"
#include "smb_server/smb_server.h"
#include "ntvfs/ntvfs.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/raw/raw_proto.h"
#include "librpc/gen_ndr/dfsblobs.h"
#include "librpc/gen_ndr/ndr_dfsblobs.h"
#include "dsdb/samdb/samdb.h"
#include "auth/session.h"
#include "param/param.h"
#include "lib/tsocket/tsocket.h"
#include "dfs_server/dfs_server_ad.h"
#define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
#define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
trans2_setup_reply(trans, 0, 0, 0);\
return req->ntvfs->async_states->status; \
} \
} while (0)
#define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
ptr = talloc_get_type(op->op_info, type); \
} while (0)
#define TRANS2_CHECK(cmd) do { \
NTSTATUS _status; \
_status = cmd; \
NT_STATUS_NOT_OK_RETURN(_status); \
} while (0)
/*
hold the state of a nttrans op while in progress. Needed to allow for async backend
functions.
*/
struct trans_op {
struct smbsrv_request *req;
struct smb_trans2 *trans;
uint8_t command;
NTSTATUS (*send_fn)(struct trans_op *);
void *op_info;
};
#define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ((blob)->length < (size)) { \
return NT_STATUS_INFO_LENGTH_MISMATCH; \
}} while (0)
/* setup a trans2 reply, given the data and params sizes */
static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
uint16_t param_size, uint16_t data_size,
uint8_t setup_count)
{
trans->out.setup_count = setup_count;
if (setup_count > 0) {
trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
}
trans->out.params = data_blob_talloc(trans, NULL, param_size);
if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
trans->out.data = data_blob_talloc(trans, NULL, data_size);
if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
return NT_STATUS_OK;
}
static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
TALLOC_CTX *mem_ctx,
DATA_BLOB *blob,
union smb_fsinfo *fsinfo,
int default_str_flags)
{
enum smb_fsinfo_level passthru_level;
switch (fsinfo->generic.level) {
case RAW_QFS_ALLOCATION:
TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
return NT_STATUS_OK;
case RAW_QFS_VOLUME:
TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
/* w2k3 implements this incorrectly for unicode - it
* leaves the last byte off the string */
TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
fsinfo->volume.out.volume_name.s,
4, default_str_flags,
STR_LEN8BIT|STR_NOALIGN));
return NT_STATUS_OK;
case RAW_QFS_VOLUME_INFO:
passthru_level = RAW_QFS_VOLUME_INFORMATION;
break;
case RAW_QFS_SIZE_INFO:
passthru_level = RAW_QFS_SIZE_INFORMATION;
break;
case RAW_QFS_DEVICE_INFO:
passthru_level = RAW_QFS_DEVICE_INFORMATION;
break;
case RAW_QFS_ATTRIBUTE_INFO:
passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
break;
default:
passthru_level = fsinfo->generic.level;
break;
}
return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
passthru_level, fsinfo,
default_str_flags);
}
/*
trans2 qfsinfo implementation send
*/
static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
{
struct smbsrv_request *req = op->req;
struct smb_trans2 *trans = op->trans;
union smb_fsinfo *fsinfo;
TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
&trans->out.data, fsinfo,
SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
return NT_STATUS_OK;
}
/*
trans2 qfsinfo implementation
*/
static NTS
|